機器學習入門(12)— 激活函數層 ReLU、Sigmoid 層的實現

1. ReLU 函數層

激活函數 ReLURectified Linear Unit)由下式(5.7)表示。
ReLU層
通過式(5.7),可以求出 y 關於 x 的導數,如式(5.8)所示。
激活函數求導
在式(5.8)中,如果正向傳播時的輸入 x 大於0,則反向傳播會將上游的值原封不動地傳給下游。反過來,如果正向傳播時的 x 小於等於0,則反向傳播中傳給下游的信號將停在此處。用計算圖表示的話,如圖5-18 所示。

ReLU 層計算圖
在神經網絡的層的實現中,一般假定 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)表示:
激活函數公式
用計算圖表示式(5.9)的話,則如圖5-19 所示。
計算圖

  • exp 節點會進行 y = exp(x) 的計算;
  • / 節點會進行 y=1xy=\frac{1}{x} 的計算;

反向傳播流程:

  1. / 節點表示 y=1xy=\frac{1}{x},它的導數可以解析性地表示爲下式。
    式 5.10
    根據式(5.10),反向傳播時,會將上游的值乘以−y2(正向傳播的輸出的平方乘以−1後的值)後,再傳給下游。計算圖如下所示。
    步驟1反向圖
  2. + 節點將上游的值原封不動地傳給下游。計算圖如下所示。
    加法反向圖
  3. exp 節點表示 y = exp(x) ,它的導數由下式表示。
    指數求導
    計算圖中,上游的值乘以正向傳播時的輸出(這個例子中是 exp(−x))後,再傳給下游。
    指數反向圖
  4. × 節點將正向傳播時的值翻轉後做乘法運算。因此,這裏要乘以 −1。
    圖 5.20
    根據上述內容,圖5-20的計算圖可以進行 Sigmoid 層的反向傳播。從圖 5-20 的結果可知,反向傳播的輸出爲 Lyy2exp(x)\frac{\partial L}{\partial y} y^2exp(-x),這個值會傳播給下游的節點。
    這裏要注意, 這個值 Lyy2exp(x)\frac{\partial L}{\partial y} y^2exp(-x) 只根據正向傳播時的輸入 x 和輸出 y 就可以算出來。
    因此,圖5-20的計算圖可以畫成圖5-21的集約化的 sigmoid 節點。

簡潔版
圖5-20 的計算圖和簡潔版的圖5-21 的計算圖的計算結果是相同的,但是,簡潔版的計算圖可以省略反向傳播中的計算過程,因此計算效率更高。此外,通過對節點進行集約化,可以不用在意 Sigmoid 層中瑣碎的細節,而只需要專注它的輸入和輸出,這一點也很重要。

另外, Lyy2exp(x)\frac{\partial L}{\partial y} y^2exp(-x) 可以進一步整理如下。
式 5.12
因此,圖5-21 所表示的 Sigmoid 層的反向傳播,只根據正向傳播的輸出就能計算出來。
圖 5-22
用代碼實現結果如下:

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的理論與實現》

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章