はじめに
「プログラミング」初学者のための『ゼロから作るDeep Learning』攻略ノートです。『ゼロつくシリーズ』学習の補助となるように適宜解説を加えています。本と一緒に読んでください。
関数やクラスとして実装される処理の塊を細かく分解して、1つずつ実行結果を見ながら処理の意図を確認していきます。
この記事は、3.2.7項「ReLU関数」の内容です。ReLU関数をPythonで実装します。
【前節の内容】
【他の節の内容】
【この節の内容】
3.2.7 ReLU関数の実装
ニューラルネットワークの活性化関数として用いられるReLU関数を実装します。
利用するライブラリを読み込みます。
# 3.2.7項で利用するライブラリ import numpy as np import matplotlib.pyplot as plt
・数式の確認
まずは、ReLU関数の定義式を確認します。
ReLU関数は、次の式で定義されます。
ReLU関数$h(x)$の入力$x$が、0より大きければそのまま$x$の値を、0以下であれば0を出力する関数です。
・処理の確認
次に、ReLU関数で行う処理を確認します。
0
または0
以上のx
の値を出力するのは、np.maximum()
を使うと簡単に行えます。
np.maximum()
は、第1引数と第2引数の要素を比較して大きい方の値を返します。np.maximum()
を確認しましょう。
どちらの引数にもスカラを渡してみます。
# スカラ同士で比較 res = np.maximum(6, 10) print(res)
10
大きい方の値を返します。
第1引数にスカラ、第2引数にリストを渡してみます。(NumPy配列を使って確認すべきですが、同じ結果になるので、np.array()
を省略してリストで試しています。)
# スカラとリスト(配列)で比較 res = np.maximum(2, [0, 1, 2, 3, 4, 5]) print(res)
[2 2 2 3 4 5]
リストの各要素とスカラを比較して、大きい方の値を返します。
リストの0番目と1番目の要素0, 1
よりも、スカラ2
の方が大きいので、出力の0番目と1番目の要素が2, 2
になりました。
リストの2番目の要素2
は、スカラ2
と等しいので、出力の2番目の要素も2
になりました。
リストの3から5番目の要素3, 4, 5
の方が、スカラ2
のよりも大きいので、出力の3から5番目の要素が3, 4, 5
になりました。
どちらの引数にもリストを渡してみます。
# リスト(配列)同士で比較 res = np.maximum([-5, 2, 10], [5, 0, 10]) print(res)
[ 5 2 10]
同じインデックスの要素を比較して、大きい方の値を返します。要素数が異なる場合はエラーになります。
では、np.maximum()
を使ってReLU関数の処理を確認します。
入力$\mathbf{x} = (x_0, x_1, \cdots, x_n)$をNumPy配列として作成します。Pythonのインデックスに合わせて、$\mathbf{x}$の添字を0からにしています。
# 仮の入力を指定 x = np.array([-2, -1, 0, 1, 2, 3])
負の値・0・正の値を持つように配列を作成しておくと、うまく処理できているかを確認しやすくなります。
np.maximum()
に、0
とNumPy配列x
を渡します。
# 0以上の値を出力:式(3.7) y = np.maximum(0, x) print(y)
[0 0 0 1 2 3]
x
の各要素と0
を比較して大きい方の値を出力します。つまり、0
以下のx
の要素については0
が、0
以上のx
の要素についてはそのままの値が出力されます。
0
以上の入力x
の値を出力できました。
以上がReLU関数で行う処理です。
・実装
処理の確認ができたので、ReLU関数を関数として実装します。
# RaLU関数の実装 def relu(x): # 0以上の値を出力:式(3.7) return np.maximum(0, x)
実装した関数を試してみましょう。
# ReLU関数による活性化 print(relu(-4.5)) print(relu(0.0)) print(relu(10)) print(relu(np.array([-2, -1, 0, 1, 2, 3])))
0.0
0.0
10
[0 0 0 1 2 3]
この関数で、2次元以上の多次元配列も処理できます。
・グラフの確認
最後に、ReLU関数の入力に対する出力の変化をグラフで確認します。
入力$x$としてグラフに表示する範囲を指定します。np.arange()
の第1引数に最小値、第2引数に最大値、第3引数に分割する間隔を指定します。
# 入力を指定(x軸の値を作成) x = np.arange(-5, 5, 0.1) print(np.round(x, 1))
[-5. -4.9 -4.8 -4.7 -4.6 -4.5 -4.4 -4.3 -4.2 -4.1 -4. -3.9 -3.8 -3.7
-3.6 -3.5 -3.4 -3.3 -3.2 -3.1 -3. -2.9 -2.8 -2.7 -2.6 -2.5 -2.4 -2.3
-2.2 -2.1 -2. -1.9 -1.8 -1.7 -1.6 -1.5 -1.4 -1.3 -1.2 -1.1 -1. -0.9
-0.8 -0.7 -0.6 -0.5 -0.4 -0.3 -0.2 -0.1 -0. 0.1 0.2 0.3 0.4 0.5
0.6 0.7 0.8 0.9 1. 1.1 1.2 1.3 1.4 1.5 1.6 1.7 1.8 1.9
2. 2.1 2.2 2.3 2.4 2.5 2.6 2.7 2.8 2.9 3. 3.1 3.2 3.3
3.4 3.5 3.6 3.7 3.8 3.9 4. 4.1 4.2 4.3 4.4 4.5 4.6 4.7
4.8 4.9]
この例では、-5
から5
まで(正確には未満)を範囲として、0.1
間隔で要素を作成します。
x
をrelu()
に入力して、出力をy
とします。
# ReLU関数による活性化(y軸の値を計算) y = relu(x) print(y)
[0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.1 0.2 0.3
0.4 0.5 0.6 0.7 0.8 0.9 1. 1.1 1.2 1.3 1.4 1.5 1.6 1.7 1.8 1.9 2. 2.1
2.2 2.3 2.4 2.5 2.6 2.7 2.8 2.9 3. 3.1 3.2 3.3 3.4 3.5 3.6 3.7 3.8 3.9
4. 4.1 4.2 4.3 4.4 4.5 4.6 4.7 4.8 4.9]
x
の値が0
以下の場合はy
の値が0
になり、x
の値が0
以上の場合はx
の値がそのままy
の値になっています。
matplotlib
ライブラリのpyplot
モジュールを利用して、ReLU関数のグラフを作成します。
# ReLU関数を作図 plt.figure(figsize=(8, 6)) # 図の設定:(サイズを指定) plt.plot(x, y) # 折れ線グラフ plt.title('ReLU Function', fontsize=20) # タイトル plt.xlabel('x') # x軸ラベル plt.ylabel('y') # y軸ラベル plt.grid() # グリッド線 plt.show() # グラフを表示
$x \leq 0$の範囲では$y = 0$で一定で、$x \geq 0$の範囲では$y = x$の直線になっています。ただし、全体では非線形のグラフになっているのが分かります。
以上で、ReLU関数を実装できました。次項では、これまでに実装した3つの活性化関数を簡単に比較します。この本では、終盤以降で活性化関数として使います。
参考文献
おわりに
加筆修正の際に記事を分割しました。
【次節の内容】