今回はKerasを使ってニューラルネットワークを実装して、
2値分類をやってみます。
超初心者向けの内容になります。
Kerasとは
Kerasは、ニューラルネットワークを非常にシンプルに構築できるライブラリです。
TensorFlow等で書くとかなり長くなってしまうコードがKerasを使うことでシンプルなコードとなります。
ちなみにKerasは下でTensorFlow等が動いています。
2値分類タスクとは
今回は2値分類タスクを扱います。
分類タスクとは、ある入力データが与えられたら、そのデータがどのカテゴリ(またはクラス)に属しているかを予想するタスクです。
医療で言えば、患者の症状(入力データ)が与えられたら、その症状によって病気(カテゴリ)を予測するといったものです。
2値分類タスクはカテゴリが2種類だけの最もシンプルな分類問題となります。
Kerasを使って2値分類をしてみる
今回は非常にシンプルな2値分類タスクをKerasを用いたニューラルネットワークによって解きます。
問題設定
入力データ\(x\)(黒い点)が関数\(f(x)=x^2\)の上に位置するか下に位置するかを分類するタスクを用います。
つまり、入力データ\(x\)(黒点)に与えられたら、それが関数\(f(x)\)の上もしくは下どちらかを出力するニューラルネットワーク(モデル)を作成します。
実装(ソースコード)
ソースコードはgithubにもあげてあります。
https://github.com/tocom242242/aifx_blog_codes/blob/master/nn_tf2/simple_binary_classification.ipynb
では、実装していきます。
まず、必要なライブラリ等をimportします。
import numpy as np import matplotlib.pyplot as plt from keras.models import Sequential from keras.layers import Dense, Activation from sklearn.model_selection import train_test_split from keras.utils import np_utils
データの作成
学習、テスト用のデータを生成します。
入力データXとラベルデータYを初期化します。
NB_DATAS = 500 # データの作成 X = np.random.rand(NB_DATAS, 2) # 入力データ Y = np.zeros(NB_DATAS) # ラベルデータ
次にラベルの設定をします。
今回はシンプルな二次関数\(f(x) = x^2\)が境界線となりますので、
この二次関数より上なら1、下なら0となるように各データにラベルをふります。
def f(x): return x**2 # ラベルの付与 for idx, x in enumerate(X): if x[1] > f(x[0]): Y[idx] = 1.0
データをプロットしてみましょう。
X1 = np.array([[x1, x2] for x1, x2 in zip(X[:, 0], X[:, 1]) if x2 > f(x1)]) X2 = np.array([[x1, x2] for x1, x2 in zip(X[:, 0], X[:, 1]) if x2 <= f(x1)]) plt.scatter(X1[:, 0], X1[:, 1], c="r", label="$x_2>f(x_1)$") plt.scatter(X2[:, 0], X2[:, 1], c="b", label="$x_2 \leq f(x_1)$") x2 = np.arange(0, 1, 0.01) y2 = x2**2 plt.plot(x2, y2, c="g", linewidth=5.0, linestyle="--", label="$f(x)=x^2$") plt.legend(loc="upper left", framealpha=1.0) plt.xlabel("$x_1$") plt.ylabel("$x_2$") plt.show()
ラベルデータをone-hot encodingしていきます。
0 → [1, 0] 、1 → [0, 1]と変換します。
# one-hotエンコード.例) 1 => [0, 1] Y_one_hot = np_utils.to_categorical(Y) print(f"y:{Y[0]},y_one_hot:{Y_one_hot[0]}") #=> y:0.0,y_one_hot:[1. 0.]
作成したデータを学習用とテスト用にわけます。
# 教師データとテストデータに分割 x_train, x_test, y_train, y_test= train_test_split(X, Y_one_hot, train_size=0.8)
このデータを使ってモデルの学習と評価をしていきます。
モデルの構築・学習・評価
では、モデル(ニューラルネットワーク)を作成します。
今回は以下の図のようなニューラルネットワークを構築します。
# モデルの作成 model = Sequential() model.add(Dense(3, input_dim=2)) # 入力層2ノード, 隠れ層に3ノード, 全結合 model.add(Activation("sigmoid")) # 活性化関数はsigmoid model.add(Dense(2)) # 出力層2ノード,全結合 model.add(Activation("sigmoid"))
Sequentialでシンプルなモデル(入力から出力に流れていくネットワーク)を初期化します。
このSequentialモデルに層を追加していきます。
Denseで全結合の層を表しています。
Activationで活性化関数を指定しています。
今回はsigmoid関数とします。
出力はone-hot-encodingで2値分類をするので、出力数は2になります。
([1, 0]で0、[0, 1]で1を表現するので)
モデルをコンパイルします。
ここで、誤差関数や最適化手法を設定します。
model.compile(loss="binary_crossentropy", # 誤差関数 optimizer="adam", # 最適化手法 metrics=['accuracy'])
modelはfitメソッドによって学習を実行します。
nb_epochはエポック数、つまり、学習回数です。
batch_sizeは一度の学習に使うデータ数です。
# 訓練 history = model.fit(x_train, y_train, epochs=200, batch_size=32) # 学習
学習過程をプロットしてみます。
正答率と誤差の推移をプロットします。
plt.plot(history.epoch, history.history["accuracy"], label="acc") plt.plot(history.epoch, history.history["loss"], label="loss") plt.xlabel("epoch") plt.legend()
accが正答率、lossが誤差を表しています。
epoch(学習回数)が進むに連れて、正答率が向上して、誤差が小さくなっていることがわかります。
うまく学習が進んでいるようです。
学習し終えたモデルを使って評価しましょう。
evaluateメソッドによってテストを行います。
先程test用に分けたデータを使って評価します。
# 評価 score = model.evaluate(x_test, y_test, verbose=1) print("Test score", score[0]) print("Test accuracy", score[1])
以下はテストデータで評価した結果になります。
Test score 0.2682757061719894 Test accuracy 0.995
Test scoreが誤差、Test accuracyは正答率を表しています。
正答率が99.5%ですのでけっこう良くできていることがわかります。
簡単な問題ですので、簡単なモデルでもうまく分類できていることがわかります。
ソースコード全体像
import numpy as np import matplotlib.pyplot as plt from keras.models import Sequential from keras.layers import Dense, Activation from sklearn.model_selection import train_test_split from keras.utils import np_utils NB_DATAS = 500 # データの作成 X = np.random.rand(NB_DATAS, 2) # 入力データ Y = np.zeros(NB_DATAS) def f(x): return x**2 # ラベルの付与 for idx, x in enumerate(X): if x[1] > f(x[0]): Y[idx] = 1.0 X1 = np.array([[x1, x2] for x1, x2 in zip(X[:, 0], X[:, 1]) if x2 > f(x1)]) X2 = np.array([[x1, x2] for x1, x2 in zip(X[:, 0], X[:, 1]) if x2 <= f(x1)]) plt.scatter(X1[:, 0], X1[:, 1], c="r", label="$x_2>f(x_1)$") plt.scatter(X2[:, 0], X2[:, 1], c="b", label="$x_2 \leq f(x_1)$") x2 = np.arange(0, 1, 0.01) y2 = x2**2 plt.plot(x2, y2, c="g", linewidth=5.0, linestyle="--", label="$f(x)=x^2$") plt.legend(loc="upper left", framealpha=1.0) plt.xlabel("$x_1$") plt.ylabel("$x_2$") plt.show() plt.savefig("datas.png") # one-hotエンコード.例) 1 => [0, 1] Y_one_hot = np_utils.to_categorical(Y) # 教師データとテストデータに分割 x_train, x_test, y_train, y_test= train_test_split(X, Y_one_hot, train_size=0.8) # モデルの作成 model = Sequential() model.add(Dense(3, input_dim=2)) # 入力層2ノード, 隠れ層に3ノード, 全結合 model.add(Activation("sigmoid")) # 活性化関数はsigmoid model.add(Dense(2)) # 出力層2ノード,全結合 model.add(Activation("sigmoid")) model.compile(loss="binary_crossentropy", # 誤差関数 optimizer="adam", # 最適化手法 metrics=['accuracy']) # 訓練 history = model.fit(x_train, y_train, nb_epoch=200, batch_size=32) # 学習 # 評価 score = model.evaluate(x_test, y_test, verbose=1) plt.plot(history.epoch, history.history["acc"], label="acc") plt.plot(history.epoch, history.history["loss"], label="loss") plt.xlabel("epoch") plt.legend() plt.savefig("result.png") print("Test score", score[0]) print("Test accuracy", score[1])
参考文献
直感 Deep Learning ―Python×Kerasでアイデアを形にするレシピ
kerasを使ったニューラルネットワークモデルをたくさん紹介してくれています。