2018/02/22
2020/04/14
chainerでニューラルネットワーク簡単実装(初心者向け)
当記事では、chainerというPythonのライブラリを用いることでニューラルネットワークが簡単に実装できることをご紹介したいと思います。初心者向けの記事ということで、一番オーソドックスな普通のニューラルネットワークの実装を目指します。そのまま使えるプログラム(Python3系)をご用意いたしました。当記事では例として、こちらのcsvファイル(→sampleNN.csv)を使います。
以下がデータの形です。
age blood_pressure lung_capacity weight disease 0 23 117 4000 75 1 1 66 139 4100 75 1 2 96 127 3500 99 0 3 65 123 3500 91 1 4 52 127 3800 107 0 5 67 141 3400 107 1
こちらのデータの前の4列(年齢、血圧、肺活量、体重)から5列目(病気)であるかどうかを予測したいと思います。1が病気有りで、0が病気なしです。(データはこちらで独自に作ったものであり、実在するものではありません。)
学習のサンプルプログラム
以下が、chainerによるニューラルネットワークのサンプルプログラムになります。
import pandas as pd import numpy as np import chainer from chainer import training, iterators, optimizers, serializers, Chain import chainer.functions as F import chainer.links as L from chainer.training import extensions from chainer.datasets import tuple_dataset #データの読み込み df = pd.read_csv("sampleNN.csv") #学習したモデルを出力するファイル名 resultFn = "sampleNN.model" #入力層のノードの数 inputNum = len(df.columns)-1 #データの行数を取得 N = len(df) #データの正規化、各列をその列の最大値で割ることで全て0~1の間にする df.iloc[:,:-1] /= df.iloc[:,:-1].max() #学習に関する基本情報の定義 epoch = 400 #学習回数 batch = 1 #バッチサイズ hiddens = [inputNum,800,400,len(df.iloc[:,inputNum].unique())] #各層のノード数 #学習、検証データの割合(単位:割) trainSt = 0 #学習用データの開始位置 0割目から〜 trainPro = 8 #学習用データの終了位置 8割目まで testPro = 10 #検証用データの終了位置 8割目から10割目まで #ニューラルネットワークの構築。 class MyChain(Chain): def __init__(self): super(MyChain, self).__init__( l1=L.Linear(hiddens[0], hiddens[1]), l2=L.Linear(hiddens[1], hiddens[2]), l3=L.Linear(hiddens[2], hiddens[3]), ) def __call__(self, x): h1 = F.sigmoid(self.l1(x)) h2 = F.sigmoid(self.l2(h1)) o = self.l3(h2) return o def learning(): #学習用データと検証用データに分ける train_df= df.iloc[0:int(N*trainPro/10),:] test_df = df.iloc[int(N*trainPro/10):int(N*testPro/10),:] #データの目的変数を落としてnumpy配列にする。 train_data = np.array(train_df.iloc[:, :-1].astype(np.float32)) test_data = np.array(test_df.iloc[:, :-1].astype(np.float32)) #目的変数もnumpy配列にする。 train_target = np.array(train_df.iloc[:,inputNum]).astype(np.int32) test_target = np.array(test_df.iloc[:,inputNum]).astype(np.int32) #ランダムにデータを抽出してバッチ学習する設定 train = tuple_dataset.TupleDataset(train_data, train_target) test = tuple_dataset.TupleDataset(test_data, test_target) train_iter = iterators.SerialIterator(train, batch_size=batch, shuffle=True) test_iter = iterators.SerialIterator(test, batch_size=batch, repeat=False, shuffle=False) #モデルを使う準備。オブジェクトを生成 model = L.Classifier(MyChain()) #最適化手法の設定。今回はAdamを使ったが他にAdaGradやSGDなどがある。 optimizer = optimizers.Adam() optimizer.setup(model) #学習データの割り当てを行う updater = training.StandardUpdater(train_iter, optimizer) #学習回数を設定してtrainerの構築 trainer = training.Trainer(updater, (epoch, 'epoch'), out='result') #trainerの拡張をしておく trainer.extend(extensions.Evaluator(test_iter, model)) #精度の確認 trainer.extend(extensions.LogReport()) #レポートを残す trainer.extend(extensions.PrintReport(['epoch', 'main/accuracy', 'validation/main/accuracy'])) #レポートの内容 trainer.extend(extensions.ProgressBar()) #プログレスバーの表示 trainer.extend(extensions.snapshot(),trigger=(1,'epoch')) #モデルの保存 #学習の実行 trainer.run() #モデルの保存 serializers.save_npz(resultFn, model) if __name__ == "__main__": learning() print("write to " + str(resultFn))
大雑把な説明はコメントアウトしてプログラム内に書いていますが、以下で詳細な説明も加えていきたいと思います。
モデルの設定
まず、クラスMyChain
#ニューラルネットワークの構築。 class MyChain(Chain): def __init__(self): super(MyChain, self).__init__( l1=L.Linear(hiddens[0], hiddens[1]), l2=L.Linear(hiddens[1], hiddens[2]), l3=L.Linear(hiddens[2], hiddens[3]), ) def __call__(self, x): h1 = F.sigmoid(self.l1(x)) h2 = F.sigmoid(self.l2(h1)) o = self.l3(h2) return o
の部分ではニューラルネットワークのノード数や活性化関数の設定を行なっています。今回は入力層、中間層2層、出力層の全4層構成で活性化関数にはシグモイド関数を採用しています。
入力層は今回の場合、説明変数が4つなので4、出力層は2値分類なので2としました。中間層は適当に800,400としています。入力層、出力層の数をデータから自動で取得しているため今回は、ノード数に変数を使っていますが、以下のように書いてるのと同じことです。
class MyChain(Chain): def __init__(self): super(MyChain, self).__init__( l1=L.Linear(4, 800), l2=L.Linear(800, 400), l3=L.Linear(400, 2), )
より深いネットワーク(ディープラーニング)にしたい場合は、ここで層の数を増やしましょう。
学習用データと検証用データに分ける
以下の部分で、学習用データと検証用データに分けています。
#学習用データと検証用データに分ける train_df= df.iloc[0:int(N*trainPro/10),:] test_df = df.iloc[int(N*trainPro/10):int(N*testPro/10),:]
今回は、データの前8割を学習に使い、残りの2割を検証に使っています。この他にランダムに分ける手法などもあります。データを分けることによって、学習の結果と予測の結果を同時に確認できるというメリットがあります。これは過学習防止などに繋がるので分けるのは必須です。
32ビットのnumpy配列に変換
chinerに学習させるときにデータをそのままでは学習ができません。64ビット配列などにも対応していないので、かならず32ビットのnumpy配列に変換して入力しましょう。
学習結果
上記のプログラムを回した結果、以下のようになりました。
最初は、ほとんど変わらず。
epoch main/accuracy validation/main/accuracy 1 0.5625 0.6 2 0.58125 0.6 3 0.6375 0.6 4 0.6 0.6 5 0.6375 0.6 6 0.60625 0.6 7 0.59375 0.6 8 0.63125 0.6 9 0.5875 0.6 10 0.6125 0.6
学習回数100辺りから、徐々に上がり始め、
91 0.69375 0.55 92 0.7125 0.7 93 0.7375 0.575 94 0.675 0.65 95 0.7375 0.775 96 0.69375 0.65 97 0.69375 0.725 98 0.7125 0.7 99 0.73125 0.775 100 0.73125 0.725 101 0.7625 0.675 102 0.75 0.675
400回目付近で98%に。
420 0.9625 0.9 421 0.91875 0.925 422 0.9625 0.9 423 0.94375 0.875 424 0.975 1 425 0.96875 0.975 426 0.96875 0.975 427 0.96875 0.9 428 0.95 0.95 429 0.98125 1 430 0.98125 0.95
学習成功まで、だいぶ学習回数を費やしました、、。ニューラルネットワークの学習の効率はデータや入力の仕方、ネットワークの形などによって変わってきます。その辺の設定を調整すれば、より効率の良い学習を目指すことが出来ます。
分類機を別のデータに適用して予測
学習が済んだモデルは、serializers.save_npz(“ファイル名”, model)で保存することができます。
保存したモデルは、
#学習済みモデルの読み込み serializers.load_npz('sampleNN.model', model)
で取り出すことが出来、model.predictor()で新しい入力データを与えることで予測に使えます。
以下に予測のサンプルプログラムを掲載いたします。
import pandas as pd import numpy as np import chainer from chainer import serializers,Chain import chainer.functions as F import chainer.links as L #モデルの形を設定。こちらは、学習させた時と同じ形にする。 class MyChain(Chain): def __init__(self): super(MyChain, self).__init__( l1=L.Linear(4, 800), l2=L.Linear(800, 400), l3=L.Linear(400, 2), ) def __call__(self, x): h1 = F.sigmoid(self.l1(x)) h2 = F.sigmoid(self.l2(h1)) o = self.l3(h2) return o model = L.Classifier(MyChain()) #学習済みモデルの読み込み serializers.load_npz('sampleNN.model', model) #予測したいデータの読み込み df = pd.read_csv("sampleNN.csv") N = len(df) #データの行数 #データの正規化。学習時におこなったものと同じものを行う。 df.iloc[:,:-1] /= df.iloc[:,:-1].max() #入力データをnumpy配列に変更 data = np.array(df.iloc[:,:-1]).astype(np.float32) #予測後の出力ノードの配列を作成 outputArray = model.predictor(data).data #予測結果の配列を作成 ansArray = np.argmax(outputArray,axis=1) #出力ノードの値のデータフレーム版を作成 outputDF = pd.DataFrame(outputArray,columns=["output_0","output_1"]) #予測結果のデータフレーム版を作成 ansDF = pd.DataFrame(ansArray,columns=["PredictedValue"]) #真の値と、予測結果、出力ノードの値を格納したデータフレームを作成 result = pd.concat([df.disease,ansDF,outputDF],axis=1) #正解数、正答率を表示 correctCount = len(np.where(result.iloc[:,0] == result.iloc[:,1])[0]) correctRate = correctCount/N print("データ数:",N) print("正解数:",correctCount) print("正答率:",correctRate) #結果をcsvファイルへ出力 result.to_csv("samplePredict.csv",index=False)
こちらのプログラムではターミナル上に簡単な正答率を出力して、最終的に真の値と予測値をcsvファイルに出力するというものです。
まとめ
いかがでしたでしょうか。Chainerを使えば比較的直感的な記述で簡単にニューラルネットワークを実装できることがお分かりいただけたかと思います。層を深くして、ディープラーニングにしたい場合はMychainで調整すれば簡単に出来ますし、最適化手法の変更も非常に簡単なので、ニューラルネットワークの実装初心者には非常にオススメです。
もし、掲載してるプログラムで何か分からないことがあればコメントいただければと思います!最後までお読みいただきありがとうございました。
最新投稿記事
-
AIプロジェクトの企画と失敗しない進め方を解説 2021年1月19日
-
AVILEN人材育成コース受講体験談:山田裕之さん「E資格の”その先”を目指して」 2021年1月8日
-
AI導入とは?RPAとの関係、プロセス、事例、メリット、費用を詳細に解説 2020年12月7日
-
注目のAI開発企業11社!支援領域や提供方法など検証! 2020年10月28日
-
AI人材を育成できる研修プログラムを一挙紹介! 2020年10月20日
-
【2021年版】期待のAI資格11選!就職・転職にも使える! 2020年10月18日
-
JDLAとは?G検定、E資格の認定プログラム、合格者の会など紹介! 2020年10月14日
-
G検定(2020#3)受験申し込み開始、11月7日(土)実施-JDLA 2020年10月1日
-
【独占】コロナ禍で人材登録急増、アノテーション単月売上高は4倍超-パソナJOB HUB 2020年10月1日
-
E資格を転職に活用!評判とデータを徹底調査! 2020年9月29日
週間ランキング
【2021年版】コスパ重視のG検定対策!おすすめの本・講座・教材を一挙紹介! 2020年6月6日
G検定に短期間・独学で合格した勉強法を解説! 2020年8月3日
【2021年版】期待のAI資格11選!就職・転職にも使える! 2020年10月18日
G検定は難しい?難易度・合格ライン・問題を徹底解説! 2020年6月19日
注目のAI開発企業11社!支援領域や提供方法など検証! 2020年10月28日
G検定に落ちた人、合格した人。勉強法の違いはどこにある? 2020年6月25日
最弱オセロを初めて攻略した天才オセロ高校生。負け方を解説! 2020年7月31日
【2021年版】E資格とは?大注目のディープラーニングの資格を解説! 2020年9月29日
E資格の難易度を、合格率と問題から徹底分析! 2020年8月11日
MLOpsとは|定義、メリット、課題、ツール、ワークフローを分かりやすく解説 2020年9月18日
