【超入門、ニューラルネットワーク】Kerasで2値分類 〜超簡単な例〜

今回はKerasを使ってニューラルネットワークを実装して、
2値分類をやってみます。

超初心者向けの内容になります。

Kerasとは

Kerasは、ニューラルネットワークを非常にシンプルに構築できるライブラリです。

https://keras.io/ja/

TensorFlow等で書くとかなり長くなってしまうコードがKerasを使うことでシンプルなコードとなります。

ちなみにKerasは下でTensorFlow等が動いています。

2値分類タスクとは

今回は2値分類タスクを扱います。

分類タスクとは、ある入力データが与えられたら、そのデータがどのカテゴリ(またはクラス)に属しているかを予想するタスクです。

医療で言えば、患者の症状(入力データ)が与えられたら、その症状によって病気(カテゴリ)を予測するといったものです。

2値分類タスクはカテゴリが2種類だけの最もシンプルな分類問題となります。

Kerasを使って2値分類をしてみる

今回は非常にシンプルな2値分類タスクをKerasを用いたニューラルネットワークによって解きます。

問題設定

入力データ\(x\)(黒い点)が関数\(f(x)=x^2\)の上に位置するか下に位置するかを分類するタスクを用います。

つまり、入力データ\(x\)(黒点)に与えられたら、それが関数\(f(x)\)の上もしくは下どちらかを出力するニューラルネットワーク(モデル)を作成します。

実装(ソースコード)

では、実装していきます。
まず、必要なライブラリ等を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 → [0, 1] 、1 → [1, 0]と変換します。

# 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"))

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, nb_epoch=200, batch_size=32) # 学習

学習過程をプロットしてみます。
正答率と誤差の推移をプロットします。

plt.plot(history.epoch, history.history["acc"], 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を使ったニューラルネットワークモデルをたくさん紹介してくれています。

タイトルとURLをコピーしました