🎯 本课核心要解决的问题
我们不再用硬编码规则(比如if有耳朵 then猫),而是教电脑如何**"看"数字** ,并利用数据驱动的方法,让电脑学会给一张图片打上正确的标签。
第一部分:电脑眼中的"图像"到底是什么?(张量基础)
你看到的是猫,电脑看到的是一堆数字(0~255)。
-
灰度图 :是一个 2维矩阵(高,宽),每个格子代表该位置的亮度(0纯黑,255纯白)。
-
彩色图(RGB) :是 3维张量 (高,宽,通道)。相当于把红、绿、蓝三张灰度图叠在一起。比如
(32, 32, 3)代表一张 32x32 的彩色图。
| 维度 | 数学名称 | 深度学习叫法 | 形状举例(通俗理解) |
|---|---|---|---|
| 0维 | 标量 | 一个数字 | 损失值 loss = 0.43 |
| 1维 | 向量 | 特征数组 | (3072,) ------ 一张图拉直后的像素串 |
| 2维 | 矩阵 | 灰度图 / 表格 | (32, 32) ------ 一张黑白小图 |
| 3维 | 张量 | 一张彩色图 | (32, 32, 3) ------ 一张RGB彩图 |
| 4维 | 张量 | 一个批次的图 | (N, 32, 32, 3) ------ N张彩图一起送进电脑 |
在 PyTorch 中,维度顺序是
(N, C, H, W)(即:批次,通道,高,宽)。上面表格里的(高, 宽, 通道)是Numpy的习惯。务必记得用.shape检查,否则程序会报错!
第二部分:图像分类面临的 6 大"死穴"(为什么这么难?)
因为像素数字随外部条件剧烈变化,导致同一物体数字天差地别:
-
视角变化:正面猫和侧面猫的数字完全不同。
-
光照变化:白天和黑夜的像素值差很多。
-
形变:猫伸懒腰和缩成球,姿态不同。
-
遮挡:猫躲在椅子后面,只有一半像素可见。
-
背景杂乱:猫和地毯颜色一样,数字混在一起。
-
类内差异:橘猫和狸花猫长得根本不像。
第三部分:解法------数据驱动方法(Data-Driven Approach)
核心认知:无法通过硬编码(Hard-coding)规则来定义"什么是猫"。
必须交给算法从数据中学习。
既然没法写死规则,那就把问题转化为 "喂数据"。
标准三步流程(像极了考试复习):
-
收集数据(教材):收集大量带标签的图片(比如1000张猫图)。
-
训练(背题库):把图片和标签塞给算法,让它总结规律(得到一个模型)。
-
评估(上考场) :给一张从未见过的新图,让模型猜它是啥。
python
# 伪代码长这样
def train(images, labels):
# 学习一个模型(比如记住所有图片)
return model
def predict(model, test_image):
# 用模型猜新图是啥
return predicted_label
第四部分:第一个分类器------最近邻(Nearest Neighbor)
这是最原始、最简单的非参数化分类器。
1. 训练阶段
训练函数极其"偷懒",仅仅是记忆所有训练数据及其标签,时间复杂度 O(1)。
2. 预测阶段
将测试图像与所有记忆的训练图像逐一比较,找出最相似的(距离最近),返回其标签。时间复杂度 O(N)(N为训练集大小),在大规模数据上预测速度极慢。
3. 距离度量(L1 与 L2)
比较两张图像的常用方法:
-
L1 距离(曼哈顿距离) :对应像素差的绝对值之和。公式:
(
,
)=
。
-
L2 距离(欧几里得距离) :对应像素差的平方和的平方根。公式:
(
,
)=
。
核心思想:近朱者赤,近墨者黑。
新图来了,你跑遍所有老图,找到那张长得最像的(距离最近),它是什么标签,新图就是什么标签。
💡 手算示例:怎么算"长得最像"?(L1距离 / 曼哈顿距离)
假设我们有两张 2x2 的超小灰度图(为了好算)。
-
老图A (标签是猫):
[10, 20; 30, 40] -
新图B (未知):
[12, 18; 28, 44]
计算"不像程度":把对应位置的数字相减,取绝对值,最后全部加起来。
-
位置1:|10-12| = 2
-
位置2:|20-18| = 2
-
位置3:|30-28| = 2
-
位置4:|40-44| = 4
-
L1总距离 = 2 + 2 + 2 + 4 = 10(数值越小,代表两张图越相似!)
如果还有一张老图C算出来距离是100,那新图B和这张老图A距离最近(10<100),所以猜新图B是**"猫"**。
📐 L1 与 L2 距离的选择(纠正一个常见的误解)
-
L1距离(曼哈顿):坐标轴上走直线,公式 ∑∣x1−x2∣。
-
L2距离(欧氏距离) :空间中的直线距离,公式
。
⚠️ 关键区别(千万别记反) :L2距离(欧氏距离)具有旋转不变性 。如果你对特征空间做旋转、平移等正交变换,L2距离保持不变。而 L1距离极度依赖坐标轴,一旦特征轴旋转,L1距离的值会发生剧烈改变
- 建议 :如果特征有明确的物理意义(比如像素位置),L1也行;如果特征是抽象的,无脑优先试L2。
从最近邻升级到 K近邻(KNN) :
为了避免因为某一张"噪声老图"而猜错,我们看 K个 最近邻居,让他们民主投票(多数投票)。比如看5个邻居:3个猫,2个狗,最终猜是猫。
第五部分:致命核心------超参数(Hyperparameters)与调参
什么是超参数? 就是你在电脑自己跑起来之前,必须手动拍脑袋定下的数值。比如:
-
KNN里的 K值(到底看几个邻居?K=3还是K=7?)
-
距离公式用 L1 还是 L2?
这些参数极度依赖具体数据集,没有万能答案。
🎓 怎么正确地"拍脑袋"?(绝对禁止作弊!)
把数据集分成三块,记住这个**"高考比喻"**:
-
训练集(平时作业):给模型随便记,用来学习的。
-
验证集(模拟考) :用来调超参数。比如你试了K=3,在模拟考得80分;K=7,模拟考得90分。那你就定下用K=7。
-
测试集(真正的高考) :一生只用一次! 当你最终定下K=7后,只在最后用一次测试集,得出最终真实成绩。
❌ 绝对禁忌(数据泄露) :绝对不许看"高考题(测试集)"来调参数!如果你根据测试集调参数,等于作弊,最后报告的100分是假的,一到现实世界就露馅。
如何正确设置超参数?(三种方式对比)
-
❌ 选择在训练集上表现最好的:绝对不可取。比如 K=1 在训练集上准确率100%,但过拟合严重,泛化能力极差。
-
❌ 选择在测试集上表现最好的 :看似还行,但这是学术大忌(Data Leakage,数据泄露)!因为当你根据测试集调参时,你就把测试集当成了训练的一部分,最终报告的准确率是虚假的,不代表模型在真实世界的能力。
-
✅ 划分出验证集(Validation Set) :这是唯一正确的方法!
-
将原始训练集分为
训练子集和验证集。 -
在训练子集上训练,在验证集上评估不同超参数的表现。
-
选出验证集上表现最好的那组超参数,最后只用一次在真正的测试集上报告最终结果。
-
数据太少怎么办?------ 交叉验证(Cross-Validation)
把训练集切成5份(A,B,C,D,E)。
-
第1次:A当模拟考,B+C+D+E当作业;
-
第2次:B当模拟考,A+C+D+E当作业...
最后算5次模拟考的平均分。哪个K值平均分最高,就定哪个。(注:深度学习数据极大,极少用交叉验证,太费算力)。
第六部分:进入现代深度学习------线性分类器(Linear Classifier)------神经网络的基石
**参数化分类器(Parametric Classifier)**的入门
最近邻太笨了(每次猜都要跑遍全城,速度极慢)。深度学习的基石是这个公式:
得分(分数)=权重(W)×像素(x)+偏置(b)得分(分数)=权重(W)×像素(x)+偏置(b)
💡 手算示例:像"面试打分"一样理解
假设我们要区分3种东西(猫、狗、船)。一张彩色图拉直后有 4个像素值(为了好算)。
-
输入图 x =
[56, 231, 10, 89](展平后的4个数字)。 -
权重 W(3行4列的表格,由电脑瞎猜的初始值,后面会调整):
| 类别 \ 像素 | 像素1 | 像素2 | 像素3 | 像素4 |
|---|---|---|---|---|
| 猫 | 0.2 | -0.5 | 0.1 | 1.0 |
| 狗 | 0.5 | 0.1 | -0.3 | 0.8 |
| 船 | -0.1 | 0.9 | 0.7 | -0.4 |
- 偏置 b (类似老板的心情分):猫=
1,狗=2,船=-1。
开始算分!
-
猫的得分 = (56×0.2) + (231×-0.5) + (10×0.1) + (89×1.0) + 1
= 11.2 + (-115.5) + 1 + 89 + 1 = -13.3分
-
狗的得分 = (56×0.5) + (231×0.1) + (10×-0.3) + (89×0.8) + 2
= 28 + 23.1 - 3 + 71.2 + 2 = 121.3分
结论 :这张图得分最高的是 121.3分(狗),所以线性分类器猜它是"狗"。(虽然现在可能猜错,但后面我们会通过"损失函数"和"优化"来调整W和b,让猫的分数变高)。
1. 数学公式
f(x,W)=Wx+b
-
x :输入图像。将 32x32x3 的图像展平成一个 3072维 的列向量。
-
W :权重矩阵(Weights) 。维度为
[10 x 3072]。这是模型要学习的核心参数。 -
b :偏置向量(Bias) 。维度为
[10 x 1]。它独立于输入 x,允许分类器在不经过原点的情况下进行划分。
2. 输出解释
对于CIFAR-10(10个类别),上述公式会输出一个 10维向量,每个维度的数值代表该类别的"得分(Score)"。得分越高,表示模型越认为图像属于该类。
3. 几何视角(超平面)
-
线性分类器在三维/高维空间中,是在寻找一个超平面(Hyperplane) 来分隔不同类别的数据。
-
偏置 b 的作用:如果没有偏置项,所有的超平面都必须硬性通过原点(坐标轴交点),这会严重限制分类器的表达能力。有了 bb,超平面可以自由平移,从而拟合更复杂的数据分布。
4. 线性分类器的致命局限
它只能学习线性可分的数据。对于在二维平面上呈同心圆分布、或螺旋交叉分布的数据,线性分类器无能为力(后续的神经网络通过堆叠多层线性层(+非线性激活函数)来解决)。
第七部分:损失函数(Loss)与 Softmax ------ 把分数变成"痛苦程度"
现在模型有了分数,但它怎么知道自己猜得好不好 ?我们需要一个 "痛苦指标(损失函数 Loss)" ,分数越高越不痛苦,分数越低越痛苦。训练的目标就是最小化损失函数
针对CIFAR-10的多分类问题,第二课重点讲了两大损失函数:
1. Softmax:把"得分"变成"百分比(概率)"(多项逻辑回归 / 交叉熵损失)
思想 :将得分 ss 映射为概率分布,我们希望正确类别的概率无限接近于 1。
刚才的分数有负数有正数(-13.3和121.3),加起来也不等于100%,看着不直观。Softmax两步把它变成概率:
第一步:取指数(exex) ------ 把负数变正数,且放大分数差距。
P(Y=k|X=) =
假设指数化后:猫=1,狗=100,船=2。
第二步:归一化(除以总数) ------ 算出各自百分比。
-
猫的概率 = 1 ÷ (1+100+2) = 0.97%
-
狗的概率 = 100 ÷ (1+100+2) = 97.1%
-
船的概率 = 2 ÷ (1+100+2) = 1.9%
现在能说"这张图有97.1%的概率是狗"了,非常直观!
计算损失(Cross-Entropy Loss / 交叉熵损失):
Li=−log(P(Y=yi∣X=xi))
当正确类别的概率趋近于1时,−log(1)→0−log(1)→0,损失最小化
-
如果这张图的正确答案是狗 ,模型猜对的概率是 97.1%。损失 = -log(0.971) ≈ 0.03(痛苦值极低,近乎为0,猜得很爽)。
-
如果这张图的正确答案是猫 ,模型猜对的概率是 0.97%。损失 = -log(0.0097) ≈ 4.6(痛苦值极高,模型很痛苦,需要赶紧调整W)。
2.SVM 损失(铰链损失 / Hinge Loss)
-
思想 :正确类别的得分不仅要高,而且至少要比错误类别的得分高出一个安全边际(Margin,通常设为1)。
-
公式 :对于第 ii 个样本,损失为:
其中
是第 j 个类别的得分,
是正确类别的得分。
-
特点:对单个异常值较敏感,但损失函数是凸的,容易优化。
📝 补充(回应你笔记里的困惑) :
对于CIFAR-10这种单标签多分类 (一张图只会是猫/狗/船中的一种),我们用的是 Softmax + 多类交叉熵 。BCE(二元交叉熵) 是给二分类用的,别记混。
KL散度(KL Divergence) 用于衡量两个分布(真实分布 PP 和预测分布 QQ)的差异。在分类问题中,真实标签是独热编码(One-hot) ,此时的交叉熵损失在数学上等价于最小化KL散度。
BCE(二元交叉熵,Binary Cross Entropy) 是专用于二分类 (或多标签分类)的损失函数。对于CIFAR-10这种单标签多分类(Mutually Exclusive) 问题,我们用的是 Softmax + 多类交叉熵(Categorical Cross-Entropy) ,不要混用。
🧠 终极认知闭环(本节课逻辑大串联)
-
图像分类的本质:给电脑输入一串像素数字(张量),输出标签。
-
最近邻(KNN):新图算L1/L2距离,找最像的K个老图投票。缺点:预测慢,必须用验证集调K。
-
超参数调优 :绝对禁止看测试集!用验证集(模拟考) 或交叉验证来选参数。
-
线性分类器 :
得分 = W×x + b。这是神经网络的砖块,通过画线(超平面)切分数据。 -
Softmax + 损失 :把得分变成概率(百分比),再用 负对数(-log) 计算模型的"痛苦值"。可电脑用梯度下降自动把痛苦值降为0。
💡建议
-
KNN别写for循环 :算距离一定要用Numpy的向量化(矩阵运算),否则代码慢到怀疑人生。
-
跑代码前检查维度 :PyTorch要求
(N, C, H, W),如果传错了会报RuntimeError: Expected 4D input,那时候记得把维度调换过来。