机器学习和深度学习中比较重要嘚内容便是计算图主流的框架如tensorflow,pytorch都是以计算图为主要框架而计算图的核心便是自动求导。
所谓自动求导就是在表达式或者网络结構确定之时,其(导数)梯度便也同时确定了自动求导听上去很玄幻,很厉害但其本质还是有向箭头的传递,该箭头是从自变量指向朂终结果
我们先定义表达式(由初等函数构造而成),在表达式构造完成之前不进行计算完成后,传入自变量在函数值通过箭头传遞的同时,导数值也同时在箭头上传递(静态图的简单描述静态图的概念这里先不说明,可以先按照函数表达式来理解我们写一个函數的时候就是f(x) = ...的形式,先写好函数是如何计算的再给X带入具体数值计算。)
这样之后给人的感觉就是计算表达式的同时导数值也自动算出来了。
举个简单的例子对于表达式:
我们在求导的时候,先求外层函数的导数再求内层函数的导数,最终两者相乘即:
接着对u(x)求导,最后得到:
这表明对函数求导的核心便是链式法则而链式法则的每一步求导正和计算图的有向结构类似(这里先不讨论计算图的概念,只针对自动求导)
算符在量子力学中,是作用在一个函数得到另一个函数的操作简单理解为将一个量变换为另一个量。
我们把這里的每一个函数看做一个算符每一个算符看做一个节点,每一个量在通过节点之后就变成了另一个量
在上面的表达式中,指数函数三角函数,指数函数对数函数求导公式和幂函数一共四个函数就是四个算符,四个节点每一个节点都存在若干个变量:value(函数值),grad(导数)root(自变量),next(下一节点最后一个节点的next为None)。
除了节点之外最重要的就是自变量了。这里用placeholder(占位符)表示(模仿tensorflow)嘚写法placeholder正如其名,作用就是占位(采用占位符的原因后续简述这里先按照这个模式使用),像极了人们书写函数时f(x)中的x(或者说就是)它也有grad(可有可无,自变量对自变量求导结果是1)size(数据尺寸,这里不会用到)root(就是自己)和next。
我们在构造一个函数表达式时前一节点的输出变成了后一节点的输入。在计算节点value时通过上一个节点的输出作为此节点中函数的输入计算而来。计算节点的grad时通過前一节点的梯度乘该节点的导数得到。
1.对于占位符本来是没有value变量的,但为了形式的统一在建立完方程形式,开始运行的时候我還是给予了placeholder一个value属性(父亲遗传下来的东西,不用怎么行)
2.对于算符,这里先简单的构建expsin,cosln和平方算符:
构造节点的时候我没有用全局列表保存每一步的操作以及名称,而是利用next的指针指向下一个需要计算的节点
这样可以用最少的变量数目保存我们需要的所有信息。(放在堆上的类减少栈上的变量增多,但是调用结束后栈上的空间立刻就被釋放了)
节点中存在root变量是为了开始计算的时候更方便些,不需要通过判断节点的上一节点是不是占位符来确定计算起始点也不需要保存函数表达式,然后从头开始算
3.最后定义Session对表达式求值
通过判断目前计算的节点是否是目标节点来决定是否停止计算,这样便可以通过Session嘚run方法直接返回目标节点的value
到此为止简单的自动求导就已经写好了,整个过程借鉴了tensorflow的套路当然我没看过tensorflow的源码,只是根据自己目前為止用到过的内容简单搭建
#构建表达式(计算图)
一开始我搭建表达式的时候,对每个节点记录其上一步操作这样可以通过递归的方式找到计算的起始点,然后喂入数据再计算本来全连接层已经按这种方式写好,正在写卷积但是某天突然醒悟之后便写下了此文,然後开始努力更改以前的东西QAQ
实现了自动求导之后,下面就要开始静态图的搭建还是会按照tensorflow2.0前的方式,不过既然新版本都出了我还迷戀旧版本,ε=(?ο`*)))唉
本人应用物理系,对ML, DL较感兴趣可毕竟不是计算机系啦,用语不那么专业操作可能显得复杂,希望大家能多多指導哦!