《计算机视觉之PyTorch数字图像处理》----解读“自动梯度与神经网络”
[复制链接]
在说明自动梯度与神经网络这个问题之前,先要介绍一下计算机视觉研究的方法,它主要分为三类,即传统方法、机器学习方法即深度学习方法。
- 传统方法
所谓“传统方法”是一种基于经典图像处理技术的方法,主要包括边缘检测、角点检测、纹理分析和状态描述等。传统方法通常需要手动设计特征提取和分类算法,它对图像质量和环境变化比较敏感、泛化性较差,只有在较为理想的条件下,才能获得满意的效果,但它对其它方法的研究具有较大的启发意义,是这方面的研究基点。
- 机器学习方法
所谓“机器学习方法”是一种通过数据自动学习其模式和规律的方法,可用于多样化的数据分析任务,该方法常用于图像分类、目标检测和图像法国等任务,在应用时常与图像处理方法结合所用。
- 深度学习方法
所谓“深度学习方法”,则是一种基于神经网络的机器学习方法,它通过多层神经网络来学习图像的高级特征和表示,比如卷积神经网络CNN的应用就已成为图像分类、目标检测和图像分割等的主流方法,并取得了接近人类视觉认知的水平。
有了以上的基本认识,再回到当初所提的问题上来。
所谓“自动梯度”是PyTorch所提供的最核心的功能,可对神经网络的梯度进行求解及反向传播,并对神经网络的权重加以优化。
自动梯度的实现是依托于torch.autograd包,可实现任何张量函数的求导计算。
在PyTorch中,是使用计算图来组织变量,且计算图是动态的。每次自动梯度的计算都是以最近一次计算图的前向传播为准。
所谓“前向传播”是指输入张量在按照函数的计算图进行运算时,其得到输出结果的这个过程被称为前向传播。
而将输出结果沿计算图前向传播的反方向梯度计算并计算到计算图输入的求解梯度过程称为“反向传播”。
在梯度计算中,使用梯度下降法可求解函数极小值,当梯度接近0或者函数值不再明显减小时,即可认为达到了极小值。
图1 用梯度下降法求解函数极小值
自动梯度不仅计算单变量的梯度,还能对多变量函数进行梯度计算,图2是对sin(x)函数的拟合过程。
图2 自动梯度拟合多元函数
对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()
# 每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 #整理y=sin(x)的值和预测的值y_pred
#绘制sin(x)和学习函数
vis.line(py,x)
#输出:
结果: y = -0.007337956223636866 + 0.9179902672767639 x + 0.004045205190777779 x^2 + -0.12921814620494843 x^3+-0.00039120070869103074x^4+0.0035445974208414555x^5
通常神经网络是由许多结构相似的模块所组成,这些结构通常也称为层。
在图像处理中涉及的层有卷积层、池化层、填充层及全连接层。
在PyTorch中,由torch.nn包提供了许多在深度学习中使用频率很高的一些层。利用这些层,则可以方便、快捷的构建起深度学习的模型。
此外,PyTorch也提供自定层的方法,可以通过继承torch.nn包中的Module类,进行层的自定义,增加了PyTorch的拓展性。
也就是说,有了PyTorch这个工具,就为深度学习打开了探索之门。
|