Как загрузить цифры MNIST и данные меток в MATLAB?

Я пытаюсь запустить код, указанный в ссылке

https://github.com/bd622/DiscretHashing

Дискретное хеширование — это метод уменьшения размерности, который используется при приблизительном поиске ближайшего соседа. Я хочу загрузить реализацию в базу данных MNIST, которая доступна по адресу http://yann.lecun.com/exdb/mnist/. Я извлек файлы из их сжатого формата gz.

ПРОБЛЕМА 1:

Используя решение для чтения базы данных MNIST, предоставленное в Чтение двоичного файла базы данных изображений MNIST в МАТЛАБ

Я получаю следующую ошибку:

Error using fread
Invalid file identifier.  Use fopen to generate a valid file identifier.

Error in Reading (line 7)
A = fread(fid, 1, 'uint32');

Вот код:

clear all;
close all;

%//Open file
fid = fopen('t10k-images-idx3-ubyte', 'r');

A = fread(fid, 1, 'uint32');
magicNumber = swapbytes(uint32(A));

%//For each image, store into an individual cell
imageCellArray = cell(1, totalImages);
for k = 1 : totalImages
    %//Read in numRows*numCols pixels at a time
    A = fread(fid, numRows*numCols, 'uint8');
    %//Reshape so that it becomes a matrix
    %//We are actually reading this in column major format
    %//so we need to transpose this at the end
    imageCellArray{k} = reshape(uint8(A), numCols, numRows)';
end

%//Close the file
fclose(fid);

ОБНОВЛЕНИЕ: проблема 1 решена, исправленный код

clear all;
close all;

%//Open file
fid = fopen('t10k-images.idx3-ubyte', 'r');

A = fread(fid, 1, 'uint32');
magicNumber = swapbytes(uint32(A));

%//Read in total number of images
%//A = fread(fid, 4, 'uint8');
%//totalImages = sum(bitshift(A', [24 16 8 0]));

%//OR
A = fread(fid, 1, 'uint32');
totalImages = swapbytes(uint32(A));

%//Read in number of rows
%//A = fread(fid, 4, 'uint8');
%//numRows = sum(bitshift(A', [24 16 8 0]));

%//OR
A = fread(fid, 1, 'uint32');
numRows = swapbytes(uint32(A));

%//Read in number of columns
%//A = fread(fid, 4, 'uint8');
%//numCols = sum(bitshift(A', [24 16 8 0]));

%// OR
A = fread(fid, 1, 'uint32');
numCols = swapbytes(uint32(A));

for k = 1 : totalImages
    %//Read in numRows*numCols pixels at a time
    A = fread(fid, numRows*numCols, 'uint8');
    %//Reshape so that it becomes a matrix
    %//We are actually reading this in column major format
    %//so we need to transpose this at the end
    imageCellArray{k} = reshape(uint8(A), numCols, numRows)';
end

%//Close the file
fclose(fid);

ПРОБЛЕМА 2:

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

traindata = double(traindata);
testdata = double(testdata);

Как подготовить базу данных MNIST, чтобы я мог подать заявку на реализацию?

ОБНОВЛЕНИЕ: я реализовал решение, но я продолжаю получать эту ошибку

Error using fread
Invalid file identifier.  Use fopen to generate a valid file identifier.

Error in mnist_parse (line 11)
A = fread(fid1, 1, 'uint32');

Это файлы

demo.m % это основной файл, который вызывает функцию для чтения данных MNIST

clear all
clc
[Trainimages, Trainlabels] = mnist_parse('C:\Users\Desktop\MNIST\train-images-idx3-ubyte', 'C:\Users\Desktop\MNIST\train-labels-idx1-ubyte');

[Testimages, Testlabels] = mnist_parse('t10k-images-idx3-ubyte', 't10k-labels-idx1-ubyte');

k=5;
digit = images(:,:,k);
lbl = label(k);

 function [images, labels] = mnist_parse(path_to_digits, path_to_labels)

% Open files
fid1 = fopen(path_to_digits, 'r');

% The labels file
fid2 = fopen(path_to_labels, 'r');

