実践型AIプログラミング特講#26

実践型AIプログラミング特講#26

今回も徐々に難易度を上げて、より発展的な課題に取り組んでみましょう。ある程度の画像は分類することができましたが例えば車を認識して車と判別してくれるアルゴリズムを組んでみましょう。前回の数字を認識するアルゴリズムを未学習の方は前回の記事を是非ご確認ください。

 写真に写った物体を認識しよう

写真に何が写っているのかを認識するプログラムを作ってみます。この物体認識のたに、CIFAR-10 というデータセットを利用します。この画像データセットには、飛行機や車、鳥·ネコなどの10 カテゴリーの写真6万枚があります。ディープラーニングでこれらを判別してみましょう。

CIFAR-10 とは?

約 8000万枚の画像が「80 Million Tiny Images」という Web サイトで公開されています。そこから、6万枚の画像を抽出し、ラベル付けしたデータセットが『CIFAR-10』です。画像は6万枚もあり、フルカラーなのですが、画像サイズは32 × 32 ピクセルと小さなサイズの画像となっています。以下のURL で公開されています。

The CIFAR-10 dataset

[URL] https://www.cs.toronto. edu/”kriz/cifar.html

CIFAR-10 のデータセットの特徴をまとめると以下のようになります。

  • 合計6万枚(学習用5万枚/テスト用1万枚)の画像とラベル
  • 画像サイズは 32 × 32 ピクセル
  • フルカラー (RGBの3チャンネル)

CIFAR-10 をダウンロードしよう

Keras には、CIFAR-10 のデータをダウンロードする機能が備わっています。Jupyter Notebook などで、以下のプログラムを実行してみましょう。CIFAR-10 のデータをダウンロードできます。

from keras.datasets import cifar10

(X_train, y_train), (X_test, y_test)=cifar10.load_data()

Jupyter Notebook でダウンロードしたデータを確認してみましょう。以下のコードを実行すると、

画像とそれが何を表すのか、40個のサンプルを表示します。

import matplotlib.pyplot as plt

from PIL import Image

plt.figure (figsize=(10, 10))

labels=[“airplane”, “automobile”, “bird”, “cat”, “deer”, “dog”, “frog”,

“horse”, “ship”, “truck”]

for i in range (0, 40):

im = Image.fromarray (X_train[i])

plt.subplot (5, 8, i + 1)

plt.title(labels [y_train[i] [0]])

plt.tick_params(labelbottom=”off”, bottom=”off”) # x 軸をオフ

plt.tick_params(labelleft=”off”,left=”off”) # y 軸をオフ

plt.imshow (im)

plt.show ()

プログラムを実行してみると、以下のように表示されます。具体的な配列データも確認してみましょう。X_train の値を表示すると、次のようになっています。ここから、1枚の画像が三次元の配列で構成されていることがわかります。つまり、CIFAR-10 のデータセットは、10クラスにわかれたさまざまな物体の画像を学習し、未知の画像を与えたときに、何が映り込んでいるかを判定する分類問題です。

ICIFAR:10 の分類問題をMLPで判別してみよう

それでは、前節と同じように多層パーセプトロン(MLP) のアルゴリズムで、この分類問題を解いてみましょう。

import matplotlib.pyplot as plt

import keras

from keras.datasets import cifar10

from keras.models import Sequential

from keras. layers import Dense, Dropout

num_classes = 10

im_rows = 32

im_cols = 32

im_size = im_rows * im_cols * 3

# データを読み込む(*1)

(X_train, y_train), (X_test, y_test)=cifar10.load_data()

# データを一次元配列に変換(*2)

X_train = X_train.reshape(-1, im_size).astype(‘float32’) / 255

X_test = X_test.reshape(-1, im_size).astype (‘float32′) / 255

# ラベルデータをOne-Hot 形式に変換

y_train =keras.utils.to_categorical (y_train, num_classes)

y_test = keras.utils.to_categorical(y_test, num_classes)

# モデルを定義(*3)

model =Sequential ()

model.add (Dense (512, activation=’relu’, input_shape=(im_size,)))

model.add (Dense (num_classes, activation=’softmax’))

# モデルを構築(*4)

