keras_iris_test
python初心者が kerasを使って、定番のiris分類をやった。
前回chainer使って作ってみたので、次はkerasでやってみようということで。
# #とりあえず動くところまで作った iris分類. # import argparse import numpy import keras from keras.layers.core import Dense, Dropout, Activation, Flatten #from keras.layers.convolutional import Convolution2D, MaxPooling2D numpy.random.seed(1192) # for reproducibility #分類した結果が文字列なので [0,1,2] という数字に変換する def iris_name_to_index(s): if s == b'setosa': return 0 #正解データは0からスタートしないとダメ elif s == b'virginica': return 1 elif s == b'versicolor': return 2 else: print("Unknown Data:{}".format(s)) raise() #逆に、数字から、setosa/virginica/versicolor に変換する. def iris_index_to_name(i): if i == 0: return 'setosa' elif i == 1: return 'virginica' elif i == 2: return 'versicolor' else: print("Unknown Label:{}".format(i)) raise() # 引数の処理 parser = argparse.ArgumentParser() parser.add_argument('--mode', type=str, default='all') #train:学習だけ pred:分類だけ all:両方 parser.add_argument('--epoch', type=int, default=500) #何回学習を繰り返すか parser.add_argument('--trainstart',type=int, default=0) #全データ150件のうち、何件から学習に使うか parser.add_argument('--trainsize', type=int, default=50) #全データ150件のうち、何件を学習に使うか ディフォルト(150件中 0件から50件までを学習に使う) parser.add_argument('--trainbatch',type=int, default=50) #学習するミニバッチに一度にかけるデータの個数 args = parser.parse_args() #csv読込 #最初の4つが学習データ 最後の5番目が正解データ csv = numpy.loadtxt("iris.csv", delimiter=",", #csvなので , で、データは区切られている skiprows=1, #ヘッダーを読み飛ばす converters={4:iris_name_to_index} #4カラム目は分類がテキストでかかれているので 0から始まる数字ラベルに置き換える ) #学習データの定義 #学習データは float32の2次元配列 #例: [ [1,2,3,4],[5,6,7,8],[1,2,3,4],[5,6,7,8],[1,2,3,4] ].astype(numpy.float32) data = csv[:,0:4].astype(numpy.float32) #正解データの定義 #正解データは 0から始まる int32の1次元配列 #例: [ 0,1,2,1,0 ].astype(numpy.int32) label= csv[:,4].astype(numpy.int32) #学習 if args.mode in ['all','train']: model = keras.models.Sequential() model.add(Dense(100,input_dim=4)) model.add(Activation('relu')) model.add(Dense(100)) model.add(Activation('relu')) model.add(Dense(3)) model.add(Activation('softmax')) model.compile(loss='sparse_categorical_crossentropy', optimizer='adam', metrics=['accuracy']) x = data[args.trainstart:args.trainstart+args.trainsize] y = label[args.trainstart:args.trainstart+args.trainsize] model.fit(x, y ,batch_size=args.trainbatch,nb_epoch=args.epoch,verbose=1) #学習結果を保存. model.save("model.dat") #分類 if args.mode in ['all','pred']: #学習結果を読み込む model = keras.models.load_model("model.dat") #すべてのデータに対して、1件ずつ、分類を答えさせて、正しいか採点する. #keras組み込みの evaluateメソッドで一発なんだけど、 表示をこりたいので、forを回すよ. #score = model.evaluate(data, label, verbose=1) #print(score) ok_count = 0 for i in range(len(data)): x = data[i:i+1] #このデータについて調べたい. y = model.predict(x, batch_size=1, verbose=0) #分類の結果を取得 pred = numpy.argmax(y) #3つの分類のうち、どれの確率が一番高いのかを返す if label[i] == pred: ok_count = ok_count + 1 #print("OK i:{} pred:{}({}) data:{}".format(i,iris_index_to_name(pred),iris_index_to_name(label[i]),data[i:i+1] )) else: print("NG i:{} pred:{}({}) data:{}".format(i,iris_index_to_name(pred),iris_index_to_name(label[i]),data[i:i+1] )) print("total:{} OK:{} NG:{} rate:{}".format(len(data),ok_count,len(data)-ok_count,ok_count/len(data)) )
ソースコードは githubにある https://github.com/rti7743/keras_iris_test
chainer_iris_testを改変してkeras版を作ったのでデータに対してはそれほど苦労としていない。
また、kerasは Tensorflowとかのラッパーであり、Tensorflowはwindowsインストール方法の解説が公式サイトに書いてあり、それが chainerのGPU対応ビルドと方法がほとんど同じなので、これも苦労しなかった。
Using TensorFlow backend. Traceback (most recent call last): File "test.py", line 85, in <module> model.fit(x, y ,batch_size=args.trainbatch,nb_epoch=args.epoch,verbose=1) File "keras\models.py", line 664, in fit sample_weight=sample_weight) File "keras\engine\training.py", line 1068, in fit batch_size=batch_size) File "keras\engine\training.py", line 985, in _standardize_user_data exception_prefix='model target') File "keras\engine\training.py", line 113, in standardize_input_data str(array.shape)) ValueError: Error when checking model target: expected activation_3 to have shap e (None, 3) but got array with shape (50, 1)
しかし、罠がなかったわけではない。
model.compile時に loss='categorical_crossentropy'を使うと上記エラーが発生して動かなかった。
いろいろ調べてみると、loss='categorical_crossentropy' なのがだめらしい。
sparse_categorical_crossentropyにするとうまく動作する。
#NG #model.compile(loss='categorical_crossentropy', # optimizer='adam', # metrics=['accuracy']) #OK model.compile(loss='sparse_categorical_crossentropy', optimizer='adam', metrics=['accuracy'])
たぶん、正解データの形式の問題かな・・・?
keras.np_utils.to_categoricalとかで用意すれば いいのかも。
まあ、どちらにせよ、loss='sparse_categorical_crossentropy'で動いたので気にしない方向で。
GPU利用については、バックエンドのTensorflowがなんかいい感じにしてくれるので、コードには何も書いていない。
何もしなくていいのは楽でいいと思った。