Deep Learning for Computer Vision——Image Classification with Linear Classifiers

🎯 本课核心要解决的问题

我们不再用硬编码规则(比如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 大"死穴"(为什么这么难?)

因为像素数字随外部条件剧烈变化,导致同一物体数字天差地别:

  1. 视角变化:正面猫和侧面猫的数字完全不同。

  2. 光照变化:白天和黑夜的像素值差很多。

  3. 形变:猫伸懒腰和缩成球,姿态不同。

  4. 遮挡:猫躲在椅子后面,只有一半像素可见。

  5. 背景杂乱:猫和地毯颜色一样,数字混在一起。

  6. 类内差异:橘猫和狸花猫长得根本不像。

第三部分:解法------数据驱动方法(Data-Driven Approach)

核心认知:无法通过硬编码(Hard-coding)规则来定义"什么是猫"。

必须交给算法从数据中学习。

既然没法写死规则,那就把问题转化为 "喂数据"

标准三步流程(像极了考试复习):

  1. 收集数据(教材):收集大量带标签的图片(比如1000张猫图)。

  2. 训练(背题库):把图片和标签塞给算法,让它总结规律(得到一个模型)。

  3. 评估(上考场) :给一张从未见过的新图,让模型猜它是啥。

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

这些参数极度依赖具体数据集,没有万能答案。

🎓 怎么正确地"拍脑袋"?(绝对禁止作弊!)

把数据集分成三块,记住这个**"高考比喻"**:

  1. 训练集(平时作业):给模型随便记,用来学习的。

  2. 验证集(模拟考)用来调超参数。比如你试了K=3,在模拟考得80分;K=7,模拟考得90分。那你就定下用K=7。

  3. 测试集(真正的高考)一生只用一次! 当你最终定下K=7后,只在最后用一次测试集,得出最终真实成绩。

绝对禁忌(数据泄露) :绝对不许看"高考题(测试集)"来调参数!如果你根据测试集调参数,等于作弊,最后报告的100分是假的,一到现实世界就露馅。

如何正确设置超参数?(三种方式对比)

  1. ❌ 选择在训练集上表现最好的:绝对不可取。比如 K=1 在训练集上准确率100%,但过拟合严重,泛化能力极差。

  2. ❌ 选择在测试集上表现最好的 :看似还行,但这是学术大忌(Data Leakage,数据泄露)!因为当你根据测试集调参时,你就把测试集当成了训练的一部分,最终报告的准确率是虚假的,不代表模型在真实世界的能力。

  3. ✅ 划分出验证集(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)不要混用

🧠 终极认知闭环(本节课逻辑大串联)

  1. 图像分类的本质:给电脑输入一串像素数字(张量),输出标签。

  2. 最近邻(KNN):新图算L1/L2距离,找最像的K个老图投票。缺点:预测慢,必须用验证集调K。

  3. 超参数调优 :绝对禁止看测试集!用验证集(模拟考)交叉验证来选参数。

  4. 线性分类器得分 = W×x + b。这是神经网络的砖块,通过画线(超平面)切分数据。

  5. Softmax + 损失 :把得分变成概率(百分比),再用 负对数(-log) 计算模型的"痛苦值"。可电脑用梯度下降自动把痛苦值降为0。

💡建议

  1. KNN别写for循环 :算距离一定要用Numpy的向量化(矩阵运算),否则代码慢到怀疑人生。

  2. 跑代码前检查维度 :PyTorch要求 (N, C, H, W),如果传错了会报 RuntimeError: Expected 4D input,那时候记得把维度调换过来。

相关推荐
AINative软件工程1 小时前
LLM API 成本失控怎么办?工程师的实时异常检测指南
python
练习两年半的攻城狮1 小时前
LlamaIndex ResponseMode 深度解析
python·llamaindex
是上好佳佳佳呀1 小时前
【深度学习|DAY03】神经网络深度学习笔记(上):框架总览、参数初始化与激活函数
笔记·深度学习·神经网络
阿pin1 小时前
Java随笔-红黑树
java·python·算法·红黑树
Hi李耶1 小时前
【LeetCode】17.电话号码的字母组合
算法·leetcode·职场和发展
探物 AI1 小时前
yolo检测中的激活函数19:ReLU激活函数 (Rectified Linear Unit)
网络·人工智能·深度学习·yolo
AI人工智能+1 小时前
智能文档抽取系统通过“视觉感知+大模型认知“双引擎架构,实现非结构化文档的自动化处理
深度学习·计算机视觉·语言模型·自然语言处理·ocr·文档抽取
2603_965148112 小时前
eBay商品数据API:寻找海外仓与价格洼地
大数据·人工智能·windows·python·microsoft