开篇
Linear Regression是很基础的一个模型,用pytorch实现也不是什么难事,主要用到的还是我们上次说到的Linear这个模块来进行线性构建。这次我们会随机生成一些数据,利用pytorch构建线性模型进行拟合,最后画图表示出来。我们开始吧。
库的引入
import torch
import torch.nn as nn
import numpy as np
import matplotlib.pyplot as plt
这次我们引入matplotlib这个库进行画图直观表示,大家应该很熟悉了
超参数的定义
input_size = 1 //输入数据尺寸
output_size = 1//输出数据尺寸
num_epochs = 60//训练轮数
learning_rate = 0.001//学习率
自定义一个数据
x_train = np.array([[3.3],[4.4],[5.5],[6.71],[6.93],[4.168],
[9.779],[6.182],[7.59],[2.167],[7.042],
[10.791], [5.313], [7.997], [3.1]],dtype=np.float32)
y_train = np.array([[1.7], [2.76], [2.09], [3.19], [1.694], [1.573],
[3.366], [2.596], [2.53], [1.221], [2.827],
[3.465], [1.65], [2.904], [1.3]], dtype=np.float32)
x_train与y_train分别表示训练数据的输入与输出。
构建线性模型,函数损失函数以及优化器
model = nn.Linear(input_size,output_size)
criterion = nn.MSELoss()
optimizer = torch.optim.SGD(model.parameters(),lr = learning_rate)
训练模型
for epoch in range(num_epochs):
# 将numpy数据转化成tensor
inputs = torch.from_numpy(x_train)
targets = torch.from_numpy(y_train)
# 利用我们刚刚创建的线性模型前向传播
outputs = model(inputs)
# 参数是input与target
loss = criterion(outputs,targets)
# 反向传播求导及优化,这一步是自动求导
# 我们要先将optimizer进行导数清0处理,反正与之前的导数造成误差
optimizer.zero_grad()
# 反向传播自动求导
loss.backward()
# 优化器进行优化
optimizer.step()
if (epoch + 1) % 5 == 0:
print('Epoch [{}/{}],Loss:{:.4f}'.format(epoch+1,num_epochs,loss.item()))
可视化
predicted = model(torch.from_numpy(x_train)).detach().numpy()
plt.plot(x_train,y_train,'ro',label = 'Original data')
plt.plot(x_train,predicted,label = 'Fitted line')
plt.legend()
plt.show()
模型保存
torch.save(model.state_dict(),'model.ckpt')
在这里我们讨论一个细节,就是在画图中的代码第一行,有一个detach的操作,所以我们来介绍一下detach和detach_的关系。
具体的作用是:
返回一个新的tensor,从当前计算图中分离下来的,但是仍指向原变量的存放位置
不同之处只是requires_grad为false,得到的这个tensor永远不需要计算其梯度,不具有grad
即使之后重新将它的requires_grad置为true,它也不会具有梯度grad
这样我们就会继续使用这个新的tensor进行计算
后面当我们进行反向传播时,到该调用detach()的tensor就会停止
不能再继续向前进行传播
注意:
使用detach返回的tensor和原始的tensor共用同一个内存,即一个修改另一个也会跟着改变。
当使用detach()分离tensor但是没有更改这个tensor时,并不会影响backward()
当使用detach()分离tensor,然后用这个分离出来的tensor去求导数,会影响backward(),会出现错误
当使用detach()分离tensor并且更改这个tensor时,即使再对原来的out求导数,会影响backward(),会出现错误
detach_:
将一个tensor从创建它的图中分离,并把它设置成叶子tensor
其实就相当于变量之间的关系本来是x -> m -> y
这里的叶子tensor是x,但是这个时候对m进行了m.detach_()操作,其实就是进行了两个操作:
将m的grad_fn的值设置为None,这样m就不会再与前一个节点x关联
这里的关系就会变成x, m -> y,此时的m就变成了叶子结点
然后会将m的requires_grad设置为False,这样对y进行backward()时就不会求m的梯度
往后我们还会见到.data()函数,这种函数虽然不起眼并且基本一看就知道大概什么意思,但是大家还是要把它弄懂,以后用到或者看源码的时候才不会拿不准。.data()可以与.tensor()相同理解,假如out = tensor.data(),则out发生改变,tensor也会发生改变,这个时候如果我们再对tensor进行反向传播就会造成巨大的错误,但是我们并不能发现,因为程序不会告诉我们的,这个requird_grad其实是个False,而且共用一个内存地址,一个变另一个也会变。但是由于不报错,我们的程序就会无阻碍的执行,从而酿成大祸。所以我们就用了.detach(),它与.data()作用几乎一致,只不过它在上述情况会报错来提醒我们
RuntimeError: one of the variables needed for gradient computation has been modified by an
总结
下一篇介绍Pytorch实现Logistic Regression