キービジュアル画像

2020年3月18日

Kerasを使って画像分類を試してみる(4)―サンプルプログラムの実行―

お手軽ディープラーニング

情報通信研究部 橋本 大樹

このコラムでは、全4回の連載で、ディープラーニングフレームワークKerasの開発環境を構築し、簡単なサンプルプログラムを動かしてディープラーニングを体験してみることを目標とします。このコラムを参考に、ディープラーニングの世界への第一歩を踏み出しましょう。

概要

連載の最終回となる今回は、Keras公式のサンプルプログラムを実行してディープラーニングによる画像分類を行います。

一般的にディープラーニング開発を行う場合、大量の学習用データが必要となりますが、Kerasには、いくつかの有名なデータセットをダウンロードしてプログラムに読み込むための機能があります。本記事で使用するサンプルプログラムでは、その機能を利用して画像分類用の既存データセットであるCIFAR10を使用します。

本記事では、サンプルプログラムのソースコードを用いて、画像分類の処理の流れについても説明を行います。

本記事を参考にサンプルプログラムを実行して、画像分類を試しましょう。

サンプルプログラムによる画像分類の学習

本記事では、CIFAR10データセットを使って、畳み込みニューラルネットワーク(CNN)による画像分類を行うKeras公式のサンプルプログラムcifar10_cnn.pyを実行します。このサンプルプログラムでは、画像を10クラスに分類するためのモデルを作成することが出来ます。

Kerasのバージョンを確認の上、対応するサンプルプログラムをダウンロードしてください。

Kerasのバージョンの確認

はじめに、前回インストールしたKerasのバージョンを確認します。

まず、Anacoda Promptにて以下のコマンドを実行してください。「py37」は前回作成した仮想環境の名前です。

activate py37

仮想環境「py37」が有効になり、Anacoda Promptに「(py37)」のように仮想環境名が表示されます。

次に、以下のコマンドを実行し、インストールされているライブラリのバージョンを確認してください。

conda list keras

kerasと名のつく複数のライブラリのバージョンが表示されますが、Nameに「keras」と表示されている行のVersionの値がインストールされたKerasのバージョンです。筆者の環境では、keras 2.3.1がインストールされていることがわかります。

図1

サンプルプログラムのダウンロード

確認したKerasのバージョンに対応するサンプルプログラムをダウンロードします。

はじめに、以下のサイトにアクセスしてください。

https://github.com/keras-team/keras

次に、「Branch:master」ボタンをクリックし、ポップアップで表示された画面の「Tags」タブから先ほど確認したKerasのバージョンをクリックして選択してください。Kerasのバージョンに適したソースコードに切り替わります。

図2

最後に、緑色の「clone or download」ボタンをクリックし、ポップアップで表示された画面の、「Download ZIP」ボタンからソースコードをダウンロードし、解凍してください。

本記事では、解凍したexamplesフォルダの下の、cifar10_cnn.pyという名前のソースコードを使用して画像分類を行います。

サンプルプログラムの処理の流れ

cifar10_cnn.pyは、画像をairplaneやautomobileなどの10クラスに分類(正確には、それぞれのクラスに該当しそうか、程度を表すスコアを計算)するCNNモデルを学習、評価するサンプルプログラムです。

ここではディープラーニングによる画像分類を行う流れを、keras 2.3.1版のソースコードを用いて説明します。データセットの読み込みと前処理を行った上で、畳み込みニューラルネットワークを定義し、学習、モデル保存、性能評価を行います。

Kerasの他のバージョンにおいても、関数の引数名等の違いはありますが、処理の流れは同じです。

1CIFAR10データセットの読み込み

必要なパッケージのインポートや変数定義を行った後、26行目にて、CIFAR10データセットを読み込んでいます。

図3

CIFAR10の学習用データを(x_train, y_train)に、評価用データを(x_test, y_test)にそれぞれ読み込みます。1つ目の要素であるx_train、x_testはそれぞれ学習用、評価用の画像データであり、2つ目の要素であるy_train、y_testは対応するラベル(画像が、分類対象の10クラスのうちどのクラスに該当するかを示すクラス番号)です。

初回実行時はデータセットのダウンロードのために時間がかかることがありますが、2回目以降はダウンロード済みのデータセットの読み込みのみが行われるため高速に実行されます。

(補足)
CIFAR10は、カラー画像と対応するラベルの対で構成されるデータセットです。ラベルは、airplaneやautomobileなどの人工物とdogやcatなどの生物を含む10クラスです。1枚の画像サイズが32×32と小さく扱い易いため、機械学習の分野では広く使われています。学習用データとして50000枚、評価用データとして10000枚の画像が用意されています。

CIFAR10データセットは以下のサイトにて公開されており、10種類のラベル名と画像の一部を確認できます。
https://www.cs.toronto.edu/~kriz/cifar.html

図4

2学習のための前処理

読み込んだ画像とラベルデータに対して、学習に用いるための前処理を行っています。

  • 画像データの正規化: 66-69行目にて、画像が格納されている変数x_train, x_testの画素値を正規化(0-255の範囲の整数値配列から、0-1の範囲の小数値配列に変換)しています。
図5
  • ラベルデータのワンホット化: 32-33行目にて、データごとの正解ラベル(クラス番号)が格納されている変数y_train, y_testを、ワンホット表現(正解ラベルのクラス番号に対応する成分のみ1、それ以外の成分は0の値を持つ10次元のベクトル)に変換しています。
図6

3畳み込みニューラルネットワークの定義

35-56行目で、Sequentialクラスを用いて、畳み込みニューラルネットワーク(CNN)の構造を定義しています。

図7

Kerasでは、Sequentialクラスを使用することで、データが流れる順に畳み込み層や全結合層といった層をつないでいく形式で、ニューラルネットワークの構造を定義することができます。

(補足)
Kerasでは、ニューラルネットワークの構造を定義するために、SequentialクラスとModelクラスの2種類が用意されています。畳み込み層や全結合層が直線状につながるネットワーク構造の場合は、今回のサンプルプログラムのようにSequentialクラスを使用します。Modelクラスを使用すると、直線状につながるネットワーク構造はもちろん、より複雑な構造のネットワークも定義できます。

SequentialクラスとModelクラスは、どちらも共通の属性や関数を持ち、ニューラルネットワークの学習や評価を同様の記述で行うことが出来ます。

また、59-64行目にて、Sequentialクラスのcompile関数を使って、最適化アルゴリズム(optimizer)や学習に使用する損失関数(loss)、学習には使用せず性能確認用に使用する評価関数(metrics)を設定しています。ここでは最適化に使用するアルゴリズムとしてRMSpropを、損失関数として交差エントロピーを、評価関数として正解率(accuracy)を設定しています。

図8

4学習

このサンプルプログラムでは、20行目において定義されている変数data_augmentationの値によって、学習用データに対するデータ拡張を行うかどうかを切り替え可能で、Trueに設定されています。data_augmentationの値によって、学習の方法が次のように切り替わります。

fit関数による学習

data_augmentationの値がFalseの場合、データ拡張を行わずに、前処理を施した学習用データをそのまま学習に使用します。サンプルプログラムでは、73-77行目にてSequentialクラスのfit関数により学習を行っています。

図9
fit_generator関数による学習

data_augmentationの値がTrueの場合、前処理を施した学習用データに対してランダムにデータ拡張を行ったデータを作成し、学習に使用します。学習に使用するデータを生成するジェネレータ(外部からデータを要求されるたびに処理が走り新しいデータを作成するもの)を用意し、そのジェネレータをSequentialクラスのfit_generator関数の引数に与えることで、ジェネレータが生成するデータを使用して学習することができます。

サンプルプログラムでは、81-108行目にて、データ拡張用のジェネレータを作成するためのImageDataGeneratorクラスのインスタンスを作成します。さらに115-119行目にて、このクラスのflow関数によって生成したジェネレータをfit_generator関数の引数に指定することで、データ拡張を行ったデータを使用した学習を行えます。紛らわしい名前ですが、ImageDataGeneratorクラス自体はジェネレータではないことに注意してください。ImageDataGeneratorクラスのflow関数によりジェネレータが生成されます。このため、fit_generator関数の引数には、ImageDataGeneratorクラスのインスタンスではなく、flow関数の戻り値を指定します。

fit_generator関数は、データ拡張以外にも様々なケースで利用可能です。例えば、一度に全データをメモリに格納することができない大量のデータを使用して学習したい場合にも利用できます。バッチ単位で毎回ファイルを読み込み、学習用データを生成するジェネレータを定義することで、必要なメモリの量を抑えつつ大量のデータを学習することができます。

図10

5学習したモデルの保存

学習後、122-125行目にて、学習したモデル(ニューラルネットワークの構造と各パラメータの重み)を保存しています。

図11

保存したモデルは、keras.modelsモジュールのload_model関数を使用して読み込むことで、別のプログラムから利用することができるようになります。記述方法は後程説明します。

6評価

最後に、129-131行目にて、学習に使用していない評価用データを使ってモデルの性能を確認します。

Sequentialクラスのevaluate関数により、損失関数と評価関数の値を計算することが出来ます。

