Чтение набора данных MNIST с помощью javascript/node.js

Я пытаюсь расшифровать набор данных из этого источника: http://yann.lecun.com/exdb/mnist/

Внизу есть описание "очень простого" типа файла IDX, но я не могу его понять.

Я пытаюсь добиться чего-то вроде:

var imagesFileBuffer = fs.readFileSync(__dirname + '/train-images-idx3-ubyte');
var labelFileBuffer  = fs.readFileSync(__dirname + '/train-labels-idx1-ubyte');
var pixelValues      = {};

Творить магию

pixelValues ​​теперь такие:

// {
//   "0": [0,0,200,190,79,0... for all 784 pixels ... ],
//   "4": [0,0,200,190,79,0... for all 784 pixels ... ],

и т. д. для всех записей изображений в наборе данных. Я пытался выяснить структуру бинарных файлов, но не смог.


person Lilleman    schedule 29.07.2014    source источник


Ответы (2)


Я понял, что в моей структуре объекта pixelValues ​​будут повторяющиеся ключи, поэтому я создал вместо него массив объектов. Следующий код создаст структуру, которая мне нужна:

var dataFileBuffer  = fs.readFileSync(__dirname + '/train-images-idx3-ubyte');
var labelFileBuffer = fs.readFileSync(__dirname + '/train-labels-idx1-ubyte');
var pixelValues     = [];

// It would be nice with a checker instead of a hard coded 60000 limit here
for (var image = 0; image <= 59999; image++) { 
    var pixels = [];

    for (var x = 0; x <= 27; x++) {
        for (var y = 0; y <= 27; y++) {
            pixels.push(dataFileBuffer[(image * 28 * 28) + (x + (y * 28)) + 15]);
        }
    }

    var imageData  = {};
    imageData[JSON.stringify(labelFileBuffer[image + 8])] = pixels;

    pixelValues.push(imageData);
}

Структура pixelValues ​​теперь примерно такая:

[
    {5: [28,0,0,0,0,0,0,0,0,0...]},
    {0: [0,0,0,0,0,0,0,0,0,0...]},
    ...
]

Есть значения 28x28=784 пикселя, все варьируются от 0 до 255.

Чтобы визуализировать пиксели, используйте мои циклы for, как я делал выше, визуализируя первый пиксель в верхнем левом углу, а затем продвигаясь вправо.

person Lilleman    schedule 01.08.2014
comment
по какой-то причине изображения отображаются сбоку, я предполагаю, что это не имеет ничего общего с приведенным выше решением, а скорее с исходными данными mnist - person dark_ruby; 02.03.2017

Просто небольшое улучшение:

for (var image = 0; image <= 59999; image++) {

с 60000 есть «запись» с нулевым значением в самом конце вашего pixelValues.

ИЗМЕНИТЬ:

Я был немного одержим деталями, потому что хотел преобразовать набор данных MNIST обратно в реальные и отдельные файлы изображений. Итак, я нашел больше ошибок в вашем коде.

  1. это определенно +16, потому что вы должны пропустить 16 байтов данных заголовка. Эта небольшая ошибка отражена в вашем ответе, где значение первого пикселя первой цифры (с 5) равно «28». На самом деле это значение, указывающее, сколько столбцов имеет изображение, а не первый пиксель изображения.

  2. Ваши вложенные циклы for должны быть вывернуты наизнанку, чтобы получить правильный порядок пикселей - при условии, что вы «перестроите» свое изображение из верхнего левого угла в нижний правый угол. С вашим кодом изображение будет перевернуто вдоль оси, идущей из левого верхнего угла в правый нижний.

Итак, ваш код должен быть:

var dataFileBuffer  = fs.readFileSync(__dirname + '/train-images-idx3-ubyte');
var labelFileBuffer = fs.readFileSync(__dirname + '/train-labels-idx1-ubyte');
var pixelValues     = [];

// It would be nice with a checker instead of a hard coded 60000 limit here
for (var image = 0; image <= 59999; image++) { 
    var pixels = [];

    for (var y = 0; y <= 27; y++) {
        for (var x = 0; x <= 27; x++) {
            pixels.push(dataFileBuffer[(image * 28 * 28) + (x + (y * 28)) + 16]);
        }
    }

    var imageData  = {};
    imageData[JSON.stringify(labelFileBuffer[image + 8])] = pixels;

    pixelValues.push(imageData);
}

Эти маленькие детали не будут проблемой, если вы останетесь последовательными и будете использовать эти извлеченные данные, например, для обучения нейронных сетей, потому что вы будете делать то же самое с набором данных для тестирования. Но если вы захотите взять эту нейронную сеть, обученную MNIST, и попытаться проверить ее с помощью реальных рукописных цифр, вы получите плохие результаты, потому что реальные изображения не перевернуты.

person Angry Coder    schedule 03.03.2016
comment
Благодарю вас! Отредактировал ответ. :) - person Lilleman; 03.03.2016
comment
@Lilleman Я не хочу мудрить, но не могли бы вы объяснить, почему вы используете 15-байтовое смещение в своем коде? Я посмотрел на веб-сайте MNIST о формате данных, и данные начинаются после 16-байтового смещения в 0016. Даже если это ошибка, это не сильно влияет. Еще раз спасибо за ваш код, он очень помог мне понять формат данных MNIST. - person Angry Coder; 03.03.2016
comment
Эм... не помню, если честно. Но я предполагаю, что это связано с тем, что 0 — первый байт, а 16 — первый байт данных. Следовательно, 0-15 являются байтами перед данными. Я могу ошибаться в этом, поэтому, если вы думаете, что мне следует переключиться на 16, и это лучше работает в коде, я изменю. Спасибо большое за добрые слова, всегда рады помочь. :) - person Lilleman; 04.03.2016
comment
@Lilleman Я добавил больше предложений по пути моего собственного кодирования. - person Angry Coder; 05.03.2016