机器学习
机器学习VS数据驱动编程

假如你想要写一个程序来分类手写数字的类别,很难去用程序表明哪个图片代表哪个数字,也很难去实现程序的流程逻辑。
使用(有监督)机器学习方法就可以很好的实现这一需求:
- 收集带标签的数据集对
- 将这些数据喂给机器学习算法
- 通过机器学习可以自动的产生一个能够解决上述问题的程序。
如下图:

机器学习算法简介
所有的机器学习算法可以由三个部分组成:
- 假设: 这是一个程序结构,通过一组可调节的参数,描述我们如何将输入(如数字图像)映射到输出(如类标签或不同类标签的概率)。
- 损失函数: 这个函数用来衡量我们的假设在这个特定问题的求解上表现的有多好。
- 优化方法: 调节假设中参数的过程,目的是使得训练集上的损失函数值总和最小。
SoftMax回归分类案例
基本情况
我们试着解决一个K分类问题,现在我们有如下东西:
- 训练数据: x(i)∈Rn, y(i)∈{1,…,k} for i=1,…,m
- n=输入数据的维度
- k=数据的类别数
- m=训练集的数据数
例如:对像素大小为28×28的MINST手写数据集分类
- n=28×28=784
- k=10
- m=60000
线性假设函数
我们提出一个线性假设函数,将输入x∈Rn映射到一个k维向量:
h:Rn→Rk
hi(x)可以表示为一种可信度,即x的标签有多大的可能性是第i类(那么最有可能的预测类别为最大hi(x)中的i类)
我们使用线性代数中的矩阵乘法来描述这个假设函数:
hθ(x)=θTx
其中θ∈Rn×k
使用批量矩阵写法
X∈Rm×n=−x(1)T−⋮−x(m)T−
y∈{1,…,k}m=y(1)⋮y(m)
那么根据上面这两个形式,线性假设可以写成如下形式:
hθ(X)=−hθ(x(1))T−⋮−hθ(x(m))T−=−x(1)Tθ−⋮−x(m)Tθ−=Xθ
损失函数
基于分类误差
分类任务中最简单的损失函数就是基于分类错误的损失函数,即如果分类错误就有损失值,否则无损失值。我们可以用下面这个公式来表示这种情况:
ℓerr(h(x),y)={01if argmaxihi(x)=yotherwise
我们通常使用这个损失函数来估计分类器的好坏。这个损失函数很直观的表明了一个分类器的好坏。
但是它的缺点是,我们很难根据这个损失函数通过优化器来对参数进行优化,因为这个损失函数是不可微分的。
基于softmax/cross-entropy loss
前面的损失函数,只是简单的判断哪一个类别的可能性会更大。让我们对假设函数输出的第i项求幂,然后除以每一项求幂的和。这样做可以把假设函数输出的值转换为概率,且所有项的概率加起来为1。这就是softmax过程,用公式表示如下:
zi=p(label=i)=∑j=1kexp(hj(x))exp(hi(x))⇔z≡softmax(h(x))
然后我们将损失值定义为概率的负对数,这就是softmax或者说cross-entropy(交叉熵)损失
ℓce(h(x),y)=−log p(label=y)=−hy(x)+logj=1∑kexp(hj(x))
softmax回归优化问题
机器学习算法的第三个要素,是通过优化算法,优化出一组假设函数中的参数,使得训练数据集中平均损失值最小。
θminimize m1i=1∑mℓ(hθ(x(i)),y(i))
通过我们前面的推理,上述式子也可以替换成下面的形式:
θminimizem1i=1∑mℓce(θTx(i),y(i))
那么我们应该如何去找到θ来解决这个优化问题呢?
优化方法:梯度下降
对于一个矩阵作为输入,标量作为输出的函数f:Rn×k→R,梯度定义为矩阵的偏导数,

梯度在物理学中通常指的是一个量的空间变化率,它描述了这个量在不同方向上变化的快慢。在数学上,梯度是一个向量微积分的概念,表示一个多变量函数在某一点处的局部变化率最大的方向和大小。梯度的方向是函数增长最快的方向,其大小是函数在该方向上增长的速率。
在机器学习中,梯度下降算法是一种优化算法,用于最小化一个目标函数,通常这个函数是损失函数(或代价函数),它衡量了模型预测值与实际值之间的差异。梯度下降算法的核心思想是利用负梯度方向作为搜索方向,因为这是函数值减小最快的方向。
为了最小化一个函数,梯度下降算法通过不断迭代向负梯度方向更新参数
θ:=θ−α∇θf(θ)
其中 α>0,α 是每次调整的步长或者称为学习率。
学习率的设置不能太小或者太大,太小了会使得结果收敛所需时间太长,太大了可能会使得训练结果收敛不了。可以从下图中看出不同学习率大小对训练的影响:

Stochastic gradient descent(随机梯度下降)
如果我们不想一次计算所有训练数据的损失值(可能受限于机器的内存大小等),我们可以每次取一个Batch的训练数据集来对参数进行优化更新。
然后不断重复使用小批次训练数据优化更新参数,最终获得一组比较的参数,用公式表示如下:
Repeat:Sample a minibatch of data X∈RB×n,y∈{1,…,k}BUpdate parameters θ:=θ−Bαi=1∑B∇θℓ(hθ(x(i)),y(i))
梯度下降(Batch Gradient Descent)
- 全批量更新:梯度下降每次更新模型参数时,都使用整个训练集来计算损失函数的梯度。
- 计算成本高:由于每次迭代都需要整个数据集,因此计算成本较高,尤其是在数据集很大时。
- 内存需求大:需要足够的内存来存储整个训练集。
- 收敛性:通常收敛到全局最小值,但这个过程可能需要很多迭代。
随机梯度下降(Stochastic Gradient Descent)
- 单样本更新:SGD每次更新模型参数时,只使用一个训练样本(或一小批样本)来计算梯度。
- 计算成本低:由于每次只处理一个样本,因此计算成本较低。
- 内存需求小:不需要存储整个训练集,只需当前样本即可。
- 快速收敛:通常能够更快地收敛到最小值附近,但可能收敛到局部最小值或鞍点。
- 噪声较大:由于每次只使用一个样本,梯度估计的噪声较大,导致学习路径波动较大。
softmax目标的梯度
我们应该如何计算softmax目标的梯度呢?
∇θℓce(θTx,y)=?
我们可以先把hθ(x) 看作一个k维向量,从而求 h∈Rk的梯度
∂hi∂ℓce(h,y)=∂hi∂(−hy + logj=1∑kexp hj)=−1{i=y} + ∑j=1kexp hjexp hi
用向量形式来表示的话则是∇hℓce(h,y)=z−ey,其中z=softmax(h),ey可以理解为一组单位基,是一个k维向量,在i=y的位置值为1,其他位置处值为0。
那么我们怎么计算∇θℓce(θTx,y)呢?
- 可以通过多元微积分的链式法则来分别对θ求偏导,但是处理所有维度的矩阵和向量变得很麻烦。
有两种方法可以解决上述麻烦:
- 方法一(正确的方法):使用矩阵微分、雅可比行列式、克罗内克积和矢量化
- 方法二(比较hacky的快速方法,但是大家都用的方法):假设一切都是标量,使用经典的链市法则,然后重新排列、转置矩阵或向量,使维度能够匹配。
下面我们来求损失的导数:
∂θ∂ℓce(θTx,y)=∂θTx∂ℓce(θTx,y)∂θ∂θTx=(z − ey)(x), (k−dim) (n−dim)where z=softmax(θTx)
因为(z − ey)是k维的,而(x)是n维的,为了让维度能够匹配式子正常运算,我们要做如下操作...
∇θℓce(θTx,y)∈Rn×k=x(z−ey)T
如果我们使用批量矩阵写法形式,下面的写法一样有效:
∇θℓce(Xθ,y)∈Rn×k=XT(Z−Iy), Z=softmax(Xθ)
总结
尽管我们上述的推导可能有些复杂,但是我们可以发现最终结果的表现形式是如此的简单,算法流程如下:
- 不断循环直到参数/损失收敛
- 在训练数据集X∈RB×n,y∈{1,…,k}B上进行小批次迭代
- 根据θ:=θ−BαXT(Z−Iy)来更新θ参数
这就是softmax回归算法的所有内容。