model.compile(

loss=’categorical_crossentropy’,

optimizer=’adam’,

metrics=[‘accuracy’])

# 学習を実行(*5)

hist = model.fit(X_train, y_train,

batch_size=32, epochs=50,

verbose=1,

validation_data=(X_test, y_test))

# モデルを評価(*6)

Score = model.evaluate(X test, y_test, verbose=1)

print(‘正解率 =’, score [1], ‘loss=’,score [0])

# 学習の様子をグラフへ描画(*7)

plt.plot (hist.history [‘accuracy’])

plt.plot (hist.history [‘val_accuracy’])

plt.title(‘Accuracy’)

plt.legend ([‘train’, ‘test’], loc=’upper left’)

plt.show()

plt.plot (hist.history[‘loss’])

plt.plot (hist.history[‘val_loss’])

plt.title(‘Loss’)

plt.legend ([‘train’, ‘test’], loc=’upper left’)

plt.show ()

 

実行すると、以下のようになりました。正解率は 0.476(約48%) です。それほど良くはありませんが、10種類のクラスへの分類ですから、0.1(10%)以上の値が出れば、デタラメではなく、ある程度判定できていると言えます。それでは、プログラムを詳しく見てみましょう。(※1)の部分では、CIFAR-10 の画像データを読み込みます。(※2)の部分では、データを一次元の配列に変換します。ラベルは、One-Hot 形式に変換しておきます。(※3)で簡単なMLP のモデルを定義、(※4)で構築、(※5)で学習を行います。最後に(※6)の部分で、テストデータを用いて評価結果を調べます。(※7)では、学習の様子をグラフに描画します。ちなみにプログラムは、前節のMLP とほとんど同じになっていることが確認できるでしょう。つまり、どんな画像データであれ、一次元の配列データに変換しさえすれば、MLP のモデルを利用してディープラーニングが実践できることを表しています。

CIFAR-10 の分類問題を CNN で判別してみよう

MLP を使った分類では 0.476(約48%)の正解率だったので、2回に1回以上は期待と違う答えが出ることになります。そこで次に、畳み込みニューラルネットワーク (CNN) を使って、分類問題を解いてみましょう。前節でもそうでしたが、CNNを使うと実行に時間はかかりますが、MLPよりも高い精度を出すことが期待できます。それでは、さっそくプログラムを作ってみましょう。とは言え、せっかく CNN を使ってプログラムを作り直すので、前回よりも凝ったモデルを採用してみましょう。

import matplotlib.pyplot as plt

import keras

from keras.datasets import cifar10

from keras.models import Sequential

from keras. layers import Dense, Dropout, Activation, Flatten

from keras.layers import Conv2D, MaxPooling2D

num_classes = 10

im_rows = 32

im_cols = 32

in_shape

(im_rows, im_cols, 3)

 

# データを読み込む(*1)

(X_train, y_train), (X_test, y_test)=cifar10.load_data()

# データを正規化(*2)

X_train =X_train.astype (‘float32’) / 255

X_test =X_test.astype (‘float32′) / 255

# ラベルデータを One-Hot 形式に変換

y_train = keras.utils.to_categorical (y_train, num_classes)

y_test = keras.utils.to_categorical(y_test, num_classes)

# モデルを定義(*3)

model =Sequential ()

model.add (Conv2D(32, (3, 3), padding=’same’,

input_shape=in_shape))

model.add (Activation(‘relu’))

model.add (Conv2D (32, (3, 3)))

model.add (Activation (‘relu’))

model.add (MaxPooling2D(pool_size=(2, 2)))

model.add (Dropout (0.25))

model.add (Conv2D (64, (3, 3), padding=’same’))

model.add (Activation (‘relu’))

model.add (Conv2D(64, (3, 3)))

model.add(Activation (‘relu’))

model.add (MaxPooling2D(pool_size=(2, 2)))

model.add (Dropout (0.25))

model.add (Flatten())

model.add (Dense (512))

model.add (Activation(‘relu’))

model.add (Dropout (0.5))

model.add (Dense (num_classes))

model.add(Activation(‘softmax’))

 

 

# モデルを構築(*4)

model.compile(

1oss=’categorical_crossentropy’,

optimizer=’adam’,

metrics=[‘accuracy’])

