上一节我们用二分类的思维把任务拆成了“是/否”两个输出,很多读者朋友反馈说:换成10类就懵了,有的直接把最后的sigmoid换成了10个输出,loss反而乱跳,准确率卡在30%上下不去。这其实是把多分类理解成了“多个二分类”导致的,概念上就差了一层。这一节“耿直哥深度学习4-8”我就带着大家把多分类问题的完整代码实现从头到尾捋一遍,数据集用Fashion-MNIST(10类衣物),模型用两层卷积神经网络,训练完输出准确率、分类报告和混淆矩阵,整个过程结束你手上会有一套能直接迁移到自己数据集上的多分类代码模板。
这套代码的核心点有三个:输出层用softmax做概率分布、损失函数用交叉熵、评估阶段用混淆矩阵看细节。我会把每一步为什么这么写的理由也一起讲清楚,不只是给你一段能跑通的代码。适合已经跑通MNIST手写数字、但对多分类的设计逻辑还停留在“改个数就能跑”阶段的朋友,也适合那些被网上零散代码坑过、想系统整理一遍训练评估流程的同学。
1. 多分类任务的整体设计与思路拆解
1.1 多分类和二分类的本质差异
二分类模型输出的是一个值,经过sigmoid映射到0到1之间,大于0.5判为正类,小于0.5判为负类,本质上是“一个事件发生/不发散”的概率。
多分类面对的是“互斥的多个类别”,比如Fashion-MNIST中一张图要么是T恤、要么是裤子、要么是连衣裙,不可能同时是两样。这种情况直接用多个sigmoid输出会产生一个问题:每个输出都是独立的,模型可能对三个类别都输出0.7,加起来超过1,这不满足概率分布的基本性质,也无法直接解释成“这个样本属于各类别的概率”。
解决方式是输出层接softmax。softmax做的事情很简单:把所有类别的原始得分(logits)做指数归一化,得到一组非负、并且总和正好等于1的输出。你可以把它想成一个抽奖箱里的10个格子,无论如何最终必须有一个球落在某个格子里,所有格子的概率加起来永远是100%。这样的输出天然适合做多分类的判别依据。
1.2 损失函数为什么选交叉熵而不是均方误差
二分类常用的损失函数是BCELoss(二元交叉熵),多分类对应的就是CrossEntropyLoss。为什么要坚持用交叉熵,而不是把输出换成softmax之后继续用均方误差(MSE)?核心在于梯度传播的特性。
softmax函数在输入特别大或特别小时,输出会趋近于0或1,此时如果配合MSE计算损失,梯度会被压缩得非常小,导致模型学习速度急剧变慢,甚至看起来像卡住了。而交叉熵损失在预测概率与真实标签差距大的时候能给出较大的梯度,推动模型快速修正,这正是分类任务所需要的。
还有一个实操上的细节:PyTorch的CrossEntropyLoss内部已经帮我们做了softmax操作。也就是说,你在模型最后的全连接层输出10个原始得分,直接把这个得分交给CrossEntropyLoss,它会自动计算softmax再算损失。所以模型定义里最后一个Linear层的输出不需要手动再套一层softmax,只有在推理或者画概率分布时才需要单独调用。
1.3 数据集与任务选型
这一节选Fashion-MNIST而不是经典的MNIST手写数字,原因是MNIST太简单了,随便一个线性模型都能到90%以上的准确率,根本体现不出多分类调参的乐趣和坑。Fashion-MNIST同样是28x28的灰度图,但图像内容是T恤、裤子、套头衫、连衣裙、外套、凉鞋、衬衫、运动鞋、包、短靴这10类,类别之间的区分难度明显更大,尤其是T恤、套头衫和衬衫这三类,人眼都容易看错,模型产生混淆是正常的。
数据规模方面,Fashion-MNIST有60000张训练图、10000张测试图,图像尺寸小,训练速度快,在一张普通消费级显卡上十几分钟就能跑完15轮,非常适合拿来走通整个多分类流程。换句话说,这个任务设计的目的是让你把注意力放在“多分类代码怎么写、评估怎么做、问题怎么排查”上,而不是等训练等到天荒地老。
1.4 模型结构与整体流程规划
多分类任务在流程上比二分类多了两个环节:一是评估阶段要逐类看precision、recall和f1,二是要画混淆矩阵观察哪些类容易互相混。整体流程是数据加载、模型定义、训练、验证、测试、逐类评估、混淆矩阵分析,最后针对混淆严重的类别做进一步优化。
模型部分我用的是一个轻量CNN:两个卷积块加两个全连接层。每个卷积块包含卷积、批归一化、ReLU激活和最大池化,最后的全连接输出10维。这个结构在Fashion-MNIST上足够用了,大约80万参数,训练快,同时不会因为模型过小导致欠拟合。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 环境准备与数据加载细节
2.1 目标环境与依赖库
动手之前先把环境确认好。我这里用的是Python 3.9和PyTorch 2.0,实际上PyTorch 1.10以上版本都能跑通全部代码。除了PyTorch之外还需要torchvision、matplotlib和scikit-learn。scikit-learn主要是用来算classification_report和confusion_matrix的,如果你不想引入这个依赖,也可以自己手写这些评估函数,但不建议,既然有现成且稳定的工具,直接用就好。
如果你还没装好PyTorch环境,我的建议是先创建一个干净的虚拟环境再装,别把系统Python搞乱了。Windows、Linux、macOS都能跑,CPU也能训完这个任务,只是慢一些。实测一个epoch在CPU上大约30到40秒,15轮大约8分钟左右,完全可以接受。
2.2 数据加载与预处理完整代码
python复制import torch
import torch.nn as nn
import torch.optim as optim
from torch.utils.data import DataLoader
from torchvision import datasets, transforms
import matplotlib.pyplot as plt
from sklearn.metrics import classification_report, confusion_matrix
# 数据处理:转Tensor + 归一化
transform = transforms.Compose([
transforms.ToTensor(),
transforms.Normalize((0.2860,), (0.3530,))
])
# 训练集和测试集
train_dataset = datasets.FashionMNIST(
root='./data', train=True, download=True, transform=transform
)
test_dataset = datasets.FashionMNIST(
root='./data
