lec 1:Regression
1.5 Linear neural networks for regression线性神经网络的回归

1.5.1 Linear regression
输入特征的仿射变换Affine transformation(特征的加权和的线性变换和附加偏差的变换)
损失函数为平方误差squared error:
当训练模型时,找到在所有训练例子中使平均损失最小的参数(w∗,b∗):
即使我们不能解析地求解模型,我们仍然可以使用梯度下降算法来训练模型(迭代更新参数的方向,逐步降低损失函数)。
损失函数的导数是数据集中每个示例的损失的平均值。非常慢,因为我们必须通过整个数据集来进行更新。
1.5.2 Minibatch stochastic gradient descent 小批量随机梯度下降
策略:做一小批(Minibatch)观察。大小(size)取决于许多因素(内存、加速器的数量、图层的选择、总数据集的大小)。32到256之间,2^m(2的m次幂)这样的形式是一个好的开始。
●小批量随机梯度下降(SGD):
初始化参数。在每次迭代t中,
用|B|训练示例随机抽样一个小批量Bt;
计算小批量w.r.t.的平均损失梯度因素;
使用η作为学习速率,执行更新:
小批量处理的大小和学习率是由用户定义的。这种在训练循环中没有更新的可调参数被称为超参数(hyperparameters)。
经过多次迭代训练后,我们记录了估计的参数(ˆw,ˆb)。这些不是损失的最小化。
1.5.3 Maximum likelihood estimation最大似然估计
最小化平方误差损失相当于线性模型在加性高斯噪声下的最大似然估计:
线性回归是一个单层全连接的神经网络,有d个输入:x1,……,xd 和一个单一的输出。
1.5.4 Synthetic data合成数据
从标准正态set(X∈R^1000×2)中生成1000个examples,用于训练集和验证集。
设置w = [2,−3.4]^T,b=4.。绘制ε~N(0,0.01²)。
#Synthetic data
import random
import torch
from d2l import torch as d2l
data = d2l.SyntheticRegressionData(w=torch.tensor([2,-3.4]), b=4.2,
noise=0.01, num_train=1000, num_val=1000, batch_size=32)
模型训练需要多次传递一个数据集,每次使用一个小批处理来更新模型。数据处理器生成批量大小(batch_size)的小批量。每个小批处理都是一个特征和标签的元组。
在训练train模式下,我们以随机的顺序读取数据。在验证test模式下,按预定义的顺序读取数据可能对调试很重要。
X, y = next(iter(data.train_dataloader())) # inspect first minibatch
X.shape, y.shape # X: [32, 2], y: [32, 1]
len(data.train_dataloader()) # no. of batches: 32
1.5.5 Implementing linear regression 线性回归的实现
使用具有学习率lr=0.03和max_epochs=3的小批量SGD训练线性回归模型。在每个epoch中,我们遍历整个训练数据集,并通过每个示例传递一次。在每个epoch结束时使用验证数据集来测量模型的性能。
通过从N(0,0.01²)采样来初始化权重,并将偏差设置为0。
model = d2l.LinearRegression(lr=0.03)
trainer = d2l.Trainer(max_epochs=3)
trainer.fit(model, data)
w, b = model.get_w_b()
#compute differences
data.w - w.reshape(data.w.shape)
data.b - b
# error in estimating w: tensor([0.0025, -0.0070])
# error in estimating b: tensor([0.0096])
图中结果表明:估计的参数接近于真值。
•对于深度模型,不存在参数的唯一解。在机器学习中,我们不太关心恢复真正的基础参数,而是更关心能够导致准确预测的参数。
1.5.6 Generalization泛化
机器学习的基本问题是:发现能够泛化的模式。拟合更接近训练数据而不是基本分布的现象是过拟合overfitting,而对抗过拟合的技术被称为正则化regularization。
在标准的监督学习中,我们假设训练数据和测试数据是从相同的分布中独立地抽取的。
训练误差Training error:根据训练集计算的统计量,
泛化错误Generalization error:一个期望的w.r.t.基础分布,
通过将模型应用于独立的测试集来估计泛化误差.
当我们有简单的模型和丰富的数据时,训练误差和泛化误差往往会很接近。当我们使用更复杂的模型或更少的例子时,我们期望训练误差会减少,但泛化差距会增加。
深度神经网络在实践中可以很好地推广,但它们太强大了,我们无法仅根据训练错误就得出结论。我们必须依靠验证(保留数据)错误来证明泛化。
——————————————————————————————————————————
当训练误差和验证误差很大,且它们之间的差距很小时,可能会出现不拟合的情况underfitting(模型表达不足)。
训练误差显著低于验证误差表示过拟合。
使用一个d度的多项式:来估计给定单一特征x的标签y。
高阶多项式的训练误差总是较低的。一个具有d = n的多项式可以完美地拟合训练集。
随着我们增加训练数据时,泛化误差通常会减少。如果有更多的数据,我们可以拟合更复杂的模型。只有当有成千上万的训练例子可用时,深度学习才优于线性模型。
当训练数据稀缺时,我们可能没有足够的保留数据。在K倍交叉验证中,数据被分成K个不重叠的子集。模型训练和验证执行K次,每次在K−1个子集上进行训练,并对未使用的子集进行验证。训练和验证误差的估计是平均了K个实验的结果。
1.5.7 Weight decay 权重衰减
权重衰减可以通过限制参数采取的值来缓解过拟合。为了将w缩小到零,将其范数作为惩罚项(penalty term)添加到最小化损失的问题中:
正则化常数λ≥0是使用验证集选择的一个超参数。越小的λ对应于约束越小的w。我们通常不规范(正则化)偏差项b。
w的小批量SGD更新变为:
从上述方程式中生成数据,为了使过拟合效果更明显,设置n = 20和d = 200。
定义其中的类、数据和权重衰减:
#如何使用权重衰减(weight decay)来正则化模型
#定义了一个L2正则化项的函数l2_penalty,用来计算权重w的L2范数的平方除以2
def l2_penalty(w):
return (w**2).sum() / 2
#创建数据集data
data = Data(num_train=20, num_val=100,num_inputs=200, batch_size=5)
trainer = d2l.Trainer(max_epochs=10)
#创建了一个WeightDecay模型对象model,并将权重衰减参数wd设置为0,学习率lr设置为0.01。(对照)
model = WeightDecay(wd=0, lr=0.01)
#通过将model.board.yscale设置为'log',可以在训练过程中将损失函数的值以对数尺度显示
#有助于观察权重衰减的效果。
model.board.yscale='log'
trainer.fit(model, data)
l2_penalty(model.get_w_b()[0]) # 0.1318
#重新创建了一个WeightDecay模型对象model,将权重衰减参数wd设置为3,学习率lr设置为0.01(实验)
model = WeightDecay(wd=3, lr=0.01)
model.board.yscale='log'
trainer.fit(model, data)
l2_penalty(model.get_w_b()[0]) # 0.0145 比0.1318降低很多
在没有使用权值衰减时,我们非常糟糕的过拟合了。
随着权值的衰减,训练误差增加,而验证误差减小。
lec2:Multilayer Perceptrons 多层感知器
2.1 Linear neural networks for classification用线性神经网络进分类
◆图像分类:
- 每个输入都是一个2×2的灰度图像。
- 每个像素用一个标量表示,给出四个特征x1,x2,x3,x4。
- 每张图片都属于三类:猫、鸡、狗。
- 使用一个热编码表示标签:y是一个3-dim向量,(1、0、0)表示猫,(0、1、0)表示鸡,(0、0、1)表示狗。
- 线性模型:
- 相应的神经网络与单层完全连接。
- 给定一个合适的损失函数,我们可以最小化o和y之间的差值。将分类作为回归问题处理得很好,但是输出oi不能等于1或在[0,1]中。
要实现此目标,使用softmax函数:
为了提高效率,在小批量中向量化计算。对于小批量X(n×d维:n examples with d inputs)以及输出中的q个类别,
利用最大似然估计来优化从特征x到概率ˆy的映射精度。
2.1.1 Softmax and cross-entropy lossSoftmax和交叉熵损失

