- 各种基础铺垫
- 如何安装d2l包?
- 本书的内容框架
- 第三节-线性神经网络(基础回归模型)
- 1 线性回归模型完整代码
- 2代码拆解-数据准备(数)
- 3代码拆解-模型准备
- 4代码拆解-模型训练
pip install d2l
网络差等问题如果无法安装的话,参考此链接。
说明:d2l是课程工具包,是为这门课配套的一些些好的方法,目的是方便读者能够直快速学习到核心的知识,而不必要在一些例如绘图等地方浪费代码复线的时间,直接复用代码就可以了。
本书的内容框架 第三节-线性神经网络(基础回归模型) 1 线性回归模型完整代码那如何查询d2l中某个方法实现了哪些功能呢?
很简单,去它的github源码(可能需要科学上网)上查就可以了,或者通过代码编辑工具,使用ctrl(苹果用command) + 鼠标左键点击方法即可进入电脑内安装好的源码处查看。
这里举两个例子:
set_figsize是作者自己自定义的方法
而d2l.plt.scatter就是作者调用其他包的方法了
作者在头文件中有引入,是外部的matplotlib工具包里的方法,因此需要百度查询pyplot.scatter()就可以了,不用从d2l源码中找了,因为d2l本身调用的也是外部的工具,同时我们可以知道像这种常用的外部包,d2l在引入时保证了命名的一致性,因此可以根据经验推断方法的功能。
首先,我们需要定义并背过机器学习代码的流程口诀:定、数、模、训、测、上。(即:问题定义、数据准备、模型搭建、模型训练、模型测试、模型上线。)
针对下面代码所对应的流程:
- 问题定义(回归问题,数据通过函数自己生成 )
- 模型准备(小口诀:模型、损失、优化器;)
- 模型训练(小口诀: 迭代、调参、降损失;)
- 模型测试
- 模型上线(学术上一般不需要这一步,测试出结果指标,说明模型好就行)
import numpy as np
import torch
from torch.utils import data
from d2l import torch as d2l
#'nn'是神经网络的缩写
from torch import nn
# 1.数据准备
true_w=torch.tensor([2,-3.4]) ##初始化w
true_b=4.2 ##初始化b
features,labels=d2l.synthetic_data(true_w,true_b,1000)
def load_array(data_arrays,batch_size,is_train=True):
"""构造一个PyTorch数据迭代器"""
# 实例化一个TensorDataset对象,这个对象可以根据索引返回特征,也可以返回样本数
dataset=data.TensorDataset(*data_arrays) #参数是指针类型,指向(features,labels)
return data.DataLoader(dataset,batch_size,shuffle=is_train) #每次挑选batch_size个样本出来
batch_size=10
data_iter=load_array((features,labels),batch_size) #(features,labels)元祖类型tuple
# print(next(iter(data_iter))) #iter迭代器,next是成组输出
# 2.构建模型
"""初始化模型参数"""
net=nn.Sequential(nn.Linear(2,1)) #Sequential容器可放多个参数(多层) y=[1000,2]*[2,1]+[1]=[1000,1],即为w的形状
net[0].weight.data.normal_(0,0.01) #net[0]指的是第0层,即nn.Linear(2,1)---w,下划线指使用正态分布来代换掉data的值
net[0].bias.data.fill_(0) #b
loss=nn.MSELoss() #使用均方误差
"""实例化SGD,定义优化算法"""
trainer=torch.optim.SGD(net.parameters(),lr=0.03)
# 3.训练模型
num_epochs=3 #迭代3个周期
for epoch in range(num_epochs):
for X,y in data_iter:
l = loss(net(X),y) #net(X)生成预测并计算损失l(向前传播)
trainer.zero_grad() ##trainer优化器梯度清零
l.backward() #无需再求sum,pytorch已经计算
trainer.step() #调用step进行模型的更新
"""以上是训练过程的loss,放入整个features做损失"""
l = loss(net(features), labels)
print(f'epoch: {epoch + 1},loss: {l:f}')
# 4.模型测试(这里的测试并不规范)
w=net[0].weight.data
print('w的估计误差:',true_w-w.reshape(true_w.shape))
b=net[0].bias.data
print('b的估计误差:',true_b-b)
2代码拆解-数据准备(数)打印结果:
epoch: 1, loss: 0.000213
epoch: 2, loss: 0.000098
epoch: 3, loss: 0.000099
w的估计误差: tensor([-0.0005, -0.0009])
b的估计误差: tensor([0.0001])
from d2l import torch as d2l
代码从d2l包中引入了torch类,并命名为d2l,下面的链接可以看到d2l.torch的详细内容:
官方的d2l.torch.py内容github链接如下:可能需要科学上网
从下图可以看出,d2l中共有如下三个文件,因此from d2l import torch的意思是引入Pytorch版本的d2l工具包,后面加上as d2l是给工具包命名为d2l。可能有点绕,可以这样理解,d2l是一个工具包,但是它有很多版本,为了区分则根据深度学习框架起了名字如下图三个,因此当我们要用d2l这个工具包的时候,需要根据我们使用的深度学习框架来导入版本,然后再重命名为一下,这里我们使用的深度学习框架是Pytorch。
d2l工具包中包含了许多方法;其中一个就是synthetic_data,在pycharm编辑器中,通过ctrl+鼠标左键(mac: command+鼠标左键)的方式就可以进入到该方法的详细内容如下:
reshape = lambda x, *args, **kwargs: x.reshape(*args, **kwargs)
我们可以看到,这个方法其实就是,根据你输入的w,b,以及样本数目,来生成数据。因此洗面这段代码就不难理解了,输入 w = [ 2 − 3.4 ] w=begin{bmatrix} 2\-3.4\ end{bmatrix} w=[2−3.4], b = 4.2 b=4.2 b=4.2,随机生成一个样本的特征矩阵 X 1000 × 2 X_{1000times{2}} X1000×2,并利用公式 y = X w + b y=Xw+b y=Xw+b进一步生成标签向量y。
# 1.数据准备 true_w=torch.tensor([2,-3.4]) ##初始化w true_b=4.2 ##初始化b features,labels=d2l.synthetic_data(true_w,true_b,1000)3代码拆解-模型准备
"""初始化模型参数""" net=nn.Sequential(nn.Linear(2,1)) #Sequential容器可放多个参数(多层) y=[1000,2]*[2,1]+[1]=[1000,1],即为w的形状 net[0].weight.data.normal_(0,0.01) #net[0]指的是第0层,即nn.Linear(2,1)---w,下划线指使用正态分布来代换掉data的值 net[0].bias.data.fill_(0) #b loss=nn.MSELoss() #使用均方误差 """实例化SGD,定义优化算法""" trainer=torch.optim.SGD(net.parameters(),lr=0.03)
4代码拆解-模型训练构建模型步骤:
- 通过Sequential的方式构建模型
- 然后对模型中的参数初始化
- 设定目标损失函数
通俗解释梯度下降参考资料:https://zhuanlan.zhihu.com/p/137374150
l.backward()和optimizer.step()解释参考资料:https://zhuanlan.zhihu.com/p/258084887
# 3.训练模型
num_epochs=3 #迭代3个周期
for epoch in range(num_epochs):
for X,y in data_iter:
l = loss(net(X),y) #net(X)生成预测并计算损失l(向前传播)
trainer.zero_grad() ##trainer优化器梯度清零
l.backward() #无需再求sum,pytorch已经计算
trainer.step() #调用step进行模型的更新
"""以上是训练过程的loss,放入整个features做损失"""
l = loss(net(features), labels)
print(f'epoch: {epoch + 1},loss: {l:f}')
在PyTorch里面,loss function 的定义都有一个 reduction 的参数,默认是 mean,也就是平均。
可以选择:
sum: 求和;
none:不做任何操作,直接按位返回所有的值;
# 比如: loss = nn.MSELoss(reduction='sum') # 'mean' or 'none'
对于任意一个定义好的模型(网络)我们需在模型的输出和标签之间建立一个衡量模型好坏的函数,并且这个函数就是目标函数(损失函数),而所谓的训练就是最小化这个损失函数。损失函数的损失值被优化地越来越小,也就代表其背后的模型精度越来越高,总结起来就是,对于定义好的任意一个模型,我们都需要通过某种方法将其对应的目标函数(损失函数)最小化。
那如何最小化目标函数,在最优化这一门课中,有很多的方法,其中最经典的是随机梯度下降算法。通过该方法,经过对目标函数中包含的模型参数进行求偏导,可以优化调整模型中的权重参数。
l.backward()就是用来执行求解梯度的过程的
trainer.step()就是通过各种不同的优化算法来更新损失函数中(也是模型中)的权重参数的
trainer.step()在参数迭代的时候是如何知道batch_size的?
因为loss = nn.MSELoss(),均方误差是对样本总量平均过得到的,所以trainer.step()使用的是平均过的grad。
在每次l.backward()前都要trainer.zero_grad(),方式l.backward()计算参数梯度的时候,梯度会累加(累加上一个循环的梯度结果)。



