1. ReLU 函数层
激活函数 ReLU
(Rectified Linear Unit
)由下式(5.7)表示。
通过式(5.7),可以求出 y
关于 x
的导数,如式(5.8)所示。
在式(5.8)中,如果正向传播时的输入 x
大于0,则反向传播会将上游的值原封不动地传给下游。反过来,如果正向传播时的 x
小于等于0,则反向传播中传给下游的信号将停在此处。用计算图表示的话,如图5-18 所示。
在神经网络的层的实现中,一般假定 forward()
和 backward()
的参数是 NumPy
数组。如下代码所示:
class Relu:
def __init__(self):
self.mask = None
def forward(self, x):
self.mask = (x <= 0)
out = x.copy()
out[self.mask] = 0
return out
def backward(self, dout):
dout[self.mask] = 0
dx = dout
return dx
Relu
类有实例变量 mask
。这个变量 mask
是由 True
/ False
构成的 NumPy
数组,它会把正向传播时的输入 x
的元素中小于等于 0 的地方保存为 True
,其他地方(大于0 的元素)保存为 False
。
如下例所示,mask
变量保存了由 True
/ False
构成的 NumPy
数组。
In [3]: x = np.array( [[1.0, -0.5], [-2.0, 3.0]] )
In [4]: x
Out[4]:
array([[ 1. , -0.5],
[-2. , 3. ]])
In [5]: mask = (x<=0)
In [6]: mask
Out[6]:
array([[False, True],
[ True, False]])
In [7]:
如图 5-18 所示,如果正向传播时的输入值小于等于 0,则反向传播的值为 0。因此,反向传播中会使用正向传播时保存的 mask
,将从上游传来的 dout
的mask
中的元素为 True
的地方设为0。
2. Sigmoid 层
sigmoid
函数由式(5.9)表示:
用计算图表示式(5.9)的话,则如图5-19 所示。
exp
节点会进行y = exp(x)
的计算;/
节点会进行 y = 1 x y=\frac{1}{x} y=x1 的计算;
反向传播流程:
/
节点表示 y = 1 x y=\frac{1}{x} y=x1,它的导数可以解析性地表示为下式。
根据式(5.10),反向传播时,会将上游的值乘以−y2(正向传播的输出的平方乘以−1后的值)后,再传给下游。计算图如下所示。
+
节点将上游的值原封不动地传给下游。计算图如下所示。
exp
节点表示y = exp(x)
,它的导数由下式表示。
计算图中,上游的值乘以正向传播时的输出(这个例子中是exp(−x)
)后,再传给下游。
×
节点将正向传播时的值翻转后做乘法运算。因此,这里要乘以 −1。
根据上述内容,图5-20的计算图可以进行Sigmoid
层的反向传播。从图 5-20 的结果可知,反向传播的输出为 ∂ L ∂ y y 2 e x p ( − x ) \frac{\partial L}{\partial y} y^2exp(-x) ∂y∂Ly2exp(−x),这个值会传播给下游的节点。
这里要注意, 这个值 ∂ L ∂ y y 2 e x p ( − x ) \frac{\partial L}{\partial y} y^2exp(-x) ∂y∂Ly2exp(−x) 只根据正向传播时的输入x
和输出y
就可以算出来。
因此,图5-20的计算图可以画成图5-21的集约化的sigmoid
节点。
图5-20 的计算图和简洁版的图5-21 的计算图的计算结果是相同的,但是,简洁版的计算图可以省略反向传播中的计算过程,因此计算效率更高。此外,通过对节点进行集约化,可以不用在意 Sigmoid
层中琐碎的细节,而只需要专注它的输入和输出,这一点也很重要。
另外,
∂
L
∂
y
y
2
e
x
p
(
−
x
)
\frac{\partial L}{\partial y} y^2exp(-x)
∂y∂Ly2exp(−x) 可以进一步整理如下。
因此,图5-21 所表示的 Sigmoid
层的反向传播,只根据正向传播的输出就能计算出来。
用代码实现结果如下:
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
这个实现中,正向传播时将输出保存在了实例变量 out
中。然后,反向传播时,使用该变量 out
进行计算。
参考:《深度学习入门:基于Python的理论与实现》