からっぽのしょこ

読んだら書く!書いたら読む!同じ事は二度調べ(たく)ない

3.1:パーセプトロンからニューラルネットワークへ【ゼロつく1のノート(実装)】

はじめに

 「プログラミング」学習初手『ゼロから作るDeep Learning』民のための実装攻略ノートです。『ゼロつく1』学習の補助となるように適宜解説を加えています。本と一緒に読んでください。

 関数やクラスとして実装される処理の塊を細かく分解して、1つずつ処理を確認しながらゆっくりと組んでいきます。

 この記事は、3.1節「パーセプトロンからニューラルネットワークへ」と3.2.5項「シグモイド関数とステップ関数の比較」の内容です。活性化関数について確認します。

【前節の内容】

www.anarchive-beta.com

【他の節の内容】

www.anarchive-beta.com

【この節の内容】

3.1 パーセプトロンからニューラルネットワークへ

 2章では、パーセプトロンを次の式で表しました。

$$ y = \begin{cases} 0 \quad (w_1 x_1 + w_2 x_2 + b \leq 0) \\ 1 \quad (w_1 x_1 + w_2 x_2 + b > 0) \end{cases} \tag{3.1} $$

 この式を、重み付き和の計算

$$ a = w_1 x_1 + w_2 x_2 + b \tag{3.4} $$

と、出力に関する計算

$$ y = h(a) \tag{3.5} $$

に分解します。
 $h(a)$は、重み付き和$a$を出力$y$に変換する関数で、パーセプトロン(3.1)の場合は次の式になります。

$$ h(a) = \begin{cases} 0 \quad (a \leq 0) \\ 1 \quad (a > 0) \end{cases} \tag{3.3} $$

 この関数はステップ関数と言い、関数の入力(パーセプトロンだと重み付き和)が0以下のとき0を、0より大きいとき1を出力します。

 この関数のように、重み付き和に非線形な変換(活性化)を行う関数を活性化関数と言います。ニューラルネットワークでは、非線形関数である活性化関数を用いる必要があります。

3.2 活性化関数

 活性化関数として用いられる3つの関数ステップ関数・シグモイド関数・ReLU関数を実装します。

 各関数の実装は、次の記事を参照してください。

www.anarchive-beta.com

www.anarchive-beta.com

www.anarchive-beta.com


3.2.5 活性化関数の比較

 この節で実装した3つの活性化関数(ステップ関数・シグモイド関数・ReLU関数)を簡単に比較します。

 利用するライブラリを読み込みます。

# 3.2.7項で利用するライブラリ
import numpy as np
import matplotlib.pyplot as plt

 また、3.2節で実装したstep_function()sigmoid()relu()の関数定義を実行している必要があります。

 まずは、ステップ関数とシグモイド関数のグラフを比較します。

 作図に用いる入力$x$の値を作成します。

