网站建设兼容性,怎样制作免费手机网站,做电影网站怎么选服务器,扬州市建筑信息平台线性回归无框架实现线性回归的从零开始实现生成数据集(简单的人工构造)读取数据初始化模型参数定义模型定义损失函数定义优化算法训练模型小结完整代码(可直接运行)线性回归的从零开始实现
为了深入理解深度学习是如何工作的#xff0c;本节不使用强大的深度学习框架#xf…
线性回归无框架实现线性回归的从零开始实现生成数据集(简单的人工构造)读取数据初始化模型参数定义模型定义损失函数定义优化算法训练模型小结完整代码(可直接运行)线性回归的从零开始实现
为了深入理解深度学习是如何工作的本节不使用强大的深度学习框架而是介绍如何只利用Tensor和autograd来实现一个线性回归的训练。
首先导入本节中实验所需的包或模块如下:
import torch
from matplotlib import pyplot as plt
import numpy as np
import random生成数据集(简单的人工构造)
设训练数据集样本数为1000输入个数特征数为2。给定随机生成的批量样本特征 X∈R1000×2\boldsymbol{X} \in \mathbb{R}^{1000 \times 2}X∈R1000×2我们使用线性回归模型真实权重 w[2,−3.4]⊤\boldsymbol{w} [2, -3.4]^\topw[2,−3.4]⊤ 和偏差 b4.2b 4.2b4.2以及一个随机噪声项 ϵ\epsilonϵ 来生成标签 yXwbϵ\boldsymbol{y} \boldsymbol{X}\boldsymbol{w} b \epsilon yXwbϵ
其中噪声项 ϵ\epsilonϵ 服从均值为0、标准差为0.01的正态分布。噪声代表了数据集中无意义的干扰。下面让我们生成数据集。
#生成数据集以及计算grand-truth,下面的计算可以根据公式来看
num_inputs2 #要训练的权重个数(面积和房龄两个特征(影响放假的因素)的权重)
num_examples1000 #样本数量
true_w[2,-4]
true_b4.2
featurestorch.randn(num_examples,num_inputs,dtypetorch.float32) #代表X矩阵
labelstorch.mm(features,torch.Tensor(true_w).view(-1,1)) #mm为矩阵相乘,此处为1000*2的矩阵乘以2*1的矩阵,mul为点乘
labelstorch.tensor(np.random.normal(0, 0.01, sizelabels.size()),dtypetorch.float32) #加均值为0,方差为1的随机噪声项
注意features的每一行是一个长度为2的向量形状为torch.Size([1000,2])代表X矩阵而labels形状为torch.Size([1000,1])每一行是一个长度为1的向量标量代表每个样本(房子)的真实价格。
print(features[0], labels[0])输出
tensor([0.8557, 0.4793]) tensor([4.2887])通过生成第二个特征features[:, 1]和标签 labels 的散点图可以更直观地观察两者间的线性关系。
plt.scatter(features[:, 1].numpy(), labels.numpy(), 1)
plt.show()读取数据
在训练模型的时候我们需要遍历数据集并不断读取小批量数据样本。这里我们定义一个函数它每次返回batch_size批量大小个随机样本的特征和标签。
def data_iter(batch_size, features, labels):num_examples len(features) #1000indices list(range(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)]) # 最后一次可能不足一个batchyield features.index_select(0, j), labels.index_select(0, j)让我们读取第一个小批量数据样本并打印。每个批量的特征形状为(10, 2)分别对应批量大小和输入个数标签形状为批量大小。
batch_size 10for X, y in data_iter(batch_size, features, labels):print(X, y)break输出
tensor([[-1.4239, -1.3788],[ 0.0275, 1.3550],[ 0.7616, -1.1384],[ 0.2967, -0.1162],[ 0.0822, 2.0826],[-0.6343, -0.7222],[ 0.4282, 0.0235],[ 1.4056, 0.3506],[-0.6496, -0.5202],[-0.3969, -0.9951]]) tensor([ [6.0394],[ -0.3365], [9.5882], [5.1810], [-2.7355], [5.3873], [4.9827], [5.7962],[4.6727], [6.7921]])初始化模型参数
我们将权重初始化成均值为0、标准差为0.01的正态随机数偏差则初始化成0。
w torch.tensor(np.random.normal(0, 0.01, (num_inputs, 1)), dtypetorch.float32)
b torch.zeros(1, dtypetorch.float32)之后的模型训练中需要对这些参数求梯度来迭代参数的值因此我们要让它们的requires_gradTrue。
w.requires_grad_(requires_gradTrue)
b.requires_grad_(requires_gradTrue) #或者在创建tensor时加requires_gradTrue定义模型
下面是线性回归的矢量计算表达式的实现。我们使用mm函数做矩阵乘法。
def linreg(X, w, b): # 本函数已保存在d2lzh_pytorch包中方便以后使用return torch.mm(X, w) b定义损失函数
我们使用上一节描述的平方损失来定义线性回归的损失函数。在实现中我们需要把真实值y变形成预测值y_hat的形状。以下函数返回的结果也将和y_hat的形状相同。
def squared_loss(y_hat, y): # 本函数已保存在d2lzh_pytorch包中方便以后使用# 注意这里返回的是向量, 另外, pytorch里的MSELoss并没有除以 2return (y_hat - y.view(y_hat.size())) ** 2 / 2定义优化算法
以下的sgd函数实现了上一节中介绍的小批量随机梯度下降算法。它通过不断迭代模型参数来优化损失函数。这里自动求梯度模块计算得来的梯度是一个批量样本的梯度和。我们将它除以批量大小来得到平均值。
def sgd(params, lr, batch_size): # 本函数已保存在d2lzh_pytorch包中方便以后使用for param in params:param.data - lr * param.grad / batch_size # 注意这里更改param时用的param.data训练模型
在训练中我们将多次迭代模型参数。在每次迭代中我们根据当前读取的小批量数据样本特征X和标签y通过调用反向函数backward计算小批量随机梯度并调用优化算法sgd迭代模型参数。由于我们之前设批量大小batch_size为10每个小批量的损失l的形状为(10, 1)。回忆一下自动求梯度一节。由于变量l并不是一个标量所以我们可以调用.sum()将其求和得到一个标量再运行l.backward()得到该变量有关模型参数的梯度。注意在每次更新完参数后不要忘了将参数的梯度清零。
在一个迭代周期epoch中我们将完整遍历一遍data_iter函数并对训练数据集中所有样本都使用一次假设样本数能够被批量大小整除。这里的迭代周期个数num_epochs和学习率lr都是超参数分别设3和0.03。在实践中大多超参数都需要通过反复试错来不断调节。虽然迭代周期数设得越大模型可能越有效但是训练时间可能过长。而有关学习率对模型的影响我们会在后面“优化算法”一章中详细介绍。
lr 0.01
num_epochs 5
net linreg
loss squared_lossfor epoch in range(num_epochs): # 训练模型一共需要num_epochs个迭代周期# 在每一个迭代周期中会使用训练数据集中所有样本一次假设样本数能够被批量大小整除。X# 和y分别是小批量样本的特征和标签for X, y in data_iter(batch_size, features, labels):l loss(net(X, w, b), y).sum() # l是有关小批量X和y的损失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()))输出
epoch 1,loss 1.3475228548049927
epoch 2,loss 0.18588872253894806
epoch 3,loss 0.02577354572713375
epoch 4,loss 0.0036298963241279125
epoch 5,loss 0.0005514014046639204训练完成后我们可以比较学到的参数和用来生成训练集的真实参数。它们应该很接近。
print(true_w, \n, w)
print(true_b, \n, b)输出
[2, -3.4] tensor([[ 1.9998],[-3.3998]], requires_gradTrue)
4.2 tensor([4.2001], requires_gradTrue)小结
可以看出仅使用Tensor和autograd模块就可以很容易地实现一个模型。接下来本书会在此基础上描述更多深度学习模型并介绍怎样使用更简洁的代码见下一节来实现它们。
完整代码(可直接运行)
import torch
import numpy as np
import random#生成数据集以及计算grand-truth,下面的计算可以根据公式来看
num_inputs2 #要训练的权重个数(面积和房龄两个特征(影响放假的因素)的权重)
num_examples1000 #样本数量
true_w[2,-4]
true_b4.2
featurestorch.randn(num_examples,num_inputs,dtypetorch.float32) #代表X矩阵
labelstorch.mm(features,torch.Tensor(true_w).view(-1,1)) #mm为矩阵相乘,此处为1000*2的矩阵乘以2*1的矩阵,mul为点乘
labelstorch.tensor(np.random.normal(0, 0.01, sizelabels.size()),dtypetorch.float32) #加均值为0,方差为1的随机噪声项#数据预处理
def data_iter(batch_size, features, labels):num_examples len(features) #1000indices list(range(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)]) #LongTensor默认64位整型 后面为切片操作使用min是因为最后一次可能不足一个batchyield features.index_select(0, j), labels.index_select(0, j)#初始化模型参数,由于要训练计算梯度,所以加requires_gradTrue
w torch.tensor(np.random.normal(0, 0.01, (num_inputs, 1)), dtypetorch.float32,requires_gradTrue) #形状为torch.Size([2,1])
b torch.zeros(1, dtypetorch.float32,requires_gradTrue)#定义模型
def linreg(X,w,b):return torch.mm(X,w)b
#定义损失函数
def squared_loss(y_hat,y):return (y_hat-y)**2/2
#定义优化算法
def sgd(params,Ir,batch_size):for param in params:param.data-Ir*param.grad/batch_size #除以batch_size之后计算批量loss的时候就不用求平均了,只需要sum()
#训练模型
num_epochs5
Ir0.01
batch_size 10
netlinreg #模型
losssquared_loss #损失函数for epoch in range(num_epochs):for X,y in data_iter(batch_size,features,labels): #每批十个lloss(net(X,w,b),y).sum() #10个loss在一个张量里,所以用sum对张量中的元素进行求和#至于为什么不求平均,在参数更新处有所体现(除以了batch_size)l.backward()#反向传播sgd([w,b],Ir,batch_size)#梯度清零w.grad.data.zero_()b.grad.data.zero_()train_lloss(net(features,w,b),labels)print(epoch {},loss {}.format(epoch1,train_l.mean().item())) #mean()对loss求平均