Softmax回归

应用场景

  • Softmax回归虽然名字叫回归,但它在多个线性回归输出基础上,经过了softmax operator,且最小化的是交叉熵损失,被用作多分类。
  • Softmax回归应用于多分类场景,也即给定多个特征,预测各类别的概率,比如图片多类别分类。
  • 类似的,Logistics回归是在单个线性回归输出的基础上,经过了sigmoid operator,且最小化的是交叉熵损失,被用作二分类。

模型

特征数 m m m,类别数 q q q,样本数 n n n

  • 单样本
    在每个类别上的预测值都是一个线性回归计算;
    q q q个类别上的预测值可以写为:
    y ^ = W ⊤ x + b , \hat{\mathbf y} = \mathbf{W}^\top \mathbf{x} + \mathbf b, y^=Wx+b,
    输入:特征向量 x ∈ R m × 1 \mathbf{x} \in \mathbb{R}^{m\times1} xRm×1
    输出:预测向量 y ^ ∈ R q × 1 \hat{\mathbf y} \in \mathbb{R}^{q\times1} y^Rq×1,是各个类别上的预测值
    参数:权重矩阵 W ∈ R m × q \mathbf{W} \in \mathbb{R}^{m\times q} WRm×q、向量 b ∈ R q × 1 \mathbf {b} \in {\mathbb {R}}^{q\times 1} bRq×1

  • 多样本
    Y ^ = X W + b , \hat{\mathbf Y} = \mathbf{X}\mathbf{W} + \mathbf b, Y^=XW+b,
    输入:特征矩阵 X = ( x ( 1 ) , x ( 2 ) , . . . , x ( n ) ) ⊤ ∈ R n × m \mathbf{X}=\left( \mathbf{x}^{(1)}, \mathbf{x}^{(2)}, ..., \mathbf{x}^{(n)} \right)^{\top} \in \mathbb{R}^{n\times m} X=(x(1),x(2),...,x(n))Rn×m
    输出:预测矩阵 Y ^ = ( y ^ ( 1 ) , y ^ ( 2 ) , . . . , y ^ ( n ) ) ⊤ ∈ R n × q \hat{\mathbf Y}=\left(\hat \mathbf y^{(1)},\hat \mathbf y^{(2)},...,\hat \mathbf y^{(n)} \right)^{\top} \in \mathbb{R}^{n\times q} Y^=(y^(1),y^(2),...,y^(n))Rn×q
    参数:权重矩阵 W ∈ R m × q \mathbf{W} \in \mathbb{R}^{m\times q} WRm×q、向量 b ∈ R q × 1 \mathbf {b} \in {\mathbb {R}}^{q\times 1} bRq×1(用了广播机制)

至此为止,得到的输出即为深度学习API调用时常说的logits数值,即还没有经过softmax或sigmoid激活函数的预测值,后面选用API时就选with_logits的。

补充一下,logit函数定义为:
L ( p ) = l n 1 1 − p L(p)=ln\frac {1}{1-p} L(p)=ln1p1

是一种将取值范围在[0,1]内的概率映射到实数域[-inf,inf]的函数,如果p=0.5,函数值为0;p<0.5,函数值为负;p>0.5,函数值为正。(相对地,softmax和sigmoid则都是将[-inf,inf]映射到[0,1]的函数。)

回归正题。直接输出回归预测值会导致两个问题:
(1)输出值的范围不确定,我们难以直观上判断这些值的意义;
(2)真实标签是离散值,难以衡量这些离散值与不确定范围的输出值之间的误差。

因此,在softmax回归预测值后面会跟一个softmax运算符(softmax operator),将一个样本的预测输出变换成值为正且和为1的概率分布:
y ^ = ( y ^ 1 y ^ 2 ⋮ y ^ q ) = softmax ( o 1 o 2 ⋮ o q ) , \hat \mathbf{y} = \begin{pmatrix} \hat{y}_1 \\ \hat{y}_2 \\ \vdots \\ \hat{y}_q \end{pmatrix} = \text{softmax} \begin{pmatrix} o_1\\ o_2 \\ \vdots \\o_q \end{pmatrix}, y^=y^1y^2y^q=softmaxo1o2oq,
其中,
y ^ 1 = exp ⁡ ( o 1 ) ∑ i = 1 q exp ⁡ ( o i ) , y ^ 2 = exp ⁡ ( o 2 ) ∑ i = 1 q exp ⁡ ( o i ) , ⋯   , y ^ q = exp ⁡ ( o q ) ∑ i = 1 q exp ⁡ ( o i ) . \hat{y}_1 = \frac{ \exp(o_1)}{\sum_{i=1}^q \exp(o_i)},\quad \hat{y}_2 = \frac{ \exp(o_2)}{\sum_{i=1}^q \exp(o_i)},\quad \cdots,\quad \hat{y}_q = \frac{ \exp(o_q)}{\sum_{i=1}^q \exp(o_i)}. y^1=i=1qexp(oi)exp(o1),y^2=i=1qexp(oi)exp(o2),,y^q=i=1qexp(oi)exp(oq).

