人工ニューロン (Artificial Neuron)
神経細胞のモデル化
前回記事で扱った生物の神経細胞(ニューロン)の機能になぞらえて、コンピュータ上に「複数の信号を受け取り、適当な重み(荷重)を加えて足し合わせて、活性化関数によって強度を調整して出力する」という関数を設計します。
このようなモデルを人工ニューロン(Artificial Neuron)とよびます。「人工」をつけているのは、もちろん本物のニューロンと区別するためですが、機械学習の分野では単に「ニューロン」とよぶのが一般的です。
説明を簡単にするために、$2$つの信号 $(x_0,x_1)$ が入力される次のような人工ニューロンを考えます。
それぞれの入力信号を重み $w_0,\ w_1$ を掛けて足し合わせ、さらにバイアスパラメータ $w_2$ を加えた値 $u$ を、このニューロンに対する入力総和とよびます。
\[u=w_0x_0+w_1x_1+w_2\]
線形基底関数モデルのときと同じように、常に $1$ の値をとるような疑似信号 $x_2$ を導入して、入力総和を
\[u=w_0x_0+w_1x_1+w_2x_2\]
と書くことにすると、$2$つのベクトル
\[\boldsymbol{w}=\begin{bmatrix}w_0\\w_1\\w_2\end{bmatrix},\quad\boldsymbol{x}=\begin{bmatrix}x_0\\x_1\\x_2\end{bmatrix}\]
の内積を使って、
\[u=\boldsymbol{w}\cdot\boldsymbol{x}\]
と表すことができます。入力総和を活性化関数 $f(x)$ に通すことによって値を調整し、これをニューロンの出力 $y=f(u)$ とします。
\[y=f(u)=f(\boldsymbol{w}\cdot\boldsymbol{x})\]
単体ニューロンの実装
Python で単体の人工ニューロンを実装してみましょう。
活性化関数としてシグモイド関数を採用します。
# Artificial_Neuron # In[1] import numpy as np # シグモイド関数 def sigmoid(x): f = 1 / (1 + np.exp(-x)) return f # 人工ニューロン def neuron(x, w): u = np.dot(x, w) y = sigmoid(u) return y
neuron()関数には信号をいくつでも入力できますが、上にも述べたように、ベクトルの最後の成分はバイアスです。$N$ 個の信号を入力するモデルでは $N+1$ 個のベクトル成分が必要です。とりあえずは信号を $2$ 個にして、neuron() に $\boldsymbol{w}=(2,-1.5,0.2),\ \boldsymbol{x}=(1,2,1)$ を渡してみましょう。
# In[2] # 重みを設定 w = np.array([2, -1.5, 0.2]) # ニューロンへの入力 x = np.array([1, 2, 1]) # ニューロンからの出力 y = neuron(x, w) print(y) # 0.31002551887238755
w や x の値を変えれば、出力は色々な値をとりますが、シグモイド関数を通しているので、必ず $0$ から $1$ の範囲に収まります。
$x_0$-$x_1$ 平面の上に $y=f(u)$ の値をプロットすれば、$x_0$ と $x_1$ の組合わせに応じた出力変化を可視化できます。matplotlib.pyplot と mpl_toolkits.mplot3d をインポートして、3Dグラフを描いてみましょう。
# In[3] import matplotlib.pyplot as plt from mpl_toolkits.mplot3d import Axes3D # 解像度を設定 xn = 33 # x0-x1平面上に格子点を作成 x0 = np.linspace(-1.0, 1.0, xn) x1 = np.linspace(-1.0, 1.0, xn) X0, X1 = np.meshgrid(x0, x1) # x0,x1の重みを1.0,-1.0に設定 # バイアスの重みを0.2に設定 w = np.array([1.0, -1.0, 0.2]) # ニューロンの出力を格納する変数 Z = np.zeros((xn, xn)) # すべての格子点でニューロンからの出力を計算 for i in range(xn): for j in range(xn): Z[j][i] = neuron(w, [i, j, 1]) # FigureとAxesを追加 fig = plt.figure(figsize = (10, 6)) ax = fig.add_subplot(111, projection='3d') # 軸ラベルを設定 ax.set_xlabel("x0", size = 16, labelpad = 10) ax.set_ylabel("x1", size = 16, labelpad = 10) ax.set_zlabel("y", size = 16) # 曲面を描画 ax.plot_surface(X0, X1, Z, color = "green") # 表示角度を設定 ax.view_init(45, 60) plt.show()
これは見覚えのある図ですね。分類問題 で使用した2変数 ロジスティック関数 のグラフです。入力総和 $u$ は $x_0$ と $x_1$ の線形結合なので、それをシグモイド関数に渡せば、$x_0$ と $x_1$ を変数とするロジシティック関数になります。一般に $x_0,\ x_1,\ \cdots,\ x_{N-1}$ の入力があれば $N$変数ロジシティック関数を計算することになります。次回記事では数個のニューロンをつないで小さなニューラルネットワークを作って出力の様子を調べてみます。
コメント
In[3] プロクラムの下の文で、ロジスティック関数のリンク先が「シグモイド関数」の記事に
なっていますので、ご確認ください。
リンクを修正しておきました。
ありがとうございます。m(_ _)m