新着情報
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、金城俊哉著