线性回归
目标:拟合出一条直线 y = w ⊤ x + b y = \mathbf{w}^\top \mathbf{x} + b y=w⊤x+b,这里的 w , x \mathbf{w},\mathbf{x} w,x均为 d × 1 d\times 1 d×1的列向量.
对于数据集
D
=
{
(
x
1
,
y
1
)
,
(
x
2
,
y
2
)
…
(
x
n
,
y
n
)
}
D=\{(\mathbf{x_1},y_1),(\mathbf{x_2},y_2)\dots (\mathbf{x_n},y_n) \}
D={(x1,y1),(x2,y2)…(xn,yn)},我们可以有
y
=
X
w
+
b
y=\mathbf{X}\mathbf{w}+b
y=Xw+b
这里
X
n
×
d
\mathbf{X}_{n\times d}
Xn×d的每一行就是一个样本
生成随机数据
import numpy as np
import matplotlib.pyplot as plt
import torch
from torch.utils import data
from torch import nn
true_w = torch.tensor([2, -3.4]).reshape(2, 1)
true_b = 4.2
def get_data(size, w=true_w, b=true_b):
X = torch.normal(0, 1, (size, len(w)))
y = torch.mm(X, w) + b + torch.normal(0,0.01,(size, 1))
return X, y
可以绘制一下数据的散点图,因为这里的 x x x是一个二维列向量,我们拿出他的第一个特征进行绘制
features, labels = get_data(500)
plt.scatter(features[:,1],labels)
设置batch
训练模型:对数据集进行遍历,每次抽取一小批量样本,并使用它们来更新模型。
我们需要定义一个函数,来打乱数据集中的样本并以小批量方式获取数据。
def load_array(data_arrays, batch_size, is_train=True):
# input: 原始数据,批量的大小,is_train表示是否希望数据迭代器对象在每个迭代周期内打乱数据
# output: 大小为batch_size的小批量, 每个小批量包含一组特征和标签
"""构造一个PyTorch数据迭代器"""
dataset = data.TensorDataset(*data_arrays)
return data.DataLoader(dataset, batch_size, shuffle=is_train)
使用next(iter(data_iter))
可以从迭代器中获取第一项,直接对data_iter
遍历也可以访问所有的batch
features, labels = get_data(6)
data_iter = load_array((features, labels), batch_size=2)
print(next(iter(data_iter)))
for X,y in data_iter:
print(X,y)
设置网络
方法01-快速搭建
在PyTorch中,全连接层在Linear类中定义。
nn.Linear
的2个参数: 第1个指定输入特征个数,即2,第2个指定输出特征个数,是1。
net = nn.Sequential(nn.Linear(2, 1))
# 初始化net的参数值,不初始化就是一个随机值
# net[0].weight.data.normal_(0, 0.01)
# net[0].bias.data.fill_(0)
loss = nn.MSELoss() # loss计算方法(MSE)
trainer = torch.optim.SGD(net.parameters(), lr=0.01) # 优化方法(梯度下降)
for epoch in range(100): # 迭代100个周期
for X, y in data_iter:
l = loss(net(X), y) # 计算batch内模型loss的值
trainer.zero_grad() # 梯度清零
l.backward() # 反向传播
trainer.step() # 梯度优化,更新参数
l = loss(net(features), labels) #计算目前我的模型在全部数据上的loss
if epoch % 10 == 0:
print('epoch = {}, loss = {}'.format(epoch+1, l.data))
方法02-继承类的方式
把方法1中的net = nn.Sequential(nn.Linear(2, 1))
换成:
class Net(nn.Module):
def __init__(self, n_input, n_output):
super(Net, self).__init__()
self.predict = nn.Linear(n_input, n_output)
def forward(self, input):
out = self.predict(out)
return out
net = Net(2,1)
拟合非线性函数
import numpy as np
import matplotlib.pyplot as plt
import torch
from torch.utils import data
from torch import nn
def get_data(size):
X = torch.linspace(-1, 1, size).reshape(size, 1)
y = X**3 + torch.randn(size, 1) / 10
return X, y
def load_array(data_arrays, batch_size, is_train=True):
"""构造一个PyTorch数据迭代器"""
dataset = data.TensorDataset(*data_arrays)
return data.DataLoader(dataset, batch_size, shuffle=is_train)
features, labels = get_data(100)
data_iter = load_array((features, labels), batch_size=10)
# ------------ 以上代码没有什么区别 --------------------
net = nn.Sequential(nn.Linear(1, 8), nn.ReLU(),
nn.Linear(8, 8), nn.Tanh(), nn.Linear(8, 1))
# 这里的net是一个三层的网络
loss = nn.MSELoss()
trainer = torch.optim.SGD(net.parameters(), lr=0.03)
for epoch in range(2020):
if epoch % 100 == 0:
print('epoch {},loss = {}'.format(epoch,loss(net(features),labels).data ))
plt.scatter(features,labels)
plt.plot(features,net(features).data.numpy(),'r-',lw = 5)
plt.pause(0.05)
for X, y in data_iter:
_loss = loss(net(X),y)
trainer.zero_grad()
_loss.backward()
trainer.step()
可以动态的看一下运行过程,未开始训练之前的时候loss较大,只能拟合出一个直线
训练2000轮之后,几乎可以完美的拟合