随着人工智能的发展,深度学习变得越来越炙手可热,所以博主也来凑一下热闹,抽空开始进行深度学习,下面是我自己 的一些学习经验分享,如果有错,请各位看官勿喷,帮忙指出一下,不胜感激。
现在最热的深度学习框架为
、
等等,下面我主要写的对象就为
,内容参考的是廖星宇老师的《深度学习之pytorch》,我觉得这本书内容很基础,也很详细,非常适合初学者入门。
基础部分网上有很多教程,我这里就不板门弄斧,后面我会再补上,这里就开始我们这章的主题:线性回归。
一维线性回归
1)原理
线性回归大家应该都不陌生,简单说,就是给定一个数据集
,线性回归希望可以找到一个最好的函数
,使得
能尽量多的拟合这些数据点。
我们一般使用向量的形式来表示函数
:
我们只需要通过不断的调整
,
,就可以找到最符合条件的点。怎么学习这两个参数呢,其实只需要衡量
,
之间的差别, 可以使用均方误差
来衡量,要做的事情就是希望能够找到
和
,使得:
现在要求解这个连续函数的最小值,那么只需要求它的偏导数,让它的偏导数等于0来估计它的参数,即:
2)实现
首先创建一些数据点:
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.scatter(x_train, y_train, color="r")
plt.xlabel("X")
plt.ylabel("Y")
plt.show()
有了数据,我们就可以开始创建模型:
class LinearRegression(nn.Module):
def __init__(self):
super(LinearRegression, self).__init__()
self.linear = nn.Linear(1, 1) # 输入和输出的维度都是1
def forward(self, x):
out = self.linear(x)
return out
上面我们定义了一个简单的模型 , 输入输出参数都是一维,当然这里可以根据我们想要的输入输出维度进行更改。同时可以根据电脑有没有英伟达的 ,来决定使用 还是 训练:
if torch.cuda.is_available():
model = LinearRegression().cuda()
else:
model = LinearRegression()
模型创建好之后,我们需要定义优化函数和损失函数,在 中提供了 方法优化我们的神经网络,我们可以直接使用,感兴趣的可以看看深度学习——优化器算法Optimizer详解:
criterion = nn.MSELoss() # 损失函数
optimizer = torch.optim.SGD(model.parameters(), 1e-3) # 优化函数
接下来我们就可以开始训练模型了,前面生成的数据为 numpy,需要将其转化为深度学习支持的 tensor:
x_train = torch.from_numpy(x_train)
y_train = torch.from_numpy(y_train)
模型训练,我们这里定义训练6000次:
num_epochs = 6000
for epoch in range(num_epochs):
x_train = Variable(x_train) # 将数据变为 Variable
y_train = Variable(y_train)
output = model(x_train) # 训练模型
loss = criterion(output, y_train) # 计算损失
optimizer.zero_grad() # 梯度归零,不然梯度会累加,造成无法收敛
loss.backward() # 进行反向传播,计算损失函数对于网络参数的梯度值
optimizer.step() # 更新参数值
if(epoch + 1) % 200 == 0:
print("loss: ", loss.data)
每次训练后的损失如下:
loss: tensor(0.1865)
loss: tensor(0.1848)
loss: tensor(0.1833)
loss: tensor(0.1819)
loss: tensor(0.1806)
loss: tensor(0.1795)
loss: tensor(0.1784)
loss: tensor(0.1775)
loss: tensor(0.1767)
loss: tensor(0.1759)
loss: tensor(0.1752)
loss: tensor(0.1746)
loss: tensor(0.1741)
loss: tensor(0.1735)
loss: tensor(0.1731)
loss: tensor(0.1727)
loss: tensor(0.1723)
loss: tensor(0.1720)
loss: tensor(0.1717)
loss: tensor(0.1714)
loss: tensor(0.1712)
loss: tensor(0.1710)
loss: tensor(0.1708)
loss: tensor(0.1706)
loss: tensor(0.1704)
loss: tensor(0.1703)
loss: tensor(0.1701)
loss: tensor(0.1700)
loss: tensor(0.1699)
loss: tensor(0.1698)
训练完成后,我们就得到了一条直线尽可能的靠近这些离散的点,下面可以看看预测的效果:
plt.scatter(x_train.numpy(), y_train.numpy(), color="r", label="origin data")
plt.plot(x_train.numpy(), output.data.numpy(), "b", label="predict data")
plt.show()
多项式回归
对于一般的线性回归,由于该函数拟合出来的是一条直线,所以精度欠佳,我们可以考虑多项式回归,也就是提高每个属性的次数,原理和上面的线性回归是一样的,只不过这里用的是高次多项式而不是简单的一次线性多项式 。
首先给出我们想要拟合的方程:
然后可以设置参数方程:
可以看到,上述方程与线性回归方程并没有本质区别。所以我们可以采用线性回归的方式来进行多项式的拟合,下面的代码实现,我就不一一细讲了。
w_target = np.array([2, 3, 4]) # 定义参数
b_target = np.array([1]) # 定义参数
f_y = '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_y)
获得实际函数的方程式:
x_sample = np.arange(-1, 1.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.show() # 实际图形
数据准备,我们需要将数据处理成矩阵的方式:
x_train = np.stack([x_sample ** i for i in range(1, 4)], axis=1)
x_train = torch.from_numpy(x_train).float() # 转换成 float tensor
y_train = torch.from_numpy(y_sample).float().unsqueeze(1) # 转化成 float tensor
定义参数和模型,在这里模型也可以使用上面一维线性回归的模型创建方式,感兴趣的朋友可以自己尝试以下,我这里就不再次实现了。
w = Variable(torch.randn(3, 1), requires_grad=True)
b = Variable(torch.zeros(1), requires_grad=True)
# 将 x 和 y 转换成 Variable
x_train = Variable(x_train)
y_train = Variable(y_train)
def multi_linear(x):
return torch.mm(x, w) + b
定义损失函数与优化函数
criterion = nn.MSELoss() # 损失函数
optimizer = torch.optim.SGD([w, b], lr=1e-3)
模型训练
epoch = 0
while True:
y_pred = multi_linear(x_train)
loss = criterion(y_pred, y_train)
optimizer.zero_grad()
loss.backward()
optimizer.step()
epoch += 1
if loss.data < 0.001:
print('epoch {}, Loss: {:.5f}'.format(epoch, loss.data))
break
epoch 42571, Loss: 0.00100,可以看出最后训练了42571次,损失为1e-3,已经是很精确的,下面我们来看看实际效果:
# 画出更新之后的结果
y_pred = multi_linear(x_train)
plt.plot(x_train.data.numpy()[:, 0], y_pred.data.numpy(), label='fitting curve', color='r')
plt.plot(x_train.data.numpy()[:, 0], y_sample, label='real curve', color='b')
plt.legend()