《计算机视觉之PyTorch数字图像处理》--自动梯度与神经网络
[复制链接]
PyTorch作为深度学习的主要框架之一,最核心的功能就是自动梯度。自动梯度可进行神经网络的梯度求解和及向传播,优化神经网络权重。
自动梯度
在神经网络的优化中,计算梯度是一个基本操作。使用梯度下降法,可以对目标函数进行优化,使得函数可以趋近目标值。PyTorch将自动梯度集成到张量及其运算中,可以方便的对张量计算梯度。
使用梯度下降法是求函数极小值的一种方法。这让人想起有些类似数学求导,计算零点,求最大最小值。下图是梯度下降进行函数极小值近似求解的示意。同样,对于求极大值可以使用梯度上升方法。
自动梯度是PyTorch中最核心的功能之一。对于自动梯度的实现是在torch.autograd包中提供的,可实现对任意标量函数的求导运算。目前PyTorch中的张量类型已经将求导功能所包含在内,只需要对求导的张量进行声明即可。
自动梯度计算:函数的前向传播是表示函数的计算图从输入的张量经过计算输出结果。而梯度的计算,则是从输出结果沿着计算图的前向传播的反方向,一直到输入,这一过程称为反向传播(back propagation)。张量是否进行求导,可将张量的requires_grad属性置True或False即可,置True时该张量会被计算梯度,置False时该张量不会被计算梯度。
自动梯度拟合多元函数,以sin(x)函数的多项式进行拟合为例,代码如下:
import torch as tc
import visdom
vis=visdom.Visdom()
lossline=vis.line([None]) #动态记录损失的变化
pi =tc.deg2rad(tc.tensor(180.0)) #得到pi的弧度值
x = tc.linspace(-pi, pi, 2000) #在-pi到pi平均间隔采2000个样
y=tc.sin(x) #计算sin(x)的值
#需要学习多项式的系数
a = tc.randn(1, requires_grad=True)
b = tc.randn(1, requires_grad=True)
c = tc.randn(1, requires_grad=True)
d = tc.randn(1, requires_grad=True)
e = tc.randn(1, requires_grad=True)
f = tc.randn(1, requires_grad=True)
epoch=80000 #训练的轮数
learning_rate = 0.55*1e-7 #学习速率
for t in range(epoch):
# 前向计算,使用5次多项式
y_pred = a + b * x + c * x ** 2 + d * x ** 3+ e * x**4 +f * x**5
# 计算每一点处拟合值与真实值的差
# 计算误差的平方和得到一个尺寸为(1,)的标量,作为损失
loss = (y_pred - y).pow(2).sum()
#loss=tc.nn.MSELoss(reduction='sum')(y_pred,y)
# 每100轮打印的值
if t % 100 == 99:
print(t, loss.item())
#将训练过程中的损失变化进行可视化
vis.line([loss.item()],[t],win=lossline,update='append')
#调用loss张量的backward方法,沿计算图反向求导
#计算出所有张量中属性requires_grad=True的梯度
#完成计算后a.grad,b.grad,c.grad,d.grad,e.grad,f.grad保存了梯度
loss.backward()
# 手动进行参数的梯度下降,由于参数都是可求导的
#使用tc.no_grad(),放弃对所包含内容加入到计算图
with tc.no_grad():
a -= learning_rate * a.grad
b -= learning_rate * b.grad
c -= learning_rate * c.grad
d -= learning_rate * d.grad
e -= learning_rate * e.grad
f -= learning_rate * f.grad
#在更新完参数后,将参数的梯度手动置0
a.grad = None
b.grad = None
c.grad = None
d.grad = None
e.grad = None
f.grad = None
#显示学习到的函数
print(f'结果: y = {a.item()} + {b.item()} x + {c.item()} x^2 + {d.item()} x^3+{e.item()}x^4+{f.item()}x^5')
py=tc.stack([y,y_pred],0).T
#绘制sin(x)和学习函数
vis.line(py,x)
拟合运行结果如下。可以看到在训练的轮数epoch=80000,得到的对sin(x)函数拟合,最终学习到的函数的预测值与真实值已经十分接近了,说明使用梯度下降的方法能够通过已经的训练数据对未知参数进行学习。
模块
通常神经网络是由许多结构相似的模块所组成,这些结构通常也称为层。层的基本功能是利用层中的参数,按照一定的计算方法对输入的张量进行变换,输出计算结果,并对层中的参数进行管理,以便进行参数的更新。在PyTorch中,在torch.nn包里定义了许多在深度学习中使用频率最高的一些层。
在PyTorch中,将神经网络的各层以及网络本身使用Module类进行封装,具有很明显的好处:具有状态的计算模块;与PyTorch的自动梯度紧密集成;易于使用和转换。
对模块(层)先初始化,再传入张量进行计算的过程,是使用各Module子类的通用流程。在PyTorch中将神经网络里的常用运算进行封装,提供了一些构成神经网络的基本结构,成为可直接调用的模块。下面做些介绍:
●卷积层(Convolution Layers):是目前构成神经网络最重要的一种层结构。在PyTorch中提供了不同种类的卷积层,可针对语音数据的一维卷积nn.Conv1d,nn.ConvTranspose1d,LazyConv1d,LazyConv1d;主要用于图像数据的二维卷积nn.Conv2d,nn.ConvTranspose2d,LazyConv2d,LazyConv2d;以及针对视频数据的三维卷积nn.Conv3d,nn.ConvTranspose3d,LazyConv3d,LazyConv3d。此外,还有较为通用的nn.Unfold和nn.Fold模块,可以完成局部的展开和恢复,以进行高级的邻域操作。
●池化层(Pooling Layers):是目前卷积神经网络中常用的层,主要用于特征的综合,以减小特征图的尺寸。在PyTorch中,对于不同维度的数据提供了不同的池化层,此外,还提供了不同的池化方法。对于图像数据,主要使用的池化方法有:nn.MaxPool2d,nn.AvgPool2d,nn.LPPool2d,nn.AdaptiveAvgPool2d等。对于池化层,在使用时需要设定的参数有kernel_size和stride,两个参数的含义与卷积层中的参数相同,但kernel_size通常取偶数。
●填充层(Padding Layers):在图像处理中,主要用于调节数据的尺寸,以保持数据中的位置关系,特别是在一些需要输入和输出数据在尺寸上相同时,用填充层进行调整。对于图像数据,常用的填充层有nn.ReflectionPad2d,nn.ReplicationPad2d,nn.ZeroPad2d和nn.ConstantPad2d等。
●全连接层(Fully Connected Layer):早期的神经网络主要就是由全连接层所构成。目前全连接层通常用在网络的输出阶段,负责全局特征的提取和最终结果的生成。全连接层是nn.Linear类,主要接收三个参数,输入的特征数、输出的特征数和是否有偏置,默认是有偏置。
激活函数
在神经网络的结构中,激活函数是一种神经网络中特殊的模块,用于给神经网络提供非线性功能。激活函数位于卷积层、池化层和归一化层之后,下一层卷积层之前。
损失函数
损失函数(Loss Function),也称为代价函数(Cost Function),用于监督神经网络的学习方向。为了让神经网络能够训练,就将真实的学习目标,用损失函数进行替代,使得当神经网络在损失函数上变小时,神经网络在学习任务的性能上也得到提升。损失函数的另一个作用是将网络的输出变成一个标量,以便于进行梯度下降,寻找极小值。
根据学习任务的不同,一般可以将损失函数分为两大类:回归损失函数和分类损失函数。回归损失用于学习标签为连续实数的学习目标,分类损失函数用于学习标签为离散数值的学习目标。
优化器
优化器(Optimizer)是网络训练的重要组成部分,作用是利用网络的梯度,进行网络中参数的学习,从而使得网络的损失减小,逐步接近训练目标。随着神经网络的发展,新的优化方法不断的提出,PyTorch的torch.optim模块就将常用的神经网络优化方法进行了组织,通过调用相应的优化器,可方便的使用不同的优化算法进行网络的训练。
全连接神经网络
PyTorch中神经网络各个部分。在实际中进行网络的构建和训练,全连接神经网络对以上几个部分进行组合,形成有机的整体。
本篇通过梳理,对PyTorch自动梯度与神经网络有更详细的需学习理解,通过仿真,对自动梯度学习训练实践,增强了认识。
|