深度学习基础——线性神经网络

线性神经网络是深度神经网络的基础,本文介绍线性神经网络的相关内容。

线性回归

虽然神经网络的模型远比线性模型复杂,然而我们依然可以用描述神经网络的方式来描述线性模型,从而把线性模型看做一个神经网络,即线性模型为单层神经网络。如果要不使用库实现线性回归,可以按照如下步骤来进行

  • 生成数据集。此处我们手动生成数据集,数据服从正态分布。

  • 读取数据集

  • 初始化模型参数

  • 定义模型

  • 定义损失函数

  • 定义优化算法

  • 训练

以Pytorch为例,如果直接应用框架,可以通过如下代码实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
import numpy as np
import torch
from torch.utils import data
from d2l import torch as d2l

true_w = torch.tensor([2, -3.4])
true_b = 4.2
features, labels = d2l.synthetic_data(true_w, true_b, 1000)


def load_array(data_arrays, batch_size, is_train=True):  #@save
    """构造一个PyTorch数据迭代器。"""
    dataset = data.TensorDataset(*data_arrays)
    return data.DataLoader(dataset, batch_size, shuffle=is_train)

batch_size = 10
data_iter = load_array((features, labels), batch_size)


# `nn` 是神经网络的缩写
from torch import nn

net = nn.Sequential(nn.Linear(2, 1))
net[0].weight.data.normal_(0, 0.01)
net[0].bias.data.fill_(0)


loss = nn.MSELoss()
trainer = torch.optim.SGD(net.parameters(), lr=0.03)


num_epochs = 3
for epoch in range(num_epochs):
    for X, y in data_iter:
        l = loss(net(X) ,y)
        trainer.zero_grad()
        l.backward()
        trainer.step()
    l = loss(net(features), labels)
    print(f'epoch {epoch + 1}, loss {l:f}')
w = net[0].weight.data
print('w的估计误差:', true_w - w.reshape(true_w.shape))
b = net[0].bias.data
print('b的估计误差:', true_b - b)

softmax回归

softmax是社会学家邓肯·卢斯发明的函数,可以将为规范化的预测变化为非负,且总和为1,同时要求保持模型可导。softmax运算不会改变未规范化的预测之间的顺序,只会确定分配给每个类别的概率。softmax函数的导数是softmax模型分配的概率与实际发生的情况之间的差异。Softmax函数为

\[\hat{\mathbf{y}}=\operatorname{softmax}(\mathbf{o}), \hat{y}_{j}=\frac{\exp \left(o_{j}\right)}{\sum_{k} \exp \left(o_{k}\right)}\]

对于所有的$j$,总有$0 \le \hat{\mathbf{y}} \le1$,因此$\hat{\mathbf{y}}$可以视为一个正确的概率分布。Softmax运算不会改变预测$o$之间的顺序,只会确定分配给每个类别的概率,因此我们仍可以通过$\underset{j}{\operatorname{argmax}} \hat{y}{j}=\underset{j}{\operatorname{argmax}} o{j}$来选择最有可能的类别。

总而言之,softmax运算可以获取一个向量并将其映射为概率,我们最终得到的不是一个分类结果,而是整个结果分布,即结果是用一个概率向量表示的,每个分量表示结果为该分类的概率。softmax函数虽然不是线性函数,但因为其对输入做了仿射变换得到输出,因此,softmax回归是线性模型。

对于线性模型,我们采用极大似然估计作为损失函数。假设整个数据集${X,Y}$具有n个样本,其中索引$i$的样本由特征向量$x^{(i)}$和独热标签向量$y^{(i)}$组成,根据概率论原理,估计值和实际值之间有如下关系

\[P(\mathbf{Y} \mid \mathbf{X})=\prod_{i=1}^{n} P\left(\mathbf{y}^{(i)} \mid \mathbf{x}^{(i)}\right)\]

对上式两边取对数,根据极大似然估计易知,相当于最小化负对数似然

\[-\log P(\mathbf{Y} \mid \mathbf{X})=\sum_{i=1}^{n}-\log P\left(\mathbf{y}^{(i)} \mid \mathbf{x}^{(i)}\right)=\sum_{i=1}^{n} l\left(\mathbf{y}^{(i)}, \hat{\mathbf{y}}^{(i)}\right)\]

其中,对于任何标签$y$和模型预测$\hat{y}$,损失函数为

\[l(\mathbf{y}, \hat{\mathbf{y}})=-\sum_{j=1}^{q} y_{j} \log \hat{y}_{j}\]

上式被称为交叉熵损失。根据定义可知,$y$是一个独热编码向量,除了一项以外其他项全部为0,而$\hat{y_j}$均为预测概率,因此其对数值永远不会大于0。

将Softmax函数带入到交叉熵损失函数中,可以得到

\[\begin{aligned} l(\mathbf{y}, \hat{\mathbf{y}}) &=-\sum_{j=1}^{q} y_{j} \log \frac{\exp \left(o_{j}\right)}{\sum_{k=1}^{q} \exp \left(o_{k}\right)} \\ &=\sum_{j=1}^{q} y_{j} \log \sum_{k=1}^{q} \exp \left(o_{k}\right)-\sum_{j=1}^{q} y_{j} o_{j} \\ &=\log \sum_{k=1}^{q} \exp \left(o_{k}\right)-\sum_{j=1}^{q} y_{j} o_{j} \end{aligned}\]

求损失函数在预测$o_j$方向的导数,可以得到

\[\partial_{o_{j}} l(\mathbf{y}, \hat{\mathbf{y}})=\frac{\exp \left(o_{j}\right)}{\sum_{k=1}^{q} \exp \left(o_{k}\right)}-y_{j}=\operatorname{softmax}(\mathbf{o})_{j}-y_{j}\]

由上式可以知道损失函数的导数为Softmax函数与观测值之差,即损失函数的梯度为观测值与估计值之差,这与线性回归中的结论相吻合。

通过推导可以得出此时的损失函数为预测值(概率向量)的负对数值用自身分量加权后的和,此损失称为交叉熵损失。