2013-10-14 35 views
2

我可以做到这一点;我只是不知道它为什么起作用。使用MNIST数据库,这是我从http://yann.lecun.com/exdb/mnist/下载,并在该页面底部的指引,我写的(如尚未完成的)方法阅读MNIST数据集使用F#

// TRAINING SET IMAGE FILE (train-images-idx3-ubyte): 
// [offset] [type]   [value]   [description] 
// 0000  32 bit integer 0x00000803(2051) magic number 
// 0004  32 bit integer 60000   number of images 
// 0008  32 bit integer 28    number of rows 
// 0012  32 bit integer 28    number of columns 
// 0016  unsigned byte ??    pixel 
// 0017  unsigned byte ??    pixel 
// ........ 
// xxxx  unsigned byte ??    pixel 

// TEST SET IMAGE FILE (t10k-images-idx3-ubyte): 
// [offset] [type]   [value]   [description] 
// 0000  32 bit integer 0x00000803(2051) magic number 
// 0004  32 bit integer 10000   number of images 
// 0008  32 bit integer 28    number of rows 
// 0012  32 bit integer 28    number of columns 
// 0016  unsigned byte ??    pixel 
// 0017  unsigned byte ??    pixel 
// ........ 
// xxxx  unsigned byte ??    pixel 
let loadMnistImage file = 
    use stream = File.Open(file, FileMode.Open) 
    use reader = new BinaryReader(stream) 
    let magicNumber = readInt(reader) 
    let nImages = readInt(reader) 
    let nRows = readInt(reader) 
    let nColumns = readInt(reader) 
    (magicNumber, nImages, nRows, nColumns);; 

这是比较容易的部分。困难的部分是readInt函数的形式。我不能只用BitConverter.ToInt();我在本页找到了答案:https://code.google.com/p/aguaviva-libs/source/browse/c%23/NeuronalNetwork/sets/HandWriting.cs?spec=svn9ffdf444c6317be049572cea59170602c8f28bea&r=9ffdf444c6317be049572cea59170602c8f28bea

翻译方法

int Read(BinaryReader b, int i) 
{ 
    int res = 0; 

    while (i-- > 0) 
    { 
     res <<= 8; 
     res |= b.ReadByte() 
    } 
    return res; 
} 

到F#给出

let readInt (b : BinaryReader) = 
    [1..4] |> List.fold (fun res item -> (res <<< 8) ||| (int)(b.ReadByte())) 0 

(假设i = 4)。这工作:在F#互动,线

loadMnistImage @"Data\t10k-images.idx3-ubyte" 
loadMnistImage @"Data\train-images.idx3-ubyte" 

分别给出的(2051, 10000, 28, 28)(2051, 60000, 28, 28)结果,这与从第一代码片段中的注释中值一致。

我不明白的是它的工作原理。在按位或操作符上所有这些位移和折叠是什么?为什么我不能只用BitConverter.ToInt()代替?

+2

您使用的方法与您运行代码的机器的字节序无关。使用bitconverter的结果将根据字节顺序变化 –

+0

谢谢约翰。那么是不是有内置的方法来做到这一点呢? –

+0

我不认为有任何内置的方式存在。 –

回答

2

发布我的评论作为一个答案

书面,该方法无论工作在其上运行代码的机器的字节序的。

标准库方法将全部返回依赖于运行代码的机器的字节顺序的结果。这可能会产生与预期不同的结果(相对字节顺序相反)。

3

标准库方法IPAddress.NetworkToHostOrder(Int32)考虑到从网络订单转换int时执行平台的字节顺序。后者按标准惯例是大端。作为MNIST文件遵循公约,是大端以下对标准库的方法是不行的readInt功能为尾数无关的替代品:

let readInt (reader: System.IO.BinaryReader) = 
    reader.ReadInt32() |> System.Net.IPAddress.NetworkToHostOrder 

的相当,但更详细的涉及BitConverter变种会

let readInt (reader: System.IO.BinaryReader) = 
    (reader.ReadBytes(4),0) 
    |> System.BitCoverter.ToInt32 
    |> System.Net.IPAddress.NetworkToHostOrder 
+0

谢谢基因 - 这非常有趣。 –