# 入力を指定(x軸の値を作成)
x = np.arange(-10, 10, 0.1)
print(np.round(x[50:150], 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]

 この例では、-10から10まで(正確には未満)を範囲として、0.1間隔で要素を作成します。

 ステップ関数step_function()とシグモイド関数sigmoid()xを入力して、それぞれの出力を計算します。

# ステップ関数の計算
y_step = step_function(x)
print(y_step[50:150])

# シグモイド関数の計算
y_sigmoid = sigmoid(x)
print(np.round(y_sigmoid[50:150], 2))
[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 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1]
[0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.02 0.02 0.02 0.02 0.02
 0.03 0.03 0.03 0.04 0.04 0.04 0.05 0.05 0.06 0.06 0.07 0.08 0.08 0.09
 0.1  0.11 0.12 0.13 0.14 0.15 0.17 0.18 0.2  0.21 0.23 0.25 0.27 0.29
 0.31 0.33 0.35 0.38 0.4  0.43 0.45 0.48 0.5  0.52 0.55 0.57 0.6  0.62
 0.65 0.67 0.69 0.71 0.73 0.75 0.77 0.79 0.8  0.82 0.83 0.85 0.86 0.87
 0.88 0.89 0.9  0.91 0.92 0.92 0.93 0.94 0.94 0.95 0.95 0.96 0.96 0.96
 0.97 0.97 0.97 0.98 0.98 0.98 0.98 0.98 0.99 0.99 0.99 0.99 0.99 0.99
 0.99 0.99]

 ステップ関数の出力をy_step、シグモイド関数の出力をy_sigmoidとします。

 ステップ関数とシグモイド関数のグラフを重ねて表示します。

# 作図
plt.figure(figsize=(8, 6)) # 図の設定:(サイズを指定)
plt.plot(x, y_step, label='step') # ステップ関数
plt.plot(x, y_sigmoid, label='sigmoid') # シグモイド関数
plt.title('Activait Function', fontsize=20) # タイトル
plt.xlabel('x') # x軸ラベル
plt.ylabel('y') # y軸ラベル
plt.grid() # グリッド線
plt.legend() # 凡例
plt.show() # グラフを表示

f:id:anemptyarchive:20210724024528p:plain
ステップ関数とシグモイド関数

 どちらの関数も、0から1の値を出力するのを確認できます。しかし、0から1への変化の仕方が大きく違いますね。滑らかな曲線であるということは、連続的な値を出力する(表現できる)ことを意味します。また、どの点においても傾きを持つことも意味します。

 ただし、シグモイド関数の出力は0にも1にも達していません。グラフに表示する範囲を狭めて確認しましょう。

・ほとんど同じなので省略(クリックで展開)

# 作図
plt.figure(figsize=(8, 6)) # 図の設定:(サイズを指定)
plt.plot(x, y_step, label='step') # ステップ関数
plt.plot(x, y_sigmoid, label='sigmoid') # シグモイド関数
plt.title('Activait Function', fontsize=20) # タイトル
plt.xlabel('x') # x軸ラベル
plt.ylabel('y') # y軸ラベル
plt.grid() # グリッド線
plt.legend() # 凡例
plt.xlim(5, 11) # x軸の表示範囲
plt.ylim(0.999, 1.001) # y軸の表示範囲
plt.show() # グラフを表示

f:id:anemptyarchive:20210724024622p:plain
ステップ関数とシグモイド関数

 $x$が大きくなるに従って、シグモイド関数の出力が1に漸近しているのが分かります。逆に、$x$が小さくなるに従って、0に漸近します。このことも含めて、滑らかな関数と言えます。

 同様に、ReLU関数のグラフも重ねて確認しましょう。

# 入力を指定(x軸の値を作成)
x = np.arange(-5, 5, 0.01)

# 活性化(y軸の値を計算)
y_step = step_function(x)
y_sigmoid = sigmoid(x)
y_relu = relu(x)
# 作図
plt.figure(figsize=(8, 6)) # サイズ
plt.plot(x, y_step, label='step') # ステップ関数
plt.plot(x, y_sigmoid, label='sigmoid') # シグモイド関数
plt.plot(x, y_relu, label='ReLU') # ReLU関数
plt.title('Activation Function', fontsize=20) # タイトル
plt.xlabel('x') # x軸ラベル
plt.ylabel('y') # y軸ラベル
plt.grid() # グリッド線
plt.legend() # 凡例
plt.ylim(-0.1, 1.5) # y軸の表示範囲
plt.show() # グラフを表示

f:id:anemptyarchive:20210724024638p:plain
活性化関数

 ReLU関数も$x > 0$の範囲で傾きを持ちます。傾きがあることが学習において重要になります。ステップ関数は傾きがないため、ニューラルネットワークでは用いられません。詳しくは4章で扱います。

 3.2節では、活性化関数について確認しました。次節では、ニューラルネットワーク(重み付き和の計算)について確認します。ニューラルネットワークの出力が、活性化関数の入力になります。

参考文献

  • 斎藤康毅『ゼロから作るDeep Learning』オライリー・ジャパン,2016年.

おわりに

 この記事で『ゼロつく1』シリーズ3記事(3日)目です。明日の更新は、記事中にURLを張ってある指数関数(とネイピア数)を簡単に確認する記事です。投稿日に読んでいただいた方、まだないリンクを張っててすみません。下の【次節の内容】には3.4節の記事を設定しているのですが、明々後日に投稿されます!明後日は、3.4節に関連する内容の記事が更新されます。その記事は3.4節の記事内にリンクが張ってあります。(もう関係ない)

 意図的に全ての記事が一直線に繋がらないようにしているので、最初の方にある記事一覧ページも是非確認してください!

 ぐだぐだはしてません。まだ順調です。次もよろしくお願いします。

  • 2021.07.23:加筆修正しました。その際に、活性化関数ごとに記事を分割しました。

 3記事分の内容を分割したら随分短くなった。でも文量的にも内容的にもこれくらいのサイズが読みやすいかな?

【次節の内容】

www.anarchive-beta.com