引言
本次文章将在上一节的二维卷积的基础上,教你如何搭建一个属于自己的训练网络。
本文概要
1
本文目标
2
Pytorch思路分析
3
本文小结
4
参考文献
正文开始
1
本文目标
上一节主要介绍了二维卷积,我们已经知道,卷积运算最主要的组成部分就是卷积核,即通过卷积核与输入数组进行互相关运算,然后得到输出数组。那么本文的主要目的是根据给出的输入数组和输出数组来训练出卷积运算中的核函数。
2
Pytoch思路分析
给定一个输入和一个输出,求解卷积核函数,从数学的角度来说,就是求解方程组,将核函数的变量求解出来。那么从训练网络的角度来讲呢?其实我们可以假设我们的输入为X,标准输出为Y,卷积核为K。如下:
输入X:
[[0., 1., 2.],
[3., 4., 5.],
[6., 7., 8.]]
标准输出Y:
[[19, 25],
[37, 43]]
卷积核K:
c_core=torch.randn(2,2).view((1,1,2,2)).type(torch.FloatTensor)
那么在pytorch中,首先可以给随机初始化卷积核数组。然后每一次的迭代更新,使用平方差来计算标准输出Y和X与K卷积得到输出,接着计算梯度来更新权重。那么直接开始源码分析(见代码注释)。
#通过tensor初始化输入X和Y,并将X,Y的type设置哼float型,
# 因为CPU默认是Long型,pytorch的计算不支持,所以要修改成float
X=torch.tensor([[0, 1, 2], [3, 4, 5], [6, 7, 8]])
X=X.view((1,1,3,3)).type(torch.FloatTensor)
Y=torch.tensor([[19, 25],[37, 43]])
Y=Y.view(1,1,2,2).type(torch.FloatTensor)
Y=Y.type(torch.FloatTensor)
# 随机化核函数,这里测c_core和上面的K表达的意思是一样的
c_core=torch.randn(2,2).view((1,1,2,2)).type(torch.FloatTensor)
# 下面这一句的目的是为了让c_core自动计算梯度
c_core=c_core.requires_grad_()
# 设置训练学习率
LR=0.01
#定义一个损失函数,这个在pytorch中表示均方差计算
loss_fun=nn.MSELoss()
# 训练开始,循环100次
for i in range(100):
# 调用pytorch的卷积计算函数
y_pre=nn.functional.conv2d(X,c_core)
# 根据损失函数计算loss
loss=loss_fun(y_pre,Y)
# 这句话特别的重要!!!目的是为了保持c_core的梯度
c_core.retain_grad()
# 反向传播,计算梯度
loss.backward()
# 根据梯度下降的方式更新核函数,并准备下一次训练
c_core=c_core-c_core.grad*LR
# 打印损失loss
print('the loss is:',loss)
print('c_core: ',c_core)
训练输出部分结果:
the loss is: tensor(1054.8984, grad_fn=<MseLossBackward>)
the loss is: tensor(454.9742, grad_fn=<MseLossBackward>)
the loss is: tensor(196.8699, grad_fn=<MseLossBackward>)
the loss is: tensor(85.7956, grad_fn=<MseLossBackward>)
the loss is: tensor(37.9659, grad_fn=<MseLossBackward>)
...
the loss is: tensor(0.0053, grad_fn=<MseLossBackward>)
the loss is: tensor(0.0051, grad_fn=<MseLossBackward>)
c_core: tensor([[[[0.8151, 0.1555],
[1.5457, 3.5254]]]], grad_fn=<SubBackward0>)
通过上面的输出可以看到,loss不断的减少,最终100次的结果输出的卷积核函数c_core(K)为:
c_core: tensor([[[[0.8151, 0.1555],
[1.5457, 3.5254]]]], grad_fn=<SubBackward0>)
最后为了验证,采用卷积核计算输出X的卷积,并与标准输出Y做对比代码如下:
import torch
X=torch.tensor([[[[0, 1, 2], [3, 4, 5], [6, 7, 8]]]]).type(torch.FloatTensor)
print('输入X: ',X)
c_core=torch.tensor([[[[0.8151, 0.1555],
[1.5457, 3.5254]]]]).type(torch.FloatTensor)
print('卷积核c_core: ',c_core)
y_out=torch.tensor([[[[19, 25],[37, 43]]]])
out=torch.nn.functional.conv2d(X,c_core)
print('标准输出:',y_out)
print('预测输出:',out)
运行如下:
输入X: tensor([[[[0., 1., 2.],
[3., 4., 5.],
[6., 7., 8.]]]])
卷积核c_core: tensor([[[[0.8151, 0.1555],
[1.5457, 3.5254]]]])
标准输出:tensor([[[[19, 25],
[37, 43]]]])
预测输出:tensor([[[[18.8942, 24.9359],
[37.0193, 43.0610]]]])
最后可以看出预测输出和标准输出相差不大,可见我们搭建训练方法有效的。
3
本文小结
本文主要介绍了如何用pytorch搭建自己的训练网络,虽然很基础,但是还是建议刚开始入门同学实践一下,实践是检验真理的唯一标准。
4
参考文献
[1]http://zh.d2l.ai/chapter_natural-language-processing/index.html