由于y是长度为q的独热向量,除一项外,所有j的和都消失了。
插入softmax的定义,
导数是模型分配的概率与观测值之间的差值。
对于一个分布P,它的熵是:
从P到Q的交叉熵是:
当P=Q时,交叉熵是最低的。
2.1.2 Image classification dataset 图像分类数据集
#使用了PyTorch和d2l库来加载FashionMNIST数据集
import torch; import torchvision
from torchvision import transforms
from d2l import torch as d2l
d2l.use_svg_display() # output graphics in SVG format 设置d2l库使用SVG格式输出图形。
data = d2l.FashionMNIST(resize=(32, 32)) # upscale to 32 x 32 via interpolation
len(data.train) # 60000
len(data.val) # 10000
data.train[0][0].shape # [1, 32, 32]
batch = next(iter(data.val_dataloader())) # 1st batch of validation set
data.visualize(batch) # 1: white, 0:black
约定:将图像存储为c×h×w张量,其中c为颜色通道数,h是高度,w是宽度。
2.1.3 Implement softmax regression 实现softmax回归
- 将每张28×28像素的图像折叠起来,作为长度为784的输入向量。
- 输出的个数为10,等于类的数目。
- 权重构成一个784×10矩阵加上一个1×10行的偏差向量。
- 用高斯噪声和偏差将权值初始化为零。
- 训练模型使用10个epoch。epoch数目,小批量大小和学习率都是超参数hyperparameters,并应根据实践中的验证集进行选择。然后在测试集上评估模型的最终结果。
#训练一个Softmax回归模型来对FashionMNIST数据集中的图像进行分类
from torch import nn
from torch.nn import functional as F
data = d2l.FashionMNIST(batch_size=256)
#构建一个具有10个输出类别的Softmax回归模型,并设置学习率为0.1
model = d2l.SoftmaxRegression(num_outputs=10, lr=0.1)
trainer = d2l.Trainer(max_epochs=10)
trainer.fit(model, data)
2.1.4 Prediction 预测
使用训练好的模型对一些图像进行分类。
#从验证集中获取第一个批次数据,
#然后使用训练好的Softmax回归模型对这批数据进行预测,
#并可视化预测结果中被错误分类的样本
X, y = next(iter(data.val_dataloader())) # 1st batch of validation set, batch_size=256
model(X).shape # torch.Size([256, 10])
#对每个样本,选择具有最高概率的类别作为预测结果
preds = model(X).argmax(axis=1) # find class with highest prob for each eg
#返回一个形状为[256]的张量 表示每个样本的预测类别
preds.shape # torch.Size([256])
#找出预测错误的样本,返回一个布尔型张量,形状与preds和y相同,对应位置为True表示预测错误
wrong = (preds != y) # find egs whose classes are predicted wrongly
#根据预测错误的布尔掩码,从原始数据中提取预测错误的样本
#分别存储为X(图像数据)、y(真实标签)、preds(预测标签)
X, y, preds = X[wrong], y[wrong], preds[wrong]
#将真实标签和预测标签拼接成字符串列表,用于可视化时显示每个样本的真实类别和预测类别。
labels = [a + '\n' + b for a, b in zip(data.text_labels(y), data.text_labels(preds))]
#可视化
data.visualize([X, y], labels=labels)
通过比较实际的标签(文本输出的第一行)与模型的预测(文本输出的第二行),可视化一些错误标记的图像。
2.2 Multilayer perceptrons 多层感知器
- 最简单的深度网络是多层感知器(由多层神经元组成,每个神经元都与下面和上面的一层完全相连)。
- 线性模型暗示了单调性(一个特征的增加必须导致输出的增加/减少),但其他特征是固定的。
- 有时这是有道理的,但违反单调性的例子却很丰富。在对猫和狗的图像进行分类时,增加一个像素的强度是否总是增加/减少图像描绘一只狗的可能性?
- 如何用简单的转换来解决这个问题并不明显,因为任何像素的重要性都以复杂的方式取决于周围的像素。
- 通过合并隐藏层,将完全连接的层相互叠加,克服了线性模型的局限性。每一层都输入到它上面的一层中,直到我们生成输出。这是多层感知器(MLP)的架构。
2.2.1 Incorporating hidden layers 合并隐藏层
- 这个MLP有4个输入,3个输出,隐藏层有5个隐藏单元。
- 输入层不涉及计算。产生输出需要计算隐藏层和输出层。因此,在这个MLP中的层是2。这两层都是完全连接的。
- 总共有n个例子,每个例子都有d个输入。
- 对于具有h隐藏单元的单隐藏层MLP,
表示隐藏层的输出。
- 添加隐藏层不会获得任何好处。上面的MLP仍然是一个线性模型!
- 为实现多层结构潜力,关键成分是在仿射变换后对每个隐藏单元应用非线性激活函数σ(·)。
- 有了激活函数,我们就不能再把MLP分解成线性模型了:
- 定义σ(·),以按元素的方式应用于其输入。
- 为了构建更通用的MLPs,堆栈隐藏层,
,...,一个接一个地产生更具表现力的模型。
- 一个单一的隐层网络可以通过给定足够的节点和正确的权值集来建模任何函数,但我们不应该用它来解决每个问题,因为我们可以使用更深(相对于更宽)的网络来更紧凑地近似许多函数。
2.2.2 Activation functions 激活函数
激活函数增加了非线性,是将输入信号转换为输出的可微算符。
★ReLU (整流线性单元rectified linear unit) function
- ReLU(x) = max(x, 0).
- 最流行的选择(简单实现,在各种预测任务上具有良好的性能)。
- 当x<0时,导数为0,当x>0时为1。在0处不可微,但我们说导数在x=值0处是0。
- 它的导数表现得很好(消失或让参数通过)。这使得优化表现得更好,并缓解了困扰早期神经网络的梯度消失的问题。