学習を実行(* 5)

hint = model.fit(X_train, y_train,

batch_size=32, epochs=50,

verbose=1,

validation_data=(X_test, y_test))

# モデルを評価(* 6)

Score=model.evaluate(X_test, y_test, verbose=1)

print (‘ 正解率=’, score[1], ‘loss=’, score[0])

# 学習の様子をグラフへ描画(*7)

plt.plot (hist.history[‘accuracy’])

plt.plot (hist.history[‘val_accuracy’])

plt.title(‘Accuracy’)

plt.legend ([‘train’, ‘test’], loc=’upper left’)

plt.show ()

plt.plot (hist.history[‘1loss’])

plt.plot (hist.history [‘val_loss’])

plt.title(‘Loss’)

plt.legend ([‘train’, ‘test’], loc=’upper left’)

plt.show ()

 

プログラムを実行してみると、以下のように表示されます。正解率は 0.7894(約 79%)です。MLPの精度、0.476に比べたらずいぶん改善しました。詳しくプログラムを見てみましょう。(※1)の部分では、先のプログラムと同じように、CIFAR-10のデータを読み込みます。(※2)の部分では、正規化を行います。CNN では、MLP と違って一次元の配列に変換する必要はなく、縦×横× RGB 色空間の三次元のデータをそのまま与えることができます。(※3)の部分では、CNNのモデルを定義します。CIFAR-10のデータセットは、手書き数字の判定よりもずっと複雑になりますので、前回のCNNよりもたくさん畳み込みとプーリング処理を行うようなネットワークを構築します。Keras のプログラムが明快なのは、model.add) の処理を順に追っていくだけで、どのようにレイヤーが積み重なっているのかが明確である点です。この部分を見ていくと、畳み込み、畳み込み、プーリング、ドロップアウト、畳み込み、畳み込み、プーリング、平滑化と、何層にもわたる構造を記述しています。このモデルですが、2014年に行われた画像認識コンテスト「ILSVRC-2014」で優秀な成績を収めた VGG のチームが利用したモデルに似たもので、VGG like と呼ばれます。そして、(※4)でモデルを構築して、(※5)で学習を実行、(※6)でモデルを評価して、(※7)で学習の推移をグラフで表示するという一連の流れになっています。

学習結果を保存してみよう

ところで、CNNでデータを学習させるには、非常に長い時間がかかったことでしょう。毎回、データを学習させるのはたいへんです。そこで、前章の scikit-learn のときと同じように、学習結果の重みデータをファイルに保存する方法を学びましょう。データを保存するには、モデルに備わっている save_weights0 メソッドを利用します。先ほどのCNNでデータを学習するプログラム「cifar10-cnn.py」をJupyter Notebook で実行したら、以下のコードを実行して、重みデータをファイルに保存してみましょう。

model.save_weights(‘cifar10-weight.h5’)

保存したデータを読み込むには、以下のようにload_weights0 メソッドを利用します。

model.load_weights(‘cifar10-weight.h5’)

自分で用意した画像を判定させてみよう

それでは、自分で用意した自動車の画像を正しく判定できるかどうか試してみましょう。ここで判定するのは、以下の画像です。では、ここまでの手順を振り返り重みデータを保存してみましょう。たとえば、上記で MLPで学習を行う「cifar10-mlp.py」を、Jupyter Notebook 上で実行した後で、以下のプログラムを実行し、重みデータをファイルに保存しましょう。

model.save_weights(‘cifar10-mlp-weight.h5’)

次に、保存したMLP の重みデータを読み込んで、サンプル画像が CIFAR-50 でどのカテゴリーに当てはまるのか判定させてみましょう。以下のプログラムをJupyter Notebook 上で実行してみましょう。

import cv2

import numpy as np

labels =[“airplane”, “automobile”, “bird”, “cat”, “deer”, “dog”, “frog”

“horse”, “ship”, “truck”]

im_size = 32 * 32 * 3

 

# モデルデータを読み込み(*1)

model.load_weights(‘cifar10-mlp-weight.h5’)

# OpenCV を使って画像を読み込む(*2)

im = cv2.imread (‘test-car.jpg’)

# 色空間を変換して、リサイズ

