实现线性回归
这一节不牵扯深度学习框架,仅使用Tensor和autograd库来训练线性回归模型。
代码语言:javascript复制#需要导入的库import torch #张量计算from IPython import display #嵌入显示图像from matplotlib import pyplot as plt #绘制图像import numpy as np #矩阵运算import random #生成随机数
创建一个数据集
要训练一个模型,首先需要训练数据集和数据对应的标签。
先随机生成一个样本数为1000的「随机样本特征」。
然后使用真实模型 y = 2x1-3.4x2 4.2 随机噪声项,生成1000个「标签」。
其中随机噪声项服从均值为0、标准差为0.01的正态分布,代表列无意义的干扰
程序实现
代码语言:javascript复制#生成数据集num_inputs = 2 #特征数,数据集的列数num_examples = 1000 #样本数,数据集的行数true_w = [2,-3.4] #线性模型的真实权重true_b = 4.2 #线性模型的真实偏差
featrues = torch.randn(num_examples,num_inputs,dtype = torch.float32)#使用随机张量函数,生成一个1000行2列的随机张量labels = true_w[0]*featrues[:,0] true_w[1]*featrues[:,1] true_b#使用随机张量作为输入生成一组标签labels = torch.tensor(np.random.normal(0,0.01,size = labels.size()),dtype = torch.float32)#为标签加随机噪声,生成随机噪声方法:使用numpy库的random.normal生成一个均值为0,标准拆为0.0.1的正态分布,其大小为1行2000个的行向量。#在这一部分,使用了两种随机矩阵生成的方法,主要区别是第二个为正态分布。且第二种生成的行向量。
数据可视化:绘制散点图象
代码语言:javascript复制def use_deg_display(): display.set_matplotlib_formats('svg') #绘制矢量图,不同散点有深浅。 def set_figsize(figsize=(3.5,2.5)): use_deg_display() plt.rcParams['figure.figsize'] = figsize #设置散点图和图像大小 set_figsize()
%matplotlib inline#使用juterpy notebook要注意,需要使用这行代码,才能显示图像
plt.scatter(featrues[:,1].numpy(),labels.numpy(),c='b');#关于散点图绘制函数的参数,见这个:https://www.imooc.com/article/29522
绘制出的散点图
读取数据
代码语言:javascript复制#读取数据def data_iter(batch_size,features,labels): num_examples = len(features) indices = list(range(num_examples)) #从0到num_examples生成一个列表indices random.shuffle(indices) #打乱indices这个列表(随机) #这个for循环也叫做迭代器 for i in range(0,num_examples,batch_size): #找到每一个小批量起始的索引(如:0 10 20...) j = torch.LongTensor(indices[i:min(i batch_size,num_examples)]) #将小批量对应的所有索引转换为张量j yield features.index_select(0,j),labels.index_select(0,j) #定义了一个生成器,节省了内存 #输出batch_size =10for X,y in data_iter(batch_size,featrues,labels): print(X,y) break #只输出一次 #使用for循环来读取生成器data_iter中的数据
20202211:48
20202228:57
初始化模型参数
模型参数指:权重w1,w2;偏差b。
首先将权重初始化成均值为0,标准差为0.01的正态随机数。偏差初始化为0。
代码语言:javascript复制w = torch.tensor(np.randm.normal(0,0.01,(num_inputs,1)),dtype = torch.float32)#使用numpy生成大小为2*1的一个均值为0,标准差为0.01正态分布b = torch.zeros(1,dtypr = float32)#生成一个大小为1的全0矩阵
定义模型
将前文所述的矩阵形式模型
转换为程序形式
代码语言:javascript复制def linreg(X,w,b): return torch.mm(X,w) b #torch.mm(X,b)函数,对X和b进行矩阵乘法运算。
定义损失函数
也是将之前的函数
转换为程序形式
代码语言:javascript复制def squared_loss(y_hat,y): return (y_hat - y.view(y_hat_size()))**2/2 #**是平方
定义优化算法
实现上一节中的小批量随机下降算法,通过不断迭代模型参数来优化损失函数。
代码语言:javascript复制def sgd(params,lr,batch_size): for param in aprams: param.data -= lr*param.grad/batch_size #不理解.data什么意思。好像是对数据本身进行操作
训练模型
在训练中,多次迭代模型参数。在每次迭代中:
- 读取小批量随机样本
- 调用反向函数.backward计算样本的梯度(小批量随机梯度)
- 调用sgd函数迭代模型参数,然后将参数的梯度清零
#当前程序迭代周期数设置为3;学习率设置为0.03lr = 0.03num_epochs = 3net = linreg #换名loss = squared_loss #换名,不知道为什么
for epoch in range(num_epochs): #一共需要num_epochs个迭代周期 #每一个迭代周期都需要遍历所有样本 for X,y in data_iter(batch_size,features,labels): #一次接收一组读取数据得到的小批量特征与标签 l = loss(net(X,w,b),y).sum() #首先计算模型得到的值,再计算损失函数值,由于直接计算得到的是向量的形式,无法直接求梯度,因此对他进行加和运算。 l.backward() #对损失函数求梯度 sgd([w,b],lr,batch_size) #利用优化算法,迭代模型参数 w.grad.data.zero_() b.grad.data.zero_() #对参数梯度清零 train_l = loss(net(features,w,b),labels) #当前周期的损失函数值 print('epoch %d,loss %f' %(epoch 1,train_l.mean().item())) #对损失值求均值。输出每一个学习周期得到的损失值。
程序
代码语言:javascript复制import torchfrom IPython import displayfrom matplotlib import pyplot as pltimport numpy as npimport random
#生成数据集num_inputs = 2num_examples = 1000true_w = [2,-3.4]true_b = 4.2features = torch.randn(num_examples,num_inputs,dtype = torch.float32)#1000行2列labels = true_w[0]*features[:,0] true_w[1]*features[:,1] true_blabels = torch.tensor(np.random.normal(0,0.01,size = labels.size()),dtype = torch.float32)
#绘制图像def use_deg_display(): display.set_matplotlib_formats('svg') def set_figsize(figsize=(3.5,2.5)): use_deg_display() plt.rcParams['figure.figsize'] = figsize # set_figsize()# %matplotlib inline# plt.scatter(featrues[:,1].numpy(),labels.numpy(),c='b');
#读取数据def data_iter(batch_size,features,labels): num_examples = len(features) indices = list(range(num_examples)) #从0到num_examples生成一个列表 random.shuffle(indices) #打乱这个列表 for i in range(0,num_examples,batch_size): j = torch.LongTensor(indices[i:min(i batch_size,num_examples)]) yield features.index_select(0,j),labels.index_select(0,j)
w = torch.tensor(np.random.normal(0,0.01,(num_inputs,1)),dtype = torch.float32)#使用numpy生成大小为2*1的一个均值为0,标准差为0.01正态分布b = torch.zeros(1,dtype = torch.float32)#生成一个大小为1的全0矩阵
w.requires_grad_(requires_grad=True)b.requires_grad_(requires_grad=True)#开始追踪其上的所有操作
def linreg(X,w,b): return torch.mm(X,w) b #torch.mm(X,b)函数,对X和b进行矩阵乘法运算。 def squared_loss(y_hat,y): return (y_hat - y.view(y_hat.size()))**2/2 #view:将y转换为与y_hat同形的 def sgd(params,lr,batch_size): for param in params: param.data -= lr*param.grad/batch_size #不理解.data什么意思。好像是对数据本身进行操作
#当前程序迭代周期数设置为3;学习率设置为0.03lr = 0.03num_epochs = 3net = linreg #换名loss = squared_loss #换名,不知道为什么batch_size = 10
for epoch in range(num_epochs): #一共需要num_epochs个迭代周期 #每一个迭代周期都需要遍历所有样本 for X,y in data_iter(batch_size,features,labels): #一次接收一组读取数据得到的小批量特征与标签 l = loss(net(X,w,b),y).sum() #首先计算模型得到的值,再计算损失函数值,由于直接计算得到的是向量的形式,无法直接求梯度,因此对他进行加和运算。 l.backward() #对损失函数求梯度 sgd([w,b],lr,batch_size) #利用优化算法,迭代模型参数 w.grad.data.zero_() b.grad.data.zero_() #对参数梯度清零 train_l = loss(net(features,w,b),labels) #当前周期的损失函数值 print('epoch %d,loss %f' %(epoch 1,train_l.mean().item()))
print(true_w,'n',w)print(true_b,'n',b)