跳转至

Lec 3: Linear Classifiers

2360 个字 4 行代码 预计阅读时间 24 分钟

Overview

这一讲开始从“记住全部训练样本”的 kNN,转向“学习一组参数”的分类器。

核心问题是:给定一张图片 \(x\),怎样通过一组可学习参数直接输出每个类别的分数?

线性分类器就是最基础的答案:

\[ f(x, W, b) = Wx + b \]

其中:

  • \(x \in \mathbb{R}^D\) 表示输入图像展平后的向量
  • \(W \in \mathbb{R}^{C \times D}\) 表示权重矩阵
  • \(b \in \mathbb{R}^{C}\) 表示偏置项
  • \(f(x, W, b) \in \mathbb{R}^{C}\) 表示每个类别的分数

对于 CIFAR-10,输入图像大小为 \(32 \times 32 \times 3 = 3072\),如果有 10 个类别,那么:

\[ W \in \mathbb{R}^{10 \times 3072}, \quad b \in \mathbb{R}^{10} \]

模型输出 10 个分数,分数最大的类别就是预测结果。

From kNN to Parametric Model

kNN 的思路是在测试时拿新图像和所有训练图像逐个比较,因此:

  • 训练几乎没有成本
  • 预测成本很高
  • 很依赖距离度量
  • 很难从数据中“抽象出规律”

线性分类器则相反:

  • 训练阶段学习参数 \(W, b\)
  • 测试阶段只需做一次矩阵乘法
  • 将知识压缩进参数,而不是记住全部样本

这就是参数化模型(parametric model)的思想。

Interpreting Linear Classifiers

线性分类器可以从两个角度理解。

Template Matching View

\(W\) 的每一行看成某个类别的一张“模板”。

对某个类别 \(j\),它的分数可以写成:

\[ s_j = W_j x + b_j \]

这里的点积可以理解成“输入图像与该类别模板的匹配程度”。匹配越强,得分越高。

这种观点能解释为什么线性分类器经常学出一些粗糙的“原型图案”:

  • ship 类,可能会偏向学习蓝色背景和水平边缘
  • car 类,可能会偏向学习轮廓、轮子、路面背景
  • horse 类,可能会试图把多种姿态揉成一个平均模板

这也解释了线性模型的一个弱点:一个类别通常只能学到有限的、单一的线性模板,难以覆盖复杂的类内变化。

Geometric View

从几何角度看,线性分类器是在高维空间里用超平面划分类别。

对于二分类,决策边界可以写成:

\[ W x + b = 0 \]

在二维空间里这是一条直线,在三维空间里是一个平面,在更高维里就是超平面。

因此线性分类器只能学习线性决策边界。

线性模型的根本局限

如果数据本身不是线性可分的,那么无论怎样调整参数,线性分类器都无法得到理想结果。

最经典的例子就是 XOR 问题:两个类别无法被一条直线分开。

Bias Trick

通常我们会把偏置项 \(b\) 合并进权重矩阵中,便于统一表示。

做法是给输入向量补一个常数维度 1

\[ x' = [x; 1], \quad W' = [W \; b] \]

这样公式可以写成:

\[ f(x) = W'x' \]

实现上这样更方便,数学上本质不变。

Loss Function

模型有了,但我们还不知道怎样判断一组参数好不好。