im = cv2.cvtColor(im, cv2.COLOR_BGR2RGB)

im = cv2.resize (im, (32, 32))

plt.imshow (im) # 画像を出力

plt.show ()

# MLP で学習した画像データに合わせる(*3)

im = im.reshape (im_size).astype (‘float32’) / 255

# 予測する(* 4)

r=model.predict (np.array ([im]), batch_size=32,verbose=1)

res = r[0]

# 結果を表示する(*5)

for i, acc in enumerate(res):

print (labels [i], “=”, int (acc * 100))

print (“—“)

print (“予測した結果 =”, labels [res.argmax()])

プログラムを実行すると……正しく「automobile( 自動車)」を判定できました。せっかくなので、自動車以外に各カテゴリーに当てはまる確率も一緒に表示してみます。

プログラムを確認してみましょう。(※1)の部分では、モデルデータを読み込みます。(※2)の部分では、OpenCV を使って画像を読み込みます。OpenCVのimread) 関数は、NumPy の配列形式で値を返すので、扱いやすいです。しかし、OpenCV の色空間は、BGR(青緑赤)の順番なので、RGB(赤緑青)に変換します。次に、MLP で画像を学習する際には、各画像データを32× 32 × 3(=3072)個の配列に変形してから学習しました。そのため、(※3) の部分でも同じ形式の配列に変形します。(※4)の部分で、モデルの predict() メソッドを利用して、画像を予測します。(※5)の部分で、予測結果を表示します。予測結果の配列 res は最終的なクラス数である 10個の配列になっていて、配列の最大値を持つ値が予測結果となります。argmax() メソッドを使うことで、何番目の配列がもっとも大きな値なのかを調べることができます。argmax0 の動きを確認してみましょう。画像サイズも32 × 32 ピクセルにリサイズします。

import numpy as np

print (np. array([1, 0, 9, 3]).argmax ()) # 結果→2

print(np.array([1, 3, 2,9]),argmax())# 結果→3

print (np. array([9, 0, 2, 3]).argmax ()) # 結果→0

なお、CNNのモデルを利用する場合でも、同じような方法で重みデータを保存できます。また、predict0 メソッドを使うことで、自分で用意した画像を判定させることができます。

応用のヒント

ここでは、あらかじめ用意された CIFAR-10 のデータセットを使って、MLP/CNN のアルゴリズムを試してみました。CNN を使うなら、物体認識のような複雑な分類問題も、高い精度で行うことができます。素材データを自分で用意すれば、人間が目視で確認していた物体も、コンピューターで判定できるでしょう。

column

どういうときにディープラーニングを使うのか?さて、ここまでの部分でディープラーニング(深層学習)について具体的な手順を紹介しました。とくに、プログラムの実行時間は、かなり長くなったと思います。それではどのような場面でディープラーニングを利用するのでしょうか。それは、高い精度が必要とされる場面でしょう。そもそも、ディープラーニングも機械学習の一分野です。ですから、scikit-learn を使った SVM やランダムフォレストのアルゴリズムを試してみて、十分精度が出るようなら、ディープラーニングを使うまでもありません。どうにも良い結果が出ない場合、とぐに時間をかけてでも、より高い精度が必要な場合にディープラーニングを試すとよいでしょう。

column

長時間の学習後でガッカリしないためになお、マシンのスペックにもよりますが、ディープラーニングにおいてデータの学習にはかなりの時間がかかることでしょう。しかし、学習を行う ftメソッドの後に書いたプログラムにうっかりミスがあり、文法エラーで長時間の学習が水泡に帰すということもあります。長時間の学習が無駄になったときのガッガリ感は筆舌に尽くし難いものがあります。そんなガッカリ体験をしないように、まず最初にftメソッドのepochs に与える値を1とか2にした上で実行してみましょう。すると、動作に問題がないことを確認できますので、その後でepochs の値を大きな値にして試すと良いでしょう。

この節のまとめ

CIFAR-10 データセットを使った物体認識のような分類問題も MLP/CNN のアルゴリズムを利用できる学習済みの重みデータを save_weights() メソッドを使ってファイルに保存できる学習済みデータは精度を調べるだけでなく、自分で用意した画像も分類できる。

 

プログラミングカテゴリの最新記事