% Read in magic numbers for both files
A = fread(fid1, 1, 'uint32');
magicNumber1 = swapbytes(uint32(A)); % Should be 2051
fprintf('Magic Number - Images: %d\n', magicNumber1);

A = fread(fid2, 1, 'uint32');
magicNumber2 = swapbytes(uint32(A)); % Should be 2049
fprintf('Magic Number - Labels: %d\n', magicNumber2);

% Read in total number of images
% Ensure that this number matches with the labels file
A = fread(fid1, 1, 'uint32');
totalImages = swapbytes(uint32(A));
A = fread(fid2, 1, 'uint32');
if totalImages ~= swapbytes(uint32(A))
    error('Total number of images read from images and labels files are not the same');
end
fprintf('Total number of images: %d\n', totalImages);

% Read in number of rows
A = fread(fid1, 1, 'uint32');
numRows = swapbytes(uint32(A));

% Read in number of columns
A = fread(fid1, 1, 'uint32');
numCols = swapbytes(uint32(A));

fprintf('Dimensions of each digit: %d x %d\n', numRows, numCols);

% For each image, store into an individual slice
images = zeros(numRows, numCols, totalImages, 'uint8');
for k = 1 : totalImages
    % Read in numRows*numCols pixels at a time
    A = fread(fid1, numRows*numCols, 'uint8');

    % Reshape so that it becomes a matrix
    % We are actually reading this in column major format
    % so we need to transpose this at the end
    images(:,:,k) = reshape(uint8(A), numCols, numRows).';
end

% Read in the labels
labels = fread(fid2, totalImages, 'uint8');

% Close the files
fclose(fid1);
fclose(fid2);

end

person SKM    schedule 19.09.2016    source источник
comment
Ошибка довольно очевидна, вы использовали fopen для недопустимого имени файла. Убедитесь, что 't10k-images-idx3-ubyte' — это полное имя файла, и он расположен в вашем текущем пути к MATLAB. В противном случае убедитесь, что это полный абсолютный путь к файлу, который вы хотите открыть.   -  person excaza    schedule 19.09.2016
comment
@excaza: Первая проблема и ошибка из-за операции чтения файла решены. Проблема действительно была в имени файла. Но теперь я понятия не имею, как использовать базу данных, я не могу понять, как использовать 4 файла. Я полагаю, что переменная traindata будет содержать файл train-images.idx3-ubyte. Тогда какой из них будет тестовыми данными, и как мне использовать файлы базы данных 2 этикеток? Пожалуйста помоги   -  person SKM    schedule 20.09.2016
comment
@rayryeng: Не могли бы вы сообщить мне, почему я получаю сообщение об ошибке из-за операции чтения файла, когда реализовал ваш ответ? Я разместил новые обновления в Вопросе. Спасибо за ваше время и усилия.   -  person SKM    schedule 22.09.2016


Ответы (1)


Я являюсь первоначальным автором Метода №1, о котором вы говорили. Процесс чтения обучающих данных и тестовых меток довольно прост. Что касается чтения изображений, код, который вы показали выше, отлично читает файлы и имеет формат массива ячеек. Однако вы пропустили чтение количества изображений, строк и столбцов внутри файла. Обратите внимание, что формат MNIST для этого файла выглядит следующим образом. Левый столбец — это смещение в байтах, на которое вы ссылаетесь, относительно начала:

[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

Первые четыре байта — это магическое число: 2051, чтобы убедиться, что вы правильно читаете файл. Следующие четыре байта обозначают общее количество изображений, затем следующие четыре байта — строки и, наконец, следующие четыре байта — столбцы. Должно быть 60000 изображений размером 28 строк по 28 столбцов. После этого пиксели чередуются в основном формате строки, поэтому вам нужно перебрать серию 28 x 28 пикселей и сохранить их. В этом случае я сохранил их в массиве ячеек, и каждый элемент в этом массиве ячеек будет одной цифрой. Такой же формат и для тестовых данных, но вместо них 10000 изображений.

Что касается собственно этикеток, то это примерно тот же формат, но есть небольшие отличия:

[offset] [type]          [value]          [description]
0000     32 bit integer  0x00000801(2049) magic number (MSB first)
0004     32 bit integer  60000            number of items
0008     unsigned byte   ??               label
0009     unsigned byte   ??               label
........
xxxx     unsigned byte   ??               label

Первые четыре байта — это магическое число: 2049, затем второй набор из четырех байтов сообщает вам, сколько существует меток, и, наконец, для каждой соответствующей цифры в наборе данных имеется ровно 1 байт. Тестовые данные также имеют тот же формат, но имеют 10000 меток. Таким образом, как только вы прочитаете необходимые данные в наборе меток, вам потребуется всего один вызов fread и убедитесь, что данные представляют собой 8-битное целое число без знака для чтения в остальных метках.

Теперь причина, по которой вы должны использовать swapbytes, заключается в том, что MATLAB будет считывать данные в формате с прямым порядком байтов, что означает, что младший байт из набора байтов читается первым. Вы используете swapbytes, чтобы изменить этот порядок, когда закончите.

Таким образом, я изменил этот код для вас, чтобы он представлял собой реальную функцию, которая принимает набор из двух строк: полный путь к файлу изображения цифр и полный путь к цифрам. Я также изменил код, чтобы изображения представляли собой трехмерную числовую матрицу, а не массив ячеек для более быстрой обработки. Обратите внимание, что когда вы начинаете считывать фактические данные изображения, каждый пиксель представляет собой 8-битное целое число без знака, поэтому нет необходимости менять местами байты. Это требовалось только при чтении нескольких байтов в одном вызове fread:

function [images, labels] = mnist_parse(path_to_digits, path_to_labels)

% Open files
fid1 = fopen(path_to_digits, 'r');

% The labels file
fid2 = fopen(path_to_labels, 'r');

% Read in magic numbers for both files
A = fread(fid1, 1, 'uint32');
magicNumber1 = swapbytes(uint32(A)); % Should be 2051
fprintf('Magic Number - Images: %d\n', magicNumber1);

A = fread(fid2, 1, 'uint32');
magicNumber2 = swapbytes(uint32(A)); % Should be 2049
fprintf('Magic Number - Labels: %d\n', magicNumber2);

% Read in total number of images
% Ensure that this number matches with the labels file
A = fread(fid1, 1, 'uint32');
totalImages = swapbytes(uint32(A));
A = fread(fid2, 1, 'uint32');
if totalImages ~= swapbytes(uint32(A))
    error('Total number of images read from images and labels files are not the same');
end
fprintf('Total number of images: %d\n', totalImages);

% Read in number of rows
A = fread(fid1, 1, 'uint32');
numRows = swapbytes(uint32(A));

% Read in number of columns
A = fread(fid1, 1, 'uint32');
numCols = swapbytes(uint32(A));

fprintf('Dimensions of each digit: %d x %d\n', numRows, numCols);

% For each image, store into an individual slice
images = zeros(numRows, numCols, totalImages, 'uint8');
for k = 1 : totalImages
    % Read in numRows*numCols pixels at a time
    A = fread(fid1, numRows*numCols, 'uint8');

    % Reshape so that it becomes a matrix
    % We are actually reading this in column major format
    % so we need to transpose this at the end
    images(:,:,k) = reshape(uint8(A), numCols, numRows).';
end

% Read in the labels
labels = fread(fid2, totalImages, 'uint8');

% Close the files
fclose(fid1);
fclose(fid2);

end

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

[images, labels] = mnist_parse('train-images-idx3-ubyte', 'train-labels-idx1-ubyte');

Кроме того, вы должны сделать следующее для тестовых изображений:

[images, labels] = mnist_parse('t10k-images-idx3-ubyte', 't10k-labels-idx1-ubyte');

Чтобы получить доступ к kth цифре, вы должны просто сделать:

digit = images(:,:,k);

Соответствующая метка для kth цифры будет:

lbl = label(k);

Чтобы наконец привести эти данные в формат, приемлемый для того кода, который я видел на Github, они предполагают, что строки соответствуют обучающим примерам, а столбцы — фичам. Если вы хотите использовать этот формат, просто измените данные, чтобы пиксели изображения были распределены по столбцам.

Поэтому просто сделайте это:

[trainingdata, traingnd] = mnist_parse('train-images-idx3-ubyte', 'train-labels-idx1-ubyte');
trainingdata = double(reshape(trainingdata, size(trainingdata,1)*size(trainingdata,2), []).');
traingnd = double(traingnd);

[testdata, testgnd] = mnist_parse('t10k-images-idx3-ubyte', 't10k-labels-idx1-ubyte');
testdata = double(reshape(testdata, size(testdata,1)*size(testdata_data,2), []).');
testgnd = double(testgnd);

В приведенном выше примере используются те же переменные, что и в сценарии, поэтому вы сможете подключить их, и все должно работать. Вторая строка изменяет форму матрицы так, чтобы каждая цифра находилась в столбце, но нам нужно транспонировать это так, чтобы каждая цифра находилась в столбце. Нам также нужно выполнить приведение к double, так как именно это делает код Github. Та же логика применяется к тестовым данным. Также обратите внимание, что я явно присвоил меткам обучения и тестирования значение double, чтобы обеспечить максимальную совместимость с любыми алгоритмами, которые вы решите использовать с этими данными.


Удачного взлома цифр!

person rayryeng    schedule 20.09.2016
comment
Большое спасибо за ваше подробное объяснение. Я не смог войти в свою учетную запись Stackoverflow из-за какого-то сбоя, поэтому я не смог проверить ваш ответ. Итак, я запускал ваш код шаг за шагом, но Matlab выдает ошибку: Ошибка при использовании fread Неверный идентификатор файла. Используйте fopen для создания действительного идентификатора файла. Ошибка в mnist_parse (строка 11) A = fread(fid1, 1, 'uint32'); Ошибка в демонстрации (строка 3) [Trainimages, Trainlabels] = mnist_parse('C:\Users\Desktop\MNIST\train-images-idx3-ubyte', 'C:\Users\Desktop\MNIST\train-labels-idx - person SKM; 22.09.2016
comment
Основываясь на вашем наблюдении, что я пропустил чтение в количестве totalImages, строк и столбцов, я исправил эту часть. Я исправил это в своем вопросе. Однако я не могу исправить эту новую ошибку, которая появляется, когда я внедряю ваше решение. Я не использовал последний абзац кода, который я должен применить к программе на GitHub. Подскажите, пожалуйста, что мне сделать, чтобы ошибка исчезла? - person SKM; 22.09.2016
comment
Это не работает, потому что ваш путь неверен. Между пользователями и рабочим столом на вашем пути должно быть ваше имя пользователя. Нет такого каталога. fopen работает, когда указан правильный путь к файлу, а вы этого не сделали. Пожалуйста, убедитесь, что путь к вашему файлу абсолютно правильный... Или поместите скрипт в тот же каталог, что и данные MNIST, и используйте локальные пути. - person rayryeng; 22.09.2016
comment
Имена файлов после распаковки отличались от тех, что были в вашем ответе. :) Тщательно просмотрев имена файлов, я увидел вместо них train-images.idx3-ubyte. То же самое для других. Итак, я не получаю эту ошибку. Однако есть новая проблема, которая заключается в том, что код GitHub использует cateTrainTest, который доступен с базой данных cifar_10_gist. Этот файл используется в строке [Pre, Rec] = Assessment_macro(cateTrainTest, Ret). - person SKM; 23.09.2016
comment
По сути, элементы указывают на сходство: 0 указывает, похожи ли две точки данных или нет, а 1 указывает на различие, если я не ошибаюсь. Вы знаете, где я могу найти этот файл данных для базы данных MNIST? Или, если бы вы могли помочь с каким-то другим взломом, чтобы можно было использовать базу данных MNIST? - person SKM; 23.09.2016
comment
Я не знаю, что делает эта линия. MNIST содержит только цифры и ожидаемые метки. Это все. Кстати, спасибо за согласие! - person rayryeng; 23.09.2016