Loss函数

交叉熵损失(cross entropy loss)
平方损失对于分类问题来说过于严格,想要预测分类结果正确,其实并不需要在各个类别上的预测概率值(通常某类别预测值比其他类别都大就可以预测对)完全等于标签中各类别的值(通常是one-hot),只需要预测的类别概率分布和标签的类别概率分布一致即可,也即对的类别概率比较大,错的类别概率比较小。通常用交叉熵来衡量两个概率分布的距离。

  • 单个样本
    对于第 i i i个样本,交叉熵可写为:
    H ( y ( i ) , y ^ ( i ) ) = − ∑ j = 1 q y j ( i ) log ⁡ y ^ j ( i ) , H\left(\mathbf y^{(i)}, \mathbf {\hat y}^{(i)}\right ) = -\sum_{j=1}^q y_j^{(i)} \log \hat y_j^{(i)}, H(y(i),y^(i))=j=1qyj(i)logy^j(i),
    对于单标签的场景,真实类别 y ( i ) \mathbf {y}^{(i)} y(i)是one-hot向量,里面的元素 y j ( i ) y_j^{(i)} yj(i)只有一个是1,其他全是0。所以这个式子对每一个样本来说,有且仅有一个累加项,也即 H ( y ( i ) , y ^ ( i ) ) = − log ⁡ y ^ y ( i ) ( i ) H(\mathbf y^{(i)}, \mathbf {\hat y}^{(i)}) = -\log \hat y_{y^{(i)}}^{(i)} H(y(i),y^(i))=logy^y(i)(i)。所以交叉熵只关心对正确类别的预测概率,因为只要其值足够大,就可以确保分类结果正确。
  • 多个样本
    ℓ ( Θ ) = 1 n ∑ i = 1 n H ( y ( i ) , y ^ ( i ) ) , \ell(\boldsymbol{\Theta}) = \frac{1}{n} \sum_{i=1}^n H\left(\mathbf y^{(i)}, \mathbf {\hat y}^{(i)}\right ), (Θ)=n1i=1nH(y(i),y^(i)),
    对于单标签的场景,交叉熵损失可以简写成 ℓ ( Θ ) = − ( 1 / n ) ∑ i = 1 n log ⁡ y ^ y ( i ) ( i ) \ell(\boldsymbol{\Theta}) = -(1/n) \sum_{i=1}^n \log \hat y_{y^{(i)}}^{(i)} (Θ)=(1/n)i=1nlogy^y(i)(i),最小化 ℓ ( Θ ) \ell(\boldsymbol{\Theta}) (Θ)等价于最大化 exp ⁡ ( − n ℓ ( Θ ) ) = ∏ i = 1 n y ^ y ( i ) ( i ) \exp(-n\ell(\boldsymbol{\Theta}))=\prod_{i=1}^n \hat y_{y^{(i)}}^{(i)} exp(n(Θ))=i=1ny^y(i)(i),即最小化交叉熵损失函数等价于最大化训练数据集所有标签类别的联合预测概率。

PyTorch实现

Softmax回归等价于一个全连接层,激活函数为softmax、输出层为n_class,用Pytorch的API即nn.Linear(n_feature, n_class),loss是nn.CrossEntropyLoss()(这个loss的实现里面已经包含了softmax计算,所以不需要手动在全连接层后面添加softmax激活函数,送入nn.CrossEntropyLoss的预测值是在经过softmax激活函数之前的logits):

softmax回归网络:

num_inputs = 784
num_outputs = 10

# 输入层
class FlattenLayer(nn.Module):
    def __init__(self):
        super(FlattenLayer, self).__init__()
    def forward(self, x): # x 的形状: (batch, *, *, ...)
        return x.view(x.shape[0], -1)

# softmax回归层
class LinearNet(nn.Module):
    def __init__(self, num_inputs, num_outputs):
        super(LinearNet, self).__init__()
        self.linear = nn.Linear(num_inputs, num_outputs)
    def forward(self, x): # x 的形状: (batch, 1, 28, 28)
        y = self.linear(x.view(x.shape[0], -1))
        return y

# 整个网络,顺序连接输入层和softmax回归层
from collections import OrderedDict
net = nn.Sequential(
        # FlattenLayer(),
        # LinearNet(num_inputs, num_outputs) 
        OrderedDict([
           ('flatten', FlattenLayer()), # 对输入的形状进行调整,相当于输入层,里面没有要学习的参数
           ('linear', LinearNet(num_inputs, num_outputs))]) # 或者写成我们自己定义的 LinearNet(num_inputs, num_outputs) 也可以
        )
print(net)

利用Softmax回归,实现图像多类别分类代码:
https://github.com/XuanxuanGao/MachineLearningWithPyTorch/blob/master/Softmax%E5%9B%9E%E5%BD%92.ipynb

你可能感兴趣的:(PyTorch,机器学习)