1.ReLU层的实现:
激活函数ReLU由下式表示:
因此,可以求出y关于x的导数:
也就是说,如果前向传播时的输入x>0,则反向传播会将上游的值原封不动地传给下游;反过来。如果前向传播时的输入x≤0,则反向传播会中传给下游的信号将停在此处。
class Relu:
def __init__(self):
self.mask = None
def forward(self, x):
# 得到布尔数组
self.mask = (x <= 0)
out = x.copy()
# 进行过滤操作,如果前向传播时的输入值≤0,那么传递的值为0,否则传递原值
out[self.mask] = 0
return out
def backward(self, dout):
# 进行过滤操作,如果前向传播时的输入值≤0,那么反向传播的值为0
dout[self.mask] = 0
dx = dout
return dx
2.Sigmoid层的实现:
激活函数ReLU由下式表示:
$$
y=\frac{1}{1+\exp \left( -x \right)}
$$
其前向传播用计算图表示的话如下所示:
通过依次计算导数,可以得到反向传播的计算图:
上述反向传播得到的值可以进一步整理:
$$
\frac{\partial L}{\partial y}\,\,y^2\,\,\exp \left( -x \right) =\frac{\partial L}{\partial y}\frac{1}{\left( 1+\exp \left( -x \right) \right) ^2}\exp \left( -x \right)
$$
$$
=\frac{\partial L}{\partial y}\frac{1}{1+\exp \left( -x \right)}\frac{\exp \left( -x \right)}{1+\exp \left( -x \right)}\,\,=\frac{\partial L}{\partial y}y\left( 1-y \right)
$$
因此反向传播的计算图可以简化为:
代码实现:
class Sigmoid:
def __init__(self):
self.out = None
def forward(self, x):
out = sigmoid(x)
self.out = out
return out
def backward(self, dout):
dx = dout * (1.0 - self.out) * self.out
return dx
Reference:
《Deep Learning from Scratch》