2013-10-14 56 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

謝謝基因 - 這非常有趣。 –