这时需要损失函数(loss function

对单个样本 \((x_i, y_i)\),其损失写作:

\[ L_i = L(f(x_i, W), y_i) \]

整个数据集上的平均损失为:

\[ L = \frac{1}{N} \sum_{i=1}^{N} L_i \]

第三讲主要介绍两类经典损失:

  • Multiclass SVM loss
  • Softmax loss

Multiclass SVM Loss

SVM loss 也常叫 hinge loss,它的核心想法非常直接:

正确类别的分数不仅要最大,还要比错误类别至少大一个 margin \(\Delta\)

设样本 \(x_i\) 的分数向量为 \(s = f(x_i, W)\),正确类别为 \(y_i\),则单样本损失:

\[ L_i = \sum_{j \neq y_i} \max(0, s_j - s_{y_i} + \Delta) \]

其中通常取 \(\Delta = 1\)

Intuition

对于每个错误类别 \(j\)

  • 如果 \(s_j - s_{y_i} + \Delta \le 0\),说明正确类别已经领先足够多,这一项损失为 0
  • 如果该值大于 0,说明间隔不够,需要惩罚

也就是说,SVM loss 关注的是“间隔是否足够大”,而不直接关心概率。

Example

假设某张图片的分数是:

\[ s = [2.1, 5.1, -1.7], \quad y = 0 \]

\(\Delta = 1\),则:

\[ L_i = \max(0, 5.1 - 2.1 + 1) + \max(0, -1.7 - 2.1 + 1) \]
\[ = 4.0 + 0 = 4.0 \]

这说明虽然第 0 类才是正确标签,但第 1 类分数过高,造成了较大损失。

Properties

  • SVM loss 不关心“正确类赢多少”,只关心是否超过 margin
  • 一旦 margin 满足,对应项损失立刻变成 0
  • 分数整体加上一个常数,不会改变损失

Regularization

如果只最小化训练损失,模型可能会把权重拉得非常大,从而过拟合训练集。

因此通常会在总损失后面加一个正则项:

\[ L = \frac{1}{N} \sum_{i=1}^{N} L_i + \lambda R(W) \]

其中:

  • \(R(W)\) 是正则项
  • \(\lambda\) 是正则化强度

最常见的是 L2 regularization

\[ R(W) = \sum_k \sum_l W_{k,l}^2 \]

它会偏好较小、更平滑的权重。

为什么需要正则化

如果某组参数已经让训练集的 SVM loss 0,那么把这组参数整体放大很多倍,loss 仍然可能保持为 0

这说明仅靠 data loss 不能区分“哪个解更合理”,需要正则化来表达我们对简单模型的偏好。

Softmax Classifier

SVM 把输出看作“分数”,但没有把它们解释成概率。

Softmax classifier 会先把分数转成概率分布,再用交叉熵定义损失。

Softmax Function

给定分数向量 \(s\),第 \(j\) 类的概率为:

\[ P(y=j \mid x) = \frac{e^{s_j}}{\sum_k e^{s_k}} \]

它有两个性质:

  • 所有概率都大于 0
  • 所有概率和为 1

Cross-Entropy Loss

对于单个样本,正确类别为 \(y_i\),则损失为:

\[ L_i = -\log \frac{e^{s_{y_i}}}{\sum_j e^{s_j}} \]

也可以展开成:

\[ L_i = -s_{y_i} + \log \sum_j e^{s_j} \]

直观上,它在做两件事:

  • 提高正确类别分数 \(s_{y_i}\)
  • 压低所有类别总体的指数和

如果正确类别的预测概率接近 1,那么损失接近 0;如果正确类别概率很小,损失会很大。

Example

假设分数:

\[ s = [2.0, 1.0, 0.1] \]

先计算:

\[ e^s = [e^2, e^1, e^{0.1}] \approx [7.39, 2.72, 1.11] \]

总和约为:

\[ 7.39 + 2.72 + 1.11 = 11.22 \]

所以概率约为:

\[ [0.66, 0.24, 0.10] \]

如果正确类别是第 0 类,则损失为:

\[ L_i = -\log(0.66) \approx 0.41 \]

Numerical Stability

Softmax 中有指数运算,直接计算 \(e^{s_j}\) 可能数值溢出。

标准做法是先对所有分数减去最大值:

\[ s' = s - \max_j s_j \]

因为 Softmax 对整体平移不敏感:

\[ \frac{e^{s_j}}{\sum_k e^{s_k}} = \frac{e^{s_j + c}}{\sum_k e^{s_k + c}} \]

这样就能保证最大的指数项是 \(e^0 = 1\),计算更稳定。

SVM vs Softmax

两者都能训练线性分类器,但关注点不同。

SVM Loss 的特点

  • 强调正确类别和错误类别之间的 margin
  • 不显式输出概率
  • margin 满足后,不再继续鼓励扩大差距

Softmax Loss 的特点

  • 输出可以解释为概率分布
  • 始终在推动正确类别概率继续变大
  • 在分类、概率建模、神经网络输出层中更常见

实践中的经验

在现代深度学习里,Softmax + Cross-Entropy 更常见; 但理解 SVM loss 很有价值,因为它能帮助你建立“分类间隔”的直觉。

A Vectorized View

如果把一个 batch 的数据记为 \(X \in \mathbb{R}^{N \times D}\),则分数矩阵可以一次性写成:

\[ S = XW \]

其中:

  • \(X\) 的每一行是一个样本
  • \(W \in \mathbb{R}^{D \times C}\)
  • \(S \in \mathbb{R}^{N \times C}\)

这也是后续实现中最常用的写法,因为它可以高效利用矩阵运算。

import numpy as np

def linear_classifier_scores(X, W, b):
    return X @ W + b

如果采用 batch-first 写法,上式通常比逐样本循环更高效。

Why Linear Classifiers Are Not Enough

线性分类器很重要,但它远远不够解决真实视觉问题。

主要原因有:

  • 只能学习线性决策边界
  • 难以处理复杂的类内变化
  • 往往会把背景也混进模板里
  • 无法自动学习多层次特征

举例来说,一匹朝左的马和一匹朝右的马,在像素空间里可能差别非常大。线性模型只能试图把它们“平均”成一个奇怪模板,这就是它表达能力不足的体现。

Main Takeaways

  • 线性分类器用 \(f(x)=Wx+b\) 为每个类别输出分数
  • 可以从“模板匹配”与“超平面划分”两个角度理解它
  • 训练模型的关键是定义损失函数并最小化总损失
  • SVM loss 关注 marginSoftmax loss 关注概率
  • 正则化用于约束权重、缓解过拟合
  • 线性模型表达能力有限,这直接引出了下一讲的优化问题,以及后续更强的神经网络模型

Terms

术语小结

  • Score: 分类器对某一类给出的原始分数
  • Margin: 正确类分数相对错误类分数需要领先的最小间隔
  • Regularization: 在损失函数中加入对参数规模或复杂度的惩罚
  • Cross-Entropy: 衡量预测分布与真实分布差异的损失函数
  • Hyperplane: 高维空间中线性分类边界的几何对象