逻辑回归 = 线性回归 + sigmoid。 线性打分 z = w·x 先算出来,再用 sigmoid 把任意实数压进 0 到 1,当作「属于正类的概率」。 损失函数换成交叉熵(不是平方误差),因为交叉熵对「错得很自信」罚得更重。 实测两团点训练 400 轮,交叉熵从 0.6931 掉到 0.0810,测试准确率 0.9750; 换成同心圆数据,准确率只有 0.5075——它只能画一条直线。
2.1 与 2.2 解决的都是「预测一个数」。 这一节开始解决「分两类」,但用的还是同一个骨架:先算加权和,再套一个函数。 这个「加权和 + 挤压」的结构,是后面神经网络的基本单元(2.8 节会看到)。 它的局限也直接引出了 2.4 和 2.5:只能画直线,所以要有支持向量机和核方法。
一、从回归到分类:把任意实数压成概率
直接用线性回归去分两类会出问题。 假设标签是 0 和 1,线性回归会给你 −0.3、1.7、5.2 这样的预测值——这些数既不是 0 也不是 1, 还得自己定一个阈值去切。更糟的是,一个离群点能把整条线拉歪,连阈值都跟着变。 逻辑回归的处理是:线性部分照旧算 z = w·x + b,但输出不再直接用 z, 而是套一个 sigmoid 函数 1 / (1 + e⁻ᶻ)。 这个函数的样子是条 S 形曲线:z 很大时趋近 1,z 很小时趋近 0,z = 0 时正好 0.5。 它把整条实数轴压缩进了开区间 (0, 1),于是输出可以直接解释成概率。 Demo 里打了五个点:z = −6 得 0.002473,z = −2 得 0.119203,z = 0 得 0.500000,z = +2 得 0.880797, z = +6 得 0.997527。两头很快就贴到 0 和 1,中间那段才是有区分力的区域。 判别的规则很简单:z 大于 0 判正类,小于 0 判负类。 而 z = 0 在原始空间里就是一条直线——这就是「逻辑回归只能画直线」的由来。
二、为什么用交叉熵,不用平方误差
这是这一节最容易滑过去、也最该停一下的地方。 平方误差当然也能用:预测概率 p、真实标签 y,误差就是 (p − y)²。 但把它和 sigmoid 组合起来求导, 会得到一个带 p(1 − p) 因子的梯度——这个因子在 p 接近 0 或 1 时趋近 0,梯度就消失了。结果是: 模型判得越离谱、错得越自信,反而学得越慢。 交叉熵 −[y log p + (1 − y) log(1 − p)] 没有这个毛病。 真实标签是 1 而预测 p = 0.01 时,交叉熵是 4.6;预测 p = 0.5 时只有 0.69。 错得越自信,罚得越重,梯度越大。 而且它求导之后形式极干净:梯度就是 (p − y) 乘特征。 看着和线性回归的梯度一模一样,只是把「预测值」换成了「预测概率」。 这不是巧合,是广义线性模型的性质——但这里不用展开,知道「换个损失函数,梯度形式没变」就够了。 顺带说一句:交叉熵的单位是 nat(用自然对数),数值本身没有直观含义,只能横向比。 0.0810 和 0.6931 比才有意义——0.6931 正是随机猜的交叉熵(两类各半时 −log 0.5 = 0.6931)。
三、训练:一行梯度,几百轮就够
逻辑回归的训练过程就是梯度下降:算 p、算梯度、挪一步。 Demo 里 400 轮、学习率 0.5,交叉熵从 0.6931 掉到 0.0810。 有个现象值得注意:准确率很早就封顶了。第 10 轮时准确率已经 0.9583,之后交叉熵继续降到 0.0810, 准确率只涨到 0.9667。原因是准确率只看「过没过 0.5」,而交叉熵还罚「明明对了但只有 0.51」。 模型可以在准确率不动的情况下继续「变得更自信」。 这也说明为什么第 4 章要讲一堆指标:单一数字总会漏东西。 学到的系数也有直观解释。 Demo 里标准化之后 w1 = 3.7476、w2 = 3.7932,两个差不多大, 说明分界线是斜 45 度的——正好垂直于两团点中心的连线。系数的大小表示「这个特征往正类推的力度」。
四、多分类:softmax 与「一对其余」
两类用 sigmoid,三类以上怎么办?教材提了两种做法。 第一种是一对其余:训练三个二分类器,每个负责「是不是第 k 类」,预测时取分数最高的那个。 简单、可并行,但三个分类器各自为政,可能出现「三个都说不是」的情况。 第二种是 softmax:给每一类算一个线性分 z_k,然后用 exp(z_k) 除以所有 exp 之和, 得到一组和恰好为 1 的概率。它是 sigmoid 在多类上的自然推广——两类时 softmax 就退化成 sigmoid。 训练目标也从交叉熵推广成 −log(正确类的概率)。 这个形式在 43 课里出现过很多次,因为它是所有分类网络的标配损失。
五、它的天花板:一条直线
Demo 最后一段是这一节最该记住的实验:换成同心圆数据,内圈一类、外圈一类, 逻辑回归的准确率只有 0.5075。 这不是训练不够。 你把轮数加到十万、学习率调到最优, 结果还是 0.5 左右——因为它的决策边界是一条直线,而这里正确的边界是一个圆。 模型表达能力到此为止,再多的训练也只是在错误的形状里找最好的那个。 这个认识很重要:遇到效果不好的模型,先分清是「没训好」还是「表达不了」。 前者的药是调参、 加数据;后者的药是换模型。用错药只会浪费时间。 下一节的支持向量机也从直线开始,但它换了个优化目标;2.5 节的核方法才真正把这条线掰弯。
六、动手 Demo:把一条直线弯成一个概率
两团点,一类在 (1,1)、一类在 (3,3),各 80 个,分训练 120、测试 40。 这一段要看的不是「分得对不对」, 而是「有多大概率」——注意最后那张表里有一行叫「概率在 0.4 到 0.6 之间」, 那个数字说明模型对自己的判断有多确定。
import numpy as np
def sigmoid(z):
return 1.0 / (1.0 + np.exp(-z))
w = np.zeros(3)
for it in range(400):
p = sigmoid(Z @ w)
grad = Z.T @ (p - y) / len(y) # 比线性回归多套了一层
w -= 0.5 * grad
p = sigmoid(Z @ w)
eps = 1e-12
loss = -(y * np.log(p + eps) + (1 - y) * np.log(1 - p + eps)).mean()
print("交叉熵 %.4f 准确率 %.4f" % (loss, ((p > 0.5) == y).mean()))
实跑输出:
--------------------------------------------------------------------
逻辑回归:把一条直线弯成一个概率
--------------------------------------------------------------------
两团点,一类在 (1,1)、一类在 (3,3),各 80 个。这次要的不是「落在哪边」,
而是「有多大概率是 1 类」——所以在直线外面套一个挤压函数,把任意实数压到 0 和 1 之间。
【一】sigmoid:把 z 压进 (0, 1)
z = -6.0 sigmoid = 0.002473
z = -2.0 sigmoid = 0.119203
z = +0.0 sigmoid = 0.500000
z = +2.0 sigmoid = 0.880797
z = +6.0 sigmoid = 0.997527
z 是线性打分 w·x,sigmoid 把它变成概率。z 大就接近 1,z 小就接近 0,z 等于 0 时正好 0.5。
**分界线就是 z = 0 的那条线。**
【二】训练:最小化交叉熵
轮数 训练交叉熵 训练准确率
--------------------------------------
1 0.6931 0.5167
10 0.2513 0.9583
50 0.1273 0.9583
100 0.1042 0.9583
400 0.0810 0.9667
【三】学到的分界面
三个系数(标准化空间里):w0 = -0.4121,w1 = 3.7476,w2 = 3.7932。w1 和 w2 差不多大,
说明这条分界线刚好是斜 45 度的——和两团点中心连线垂直,符合直觉。
指标 数值
------------------------------------------
测试准确率 0.9750
测试交叉熵 0.0455
概率在 0.4 到 0.6 之间 1 个(共 40 个)
交叉熵和准确率不是一回事:准确率只看「过没过 0.5」,交叉熵还罚「明明是对的却只有 0.51」。
**模型可以全对但交叉熵很高**,
因为它对每个样本都只是勉强猜对。第 4 章会讲怎么用这条曲线看模型好坏。
【四】逻辑回归的天花板:它只能画一条直线
换成同心圆:内圈半径 0.7 一类、外圈半径 2.0 另一类,各 200 个点。
逻辑回归的准确率只有 0.5075——**两条线打不过一个圈。**
它学到的分界线还是一条直线,而这里正确的边界是圆的。这不是训练不够,
是模型表达能力到此为止。下一节的支持向量机也从直线开始,2.5 节的核方法才把这条线掰弯。
sigmoid 那五个点值得记住:−6 到 0.0025,+6 到 0.9975。中间 z = 0 处是 0.5,斜率最大; 两边迅速饱和。这就是为什么逻辑回归的梯度会「消失」——饱和区导数接近 0。 训练那一栏:第 1 轮 0.6931,第 10 轮 0.2513,第 400 轮 0.0810。0.6931 不是随便来的, 它是 −log 0.5,也就是「两类各半乱猜」的交叉熵。 任何分类模型的交叉熵起点都在这个数附近,看到它就知道模型还没学到东西。 准确率从第 10 轮起就停在 0.9583,一直到最后才动到 0.9667。交叉熵却一直在降。 这个「指标不同步」的现象,是第 4 章讲评估的引子。 系数 w1 ≈ w2 ≈ 3.75,说明分界线斜 45 度。 两团点中心 (1,1) 与 (3,3) 的连线也是 45 度,分界线正好垂直于它——这是最优解该有的样子。 「概率在 0.4 到 0.6 之间」那一行是 1 个(共 40 个)。说明 40 个测试点里只有 1 个模型拿不准, 其余都被推到了很确定的两端。 这既是好事(判别力强),也是隐患(过度自信的模型在遇到新分布时会错得很惨)。 最后一段的 0.5075 是这一节的句号。同心圆数据上,逻辑回归等于瞎猜。 记住这个数,2.8 节的神经网络会拿同一类数据做出 1.0000。
30 秒实验
- 把 sigmoid 换成「z 大于 0 就输出 1、否则输出 0」的硬阶跃,还能训练吗?为什么?
- 把两团点的距离从 (1,1) 与 (3,3) 拉近到 (1.5,1.5) 与 (2.5,2.5),测试准确率会掉到多少?
- 逻辑回归的交叉熵最低能到 0 吗?为什么不能?
常见误区
- 以为「逻辑回归」是一种回归。它做的是分类,名字里的「回归」来自它用的线性模型形式。 输出是概率,不是连续值。
- 用平方误差训练逻辑回归。能跑,但收敛慢、容易被「错得很自信」的样本拖住。 分类问题的标配损失是交叉熵。
- 把输出的概率当成可信度。模型说 0.95,不代表真有 95% 的把握——逻辑回归的概率没有经过校准, 尤其在数据不平衡时会系统性偏高或偏低。要当真,得先做概率校准。
自测三问(点开对答案)
1. 交叉熵 0.6931 这个数是怎么来的?为什么说它是「乱猜的起点」? —— 两类各半时,任何模型都只能给 0.5 的概率,交叉熵是 −log 0.5 = 0.6931。 训练开始时权重接近 0,输出接近 0.5,所以起点就在这个数附近。 2. 为什么逻辑回归在同心圆数据上只有 0.5075,加到十万轮也没用? —— 因为它的决策边界是一条直线,而数据的真实边界是圆。这是模型表达能力的问题,不是训练不足。 加轮数只能在这条直线里找最优,找不到圆。 3. 准确率早早停在 0.9583,交叉熵却一直降,这矛盾吗? —— 不矛盾。准确率只看「过没过 0.5」,交叉熵还看「离 0.5 有多远」。 模型可以继续把已经判对的样本推得更确定,交叉熵降而准确率不变。逻辑回归靠「概率大于 0.5」来分界,那条线是它自己学出来的,没考虑「离边界远近」。 2.4 节的支持向量机换了个目标:不光要分对,还要让两边的空隙尽量宽。
- ☐ (本节完,下一节 2.4 算法 4:支持向量机)