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)
的計算;/
節點會進行 的計算;
反向傳播流程:
/
節點表示 ,它的導數可以解析性地表示爲下式。
根據式(5.10),反向傳播時,會將上游的值乘以−y2(正向傳播的輸出的平方乘以−1後的值)後,再傳給下游。計算圖如下所示。
+
節點將上游的值原封不動地傳給下游。計算圖如下所示。
exp
節點表示y = exp(x)
,它的導數由下式表示。
計算圖中,上游的值乘以正向傳播時的輸出(這個例子中是exp(−x)
)後,再傳給下游。
×
節點將正向傳播時的值翻轉後做乘法運算。因此,這裏要乘以 −1。
根據上述內容,圖5-20的計算圖可以進行Sigmoid
層的反向傳播。從圖 5-20 的結果可知,反向傳播的輸出爲 ,這個值會傳播給下游的節點。
這裏要注意, 這個值 只根據正向傳播時的輸入x
和輸出y
就可以算出來。
因此,圖5-20的計算圖可以畫成圖5-21的集約化的sigmoid
節點。
圖5-20 的計算圖和簡潔版的圖5-21 的計算圖的計算結果是相同的,但是,簡潔版的計算圖可以省略反向傳播中的計算過程,因此計算效率更高。此外,通過對節點進行集約化,可以不用在意 Sigmoid
層中瑣碎的細節,而只需要專注它的輸入和輸出,這一點也很重要。
另外, 可以進一步整理如下。
因此,圖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的理論與實現》