1.计算图
- 背景
神经网络通过数值微分计算神经网络的权重参数的梯度(即损失函数关于权重参数的梯度)
数值微分虽然简单,容易实现,但是计算比较耗时。
- 优点
计算图的特征是可以通过传递“局部计算结果“获得最终结果。
可以通过正向传播和反向传播高效地计算各个变量的导数值。
- 模型
计算图将神经网络的计算过程通过数据的图结构表示出来。
(“从左往右进行计算”是一种正方向上的传播(从计算图出发点到结束点的传播),简称为正向传播;反之,则为反向传播。)
2.链式法则定义
如果某一个函数是由复合函数表示,则该复合函数的导数可以用构成复合函数的各个函数的导数的乘积表示。
计算图与链式法则:
3.反向传播
反向传播局部导数的传递,是基于链式法则的。
反向传播的计算顺序:先将节点的输入信号乘以节点的局部导数(偏导数),然后再传递给下一个节点。
案例:苹果含税(乘法层);苹果和橘子含税(既包含乘法层,也包含加法层)
说明:关于程序中"backward"中“self.x”和“self.y"互换可以这样理解:
若苹果的费用(price)=苹果的价格(apple)*苹果的数量(apple_num),则苹果费用对苹果单价的导数则为苹果的数量;反之为苹果的单价。
程序源码
class MulLayer:
def __init__(self):
#self.x=None
#self.y=None
self.x,self.y=None,None
def forward(self,x,y):
#self.x=x
#self.y=y
self.x,self.y=x,y
out=x*y
return out
def backward(self,dout):#dout为上游传来的导数
dx=dout*self.y#反转x和y
dy=dout*self.x
return dx,dy
class AddLayer:
def __init__(self):
pass
def forward(self,x,y):
return x+y
def backward(self,dout):
dx=dout*1
dy=dout*1
return dx,dy
if __name__=="__main__":
apple=100
apple_num=2
tax=1.1
mul_apple_layer=MulLayer()
mul_tax_layer=MulLayer()
dprice=1
print("苹果-->正向传播".center(50,"-"))
apple_price=mul_apple_layer.forward(apple,apple_num)#1
print("未缴税的价格{}".format(int(apple_price)))
print("mul_apple_layer初始值:self.x-->{},self.y-->{}".format(mul_apple_layer.x,mul_apple_layer.y))
price=mul_tax_layer.forward(apple_price,tax)#2
print("mul_tax_layer初始值:self.x-->{},self.y-->{}".format(mul_tax_layer.x,mul_tax_layer.y))
print("交税后的价格{}".format(int(price)))
print("苹果-->反向传播".center(50,"="))
dapple_price,dtax=mul_tax_layer.backward(dprice)
print("税率{},消费税的导数{}".format(dapple_price,dtax))
dapple,dapple_num=mul_apple_layer.backward(dapple_price)
print("苹果单价的导数{},苹果数量的导数{}".format(dapple,int(dapple_num)))
for i in range(3):
print("\n")
######苹果和橘子
mul_apple_layer2=MulLayer()
mul_orange_layer2=MulLayer()
add_apple_orange_layer=AddLayer()
mul_tax_layer2=MulLayer()
orange=150
orange_num=3
print("苹果和橘子-->正向传播".center(50,"-"))
#forward
apple_price=mul_apple_layer2.forward(apple,apple_num)#1
orange_price=mul_orange_layer2.forward(orange,orange_num)#2
all_price=add_apple_orange_layer.forward(apple_price,orange_price)#3
price=mul_tax_layer2.forward(all_price,tax)#4
print("苹果和橘子的总费用{},以及交税后的价格{}".format(all_price,int(price)))
#backward
print("苹果和橘子-->反向传播".center(50,"="))
dall_price,dtax=mul_tax_layer2.backward(dprice)#4
dapple_price,dorange_price=add_apple_orange_layer.backward(dall_price)#3
dorange,dorange_num=mul_orange_layer2.backward(dorange_price)#2 dapple_price=dapple*dapple_num
dapple,dapple_num=mul_apple_layer2.backward(dapple_price)#1
print("苹果数量的导数{},苹果价格的导数{}\n 橘子数量的导数{},橘子价格的导数{}\n税率{},消费税的导数{}".format(dapple_num,dapple,dorange_num,dorange,dtax,dall_price))