4

我正在尝试从以下来源解码数据集: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 ... ],

等用于数据集中的所有图像条目。我试图弄清楚二进制文件的结构,但失败了。

4

2 回答 2

10

我意识到我的 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 循环,渲染左上角的第一个像素,然后向右工作。

于 2014-08-01T15:06:11.480 回答
2

只是一个小改进:

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 训练的神经网络并尝试用现实生活中的手写数字来验证它,你会得到不好的结果,因为真实的图像没有翻转。

于 2016-03-03T14:45:51.323 回答