Pythonプログラミング(ディープラーニングによる画像の分類・演習)

(このページは目下作成中)

このページでは、クラスで分担して、ラベル付きの画像データを収集し、それを使って画像をラベル毎に分類できるようにCNNを学習させる。 学習した結果は、教員がサーバーに設定し、スマートフォン等で撮影した画像が実際に期待通りに分類できるかを確認する。

大福帳.dcへのサインアップ

学習支援用のウェブアプリ大福帳.dcにアクセスし、サインアップを行う。

ラベル付き画像データの収集

まず、スマートホンで大福帳.dcにログインする。科目への受講登録を済ませておくと、その科目の以下のような「大福帳」が表示される:

上向き矢印のアイコンをタップすると、画像とラベルをアップロードするための画面が開く。 画像を選択し、その画像のラベルを記入した後、画像をアップロードするボタンを押す。 この操作を繰り返すことによって、複数のラベル付き画像データが収集される。

アップロード済みの画像は、画像のアイコンをクリックして確認することができる。 撮り損なった画像やラベルの入力ミスが見つかった場合は、画像の右下のゴミ箱のアイコンをタップすると、削除することができる。

収集したラベル付き画像データのダウンロード

次に、パソコンで大福帳.dcにログインする。画像のアイコンをクリックして登録データを確認し、一番下の 画像をダウンロードするボタンと、 ラベルをダウンロードするボタンをそれぞれ押す。 画像データはZIP形式で一つのファイルにまとめられた状態(ファイル名は "英数字列.zip")でダウンロードされる。 また、ラベルはCSV形式で "英数字列-label.csv" というファイル名が付けられている。

画像はカラーで、全て$128 \times 128$ピクセルにサイズが調整されている。

ニューラルネットワークの学習

Google Colaboratoryにアクセスし、Python3のノートブックを開く。

左側のタブを開き、「ファイル」をクリックする。 マウスを右クリックして、画像データ(英数字列.zip)とラベルデータ(英数字列-label.csv)をそれぞれアップロードする。 「ファイル」の区画にファイルをドラッグ&ドロップしてアップロードすることもできる。

コードセルを挿入し、以下のPythonコードを実行する。ただし、11行目の英数字列の箇所は、データに合わせてあらかじめ変更しておくこと。 必要に応じて、モデルの構成やトレーニングパラメータ等を工夫する。

ラベルに従った画像の分類を行うCNNの例

# coding: utf-8
import zipfile
import csv
import matplotlib.pyplot as plt
from keras.preprocessing.image import array_to_img,img_to_array,load_img
from keras import layers,models
from keras import optimizers
from keras.utils import np_utils
import numpy as np

data_id='英数字列' # この箇所は適宜変更

X_train=[]
Y_train=[]
Y_dict={}

X_test=[]
Y_test=[]

with zipfile.ZipFile(data_id + '.zip') as zipf:
  zipf.extractall('img')

with open(data_id + '-label.csv') as csvfile:
    reader = csv.reader(csvfile, delimiter = ',')
    cnt=0
    for row in reader:
        if cnt>0:
            Y_dict[row[0]]=row[1].strip()
        cnt=cnt+1
        
categories=list(set(Y_dict.values()))
categories.sort()
nb_classes=len(categories)

n=0
for key in Y_dict.keys():
    image=load_img('img/' + key + '.png')
    img_array=img_to_array(image)
    if n>30:  # テスト用のサンプル数を加減するには、この30のところを変更
        X_train.append(img_array)
        Y_train.append(categories.index(Y_dict[key]))
    else:
        X_test.append(img_array)
        Y_test.append(categories.index(Y_dict[key]))
    n=n+1

# convert list to ndarray
X_train = np.array(X_train, dtype=np.float32)
X_test = np.array(X_test, dtype=np.float32)
    
x_train=X_train.astype("float")/255
x_test=X_test.astype("float")/255
y_train=np_utils.to_categorical(Y_train,nb_classes)
y_test=np_utils.to_categorical(Y_test,nb_classes)

model=models.Sequential()
model.add(layers.Conv2D(32,(3,3),activation="relu",input_shape=(128,128,3)))
model.add(layers.MaxPool2D((2,2)))
model.add(layers.Conv2D(64,(3,3),activation="relu"))
model.add(layers.MaxPool2D((2,2)))
model.add(layers.Conv2D(128,(3,3),activation="relu"))
model.add(layers.MaxPool2D((2,2)))
model.add(layers.Conv2D(128,(3,3),activation="relu"))
model.add(layers.MaxPool2D((2,2)))
model.add(layers.Dropout(0.5))
model.add(layers.Flatten())
model.add(layers.Dense(512,activation="relu"))
model.add(layers.Dropout(0.25))
model.add(layers.Dense(nb_classes,activation="softmax"))
model.summary()

json_string=model.to_json()
open("train.json","w").write(json_string)

model.compile(loss="categorical_crossentropy",optimizer="rmsprop",metrics=["acc"])

epochs=30
batch_size=64

stack=model.fit(x_train,y_train,epochs=epochs,batch_size=batch_size,validation_data=(x_test,y_test))

x = range(epochs)
plt.plot(x, stack.history['acc'], label="acc")
plt.title("accuracy")
plt.legend(loc='center left', bbox_to_anchor=(1, 0.5))
plt.show()

plt.plot(x, stack.history['loss'], label="loss")
plt.title("loss")
plt.legend(loc='center left', bbox_to_anchor=(1, 0.5))
plt.show()

model.save_weights("train.hdf5")

score=model.evaluate(x_test,y_test,verbose=0)
print("test loss : ",score[0])
print("test acc : ",score[1])

cnt=0
for cate in categories:
    print(cnt,cate)
    cnt=cnt+1

学習結果の保存

生成した学習モデルは train.json、ネットワークの荷重は train.hdf5というファイルにそれぞれ格納されているので、 後で用いるため、ダウンロードしておく。

また、結果の最後に、カテゴリー番号とラベルの名称が出力されるので、対応関係を控えておく。

動作の確認

モデルと学習済みの荷重データを、教員があらかじめ大福帳.dcのシステムに登録し、受講生にその旨を通知する。

スマートホンで大福帳.dcにログインし、スマートホンのアイコンをタップする。画像を撮影し、 画像を分類するボタンを押すと、少し間をおいて、結果が表示される。 サーバーの容量が限られているので、多人数が一斉にアクセスすると、応答に時間がかかったり、エラーになる場合も想定される。

このとき、サーバー側では、概ね、以下のようなコードが動作している:

from tensorflow.keras import models
from tensorflow.keras.models import model_from_json
from tensorflow.keras.preprocessing.image import array_to_img,img_to_array,load_img
import numpy as np

model=model_from_json(open("train.json").read())
model.load_weights("train.hdf5")

test_image=("test-image.png")

image=load_img(test_image)
x=img_to_array(image)
x=np.expand_dims(x,axis=0)
f=model.predict(x)
r=f[0]
idx = np.argmax(r)
val = r[idx]
print(idx,val)

icon-pc 練習:画像の分類

この画像分類の仕掛けを使うと、どのような応用が可能になるか、提案しなさい。

そのためには、どのような手順でデータを収集したらよいか、分担体制や作業手順、作業の上での注意点をまとめなさい。

CNNの性能をさらに高める工夫を施してみなさい。