KerasでIrisのデータセットを分類し、モデルを保存する
目次
イントロダクション
以前まで、Tensorflowを使っていましたが、 モデルを構築することが簡単 だったので、Kerasに乗り換えてみました。
今回は、非常に簡単な問題であるアヤメデータセットの分類を多層パーセプトロンで学習、予測してみます。
計算機環境
- OS : Ubuntu 16.04
- CPU : core i7 (第7世代)
- RAM : 16GB
- Python 3.5.5, Keras 2.2.0 (バックエンドはTensorflow 1.9.0)
(どうでもいいですが、エディターもAtomからVSCodeに乗り換えました)
データのロード
scikit-learnがあれば、簡単にデータをロードできます。
from sklearn.datasets import load_iris iris = load_iris() print(iris.data) # xデータ print(iris.feature_names) # 変数の説明 print(iris.target) # yデータ print(iris.target_names) # 変数の説明
結果 :
[[5.1 3.5 1.4 0.2] [4.9 3. 1.4 0.2] [4.7 3.2 1.3 0.2] ... [6.5 3. 5.2 2. ] [6.2 3.4 5.4 2.3] [5.9 3. 5.1 1.8]] ['sepal length (cm)', 'sepal width (cm)', 'petal length (cm)', 'petal width (cm)'] [0 0 0 0 0 0 0 ... 2 2 2 2 2 2 2] ['setosa' 'versicolor' 'virginica']
ちなみに、データの型はnumpy配列です。
print(type(iris.data)) print(type(iris.target))
結果 :
<class 'numpy.ndarray'> <class 'numpy.ndarray'>
データ処理
分類問題なので、one-hotエンコーディングを実装します。
kerasにはnp_utilsという関数があるので、それを使います。
これは、int変数をone-hotエンコーディングで使われる配列形式に変換できます。
Irisデータセットでは、3種類の花に分類するので、[0, 0, 1], [0, 1, 0], [1, 0, 0]のいずれかに変換することになります。
from keras.utils import np_utils data_y = np_utils.to_categorical(iris.target)
次に、データセットを訓練データとテストデータに分離させます。
これには、scikit-learnのtrain_test_splitを使います。
ここで、引数のtest_sizeはデータ全体から見たテストデータの割合、random_stateはランダムシードの設定を示しています。
つまり、test_size=0.3は (訓練データ数):(テストデータ)=7:3 を意味します。
通常、random_stateは設定しませんが、今回は設定してみます。
from sklearn.model_selection import train_test_split data_X = iris.data data_y = np_utils.to_categorical(iris.target) X_train, X_test, y_train, y_test = train_test_split(data_X, data_y, test_size=0.3, random_state=0) print(X_train, X_test, y_train, y_test)
結果 :
[[5.8 2.8 5.1 2.4] [6. 2.2 4. 1. ] [5.5 4.2 1.4 0.2] ... [5.8 2.7 4.1 1. ] [7.7 3.8 6.7 2.2] [4.6 3.2 1.4 0.2]] [[5.8 2.8 5.1 2.4] [6. 2.2 4. 1. ] [5.5 4.2 1.4 0.2] ... [6.9 3.1 5.1 2.3] [5. 3.5 1.6 0.6] [5.4 3.7 1.5 0.2]] [[0. 1. 0.] [0. 0. 1.] [0. 0. 1.] ... [0. 1. 0.] [0. 0. 1.] [1. 0. 0.]] [[0. 0. 1.] [0. 1. 0.] [1. 0. 0.] ... [0. 0. 1.] [1. 0. 0.] [1. 0. 0.]]
Kerasで学習
流れは、モデルを定義 -> ネットワークを構築 -> コンパイル -> 実行 みたいな感じです。
層を重ねる時は、基本的にmodel.add
を使用すればよいです。
ここで、 model.add(Dense(input_dim=4, output_dim=100, activation='relu'))
は、この層の入力には4変数、出力には100変数、活性化関数にはrelu関数を使うことを意味しています。
また、model.compile(loss='categorical_crossentropy', optimizer=Adam(), metrics=['accuracy'])
とは、損失関数をcategorical_crossentropy、最適化関数にはAdam、評価関数には精度を使用するという意味です。
csv_logger = CSVLogger('log.csv', separator=',', append=False)
の部分はログをcsvで保存するためのものです。
学習の条件ですが、
変数名 | 値 |
---|---|
層の数 | 3 |
入力層 | 4変数 |
中間層 | 100変数 |
出力層 | 3変数 |
バッチ数 | 32 |
epoch数 | 100 |
以下、コード
from keras.models import Sequential from keras.layers.core import Dense from keras.utils import to_categorical from keras.optimizers import Adam from keras.callbacks import CSVLogger model = Sequential() model.add(Dense(input_dim=4, output_dim=100, bias=True, activation='relu')) model.add(Dense(input_dim=100, output_dim=3, bias=True, activation='softmax')) model.compile(loss='categorical_crossentropy', optimizer=Adam(), metrics=['accuracy']) csv_logger = CSVLogger('log.csv', separator=',', append=False) history = model.fit(X_train, y_train, batch_size=32, epochs=100, validation_data=(X_test, y_test), callbacks=[csv_logger])
ターミナルの画面はこんな感じになります。
Epoch 1/100 105/105 [==============================] - 1s 5ms/step - loss: 1.1275 - acc: 0.3714 - val_loss: 1.1719 - val_acc: 0.2444 Epoch 2/100 105/105 [==============================] - 0s 75us/step - loss: 1.0522 - acc: 0.3714 - val_loss: 1.1002 - val_acc: 0.2444 Epoch 3/100 105/105 [==============================] - 0s 62us/step - loss: 1.0023 - acc: 0.3714 - val_loss: 1.0427 - val_acc: 0.2444 Epoch 4/100 105/105 [==============================] - 0s 54us/step - loss: 0.9615 - acc: 0.3714 - val_loss: 0.9832 - val_acc: 0.2444 ...
もし、ターミナルの画面に上のような途中結果を出力したくなかったら、model.fit
にverbose=0
と追記します。
history = model.fit(X_train, y_train, batch_size=32, epochs=100, validation_data=(X_test, y_test), verbose=1, callbacks=[csv_logger])
モデルの評価
model.evaluate
を使うと、学習し終えたモデルの誤差と精度を呼び出すことができます。
train_score = model.evaluate(X_train, y_train) test_score = model.evaluate(X_test, y_test) print('Train loss:', train_score[0]) print('Train accuracy:', train_score[1]) print('Test loss:', test_score[0]) print('Test accuracy:', test_score[1])
結果 :
Train score: 0.15385689522538867 Train accuracy: 0.9809523815200443 Test score: 0.18351854549513924 Test accuracy: 0.9777777791023254
ちなみに、model.predict
では具体的な予測結果がわかります。
one-hotエンコーディングなので、一番大きな値のインデックスを出力します。
ついでに、答えも同時に出力しておきます。
pred_train = model.predict(X_train) pred_test = model.predict(X_test) pred_train = np.argmax(pred_train, axis=1) pred_test = np.argmax(pred_test, axis=1) print(pred_train) print(np.argmax(y_train, axis=1)) print(pred_test) print(np.argmax(y_test, axis=1))
結果 :
[1 2 2 2 2 ... 0 2 1 2 0] [1 2 2 2 2 ... 0 2 1 2 0] [2 1 0 2 0 ... 2 0 2 0 0] [2 1 0 2 0 ... 2 0 2 0 0]
モデルの保存
機械学習のモデルを保存をすることは重要なので、保存についても説明します。 保存するときは、jsonファイル(またはyaml)でモデルを保存し、重みは別のファイルで保存します。
from keras.models import model_from_json model_json = model.to_json() with open('model.json', 'w') as file: file.write(model_json) model.save_weights('weights.hdf5')
モデルの読み込み
読み込むときも似たような感じですが、model.evaluate
を使うには、もう一回compileしないと、エラーが出ます。
with open('model.json', 'r') as file: model_json = file.read() model = model_from_json(model_json) model.load_weights('weights.hdf5') model.compile(loss='categorical_crossentropy', optimizer=Adam(), metrics=['accuracy']) train_score = model.evaluate(X_train, y_train) test_score = model.evaluate(X_test, y_test) print('Train score:', train_score[0]) print('Train accuracy:', train_score[1]) print('Test score:', test_score[0]) print('Test accuracy:', test_score[1])
結果 :
Train score: 0.15385689522538867 Train accuracy: 0.9809523815200443 Test score: 0.18351854549513924 Test accuracy: 0.9777777791023254
model.compile
の行を削除した時の結果 :
... File "/home/user/anaconda3/lib/python3.5/site-packages/keras/engine/training.py", line 1105, in evaluate batch_size=batch_size) File "/home/user/anaconda3/lib/python3.5/site-packages/keras/engine/training.py", line 680, in _standardize_user_data raise RuntimeError('You must compile a model before ' RuntimeError: You must compile a model before training/testing. Use `model.compile(optimizer, loss)`.
ソースコード全体
# -*- coding: utf-8 -*- # import numpy as np from keras.models import Sequential, model_from_json from keras.layers.core import Dense from keras.utils import to_categorical, np_utils from keras.optimizers import Adam from keras.callbacks import CSVLogger from sklearn.datasets import load_iris from sklearn.model_selection import train_test_split def keras_learning(X_train, X_test, y_train, y_test): # モデルの構築 model = Sequential() model.add(Dense(input_dim=4, output_dim=100, activation='relu')) model.add(Dense(input_dim=100, output_dim=3, activation='softmax')) model.compile(loss='categorical_crossentropy', optimizer=Adam(), metrics=['accuracy']) # 訓練の開始 csv_logger = CSVLogger('log.csv', separator=',', append=False) history = model.fit(X_train, y_train, batch_size=32, epochs=100, verbose=1, validation_data=(X_test, y_test), callbacks=[csv_logger]) return model def keras_predict(X_train, X_test, y_train, y_test, model): # モデルの評価(evaluate) train_score = model.evaluate(X_train, y_train) test_score = model.evaluate(X_test, y_test) print('Train score:', train_score[0]) print('Train accuracy:', train_score[1]) print('Test score:', test_score[0]) print('Test accuracy:', test_score[1]) # モデルの評価(predict) pred_train = model.predict(X_train) pred_test = model.predict(X_test) pred_train = np.argmax(pred_train, axis=1) # for one-hot pred_test = np.argmax(pred_test, axis=1) # for one-hot print(pred_train) print(np.argmax(y_train, axis=1)) print(pred_test) print(np.argmax(y_test, axis=1)) def save_model(model): # モデルの保存 model_json = model.to_json() with open('model.json', 'w') as file: file.write(model_json) model.save_weights('weights.hdf5') def load_model(): # モデルの読み込み with open('model.json', 'r') as file: model_json = file.read() model = model_from_json(model_json) model.load_weights('weights.hdf5') return model def main(): # データセットをロード iris = load_iris() print(iris.data) print(iris.feature_names) print(iris.target) print(iris.target_names) print(type(iris.data)) print(type(iris.target)) data_X = iris.data data_y = iris.target data_y = np_utils.to_categorical(data_y) print(data_X) print(data_y) X_train, X_test, y_train, y_test = train_test_split(data_X, data_y, test_size=0.3, random_state=0) print(X_train) print(y_train) print(X_test) print(y_test) model = keras_learning(X_train, X_test, y_train, y_test) keras_predict(X_train, X_test, y_train, y_test, model) save_model(model) model = load_model() model.compile(loss='categorical_crossentropy', optimizer=Adam(), metrics=['accuracy']) keras_predict(X_train, X_test, y_train, y_test, model) if __name__ == '__main__': main()
まとめ
Kerasでのコーディングは簡単でいいですね。 PyTorchなども流行っているので、試して比較してみたいです。
いろいろしたいことがありますが、時間に余裕ができるまでは更新が遅くなりそうです。