深度学习中,计算是核心部分,所以一直在致力于提供算法网络的计算能力,比较基础的两种优化形式有:
1.将计算过程做为一个计算图来进行运算,每个计算过程用节点来模拟,这样的好处可以分割运算,甚至可以多线程,多gpu开session来进行运算
2.向量化:以tensorflow为例,进行向量化的运算,由于python独有的广播机制,向量化运算不需要显式的for循环,可以大大提高运算速度
下面具体来看深度网络框架中的计算图 && 向量化运算
1.计算图
在深度学习中有图的概念: 创建计算节点链接成一个计算图,每个节点是一个 t e n s o r tensor tensor用于记录变量
下面是一个标量的简单例子,我们模拟前馈传递和反向传播的过程:
基础函数: J ( x , y , z ) = 2 ( x y + y z ) J(x,y,z) = 2(xy + yz) J(x,y,z)=2(xy+yz)
那么构建其计算图:
前馈过程:
- 第一步: 初始化 x , y , z x,y,z x,y,z
- 第二步:令 u = x y v = y z u = xy \; v =yz u=xyv=yz
- 第三部: 令 p = u + v p = u+v p=u+v
- 最后一步: J ( x , y , z ) = J ( u , v ) = J ( p ) = 2 p J(x,y,z) = J(u,v) = J(p) = 2p J(x,y,z)=J(u,v)=J(p)=2p 这样一个计算过程就一步步分解出来
反向微分过程:
-
从 J J J开始反向传播: d p = d J / d p = 2 dp = dJ/dp = 2 dp=dJ/dp=2
-
d u = d J / d p d p / d u = 2 ∗ 1 = 2 du = dJ/dp \;dp/du= 2 * 1 = 2 du=dJ/dpdp/du=2∗1=2, d v = d J / d p d p / d v = 2 ∗ 1 = 2 dv = dJ/dp\; dp/dv = 2 * 1 = 2 dv=dJ/dpdp/dv=2∗1=2
-
接着求 d x , d y , d z dx,dy,dz dx,dy,dz
d x = d u d u / d x = 2 y dx = du du/dx = 2y dx=dudu/dx=2y
d y = d u d u / d y + d v d v / d y = 2 x + 2 z dy = du du/dy + dv dv/dy = 2x + 2z dy=dudu/dy+dvdv/dy=2x+2z
d z = d v d v / d z = 2 y dz = dv dv/dz = 2y dz=dvdv/dz=2y
不难发现计算图反向梯度下降的时候是逐级递归相乘的,这就是深度学习中的链式相乘法则,我们只有一个模型,在神经网络中会链式相乘的参数会逐级递增来更新每一个网络层的参数
我们接着来看logistic回归的计算图,这里使用Andrew NG文档中的一个图:
前馈的过程如图,也是一个节点简单运算,向后递归的过程:
我们来看反向传播过程:
- d a = d l / d a = d ( − ( y l o g y p r e + ( 1 − y ) l o g ( 1 − y p r e ) ) ) = − y / a + ( 1 − y ) / 1 − a da = dl/da = d(-(ylogy^{pre}+(1-y)log(1-y^{pre}) )) = -y/a + (1-y)/1-a da=dl/da=d(−(ylogypre+(1−y)log(1−ypre)))=−y/a+(1−y)/1−a
- d z = d a d a / d z = a − y dz = da \; da/dz = a - y dz=dada/dz=a−y
- d w 1 = x 1 d z d w 2 = x 2 d z d z d b = d z dw1 = x_1\;dz \;\;\;\;\; dw2 = x_2\;dz \;\;\;\;\;dz \; db = dz dw1=x1dzdw2=x2dzdzdb=dz
2.向量化
在常规的编程中:
比如对于一个多实例,多特征的网络中,至少要用到两个for循环,这会大大降低算法的效率:
如下面的公式
前馈过程 :
y p r e = σ ( w ! T x 1 ( i ) + w 2 T x 2 ( i ) + b ) y^pre = \sigma(w_!^Tx_1^{(i)} + w_2^Tx_2^{(i)} + b) ypre=σ(w!Tx1(i)+w2Tx2(i)+b)
反向传播过程(直接使用上面的公式)
d w 1 = ∑ i = 0 m x 1 ( i ) d z = ∑ i = 0 m x 1 ( i ) ( σ ( w 1 T x 1 ( i ) + w 2 T x 2 ( i ) + b ) − y ) dw1 = \sum_{i =0}^{m}x_1^(i)\;dz = \sum_{i =0}^{m}x_1^(i)(\sigma(w_1^Tx_1^{(i)} + w_2^Tx_2^{(i)} +b) - y) dw1=i=0∑mx1(i)dz=i=0∑mx1(i)(σ(w1Tx1(i)+w2Tx2(i)+b)−y)
这样来看实现上述的前馈过程和反向传播,至少需要两层for循环 一层遍历实例 一层遍历实例中的特征,那么算法将会奇慢无比
但是python中支持向量化的运算所以我们直接利用相关Api进行矩阵运算或者向量运算
那么
前馈过程:
Y = s i g m a ( W T X + b ) ) Y = sigma(W^TX +b)) Y=sigma(WTX+b))
反向传播过程:
d W = X d z = X ( σ ( W T X + b ) − y ) d\;W = Xdz = X(\sigma(W^TX +b) - y) dW=Xdz=X(σ(WTX+b)−y)
有兴趣的可以试一下,时间的量级可以提升2个量级以上