Softmax回归及其优化问题

简介

温故而知新

本文所属系列为笔者学习陈天奇和J.Zico Kolter在CMU开设的Deep Learning Systems的课程笔记。

本文为Deep Learning Systems课程的第二课:2 - ML Refresher / Softmax Regression。

数据定义

在这一章节,我们将定义在本文中会用到的输入数据。

让我们来考虑一个$k$分类问题,给定:

  1. 训练数据:$x^{(i)}\in \mathbb{R}^n$,$y^{(i)}\in {1,…,k}$ $for$ $i = 1,..,m$。
  2. n为输入数据的维度数
  3. k为类别/label的数量
  4. m为训练数据的数量

至此,本文中所有的输入数据定义完毕。

线性映射

在这一章节,我们将定义将输入数据 $x$ 映射到 $k$ 个类别的假设函数 $h$。

我们将使用线性函数来实现这一功能并提供形式化表述,同时提供函数是线性的的证明。

向量形式

由于我们要将维度为$n$的数据$x$分为$k$类,因此我们需要将这个功能形式化表述。

对于$k$分类问题,我们希望将维度为$n$的输入向量$x\in \mathbb{R}^n$映射到一个$k$维的解空间中,即 $$ h{:}\mathbb{R}^n\to\mathbb{R}^k $$ 其中,$h_i(x)$表示对于输入数据$x$,它是第$i$类的置信度。

上述过程,我们可以用线性映射函数来表示: $$ {h_\theta(x)=\theta^Tx} $$ 其中,$\theta \in \mathbb{R}^{n\times k}$。

至此,映射函数的形式化表述完毕。

为什么$ h_\theta(x) = \theta^T x $是线性的?

一个线性的函数需要满足可加性和齐次性。

  1. 可加性(Additivity): 假设我们有两个 $n$-维输入向量 $x_1$ 和 $ x_2$。那么对于线性假设函数 $h$,我们有: $$ h_\theta(x_1 + x_2) = \theta^T (x_1 + x_2) $$ 由于矩阵乘法与向量加法相容,根据分配律: $$h_\theta(x_1 + x_2) = \theta^T x_1 + \theta^T x_2 $$ 而上式右侧等于把每个向量单独变换然后相加: $$h_\theta(x_1 + x_2) = h_\theta(x_1) + h_\theta(x_2) $$ 故满足可加性

  2. 齐次性(Homogeneity): 如果我们取$ x$的一个标量倍数$cx$,其中$c$是任意实数,那么线性假设函数$h$的输出为: $$ h_\theta(cx) = \theta^T (cx) $$ 根据分配律: $$ h_\theta(cx) = c(\theta^T x) $$ 这表明通过函数 ( h ) 变换的标量倍数正是标量倍数的变换: $$ h_\theta(cx) = c h_\theta(x) $$

故满足齐次性

因此可证,矩阵乘法满足可加性和齐次性,所以$h_\theta(x)$是一个线性函数。。

矩阵格式

在上小节中,$x$ 的形状为 $1 \times n$ 的向量。在这一小节,我们将 $m$ 个 $x$ 向量拼接为一个形状为 $m \times n$ 的矩阵:

$$ X\in\mathbb{R}^{m\times n}=\begin{bmatrix}-{x^{(1)}}^T-\\\vdots\\-{x^{(m)}}^T-\end{bmatrix} $$

对于一个向量 $x$ ,其label,即 $y$ ,为一个实数 $y$ 。类似地,当 $m$ 个 $x$ 拼接为矩阵,其label,即 $y$, 是一个形状为$m \times 1$的矩阵:

$$ y\in\{1,...,k\}^m=\begin{bmatrix}y^{(1)}\\\vdots\\y^{(m)}\end{bmatrix} $$

损失函数

在这一章节,我们将讨论两种损失函数的定义、利弊——0-1损失函数和交叉损失函数。

损失函数的意义在于,它将模型的参数矩阵映射到一个实数值上,这个值用于评估假设函数 $h_\theta(x)$ 的"好坏"程度。

0-1损失函数

对于一个分类问题,我们如何判断一个假设函数 $h_\theta(x)$ 的好坏呢?

一个非常直观的想法是,如果判断正确置$1$,分类错误置$0$。这种损失函数叫做"0-1损失函数"(0-1 loss function)。这个函数的值取决于一个分类器 $h$ 在输入 $x $上的预测 $h_\theta(x) $ 是否与真实标签 $y$ 相同。如果预测正确,那么损失为0;如果预测错误,则损失为1。简而言之,这个函数是在衡量“分类器是否犯错”,如果犯错就惩罚,否则不惩罚。其形式化表述为:

$$ \ell_{err}(h(x),y)=\begin{cases}0&\text{if }\operatorname{argmax}_ih_i(x)=y\\1&\text{otherwise}\end{cases} $$

这个损失函数的好处在于非常简单。然而,不幸的是,这种损失函数非常不利于后续我们对模型参数进行优化。这是因为这种损失函数在优化过程中不能使用基于梯度的方法,因为它本身就没有梯度!当预测是正确的,损失函数的输出突然跳跃到0,这导致没有一个有意义的梯度方向来指导参数更新。

其中,$ \text{argmax}_i h_i(x) $ 表示分类器对于所有可能的类别输出的得分中,得分最高的类别。

Softmax 和 Cross-entropy loss

在上一小节中提到的"0-1损失函数"的思想可以总结为"一刀切",正确为1,错误为0。然而,即使是错,也有错了一点和错得离谱之分。

基于这个思想,我们希望将假设函数$h_\theta(x)$的输出从生硬的"一刀切"转换为"概率"。这里,我们可以使用softmax函数,它可以将任何实数向量转换为一个概率分布。对于分类 $i $,模型预测的概率 $p(\text{label} = i) $ 计算为该类的得分 $ h_i(x) $ 的指数,除以所有类得分指数的总和,以确保所有预测概率相加等于1。其形式化表述为:

$$ z_i=p(\text{label}=i)=\frac{\exp\bigl(h_i(x)\bigr)}{\sum_{j=1}^k\exp\bigl(h_j(x)\bigr)}\Longleftrightarrow z\equiv\text{softmax}\bigl(h(x)\bigr) $$

其中,将输出除以所有的输出的和这一步骤很好理解,其意义在于通过对输出归一化使得每个类别的输出值都在0到1之间各类别输出和为1。我们好奇在于,为什么要将 $ h_i(x) $ 指数化呢?

这么做主要有两个原因

  1. 通过将输出指数化,将假设函数的输出转换为正值。这对于创建一个有效的概率分布是必需的,因为概率值不能为负。
  2. 指数函数曲线呈现递增趋势,最重要的是斜率逐渐增大,也就是说在x轴上一个很小的变化,可以导致y轴上很大的变化。这有助于在计算概率时清晰地区分那些具有更高原始逻辑值的类别。

有了softmax函数,我们可以用交叉熵损失函数(cross-entropy loss)来计算损失值,其形式化表述为:

$$ \ell_{ce}(h(x),y)=-\log p(\text{label}=y)=-h_y(x)+\log\sum_{j=1}^k\exp\left(h_j(x)\right) $$

我们注意到,交叉熵损失函数实质上是对 $y$ 类别的softmax输出做$-log$操作。

对于加$log$,其意义在于:

  1. 将(0, 1)区间内的值映射到负无穷大到0的区间,使得概率的微小变化在损失值中得到放大,从而提供更好的区分度。

  2. 当预测概率接近真实标签的概率时,损失函数的梯度会变小,模型的学习速度会减慢。相反,当预测概率与真实标签差异很大时,损失函数的梯度会显著变大,模型速度会加快。这样使得模型能够更有效地学习,当模型经常做出错误预测时,可以快速调整方向。

对于加$-$,其意义在于将负值转为正值。这样,差异越大损失值越大,反之亦然。

优化

在上文我们提到,我们可以通过损失函数来判断假设函数$h_\theta(x)$中的权重参数的好坏程度。

那么,如果$h_\theta(x)$中的权重参数不够好,我们应该如何进行优化呢?

定义

广义上讲,我们希望通过优化权重参数 $\theta$,使得损失函数的输出值最小。其形式化表述如公式所示: $$ \underset{\theta}{\operatorname*{minimize}}\frac1m\underset{i=1}{\operatorname*{\sum}}\ell(h_\theta(x^{(i)}),y^{(i)}) $$ 其中 $i$ 表示当前样本索引,$h$ 表示假设函数,$y$ 表示样本的真实标签 (Ground truth)。

我们将交叉熵损失函数 $\ell_{ce}$ 带入 $\ell$ ,得到下述公式: $$ \underset{\theta}{\operatorname*{minimize}}\frac1m\sum_{i=1}^m\ell_{ce}(\theta^Tx^{(i)},y^{(i)}) $$ 至此,优化的定义有了。

