ニューラルネットワークの学習過程を可視化してみよう
IT技術
ニューラルネットワークの学習過程は可視化できるの?
「ニューラルネットワークのモデルを作ってみたけど、本当にうまく機能しているのか分からない…」
「AIはブラックボックスだから、どのように学習が起こっているかイマイチ分からない…」
こんな悩みを抱えていませんか?
この記事では、このような疑問を解決するために「ニューラルネットワークの学習過程を可視化」していきたいと思います。
ニューラルネットワークの学習過程を可視化して、「モデルがどのように訓練されているのか」「モデルの学習で問題が起こっていないか」などを見てみましょう!
ライブラリとフレームワークのインポート
今回は、「TensorFlow」と「Keras」で構築した画像分類モデルを可視化します。
TensorFlow と Keras の他に、ヘルパーライブラリとして「Numpy」と「matplotlib」も使用するので、まずはインポートしておきましょう!
1from __future__ import absolute_import, division, print_function,unicode_literals
2
3# TensorFlow、Keras
4import tensorflow as tf
5from tensorflow.keras import datasets, layers, models
6
7# ヘルパーライブラリ
8import numpy as np
9import matplotlib.pyplot as plt
使用するデータセット
それでは、使用するデータセットを用意しましょう!
今回使用するのは、おなじみに「MNIST」という手書き数字のデータセットです。
MNISTについて
MNIST には、1枚の画像に「0~9」までの数字がそれぞれ1つ書かれたデータが入っています。
28×28のピクセルの中には「0~255」の整数が格納されています。
「0」は「黒」を、「255」は「白」を表しています。
画像は全部で70,000件あり、そのうちの60,000件が訓練データで、残りの10,000件がテストデータです。
また、すべての画像に「5」「0」「4」などの正解が記されたラベルがつけられています。
今回は、この MNIST を使って、画像に書かれている数字を推測するモデルを構築していきましょう!
データセットのロード
まずは、データセットをロードします。
1(x_train, y_train), (x_test, y_test) = datasets.mnist.load_data()
2
3# モデルを訓練するときのためにサイズを変更する
4x_train.resize(60000, 28, 28, 1)
5x_test.resize(10000, 28, 28, 1)
6
7print(x_train.shape, y_train.shape) # (60000, 28, 28, 1) (60000,)
8print(x_test.shape, y_test.shape) # (10000, 28, 28, 1) (10000,)
x_train とy_train はそれぞれ「訓練データ」の画像とラベルで、x_test とy_test はそれぞれ「テストデータ」の画像とラベルです。
訓練データには60,000件、テストデータには10,000件のデータがあり、画像は28×28ピクセル、ラベルはそれぞれ1つの値であることが確認できますね。
データの前処理
データセットをロードできたら、モデルの構築をする前に、前処理をしましょう。
画像データのピクセルは「0~255」までの整数をとりますが、これを「0~1」に正規化します。
1x_train = x_train / 255.0
2x_test = x_test / 255.0
3
4print('Max:', x_train.max(), ', Min:', x_train.min()) # Max: 1.0 , Min: 0.0
5print('Max:', x_test.max(), ', Min:', x_test.min()) # Max: 1.0 , Min: 0.0
訓練データとテストデータともに、最大値が「1」、最小値が「0」のデータに正規化できました。
MNISTを画像分類するモデルを構築する
それでは、MNISTを画像分類するモデルを構築していきましょう!
今回は、4つの層からなる「簡単なモデル」を作成します。
1model = models.Sequential([
2 layers.Conv2D(16, (3, 3), activation='relu', input_shape=(28, 28, 1)), # 畳み込み
3 layers.MaxPooling2D((2, 2)), # プーリング
4 layers.Flatten(), #ベクトル化
5 layers.Dense(10, activation='softmax') # 出力
6])
ネットワークを定義したらモデルをコンパイルし、構築したモデルを確認します。
1model.compile(
2 optimizer='adam',
3 loss='sparse_categorical_crossentropy',
4 metrics=['accuracy']
5)
6
7model.summary()
8
9"""
10_________________________________________________________________
11Layer (type) Output Shape Param #
12=================================================================
13conv2d_5 (Conv2D) (None, 26, 26, 16) 160
14_________________________________________________________________
15max_pooling2d_5 (MaxPooling2 (None, 13, 13, 16) 0
16_________________________________________________________________
17flatten_5 (Flatten) (None, 2704) 0
18_________________________________________________________________
19dense_6 (Dense) (None, 10) 27050
20=================================================================
21Total params: 27,210
22Trainable params: 27,210
23Non-trainable params: 0
24_________________________________________________________________
25"""
問題なくモデルを構築することができました!
モデルを訓練する
モデルの構築が完了したら、次はモデルを訓練をしましょう。
1history = model.fit(x_train, y_train, validation_data=(x_test, y_test), epochs=10)
2
3"""
4Epoch 1/10
51875/1875 [==============================] - 20s 10ms/step - loss: 0.2849 - accuracy: 0.9194 - val_loss: 0.1273 - val_accuracy: 0.9646
6Epoch 2/10
71875/1875 [==============================] - 19s 10ms/step - loss: 0.1103 - accuracy: 0.9692 - val_loss: 0.0820 - val_accuracy: 0.9748
8Epoch 3/10
91875/1875 [==============================] - 19s 10ms/step - loss: 0.0753 - accuracy: 0.9783 - val_loss: 0.0679 - val_accuracy: 0.9775
10(省略)
11Epoch 10/10
121875/1875 [==============================] - 19s 10ms/step - loss: 0.0089 - accuracy: 0.9976 - val_loss: 0.0679 - val_accuracy: 0.9827
13"""
Keras では、このように訓練の過程がデフォルトで可視化されます。
- 現在どのくらい学習が進んでいるのか
- 損失関数の値はどのくらいか
- 正解率がどのくらいか
これで、学習の様子を知ることができます。
しかし、このように損失値や正解率を数字で眺めても、いまいちピンと来ませんね。
そこで、グラフを描画するライブラリ「matplotlib」を使用して、これらの値の変化を可視化してみましょう!
学習の様子を可視化する
それでは、「matplotlib」を使って学習の様子を可視化しましょう。
実装例コード
学習を可視化するときのコードは、こちらです。
1metrics = ['loss', 'accuracy'] # 使用する評価関数を指定
2
3plt.figure(figsize=(10, 5)) # グラフを表示するスペースを用意
4
5for i in range(len(metrics)):
6
7 metric = metrics[i]
8
9 plt.subplot(1, 2, i+1) # figureを1×2のスペースに分け、i+1番目のスペースを使う
10 plt.title(metric) # グラフのタイトルを表示
11
12 plt_train = history.history[metric] # historyから訓練データの評価を取り出す
13 plt_test = history.history['val_' + metric] # historyからテストデータの評価を取り出す
14
15 plt.plot(plt_train, label='training') # 訓練データの評価をグラフにプロット
16 plt.plot(plt_test, label='test') # テストデータの評価をグラフにプロット
17 plt.legend() # ラベルの表示
18
19plt.show() # グラフの表示
コードを解説するので、1つずつ見ていきましょう!
使用する評価関数を決める
まず最初のコードでは、使用する評価関数をリストとして指定します。
1metrics = ['loss', 'accuracy']
今回の場合は、損失関数loss と正解率accuracy を使用していますね。
なお、損失関数と評価関数は本来異なるものですが、今回は「モデルを評価できる関数」という意味で、「評価関数」として統一して説明します。
グラフを描画するための準備
plt.figure(figsize=(10, 5))は、matplotlib でグラフを表示するときに必要なコードです。
このコードでは、グラフを表示するスペース(この場合は10×5のスペース)を確保しています。
なお、for 文の中にあるplt.subplot(2, 2, i+1) とplt.title(metric) はコメントの通り、グラフを描くスペースを決めてタイトルを表示するためのコードです。
評価を取得する
それでは、for 文の中を詳しく見てみましょう。
まずは、for 文を使うことで、metrics から評価関数を1つずつ取り出し、metrics に代入しています。
このことから、このループでは「評価関数ごとにグラフを表示していく(ループを繰り返す)」ということが分かりますね。
metric に評価関数を代入したら、次はhistory.history[metric] とhistory.history['val_' + metric] で、history から評価関数の値を取得してplt_train とplt_test にそれぞれ代入します。
ところで、history にはモデルをコンパイルしたときの返り値が代入されていましたね。
ここで、history.history とすることで訓練中・テスト中の評価を取得することができます。
なお、テストの評価はval_metric のように、先頭にval_ をつけることで取り出せるため、テストデータの評価はplt_test = istory.history['val_' + metric] として取得しています。
評価をグラフ化する
訓練データとテストデータの評価を取得したら、これらの評価をグラフにプロットしましょう。
plt.plot(plt_train, label='training') では訓練データの評価であるplt_train をグラフにプロットし、plt.plot(plt_test, label='test') ではテストデータの評価であるplt_test をグラフにプロットしています。
それぞれのグラフにはtraining ラベルとtest ラベルがついていますが、これらのラベルはplt.legend() で表示することが可能です。
コードを実行する
それでは、実際にコードを実行してみましょう。
無事にグラフが表示されました!
損失関数(左のグラフ)
左のグラフは、「損失関数の値をグラフにしたもの」です。
青い線が訓練中の損失値、オレンジの線がテスト中の損失値です。
ニューラルネットワークの学習では損失関数の値を小さくするように学習が進んでいくため、一般には損失値が小さいほど良いモデルであると考えられます。
ところが、可視化したグラフを見てみてみましょう!
4エポック目以降はテスト中の損失値があまり小さくならず、訓練中の損失値との差が徐々に広がっていることが分かりますね。
これは、4エポック目以降に「過学習」が発生していることを表しています。
正解率(右のグラフ)
右のグラフは、「正解率をグラフにしたもの」です。
左のグラフと同様に、青い線が訓練中の正解率、オレンジの線がテスト中の正解率を表しています。
正解率が高いほど良い状態なのですが、損失値と同じように、4エポック目以降はテスト中の正解率が停滞していることが分かりますよね。
こちらも、「過学習」を示すサインです。
このようにグラフを可視化することで、「モデルがどのように学習しているか」「モデルの学習中に問題が起こっていないか」などを簡単に理解することができるようになります。
グラフを可視化するメリットが十分に分かったところで、次は色々な評価関数を使って、モデルの学習過程を可視化してみましょう。
色々な評価関数で可視化してみる
先ほど可視化したのは「損失値」と「正解率」でしたが、他にも様々な評価関数の値を可視化することができます。
こちらは、先ほどモデルのコンパイルをしたときのコードです。
1model.compile(
2 optimizer='adam',
3 loss='sparse_categorical_crossentropy',
4 metrics=['accuracy']
5)
metrics=['accuracy'] と正解率で評価していましたが、このmetrics に評価関数を指定することで、様々な種類の評価関数を使うことができます。
色々な評価関数を使った可視化の実装
それでは、他の評価関数を使ってモデルの学習を可視化してみましょう。
Keras ではbinary_accuracy 、categorical_accuracy 、sparse_categorical_accuracy 、top_k_categorical_accuracy の4つの評価関数に加え、自分で作成した評価関数も使用することができます。
なお、単にaccuracy を指定した場合には、4つの評価関数の中から最適な関数が適用されています。
それでは、実際に4つの評価関数をすべて使い、モデルが学習する様子を可視化してみましょう!
実装例コード
コードはこちらになります。
1# 使用する評価関数を指定
2metrics = ['binary_accuracy', 'categorical_accuracy', 'sparse_categorical_accuracy', 'top_k_categorical_accuracy']
3
4# 指定したmetricsでコンパイル
5model.compile(
6 optimizer='adam',
7 loss='sparse_categorical_crossentropy',
8 metrics=metrics
9)
10
11# モデルの訓練
12history = model.fit(x_train, y_train, validation_data=(x_test, y_test), epochs=10)
13
14
15# グラフを描画
16
17plt.figure(figsize=(10, 10)) # 10×10のスペースを用意
18
19for i in range(len(metrics)):
20
21 metric = metrics[i]
22
23 plt.subplot(2, 2, i+1) # figureを2×2のスペースに分ける
24 plt.title(metric)
25
26 plt_train = history.history[metric]
27 plt_test = history.history['val_' + metric]
28
29 plt.plot(plt_train, label='training')
30 plt.plot(plt_test, label='test')
31 plt.legend()
32
33plt.show()
ほとんどが先ほどのコードと同じなので、変わった部分について見ていきましょう!
評価関数をリスト指定
まず、metrics = ['binary_accuracy', 'categorical_accuracy', 'sparse_categorical_accuracy', 'top_k_categorical_accuracy']では、4種類の評価関数をリストで指定しています。
モデルのコンパイルと訓練
上記で、使用する評価関数が変わったため、モデルのコンパイルと訓練をもう一度行います。
1model.compile(
2 optimizer='adam',
3 loss='sparse_categorical_crossentropy',
4 metrics=metrics
5)
6
7history = model.fit(x_train, y_train, validation_data=(x_test, y_test), epochs=10)
metrics=metrics で左辺のmetrics に渡しているのは、最初に指定したリストのmetrics です。
グラフを表示
グラフを表示する部分はほとんど変わりません。
plt.figure(figsize=(10, 10)) ではグラフを表示するためのスペースを10×10で指定し、plt.subplot(2, 2, i+1) では表示するスペースを2×2に分割しているだけです。
Keras は様々な評価関数が使える
このように、Keras では様々な評価関数を使って、モデルが学習する様子を簡単に可視化することもできます。
なお、自分で作成した評価関数についてもmetrics で指定すれば簡単に使えるので、気になる方はぜひ自作の評価関数で挑戦してみてください!
注意点
モデルをコンパイルする際、metrics にloss を指定してしまうとエラーが発生してしまいます。
1model.compile(
2 optimizer='adam',
3 loss='sparse_categorical_crossentropy',
4 metrics=['loss'] # metricsにlossを指定している
5)
6
7history = model.fit(x_train, y_train, validation_data=(x_test, y_test), epochs=10)
8
9# ValueError: Unknown metric function:loss
これは「損失関数」が「評価関数」とは異なり、ディープラーニングに欠かせないものだからです。
ディープラーニングでは学習に「損失関数」を使っているため、metrics にloss を指定せずとも、history.history['loss'] のように「損失関数」の値を取得することができます。
さいごに
今回は、「ニューラルネットワークの学習過程を可視化」していきました。
「モデルがどのように訓練されているのか」
「モデルの学習中に問題が起こっていないか」
このような疑問は、実際に「TensorFlow」と「Keras」でモデルを構築し、学習の様子を可視化することで解決できます。
これを機に、ぜひ色々なニューラルネットワークを可視化してみましょう!
こちらの記事もオススメ!
2020.07.28機械学習 特集知識編人工知能・機械学習でよく使われるワード徹底まとめ!機械学習の元祖「パーセプトロン」とは?【人工知能】ニューラルネ...
2020.07.17ライトコード的「やってみた!」シリーズ「やってみた!」を集めました!(株)ライトコードが今まで作ってきた「やってみた!」記事を集めてみました!※作成日が新し...
ライトコードでは、エンジニアを積極採用中!
ライトコードでは、エンジニアを積極採用しています!社長と一杯しながらお話しする機会もご用意しております。そのほかカジュアル面談等もございますので、くわしくは採用情報をご確認ください。
採用情報へ
「好きを仕事にするエンジニア集団」の(株)ライトコードです! ライトコードは、福岡、東京、大阪、名古屋の4拠点で事業展開するIT企業です。 現在は、国内を代表する大手IT企業を取引先にもち、ITシステムの受託事業が中心。 いずれも直取引で、月間PV数1億を超えるWebサービスのシステム開発・運営、インフラの構築・運用に携わっています。 システム開発依頼・お見積もり大歓迎! また、現在「WEBエンジニア」「モバイルエンジニア」「営業」「WEBデザイナー」を積極採用中です! インターンや新卒採用も行っております。 以下よりご応募をお待ちしております! https://rightcode.co.jp/recruit