python-machine-learning-book 中的 MNIST 数据集:从 IDX 二进制格式解析到第 12/13 章 MLP 实战
2026/9/23 2:01:47 网站建设 项目流程

python-machine-learning-book 中的 MNIST 数据集:从 IDX 二进制格式解析到第 12/13 章 MLP 实战

【免费下载链接】python-machine-learning-bookThe "Python Machine Learning (1st edition)" book code repository and info resource项目地址: https://gitcode.com/gh_mirrors/py/python-machine-learning-book

MNIST 手写数字数据库是本仓库《Python Machine Learning(第 1 版)》配套代码中第 12 章(多层感知机)与第 13 章(Theano/Keras 深度学习)的核心实验数据。本篇文章以 code/datasets/mnist/README.md 为骨架,结合仓库内真实的数据文件、加载函数与训练脚本,系统讲解 MNIST 的构成、IDX 二进制存储格式、NumPy 解析方法,以及如何在本仓库的 MLP 与 Keras 代码中直接复现训练流程,读完即可在本地跑通「下载 → 解析 → 训练 → 评估」的完整链路。

一、MNIST 数据集的来源与构成

MNIST(Modified National Institute of Standards and Technology database)由美国国家标准与技术研究院(NIST)的两个数据集加工而来。根据 code/datasets/mnist/README.md 的说明:

  • 训练集的手写数字来自250 位不同的人,其中 50% 是高中生,50% 是美国人口普查局的员工;
  • 测试集同样遵循该比例拆分,但书写者与训练集不重叠,从而保证测试评估的公平性;
  • 数字类别覆盖 0~9 共 10 个类别。

这一「作者不重叠」的设计正是 MNIST 能成为经典基准的原因:测试结果不会因为书写者出现在训练集中而被高估。仓库 code/datasets/README.md 中也明确标注:mnist - used in chapters 12 and 13,与本数据集目录 README 的描述相互印证。

二、仓库中随附的四个二进制数据文件

本仓库在 code/datasets/mnist/ 目录下直接提供了完整的 MNIST 原始数据(gzip 压缩的 IDX 字节流),共四个文件:

文件内容大小(gzip 后)样本数
train-images-idx3-ubyte.gz训练集图像约 9.9 MB(解压后约 47 MB)60,000
train-labels-idx1-ubyte.gz训练集标签约 29 KB(解压后约 60 KB)60,000
t10k-images-idx3-ubyte.gz测试集图像约 1.6 MB(解压后约 7.8 MB)10,000
t10k-labels-idx1-ubyte.gz测试集标签约 5 KB(解压后约 10 KB)10,000

文件命名遵循 MNIST 官方约定:idx3-ubyte表示三维图像字节流,idx1-ubyte表示一维标签字节流,t10k即 test 10k(测试集 10,000 张)。

需要特别强调的是,本 README 描述的是 5,000 张图像的子集(每类取前 500 个数字,目标变量为{500×0, …, 500×9}),这一子集用于书中教学演示;而仓库实际附带的完整四个文件包含完整的 60,000/10,000 样本,code/ch12/ch12.ipynb 加载时输出的Rows: 60000, columns: 784Rows: 10000, columns: 784即为完整数据集的实证。

三、特征表示:从 28×28 图像到 784 维向量

每个样本的特征向量(特征矩阵的一行)由784 个像素强度值组成,它们是把原始的28×28 灰度图像按行展平(unrolled)得到的:

  • 每张图像是 28×28 = 784 个像素;
  • 每个像素取值 0~255(uint8 灰度强度),0 为黑色背景,255 为白色笔画;
  • 展平后每行images[i]恰好对应一张手写数字图像,可直接reshape(28, 28)还原显示。

目标变量是离散的类别标签(0~9),与 784 维特征向量一一对应。这种「1 行 = 1 张图、1 列 = 1 个像素」的扁平化组织方式,正是传统全连接神经网络(MLP)的输入格式,也是第 12、13 章代码直接使用X_train.shape[1](784)作为输入维度的原因。

四、IDX 二进制格式解析:手写 load_mnist 函数

MNIST 原始数据不是 CSV 或图片文件,而是带有魔数(magic number)头部的 IDX 二进制格式。仓库中给出了两个版本的解析实现,我们先看 code/ch12/ch12.ipynb 中的标准版本:

import os import struct import numpy as np def load_mnist(path, kind='train'): """Load MNIST data from `path`""" labels_path = os.path.join(path, '%s-labels-idx1-ubyte' % kind) images_path = os.path.join(path, '%s-images-idx3-ubyte' % kind) with open(labels_path, 'rb') as lbpath: magic, n = struct.unpack('>II', lbpath.read(8)) labels = np.fromfile(lbpath, dtype=np.uint8) with open(images_path, 'rb') as imgpath: magic, num, rows, cols = struct.unpack(">IIII", imgpath.read(16)) images = np.fromfile(imgpath, dtype=np.uint8).reshape(len(labels), 784) return images, labels

