今回の記事では前回習得したアヤメの分類アルゴリズムをtensorflowを用いてアルゴリズムを再構築してみましょう。アルゴリズムの再構築及びリエンジニアリングは現場でもよくある話で、現場を想定した訓練を兼ねてtensorflowを学んでみましょう。
TensorFlowでアヤメの分類をしてみよう
過去の記事にてアヤメの分類に挑戦しました。本記事ではTensorFlow の使い方に慣れるために、同じ例題を解いてみましょう。まだディープラーニングではありませんが、TensorFlowの基本的な使い方を学ぶことができるでしょう。
アヤメの分類問題の復習
ここでは、scikit-learn を用いて解いたアヤメの分類問題を、TensorFlow を用いて解いてみます。ぜひ、前回の記事内で紹介したプログラムとどう違うのか比較しながら読み進めてみてください。最初に、改めてアヤメの分類問題では、何を解くのかを復習してみましょう。アヤメの分類問題は、アヤメのがく片と花びらについて、それぞれの幅と長さの情報を利用して、アヤメの品種を特定します。少し難しいプログラムなので、少しずつ内容を抜粋して見ていきましょう。

まずは、これまでと同じように CSVファイルを読み込んで、データをテスト用と学習用に分割したいと思います。以下は、CSV ファイルを読み込んで、ラベル情報とアヤメのデータに分割しました。
import pandas as pd
# アヤメデータの読み込み
iris_data = pd.read_csv(“iris.csv”, encoding=”utf-8″)
# アヤメデータをラベルと入力データに分離する
y labels = iris_data.loc[:,”Name”]
x_data =iris_data.loc[:,
“SepalLength”,”SepalWidth”,”PetalLength”,”PetalWidth”]]
ラベルを One-Hot ベクトル形式に直そう
ただし、TensorFlow ではラベルデータを「One-Hotベクトル」という形式で表す必要があります。「One-Hot(ワンホット)」というのは1つだけ High(1) の状態であり、他は Low(0) の状態であるようなビット列のことを指します。たとえば、アヤメデータのラベルデータでは、「Iris-setosa」が[1,0,0]、「Iris-versicolor」が [0, 1,0]、「Iris-virginica」が[0, 0, 1] のようにして表現します。CSV ファイルから読み込んだアヤメのラベルデータを、One-Hot ベクトル形式に直すには、以下のようにします。
# ラベルデータを One-Hot ベクトルに直す
labels = {
‘Iris-setosa’: [1, 0, 0],
‘Iris-versicolor’: [0, 1, 0],
‘Iris-virginica’: [0, 0, 1]
}
y_nums = 1ist (map(lambda v : labels [v] ,y_labels))
print (y_nums)
テストデータを学習用とテスト用に分ける
続けて、データを学習用とテスト用に分割します。
from sklearn.model_selection import train_test_split
# 学習用とテスト用に分離する
x_train, x_test, y_train, y_test = train_test_split(
X_data, y_nums, train_size30.8)
学習アルゴリズムを定義
続けて、TensorFlow で学習アルゴリズムを定義してみましょう。アヤメの品種分類のプログラムでは、入力値となるアヤメデータは、SepallLength(がく片の長さ)、SepalWidth(がく片の幅)、PetalLength(花びらの長さ)、PetalWidth(花びらの幅)なので、四次元となります。そして、出力値はアヤメの品種 (Iris-setosa/lris-versicolor/Iris-virginica) なので三次元です。言い換えると、入カデータは四次元、出力は三次元ということになります。TensorFlow を使う時にもっとも気をつけないといけないのが、この入力と出力の次元数です。この値が間違っていると正しく動きません。なお、モデルを構築する際、ニューラルネットワークに活性化関数(activation function) を指定します。活性化関数のことを伝達関数とも言います。これは、ニューラルネットワークにおいて、入力の合計から出力を決定するための関数です。
import tensorflow as tf
import tensorflow.keras as keras
Dense = keras.layers.Dense
model = keras.models.Sequential ()
model.add (Dense (10, activation=’relu’, input_shape=(4,)))
model.add (Dense (3, activation=’softmax’))
ここでは、モデルを Sequential( 逐次実行)なものとして定義します。Dense というのは、全結合ニューラルネットワークです。そこにまず、ユニット数が10のネットワークを構築します。その際、入力データ (input_shape) は四次元、活性化関数 (activation) には relu を指定しています。そして、出力用にユニット数3のニューラルネットワークを追加します。ここで指定するユニット数は、出力ユニットの数で、出力データの三次元を指定します。また、活性化関数 (activation) には、softmax を指定します。まず、1つ目のネットワークで「ReLU(ランプ関数)」を指定しています。これは、以下のような数式で表されます。
y(x) = x+ = max(0, x)
そして2つ目のネットワークで指定する活性化関数の softmax とは、ソフトマックス回帰を表すもので、次のような数式で表されるものです。
y = softmax (Wx+b)
突然、数式が出てくると難しいもののように感じます。しかし、数学に詳しくなくても、気軽にニューラルネットワークを利用できるのが TensorFlowの良いところです。ここでは、参考までに数式を紹介しましたが、パラメーターの1つとして捕らえ、いろいろ試してみると良いでしょう。続いて、定義したモデルを構築してみましょう。
model.compile(
loss=’categorical_crossentropy’,
optimizer=’adam’,
metrics=[‘accuracy’])
モデルを構築する時には、モデルをどのように評価するのかを metrics パラメーターに指定します。ここでは、正解率 (accuracy) を指定しています。また、損失関数の評価値(loss) には、categorical_crossentropy を指定しています。これは、カテゴリーごとのクロスエントロピーを指定していますが、クラス分類でよく使われる誤差関数の1つです。また、最適化の手法には adam を指定していますが、これは確率的勾配降下法の1つアダム法を使って最適化を行うように指定しています。
データの学習と実行テスト
続いて、定義したモデルを利用して、機械学習を実行し、正解率を求めてみましょう。学習用のデータを用いて学習を行った後、テストデータを利用して評価を行います。
# 学習を実行
model.fit(x_train, y_train,
batch_size=20,
epochs=300)
# モデルを評価
Score =model.evaluate(x_test, y_test, verbose=1)
print(‘EM =’, score [1], ‘loss=’, score [0])
ここでftメソッドに指定するのは、データとラベルだけではありません。バッチサイズ (batch size)とエポック (epochs) も指定します。バッチサイズとは1回に計算するデータの数のことで、エポックは繰り返し回数です。バッチサイズを小さくすると、使用するメモリー量が少なくなりますが、小さくしすぎるとうまく動かなくなります。
そして学習の後で、テストデータを用いてモデルを評価します。評価を終えると戻り値に正解率が得られます。なお、プログラムを実行すると、以下のように結果が表示されます。ただし、マシンの性能にもよりますが、実行には少々時間がかかる場合があります。
正解率0,96666664 loss= 0 19096146523952484
ランダムに学習データとテストデータを分けているので、学習結果にばらつきがありますが、だいたい0.93 から1.0の間の値が表示されます。ここで改めて注目したい点は、ニューラルネットワークでは繰り返し学習を行うという点です。このように繰り返しデータを学習することで、パラメーターが調整されて、データを予測することができるようになります。
アヤメ分類問題の完全なプログラムと Keras について
ここまでの部分で、TensorFlow の基本的なプログラムを紹介しました。改めて、完全なプログラムを紹介します。
import tensorflow as tf
import tensorflow.keras as keras
from sklearn.model_selection import train_test_split
import pandas as pd
import numpy as np
# アヤメデータの読み込み(*1)
iris_data = pd.read_csv(“iris.csv”, encoding=”utf-8″)
# アヤメデータをラベルと入力データに分離する
y_labels= iris_data.loc[: ,”Name”]
x_data=iris data.loc[: , [“SepalLength”,”SepalWidth”,”PetalLength”,”PetalWidth”]]
# ラベルデータをOne-Hot ベクトルに直す
labels = {
‘Iris-setosa’: [1, 0, 0],
‘Iris-versicolor’: [0, 1, 0],
‘Iris-virginica’: [0, 0,
}
y_nums =np.array (list (map(lambda v : labels [v] , y_labels)))
x_data =np.array (x_data)
# 学習用とテスト用に分割する(*2)
x_train, x_test, y_train, y_test = train_test_split(
x_data, y_nums, train_size=0.8)
# モデル構造を定義(*3)
Dense = keras.layers.Dense
Model= keras.models.Sequential ()
model.add(Dense (10, activation=’relu’, input_shape=(4,)))
model.add(Dense(3, activation=’softmax’))
# モデルを構築(*4)
model.compile(
loss=’categorical_crossentropy’,
optimizer=’adam’,
metrics=[‘accuracy’])
# 学習を実行(*5)
model.fit(x_train, y_train,
batch_size=20,
epochs=300)
# モデルを評価(*6)
Score=model.evaluate (x_test, y_test, verbose%3D1)
print (‘ 正解=’, score [1], ‘loss=’, score[0])
プログラムを概観してみましょう。プログラムの(※1)の部分では、アヤメデータを読み込んで、ラベルを One-Hot ベクトル形式に変換します。このとき、np.array) を利用して、リスト型から NumPyそして、(※2)の部分でアヤメデータを学習用とテスト用に分割します。2章と同じく、学習データ形式に変換しておきます。を0.8(80%)、テストデータを0.2(20%) とします。プログラムの(※3)以降の部分でモデルを定義します。(※4)の部分では、モデルを構築します。(※5)の部分では、学習データを与えて、データの学習を実行します。そして、(※6)でモデルを評価します。
TensorFlow の使い方を改善したKeras ライブラリー
ここまで、ジャンケンのルールを学習するプログラムと、アヤメの分類問題のプログラム、TensorFlow を利用した2つのプログラムを見てきました。これを scikit-learn と使い勝手を比べるとどうでしょうか。もちろん、TensorFlow と scikit-learn は異なるライブラリーであるため、まったく同じように使うということはできませんが、モデル定義という手間が増えるものの、似ている部分も多くあったのではないでしょうか。ところが、バージョン1の頃のTensorFlow は、柔軟性は非常に高かったものの、簡単なニューラルネットワークのモデルを記述する際にも、煩雑なコーディングが必要とされていました。そのため、もっとTensorFlow を手軽に利用したいというニーズがありました。ここまで紹介したプログラムでモデルを定義するのに、tensorfiow.keras 以下のオブジェクトを利用していたことに気づいたでしょうか。実はもともと、Keras は TensorFlow を利用する別のライブラリーとして開発されていました。しかし、とても使いやすいライブラリーであったため、TensorFlow に取り込まれたのです。Keras を利用することで、scikit-learn のように手軽に機械学習を実践することが可能になりました。Keras がTensorFlow の使い勝手を劇的に改善したと言えます。なお、本書の初版では、TensorFlowとKeras の両方の使い方を紹介していたのですが、Keras がTensorFlow に取り込まれたため、本改訂版では、煩雑な TensorFlow の使い方を大幅にカットするという編集が行われました。
column
学習の様子を視覚化しよう
ジァまでの部分で紹介した通り、ニューラルネットワークでは、繰り返し学習を行ってパラメーターを調整することで精度を高めます。そのため、繰り返し回数を指定する epochs の値が重要です。ToncorFlow のプログラムを実行すると、次のように損失関数(loss) の値が下がっていき、正解率(accuracy) の値が上がっているのを観察できます。TensorFlow ではこの値をグラフに描画することができます。先ほどのアヤメの分類問題で関数fit0 の戻り値には、history という履歴データが含まれています。そこで、matplotib を使って手軽にグラフを描画できます。プログラム「keras-iris.py」の後半を以下のように修正します。
#アヤメの分類問題を修正
import matplotlib.pyplot as plt
epochs=10
# 学習を実行
result =model.fit (x_train, y_train,
batch_size=20,
epochs=epochs)
# モデルを評価
score = model.evaluate (x_test, y_test, verbose=1)
print (‘ EM*=’, score [1], ‘loss=’, score [0])
# 学習の様子をグラフに描面
plt.plot (range(1, epochs+1),
result.history[‘accuracy’], label=”training”)
plt.plot (range (1, epochs+1),
result.history[‘loss’], label=”loss”)
plt.xlabel(‘Epochs=’ + str(epochs))
plt.ylabel (‘Accuracy’)
plt.legend ()
plt.show ()
これを実行すると、次の図のようにloss と accuraCy の推移を確認できます。ここでは、epochsに 10を指定した場合のグラフです。確かに、これを見ると繰り返しのたびに損失関数(loss) の値が下がり、正解率 (accuracy) の値が上がっているのが視覚的にわかります。とは言え、グラフを見る限り、もっと高い精度が望めそうな感じがします。それでは、繰り返し回数を10倍の100回に増やしてみましょう。すると「正解率= 0.93 ロス= 0.31」となり、以下のようなグラフを描きました。epochs が 10回の時の正解率は 0.267 だったので確かに精度は上がりました。ロスの下降が緩やかになっているものの、正解率の値はまだ上昇しそうな余地があります。それでは、epochs を300にして実行してみましょう。結果は「正解率= 1.0 ロス= 0.12」でした。十分な結果が出ています。どのようなグラフが描画されたでしょうか。ロスの値は下がりきり、正解率も上がりきっています。このように、正解率とロスの値を描画してみると、パラメーター epochs の値が正しいのかどうかを確認できます。精度が正しいのかどうか、またニューラルネットワークの構造や活性化関数が有効かどうかなど、パフォーマンスチューニングを行う上で視覚的に学習の様子を見られるのは大きな助けになります。
この節のまとめ
・TensorFlow を利用してジャンケンのルールを学習したり、アヤメの分類問題を解く
・TensorFlow ではさまざまなニューラルネットワークが記述できる
・cikit-learn で培った機械学習の基礎的な知識を、TensorFlow でもそのまま活用できる
いかがでしたでしょうか。今回は前回触れたヤマメの分類問題に対して別のアプローチを行ってみました。次回は数字の分類問題についてご紹介する予定なので是非一読ください。