先自己定义一个多项式公式,比如:
y = 2.70 ∗ x 3 + 3.00 ∗ x 2 + 5.00 ∗ x + 0.90 y = 2.70 * x^3 + 3.00 * x^2 + 5.00 * x + 0.90 y=2.70∗x3+3.00∗x2+5.00∗x+0.90
然后计算出在 x x x 处于区间 [-3, 3] 时,其对应的 y y y 的值:
# 定义多项式参数
w = np.array([2.7, 3, 5])
b = np.array([0.9])
# 生成样本数据
x_sample = np.arange(-3, 3, 0.1) # 维度: 60x1
y_sample = w[0] * x_sample ** 3 + w[1] * x_sample ** 2 + w[2] * x_sample + b[0]
现在呢,只告诉你 y_sample 的值,然后告诉你 x x x 处于 [-3, 3] 区间,要你给出这个多项式公式:
y = w 1 ∗ x 3 + w 2 ∗ x 2 + w 3 ∗ x + b y = w_1 * x^3 + w_2* x^2 +w_3 * x + b y=w1∗x3+w2∗x2+w3∗x+b
该如何解决呢?
这类线性问题采用 pytorch 中的全连接层就可以了
首先,构造出输入矩阵,也就是输入数据,这个数据格式长这个样子:
[ x 1 3 x 1 2 x 1 x 2 3 x 2 2 x 2 x 3 3 x 3 2 x 3 . . . . . . . . . x 60 3 x 60 2 x 60 ] \begin{bmatrix} x_1^3 & x_1^2 & x_1 \\ x_2^3 & x_2^2 & x_2 & \\ x_3^3 & x_3^2 & x_3 & \\ ... & ... & ... & \\ x_{60}^3 & x_{60}^2 & x_{60} & \\ \end{bmatrix} ⎣⎢⎢⎢⎢⎡x13x23x33...x603x12x22x32...x602x1x2x3...x60⎦⎥⎥⎥⎥⎤
代码如下:
# 构建训练数据
x_train = np.array([x_sample ** i for i in [3, 2, 1]]).T # 对3x60维度的矩阵做矩阵转置,使其变成60x3,每一行对应: x³、x²、x
然后将 numpy 数据类型转为 pytorch 的张量类型
# 训练数据与目标值
inputs = torch.from_numpy(x_train).float() # 转换成 float tensor
target = torch.from_numpy(y_sample).float().reshape(-1, 1) # 将1维数组转换为二维矩阵60x1,使其可与预测值进行相减操作,计算误差
接下来定义线性回归模型:(理解 nn.Linear(3, 1) 的含义比较重要!)
class LinearRegression(nn.Module):
def __init__(self):
super(LinearRegression, self).__init__()
self.linear = nn.Linear(3, 1) # 每行输入为3个特征值: x³、x²、x 输出为1个特征值: y
"""
输入矩阵 weight bias target
------------------------------------------------
[[x₁³ x₁² x₁] y₁
[x₂³ x₂² x₂] [[w₁] y₂
[x₃³ x₃² x₃] x [w₂] + [b] = y₃
... [w₃]] ..
[x₆₀³ x₆₀² x₆₀]] y₆₀
------------------------------------------------
"""
def forward(self, x):
output = self.linear(x)
return output
然后就是实例化模型,定义损失函数和优化函数
# 实例化模型
model = LinearRegression()
# 定义损失函数
criterion = nn.MSELoss() # 均方误差
# 定义优化函数 (这里不用自己构造权重和偏执参数,pytorch内部会自己构造出参数)
optimizer = optim.SGD(model.parameters(), lr=1e-3) # SGD:随机梯度下降,lr:学习率
OK,开始训练吧
# 定义超参数 (训练周期)
epochs = 2000
# 开始训练
model.train()
for epoch in range(epochs):
# 正向传播
output = model(inputs) # 输出预测值
loss = criterion(output, target) # 计算损失值
# 反向优化
loss.backward()
optimizer.step() # 更新参数
optimizer.zero_grad() # 清零梯度
if epoch % 100 == 0:
print('epoch:{}, loss: {:.5f}'.format(epoch, loss))
代码是不是超简单,完了验证一下结果:
# 打印参数
state_dict = model.state_dict()
weight = state_dict['linear.weight']
bias = state_dict['linear.bias']
print(state_dict)
# 比较公式
print('real:', fx.format(w[0], w[1], w[2], b[0]))
print('pred:', fx.format(weight[0][0], weight[0][1], weight[0][2], bias[0]))
每次训练结果都是不同的,这是我本地的一次结果:
real: y = 2.70 * x^3 + 3.00 * x^2 + 5.00 * x + 0.90
pred: y = 2.80 * x^3 + 3.02 * x^2 + 4.34 * x + 0.81
emmm,我做了个GIF动图来展示这个拟合过程:
完整代码:
# -*- coding: utf-8 -*-
import torch
from torch import nn, optim
import numpy as np
import matplotlib.pyplot as plt
# 定义多项式参数
w = np.array([2.7, 3, 5])
b = np.array([0.9])
# 多项式公式,模型将尽量拟合这个公式
fx = 'y = {:.2f} * x^3 + {:.2f} * x^2 + {:.2f} * x + {:.2f}'
# 生成样本数据
x_sample = np.arange(-3, 3, 0.1) # 维度: 60x1
y_sample = w[0] * x_sample ** 3 + w[1] * x_sample ** 2 + w[2] * x_sample + b[0]
# 构建训练数据
x_train = np.array([x_sample ** i for i in [3, 2, 1]]).T # 对3x60维度的矩阵做矩阵转置,使其变成60x3,每一行对应: x³、x²、x
# 训练数据与目标值
inputs = torch.from_numpy(x_train).float() # 转换成 float tensor
target = torch.from_numpy(y_sample).float().reshape(-1, 1) # 将1维数组转换为二维矩阵60x1,使其可与预测值进行相减操作,计算误差
class LinearRegression(nn.Module):
def __init__(self):
super(LinearRegression, self).__init__()
self.linear = nn.Linear(3, 1) # 每行输入为3个特征值: x³、x²、x 输出为1个特征值: y
"""
输入矩阵 weight bias target
------------------------------------------------
[[x₁³ x₁² x₁] y₁
[x₂³ x₂² x₂] [[w₁] y₂
[x₃³ x₃² x₃] x [w₂] + [b] = y₃
... [w₃]] ..
[x₆₀³ x₆₀² x₆₀]] y₆₀
------------------------------------------------
model.parameters 是一个迭代器,可以对其进行循环,打印出里面的 weight 和 bias
但是很纳闷,打印出来的 wieght 的维度是(1, 3),估计内部计算时对其做了矩阵转置吧
"""
def forward(self, x):
output = self.linear(x)
return output
# 实例化模型
model = LinearRegression()
# 定义损失函数
criterion = nn.MSELoss() # 均方误差
# 定义优化函数 (这里不用自己构造权重和偏执参数,pytorch内部会自己构造出参数)
optimizer = optim.SGD(model.parameters(), lr=1e-3) # SGD:随机梯度下降,lr:学习率
# 训练前的拟合图
output = model(inputs)
plt.plot(x_train[:, -1], y_sample, label='real curve')
plt.plot(x_train[:, -1], output.data.numpy(), label='fitting curve', color='r')
plt.legend(loc='best')
plt.show()
# 定义超参数 (训练周期)
epochs = 2000
# 开始训练
model.train()
for epoch in range(epochs):
# 正向传播
output = model(inputs) # 输出预测值
loss = criterion(output, target) # 计算损失值
# 反向优化
loss.backward()
optimizer.step() # 更新参数
optimizer.zero_grad() # 清零梯度
if epoch % 100 == 0:
print('epoch:{}, loss: {:.5f}'.format(epoch, loss))
# 训练后的拟合图
model.eval()
output = model(inputs)
plt.plot(x_train[:, -1], y_sample, label='real curve')
plt.plot(x_train[:, -1], output.data.numpy(), label='fitting curve', color='r')
plt.legend(loc='best')
plt.show()
# 保存模型
torch.save(model.state_dict(), 'linear02.pth')
# 打印参数
state_dict = model.state_dict()
weight = state_dict['linear.weight']
bias = state_dict['linear.bias']
print(state_dict)
# 比较公式
print('real:', fx.format(w[0], w[1], w[2], b[0]))
print('pred:', fx.format(weight[0][0], weight[0][1], weight[0][2], bias[0]))