李沐《动手学深度学习》 | 线性神经网络-线性回归
文章目录
- 线性回归
- 1.确定模型
- 2.衡量预估质量-损失函数
- 3.深度学习的基础优化算法
- 随机梯度下降
- 小批量随机梯度下降
- 从线性回归到深度网络
- 线性回归从0开始实现
- 构造一个人造数据集
- 创建数据集
- 可视化数据集
- 读取数据-随机抽取样本
- 模型定义
- 模型参数初始化
- 定义模型
- 定义损失函数
- 定义优化算法 - 小批量随机梯度下降
- 训练
- 代码总结
- 线性回归的简洁实现
- 1.生成数据集
- 2.读取数据集
- 3.模型定义
- 4.初始化模型参数
- 5.定义损失函数
- 6.定义优化算法
- 7.训练
- 完整训练流程
线性回归
回归:建模一个或多个自变量与因变量之间的关系
1.确定模型
案例:我们希望开发一个能预测房屋价格的模型
假设1:影响房价的关键因素是卧室个数,卫生间个数和居住面积,记为 x 1 , x 2 , x 3 x_1,x_2,x_3 x1,x2,x3
假设2:成交价是关键因素的加权和 y = w 1 x 1 + w 2 x 2 + w 3 x 3 + b y=w_1x_1+w_2x_2+w_3x_3+b y=w1x1+w2x2+w3x3+b
权重 w 1 , w 2 , w 3 w_1,w_2,w_3 w1,w2,w3和偏差 b b b的实际值在后面决定
权重决定了每个特征队我们预测值的影响。偏置是值当所有特征值都取0时,预测值应该是多少。
上述的式子可以看成输入特征的一个仿射变换。
仿射变换的特点是通过加权和特征进行线性变换,并通过偏置项进行平移。
目标变换:确定一下目标,我们希望开发一个房屋价格模型,根据假设问题变成了:
给定一个数据集,目标是寻找模型的权重w和偏置b,使得根据模型做出的预测大体符合数据中的真实价格。输出的预测值由输入特征通过线性模型的仿射变换确定,仿射变换由所选权重和偏置决定。
扩展到一般情况
给定d维输入 x = [ x 1 , x 2 , … , x d ] T x=[x_1,x_2,…,x_d]^T x=[x1,x2,…,xd]T,d个特征
线性模型有一个d维权重和一个标量偏差 w = [ w 1 , w 2 , . . . , w d ] T w=[w_1, w_2,...,w_d]^T w=[w1,w2,...,wd]T, b
输出是输入的加权和 y ^ = w 1 x 1 + w 2 x 2 + . . . + w d x d + b \hat y=w_1x_1+w_2x_2+...+w_dx_d+b y^=w1x1+w2x2+...+wdxd+b,通常使用尖角符号表示y的估计值
将所有特征放到向量 x ∈ R d x\in R^d x∈Rd中,并将所有权重放到向量 x ∈ R d x\in R^d x∈Rd中,可以用点积简洁表示模型 y ^ = w T x + b \hat y=w^Tx+b y^=wTx+b。
在这个式子中 x x x对应于单个数据样本的特征,整个数据集n个样本可以用矩阵 X ∈ R n × d X\in R^{n \times d} X∈Rn×d。其中X的每一行是一个样本,每一列是一种特征。
对于特征集合X,预测值 y ^ ∈ R n \hat y \in R^n y^∈Rn可以通过矩阵-向量乘法表示为 y ^ = X w + b \hat y =Xw+b y^=Xw+b
现在我们已经有一个模型了,接下来还需要两个工具
① 一种模型质量的度量方式
② 一种能够更新模型以提高模型预测质量的方法
2.衡量预估质量-损失函数
衡量方法:损失函数,比较真实值和预估值,比如房屋售价和估价
损失函数能够量化目标的实际值与预测值之间的差距,通常会选择非负数作为损失,且数值越小表示损失越小。
回归问题中最常用的损失函数是平方误差函数: l ( y , y ^ ) = 1 2 ( y − y ^ ) 2 l(y,\hat y) = \frac{1}{2}(y-\hat y)^2 l(y,y^)=21(y−y^)2,这里的 1 2 \frac{1}{2} 21不会带来本质的差别,只是为了损失函数求导后常数系数为1,形式上稍微简单一点。
为了度量模型再整个数据集上的预测质量,我们需要计算在n个样本上的损失均值: L ( X , y , w , b ) = 1 n ∑ i = 1 n l ( i ) ( w , b ) = 1 n ∑ i = 1 n 1 2 ( y ( i ) − y ^ ( i ) ) 2 = 1 n ∑ i = 1 n 1 2 ( y ( i ) − w T x ( i ) − b ) 2 = 1 2 n ∣ ∣ y − X w − b ∣ ∣ 2 L(X,y,w,b)=\frac{1}{n}\sum_{i=1}^n l^{(i)}(w,b) = \frac{1}{n}\sum_{i=1}^n\frac{1}{2}( y^{(i)}-\hat y^{(i)})^2 = \frac{1}{n}\sum_{i=1}^n\frac{1}{2}(y^{(i)}-w^Tx^{(i)}-b)^2 = \frac{1}{2n} ||y-Xw-b||^2 L(X,y,w,b)=n1∑i=1nl(i)(w,b)=n1∑i=1n21(y(i)−y^(i))2=n1∑i=1n21(y(i)−wTx(i)−b)2=2n1∣∣y−Xw−b∣∣2,这里的(i)表示第i个样本。
目标变换:现在我们的目标变成了寻找一个w*、b*使得损失函数L的值最小: w , b = a r g min w , b L ( X , y , w , b ) w,b= arg \min_{w,b}L(X,y,w,b) w,b=argminw,bL(X,y,w,b)
解析解: 线性回归的解可以用一个公式简单的表示,此类解叫做解析解(显示解)
<fo为了简化计算,通常将偏置项 b b b合并到权重向量 w w w中:
- 扩展矩阵:在 X X X的最后一列添加一列全1,得到新的设计矩阵: X = [ X 1 ] X=\begin{bmatrix} X&1 \end{bmatrix} X=[X1]维度 n × ( d + 1 ) n \times (d+1) n×(d+1)
- 扩展权重向量:将 b b b添加到 w w w的末尾,得到新的权重向量 w = [ w b ] w = \begin{bmatrix} w \\ b \\ \end{bmatrix} w=[wb]维度 ( d + 1 ) × 1 (d+1) \times 1 (d+1)×1
这样损失函数可以表示为 1 2 n ∣ ∣ y − X w ∣ ∣ 2 \frac{1}{2n} ||y-Xw||^2 2n1∣∣y−Xw∣∣2(Xw是一个 n × 1 n \times 1 n×1的向量)
因为这是一个线性模型,所以损失是一个凸函数,所以最优解满足求导结果为0。
可以通过求导来计算最小的w: ∂ ∂ w ( 1 2 n ∥ y − X w ∥ 2 ) \frac{\partial}{\partial w} ( \frac{1}{2n} \lVert y - Xw \rVert^2 ) ∂w∂(2n1∥y−Xw∥2),求出 w ∗ = ( X T X ) − 1 X T Y w^* = (X^TX)^{-1}X^TY w∗=(XTX)−1XTY
这里推荐视频:https://www.bilibili.com/video/BV1xk4y1B7RQ
3.深度学习的基础优化算法
随机梯度下降
最常见的优化方法:梯度下降 => 核心是不断在损失函数递减的方向上更新参数来降低误差
- 挑选一个随机初始值 w 0 w_0 w0,开始不断更新 w 0 w_0 w0使其接近最优解。
- 更新法则为: w t = w t − 1 − η ∂ L ∂ w t − 1 w_t = w_{t-1}-\eta \frac{\partial L}{ \partial w_{t-1}} wt=wt−1−η∂wt−1∂L η \eta η学习率,是步长的超参数
超参数hyperparameter:预先手动指定,不通过模型训练。可以调整但不在训练过程中更新的参数
调参hyperparameter tuning:选择超参数的过程
超参数通常是我们根据训练迭代(验证数据集上评估)的结果来调整的
学习率的选择
- 学习率不能选太小,太小每一次走的步长有限,需要更新很多次的梯度,而计算梯度是一个很贵的事情,我们希望梯度计算的次数较少(更新参数前需要遍历整个数据集)
- 学习率也不能选太大,步子迈大了可能导致一直在震荡而不是在下降
小批量随机梯度下降
在实际情况中,很少直接选择随机梯度下降,因为每一次计算梯度需要对损失函数求导,而损失函数需要遍历整个训练集。
在实际中最常见的版本是小批量随机梯度下降,核心是每次更新参数时随机抽取固定数量的一小批样本,至于固定数量是多少,这是另一个重要的超参数。
步骤
随机抽取小批量B个样本 i 1 , i 2 , . . . , i b i_1,i_2,...,i_b i1,i2,...,ib,然后计算小批量的损失均值 1 b ∑ i ∈ I b L ( x i , y i , w ) \frac{1}{b}\sum_{i \in I_b} L(x_i,y_i,w) b1∑i∈IbL(xi,yi,w)来近似整个数据集的损失均值。
从线性回归到深度网络
线性模型可以看作是单层神经网络,输入为 x 1 , . . . , x d x_1,...,x_d x1,...,xd,输入层中的输入数(特征维度)为d;网络的输出为 o 1 o_1 o1,输出层中的输出数是1。
在计算层数时不考虑输入层,所以下图神经网络的层数为1。
线性回归从0开始实现
这里只使用张量和自动求导,在之后的章节中会充分利用深度学习框架的优势,介绍更简单的实现方式。
构造一个人造数据集
创建数据集
使用线性模型参数 w = [ 2 , − 3 , 4 ] T 、 b = 4.2 w=[2,-3,4]^T、b=4.2 w=[2,−3,4]T、b=4.2和噪声项 ϵ \epsilon ϵ生成数据集及其标签: y = X w + b + c y=Xw+b+c y=Xw+b+c
变量x:从均值为0、标准差为1的正态分布中采样,生成形状为 (num_examples, len(w)) 的矩阵,表示 num_examples个样本(矩阵行数),每个样本有len(w) 个特征(矩阵列数)。
返回值reshape((-1, 1)),将数组转换为二维列向量,形状为(n,1)的二维数组
def synthetic_data(w, b, num_examples): #@save# 从0-1的离散正态分布中抽取随机数,返回一个张量X = torch.normal(0, 1, (num_examples, len(w)))# 矩阵乘法,通过线性变换 y = Xw + b 生成目标值y = torch.matmul(X, w) + b # torch.Size([10])# 引入均值为0、标准差为0.01的高斯噪声,模拟真实数据中的随机扰动。y += torch.normal(0, 0.01, y.shape) # torch.Size([10])# 将 y 转换为二维列向量(形状n,1)return X, y.reshape((-1, 1))# 这里调用函数生成1000个样本
true_w = torch.tensor([2, -3.4])
true_b = 4.2
features, labels = synthetic_data(true_w, true_b, 1000)
问题1:为什么需要转换维列向量(-1,1)
这里先随便生成10个数字,发现原始的y是一个一维数组,转换后y是一个10行1列的矩阵格式。
- 输入特征X的形状一般为(样本数, 特征数)(例如(1000, 2))。
- 标签y的形状应为 (样本数, 1),保持维度一致,之后计算才方便。
def synthetic_data(w, b, num_examples): #@save# 从均值为0、标准差为1的正态分布中采样,生成形状为# (num_examples, len(w)) 的矩阵,表示 num_examples 个样本,每个样本有 len(w) 个特征。#X = torch.normal(0, 1, (num_examples, len(w)))y = torch.matmul(X, w) + by += torch.normal(0, 0.01, y.shape)print("原始 y 的形状:", y,y.shape)y = y.reshape(-1,1)print("转换后 y 的形状:", 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, 10)原始 y 的形状: tensor([ 1.8253, 0.7458, 4.7804, 3.6786, -1.0490, 0.3278, 4.2530, 7.2494,3.8678, 10.9984]) torch.Size([10])
转换后 y 的形状: torch.Size([10, 1])
可视化数据集
features表示的每一行是一个二维数据(两个特征)的样本,labels中的每一行表示一个标签值
d2l.set_figsize()
:设置绘图的尺寸大小,不传参数则使用默认值
d2l.plt.scatter绘制二维散点图,将数据的第二个维度(特征)作为 x 轴坐标,将标签数据作为 y 轴坐标。参数 1是指定散点的大小。
features[:, 1].detach().numpy()
表示从数据features中,选择每个样本的第二个特征并转换维为NumPy 数组的形式
labels.detach().numpy()
表示将标签数据转换为NumPy 数组。
features, labels = synthetic_data(true_w, true_b, 1000)
#随机的一个样本数据
#features: tensor([1.7741, 0.0435])
#label: tensor([7.6021])
print('features:', features[0],'\nlabel:', labels[0])
d2l.set_figsize()
d2l.plt.scatter(features[:, 1].detach().numpy(), labels.detach().numpy(), 1);
#显示当前绘制的图像
d2l.plt.show()
问题1: 为什么要使用 detach()函数
这里移除detach()方法,代码仍然可以运行并得到类似的结果。detach()方法确保 PyTorch 张量能安全转换为 NumPy 数组,避免梯度计算干扰可视化
问题2: 运行时报错No module named ‘d2l’
解决办法: 进入到项目所在环境,使用pip install d21
安装
读取数据-随机抽取样本
训练模型时要对数据集进行遍历,每次抽取小批量样本并使用它更新模型,所以需要定义一个抽取函数。抽取函数需要能满足随机取样。
def data_iter(batch_size, features, labels):num_examples = len(features)# 创建一个从 0 到 num_examples-1 的整数列表,代表所有样本的索引。indices = list(range(num_examples))# 打乱索引列表,确保数据的随机性random.shuffle(indices)# 开始取小批量样本for i in range(0, num_examples, batch_size):batch_indices = torch.tensor(# 防止最后一次抽样时样本不足batch_size的情况indices[i: min(i + batch_size, num_examples)])# 调用一次next返回一次数据yield features[batch_indices], labels[batch_indices]# 测试代码,取10个样本
true_w = torch.tensor([2, -3.4])
true_b = 4.2
features, labels = synthetic_data(true_w, true_b, 30)
batch_size = 10
for X,y in data_iter(batch_size,features,labels):print(X,'\n',y)# 一共30个样本,每次取10个,会打印三次
模型定义
模型参数初始化
从均值为0、标准差为0.01的正态分布中采样随机数来初始化权重。
torch.zeros(1)
表示生成一个一维向量,形状为(1,)
w = torch.normal(0, 0.01, size=(2,1), requires_grad=True)
b = torch.zeros(1, requires_grad=True)
定义模型
模型输入X数据集,w权重的矩阵,b偏置量,输出预测的结果y向量
def linreg(X, w, b): #@save"""线性回归模型"""return torch.matmul(X, w) + b
定义损失函数
这里使用的均方损失函数 1 2 ( y ^ − y ) 2 \frac{1}{2}(\hat y - y)^2 21(y^−y)2,需要比较真实值 y y y和预测值 y ^ \hat y y^之间的差距
# 均方损失
def squared_loss(y_hat, y): #@save# 防止形状不匹配,我们统一一下return (y_hat - y.reshape(y_hat.shape)) ** 2 / 2
定义优化算法 - 小批量随机梯度下降
首先需要超参数学习率与批量大小,所以我们将其作为输入lr
,batch_size
。目标是求损失的梯度,接着朝减少损失的方向更新参数,所以还需要参数w,b
,我们将其一起传递给params
参数。
θ n e w = θ o l d − η y ^ b a t c h _ s i z e \theta_{new} = \theta_{old} - \eta\frac{\hat y}{batch\_size} θnew=θold−ηbatch_sizey^,其中 y ^ \hat y y^表示当前的小批量梯度,之前求损失函数的时候没有取均值,所以我们在这里取均值运算也就是除以batch_size
。手动将当前梯度值设置成0,这样下一次计算梯度时不会和上一次相关。
PyTorch 默认会累积梯度
def sgd(params, lr, batch_size): #@save"""小批量随机梯度下降"""with torch.no_grad():for param in params: #一次更新参数w和bparam -= lr * param.grad / batch_sizeparam.grad.zero_()
问题1:grad属性是什么
grad
是张量的一个属性,用于保存损失函数对该向量的导数。只有当张量的 requires_grad=True
时,PyTorch 才会跟踪其梯度,并生成 grad
属性。
训练
其实之前我们都忽略了一个问题,我们不断朝着减少损失的方向更新参数,那么什么时候停下来呢?理想的情况是找到让损失最小值的地方停下来,但通常难以实现。
常见的做法是设置一个轮次的超参数epoch
,我们参数更新epoch
轮就可以了。每一轮中,使用data_iter
函数遍历整个数据集,并将训练数据集中的所有样本都使用一次去更新参数(扫一遍数据)。
训练的实现基本都是两层训练
- 外层循环
epoch
:
控制训练的总轮数,每轮会遍历整个数据集一次。 - 内层循环:
按小批量batch_size
迭代数据,每次处理一个批次的数据去更新参数。
向量的sum
函数表示将其分量求和为一个标量,原因是PyTorch 的 backward()
需要对标量求梯度。调用 backward()
函数自动计算损失对参数 w
和 b
的梯度,并存储在 w.grad 和
b.grad`中
lr = 0.03
num_epochs = 3
net = linreg # 这里为了方便之后替换其他的模型,我们将线性模型赋值给net变量
loss = squared_loss # loss为均方损失for epoch in range(num_epochs):for X, y in data_iter(batch_size, features, labels):l = loss(net(X, w, b), y) # X和y的小批量损失# 因为l形状是(batch_size,1),而不是一个标量。l中的所有元素被加到一起,# 并以此计算关于[w,b]的梯度l.sum().backward() # sum 将当前批次的损失求和,将形状从 (batch_size, 1) 转换为标量。sgd([w, b], lr, batch_size) # 使用参数的梯度更新参数with torch.no_grad(): # 记录一下梯度情况,这里不需要计算梯度train_l = loss(net(features, w, b), labels) # 将整个数据集传进去计算损失值print(f'epoch {epoch + 1}, loss {float(train_l.mean()):f}')
问题1:backward怎么知道参数变量是w和b的?
设置了 requires_grad=True
的张量(如 w
、 b
)会被跟踪,当这些数据参与计算时,PyTorch 会动态记录所有操作,形成一个有向无环图。调用 loss.backward
时,PyTorch会自动沿着计算图反向传播 ,然后计算被跟踪向量的梯度,并赋值给该向量的 grad
属性。
with torch.no_grad()
会创建一个上下文环境,在该环境中计算的所有张量都不会被跟踪其操作历史,并且梯度信息也不会被记录。
代码总结
import random #导入Python内置的random模块,用于生成随机数和随机操作。
import torch #导入PyTorch深度学习框架,提供张量计算、自动求导和神经网络构建功能。
from d2l import torch as d2l# 构造一个人造数据集
def synthetic_data(w, b, num_examples): #@save# 从均值为0、标准差为1的正态分布中采样,生成形状为# (num_examples, len(w)) 的矩阵,表示 num_examples 个样本,每个样本有 len(w) 个特征。X = torch.normal(0, 1, (num_examples, len(w)))y = torch.matmul(X, w) + by += torch.normal(0, 0.01, y.shape)y = y.reshape(-1,1)return X, y.reshape(-1, 1)# 小批量取样
def data_iter(batch_size, features, labels):num_examples = len(features)indices = list(range(num_examples))random.shuffle(indices)for i in range(0, num_examples, batch_size):batch_indices = torch.tensor(indices[i: min(i + batch_size, num_examples)])yield features[batch_indices], labels[batch_indices]# 定义模型,模型输入X数据集,w权重,b偏置量,输出预测的结果y向量
def linreg(X, w, b): #@savereturn torch.matmul(X, w) + b
# 均方损失
def squared_loss(y_hat, y): #@savereturn (y_hat - y.reshape(y_hat.shape)) ** 2 / 2
# 优化算法
def sgd(params, lr, batch_size): #@savewith torch.no_grad():for param in params: #一次更新参数w和bparam -= lr * param.grad / batch_sizeparam.grad.zero_()# true_w = torch.tensor([2, -3.4])
# true_b = 4.2
features, labels = synthetic_data(true_w, true_b, 1000)
batch_size = 10
lr = 0.03
num_epochs = 3
net = linreg # 这里为了方便之后替换其他的模型,我们将线性模型赋值给net变量
loss = squared_loss # loss为均方损失# 初始化参数
w = torch.normal(0, 0.01, size=(2,1), requires_grad=True)
b = torch.zeros(1, requires_grad=True)for epoch in range(num_epochs):for X, y in data_iter(batch_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, batch_size) # 使用参数的梯度更新参数with torch.no_grad():train_l = loss(net(features, w, b), labels)print(f'epoch {epoch + 1}, loss {float(train_l.mean()):f}')
线性回归的简洁实现
前面从0开始实现线性回归,我们只使用了
(1)通过张量来进行数据存储和线性代数;
(2)通过自动微分来计算梯度。
实际上,由于数据迭代器、损失函数、优化器和神经网络层很常用, 现代深度学习库也为我们实现了这些组件,可以直接使用。
1.生成数据集
直接使用apid2l.synthetic_data()
生成数据集
import numpy as np
import torch
from torch.utils import data
from d2l import torch as d2ltrue_w = torch.tensor([2, -3.4])
true_b = 4.2
features, labels = d2l.synthetic_data(true_w, true_b, 1000)
2.读取数据集
iter(data_iter)
生成一个全新的迭代器,next
取该迭代器的第一批数据(10个样本数据+10个预测值)
*
在函数调用中的解包作用,可以解包一个 ** 可迭代对象(如列表、元组) ** ,将其元素作为位置参数传递。 *data_arrays
这里表示将传入的元组(features, labels)解包为 features
、 labels
两个参数。
def load_array(data_arrays, batch_size, is_train=True): #@save"""构造一个PyTorch数据迭代器"""# 得到pytorch的dataseatdataset = data.TensorDataset(*data_arrays)# 每次随机挑选batch_size个样本出来return data.DataLoader(dataset, batch_size, shuffle=is_train)batch_size = 10
# (features, labels) 组合成一个list传递
data_iter = load_array((features, labels), batch_size)
print(data_iter) #<torch.utils.data.dataloader.DataLoader object at >
print(next(iter(data_iter)))
一般做法,数据都是存在硬盘中的,不需要将所有的数据一次性读完到内存里。
3.模型定义
对于标准深度学习模型,我们可以使用框架的预定义好的层。这使我们只需关注使用哪些层来构造模型,而不必关注层的实现细节。
我们首先定义一个模型变量 net
,它是一个 Sequential
类的实例。 Sequential
类将多个层串联在一起。 当给定输入数据时, Sequential
实例将数据传入到第一层, 然后将第一层的输出作为第二层的输入,以此类推。
在线性回归的例子中,我们的模型只包含一个层,因此实际上不需要 Sequential
。 但是由于以后几乎所有的模型都是多层的,在这里使用 Sequential
会让你熟悉“标准的流水线”。
线性回归使用的是线性层(全连接层),它的每一个输入都通过矩阵-向量乘法得到它的每个输出。
全连接层在 Linear
类中定义,需要传递两个参数。第一个参数是输入特征的形状,我们这里是两个特征,所以是2。第二个参数指定输出特征的形状,输出特征形状为单个标量,所以为1。
nn.Linear(2, 1)
作用 : 将输入数据从2维映射到1维。
# nn是神经网络的缩写
from torch import nnnet = nn.Sequential(nn.Linear(2, 1))
4.初始化模型参数
在使用net之前,需要初始化模型参数。
这个神经网络只有一层全连接层(除去输入层),所以通过net[0]
就可以获取到这个Linear
,然后使用 weight.data
和 bias.data
方法访问参数。
在这里,我们指定每个权重参数应该从均值为0、标准差为0.01的正态分布中随机采样, 偏置参数将初始化为零。
print(net[0].weight.data) # tensor([[-0.3005, -0.2747]])
net[0].weight.data.normal_(0, 0.01) # 使用正态分布替换原始值
print(net[0].weight.data) # tensor([[-0.0023, -0.0087]])
net[0].bias.data.fill_(0) # 使用fill_填充原始值
5.定义损失函数
计算均方误差使用的是 MSELoss
类, 计算当前批次(batch)内所有样本的损失平均值。
在 PyTorch 中, nn.MSELoss
默认使用均值模式( reduction='mean'
),即对批量数据取平均: M S R = 1 B ∑ i = 1 B ( y ^ i − y i ) 2 MSR = \frac{1}{B}\sum_{i=1}^B(\hat y_{i}-y_{i})^2 MSR=B1∑i=1B(y^i−yi)2 ,B为批量大小
loss = nn.MSELoss()
6.定义优化算法
小批量随机梯度下降算法是一种优化神经网络的标准工具, PyTorch在 optim模块中实现了该算法的许多变种。
这里实例化SGD(stochastic gradient descent,SGD)实例,参数要指定优化的参数( net.parameters()
获取)以及优化算法所需超参数字典,小批量随机梯度下降只需要设置 lr
的值。
print(net.parameters())# <generator object Module.parameters at 0x0000027423D0B920>
trainer = torch.optim.SGD(net.parameters(), lr=0.03)
7.训练
在每个迭代周期里,我们将完整遍历一次数据集( train_data
), 不停地从中获取一个小批量的输入和相应的标签。 对于每一个小批量,我们会进行以下步骤:
- 通过调用
net(X)
生成预测并计算损失l
(前向传播)。 - 通过进行反向传播来计算梯度。
- 通过调用优化器来更新模型参数。
为了更好的衡量训练效果,我们计算每个迭代周期后的损失,并打印它来监控训练过程。
num_epochs = 3
for epoch in range(num_epochs):for X, y in data_iter:# net传入输入数据,自动计算预测值l = loss(net(X) ,y) # 这里已经求和了# 清空优化器跟踪的所有模型参数的梯度 每个轮次epoch要重新使用优化器计算# 如果不手动清零,梯度会随着每个批次(batch)不断累积,导致参数更新错误。trainer.zero_grad() l.backward() # 先对每个分量计算梯度trainer.step() # 进行一次模型参数更新 l = loss(net(features), labels)print(f'epoch {epoch + 1}, loss {l:f}')# epoch 1, loss 0.000196# epoch 2, loss 0.000101# epoch 3, loss 0.000101
trainer.step()
可以想象之前自定义函数sgb
的内部, 根据当前梯度更新模型参数: p a r a m = p a r a m − l r ⋅ p a r a m . g r a d param=param−lr⋅param.grad param=param−lr⋅param.grad
完整训练流程
- 前向传播 :输入数据通过模型计算预测值。
- 计算损失 :比较预测值和真实值的差异(如均方误差、交叉熵等)。
- 反向传播 :调用
loss.backward()
计算梯度。 - 梯度清零 :调用
trainer.zero_grad()
清空历史梯度。 - 参数更新 :调用
trainer.step()
根据梯度更新参数。
相关文章:
李沐《动手学深度学习》 | 线性神经网络-线性回归
文章目录 线性回归1.确定模型2.衡量预估质量-损失函数3.深度学习的基础优化算法随机梯度下降小批量随机梯度下降 从线性回归到深度网络 线性回归从0开始实现构造一个人造数据集创建数据集可视化数据集 读取数据-随机抽取样本模型定义模型参数初始化定义模型定义损失函数定义优化…...
LabVIEW 中 “Flatten To Json String” VI 应用及优势
在 LabVIEW 开发涉及机器人数据等场景时,常需将数据以特定 JSON 格式输出。“Flatten To Json String” VI 在此过程中能发挥重要作用,相比 LabVIEW 系统自带的 JSON 处理方式,它具备独特优势。以下将介绍其获取、使用方法及相较系统自带方式…...
关于 Spring Boot 后端项目使用 Maven 打包命令、JAR/WAR 对比、内嵌服务器与第三方服务器对比,以及热部署配置的详细说明
以下是关于 Spring Boot 后端项目使用 Maven 打包命令、JAR/WAR 对比、内嵌服务器与第三方服务器对比,以及热部署配置的详细说明: 一、Maven 打包命令详解 1. 基础命令 1.1 清理并打包 mvn clean packageclean:删除 target 目录中的旧构建文…...
用labview写crc8校验
crc8校验有好几种,我这里写的是不带任何后缀的crc8。 首先,我们百度一下crc8的计算方式 一般搜索出来下面还有c语言写的crc8可以做为参考。 下面便是根据百度的计算方式写的crc8,已校验过,无问题。 写完后,可以输入下…...
阿里云CDN与DCDN主动推送静态资源至边缘服务器的ASP.NET WEB实例
一、CDN,需要调用PushObjectCache接口进行URL预热,以下是操作步骤: 1. 准备工作 首先,安装阿里云SDK NuGet包: Install-Package Aliyun.NET.SDK.CDN -Version 3.0.0 Install-Package Aliyun.NET.SDK.Core -Version 3.0.0 2. 创建ASP.NET Web页面代码 CDNPreheat.aspx…...
LangChain-提示模板 (Prompt Templates)
提示模板是LangChain的核心组件,用于构建发送给语言模型的输入。本文档详细介绍了提示模板的类型、功能和最佳实践。 概述 提示工程是使用大型语言模型的关键技术。通过精心设计的提示,可以显著提高模型的输出质量和相关性。LangChain的提示模板系统提…...
多线程中的互斥与同步
多线程中的互斥与同步 1. 互斥与同步的区别 互斥:确保某一资源在同一时刻只能被一个线程访问。其主要目的是保证资源的唯一性和排他性,但无法控制访问的顺序。同步:在互斥的基础上,进一步通过其他机制保证访问资源的有序性。 2…...
ValueError: Cannot handle batch sizes > 1 if no padding token is defined`
ValueError: Cannot handle batch sizes > 1 if no padding token is defined` batch sizes > 1 进行掩码填充:pad_token,eos_token 在处理自然语言处理任务时,尤其是在使用批量数据进行训练或推理时,经常需要对输入文本进行填充(padding),以确保每个输入序列具…...
Gemma 3模型:Google 开源新星,大语言模型未来探索
🐇明明跟你说过:个人主页 🏅个人专栏:《深度探秘:AI界的007》 🏅 🔖行路有良友,便是天堂🔖 目录 一、引言 1、快速发展的AI世界:为何关注Gemma 3&#x…...
先占个日常,等会写。
引入一个重要的概念 “struct” (译为中文:结构体) 可用作设出比较复杂的一些变量类型 语法 :struct point name { int x; int y; int z;} point 和 name是任意命名的名字,含义是,声明一个变量类型为st…...
PyTorch Tensor维度变换实战:view/squeeze/expand/repeat全解析
本文从图像数据处理、模型输入适配等实际场景出发,系统讲解PyTorch中view、squeeze、expand和repeat四大维度变换方法。通过代码演示对比不同方法的适用性,助您掌握数据维度调整的核心技巧。 一、基础维度操作方法 1. view:内存连续的形状重…...
212、【图论】字符串接龙(Python)
题目描述 题目链接:110. 字符串接龙 代码实现 import collectionsn int(input()) beginStr, endStr input().split() strList [input() for _ in range(n)]deque collections.deque() # 使用队列遍历结点 deque.append([beginStr, 1]) # 存储当前字符串和遍…...
土堆教程笔记【PyTorch】
官网:torch — PyTorch 2.6 documentation Pycharm 解释器 一般搞深度学习都用虚拟环境的解释器,为了满足不同的项目所需要的不同的包的版本。 1. system interpreter表示本地的解释器 也就是你电脑系统里安装的解释器 2. Virtual Environment—Py…...
【今日三题】小乐乐改数字 (模拟) / 十字爆破 (预处理+模拟) / 比那名居的桃子 (滑窗 / 前缀和)
⭐️个人主页:小羊 ⭐️所属专栏:每日两三题 很荣幸您能阅读我的文章,诚请评论指点,欢迎欢迎 ~ 目录 小乐乐改数字 (模拟)十字爆破 (预处理模拟)比那名居的桃子 (滑窗 / 前缀和) 小乐乐改数字 (模拟) 小乐乐改数字…...
各类神经网络学习:(九)注意力机制(第1/4集),背景介绍,以及理解与引入
上一篇下一篇GRU(下集)注意力机制(第2/4集) Attention(注意力机制) 又叫做: attention pooling 简单来说,就是在训练的过程中,已知哪些东西更重要,哪些东西次重要。从而更…...
微软出品的AI Toolkit,在VS Code中使用DeepSeek
文章目录 简介调用DeepSeek 简介 AI Toolkit是微软出品的VS Code智能插件,整合了多种AI大模型,使之可以在VS Code中调用。 在插件栏搜索【AI Toolkit for Visual Studio Code】即可安装。安装完成后,左侧活动栏中会出现【AI Toolkit】的图标…...
随机森林与决策树
随机森林 vs 决策树: 随机森林(Random Forest)和决策树(Decision Tree)都是经典的机器学习算法,但它们在原理、性能和适用场景上有显著差异。以下是关键对比: 1. 决策树(Decision T…...
Selenium中`driver.get(htmlfile)`方法可能出现的超时问题
针对Selenium中driver.get(htmlfile)方法可能出现的超时问题,以下是几种改进方案及具体实现方法: 1. 设置页面加载超时时间 通过set_page_load_timeout()方法直接控制页面加载的最大等待时间。若超时,会抛出TimeoutException异常,…...
selenium快速入门
一、操作浏览器 from selenium import webdriver from selenium.webdriver.chrome.options import Options from selenium.webdriver.chrome.service import Service from selenium.webdriver.common.by import By# 设置选项 q1 Options() q1.add_argument("--no-sandbo…...
C++_智能指针
目录 一、智能指针的使用场景、基本概念 (1)因为抛异常而出现的资源泄漏的情况 二、RAII和智能指针的设计思路 三、c标准库智能指针以及使用 (1)几种智能指针的概念 auto_ptr unique_ptr shared_ptr weak_ptr 不是new出来…...
微服务简述
单体架构和微服务架构的区别? 最显著的区别看上去就是单体架构用的同一个数据库,微服务架构用的各自的数据库 单体架构: 所有功能模块(如用户管理、订单处理、支付等)都紧密耦合在一个代码库中。模块之间通过函数调用…...
研发效能实践:BDD(行为驱动开发)深度解毒手册:从「撕逼大会」到「人见人爱」的协作秘笈
引言:每个研发团队都该养一亩「黄瓜田」——论BDD如何终结「三体人」式需求沟通 🌌 「产品说登录要人脸识别,开发做成了指纹验证,测试按文档测出18个bug,最后发现原型图藏在三年前的邮件附件里…」家人们…...
【第40节】windows编程:仿造MFC版本QQ安全卫士
目录 前言 一、实现功能 二、附加功能 三、开发环境 四、数据库简单字段设计 五、代码架构 六、软件界面 七、功能架构 八、部分功能截图 九、相关实现细节概要 9.1 获取文件信息 9.2 清理电脑垃圾信息 9.2.1 回收站 9.2.2 清理指定数据下的文件 9.3 数据库与网…...
BOE(京东方)旗下控股子公司“京东方能源”成功挂牌新三板 以科技赋能零碳未来
2025年4月8日,BOE(京东方)旗下控股子公司京东方能源科技股份有限公司(以下简称“京东方能源”)正式通过全国中小企业股份转让系统审核,成功在新三板挂牌(证券简称:能源科技,证券代码:874526),成为BOE(京东方)自物联网转型以来首个独立孵化并成功挂牌的子公司。此次挂牌是BOE(京…...
【汽车产品开发项目管理——端到端的汽车产品诞生流程】
MPU:集成运算器、寄存器和控制器的中央处理器芯片 MCU:微控制单元,将中央处理器CPU、存储器ROM/RAM、计数器、IO接口及多种外设模块集成在单一芯片上的微型计算机系统。 汽车产品开发项目属性:临时性、独特性、渐进明细性、以目标…...
Visual Studio 2019 配置VTK9.3.1
文章目录 参考博客1、 VTK下载和编译2、vs2019配置vtk9.3.1参考博客 Visual Studio 2022 配置VTK9.3.0 1、 VTK下载和编译 见博客 CMake编译VTK 2、vs2019配置vtk9.3.1 新建一个项目 写入以下代码 #include <vtkActor.h> #include <vtkAssembly.h> #include…...
【含文档+PPT+源码】基于小程序的智能停车管理系统设计与开发
项目视频介绍: 毕业作品基于小程序的智能停车管理系统设计与开发 课程简介: 本课程演示的是一款基于小程序的智能停车管理系统设计与开发,主要针对计算机相关专业的正在做毕设的学生与需要项目实战练习的 Java 学习者。 1.包含:…...
科技自立+产业周期:透视人工智能的配置机遇
最近,全球市场因关税政策调整引发震荡,科技板块波动尤为明显。在此背景下,中国人工智能产业经历了一轮回调。 不过,《一点财经》注意到,4月9日上证科创板人工智能指数一度上涨3.7%。拉长周期看,Wind数据显…...
linux网络配置
今天我们来了解一下linux的网络配置,这个是我们进行网络传输的基础,保证网络资源的使用的手段.那么来看. 网络配置原理图: 查看网络ip和网关 windows:ipconfig linux:ifconfig ping测试主机之间网络联通性 ⭐️ip地址要在同一个网段下才…...
机器学习 | 强化学习方法分类汇总 | 概念向
文章目录 📚Model-Free RL vs Model-Based RL🐇核心定义🐇核心区别 📚Policy-Based RL vs Value-Based RL🐇核心定义🐇 核心区别 📚Monte-Carlo update vs Temporal-Difference update…...
git仓库迁移包括提交记录日志
网上找了很多资料都不好用,直到看到一个亲测有效后,整理如下: 1、进入仓库目录下,并且切换到要迁移的分支上 前提是你本地已有旧仓库的代码;如果没有的话,先拉取。 2、更改仓库地址 git remote set-url …...
Docker部署.NetCore8项目
在VS.net新建.netCore8项目,生成项目的发布文件,之后添加Dockerfile,内容如下: FROM mcr.microsoft.com/dotnet/aspnet:8.0 # 设置工作目录 WORKDIR /app # 挂载临时卷(类似于 VOLUME /tmp) VOLUME /tmp …...
xv6部分源码阅读-1
xv6部分源码阅读 前言 在lab2中,我们会为了完成attack这个实验,而花费大量的时间去阅读相关的系统调用源码,以此来分析出我们最终secret所在的页表的位置,而我写lab2中,重点并没有关注其中的逻辑关系,有很…...
CentOS中离线安装DockerCompos并用其部署Rabbitmq(使用离线导入导出docker镜像方式)
场景 DockerDockerCompose实现部署jenkins,并实现jenkinsfile打包SpringBootVue流水线项目过程详解、踩坑记录(附镜像资源、离线包资源下载): DockerDockerCompose实现部署jenkins,并实现jenkinsfile打包SpringBootVue流水线项目过程详解、踩坑记录(附镜像资源、离…...
基于 OpenHarmony 5.0 的星闪轻量型设备应用开发——Ch2 OpenHarmony LiteOS-M 内核应用开发
写在前面: 此篇是系列文章《基于 OpenHarmony5.0 的星闪轻量型设备应用开发》的第 2 章。本篇介绍了如何在 OpenHarmony 5.0 框架下,针对 WS63 进行 LiteOS-M 内核应用工程的开发。 为了方便读者学习,需要OpenHarmony 5.0 WS63 SDK 的小伙伴可…...
2025年4月9日-华为暑期实习-第二题-200分
📌 点击直达笔试专栏 👉《大厂笔试突围》 💻 春秋招笔试突围在线OJ 👉 笔试突围OJ 02. 智能导航系统 问题描述 K小姐生活在一个被称为"未来之城"的智能城市,这个城市拥有高效的无人驾驶运输网络。城市内的智能车辆可以在不同的交通枢纽之间穿行,每个枢…...
抖音视频下载工具
抖音视频下载工具 功能介绍 这是一个基于Python开发的抖音视频下载工具,可以方便地下载抖音平台上的视频内容。 主要特点 支持无水印视频下载自动提取视频标题作为文件名显示下载进度条支持自动重试机制支持调试模式 使用要求 Python 3.10Chrome浏览器必要的P…...
基于大模型预测儿童急性淋巴细胞白血病诱导达完全缓解患者综合治疗方案研究报告
目录 一、引言 1.1 研究背景与意义 1.2 研究目的 1.3 国内外研究现状 二、儿童急性淋巴细胞白血病及大模型相关理论基础 2.1 儿童急性淋巴细胞白血病概述 2.2 大模型技术原理及特点 三、大模型在术前评估中的应用 3.1 患者基本信息与病情数据收集 3.2 大模型对病情严…...
项目合同从专家到小白
文章目录 按项目范围划分项目总承包合同项目单项承包合同项目分包合同 按项目付款方式划分总价合同固定总价合同总价加激励费用合同(FPIF)总价加经济价格调整合同订购单 \ 单边合同 成本补偿合同工料合同(混合型) 基础概念目标成本…...
【windows10】基于SSH反向隧道公网ip端口实现远程桌面
【windows10】基于SSH反向隧道公网ip端口实现远程桌面 1.背景2.SSH反向隧道3.远程连接电脑 1.背景 Windows 10远程桌面协议的简称是RDP(Remote Desktop Protocol)。 RDP是一种网络协议,允许用户远程访问和操作另一台计算机。 远程桌面功…...
学习海康VisionMaster之四边形查找
一:进一步学习了 今天学习下VisionMaster中的四边形查找,这个还是拟合直线的衍生应用,可以同时测量四条直线并且输出交点或者判定是否有交点 二:开始学习 1:什么是四边形查找? 按照传统的算法,…...
菊风RTC 2.0 开发者文档正式发布,解锁音视频新体验!
重磅发布! 开发者们,菊风实时音视频2.0文档已正式发布上线,为您提供更清晰、更高效的开发支持!让菊风实时音视频2.0为您的音视频应用加速~ 菊风实时音视频2.0聚焦性能升级、体验升级、录制服务升级,助力视频通话、语…...
用Python和OpenCV开启图像处理魔法之旅
你是否曾好奇计算机是如何“看懂”这个世界的?从人脸识别到自动驾驶,计算机视觉技术正日益渗透到我们的生活中。而 OpenCV (Open Source Computer Vision Library),作为一个强大的开源计算机视觉库,正是我们探索这个奇妙世界的强大…...
初识MySQL · 复合查询(内外连接)
目录 前言: 基本查询回顾 笛卡尔积和子查询 笛卡尔积 内外连接 子查询 单行子查询 多行子查询 多列子查询 from中使用子查询 合并查询 前言: 在前文我们学习了MySQL的基本查询,就是简单的套用了select语句,最多不过是…...
Devops系列之对接Gerrit的设计与实现(三)-- Java编程实现
一、背景 上文讲述了如何使用shell命令实现创建gerrit项目,本文介绍如何使用java语言编程实现。 二、java语言实现 1、引入jar包 <dependency><groupId>com.urswolfer.gerrit.client.rest</groupId><artifactId>gerrit-rest-java-client…...
深入理解全排列算法:DFS与回溯的完美结合
全排列问题是算法中的经典问题,其目标是将一组数字的所有可能排列组合列举出来。本文将详细解析如何通过深度优先搜索(DFS)和回溯法高效生成全排列,并通过模拟递归过程帮助读者彻底掌握其核心思想。 问题描述 给定一个正整数 n&a…...
服务器(一种管理计算资源的计算机)
服务器是在网络环境中提供计算能力并运行软件应用程序的特定IT设备,它在网络中为其他客户机(如个人计算机、智能手机、ATM机等终端设备)提供计算或者应用服务, 一般来说服务器都具备承担响应服务请求、承担服务、保障服务的能力。服务器相比普…...
时态--02--一般过去时
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 一般过去时1.肯定句am/is — wasare — were 2.否定句3.⼀般疑问句4.特殊疑问句5.there be 过去式 practice过去分词 一般过去时 1.肯定句 am/is — was are — wer…...
WSA(Windows Subsystem for Android)安装LSPosed和应用教程
windows安卓子系统WSA的Lsposed和shamiko的安装教程 WSA(Windows Subsystem for Android)安装LSPosed和应用教程 一、环境准备 在开始之前,请确保: 已经安装好WSA(Windows Subsystem for Android)已经安装好ADB工具下载好LSPosed和Shamiko框架安装包 二、连接WSA 首先需要…...
Opencv计算机视觉编程攻略-第十三节 跟踪视频中的物品
这是opencv系列的最后一节,主要学习视频序列,上一节介绍了读取、处理和存储视频的工具,本文将介绍几种跟踪图像序列中运动物体的算法。可见运动或表观运动,是物体以不同的速度在不同的方向上移动,或者是因为相机在移动…...