以下内容为结合李沐老师的课程和教材补充的学习笔记,以及对课后练习的一些思考,自留回顾,也供同学之人交流参考。
本节课程地址:09 Softmax 回归 + 损失函数 + 图片分类数据集【动手学深度学习v2】_哔哩哔哩_bilibili
本节教材地址:3.4. softmax回归 — 动手学深度学习 2.0.0 documentation (d2l.ai)
本节开源代码:...>d2l-zh>pytorch>chapter_linear-networks>softmax-regression.ipynb
softmax回归
在 3.1节 中我们介绍了线性回归。 随后,在 3.2节 中我们从头实现线性回归。 然后,在 3.3节 中我们使用深度学习框架的高级API简洁实现线性回归。
回归可以用于预测多少的问题。 比如预测房屋被售出价格,或者棒球队可能获得的胜场数,又或者患者住院的天数。
事实上,我们也对分类问题感兴趣:不是问“多少”,而是问“哪一个”:
- 某个电子邮件是否属于垃圾邮件文件夹?
- 某个用户可能注册或不注册订阅服务?
- 某个图像描绘的是驴、狗、猫、还是鸡?
- 某人接下来最有可能看哪部电影?
通常,机器学习实践者用分类这个词来描述两个有微妙差别的问题: 1. 我们只对样本的“硬性”类别感兴趣,即属于哪个类别; 2. 我们希望得到“软性”类别,即得到属于每个类别的概率。 这两者的界限往往很模糊。其中的一个原因是:即使我们只关心硬类别,我们仍然使用软类别的模型。
分类问题
我们从一个图像分类问题开始。 假设每次输入是一个 2×2 的灰度图像。 我们可以用一个标量表示每个像素值,每个图像对应四个特征 𝑥1,𝑥2,𝑥3,𝑥4 。 此外,假设每个图像属于类别“猫”“鸡”和“狗”中的一个。
接下来,我们要选择如何表示标签。 我们有两个明显的选择:最直接的想法是选择 𝑦∈1,2,3 , 其中整数分别代表 狗猫鸡狗,猫,鸡 。 这是在计算机上存储此类信息的有效方法。 如果类别间有一些自然顺序, 比如说我们试图预测 婴儿儿童青少年青年人中年人老年人婴儿,儿童,青少年,青年人,中年人,老年人 , 那么将这个问题转变为回归问题,并且保留这种格式是有意义的。
但是一般的分类问题并不与类别之间的自然顺序有关。 幸运的是,统计学家很早以前就发明了一种表示分类数据的简单方法:独热编码(one-hot encoding)。 独热编码是一个向量,它的分量和类别一样多。 类别对应的分量设置为1,其他所有分量设置为0。 在我们的例子中,标签 𝑦 将是一个三维向量, 其中 (1,0,0) 对应于“猫”、 (0,1,0) 对应于“鸡”、 (0,0,1) 对应于“狗”:
𝑦∈{(1,0,0),(0,1,0),(0,0,1)}.
网络架构
为了估计所有可能类别的条件概率,我们需要一个有多个输出的模型,每个类别对应一个输出。 为了解决线性模型的分类问题,我们需要和输出一样多的仿射函数(affine function)。 每个输出对应于它自己的仿射函数。 在我们的例子中,由于我们有4个特征和3个可能的输出类别, 我们将需要12个标量来表示权重(带下标的 𝑤 ), 3个标量来表示偏置(带下标的 𝑏 )。 下面我们为每个输入计算三个未规范化的预测(logit): 𝑜1 、 𝑜2 和 𝑜3 。
我们可以用神经网络图来描述这个计算过程。 与线性回归一样,softmax回归也是一个单层神经网络。 由于计算每个输出𝑜1 、 𝑜2 和 𝑜3取决于 所有输入 𝑥1 、 𝑥2 、 𝑥3 和 𝑥4 , 所以softmax回归的输出层也是全连接层。
为了更简洁地表达模型,我们仍然使用线性代数符号。 通过向量形式表达为 𝑜=𝑊𝑥+𝑏 , 这是一种更适合数学和编写代码的形式。 由此,我们已经将所有权重放到一个 3×4 矩阵中。 对于给定数据样本的特征 𝑥 , 我们的输出是由权重与输入特征进行矩阵-向量乘法再加上偏置 𝑏 得到的。
全连接层的参数开销
正如我们将在后续章节中看到的,在深度学习中,全连接层无处不在。 然而,顾名思义,全连接层是“完全”连接的,可能有很多可学习的参数。 具体来说,对于任何具有 𝑑 个输入和 𝑞 个输出的全连接层, 参数开销为 𝑂(𝑑𝑞) ,这个数字在实践中可能高得令人望而却步。 幸运的是,将 𝑑 个输入转换为 𝑞 个输出的成本可以减少到 𝑂(𝑑𝑞𝑛) , 其中超参数可以由我们灵活指定,以在实际应用中平衡参数节约和模型有效性 (ef="https://zh-v2.d2l.ai/chapter_references/zreferences.html#id195">Zhanget al., 2021)。
softmax运算
现在我们将优化参数以最大化观测数据的概率。 为了得到预测结果,我们将设置一个阈值,如选择具有最大概率的标签。
我们希望模型的输出 𝑦^𝑗 可以视为属于类 𝑗 的概率, 然后选择具有最大输出值的类别 作为我们的预测。 例如,如果 、 和 分别为0.1、0.8和0.1, 那么我们预测的类别是2,在我们的例子中代表“鸡”。
然而我们能否将未规范化的预测 直接视作我们感兴趣的输出呢? 答案是否定的。 因为将线性层的输出直接视为概率时存在一些问题: 一方面,我们没有限制这些输出数字的总和为1。 另一方面,根据输入的不同,它们可以为负值。 这些违反了 2.6节 中所说的概率基本公理。
要将输出视为概率,我们必须保证在任何数据上的输出都是非负的且总和为1。 此外,我们需要一个训练的目标函数,来激励模型精准地估计概率。 例如, 在分类器输出0.5的所有样本中,我们希望这些样本是刚好有一半实际上属于预测的类别。 这个属性叫做校准(calibration)。
社会科学家邓肯·卢斯于1959年在选择模型(choice model)的理论基础上 发明的softmax函数正是这样做的: softmax函数能够将未规范化的预测变换为非负数并且总和为1,同时让模型保持 可导的性质。 为了完成这一目标,我们首先对每个未规范化的预测求幂,这样可以确保输出非负。 为了确保最终输出的概率值总和为1,我们再让每个求幂后的结果除以它们的总和。如下式:
其中
这里,对于所有的 𝑗 总有 。 因此, 可以视为一个正确的概率分布。 softmax运算不会改变未规范化的预测 𝑜 之间的大小次序,只会确定分配给每个类别的概率。 因此,在预测过程中,我们仍然可以用下式来选择最有可能的类别。
尽管softmax是一个非线性函数,但softmax回归的输出仍然由输入特征的仿射变换决定。 因此,softmax回归是一个线性模型(linear model)。
小批量样本的矢量化
为了提高计算效率并且充分利用GPU,我们通常会对小批量样本的数据执行矢量计算。 假设我们读取了一个批量的样本 𝑋 , 其中特征维度(输入数量)为 𝑑 ,批量大小为 𝑛 。 此外,假设我们在输出中有 𝑞 个类别。 那么小批量样本的特征为 , 权重为 , 偏置为 。 softmax回归的矢量计算表达式为:
相对于一次处理一个样本, 小批量样本的矢量化加快了 和𝑋和𝑊 的矩阵-向量乘法。 由于 𝑋 中的每一行代表一个数据样本, 那么softmax运算可以按行(rowwise)执行: 对于 𝑂 的每一行,我们先对所有项进行幂运算,然后通过求和对它们进行标准化。 在上式中, 𝑋𝑊+𝑏 的求和会使用广播机制, 小批量的未规范化预测 𝑂 和输出概率 都是形状为 𝑛×𝑞 的矩阵。
损失函数
接下来,我们需要一个损失函数来度量预测的效果。 我们将使用最大似然估计,这与在线性回归 ( 3.1.3节 ) 中的方法相同。
对数似然
softmax函数给出了一个向量 , 我们可以将其视为“对给定任意输入 𝑥 的每个类的条件概率”。 例如, = 猫 。 假设整个数据集 𝑋,𝑌 具有 𝑛 个样本, 其中索引 𝑖 的样本由特征向量 𝑥(𝑖) 和独热标签向量 𝑦(𝑖) 组成。 我们可以将估计值与实际值进行比较:
根据最大似然估计,我们最大化 𝑃(𝑌∣𝑋) ,相当于最小化负对数似然:
其中,对于任何标签 𝑦 和模型预测 𝑦^ ,损失函数为:
在本节稍后的内容会讲到, 上式中的损失函数 通常被称为交叉熵损失(cross-entropy loss)。 由于 𝑦 是一个长度为 𝑞 的独热编码向量, 所以除了一个项以外的所有项j都消失了。 由于所有 𝑦^𝑗 都是预测的概率,所以它们的对数永远不会大于 0 。 因此,如果正确地预测实际标签,即如果实际标签 𝑃(𝑦∣𝑥)=1 , 则损失函数不能进一步最小化。 注意,这往往是不可能的。 例如,数据集中可能存在标签噪声(比如某些样本可能被误标), 或输入特征没有足够的信息来完美地对每一个样本分类。
推导:
根据《3.1线性回归》中3.1.3的推导,可知:
在高斯噪声的假设下,最小化均方误差等价于对线性模型的极大似然估计,
即:
对于第 𝑖 行,
其中, 意为给定 时, 的条件概率,
且 的 𝑞 个项中,只有第 𝑗 项为1,其余均为0
因此:
即证:
(除第 𝑗 项外,其余项均为0,
即:
softmax及其导数
由于softmax和相关的损失函数很常见, 因此我们需要更好地理解它的计算方式。 利用softmax的定义,我们得到:
考虑相对于任何未规范化的预测 𝑜𝑗 的导数,我们得到:
换句话说,导数是我们softmax模型分配的概率与实际发生的情况(由独热标签向量表示)之间的差异。 从这个意义上讲,这与我们在回归中看到的非常相似, 其中梯度是观测值 𝑦 和估计值 𝑦^ 之间的差异。 这不是巧合,在任何指数族分布模型中 (参见本书附录中关于数学分布的一节), 对数似然的梯度正是由此得出的。 这使梯度计算在实践中变得容易很多。
交叉熵损失
现在让我们考虑整个结果分布的情况,即观察到的不仅仅是一个结果。 对于标签 𝑦 ,我们可以使用与以前相同的表示形式。 唯一的区别是,我们现在用一个概率向量表示,如 (0.1,0.2,0.7) , 而不是仅包含二元项的向量 (0,0,1) 。 我们使用 :eqref:eq_l_cross_entropy
来定义损失 𝑙 , 它是所有标签分布的预期损失值。 此损失称为交叉熵损失(cross-entropy loss),它是分类问题最常用的损失之一。 本节我们将通过介绍信息论基础来理解交叉熵损失。 如果想了解更多信息论的细节,请进一步参考 本书附录中关于信息论的一节。
信息论基础
信息论(information theory)涉及编码、解码、发送以及尽可能简洁地处理信息或数据。
熵
信息论的核心思想是量化数据中的信息内容。 在信息论中,该数值被称为分布 𝑃 的熵(entropy)。可以通过以下方程得到:
信息论的基本定理之一指出,为了对从分布 𝑝 中随机抽取的数据进行编码, 我们至少需要 𝐻[𝑃] “纳特(nat)”对其进行编码。 “纳特”相当于比特(bit),但是对数底为 𝑒 而不是2。因此,一个纳特是 1log(2)≈1.44 比特。
信息量
压缩与预测有什么关系呢? 想象一下,我们有一个要压缩的数据流。 如果我们很容易预测下一个数据,那么这个数据就很容易压缩。 为什么呢? 举一个极端的例子,假如数据流中的每个数据完全相同,这会是一个非常无聊的数据流。 由于它们总是相同的,我们总是知道下一个数据是什么。 所以,为了传递数据流的内容,我们不必传输任何信息。也就是说,“下一个数据是xx”这个事件毫无信息量。
但是,如果我们不能完全预测每一个事件,那么我们有时可能会感到"惊异"。 克劳德·香农决定用信息量 来量化这种惊异程度。 在观察一个事件 𝑗 时,并赋予它(主观)概率 𝑃(𝑗) 。 当我们赋予一个事件较低的概率时,我们的惊异会更大,该事件的信息量也就更大。 在 :eqref:eq_softmax_reg_entropy
中定义的熵, 是当分配的概率真正匹配数据生成过程时的信息量的期望。
重新审视交叉熵
如果把熵 𝐻(𝑃) 想象为“知道真实概率的人所经历的惊异程度”,那么什么是交叉熵? 交叉熵从 𝑃 到 𝑄 ,记为 𝐻(𝑃,𝑄) 。 我们可以把交叉熵想象为“主观概率为 𝑄 的观察者在看到根据概率 𝑃 生成的数据时的预期惊异”。 当 𝑃=𝑄 时,交叉熵达到最低。 在这种情况下,从 𝑃 到 𝑄 的交叉熵是 𝐻(𝑃,𝑃)=𝐻(𝑃) 。
简而言之,我们可以从两方面来考虑交叉熵分类目标: (i)最大化观测数据的似然;(ii)最小化传达标签所需的惊异。
模型预测和评估
在训练softmax回归模型后,给出任何样本特征,我们可以预测每个输出类别的概率。 通常我们使用预测概率最高的类别作为输出类别。 如果预测与实际类别(标签)一致,则预测是正确的。 在接下来的实验中,我们将使用精度(accuracy)来评估模型的性能。 精度等于正确预测数与预测总数之间的比率。
小结
- softmax运算获取一个向量并将其映射为概率。
- softmax回归适用于分类问题,它使用了softmax运算中输出类别的概率分布。
- 交叉熵是一个衡量两个概率分布之间差异的很好的度量,它测量给定模型编码数据所需的比特数。
Note:深度学习常用三大损失函数
- L2 Loss 均方损失函数 Mean Square Error
调用代码:nn.MSELoss
y = 0时,蓝色线--均方损失函数;橙色线--均方损失函数的梯度;绿色线--似然函数
红色箭头大小表示参数(w和b)更新速率,当y‘越靠近原点时,梯度的绝对值越小(<1),也即当y和y’越接近时,参数的更新速率逐渐减小。
· 优点:处处可导,收敛速度快。
· 缺点:由于平方运算的特点,当$|y - y'|>1$时,会放大误差,因此,MSE对离群点比较敏感,受其影响较大,如下图所示(拟合梯度偏向离群点):
2. L1 Loss 绝对值损失函数 Mean Absolute Error
调用代码:nn.L1Loss
y = 0时,蓝色线--绝对值损失函数;橙色线--绝对值损失函数的梯度;绿色线--似然函数
红色箭头大小表示参数(w和b)更新速率,除原点处不可导之外,其余处梯度均相等(为常数)。
· 优点:参数更新速率均等,对离群值不敏感,鲁棒性好。
· 缺点:原点处不可导,当y和y’的值接近时(即靠近原点时),梯度在[-1, 1]之间波动,模型不稳定;收敛速度慢。
3. Huber Loss Huber损失函数 -- 分段函数
调用代码:nn.SmoothL1Loss
y = 0时,蓝色线--Huber损失函数;橙色线--Huber损失函数的梯度;绿色线--似然函数
红色箭头大小表示参数(w和b)更新速率,在[-1, 1]之外,函数为L1 Loss,收敛速率恒定;在[-1, 1]之间,函数为L2 Loss,收敛速度逐渐减小。
· 优点:兼具L2 Loss和L1 Loss的优点,规避二者的缺点,既对离群值不敏感,又处处可导,收敛速度较快。
· 缺点:原点处不可导,当y和y’的值接近时(即靠近原点时),梯度在[-1, 1]之间波动,模型不稳定;收敛速度慢。
练习
1. 我们可以更深入地探讨指数族与softmax之间的联系。
A. 计算softmax交叉熵损失 𝑙(𝑦,𝑦^) 的二阶导数。
解:
∵
∴
B. 计算 softmax(𝑜) 给出的分布方差,并与上面计算的二阶导数匹配。
解:
∵ ∴
2. 假设我们有三个类发生的概率相等,即概率向量是 。
A. 如果我们尝试为它设计二进制代码,有什么问题?
解:
如果我们尝试为这个概率向量设计二进制代码,会遇到的问题是无法准确地表示各个类的概率。由于三个类的概率相等,如果使用等长的二进制编码,比如类1编码为00,类2编码为01,类3编码为10,那么每个类的编码长度都相同,无法反映各个类的概率差异。
同时,该方法会导致前缀冲突,指两个编码序列中的一个序列是另一个序列的前缀。例如,第一个类别编码 “00”和第二个类别编码 “01”,就存在前缀冲突,因为 “00” 是 “01” 的前缀,因此在进行解码时,当我们遇到编码为 “0” 的序列时,无法确定这是第一个类别还是第二个类别。
这种前缀冲突会导致解码错误,使我们无法准确地将编码映射回原始的类别。
B. 请设计一个更好的代码。提示:如果我们尝试编码两个独立的观察结果会发生什么?如果我们联合编码 𝑛 个观测值怎么办?
解:
为了设计一个更好的代码,我们可以使用霍夫曼编码(Huffman coding),以便能够准确表示各个类的概率。
如果我们尝试编码两个独立的观察结果,可以使用霍夫曼编码。首先,将两个观察结果看作一个整体,构建一个二叉树。然后,从根节点开始,沿着左子树和右子树分支,分别分配0和1作为编码。这样的编码方式是唯一的,并且可以准确地区分每个类的概率。
如果我们要联合编码n个观测值,可以使用联合霍夫曼编码或嵌套霍夫曼编码。联合编码的基本思想是将多个观测值看作一个整体,构建一棵多叉树,并按照霍夫曼编码的原则进行编码。嵌套霍夫曼编码则是多层次地应用霍夫曼编码,将每个观测值集合看作一个整体进行编码。
3. softmax是对上面介绍的映射的误称(虽然深度学习领域中很多人都使用这个名字)。真正的softmax被定义为 。
A. 证明 。
证:
假设
即证
B. 证明 成立,前提是 𝜆>0 。
证:
当 𝜆>0 时,假设
即证
C. 证明对于 𝜆→∞ ,有 。
证:
当 𝜆→∞ 时,
假设 𝑚𝑎𝑥(𝑎,𝑏)=𝑎
则𝜆𝑎>>𝜆𝑏 , 也即exp(𝜆𝑎)>>exp(𝜆𝑏)
故
或是 𝑎=𝑏
则
即证
D. soft-min会是什么样子?
解:
E. 将其扩展到两个以上的数字。
解: