如何将数百万个双精度值写入一个txt文件

How to write millions of double values into a txt file

我制作了一个神经网络,现在我需要将训练过程的结果保存到本地文件中。总共有 7,155,264 个值。我试过这样的循环

string weightsString = "";
string biasesString = "";

for (int l = 1; l < layers.Length; l++)
{
    for (int j = 0; j < layers[l].Length; j++)
    {
        for (int k = 0; k < layers[l - 1].Length; k++)
        {
            weightsString += weights[l][j, k] + "\n";
        }

        biasesString += biases[l][j] + "\n";
    }
}

File.WriteAllText(@"path", weightsString + "\n" + biasesString);

但是遍历所有值确实需要很长时间。有没有办法不用先写成字符串就直接写内容?

(权重是双精度[][] 而偏差是双精度[][])

StringBuilder weightsSB = new StringBuilder();
StringBuilder biasesSB = new StringBuilder();

for (int l = 1; l < layers.Length; l++)
{
    for (int j = 0; j < layers[l].Length; j++)
    {
        for (int k = 0; k < layers[l - 1].Length; k++)
        {
            weightsSB.Append(weights[l][j, k] + "\n");
        }

        biasesSB.Append(biases[l][j] + "\n");
    }
}

按照评论中的建议,我改用了 StringBuilder。很有魅力。

  1. 错误的变体 - 您可以使用 json 序列化

  2. So-so 变体 - 立即写入文件。使用 File.AppendText

  3. 恕我直言,最好的变体 - 使用 DB

  4. 恕我直言,不错的变体 - 使用 BinaryFormatter(您自己无法阅读,但应用程序可以)

  5. 工作变体 - 使用 StringBuilder

首先写下700万个数据集显然会花费很多时间。 我建议您将权重和偏差分成两个文件并即时写入,在完成之前无需将它们全部存储在内存中。

using StreamWriter weigthStream = new("weigths.txt", append: true);
using StreamWriter biasStream = new("biases.txt", append: true);

for (int l = 1; l < layers.Length; l++)
{
    for (int j = 0; j < layers[l].Length; j++)
    {
        for (int k = 0; k < layers[l - 1].Length; k++)
        {
            await weightStream.WriteLineAsync(weights[l][j, k]);
        }

        await biasStream.WriteLineAsync(biases[l][j]);
    }
}

But it literally takes forever to go through all of the values. Is there no way to write the contents directly without having to write them in a string first?

一种选择是将其保存为二进制数据。这使得它更难被人类阅读,但对于大量数据来说,这确实是更可取的,因为它会在阅读和写作时节省大量时间。例如使用 BinaryWriter 和使用不安全代码。

myBinaryWriter.Write(myArray.GetLength(0));
myBinaryWriter.Write(myArray.GetLength(1));
fixed (double* ptr = myArray)
{
    var span = new ReadOnlySpan<byte>(ptr, myArray.GetLength(0) *myArray.GetLength(1) * 8);
    myBinaryWriter.Write(span);
}

您也可以考虑使用像 protbuf.net 这样的二进制序列化库,它可以获取对象并将其序列化为流。请注意,某些库可能需要将属性添加到 类 和属性中。一些库也可能存在多维 and/or 锯齿状数组的问题。因此,有时定义您自己的使用一维数组作为后备存储的二维数组很有用,这可以使序列化或将数据传递给其他组件等事情变得更加简单。

另一种比较常见的做法是使用 json 或 xml 等方式将元数据(如高度、宽度等)存储在简单的人类可读 text-file 中。同时将实际数据保存在单独的原始二进制文件中。