女的有没有做网站的,上海市建设厅网站,wordpress 3.6,政务网站模板深度学习——线性神经网络一 文章目录 前言一、线性回归1.1. 线性回归的基本元素1.1.1. 线性模型1.1.2. 损失函数1.1.3. 解析解1.1.4. 随机梯度下降1.1.5. 用模型进行预测 1.2. 向量化加速1.3. 正态分布与平方损失1.4. 从线性回归到深度网络 二、线性回归的从零开始实现2.1. 生… 深度学习——线性神经网络一 文章目录 前言一、线性回归1.1. 线性回归的基本元素1.1.1. 线性模型1.1.2. 损失函数1.1.3. 解析解1.1.4. 随机梯度下降1.1.5. 用模型进行预测 1.2. 向量化加速1.3. 正态分布与平方损失1.4. 从线性回归到深度网络 二、线性回归的从零开始实现2.1. 生成数据集2.2. 读取数据集2.3. 初始化模型参数2.4. 定义模型2.5. 定义损失函数2.6. 定义优化算法2.7. 训练 三、线性回归的简洁实现3.1. 生成数据集3.2. 读取数据集3.3. 定义模型3.4. 初始化模型参数3.5. 定义损失函数3.6. 定义优化算法3.7. 训练 总结 前言
书接上章当预备知识有一定了解后接下来将进入神经网络的学习而本章主要介绍一下最简单的人工神经网络——线性神经网络。 参考书 《动手学深度学习》 一、线性回归 回归regression是能为一个或多个自变量与因变量之间关系建模的一类方法。在机器学习领域中的大多数任务通常都与预测有关。 当我们想预测一个数值时就会涉及到回归问题。 我们把试图预测的目标称为标签label或目标target。 预测所依据的自变量称为特征feature或协变量。 1.1. 线性回归的基本元素
1.1.1. 线性模型 在机器学习领域我们通常使用的是高维数据集建模时采用线性代数表示法会比较方便。 当我们的输入包含d个特征时我们将预测结果 y ^ \hat{y} y^通常使用“尖角”符号表示y的估计值表示为 y ^ w 1 x 1 . . . w d x d b . \hat{y} w_1 x_1 ... w_d x_d b. y^w1x1...wdxdb.
将所有特征放到向量 x \mathbf{x} x中并将所有权重放到向量 w \mathbf{w} w中我们可以用点积形式来简洁地表达模型 y ^ w ⊤ x b . \hat{y} \mathbf{w}^\top \mathbf{x} b. y^w⊤xb.
上式向量 x \mathbf{x} x对应于单个数据样本的特征。 用符号表示的矩阵 X \mathbf{X} X 可以很方便地引用我们整个数据集的 n n n个样本。其中 X \mathbf{X} X的每一行是一个样本每一列是一种特征。
对于特征集合 X \mathbf{X} X预测值 y ^ \hat{\mathbf{y}} y^可以通过矩阵-向量乘法表示为 y ^ X w b {\hat{\mathbf{y}}} \mathbf{X} \mathbf{w} b y^Xwb 线性回归的目标是找到一组权重向量 w \mathbf{w} w和偏置 b b b 这组权重向量和偏置能够使得新样本预测标签的误差尽可能小。 1.1.2. 损失函数 损失函数loss function能够量化目标的实际值与预测值之间的差距。 通常我们会选择非负数作为损失且数值越小表示损失越小完美预测时的损失为0。 回归问题中最常用的损失函数是平方误差函数。当样本 i i i的预测值为 y ^ ( i ) \hat{y}^{(i)} y^(i)其相应的真实标签为 y ( i ) y^{(i)} y(i)时 平方误差可以定义为以下公式 l ( i ) ( w , b ) 1 2 ( y ^ ( i ) − y ( i ) ) 2 . l^{(i)}(\mathbf{w}, b) \frac{1}{2} \left(\hat{y}^{(i)} - y^{(i)}\right)^2. l(i)(w,b)21(y^(i)−y(i))2.
为了度量模型在整个数据集上的质量我们需计算在训练集 n n n个样本上的损失均值也等价于求和。 L ( w , b ) 1 n ∑ i 1 n l ( i ) ( w , b ) 1 n ∑ i 1 n 1 2 ( w ⊤ x ( i ) b − y ( i ) ) 2 . L(\mathbf{w}, b) \frac{1}{n}\sum_{i1}^n l^{(i)}(\mathbf{w}, b) \frac{1}{n} \sum_{i1}^n \frac{1}{2}\left(\mathbf{w}^\top \mathbf{x}^{(i)} b - y^{(i)}\right)^2. L(w,b)n1i1∑nl(i)(w,b)n1i1∑n21(w⊤x(i)b−y(i))2.
在训练模型时我们希望寻找一组参数 w ∗ , b ∗ \mathbf{w}^*, b^* w∗,b∗ 这组参数能最小化在所有训练样本上的总损失。如下式 w ∗ , b ∗ argmin w , b L ( w , b ) . \mathbf{w}^*, b^* \operatorname*{argmin}_{\mathbf{w}, b}\ L(\mathbf{w}, b). w∗,b∗w,bargmin L(w,b).
1.1.3. 解析解 线性回归的解可以用一个公式简单地表达出来 这类解叫作解析解analytical solution。但并不是所有的问题都存在解析解。 首先我们将偏置 b b b合并到参数 w \mathbf{w} w中合并方法是在包含所有参数的矩阵中附加一列。 我们的预测问题是最小化 ∥ y − X w ∥ 2 \|\mathbf{y} - \mathbf{X}\mathbf{w}\|^2 ∥y−Xw∥2。 这在损失平面上只有一个临界点这个临界点对应于整个区域的损失极小值点。 将损失关于 w \mathbf{w} w的导数设为0得到解析解 w ∗ ( X ⊤ X ) − 1 X ⊤ y . \mathbf{w}^* (\mathbf X^\top \mathbf X)^{-1}\mathbf X^\top \mathbf{y}. w∗(X⊤X)−1X⊤y.
1.1.4. 随机梯度下降 即使在我们无法得到解析解的情况下我们仍然可以有效地训练模型。 在许多任务上那些难以优化的模型效果要更好。 因此弄清楚如何训练这些难以优化的模型是非常重要的。 梯度下降gradient descent的方法几乎可以优化所有深度学习模型。它通过不断地在损失函数递减的方向上更新参数来降低误差
因为梯度下降在每次更新参数之前我们必须遍历整个数据集。执行极慢。所以通常采用小批量随机梯度下降 在每次迭代中我们首先随机抽样一个固定数量样本的小批量 B \mathcal{B} B 然后我们计算小批量的平均损失关于模型参数的导数也可以称为梯度。 最后我们将梯度乘以一个预先确定的正数 η \eta η并从当前参数的值中减掉。
我们用下面的数学公式来表示这一更新过程 ∂ \partial ∂表示偏导数 ( w , b ) ← ( w , b ) − η ∣ B ∣ ∑ i ∈ B ∂ ( w , b ) l ( i ) ( w , b ) . (\mathbf{w},b) \leftarrow (\mathbf{w},b) - \frac{\eta}{|\mathcal{B}|} \sum_{i \in \mathcal{B}} \partial_{(\mathbf{w},b)} l^{(i)}(\mathbf{w},b). (w,b)←(w,b)−∣B∣ηi∈B∑∂(w,b)l(i)(w,b).
对于平方损失和仿射变换我们可以明确地写成如下形式 w ← w − η ∣ B ∣ ∑ i ∈ B ∂ w l ( i ) ( w , b ) w − η ∣ B ∣ ∑ i ∈ B x ( i ) ( w ⊤ x ( i ) b − y ( i ) ) , b ← b − η ∣ B ∣ ∑ i ∈ B ∂ b l ( i ) ( w , b ) b − η ∣ B ∣ ∑ i ∈ B ( w ⊤ x ( i ) b − y ( i ) ) . \begin{aligned} \mathbf{w} \leftarrow \mathbf{w} - \frac{\eta}{|\mathcal{B}|} \sum_{i \in \mathcal{B}} \partial_{\mathbf{w}} l^{(i)}(\mathbf{w}, b) \mathbf{w} - \frac{\eta}{|\mathcal{B}|} \sum_{i \in \mathcal{B}} \mathbf{x}^{(i)} \left(\mathbf{w}^\top \mathbf{x}^{(i)} b - y^{(i)}\right),\\ b \leftarrow b - \frac{\eta}{|\mathcal{B}|} \sum_{i \in \mathcal{B}} \partial_b l^{(i)}(\mathbf{w}, b) b - \frac{\eta}{|\mathcal{B}|} \sum_{i \in \mathcal{B}} \left(\mathbf{w}^\top \mathbf{x}^{(i)} b - y^{(i)}\right). \end{aligned} wb←w−∣B∣ηi∈B∑∂wl(i)(w,b)w−∣B∣ηi∈B∑x(i)(w⊤x(i)b−y(i)),←b−∣B∣ηi∈B∑∂bl(i)(w,b)b−∣B∣ηi∈B∑(w⊤x(i)b−y(i)). ∣ B ∣ |\mathcal{B}| ∣B∣表示每个小批量中的样本数 η \eta η表示学习率 批量大小和学习率的值通常是手动预先指定而不是通过模型训练得到的。 这些可以调整但不在训练过程中更新的参数称为超参数调参是选择超参数的过程 1.1.5. 用模型进行预测 给定“已学习”的线性回归模型 w ^ ⊤ x b ^ \hat{\mathbf{w}}^\top \mathbf{x} \hat{b} w^⊤xb^现在我们可以通过给定特征来估计目标这个过程通常称为预测 1.2. 向量化加速 在训练我们的模型时我们经常希望能够同时处理整个小批量的样本。 为了实现这一点需要我们对计算进行向量化从而利用线性代数库而不是在Python中编写开销高昂的for循环。 import time
import numpy as np
import torch
from d2l import torch as d2l
n 10000
a torch.ones([n])
b torch.ones([n])
# print(a.numel())#我们定义一个计时器
class Timer: #save记录多次运行时间def __init__(self):self.times []self.start()def start(self):启动计时器self.tik time.time()def stop(self):停止计时器并将时间记录在列表中self.times.append(time.time() - self.tik)return self.times[-1]def avg(self):返回平均时间return sum(self.times) / len(self.times)def sum(self):返回时间总和return sum(self.times)def cumsum(self):返回累计时间return np.array(self.times).cumsum().tolist()c torch.zeros(n)
timer Timer()
#我们使用for循环每次执行一位的加法
for i in range(n):c[i] a[i] b[i]
print(f{timer.stop():.5f} sec)#使用重载的运算符来计算按元素的和
timer.start()
d a b
print(f{timer.stop():.5f} sec)#结果
0.10190 sec
0.00000 sec
结果很明显第二种方法比第一种方法快得多。向量化代码通常会带来数量级的加速。
1.3. 正态分布与平方损失 接下来我们通过对噪声分布的假设来解读平方损失目标函数。正态分布和线性回归之间的关系很密切。 简单的说若随机变量 x x x具有均值 μ \mu μ和方差 σ 2 \sigma^2 σ2标准差 σ \sigma σ其正态分布概率密度函数如下 p ( x ) 1 2 π σ 2 exp ( − 1 2 σ 2 ( x − μ ) 2 ) . p(x) \frac{1}{\sqrt{2 \pi \sigma^2}} \exp\left(-\frac{1}{2 \sigma^2} (x - \mu)^2\right). p(x)2πσ2 1exp(−2σ21(x−μ)2).
#正态分布与平方损失
def normal(x,mu,sigma):p 1/np.sqrt(2*math.pi*sigma**2)return p * np.exp(-0.5 /sigma**2 * (x-mu)**2)
# 再次使用numpy进行可视化
x np.arange(-7, 7, 0.01)# 均值和标准差对
params [(0, 1), (0, 2), (3, 1)]
d2l.plot(x, [normal(x, mu, sigma) for mu, sigma in params], xlabelx,ylabelp(x), figsize(6.5, 4.5),legend[fmean {mu}, std {sigma} for mu, sigma in params])
d2l.plt.show()
如图改变均值会产生沿 x x x轴的偏移增加方差将会分散分布、降低其峰值。 均方误差损失函数简称均方损失可以用于线性回归的一个原因是 我们假设了观测中包含噪声其中噪声服从正态分布。 噪声正态分布如下式: y w ⊤ x b ϵ , y \mathbf{w}^\top \mathbf{x} b \epsilon, yw⊤xbϵ,
其中 ϵ ∼ N ( 0 , σ 2 ) \epsilon \sim \mathcal{N}(0, \sigma^2) ϵ∼N(0,σ2)。
因此我们现在可以写出通过给定的 x \mathbf{x} x观测到特定 y y y的似然 P ( y ∣ x ) 1 2 π σ 2 exp ( − 1 2 σ 2 ( y − w ⊤ x − b ) 2 ) . P(y \mid \mathbf{x}) \frac{1}{\sqrt{2 \pi \sigma^2}} \exp\left(-\frac{1}{2 \sigma^2} (y - \mathbf{w}^\top \mathbf{x} - b)^2\right). P(y∣x)2πσ2 1exp(−2σ21(y−w⊤x−b)2).
现在根据极大似然估计法参数 w \mathbf{w} w和 b b b的最优值是使整个数据集的似然最大的值 P ( y ∣ X ) ∏ i 1 n p ( y ( i ) ∣ x ( i ) ) . P(\mathbf y \mid \mathbf X) \prod_{i1}^{n} p(y^{(i)}|\mathbf{x}^{(i)}). P(y∣X)i1∏np(y(i)∣x(i)).
根据极大似然估计法选择的估计量称为极大似然估计量。
由于历史原因优化通常是说最小化而不是最大化。我们可以改为最小化负对数似然 − log P ( y ∣ X ) -\log P(\mathbf y \mid \mathbf X) −logP(y∣X)。 − log P ( y ∣ X ) ∑ i 1 n 1 2 log ( 2 π σ 2 ) 1 2 σ 2 ( y ( i ) − w ⊤ x ( i ) − b ) 2 . -\log P(\mathbf y \mid \mathbf X) \sum_{i1}^n \frac{1}{2} \log(2 \pi \sigma^2) \frac{1}{2 \sigma^2} \left(y^{(i)} - \mathbf{w}^\top \mathbf{x}^{(i)} - b\right)^2. −logP(y∣X)i1∑n21log(2πσ2)2σ21(y(i)−w⊤x(i)−b)2.
现在我们只需要假设 σ \sigma σ是某个固定常数就可以忽略第一项 因为第一项不依赖于 w \mathbf{w} w和 b b b。 现在第二项除了常数 1 σ 2 \frac{1}{\sigma^2} σ21外其余部分和前面介绍的均方误差是一样的。 幸运的是上面式子的解并不依赖于 σ \sigma σ。 因此在高斯噪声的假设下最小化均方误差等价于对线性模型的极大似然估计。
1.4. 从线性回归到深度网络 尽管神经网络涵盖了更多更为丰富的模型我们依然可以用描述神经网络的方式来描述线性模型从而把线性模型看作一个神经网络。 二、线性回归的从零开始实现
2.1. 生成数据集 我们使用线性模型参数w[2,−3.4]⊤、b4.2 和噪声项ϵ生成数据集及其标签 yXwbϵ. ϵ可以视为模型预测和标签时的潜在观测误差。 在这里我们认为标准假设成立即ϵ服从均值为0的正态分布。 为了简化问题我们将标准差设为0.01。 下面的代码生成合成数据集
import random
import torch
from d2l import torch as d2l#生成数据集
def synthetic_data(w, b, num_examples): #save生成yXwb噪声X torch.normal(0, 1, (num_examples, len(w)))y torch.matmul(X, w) by torch.normal(0, 0.01, y.shape)return X, y.reshape((-1, 1))true_w torch.tensor([2, -3.4])
true_b 4.2
features, labels synthetic_data(true_w, true_b, 1000)
#features中的每一行都包含一个二维数据样本 labels中的每一行都包含一维标签值一个标量
print(features:, features[0],\nlabel:, labels[0])
#可视化线性关系第二个特征和标签值的散点图
# d2l.set_figsize()
d2l.plt.scatter(features[:, 1].detach().numpy(), labels.detach().numpy(), 1)
d2l.plt.show()#结果
features: tensor([-0.5307, 1.2137])
label: tensor([-0.9951])2.2. 读取数据集 定义一个data_iter函数 该函数随机接收批量大小、特征矩阵和标签向量作为输入生成大小为batch_size的小批量。 每个小批量包含一组特征和标签 #读取数据集
def data_iter(bath_size,features,labels):num_examples len(features) #获取数据集的总样本数量indices list(range(num_examples))random.shuffle(indices) #将样本索引列表打乱#这些样本是随机读取的没有特定的顺序for i in range(0,num_examples,bath_size):bath_indices torch.tensor(indices[i:min(ibath_size,num_examples)])yield features[bath_indices],labels[bath_indices]#查看
bath_size 10
for X ,y in data_iter(bath_size,features,labels):print(X,\n,y)break2.3. 初始化模型参数 在我们开始用小批量随机梯度下降优化我们的模型参数之前我们需要先有一些参数 #初始化参数
w torch.normal(0,0.01,size(2,1),requires_grad True)
b torch.zeros(1,requires_gradTrue)
2.4. 定义模型
#定义模型
def linreg(X,w,b):#线性回归模型return torch.matmul(X,w) b #或用torch.mv()
2.5. 定义损失函数
#定义损失函数
def squared_loss(y_hat,y):#均方损失return (y_hat - y.reshape(y_hat.shape))**2 / 2
2.6. 定义优化算法
#定义优化算法
def sgd(params,lr,bath_size):#小批量随机梯度下降with torch.no_grad():for param in params:param - lr *param.grad /bath_size #梯度反方向传播param.grad.zero_()
2.7. 训练
#训练执行以下循环
初始化参数
重复以下训练直到完成
计算梯度
更新参数
lr 0.03 #学习率
num_epochs 3 #迭代轮数
net linreg #线性模型
loss squared_loss #损失函数for epoch in range(num_epochs):for X,y in data_iter(bath_size,features,labels):l loss(net(X, w, b), y) # X和y的小批量损失# 因为l形状是(batch_size,1)而不是一个标量,l中的所有元素被加到一起# 并以此计算关于[w,b]的梯度l.sum().backward()sgd([w,b],lr,bath_size) # 使用参数的梯度更新参数with torch.no_grad():train_l loss(net(features,w,b),labels)print(fepoch{epoch 1},loss {float(train_l.mean()):f})#比较真实参数和通过训练学到的参数来评估训练的成功程度
print(fw的估计误差: {true_w - w.reshape(true_w.shape)})
print(fb的估计误差: {true_b - b})#结果
epoch1,loss 0.033319
epoch2,loss 0.000119
epoch3,loss 0.000048
w的估计误差: tensor([ 0.0004, -0.0006], grad_fnSubBackward0)
b的估计误差: tensor([0.0005], grad_fnRsubBackward1)
三、线性回归的简洁实现
3.1. 生成数据集 与前面类似 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)3.2. 读取数据集 features和labels作为API的参数传递并通过数据迭代器指定batch_size。 此外布尔值is_train表示是否希望数据迭代器对象在每个迭代周期内打乱数据。 取数据集
def load_array(data_arrays,batch_size,is_train True): #save#构造一个pytorch数据迭代器dataset data.TensorDataset(*data_arrays)return data.DataLoader(dataset,batch_size,shuffleis_train)batch_size 10
data_iter load_array((features, labels), batch_size)#print(next(iter(data_iter))) #从迭代器中获取第一项。
3.3. 定义模型 定义一个模型变量net它是一个Sequential类的实例。 Sequential类将多个层串联在一起。 当给定输入数据时Sequential实例将数据传入到第一层 然后将第一层的输出作为第二层的输入以此类推。 在下面的例子中我们的模型只包含一个层因此实际上不需要Sequential。 # nn是神经网络的缩写
from torch import nn
net nn.Sequential(nn.Linear(2, 1)) #2表示输入特征的维度1表示输出特征的维度
3.4. 初始化模型参数 我们通过net[0]选择网络中的第一个图层 然后使用weight.data和bias.data方法访问参数。 我们还可以使用替换方法normal_和fill_来重写参数值。 print(net[0].weight.data.normal_(0,0.01))
print(net[0].bias.data.fill_(0))
print(net[0])
print(net)#结果
tensor([[-8.8769e-03, -2.7674e-05]])
tensor([0.])
Linear(in_features2, out_features1, biasTrue)
Sequential((0): Linear(in_features2, out_features1, biasTrue)
)3.5. 定义损失函数 计算均方误差使用的是MSELoss类也称为平方L2范数。 默认情况下它返回所有样本损失的平均值。 loss nn.MSELoss()3.6. 定义优化算法 小批量随机梯度下降算法是一种优化神经网络的标准工具 PyTorch在optim模块中实现了该算法的许多变种。 当我们(实例化一个SGD实例)时我们要指定优化的参数 可通过net.parameters()从我们的模型中获得以及优化算法所需的超参数字典。 #定义优化算法:
trainer torch.optim.SGD(net.parameters(),lr 0.03)3.7. 训练 在每个迭代周期里我们将完整遍历一次数据集train_data 不停地从中获取一个小批量的输入和相应的标签。 对于每一个小批量我们会进行以下步骤: 通过调用net(X)生成预测并计算损失l前向传播。通过进行反向传播来计算梯度。通过调用优化器来更新模型参数。
#训练
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(fepoch {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)#结果
epoch 1, loss 0.000213
epoch 2, loss 0.000100
epoch 3, loss 0.000099
w的估计误差 tensor([3.5274e-04, 3.2663e-05])
b的估计误差 tensor([9.5367e-07])总结
本章根据书本知识详细介绍了线性神经网络中的线性回归原理并从零开始展示了线性回归的代码实现以及在pytorch深度学习框架下更简洁的线性回归代码实现。接下来将进入softmax回归的讲解。
靖康耻犹未雪臣子恨何时灭驾长车踏破贺兰山缺…
–2023-9-18 进阶篇