新着情報
Neural Network Classをインスタント化して手書き数字の訓練データの学習
Neural Newwork Classをインスタンス化して、手書き数字の画像データセットMINSTの訓練データの学習を実施する。
それを行うnn_ecognition.pyのプログラム例を示す。
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, # 目標値の配列 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
学習の実行に際し、以下の様に、MINSTデータ・セットを読み込み、0.01から0.99の範囲に値を加工する。
from keras.datasets import mnist (x_trains, y_trains), (x_tests, y_tests) = mnist.load_data() # 60000x28x28の2次元配列を60000×784の行列に変換 x_trains = x_trains.reshape(60000, 784) # データを255で割って0.99を掛けた後、0.01を加えてシフトする x_trains = (x_trains / 255.0 * 0.99) + 0.01
ニューラル・ネットワークによるMINSTデータセットの学習の実行
import time # 学習を行って結果を出力 start = time.time() # プログラムの開始時刻を取得 input_neurons = 784 # 入力層のニューロンの数 hidden_neuronss = 200 # 隠れ層のニューロンの数 output_neurons = 10 # 出力層のニューロンの数 learning_rate = 0.1 # 学習率 # neuralNetworkオブジェクトの生成 n = neuralNetwork(input_neurons, hidden_neuronss, output_neurons, learning_rate) # ニューラルネットワークの学習 # 学習を繰り返す回数 epochs = 5 # 指定した回数だけ学習を繰り返す for e in range(epochs): # 画像データと正解ラベルを順番に取り出してネットワークに入力 for (inputs, target) in zip(x_trains, y_trains): # 出力層のニューロン数に合わせて目標配列を作成 targets = np.zeros(output_neurons) + 0.01 # 正解値に対応する要素を0.99にする targets[int(target)] = 0.99 # 学習を実行 n.train(inputs, # 訓練データの行列 targets # 目標値の行列 ) print('done') # 処理にかかった時間を出力 print("Computation time:{0:.3f} sec".format(time.time() - start))
次に、訓練データを使って学習したニューラル・ネットワークの精度をMINSTデータ・セットのtestsデータ10,000個を使用して調べた結果を以下に示す。
# 10000x28x28の2次元配列を10000×784の行列に変換 x_tests = x_tests.reshape(10000, 784) # データを255で割って0.99を掛けた後、0.01を加えてシフトする x_tests = (x_tests / 255.0 * 0.99) + 0.01 # 正解は1、不正解は0を格納する配列 score = [] # x_testsをinputs、y_testsをcorrect_labelに格納 for (inputs, correct_label) in zip(x_tests, y_tests): # ニューラルネットワークで評価する outputs = n.evaluate(inputs) # 出力層のニューロン数に合わせて正解の配列を作成 targets = np.zeros(output_neurons) + 0.01 # 正解値に対応する要素を0.99にする targets[int(target)] = 0.99 # 出力の行列の最大値のインデックスが予測する手書き数字に対応 label = np.argmax(outputs) # ネットワークの出力と正解ラベルを比較 if (label == correct_label): # 正解ならscoreに1を追加 score.append(1) else: # 不正解なら0を追加 score.append(0)
配列score[]の可視化を以下により実施した結果
result = ['□' if i == 1 else '■' for i in score] print(result)
10,000個も示すことができないので一部だけ表示する。
‘□’は正解、’■’は不正解を示す
[‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘■’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘■’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘■’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’,
正解率の計算は以下の様に実施できる。
# 配列scoreをNumPy配列に変換 score_arry = np.asarray(score) # score_arryの合計をscore_arryの要素数で割って正解率を求める print ("performance = ", score_arry.sum() / score_arry.size)
正解率は約 97.4 % となった。
performance = 0.9737
参考文献に記載されたpythonプログラムを、python 3.5, Tensorflow 1.9.0の環境下で使用してMNISTデータセットの訓練用手書き数字データの学習を実施、テストデータを使用して精度検証をおこなった。
参考文献:
夢見るディープラーニング:ニューラルネットワーク[Python実装]入門
秀和システム、2018、金城俊哉著