该函数的核心逻辑值得逐行拆解:

  1. 标签文件头(8 字节)struct.unpack('>II', ...)按大端序(>)解析两个 32 位无符号整数——magic(魔数,校验文件类型)和n(标签数量),随后的字节流全部是uint8标签;
  2. 图像文件头(16 字节):解析四个字段——magicnum(图像数量)、rows(行数 28)、cols(列数 28),随后的字节流是全部像素;
  3. 关键一步np.fromfile(imgpath, dtype=np.uint8).reshape(len(labels), 784)把连续像素字节流直接重塑为「样本数 × 784」的特征矩阵,与标签数量len(labels)对齐;
  4. kind参数决定加载训练集('train')还是测试集('t10k'),拼出%s-images-idx3-ubyte这类标准文件名。

调用方式与预期输出(来自 code/ch12/ch12.ipynb 的实际运行结果):

X_train, y_train = load_mnist('mnist/', kind='train') print('Rows: %d, columns: %d' % (X_train.shape[0], X_train.shape[1])) # Rows: 60000, columns: 784 X_test, y_test = load_mnist('mnist/', kind='t10k') print('Rows: %d, columns: %d' % (X_test.shape[0], X_test.shape[1])) # Rows: 10000, columns: 784

4.1 兼容性增强:直接读取 gz 压缩包

code/ch12/ch12.ipynb 还记录了一个实战中常见的坑:部分解压工具会把-labels-idx1-ubyte重命名为-labels.idx1-ubyte(连字符被替换为点号),导致按原文件名open失败。为避免该问题,书中提供了基于gzip模块、直接读取.gz归档的改进版:

import os import struct import numpy as np import gzip def load_mnist(path, kind='train'): """Load MNIST data from `path`""" labels_path = os.path.join(path, '%s-labels-idx1-ubyte.gz' % kind) images_path = os.path.join(path, '%s-images-idx3-ubyte.gz' % kind) with gzip.open(labels_path, 'rb') as lbpath: lbpath.read(8) buffer = lbpath.read() labels = np.frombuffer(buffer, dtype=np.uint8) with gzip.open(images_path, 'rb') as imgpath: imgpath.read(16) buffer = imgpath.read() images = np.frombuffer(buffer, dtype=np.uint8).reshape( len(labels), 784).astype(np.float64) return images, labels

改进点有三:文件名后缀带上.gz;用gzip.open代替open;用np.frombuffer从内存缓冲直接构造数组,且图像数组额外.astype(np.float64)转为浮点型——这一步正是为后续神经网络反向传播的浮点运算做准备。

五、数据准备与可视化

5.1 手动解压(可选)

第 12 章给出了终端解压命令,在 MNIST 下载目录中执行:

gzip *ubyte.gz -d

如果你希望直接加载本仓库中现成的.gz文件,则无需解压,直接使用 4.1 节的 gzip 版load_mnist,传入仓库内的 code/datasets/mnist/ 目录路径即可。

5.2 用 matplotlib 预览样本

code/ch12/ch12.ipynb 提供了两类可视化:每类首张数字拼接图,以及同一数字「7」的 25 个不同写法。核心代码(每类首张样本)如下:

import matplotlib.pyplot as plt fig, ax = plt.subplots(nrows=2, ncols=5, sharex=True, sharey=True,) ax = ax.flatten() for i in range(10): img = X_train[y_train == i][0].reshape(28, 28) ax[i].imshow(img, cmap='Greys', interpolation='nearest') ax[0].set_xticks([]) ax[0].set_yticks([]) plt.tight_layout() plt.show()

这里的技巧是X_train[y_train == i][0].reshape(28, 28):先用布尔索引选出类别i的全部样本,取第一个(即每类的「首张」),再还原为 28×28 矩阵交给imshow渲染。通过可视化可以直观确认解析正确性——例如「1」应有竖直笔画、「7」应有顶部横杠,从而在进入训练环节前完成数据校验。

六、在项目中的实战应用:第 12 章 MLP 与第 13 章 Keras

6.1 第 12 章:从零实现多层感知机

第 12 章(code/ch12/ch12.ipynb 及 code/ch12/neuralnet.py、code/ch12/optional-streamlined-neuralnet.py)使用 NumPy 从零实现 MLP 反向传播,MNIST 是其目标数据集。加载后的 784 维输入直接喂给输入层,输出层 10 个单元对应 0~9 十个类别,通过 one-hot 编码构造目标矩阵。