接下来,具体而言,我们应该如何进行优化呢?

梯度优化

梯度


对于一个输入为矩阵,输出为实数的函数 $f{:\mathbb{R}^{n\times k}\to\mathbb{R}}$,其梯度被定义为偏导数矩阵,可被形式化表述为:

$$ \nabla_\theta f(\theta)\in\mathbb{R}^{n\times k}=\begin{bmatrix}\dfrac{\partial f(\theta)}{\partial\theta_{11}}&...&\dfrac{\partial f(\theta)}{\partial\theta_{1k}}\\\vdots&\ddots&\vdots\\\dfrac{\partial f(\theta)}{\partial\theta_{n1}}&...&\dfrac{\partial f(\theta)}{\partial\theta_{nk}}\end{bmatrix} $$

结合我们上文可知,此处的$f$代表了上文中的损失函数。

在数学上,梯度指向的是损失函数局部下降最快的方向。

因此,在优化中,我们通常希望找到损失函数梯度下降的方向,来调整参数以最小化损失函数。

学习率

现在我们可以通过梯度这个强有力的工具来对权重参数进行更新了!

然而需要注意的是,我们在更新权重参数的时候,我们是一轮一轮地进行更新。于是,我们需要用一个缩放因子$\alpha$定义每一轮训练对权重参数的更新幅度。这个缩放因子$\alpha$就被称为学习率。在利用梯度对权重参数进行的过程中,更新每一步的更新的形式化表述可以表示为: $$ \begin{aligned}\theta:=\theta-\alpha\nabla_\theta f(\theta)\end{aligned} $$ 其中:

  • $\theta$ 是需要优化的权重参数。
  • $\alpha$是学习率,为正数,它控制了每一步的更新幅度。
  • $\nabla_\theta f(\theta)$ 是损失函数 $f(\theta) $ 关于参数 $ \theta$ 的梯度。

上述方法就是著名的梯度下降法(Gradient-Descent)。其原理是,通过计算损失函数在当前参数下的梯度,然后沿着梯度的负方向更新参数,不断迭代直到收敛。

在梯度下降法中,选择适当的学习率对于梯度下降算法的优化性能至关重要。下方的三个子图展示了使用不同学习率 $\alpha$ 在一个二维参数空间中进行梯度下降时的路径,其中的等高线表示损失函数的值。从左到右,学习率分别是 0.05、0.2 和 0.42。梯度下降的目的是找到损失函数的全局最小点,也就是图中是最内层的那圈等高线。


通过上方三个子图,我们可以观察到:

  • 当学习率较小(如左图的 0.05)时,梯度下降路径较长,需要更多的迭代次数才能达到最小点。这意味着我们需要经过多轮迭代才能找到最优的权重参数。
  • 当学习率适中(中图的 0.2)时,梯度下降可以较快地接近最小点。
  • 当学习率较大(如右图的 0.42)时,可能会导致过度更新,使得梯度下降路径在最小点附近游荡,难以稳定下来。

因此,在梯度下降法中,我们需要谨慎地来设置学习率。

这是因为:

  • 收敛速度:如果学习率设置得过小,梯度下降可能会非常缓慢地收敛到最小值,这会增加达到最优解所需的迭代次数,导致训练过程耗时更长。
  • 反复横跳:如果学习率设置得过大,可能会导致参数更新过度,从而使得算法在最小值附近跳跃,甚至可能越过最小值点,使得损失函数反而增加。这会导致算法发散,无法找到最小值。
  • 避免陷入局部最小值:一个好的学习率设置可以帮助算法准确地收敛到损失函数的全局最小值或一个好的局部最小值,而不是收敛到一个不太理想的局部最小值或鞍点。
  • 稳定性:过大的学习率可能导致在最小值周围震荡而不是收敛,而一个适当的学习率则可以确保参数更新过程平稳且稳定地接近最优解。

随机梯度下降法

在上一小节我们介绍了梯度下降法,此时,我们已经拥有了对权重参数进行优化的范式。然而,在实际中,我们更多的使用一种叫随机梯度下降法(Stochastic Gradient Descent, SGD)的优化方式来对权重参数进行更新。

在机器学习中,当我们的损失函数是个体损失的总和时,我们不希望用所有样本来计算梯度进行一次单一的参数更新,因为这样计算和时间成本较高。

因此,我们可以每次只取数据集的一个小部分(称为一个小批量或minibatch)来计算梯度并更新参数,这样可以减少计算资源的消耗而且可以更快地进行多次参数更新。

