【问题标题】:What did I do wrong with parsing MNIST dataset with BinaryReader in C#?在 C# 中使用 BinaryReader 解析 MNIST 数据集时我做错了什么?
【发布时间】:2014-01-24 20:49:17
【问题描述】:

我正在解析 C# 中的 MNIST 数据集,来自:http://yann.lecun.com/exdb/mnist/

我正在尝试从二进制文件中读取第一个Int32

FileStream fileS = new FileStream(fileName, FileMode.Open, FileAccess.Read);
BinaryReader reader = new BinaryReader(fileS);
int magicNumber = reader.ReadInt32();

但是,它给了我一个无意义的数字:50855936。

如果我使用File.ReadAllBytes()

buffer = File.ReadAllBytes(fileName);

然后查看字节,它工作正常(前四个字节现在代表 2049),我对 BinaryReader 做错了什么?

文件格式如下(我正在尝试读取第一个幻数):

All the integers in the files are stored in the MSB first (high endian) format used by most non-Intel processors. Users of Intel processors and other low-endian machines must flip the bytes of the header.

训练集标签文件(train-labels-idx1-ubyte):

[offset] [type]          [value]          [description] 
0000     32 bit integer  0x00000801(2049) magic number (MSB first) 
0004     32 bit integer  60000            number of items 
0008     unsignebyte     ??               label 
0009     unsigned byte   ??               label 
........ 
xxxx     unsigned byte   ??               label
The labels values are 0 to 9.d 

【问题讨论】:

  • 你的文件是什么编码的?默认情况下,BinaryReader 使用 UTF-8。如果它不同于 UTF-8,请尝试在 BinaryReader 构造函数调用中指定它。
  • 你能举个例子说明你觉得哪里不对吗?
  • 字节序有问题?
  • 它返回什么,你期待什么?可能是字节序的问题。
  • 好吧,现在ReadInt32 的文档以及您添加的内容应该清楚了。 “BinaryReader 以 little-endian 格式读取此数据类型。”

标签: c# binary endianness mnist


【解决方案1】:

50855936 == 0x03080000。或者 0x00000803 当你反转字节时,几乎所有机器都需要,因为 little-endian 赢得了鸡蛋大战。足够接近 2049,不知道什么解释了 2 的偏移量。这里有一个扩展方法可以帮助您阅读它:

  public static class BigEndianUtils {
      public static int ReadBigInt32(this BinaryReader br) {
          var bytes = br.ReadBytes(sizeof(Int32));
          if (BitConverter.IsLittleEndian) Array.Reverse(bytes);
          return BitConverter.ToInt32(bytes, 0);
      }
  }

如果文件包含更多字段类型,则添加其他方法,只需在 sn-p 中替换 Int32。

【讨论】:

  • 0x03080000 值可能是由于其他一些错误(OP 可能只是在键入数字时出错)。如果你使用 BinaryWriter 写入 2049 值,它会使用 little-endian 生成 0x01080000。
  • 对于后验性 - OP 正在 C# (yann.lecun.com/exdb/mnist) 和 0x00000803 (2051) 和 0x00000801中解析 MNIST 数据库> (2049) 差异是由于从提到的站点复制错误造成的。 2049 代表 train-labels-idx1-ubyte 数据集的“幻数”,2051 代表来自 MNIST 的 train-images-idx3-ubyte 数据集的“幻数”。
【解决方案2】:

您的问题似乎出在其他地方。您能否发布一个无法按预期工作的最小可编译 sn-p?

例如,这个 sn-p 完全按预期工作 - 它创建一个 8 字节的二进制文件,这是两个大端 Int32。然后阅读器将数据正确地读取为两个整数。

using (var str = File.Create("C:\\Test.dat"))
    using (var wr = new BinaryWriter(str))
    {
        wr.Write(2049);
        wr.Write(60000);
    }

using (var str = File.Open("C:\\Test.dat", FileMode.Open))
    using (var rdr = new BinaryReader(str))
    {
        rdr.ReadInt32().Dump();
        rdr.ReadInt32().Dump();
    }

但是,字节序是固定的。如果您需要先使用 MSB,则需要自己读取字节并将它们转换为整数(或者,如果您愿意,当然可以使用按位运算反转字节顺序)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-04-04
    • 2015-02-19
    • 2018-05-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多