新着情報
Neural Network Classをインスタント化して手書き数字の訓練データの学習
Neural Newwork Classをインスタンス化して、手書き数字の画像データセットMINSTの訓練データの学習を実施する。
それを行うnn_ecognition.pyのプログラム例を示す。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 | 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の範囲に値を加工する。
1 2 3 4 5 6 | 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データセットの学習の実行
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | 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個を使用して調べた結果を以下に示す。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | # 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[]の可視化を以下により実施した結果
1 2 | result = [ '□' if i = = 1 else '■' for i in score] print (result) |
10,000個も示すことができないので一部だけ表示する。
‘□’は正解、’■’は不正解を示す
[‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘■’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘■’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘■’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’, ‘□’,
正解率の計算は以下の様に実施できる。
1 2 3 4 5 | # 配列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、金城俊哉著