新着情報

Neural Network Classのインスタント化

pythonによるNeuralNetworkをクラスで実装する:

実装するpythonのNeuralNetwork classは入力層(第0層)、隠れ層(第1層)、出力層(第2層)から成る2層構造のNeuralNetworkを考える。

Fig.1 2層のneural network.

ニューラル・ネットワークをNeuralNetwork classによって実装することにする。NeuralNetworkの実現には

ネットワークの作成、重みの更新、ネットワークへの照会という異なる処理が必要となる。まず、

class NeuralNetwork:

def _ _init_ _( ): コンストラクタ(初期化)・メソッド

ここで、入力層、隠れ層、出力層のneuronの数と学習率をインスタンス変数に代入し、ニューラル・ネットワークの  初期化をする。

def weight_initialize( ): 重みの初期化をするメソッド。

def activation_function( ): シグモイド関数を実装するメソッド。

def train( ):訓練データを読み込み、最適な重みを計算するメソッド。

def evaluate( ): 更新された重みを用いてテストデータを評価するメソッド。

import numpy as np
class neuralNetwork:    
    
    # ニューラルネットワークの初期化
    def __init__(self,
                 input_neurons,  # 入力層のニューロン数
                 hidden_neurons, # 隠れ層のニューロン数
                 output_neurons, # 出力層のニューロン数
                 learning_rate   # 学習率
                ):
        # 入力層、隠れ層、出力層のニューロン数をインスタンス変数に代入
        self.inneurons = input_neurons     # 入力層のニューロン数
        self.hneurons = hidden_neurons     # 隠れ層のニューロン数
        self.oneurons = output_neurons     # 出力層のニューロン数
        # 学習率をインスタンス変数に代入
        self.lr = learning_rate
        # weight_initialize()を呼ぶ
        self.weight_initialize()

    # 重みの初期化を行う
    def weight_initialize(self):
        # 入力層と隠れ層の間のリンクの重みの初期値を設定
        self.w_h = np.random.normal(0.0,                       # 平均は0
                                    pow(self.inneurons, -0.5), # 標準偏差は入力層のニューロン数を元に計算
                                    (self.hneurons,            # 隠れ層のニューロン数を行数
                                     self.inneurons + 1)       # バイアスを加え、列数とする
                                    )
       # 隠れ層と出力層の間のリンクの重みの初期値を設定
        self.w_o = np.random.normal(0.0,                       # 平均は0
                                    pow(self.hneurons, -0.5),  # 標準偏差は隠れ層のニューロン数を元に計算
                                    (self.oneurons,            # 出力層のニューロン数を行数
                                                               # 隠れ層のニューロン数に
                                     self.hneurons + 1)        # バイアスを加え、列数とする
                                   )
    
    # シグモイド関数を活性化関数として定義
    def activation_function(self, x):
        return 1 / (1 + np.exp(-x))

    # ニューラルネットワークの学習を行うメソッド
    def train(self,
              inputs_list,  # 入力値の配列
              targets_list  # 目標出力の配列
             ):
        # 入力値の配列にバイアス項を追加して1列の行列に変換
        inputs = np.array(
            np.append(inputs_list, [1]),     # 配列の末尾にバイアスのための値「1」を追加
            ndmin=2                          # 2次元化
        ).T                                  # 転置して1列の行列にする
        
        # 目標値の配列を1列の行列に変換する
        targets = np.array(targets_list,     # 目標値の配列
                           ndmin=2           # 2次元化
                          ).T                # 転置して1列の行列にする
        
        # 隠れ層への入力信号を計算
        hidden_inputs = np.dot(self.w_h,     # 入力層と隠れ層の間の重み
                               inputs        # 入力値の行列
                              )

        # 活性化関数を適用して隠れ層から出力する
        hidden_outputs = self.activation_function(hidden_inputs)
        
        # 隠れ層の出力行列の末尾にバイアスの値として1を追加
        hidden_outputs = np.append(hidden_outputs,     # 隠れ層の出力行列
                                   [[1]],    # 2次元形式でバイアス値を追加
                                   axis=0    # 行を指定(列は1)
                                  )        
        # 出力層への入力信号を計算
        final_inputs = np.dot(self.w_o,      # 隠れ層と出力層の間の重み
                              hidden_outputs # 隠れ層の出力
                              )

        # 活性化関数を適用して出力層から出力する
        final_outputs = self.activation_function(final_inputs)
        
        # 目標値と出力層の出力信号の誤差を求める
        output_errors = targets - final_outputs
        # 誤差逆伝播により隠れ層の誤差を求める
        hidden_errors = np.dot(self.w_o.T,   # 隠れ層と出力層の間の重み行列を転置する
                               output_errors # 出力値と目標値との誤差
                              ) 
        # 隠れ層と出力層の間の重みの更新
        self.w_o += self.lr * np.dot(
            # 出力誤差*出力信号* (1-出力信号)
            (output_errors * final_outputs * (1.0 - final_outputs)),
            # 出力信号の行列を転置
            np.transpose(hidden_outputs)
        )
        
        # 隠れ層の出力エラーからバイアスのものを取り除く
        hidden_errors_nobias = np.delete(
            hidden_errors,  # 隠れ層の出力エラーの行列
            self.hneurons,  # バイアスを除くニューロン数をインデックスにする
            axis=0          # 行の削除を指定
            )
        # 隠れ層の出力からバイアスを取り除く
        hidden_outputs_nobias = np.delete(
            hidden_outputs, # 隠れ層の出力の行列
            self.hneurons,  # バイアスを除くニューロン数をインデックスにする
            axis=0          # 行の削除を指定
            )

        # 入力層と隠れ層の間の重みの更新
        self.w_h += self.lr * np.dot(
            # 隠れ層の出力誤差*隠れ層の出力* (1-隠れ層の出力)
            (hidden_errors_nobias * hidden_outputs_nobias * (
                1.0 - hidden_outputs_nobias)),
            # 入力層の出力信号の行列を転置
            np.transpose(inputs))
   
    # 学習結果を元にテストデータを評価するメソッド
    def evaluate(self,
                 inputs_list                 # テスト用データの配列
                ):
        # テスト用データの配列を1列の行列に変換する
        inputs = np.array(
            np.append(inputs_list, [1]),     # 配列の末尾にバイアスの値「1」を追加
            ndmin=2                          # 2次元化
        ).T                                  # 転置して1列の行列にする
        
        # 隠れ層への入力信号を計算
        hidden_inputs = np.dot(self.w_h,     # 入力層と隠れ層の間の重み
                               inputs        # テストデータの行列
                              )
        
        # 活性化関数を適用して隠れ層から出力する
        hidden_outputs = self.activation_function(hidden_inputs)
        
        # 出力層への入力信号を計算
        final_inputs = np.dot(
            self.w_o,                        # 隠れ層と出力層の間の重み
            np.append(hidden_outputs, [1]),  # 隠れ層の出力配列の末尾にバイアスの値「1」を追加
            )
        
        # 活性化関数を適用して出力層から出力する
        final_outputs = self.activation_function(final_inputs)
        
        # 出力層からの出力を戻り値として返す
        return final_outputs

neuralNetworkクラスをインスタンス化して、train()メソッドで手書き数字の訓練データの学習を行う。

コメント投稿フォーム

メールアドレスが公開されることはありません。 が付いている欄は必須項目です