一、背景
在廖星宇《深度学习入门》的github项目中,留了一道思考题:
小练习:上面的例子是一个三次的多项式,尝试使用二次的多项式去拟合它,看看最后能做到多好
提示:参数 w = torch.randn(2, 1),同时重新构建 x 数据集
二、代码部分
在项目中没有给出代码,作者自己改写了一个,作了大概如下改动:
- 改动了criterion,选用了自带的MSE
- 使用了nn.Sequential并强其放到了cuda上,试图用GPU增加运算效率
- 训练100000000次
- 多画几个窗口,好对比一下
- 代码部分没有精校,可能存在一些错误
- 也许criterion是否有更好的选择
- 代码在我本地没有问题啊!(手动狗头
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Fri Mar 27 17:36:24 2020
@author: ftimes
"""
import torch
import numpy as np
import matplotlib.pyplot as plt
import torch.nn as nn
SEED=2020
torch.manual_seed(SEED)
DEVICE=torch.device("cuda" if torch.cuda.is_available() else "cpu")
# 定义一个多变量函数
w_target = np.array([0.5, 3, 2.4]) # 定义参数
b_target = np.array([0.9]) # 定义参数
f_des = 'y = {:.2f} + {:.2f} * x + {:.2f} * x^2 + {:.2f} * x^3'.format(
b_target[0], w_target[0], w_target[1], w_target[2]) # 打印出函数的式子
print(f_des)
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
plt.plot(x_sample, y_sample ,label='real curve')
plt.legend(loc='best')
# 构建数据 x 和 y
# x 是一个如下矩阵 [x, x^2, x^3]
# y 是函数的结果 [y]
x_train = np.stack([x_sample ** i for i in range(1, 3)], axis=1)
x_train = torch.tensor(x_train).float().to(DEVICE) # 转换成 float tensor
y_train = torch.tensor(y_sample).float().unsqueeze(1).to(DEVICE) # 转化成 float tensor
seq_net = nn.Sequential(
nn.Linear(2, 1), # PyTorch 中的线性层,wx + b
).to(DEVICE)
'''
w = nn.Parameter(torch.randn(2, 1)*0.01).to(DEVICE)
b = nn.Parameter(torch.zeros(1)).to(DEVICE)
'''
optimizer=torch.optim.SGD(seq_net.parameters(),0.000001)
criterion=nn.MSELoss().to(DEVICE)
y_pred = seq_net(x_train)
plt.figure(2)
#plt.plot(x_train.data.numpy()[:, 0], y_pred.data.numpy(), label='fitting curve', color='r')
plt.plot(x_train.data.cpu().numpy()[:, 0], y_pred.data.cpu().numpy(), label='fitting curve', color='r')
plt.plot(x_train.data.cpu().numpy()[:, 0], y_sample, label='real curve', color='b')
plt.legend()
EPOCH=1000000
for e in range(EPOCH):
y_pred = seq_net(x_train)
loss=criterion(y_pred,y_train)
optimizer.zero_grad()
loss.backward()
optimizer.step()
if (e + 1) % 100000 == 0:
print('epoch: {}, loss: {}'.format(e+1, loss.data))
y_pred =seq_net(x_train)
plt.figure(3)
#plt.xlim(1, 2)
#plt.ylim(0, 20)
plt.plot(x_train.data.cpu().numpy()[:, 0], y_pred.data.cpu().numpy(), label='fitting curve', color='r')
plt.plot(x_train.data.cpu().numpy()[:, 0], y_sample, label='real curve', color='b')
plt.legend()
print(seq_net[0].weight,seq_net[0].bias)
print(f_des)
三、测试结果
epoch: 100000, loss: 279.2529296875
epoch: 200000, loss: 155.79791259765625
epoch: 300000, loss: 120.1278305053711
epoch: 400000, loss: 109.79125213623047
epoch: 500000, loss: 106.81745910644531
epoch: 600000, loss: 105.95108795166016
epoch: 700000, loss: 105.70142364501953
epoch: 800000, loss: 105.61643981933594
epoch: 900000, loss: 105.60639953613281
epoch: 1000000, loss: 105.60639953613281
Parameter containing:
tensor([[13.8103, 3.0138]], device='cuda:0', requires_grad=True) Parameter containing:
tensor([0.8424], device='cuda:0', requires_grad=True)
y = 0.90 + 0.50 * x + 3.00 * x^2 + 2.40 * x^3
我们可以看到,在学习率非常小的情况下,这个loss始终维持在了105.58638763427734。
如果是设置成0.03,可以迅速收敛到这个数。
可能是我哪里弄错了?恳请您指正我这个初学者。
但我们可以肯定的是,用二次多项式无法很好的拟合的三次多项式。
下面上图。
- 原始图像
2. 初始图像
3. 1000000次模拟后的图像
如果您有更好的代码,欢迎在评论区留言,感激不尽~