1线性回归的从零实现
import random
import torch
#####生成数据集
def synthetic_data(w,b,num_examples): #@save
#上面一行的注释将此函数存入d2l库中
'''生成y=Xw+b'''
X=torch.normal(0,1,(num_examples,len(w)))#均值,方差,形状
y=torch.matmul(X,w)+b#torch.matmul实现两个张量相乘
y+=torch.normal(0,0.01,y.shape)#生成与y相同形状的正态分布噪声
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)
print("features:",features[0],"\nlabels:",labels[0])
#####读取数据集
#生成大小为batch_size的小批量,可以GPU并行计算
#此方法效率较低,需要把所有数据加载进内存
def data_iter(batch_size,features,labels):
num_examples=len(features)#len读取axis=0轴的维数,即样本数
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]#yield迭代器,粗浅认为是return
batch_size=10
for X,y in data_iter(batch_size,features,labels):
print(X,'\n',y)
break
#####初始化模型参数
w=torch.normal(0,0.01,size=(2,1),requires_grad=True)
b=torch.zeros(1,requires_grad=True)
#####定义模型
def linreg(X,w,b):
'''线性回归模型'''
return torch.matmul(X,w)+b
#####损失函数
def squared_loss(y_hat,y):#@save
'''均方损失'''#y为labels
return (y_hat-y.reshape(y_hat.shape))**2/2#返回不是标量,而是(-1,1)
#####定义优化算法
def sdg(params,lr,batch_size):#@save
'''小批量随机梯度下降'''
with torch.no_grad():#强制后面计算不进行反向传播
for param in params:
param-=lr*param.grad/batch_size#除以batch_size防止批量大小影响步长
param.grad.zero_()
#####训练
#设置超参数
lr=0.03
num_epochs=3
net=linreg
loss=squared_loss
batch_size=10
for epoch in range(num_epochs):
for X,y in data_iter(batch_size,features,labels):#抽小批量计算
l=loss(net(X,w,b),y)#计算损失
l.sum().backward()#反向传播得到梯度存在param.grad中,w.grad,b.grad
sdg([w,b],lr,batch_size)#更新所有参数
with torch.no_grad():#此步不进行参数反向更新
train_l=loss(net(features,w,b),labels)#计算所有的loss
print(f'epoch{epoch+1},loss{float(train_l.mean()):f}')
分为以下步骤:
1数据集
2读取数据集(采用batch)
3定义模型(获得y_hat预测值)
4初始化参数(此处为w,b)
5定义损失函数(此处采用均方误差,计算loss)
6定义优化算法(如何更新参数,采用param-=lr*param.grad()/batch_size)
-=保证在同一块内存中,/batch_size为了使得步长与batch_size无关
7训练(将以上函数连接起来)
2简洁编码模式
以上重复性动作已经实现自动化,可以利用API(Application Programming Interface)的程序接口实现:
2.1首先生成数据集
import numpy as np
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)#借用之前存在d2l中函数
2.2读取数据集(分成小batch)
API涉及的有:(from torch.utils import data)
data.TensorDataset():
dataset=data.TensorDataset(*data_arrays)生成存有features和labels的数据集
data.DataLoader():
data.DataLoader(dataset,batch_size,shuffle=is_train)返回存有一组一组batch数据(features,labels组合)的张量,shuffle=True是打乱样本顺序
def load_array(data_arrays,batch_size,is_train=True):
'''构造一个Pytorch数据迭代器'''
dataset=data.TensorDataset(*data_arrays)
return data.DataLoader(dataset,batch_size,shuffle=is_train)
batch_size=10
data_iter=load_array((features,labels),batch_size)
print(next(iter(data_iter)))#next从迭代器中获得第一项,iter构造Python迭代器
还需注意next(iter(data_iter))将含有一组一组batch的张量变为迭代器(iter),输出其中第一项(next)
2.3 定义模型
#####定义模型
from torch import nn
net=nn.Sequential(nn.Linear(2,1))
定义模型变量net,是Sequential的实例,Sequential将多个层串联在一起
nn.Linear第一个参数为输入特征形状,第二个参数为输出特征形状
2.4 初始化模型
#####初始化模型参数
net[0].weight.data.noraml_(0,0.1)#weight.data访问参数,normal_替换参数
net[0].bias.data.fill_(0)#fill_重写参数
net[0]访问模型这一层,weight.data或者bias.data访问参数,normal_()与fill_()改写参数
2.5 定义损失函数
#####定义损失函数
loss=nn.MSELoss()
#平方L2类,返回所有样本损失的平均值
L2计算均方误差(所有样本误差的均值)nn中的MSELoss类
2.6定义优化函数
#####定义优化算法
trainer=torch.optim.SGD(net.parameters(),lr=0.03)#optim模块中有小批量随机梯度下降算法
torch.optim中有小批量随机梯度下降算法,使用torch.optim.SGD()。括号中要写需要优化的参数以及学习率。需要优化的参数可以使用net.parameters()进行获得。
2.7训练
#####训练
num_epochs=3
for epoch in range(num_epochs):
for X,y in data_iter:#取一个batch
l=loss(net(X),y)#计算损失函数
trainer.zero_grad()#梯度置零
l.backward()#梯度反向传播
trainer.step()#更新参数
l=loss(net(features),labels)
print(f'epoch{epoch+1},loss{l:f}')#l:f形式为float