代码来源于动手学深度学习pytorch版,感兴趣的同学可以自行购买观看。本节内容带着大家了解深度学习框架底层实现逻辑,如何自定义模型,自定义层或自定义损失函数,方便大家后续使用深度学习框架时候能够明白一些基本函数的实现过程,让我们知道每一步在做什么,更好的调试我们的代码。
一、前言
为了展示每个代码块的输出,本文在jupyter notebook编译环境进行编写代码,还不知道怎么配置的友子们可以看看前面的帖子。配置完成后可以跟着一起操作,本文附带源码。
二、代码实现及解释
实现线性回归,首先需要创建一个数据集,为了简单起见,我们根据一个带噪声的线性模型构造一个数据集。在下面的实验中我们生成了一个包含1000个样本的数据集,每个样本包含从标准正态分布中抽样的两个特征。我们的合成数据集是一个矩阵 。
线性模型如下:
模型参数 ,将行向量转置为列向量方便与X向量对应相乘,b = 4.2,表示预测值与真实值的偏差,模拟真实情况。这里模型参数都是预先假设,可以设置为其他数字。
假设服从均值为0,标准差为0.01的正态分布,下面代码用于生成数据集及标签。
%matplotlib inline
import random
import torch
from d2l import torch as d2l
这里简单说明一下,%matplotlib inline
是一个在使用 Jupyter Notebook 或者 JupyterLab 这样的交互式环境中使用的魔法命令,它告诉这些环境将绘图直接嵌入到笔记本中,而不是在一个新的窗口里打开。这样做的好处是,绘制的图表会与生成它们的代码单元格紧密相连,便于查看和调试 。d2l是一个专注于深度学习的包,大家可以自己查找d2l包的下载教程,记住要下载到自己注册内核的那个环境中,我是直接pip进行下载的,但是网上好像有部分人直接下载发生报错,大家对症下药。
2.1 生成数据集
# 生成数据集
def synthetic_data(w,b,num_examples): #@save
# 创建了一个形状为(num_examples,len(w))大小的张量,normal服从正态分布均值为0,标准差1
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))
torch.normal表示生成一个服从正态分布的随机数,样本X 均值为0,标准差为1,形状为(num_examples,len(w)),torch.matmul实现后就与上述线性模型公式相同,大家可以自行观察是如何计算的。y += torch.normal(0,0.01,y.shape)表示加入的噪声。
最后返回生成的样本与标签,reshape是为了保证计算的y是只包含一个标签,原本矩阵y是一个(1,num_examples)的向量,转化后变为(num_examples,1)的向量。
2.2 展示生成的数据集
true_w = torch.tensor([2,-3.4])
true_b = 4.2
features,labels = synthetic_data(true_w,true_b,1000)
print('features:',features[0],'\nlabel:',labels[0])
这里带入权重与偏置参数,输出第一个样本与标签值。
2.3 绘制特征与标签图
这里样本具有两个特征,取第二个特征作为横轴,标签值作为纵轴绘制散点图。因为第二个特征对应的权重值为-3.4,在图中很容易看出两者呈负相关。
2.4 读取数据集
训练模型需要对数据集进行遍历,本次实验每次抽取小批量数据进行训练。梯度下降三种选取数据集样本的方式,随机梯度下降,小批量梯度下降和批量梯度下降。这里简单介绍一下三者的优缺点。
随机梯度下降,每次选取一个随机的样本进行训练,优:训练速度快,对cpu要求较低;缺:单个样本的梯度估计存在较大的方差,收敛过程较为动荡,可能只得到局部最优。
批量梯度下降,使用整个训练数据集来计算损失函数关于模型参数的梯度。优:使用了全部样本的梯度信息,更加稳定地收敛得到全局最优解。缺:数据集大,计算成本高,对cpu要求高。
小批量梯度下降,从训练集中随机选择一个大小为batch_size的小批量样本,优缺点:介于批量梯度下降与随机梯度下降两者之间,比较稳定,且训练速度较快。目前梯度下降选择最多的就是小批量梯度下降。
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]
定义了一个data_iter函数用于生成小批量样本。indices中包含了每个样本的下标,如下所示:[0,1,2,3....num_examples],使用下标获取样本,方便我们打乱样本的顺序,做到随机抽取。
如何获取连续的小批量