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

Метод, который вы использовали, не зависит от консистенции машины, на которой вы используете код. Используя битконвертер, результаты будут меняться в зависимости от конечности –

+0

Спасибо John. Так что еще нет встроенного способа сделать это? –

+0

Я не думаю, что любой встроенный способ существует. –

ответ

2

проводки мой комментарий как ответ

Как написано, этот метод будет работать независимо от байтов машины, на которой выполняется код.

Стандартные методы библиотеки возвратят результаты, зависящие от контентоспособности машины, на которой запущен код. Это может привести к разным результатам, которые вы ожидаете (относительный порядок байтов отменяется).

3

Метод стандартной библиотеки IPAddress.NetworkToHostOrder(Int32) учитывает конечную точку исполняющей платформы при преобразовании int из сетевого заказа. Последний по стандартному соглашению является big-endian. Как 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

Спасибо, Джин - это очень интересно. –

Смежные вопросы