文章目录
-
- [01 本篇要解决什么问题](#01 本篇要解决什么问题)
- [02 背景:同样是28×28,分类难点已经改变](#02 背景:同样是28×28,分类难点已经改变)
- [03 实操:设计一个有边界的比较实验](#03 实操:设计一个有边界的比较实验)
- [04 一个具体例子:一条命令训练两个模型](#04 一个具体例子:一条命令训练两个模型)
- [05 常见问题与自测](#05 常见问题与自测)
- [06 本篇回顾与下一步](#06 本篇回顾与下一步)
01 本篇要解决什么问题
跑通MNIST以后,很容易想试试更大的模型。但一个模型的准确率比另一个高,究竟是结构带来的,还是训练轮数、样本划分或数据增强不同?
本篇使用Fashion-MNIST,让一个MLP和一个小CNN完成同一任务。除了训练,还要把"怎样比较"这件事做清楚。
- 本篇关键词:Fashion-MNIST、MLP、CNN、公平比较、错分分析。
- 完成标志:用同一份划分训练两个模型,分别保存权重和结果,形成可复查的比较。
- 运行约定 :保留完整
examples目录,命令从练习根目录执行;依赖沿用第12篇。
02 背景:同样是28×28,分类难点已经改变
Fashion-MNIST包含60000张训练图和10000张测试图,每张为28×28灰度图,共10类服装。发布方提供文件、校验和及类别说明,见Fashion-MNIST作者仓库。
类别包括T恤、裤子、套头衫、连衣裙、外套、凉鞋、衬衫、运动鞋、包和短靴。低分辨率下,某些服装轮廓接近,单靠"整体像一个形状"可能不够。
这里可以沿用数字识别的数据流程,但不能沿用数字类别的解释。项目必须把真实的类别映射随权重一起保存。
03 实操:设计一个有边界的比较实验
(1)先下载,沿用固定划分
powershell
python examples/download_data.py --dataset fashion --data data
代码使用发布方GitHub数据文件作为优先镜像,并保留作者原始下载站作为备用,仍检查原始文件校验和。
官方训练部分按类别划为约54000训练、6000验证,官方10000测试保留。两个模型共用同一份索引;如果缩小数据规模,也共用同一份子集。
(2)MLP先把图像展平成向量
下面的模型把784个像素当作输入特征,经过一个128维隐藏层,再输出10个类别分数。
python
from torch import nn
class FashionMLP(nn.Module):
def __init__(self):
super().__init__()
self.layers = nn.Sequential(nn.Flatten(), nn.Linear(28 * 28, 128),
nn.ReLU(), nn.Linear(128, 10))
def forward(self, x):
return self.layers(x)
它有101770个参数,计算直接,适合作为起点。但展平之后,网络没有显式采用卷积中的局部连接与权重共享机制。
(3)CNN保留二维邻域信息
CNN使用第12篇的GrayCNN(classes=10):两次卷积与池化后接分类头。它在不同位置重复使用卷积核,有机会利用局部边缘和纹理。
本版CNN有114314个参数,与MLP处于相近量级,但并不完全相同。因此这个实验是两个具体配置的比较,不能解释成"只改变一种因素、其余完全相等"的严格结构消融。
卷积带来的先验也不代表任何设置下都必然更好。训练是否充分、优化器是否合适、样本规模多大,都可能改变结论。
(4)控制能控制的条件
| 条件 | 本篇约定 |
|---|---|
| 数据划分、使用数量 | 两个模型完全相同 |
| 预处理 | 灰度浮点、统一缩放与标准化 |
| 随机增强 | 两个模型均不使用 |
| 优化器 | Adam,相同初始学习率 |
| batch size与轮数 | 使用同一组参数 |
| 批次顺序 | 每个模型重新设置同一数据加载随机种子 |
| 最优权重 | 各自按验证损失最小选择 |
模型初始化使用相同种子,方便重复实验,但不同结构不会因此得到一一对应的相同初始权重。这里先做一次可复查的比较;如果要形成更可靠结论,还应在多个种子下报告均值与波动。
(5)比较指标,同时查看错误样本
总体准确率适合快速观察,但建议同时看macro-F1和逐类召回率。某个类别预测困难时,混淆矩阵能帮助定位它通常被分成哪一类。
不要预先认定某几类一定混淆。先从本次的predictions.csv和错分图中找到证据,再回看这些类别的轮廓、局部纹理和遮挡情况。
不同模型的计算成本也值得记录。本篇输出参数量与本次总耗时;总耗时包含评价和文件输出,不能直接当作纯推理延迟。需要比较部署速度时,应另做同设备、同批次和统一预热的测量。
(6)从小规模检查过渡到完整比较
powershell
python examples/compare_fashion.py --epochs 1 --limit-train 1024 --limit-val 256 --limit-test 256
正式使用完整划分时:
powershell
python examples/compare_fashion.py --epochs 5 --output artifacts/13_fashion_full
一轮小样本结果主要确认两个流程都正常,不能据此给出结构优劣的普遍结论。即使固定轮数相同,两个模型也未必都已充分收敛,应结合训练与验证曲线解释。

图:本篇原创比较设计图,列出两个模型共享与不同的部分。
04 一个具体例子:一条命令训练两个模型
主入口是examples/compare_fashion.py。数据只加载和划分一次,再分别创建模型、重置训练随机状态并保存到独立子目录。
python
"""Chapter 13: compare two models using identical splits and training budgets."""
import copy
from project_common import parser_for, validate_args, seed_everything, run_experiment, write_json
from project_data import load_data, preprocessing
from project_models import build_model
def main():
parser = parser_for(__doc__,"artifacts/13_fashion",epochs=5,batch_size=128)
args = parser.parse_args()
validate_args(parser,args)
data,classes,manifest = load_data("fashion",args)
results = {}
for name,spec in [("mlp",{"kind":"fashion_mlp"}),
("cnn",{"kind":"gray_cnn","classes":10})]:
seed_everything(args.seed,args.threads)
current = copy.copy(args)
current.output = args.output/name
result = run_experiment(build_model(spec),spec,data,classes,manifest,
preprocessing("fashion"),current)
results[name] = {"parameters":result["parameters"],"best_epoch":result["best_epoch"],
"test_accuracy":result["test"]["accuracy"],
"test_macro_f1":result["test"]["macro_f1"]}
write_json(args.output/"comparison.json",results)
print(results)
if __name__ == "__main__":
main()
输出目录中的mlp与cnn分别保存最优权重、训练历史、混淆矩阵数据和预测图。顶层comparison.json汇总两者参数量、最优轮次、测试准确率与macro-F1。
powershell
python examples/visualize_run.py --run artifacts/13_fashion/mlp
python examples/visualize_run.py --run artifacts/13_fashion/cnn
python examples/predict_image.py --checkpoint artifacts/13_fashion/cnn/best.pt --image data/my_clothing.png
单图输入也应尽量接近数据集的灰度、背景和主体占比。真实商品照片涉及更复杂背景,后面第15篇会用真实彩色图与迁移学习继续处理这种差异。
公共函数和模型完整代码见配套工程及公共代码附录。本篇不填写预设的"CNN比MLP高几个百分点",比较结果以实际输出为准。
05 常见问题与自测
问题1:给两个模型设同一个seed,实验就完全公平了吗?
还要控制划分、样本数、预处理、训练预算和选择规则。不同结构的初始化也不会因同一个seed变成相同参数。
问题2:为什么这次不先给CNN加很多数据增强?
先让两个起点共享输入条件。后续要研究增强作用,可以固定模型再单独比较有无增强。
问题3:参数量接近,就代表计算量和显存相同吗?
不代表。中间特征、运算方式和输入尺寸也会影响成本,不能只凭参数量判断运行速度。
问题4:能不能只把测试结果更好的模型叫"最佳模型"?
本篇报告两个已确定配置的测试结果。若还要据此不断修改和选择方案,就需要保留新的独立最终评价数据。
问题5:测试macro-F1和Accuracy为什么不同?
它们统计的角度不同。macro-F1逐类计算再等权平均,更容易反映具体类别的短板。
06 本篇回顾与下一步
这次项目增加的能力,是把模型比较组织成一个可解释的实验。结果文件负责记录数值,数据划分和训练约定负责让这些数值有可比较的含义。
| 中文 | 常见英文或写法 |
|---|---|
| 多层感知机 | MLP |
| 归纳偏置 | Inductive Bias |
| 宏平均F1 | Macro-F1 |
| 对照实验 | Controlled Comparison |
下一篇进入32×32彩色自然图像,用适配小图的ResNet学习更复杂的特征。
参考与延伸阅读