今回のサンプルプログラムでは、損失関数として交差エントロピーが、評価関数として正解率(accuracy)が計算されます。これらは、compile関数(62-64行目)の引数により指定した関数の評価値になります。compile関数については「3: 畳み込みニューラルネットワークの定義」にて説明を行っています。

図12

サンプルプログラムの実行

Anacoda Promptにて仮想環境を有効にし、カレントディレクトリをcifar10_cnn.pyファイルが存在するディレクトリに変更して、以下のコマンドを実行します。

python cifar10_cnn.py

データセットの読み込みから前処理、学習、評価までの一連の処理が実行されます。筆者の環境では、実行に20分程度かかりました。評価用データに対する損失関数(Test loss)と正解率(Test accuracy)の値が表示されたら実行終了です。

図13

筆者の環境では、損失関数の交差エントロピーの値は約0.716、正解率は約77.4%でした。乱数のシードを固定していないため、この結果は毎回変わります。

任意の画像に対する画像分類

サンプルプログラムcifar10_cnn.pyには、自分のPCにある任意の画像に対して画像分類を行う機能がありません。ここでは、cifar10_cnn.pyで作成、保存した学習済みモデルを使って画像分類を行うプログラムを作成します。

パッケージのインストール

画像ファイルを読み込むため、Pillowパッケージを使用します。

Anacoda Promptにて仮想環境を有効にした状態で、以下のコマンドを実行することで、Pillowパッケージをインストールすることができます。

conda install pillow

なお、Pythonスクリプトからは、pillowではなくPILという名前でimportを行います。

画像分類用プログラムの実装

cifar10_cnn.pyで作成、保存した学習済みモデルと、分類したい画像を読み込み、画像分類を行います。

1学習済みモデルの読み込み

keras.modelsモジュールのload_model関数を使用し、cifar10_cnn.pyで作成、保存した学習済みモデルのニューラルネットワーク構造と重みを読み込みます。

図14

2画像の読み込みおよび前処理

PillowパッケージのImageクラスを使用して画像を読み込み、学習済みモデルの入力サイズ(=今回の場合はCIFAR10の画像サイズである32x32)に合わせるリサイズを行った後、学習時の前処理と同様に、画像データの正規化を行います。

図15

3画像分類

Sequentialクラスのpredict関数により、入力した画像の各クラスごとのスコアを算出し、画像分類を行います。

図16

プログラム全体

筆者が作成した、画像分類を行うプログラムpredict.pyは下記のリンクからダウンロード可能です。Python 3.7.6, tensorflow 2.0.0, keras 2.3.1, pillow 7.0.0 で動作を確認しています。

predict.py(ZIP/2KB)

以下のように、実行引数で分類する画像と学習済みモデルを指定する仕様です。image_pathに画像のファイルパスを、MODEL_PATHに学習済みモデル(.h5ファイル)のファイルパスを指定して実行してください。

usage: predict.py [-h] [--model-path MODEL_PATH] image_path

positional arguments:
  image_path: 画像分類を行いたい画像のパス

optional arguments:
  -h, --help: ヘルプの表示
  --model-path MODEL_PATH:
      学習済みモデル(.h5ファイル)のファイルパス。
      デフォルトは「./saved_models/keras_cifar10_trained_model.h5」。

画像分類結果

筆者の環境でcifar10_cnn.pyプログラムで学習を行い、評価用に用意した3枚の画像に対して分類を行った結果を以下に示します。

  • * 前述の通り乱数のシードを固定していないため、分類結果は再現されないことがあります。

犬(分類成功)

図17
図18

犬の分類に成功しました。スコアを見ても、自信満々で犬と判定されたことがわかります。

トラック(分類成功)

図19
図20

トラックの画像も、正しく分類できました。スコアを見ると、次点で車と予測されており、妥当な結果となりました。

シカ(分類失敗)

図21
図22

シカの画像を分類してみたところ、シカの特徴である角がないためか、馬と誤判定されました。スコアを見ると、次点でシカ、その次は犬と予測されたことがわかります。

おわりに

Keras公式のサンプルプログラムを実行し、画像分類を試してみました。Kerasを使うことで、ニューラルネットワークの定義や学習を行うプログラムを直観的に実装できることがおわかりいただけたかと思います。

ダウンロードしたexamplesフォルダには、今回使用したcifar10_cnn.py以外にも多くのサンプルコードがあります。例えば、cifar10_resnet.pyでは、Modelクラスを使ってより複雑なニューラルネットワークを定義しています。この記事とこれらのサンプルコードを参考に、Kerasの実装への理解を深め、ディープラーニングエンジニアの第一歩を踏み出してみましょう。