手写前向传播和反向传播

"""
前向传播
"""
#定义这些值,逐步求出最终的L
a=2.0
print("a:",a)
b=-3.0
print("b:",b)
c=10.0
print("c:",c)
f=-2.0
e=a*b
print("e:",e)
d=e+c
print("d:",d)
L=d*f
print(L)
a: 2.0
b: -3.0
c: 10.0
e: -6.0
d: 4.0
-8.0
"""
反向传播
"""
"""
我们要算的是L对每个节点的导数,也就是每个节点的grad。规则只有三条局部导数:
1. 乘法 y=u*v: dy/du=v, dy/dv=u (交换一个对方的值)
2. 加法 y=u+v: dy/du=1, dy/dv=1 (梯度原样穿过)
3. 然后用链式法则:某节点.grad = 上游.grad * 本节点的局部导数
"""
"""
起点:L对自已求导, dL/dL=1.0
开始反向: 
1. L = d*f (乘法,对方的值就是局部导数)
dL/dd = dL/dL * f = 1.0*(-2.0)=-2.0
dL/df = dL/dL * d = 1.0*4.0=4.0

2. d = e+c (加法,梯度原样向两边传)
dL/de = dL/dd*1 = -2.0
dL/dc = dL/dd*1 = -2.0

3. e = a*b (乘法,再次交换对方的值)
dL/da = dL/de * b = -2.0 * (-3.0) = 6.0
dL/db = dL/de * a = -2.0 * 2.0 = -4.0
"""

下面这张计算图把上面的算术整合在一起——每个方框里是前向传播得到的值,下面一行是反向传播算出的梯度。蓝色是输入(叶子节点),绿色是运算结果:

karpathy_micrograd_backprop_example_one

 

例子二

#例子二, 一个神经元+tanh
"""
前向传播
"""
x1=2.0
x2=0.0
w1=-3.0
w2=1.0
b=6.88137

y1=x1*w1
y2=x2*w2
print(y1)
print(y2)

y3=y1+y2
print(y3)

n=y3+b
print(n)

import numpy as np
o=np.tanh(n)
print(o)
-6.0
0.0
-6.0
0.8813700000000004
0.7071049876722272
"""
反向传播
"""
#因为: o=tanh(n), 根据公式得出do/dn=1-o**2
#起点: o.grad=1, 因为o=0.7,所以o**2=0.5,于是do/dn=0.5
"""
n=x1w1x2w2+b,加法把梯度原样分给两边
x1w1x2w2.grad=0.5
b.grad=0.5

x1w1x2w2 = x1w1+x2w2, 加法再分一次
x1w1.grad=0.5
x2w2.grad=0.5

x1w1 = x1*w1, 乘法交换对方的值
x1.grad = x1w1.grad * w1 = 0.5*-3.0=-1.5
w1.grad = x1w1.grad * x1 =  0.5*2.0=1.0

x2w2 = x2*w2, 乘法交换对方的值
x2.grad = x2w2.grad * w2 = 0.5*1.0=0.5
w2.gard = x2w2.grad * x2 = 0.5*0.0=0.0
"""

几条要记住的规则: 反向传播其实就是几条局部导数规则反复套用:

加法节点y=u+v是梯度路由器,把上游梯度原样复制给每个输入(本地导数都是1)。乘法节点y=u*v把上游梯度乘以另一个输入的值再传回去。tanh节点的本地导数是1-tanh**2(n),即1-o**2。每个节点只需知道自已的局部导数,再乘上从右边传来的上游梯度,就完成了它那一段链式法则。

posted @ 2026-06-19 10:51  johnny_zhao  阅读(4)  评论(0)    收藏  举报