问题介绍
很多个数据点,希望能找到一个函数来你和这些数据点,使其误差最小。
我们从一位线性回归入手。
一维线性回归
我们从一元函数入手。
目标函数为
f
(
x
i
)
=
ω
x
i
+
b
f(x_i) = \omega x_i +b
f(xi)=ωxi+b
那么我们如何确定参数w和b呢?
只需要衡量f(x)和y的差别。
我们可以用它们之间的距离差异:
L
o
s
s
=
∑
i
=
1
m
(
f
(
x
i
)
−
y
i
)
2
Loss = \sum_{i=1}^m(f(x_i)-y_i)^2
Loss=i=1∑m(f(xi)−yi)2
取平方是因为它们之间的距离差异有正有负。
这也是著名的均方误差。
MSE:估计量与被估计量差异之间的度量。
(
w
∗
,
b
∗
)
=
arg min
w
,
b
∑
i
=
1
m
(
y
i
−
w
x
i
−
b
)
(w^*,b^*) = \argmin_{w,b} \sum_{i=1}^m(y_i - wx_i - b)
(w∗,b∗)=w,bargmini=1∑m(yi−wxi−b)
我们采用最小二乘法来求解均方差最小化。
一维线性回归的代码实现
import torch
from torch.autograd import Variable
import torch.nn as nn
import torch.optim as optim
import matplotlib.pyplot as plt
x_train = torch.Tensor([[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]])
print(x_train.size())
y_train = torch.Tensor([[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]])
print(y_train.size())
#定义一个简单的模型
class LinearRegression(nn.Module):
def __init__(self):
super(LinearRegression,self).__init__()
self.linear = nn.Linear(1,1)
'''
torch.nn —— Linear layers
class torch.nn.Linear(in_feature,out_features,bias=True)
对输入数据做线性变换:y=Ax+b
参数:
in_features - 每个输入样本的大小/张量形状
out_features - 每个输出样本的大小/张量形状
bias - 若设置为False,这层不会学习偏置。默认值:True
变量:
weight -形状为(out_features x in_features)的模块中可学习的权值
bias -形状为(out_features)的模块中可学习的偏置
根据in_features随机生成
'''
def forward(self,x):
out = self.linear(x)
return out
model = LinearRegression()
#定义损失函数和优化函数
criterion = nn.MSELoss()
optimizer = optim.SGD(model.parameters(),lr = 1e-3) #model.parameters() model中可以优化的参数
#训练
num_epochs = 1000
for epoch in range(num_epochs):
#导入Variable是因为其可以自动求导
inputs = Variable(x_train)
target = Variable(y_train)
#forward
out = model(inputs)
'''
model(inputs)等价于model.forwrd(inputs)
这是因为:
forward方法的具体流程:
以一个Module为例:
1. 调用module的call方法
2. module的call里面调用module的forward方法
3. forward里面如果碰到Module的子类,回到第1步,如果碰到的是Function的子类,继续往下
4. 调用Function的call方法
5. Function的call方法调用了Function的forward方法。
6. Function的forward返回值
7. module的forward返回值
8. 在module的call进行forward_hook操作,然后返回值。
上述中“调用module的call方法”是指nn.Module 的__call__方法。定义__call__方法的类可以当作函数调用,具体参考Python的面向对象编程。
也就是说,当把定义的网络模型model当作函数调用的时候就自动调用定义的网络模型的forward方法。nn.Module 的__call__方法部分源码如下所示:
def __call__(self, *input, **kwargs):
result = self.forward(*input, **kwargs)
for hook in self._forward_hooks.values():
#将注册的hook拿出来用
hook_result = hook(self, input, result)
...
return result
'''
loss = criterion(out,target) #nn中的其他模块同理 将out和target中的逐个元素求差,再求均值
#backward
optimizer.zero_grad() #优化器梯度清零 不然梯度会累加在一起,造成结果不收敛
loss.backward() #计算梯度 对这些操作求其梯度
optimizer.step() #更新参数 参考网络参数更新公式
if (epoch+1) % 20 == 0:
print('Epoch[{}/{}],loss:{:.6f}'.format(epoch+1,num_epochs,loss.item()))
#预测
model.eval() #转化为测试模式
predict = model(Variable(x_train))
predict = predict.data.numpy()
plt.plot(x_train.numpy(),y_train.numpy(),'ro',label = 'Original data')
plt.plot(x_train.numpy(),predict,label = 'Fitting Line')
plt.show()
网络构成三步走:
1.搭建model并设置;
2.设置loss和optimizer;
3.设置epoch开始训练;
epoch三步走:
1.转化Variable,将数据导入model
2.计算loss
3.梯度清空,反向传播,更新参数
多维线性回归
多项式回归的代码实现
y = b + ω 1 x + ω 2 x 2 + ω 3 x 3 y = b + \omega_1 x + \omega_2 x^2 + \omega_3 x^3 y=b+ω1x+ω2x2+ω3x3
import torch
import torch.nn as nn
import torch.optim as optim
from torch.autograd import Variable
#我们首先要将数据处理为矩阵形式
def make_features(x):
x = x.unsqueeze(1)
"""
unsqueeze()用于调整维度 默认增加一维或减少一维(在维度是1时才有效)
增加一个括号,如果宽为1,可以默认是一维,只含长
unsqueeze(0):增加第一维
unsqueeze(1):增加第二维
unsqueeze(2):增加第三维
unsqueeze(-1):减少第三维
unsqueeze(-2):减少第二维
unsqueeze(-3):减少第三维
"""
return torch.cat([x ** i for i in range(1,4)],1)
"""
对输入的张量序列进行链接操作
>>> x = torch.randn(2, 3)
>>> x
0.5983 -0.0341 2.4918
1.5981 -0.5265 -0.8735
[torch.FloatTensor of size 2x3]
>>> torch.cat((x, x, x), 0)
0.5983 -0.0341 2.4918
1.5981 -0.5265 -0.8735
0.5983 -0.0341 2.4918
1.5981 -0.5265 -0.8735
0.5983 -0.0341 2.4918
1.5981 -0.5265 -0.8735
[torch.FloatTensor of size 6x3]
>>> torch.cat((x, x, x), 1)
0.5983 -0.0341 2.4918 0.5983 -0.0341 2.4918 0.5983 -0.0341 2.4918
1.5981 -0.5265 -0.8735 1.5981 -0.5265 -0.8735 1.5981 -0.5265 -0.8735
[torch.FloatTensor of size 2x9]
"""
W_target = torch.FloatTensor([0.5,3,2.4]).unsqueeze(1) #将张量由3变为(3,1)
b_target = torch.FloatTensor([0.9])
def f(x):
return x.mm(W_target) + b_target[0] #x.mm()矩阵乘法 x必须为张量
def get_batch(batch_size=32):
random = torch.randn(batch_size)
x = make_features(random)
y = f(x)
return Variable(x),Variable(y)
#定义多项式模型
class poly_model(nn.Module):
def __init__(self):
super(poly_model,self).__init__()
self.poly = nn.Linear(3,1)
def forward(self,x):
out = self.poly(x)
return out
model = poly_model()
criterion = nn.MSELoss()
print(model.parameters())
optimizer = optim.SGD(model.parameters(),lr=1e-3)
epoch = 0
while True:
batch_x,batch_y = get_batch()
output = model(batch_x)
loss = criterion(output , batch_y)
print_loss = loss.item() #将零维张量转化为浮点数
optimizer.zero_grad()
loss.backward()
optimizer.step()
epoch += 1
print(f'epoch={epoch},loss={print_loss}')
if print_loss <1e-3:
break