MNIST数据集IDX转像素矩阵时数值全部右移的问题求助
MNIST IDX格式转像素矩阵出现右移问题排查
在探索神经网络与机器学习时,使用MNIST手写数字数据集,将IDX格式文件转换为神经网络可输入的像素矩阵时,所有数值出现右移现象(附效果截图)。以下是转换代码及问题分析:
原转换代码
const fs = require("fs"); const { hex_to_decimal } = require("../utils/hex_to_decimal"); function read_idx_file(path) { return new Promise(function (resolve, reject) { fs.readFile(path, (err, data) => { if (err) { console.log(err.message); reject(err.message); } resolve(data); }); }); } function input_into_json(data, path) { return new Promise(function (resolve, reject) { fs.writeFile(path, data, {}, (err) => { if (err) reject(err.message); else resolve(); }); }); } // inputting training-images into json file read_idx_file("../samples/unzipped/train-images.idx3-ubyte") .then((data) => { const output = []; let temp_row_arr = []; let temp_col_arr = []; let temp_index = 8; while (data[temp_index] !== undefined) { for (let i = temp_index; i - temp_index < 28; i++) { temp_row_arr.push(hex_to_decimal(data[i])); } temp_index += 28; temp_col_arr.push(temp_row_arr); temp_row_arr = []; if (temp_col_arr.length === 28) { output.push(temp_col_arr); temp_col_arr = []; } } input_into_json( JSON.stringify(output), "../samples/json/training-images.json" ); }) .then(() => console.log("done")) .catch((err) => console.log(err));
IDX格式说明(中文翻译)
IDX文件格式用于存储向量与多维矩阵,结构如下:
- 文件头由多个32位大端(big-endian)整数组成:
- 前两个字节为填充值0
- 第三个字节表示数据类型:
- 0x08:无符号字节(对应MNIST像素的0-255灰度值)
- 0x09:有符号字节
- 0x0B:16位短整数
- 0x0C:32位整数
- 0x0D:32位单精度浮点数
- 0x0E:64位双精度浮点数
- 第四个字节表示数据维度数(如向量为1维,图像矩阵为2维)
- 后续每个32位大端整数对应各维度的大小
- 文件头之后是实际数据,按维度顺序排列,数据元素的大小与类型由文件头指定
针对MNIST的train-images.idx3-ubyte,文件头包含4个32位整数(共16字节):
- 第0-3字节:魔术数(固定为0x00000803,标识无符号字节类型的3维数据)
- 第4-7字节:图像总数量
- 第8-11字节:单图像行数(固定为28)
- 第12-15字节:单图像列数(固定为28)
- 第16字节及之后:每个图像的28×28字节像素数据
问题原因分析
- 文件头跳过长度错误:原代码从索引8开始读取数据,错误地将文件头中第8-15字节(行数、列数字段,共8字节)当成了第一个图像的前8个像素,导致所有图像数据整体偏移,显示时出现右移现象。
- 多余的数值转换:Buffer对象通过索引访问时,返回的已经是0-255的十进制灰度值,调用
hex_to_decimal函数属于画蛇添足——若该函数将数字当作十六进制字符串处理,会导致数值错误(比如十进制10被转成十六进制10对应的十进制16),进一步加剧显示异常。
修正后的代码
const fs = require("fs"); function read_idx_file(path) { return new Promise(function (resolve, reject) { fs.readFile(path, (err, data) => { if (err) { console.log(err.message); reject(err.message); } resolve(data); }); }); } function input_into_json(data, path) { return new Promise(function (resolve, reject) { fs.writeFile(path, data, {}, (err) => { if (err) reject(err.message); else resolve(); }); }); } // 处理训练图像转JSON read_idx_file("../samples/unzipped/train-images.idx3-ubyte") .then((data) => { const output = []; // MNIST图像文件头共16字节,从索引16开始读取像素数据 let temp_index = 16; // 从文件头读取总图像数(大端字节序) const totalImages = data.readUInt32BE(4); const imageWidth = 28; const imageHeight = 28; for (let i = 0; i < totalImages; i++) { const image = []; for (let row = 0; row < imageHeight; row++) { const pixels = []; for (let col = 0; col < imageWidth; col++) { // 直接取Buffer中的十进制灰度值 pixels.push(data[temp_index]); temp_index++; } image.push(pixels); } output.push(image); } return input_into_json( JSON.stringify(output), "../samples/json/training-images.json" ); }) .then(() => console.log("done")) .catch((err) => console.log(err));
内容的提问来源于stack exchange,提问作者maxovic
相关产品推荐
相关产品推荐

