如图,共两部分,softmax一部分,cross-entropy一部分,a1、a2、a3是输入,y1、y2、y3是softmax的输出,t1、t2、t3是label,图中右侧输出Loss=cross entropy,输入gradient=1。
正向传播和反向传播基本规则(可以参考cs231n的教程):
正向就是正常运算,没什么说的,正向的多对一操作,求和,正向的一对多,每一条线都传播同样的值。关于汇聚和分散的原则,正向反向一样。
反向传播操作:
加法,grad_c=1,c=a+b,则grad_a=grad_b=grad_c。
乘法,grad_c=1,c=a×b,则grad_a=grad_c*b和grad_b=grad_c*a。
log、取导数等,都按正常导数就好了,需要注意反向传播求导过程的一个特点,y = w*x,dy/dw=x,所以想反向传播去更新网络参数w,前向传播过程是需要保留这个x的,x指每一个中间操作(例如图中的exp(a1)、y1、t1logy1等等),不特指输入数据x,所以关于神经网络的内存占用量等计算都少不了这些考量。
神经网络两大内存占用:前向传播的缓存,网络自身的参数。
参考图:
参考实现:
前向传播的loss并没有直接被后向传播使用,直接使用前边推导出的结果(y-t)作为梯度。。
关于if-else,我刚开始也看蒙了,刚开始我以为ifelse是为了应对脏数据的容错,后来测了一下,代码是跑不通的。
所以这段代码的意思是,如果size相等,说明你的label是onehot形式的,如果size不相等,说明你的label是index形式的,onehot直接相减就是误差,index实际是按label去取数据,如果一样,取出来就是1,就是误差0(公式里有个-1),如果label不一样,就是误差“2”,为什么,因为这个错误的y没被t指向,所以没减1,且t指向的那个0被减1,所以是-1和+1两个误差,因为这两个误差分属于两个index,也就是两个分类,所以虽然-1++1=0,但是误差不是0,onehot学的是分布。
demo:
import numpy as np
a = np.array([
[0,1,0,0],
[0,0,0,1],
[1,0,0,0],
])
t = np.array([
[0,1,0,0],
[0,0,1,0],
[1,0,0,0],
])
t2 = np.array([1,2,0])
t3 = np.array([1,3,0])
print(a)
a[np.arange(3),t2] -= 1
a = a/3
print(a)
print(sum(a))
t是one-hot形式的target,t2、t3代表非one-hot形式的target,t2对应t,a相应的有一个数据不正确,会得到如下结果。
如果使用t3,结果就是全0。
[[0 1 0 0]
[0 0 0 1]
[1 0 0 0]]
[[ 0. 0. 0. 0. ]
[ 0. 0. -0.33333333 0.33333333]
[ 0. 0. 0. 0. ]]
[ 0. 0. -0.33333333 0.33333333]