【深度学习项目实战·13】服装图像分类:在相同条件下比较MLP与CNN

文章目录

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学习更复杂的特征。

参考与延伸阅读

相关推荐
微尘hjx14 小时前
【Deep-OC-SORT 01】多轨迹算法Deep-OC-SORT源码分析
深度学习·yolo·目标跟踪·ultralytics·轨迹算法·deep-oc-sort·车流统计
tellmewhoisi15 小时前
深度学习39:RNN基础介绍,api参数解惑和代码api
人工智能·rnn·深度学习
武天旭16 小时前
AI安全--AI大模型的毒性偏见与安全对齐实践
人工智能·python·深度学习
电科_银尘17 小时前
【深度学习项目实战·11】损失函数与评价指标:让模型输出、标签与结果真正对应
人工智能·深度学习
陈嘿萌19 小时前
ECCV 2026 | CausalDrive:澳门大学×小米汽车,面向自动驾驶的实时因果世界模型
图像处理·人工智能·深度学习·计算机视觉·自动驾驶·学术研究与理论基础
七元权20 小时前
FoundationPose 推理全流程解读:从一帧 RGB-D 到 6D 位姿
论文阅读·深度学习·6d姿态估计
Neurocoda1 天前
基于 NumPy 从零实现 Tiny-AlexNet 在 MNIST 数据集上的验证
人工智能·深度学习
AOI小白新手上路1 天前
深度学习算力购置方案分析:本地 RTX 4090 服务器 vs 云端租赁
服务器·人工智能·深度学习
坐吃山猪1 天前
果蝇AI06-Mac部署实操
人工智能·深度学习·机器学习·果蝇ai