线性模型实现
这里主要涉及代码实现部分,理论部分的内容较少
一维线性模型
思路:
1.得到训练数据画出原始图像,并将训练数据通过torch.from_numpy
转换成Variable类型的变量;
定义参数w和b,并将参数设置成requires_grad=True
,True说明反向传播时自动求导,而一般情况下该属性默认为False
2.构建参数模型即线性模型和损失函数
3.进行训练,训练过程中需要记得归零梯度w.grad.zero_()
,利用backward()
来自动求导,随后更新参数w和b
在进行训练的时候需要在循环外面先求一次导这样做的目的是loss.backward()
先行,防止出现AttributeError: 'NoneType' object has no attribute 'zero_'
的错误,或者在循环内先loss.backward()
,随后再梯度归零。
总之是不可以让w.grad.zero_()
放在前面
4.画图查看训练情况,这里画图需要注意将x_train、y_train和y_的类型进行转换x_train.data.numpy()
。
实现的代码如下:
import torch
import numpy as np
from torch.autograd import Variable
import matplotlib
import matplotlib.pyplot as plt
# 数据
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)
# 画出原始图像
plt.plot(x_train, y_train,'bo')
plt.show()
# 转换类型
x_train = torch.from_numpy(x_train)
y_train = torch.from_numpy(y_train)
# 定义w和b参数
w = Variable(torch.randn(1), requires_grad=True)
b = Variable(torch.zeros(1), requires_grad=True)
# 得到参数模型和损失函数
def linear_model(x):
return x*w+b
def get_loss(y_, y):
return torch.mean((y_-y_train)**2)
y_ = linear_model(x_train)
loss = get_loss(y_, y_train)
loss.backward() # 自动求导
w.data = w.data - 1e-2*w.grad.data
b.data = b.data - 1e-2*b.grad.data
for i in range(100):
# 计算损失函数
y_ = linear_model(x_train)
loss = get_loss(y_, y_train)
print("loss:{}".format(loss))
# 归零梯度
w.grad.zero_() # 要在外面走一次
b.grad.zero_()
loss.backward()
# 更新参数
w.data = w.data - 1e-2*w.grad.data
b.data = b.data - 1e-2*b.grad.data
y_ = linear_model(x_train)
# 画图
plt.plot(x_train.data.numpy(), y_train.data.numpy(), 'bo', label='real')
plt.plot(x_train.data.numpy(), y_.data.numpy(), 'ro', label='estimated')
plt.legend()
plt.show()
结果
原始数据:
训练之后:
误差(部分截图):
多维线性模型
思路:
1.定义目标函数: 以三维函数为例,首先需要定义具体的函数模型,即向量’w_target
和b_target
,两个向量是准确的参数;
2.得到数据样本: 选取一定的区域的x_sample
变量,随后根据所定义的参数来得到y_sample
。随后可以画出图像,对于样本数据需要定义相应的训练数据方便计算;
x_train = np.stack([x_sample**i for i in range(1, 4)], axis=1) # 因为后面需要w和x矩阵运算因此需要将x训练模型扩展
x_train = torch.from_numpy(x_train).float()
y_train = torch.from_numpy(y_sample).float().unsqueeze(1)
这里涉及unsqueeze()方法和numpy数组中的stack()方法,此部分会在后面进行说明
3.定义训练参数: 该内容与一维的过程同样;
4.定义训练模型和损失参数: 该内容与一维的过程相似,不过需要注意此时是多维运算因此需要用到torch.mm()
即向量的乘法运算;
5.训练: 步骤和过程与一维相同,同样需要经历:求y值,随后根据损失函数的求导更新参数w和b,可通过第一次和最后一次画出图像来比较。
实现的代码如下:
# 定义函数
w_target = np.array([0.5, 3, 2.4])
b_target = np.array([0.9])
# 得到数据
x_sample = np.arange(-3, 3.1, 0.1)
y_sample = b_target[0]+w_target[0]*x_sample+w_target[1]*x_sample**2+w_target[2]*x_sample**3
print("the function is:{:.2f}+{:.2f}*x+{:.2f}*x^2+{:.2f}*x^3".format(b_target[0],
w_target[0], w_target[1], w_target[2]))
# 画图
plt.plot(x_sample, y_sample, label="fitting", color='r')
plt.legend()
plt.show()
# 获得训练模型
x_train = np.stack([x_sample**i for i in range(1, 4)], axis=1) # 因为后面需要w和x矩阵运算因此需要将x训练模型扩展
x_train = torch.from_numpy(x_train).float()
y_train = torch.from_numpy(y_sample).float().unsqueeze(1)
# 定义参数
w = Variable(torch.randn(3, 1), requires_grad=True)
b = Variable(torch.zeros(1), requires_grad=True)
# 定义模型和损失函数
def multi_model(x):
return torch.mm(x, w)+b
def get_loss(y_, y):
return torch.mean((y_-y)**2)
# 多次训练
for i in range(200):
y_pred = multi_model(x_train)
loss = get_loss(y_pred, y_train)
loss.backward()
w.data = w.data - 0.001 * w.grad.data
b.data = b.data - 0.001 * b.grad.data
print("the loss is :{}".format(loss))
# 第一次和最后一次画出训练图像
if i == 0 or i == 199:
y_pred = multi_model(x_train)
plt.plot(x_train.data.numpy()[:, 0], y_pred.data.numpy()[:, 0], label="fitting", color='b')
plt.plot(x_train.data.numpy()[:, 0], y_sample, label='real', color='r')
plt.legend()
plt.show()
结果
原始数据:
训练之后:
第一次训练:
最后一次训练:
最后说明的内容:
unsqueeze()方法:
可以参考:
https://blog.csdn.net/flysky_jay/article/details/81607289
numpy的stack()方法:
可以参考:
https://blog.csdn.net/zzw000000/article/details/52857964
https://blog.csdn.net/csdn15698845876/article/details/73380803?utm_medium=distribute.pc_relevant_t0.none-task-blog-BlogCommendFromMachineLearnPai2-1.channel_param&depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-BlogCommendFromMachineLearnPai2-1.channel_param
————————————————————————————————————
代码的参考:
https://github.com/L1aoXingyu/code-of-learn-deep-learning-with-pytorch