dl-r-00线性全连接
线性回归
线性回归(linear regression)使用一个线性模型来定义, 将所有特征放到向量$\mathbf{x} \in \mathbb{R}^d $ 中,并将所有权重放到向量 ,$\mathbf{w} \in \mathbb{R}^d$ 中,我们可以用点积形式来简洁地表达模型:
\[\hat{y}=\mathbf{w}^{\top} \mathbf{x}+b\]考虑如何用模型拟合(fit)数据之前,我们需要确定一个拟合程度的度量。损失函数(loss function) 能够量化目标的实际值与预测值之间的差距。通常我们会选择非负数作为损失 :
\[l^{(i)}(\mathbf{w}, b)=\frac{1}{2}\left(\hat{y}^{(i)}-y^{(i)}\right)^2\]事实上,在训练模型的时候,我们使用一组参数最小化在所有训练样本上的损失:
\[\mathbf{w}^*, b^*=\underset{\mathbf{w}, b}{\operatorname{argmin}} L(\mathbf{w}, b)\]线性回归是有解析解的,这里我们也乐意尝试使用随机梯度下降的方法,即随机抽取小批量样本计算损失函数关于模型参数的梯度。
以上都摘选自《动手学深度学习》,里面一个提醒我的也是我觉得所有人有必要知道的就是为什么可以使用该损失函数进行建模。事实上,对线性回归模型进行建模,加入高斯随机噪声,进行逐步推导,我们会发现这个损失函数即线性模型的极大似然估计(推导见动手学深度学习92页)。
这里进行一次重复造轮子的工作,随机取数并进行线性回归拟合。/毕竟基本功还是要有的/
import torch
from torch import nn
from torch.utils import data
import matplotlib.pyplot as plt
def synthetic_data(w, b, num_examples):
X = torch.normal(0, 1, (num_examples, len(w)))
y = torch.matmul(X, w) + b
y += torch.normal(0, 0.01, y.shape)
return X, y.reshape((-1, 1))
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)
true_w = torch.tensor([2,-3.4])
true_b = 4.2
features, labels = synthetic_data(true_w, true_b, 1000)
plt.scatter(features[:,(1)].detach().numpy(),labels.detach().numpy(),1)
batch_size = 8
data_iter = load_array((features, labels), batch_size)
next(iter(data_iter))
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.01)
num_epochs = 5
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}')
print(net[0].weight.data - true_w)
print(net[0].bias.data - true_b)
输出结果:
epoch 1, loss 0.187031
epoch 2, loss 0.001173
epoch 3, loss 0.000104
epoch 4, loss 0.000097
epoch 5, loss 0.000097
tensor([[0.0006, 0.0003]])
tensor([-0.0003])
各个参数的误差小于0.001,finish。
SoftMax回归
考虑一个多分类任务中,如果我们使用类似于线性回归的方式得到最后的输出结果,如何去衡量每个类别呢?统计学家很早以前就发明了一种表示分类 数据的简单方法:独热编码(one‐hotencoding)。独热编码是一个向量,它的分量和类别一样多。类别对应的分量设置为1,其他所有分量设置为0。在我们的例子中,标签y将是一个三维向量,其中(1,0,0)对应于 “猫”、(0,1,0)对应于“鸡”、(0,0,1)对应于“狗”。
但是我们知道线性回归的未规范化的输出是无法直接认为是独热编码,因为我们并没有限制输出为[0,1]的区间;SoftMax回归就可以很好的完成这个任务
\[\hat{\mathbf{y}}=\operatorname{softmax}(\mathbf{o})\] \[\hat{y}_j=\frac{\exp \left(o_j\right)}{\sum_k \exp \left(o_k\right)}\]同样的,这里对于损失函数的推导也比较感兴趣,/好吧,每次打通两个课程,把学到的数学知识用上都会让我很舒服/,仍然是使用最大似然估计,从条件概率推导出了信息交叉熵。这部分简单延展一下,因为初看的时候我看得有点懵。
我们要最大化条件概率:
\[P(\mathbf{Y} \mid \mathbf{X})=\prod_{i=1}^n P\left(\mathbf{y}^{(i)} \mid \mathbf{x}^{(i)}\right)\]我比较懵的地方是样本的条件概率应该是什么形式,现在给出来并予以说明:
\[P(\mathbf{y} \mid \mathbf{x})=\prod_{j=1}^q \hat{y}_j^{y_j}\]$y_j$是独热标签,即每一项只可能取0或1,$\hat{y}_j$是经过softmax得到的最终概率,所以只有真实类别的$\hat{y}_j$会留下,完成了统一建模很巧妙。
\[-\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)\] \[l(\mathbf{y}, \hat{\mathbf{y}})=-\sum_{j=1}^q y_j \log \hat{y}_j\]上式即交叉熵损失。
后续还有关于导数的推导,参见P109,公式3.4.9 - 3.4.10。