我们定义一个minibatch的形式化表述为: $$ X\in\mathbb{R}^{B\times n},y\in{1,…,k}^B $$

随机梯度下降法的优化方式可被形式化表示为: $$ \theta:=\theta-\frac{\alpha}{B}\sum_{i=1}^{B}\nabla_{\theta}\ell(h_{\theta}(x^{(i)}),y^{(i)}) $$

交叉熵损失函数的梯度计算

在上一章节,我们知道了如何使用梯度对权重参数进行更新。此时,距离我们达成目的只差最后一步了——计算梯度

那么我们应该如何计算交叉熵损失函数的梯度呢? $$ \nabla_\theta\ell_{ce}(\theta^Tx,y)=? $$ 根据链式法则,上式可被表述为: $$ \frac\partial{\partial\theta}\ell_{ce}(\theta^Tx,y) = \frac{\partial\ell_{ce}(\theta^Tx,y)}{\partial\theta^Tx}\frac{\partial\theta^Tx}{\partial\theta} $$ 对于右侧式子,我们可以拆分成两项,分别是: $$ \frac{\partial\ell_{ce}(\theta^Tx,y)}{\partial\theta^Tx} \tag{1} $$ 和 $$ \frac{\partial\theta^Tx}{\partial\theta} \tag{2} $$ 对于 ${(1)}$:

还记得交叉熵损失函数的公式吗?让我们对损失函数关于某个类别的输出$h_i$求偏导。

$$ \begin{aligned} \begin{aligned}\frac{\partial\ell_{ce}(h,y)}{\partial h_i}\end{aligned}& \begin{aligned}=\frac{\partial}{\partial h_i}\left(-h_y+\log\sum_{j=1}^k\exp h_j\right)\end{aligned} \\ &=-1\{i=y\}+\frac{\exp h_i}{\sum_{j=1}^k\exp h_j} \end{aligned} $$

忽然我们有一个惊奇的发现,对交叉熵损失函数的求导结果中,竟然出现了$\frac{\exp h_i}{\sum_{j=1}^k\exp h_j}$ !有点眼熟对吗?这不正是Softmax(h(x))的展开嘛!

于是,我们可以$\begin{aligned}\nabla_h\ell_{ce}(h,y)=z-e_y\end{aligned}$来简化上述公式的结果。其中,$z=\mathrm{softmax}(h)$,$e_y$是对应于正确类别的one-hot编码向量。

对于 ${(2)}$:

我们可以很方便的求导 $$ \frac{\partial\theta^Tx}{\partial\theta} = x $$ 于是,$(0)$式可被表达为:

$$ \begin{aligned} \begin{aligned}\frac{\partial}{\partial\theta}\ell_{ce}(\theta^Tx,y)\end{aligned}& \begin{aligned}=\frac{\partial\ell_{ce}(\theta^Tx,y)}{\partial\theta^Tx}\frac{\partial\theta^Tx}{\partial\theta}\end{aligned} \\ &=({z-e_y})(x),\quad\text{where }z=\text{softmax}(\theta^Tx) \end{aligned} $$

距离大功告成就差最后一步了!

让我们再做一些矩阵对齐的操作…

于是,当输入为向量 $x$ 时,通过交叉熵损失函数对权重矩阵 $\theta$ 的梯度为: $$ \nabla_\theta\ell_{ce}(\theta^Tx,y)\in\mathbb{R}^{n\times k}=x(z-e_y)^T $$ 当输入拓展到batch中所有的向量 $x$ 拼接成的矩阵 $X$ 时,上式被拓展为: $$ \nabla_\theta \ell_{ce}(X\theta, y) \in \mathbb{R}^{n \times k} = X^T(Z - I_y) $$ 其中:

  • $X$ 是整个数据批量的特征矩阵。
  • $Z$ 是假设函数对于整个批量的预测概率矩阵。每一行对应一个样本的预测概率分布,通过将 $X\theta$ 输入softmax函数得到。
  • $ I_y $ 是一个矩阵,其中每一行对应一个样本的正确类别的one-hot编码向量。

至此,我们完成了交叉损失函数的梯度计算!我们可以用梯度来对权重矩阵进行更新了!

总结

在本文,我们介绍了Softmax函数、交叉熵损失函数、梯度、梯度下降法、随机梯度下降法、如何利用梯度下降法来对权重参数进行优化等问题。

欢迎关注后续文章~