深度学习框架——自动求导
最开始接触深度学习的框架就是Caffe,用Caffe做过目标检测、图像分类、人脸识别等训练任务。当时写C++代码时一项很头痛的事就是自己去写反向传播代码。后来tensorflow出来后,只需要写前向过程不需要写反向过程,真的是极大的缓解了编程压力,让人们可以投入更多精力去设计网络结构、损失函数、各种新的创意。在公司里面做业务也没有时间去深入了解为什么可以这样,这几天抽空来梳理一下。主要参考了下述博客文章:
【1】AI 框架基础技术之自动求导机制 (Autograd)
https://blog.csdn.net/a321123b/article/details/114147332
看完之后,我个人理解是,本质上还是使用链式法则。
(1)对人:给出一个解析表达式,可以给出函数关于各个变量(偏)导数表达式。
(2)对计算机:但是在各个深度学习框架中,其实每个操作或每个层,都会求解当前输出关于输入的(偏)导数。现在回想当时在Caffe中也是单独写一个层的反向计算代码。然后根据各个操作/层之间的拓扑关系,形成完整的最终损失值关于网络中任意一个变量的梯度值。
关于现在主流框架自动求导的思路:
(1)是每个底层函数/操作构成一个独立的计算单元,包含其前向计算函数\(x_{out} = f(x_{in})\)的实现代码和反向计算函数\(grad(x_{in})=\frac{dx_{out}}{dx_{in}}=\frac{d}{dx_{in}}{f(x_{in})}\)的实现代码。但是这里计算的仅仅是当前函数的关于输入的梯度,并不是网络输出关于输入或中间变量的梯度。其实这里反向计算的是链式法则中一个环节。
(2)自动求导需要构建组成网络中各个计算单元之间的拓扑结构,构建好了这个拓扑关系结构图,再根据每个计算单元/函数计算出的梯度值,就可以从后到前,计算出网络输出关于输入或中间变量的真实梯度值。
而对于有解析表达式,我们人工计算导函数的过程,其实也是分上述(1)和(2)两个部分完成的,但是我们没有特别区分这两个步骤罢了。但是当表达式过于复杂时,人工构建拓扑关系结构图就比较麻烦,容易出错。而现在的机器学习框架则将这2件事自动化解决了,方便且不容易出错。