Output_layer_cクラス
バックプロパゲーション機能 を持つ ニューラルネットワーク の実装を始めます。
今回は 出力層 をインスタンスとして生成する Output_layer_c クラスを設計します (Python におけるクラスの設計の基本についてはこちらの記事を参照してください)。末尾に添えた _c は classify (分類) 用の出力層であることを意味します。以下に Output_layer_cクラスが備えておくべき機能をまとめておきます。
基本機能
・重みの初期値を生成してデータを保持しておく。
順伝播 (Forward Propagation)
・上の層から入力信号を受け取る。
・正解値信号を受け取る。
・入力信号に重みをつけて入力総和を計算する。
・入力総和をソフトマックス関数に通して出力する。
逆伝播 (Back Propagation)
・出力値と正解値の誤差 $\delta_j$ を計算する。
・平均交差エントロピー誤差を計算する。
・$\delta_j$ の線形和を上の層へ出力する(逆伝播信号)。
・重みパラメータを修正する。
Output_layer_c クラスのコードです。
# Output_classify # In[1] import numpy as np # ソフトマックス関数 def softmax(x): f = np.exp(x) / np.sum(np.exp(x), axis=1, keepdims=True) return f # 平均交差エントロピー誤差関数 def cross_entropy(y, t): ce = - np.sum(t * np.log(y + 1e-8)) / y.shape[0] return ce class Output_layer_c: def __init__(self, n_upper, n): self.w = np.random.normal(0, 0.05, (n, n_upper + 1)) self.w2 = np.delete(self.w, -1, 1) def activate(self, y_in, t): self.t = t dummy = np.ones((y_in.shape[0], 1)) # 疑似信号を作成 y_in = np.append(y_in, dummy, axis = 1) # 入力信号に疑似信号を追加 u = np.dot(y_in, self.w.T) # 入力総和を計算 self.y_out = softmax(u) # 入力総和をソフトマックス関数に通して出力 self.delta = self.y_out - self.t # 出力値と正解値の誤差を計算 self.ce = cross_entropy(self.y_out, self.t) # 交差エントロピー誤差 self.y_back = np.dot(self.delta, self.w2) # 逆伝播信号を出力 self.w -= alpha * np.dot(self.delta.T, y_in) # 重みの更新 self.w2 = np.delete(self.w, -1, 1) def forward(self, y_in): dummy = np.ones((y_in.shape[0], 1)) # 疑似信号を作成 y_in = np.append(y_in, dummy, axis=1) # 入力信号に疑似信号を追加 u = np.dot(y_in, self.w.T) # 入力総和を計算 self.y_out = softmax(u) # 入力総和をソフトマックス関数に通して出力
Output_layer_c クラスのインスタンスは、上層のニューロン数と自身のもつニューロン数を引数に受け取って生成されます。インスタンスが生成されると、自動的に平均 0、標準偏差 0.05 の正規分布を使って重みを初期設定します。
activate()メソッドを使用すると(信号を入力して層を活性化させると)、一斉に計算が実行されて、オブジェクトに新しいデータ属性が付与されるとともに、重みの値が書き換えられます。
forward() は受け取った信号を出力するだけのメソッドで、重みの更新などは行われません。このメソッドが学習過程で使用されることはありませんが、学習済みのネットワークに新しいデータを入れて出力を確認するときなどに使います。
実際に出力層 (Output_layer_c クラスのインスタンス) を作成し、テスト信号を入力して動作を確認してみましょう。出力層は 2 個、1つ上の中間層は 3 個のニューロンで構成されるものとします。バッチサイズ は 2 です。
# In[2] # 出力層の動作テスト # 乱数を初期化 np.random.seed(10) # 学習率を設定 alpha = 0.01 # テスト信号 test_y = np.array([[3, 2, 5], [2, 1, 4]]) test_t = np.array([[0, 1], [1, 0]]) # 出力層を作成 out_layer = Output_layer_c(3, 2) # 重みの初期値を表示 print("重みの初期値:\n{}\n".format(out_layer.w)) # 出力層にテスト信号を入力 out_layer.activate(test_y, test_t) # 誤差を表示 print("誤差:\n{}\n".format(out_layer.delta)) # 交差エントロピー誤差を表示 print("交差エントロピー誤差:\n{}\n".format(out_layer.ce)) # 逆伝播信号を表示 print("逆伝播信号:\n{}\n".format(out_layer.y_back)) # 更新された重みを表示 print("更新された重み:\n{}".format(out_layer.w)) ''' 重みの初期値: [[ 0.06657933 0.03576395 -0.07727001 -0.00041919] [ 0.0310668 -0.03600428 0.01327558 0.00542743]] 誤差: [[ 0.44806288 -0.44806288] [-0.55607208 0.55607208]] 交差エントロピー誤差: 0.7032070887102677 逆伝播信号: [[ 0.01591184 0.03215668 -0.04057012] [-0.01974752 -0.03990831 0.05034988]] 更新された重み: [[ 0.06425888 0.03236341 -0.07743028 0.0006609 ] [ 0.03338724 -0.03260374 0.01343584 0.00434733]] '''
平均交差エントロピー誤差の値そのものは、バックプロパゲーションで直接使用するものではありませんが、ネットワークの学習効率などを検証するときに必要なので属性に組み込んであります。
コメント
本記事のコードIn[1]をChatGPTに解読させてみました。
[ChatGPT] このコードは、ニューラルネットワークの出力層を定義し、学習と予測の機能を持つ単純な多クラス分類モデルを表しています。以下はコードの主要な部分の説明です。
softmax 関数:softmax 関数は、与えられた入力ベクトル x に対してソフトマックス関数を適用するための関数です。ソフトマックス関数は、各要素の指数関数を計算し、それらの合計で各要素を割ることで、確率分布を生成します。
cross_entropy 関数:cross_entropy 関数は、ネットワークの出力 y と正解ラベル t を使用して、クロスエントロピー誤差を計算する関数です。
クロスエントロピー誤差は、モデルの出力と正解ラベルとの差を評価するための一般的な誤差関数です。
Output_layer_c クラス:Output_layer_c クラスは、出力層を表すクラスで、多クラス分類タスクを扱います。クラスのコンストラクタ __init__ は、出力層の重み行列 w を初期化し、その一部を w2 として切り取ります。activate メソッドは、学習時に呼び出され、与えられた入力 y_in に対して活性化を行い、誤差を計算します。forward メソッドは、予測時に呼び出され、入力 y_in に対して活性化を行います。
このコードは、ニューラルネットワークの出力層を構築し、クロスエントロピー誤差を使用して学習を行うためのクラスを提供します。この出力層は多クラス分類のタスクに特化しており、ソフトマックス関数を使用して確率分布を生成し、クロスエントロピー誤差を最小化するように学習を行います。