6.2 第 13 章:Keras + Theano 快速实现

第 13 章提供了可直接运行的脚本 code/ch13/mnist_keras_mlp.py,其加载函数与第 12 章同源(struct+np.fromfile),训练部分则基于 Keras 顺序模型:

X_train, y_train = load_mnist('mnist', kind='train') X_test, y_test = load_mnist('mnist', kind='t10k') X_train = X_train.astype(theano.config.floatX) X_test = X_test.astype(theano.config.floatX) y_train_ohe = np_utils.to_categorical(y_train) model = Sequential() model.add(Dense(input_dim=X_train.shape[1], output_dim=50, init='uniform', activation='tanh')) model.add(Dense(input_dim=50, output_dim=50, init='uniform', activation='tanh')) model.add(Dense(input_dim=50, output_dim=y_train_ohe.shape[1], init='uniform', activation='softmax')) sgd = SGD(lr=0.001, decay=1e-7, momentum=.9) model.compile(loss='categorical_crossentropy', optimizer=sgd) model.fit(X_train, y_train_ohe, nb_epoch=50, batch_size=300, verbose=1, validation_split=0.1, show_accuracy=True) y_train_pred = model.predict_classes(X_train, verbose=0) train_acc = np.sum(y_train == y_train_pred, axis=0) / X_train.shape[0] print('Training accuracy: %.2f%%' % (train_acc * 100)) y_test_pred = model.predict_classes(X_test, verbose=0) test_acc = np.sum(y_test == y_test_pred, axis=0) / X_test.shape[0] print('Test accuracy: %.2f%%' % (test_acc * 100))

几个可直接复用的参数要点:

  • 网络结构:784 → 50(tanh)→ 50(tanh)→ 10(softmax),构成三层全连接;
  • one-hot 编码np_utils.to_categorical(y_train)把 0~9 整数标签转为 10 维 0/1 向量,与 softmax 输出层 +categorical_crossentropy损失函数配套;
  • SGD 配置:学习率lr=0.001、权重衰减decay=1e-7、动量momentum=0.9
  • 训练配置:50 个 epoch、batch 300、10% 验证集;
  • 精度计算:用predict_classes取概率最大类别,与真实标签逐位比较后求均值。

6.3 启用 GPU 加速运行

code/ch13/ch13.ipynb 给出的 GPU 运行命令(依赖 Theano 后端,注意这是该书第 1 版对应的旧式 Theano/Keras 环境):

THEANO_FLAGS=mode=FAST_RUN,device=gpu,floatX=float32 python mnist_keras_mlp.py

其中floatX=float32与脚本中theano.config.floatX的用法一致——将像素数据转为单精度浮点以适配 GPU 计算;若在 CPU 上运行,去掉device=gpu即可。

七、扩展加载工具:mlxtend 的 load_mnist

README 还提到作者在其开源机器学习扩展包 mlxtend 中提供了现成的便捷函数:load_mnist(将 MNIST 数据直接加载为 NumPy 数组)与mnist_data(从字节形式解析 MNIST)。其底层原理与上文手写实现一致——解析 IDX 魔数头、读取 uint8 字节流、重塑为 784 维特征矩阵。读者若不想手写解析逻辑,可借助这类现成工具;而理解本仓库中的struct.unpack实现,则有助于在无第三方依赖时独立完成数据加载。

八、小结:MNIST 在本仓库中的完整使用路径

围绕 code/datasets/mnist/README.md,MNIST 的完整使用链路可以归纳为:

  1. 数据落盘:使用仓库随附的 code/datasets/mnist/ 下四个.gz文件,或从 LeCun 的 MNIST 官方数据库下载同名文件(README 中给出的参考文献);
  2. 解压/直读:执行gzip *ubyte.gz -d解压,或直接用 gzip 版load_mnist直读压缩包;
  3. 解析为 NumPy:通过struct.unpack跳过文件头,np.fromfile/np.frombuffer得到(60000, 784)训练矩阵与(10000, 784)测试矩阵;
  4. 可视化校验reshape(28, 28)+imshow抽查各类别样本;
  5. 训练与评估:第 12 章 NumPy MLP(code/ch12/neuralnet.py)或第 13 章 Keras MLP(code/ch13/mnist_keras_mlp.py),最后输出训练/测试精度。

掌握这套「IDX 二进制 → NumPy 矩阵 → 神经网络」的数据管线,是理解深度学习入门实验的基础,也可以直接迁移到任何使用 MNIST 及其变体(如 Fashion-MNIST)的场景中。

【免费下载链接】python-machine-learning-bookThe "Python Machine Learning (1st edition)" book code repository and info resource项目地址: https://gitcode.com/gh_mirrors/py/python-machine-learning-book

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询