机器学习入门(12)— 激活函数层 ReLU、Sigmoid 层的实现

1. ReLU 函数层

激活函数 ReLURectified Linear Unit)由下式(5.7)表示。
机器学习入门(12)— 激活函数层 ReLU、Sigmoid 层的实现_第1张图片
通过式(5.7),可以求出 y 关于 x 的导数,如式(5.8)所示。
机器学习入门(12)— 激活函数层 ReLU、Sigmoid 层的实现_第2张图片
在式(5.8)中,如果正向传播时的输入 x 大于0,则反向传播会将上游的值原封不动地传给下游。反过来,如果正向传播时的 x 小于等于0,则反向传播中传给下游的信号将停在此处。用计算图表示的话,如图5-18 所示。

机器学习入门(12)— 激活函数层 ReLU、Sigmoid 层的实现_第3张图片
在神经网络的层的实现中,一般假定 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 ,将从上游传来的 doutmask 中的元素为 True 的地方设为0。

2. Sigmoid 层

sigmoid 函数由式(5.9)表示:
机器学习入门(12)— 激活函数层 ReLU、Sigmoid 层的实现_第4张图片
用计算图表示式(5.9)的话,则如图5-19 所示。
机器学习入门(12)— 激活函数层 ReLU、Sigmoid 层的实现_第5张图片

  • exp 节点会进行 y = exp(x) 的计算;
  • / 节点会进行 y = 1 x y=\frac{1}{x} y=x1 的计算;

反向传播流程:

  1. / 节点表示 y = 1 x y=\frac{1}{x} y=x1,它的导数可以解析性地表示为下式。
    机器学习入门(12)— 激活函数层 ReLU、Sigmoid 层的实现_第6张图片
    根据式(5.10),反向传播时,会将上游的值乘以−y2(正向传播的输出的平方乘以−1后的值)后,再传给下游。计算图如下所示。
    机器学习入门(12)— 激活函数层 ReLU、Sigmoid 层的实现_第7张图片
  2. + 节点将上游的值原封不动地传给下游。计算图如下所示。
    机器学习入门(12)— 激活函数层 ReLU、Sigmoid 层的实现_第8张图片
  3. exp 节点表示 y = exp(x) ,它的导数由下式表示。
    机器学习入门(12)— 激活函数层 ReLU、Sigmoid 层的实现_第9张图片
    计算图中,上游的值乘以正向传播时的输出(这个例子中是 exp(−x))后,再传给下游。
    机器学习入门(12)— 激活函数层 ReLU、Sigmoid 层的实现_第10张图片
  4. × 节点将正向传播时的值翻转后做乘法运算。因此,这里要乘以 −1。
    机器学习入门(12)— 激活函数层 ReLU、Sigmoid 层的实现_第11张图片
    根据上述内容,图5-20的计算图可以进行 Sigmoid 层的反向传播。从图 5-20 的结果可知,反向传播的输出为 ∂ L ∂ y y 2 e x p ( − x ) \frac{\partial L}{\partial y} y^2exp(-x) yLy2exp(x),这个值会传播给下游的节点。
    这里要注意, 这个值 ∂ L ∂ y y 2 e x p ( − x ) \frac{\partial L}{\partial y} y^2exp(-x) yLy2exp(x) 只根据正向传播时的输入 x 和输出 y 就可以算出来。
    因此,图5-20的计算图可以画成图5-21的集约化的 sigmoid 节点。

机器学习入门(12)— 激活函数层 ReLU、Sigmoid 层的实现_第12张图片
图5-20 的计算图和简洁版的图5-21 的计算图的计算结果是相同的,但是,简洁版的计算图可以省略反向传播中的计算过程,因此计算效率更高。此外,通过对节点进行集约化,可以不用在意 Sigmoid 层中琐碎的细节,而只需要专注它的输入和输出,这一点也很重要。

另外, ∂ L ∂ y y 2 e x p ( − x ) \frac{\partial L}{\partial y} y^2exp(-x) yLy2exp(x) 可以进一步整理如下。
机器学习入门(12)— 激活函数层 ReLU、Sigmoid 层的实现_第13张图片
因此,图5-21 所表示的 Sigmoid 层的反向传播,只根据正向传播的输出就能计算出来。
机器学习入门(12)— 激活函数层 ReLU、Sigmoid 层的实现_第14张图片
用代码实现结果如下:

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的理论与实现》

你可能感兴趣的:(Machine,Learning)