- 将R中的任何输入压缩为(0,1)中的值。
- 在早期的神经网络中,科学家们对模拟是否点火的生物神经元很感兴趣。
- 对阈值激活的平滑近似(输入<阈值时为0,输入>阈值时为1)。
-
当输入接近于0时,接近一个线性变换。 - 给优化带来了挑战,因为它的梯度为大的积极和消极的参数消失,导致难以摆脱的高原。
- 当我们想将输出解释为二进制分类中的概率(softmax的特殊情况)时,作为输出单元上的激活函数使用。
★Tanh (双曲切线hyperbolic tangent) function
- 将R中的任何输入压缩为(−1,1)中的值。
- 当输入接近0时接近线性变换。
- 形状与s型相似,但tanh对原点呈点对称。
- 当输入接近于0时,导数接近于最大值1。当输入在任何一个方向上远离0时,导数趋于0。
2.2.3 Implement MLPs 实现MLPs
mlp的实现并不比线性模型复杂多少。关键的区别在于:连接多个层并应用激活函数。
时尚-MNIST有10个class。每幅图像都有一个28×28 = 784的灰度像素值网格。
MLP:一个隐藏层和256个隐藏单元。不的层和宽度是可调的。
选择宽度为2^m形式(由于硬件中的内存分配,计算效率高)。
class MLP(d2l.Classifier):
def __init__(self, num_outputs, num_hiddens, lr):
#调用父类(Classifier类)的初始化方法,确保正确初始化。
super().__init__()
#保存模型的超参数,以便在需要时进行访问和记录。
self.save_hyperparameters()
#定义了一个包含两个隐藏层的神经网络模型
#包括一个Flatten层(用于将输入数据展平)、两个LazyLinear层(延迟初始化的全连接层)、一个ReLU激活函数层。
self.net = nn.Sequential(nn.Flatten(), nn.LazyLinear(num_hiddens),
nn.ReLU(), nn.LazyLinear(num_outputs))
data = d2l.FashionMNIST(batch_size=256)
#创建一个MLP模型对象,指定输出类别数为10,隐藏层单元数为256,学习率为0.1。
model = MLP(num_outputs=10, num_hiddens=256, lr=0.1)
trainer = d2l.Trainer(max_epochs=10)
trainer.fit(model, data)
2.3 Forward and backward propagation 正向传播和反向传播
在训练神经网络时,在初始化模型参数后,交替进行正传播和反向传播。
前向传播:按从输入层到输出层的顺序计算和存储神经网络的中间变量。
反向传播:利用链规则从输出到输入层计算参数的梯度。存储了计算梯度时所需的中间偏导数。
神经网络有一个隐藏层,无偏差和输入
有向图:可视化变量的依赖性。
反向传播的目标:计算梯度
从结果开始,并努力走向参数。v(·)从左到右依次向量化一个矩阵。
反向传播重用正向传播中存储的中间值,以避免重复计算。
需要保留中间值,直到反向传播完成为止。
因此,训练需要更多的记忆,而不是预测。
中间值的大小大致与图层和批处理的大小成正比。因此,使用更大的批处理规模来训练更深层次的网络会更容易导致内存耗尽错误。
2.4 Numerical stability and initialization 数值稳定性和初始化
初始化对于神经网络学习中的数值稳定性至关重要。
它与非线性激活函数的选择有关,并决定了算法收敛的速度。
糟糕的选择会导致在训练时的梯度爆炸/消失。
考虑具有L层、输入x和输出o的深度网络。对于每个层ℓ,定义由权重Wℓ参数化的转换fℓ,具有隐藏层输出令
那么,
易受数值下积问题的许多项可能很大或很小。
不可预测的幅度梯度威胁着算法的稳定性。参数更新可能过大(爆炸梯度问题)或过小(消失梯度问题),使得学习变得不可能。