「ゼロから作るDeepLearning」を読んでざっくり機械学習の概要を把握しつつ、フレームワークを使わずほぼnumpyオンリーでプリキュアの画像認識を作ったことがあります。しかしながら精度は60%が関の山といったところだったのでここらでフレームワークを使って画像認識のプログラムを作成しようと思い立ちました。
機械学習のフレームワークといってもCaffeやらChainerやらTensorFlowやらといろいろな種類がありますが、とりあえずKerasを使ってみることにしました。理由は単純にとっつきやすそうだったからです。
この記事のコードを動かすためには以下の準備が必要になります。
・Python3を実行できる環境(Anaconda推奨)
・open cv
・numpy
・keras
・訓練データ
他にも色々あるかもしれませんが正直この辺の環境構築は調べながら適当に作ったため自信ないです。何かしらエラーが出たら適当に調べて解決してください。意外と何とかなります。
機械学習は何をやるにしてもまずデータが必要です。
ということでKerasに突っ込むためのデータを作るプログラムから。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
|
""" 学習用のデータセットを作成するモジュール """ import os import cv2 as cv import numpy as np data_dir_path = "./train_image/" categories = os.listdir(data_dir_path) categories.sort() x_target = [] x_label = [] f = open('label.txt', 'a') label_number = 0 for category in categories: # 分類フォルダに入ってるファイル一覧を取得 files = os.listdir(data_dir_path + category) for file in files: if file.endswith('.png'): image_path = data_dir_path + category + '/' + file image = cv.imread(image_path) # imread失敗時は無視してループ続行 if image is None: continue image = cv.resize(image, (32, 32)) image = image.transpose(2, 0, 1) image = image/255.0 x_target.append(image) # ラベルを保存 x_label.append(label_number) # カテゴリがどのラベル番号に対応するかtxtファイルに出力する txt = category + ":" + str(label_number) + "\n" f.writelines(txt) # ラベルの値を更新 label_number += 1 f.close() # numpy配列に変換してデータセットとラベルを保存 label_arr = np.array(x_label) np.save('x_label.npy', label_arr) data_arr = np.array(x_target) np.save('x_train.npy', data_arr) |
以下、上記のコードの解説。
・9行目~11行目
data_dir_pathに設定しているディレクトリはこんな構造です。

aquaフォルダの中にはキュアアクアの画像が沢山入っていて、berryフォルダにはキュアベリーの画像が沢山入っていて…みたいな感じです。
画像の収集とフォルダ分け?それは手作業でやるんだよ!!!
18行目~43行目
分類ごとの訓練画像が入ってるパスを作成。
リサイズ、正規化、次元を入れ替え、正規化をしてリストに突っ込んでます。テキストファイルに何か書き込んでるのはどの分類がどのラベル番号に対応するかを一応テキストファイルとして出力しています。aqua:0、berry:1、みたいな感じでその分類の正解ラベルは何番なのかをメモってます。
28行目はimreadが失敗した時、そのまま31行目以降の処理に突っ込んでいくとエラーになるため入れた処理。読み込み失敗した画像をテキストファイルに出力する様にした方がよかったかもしれないですな。
47行目~52行目
作ったリストをnumpy配列に変換してファイルを出力しています。
これでKerasに食わせる画像データとラベルデータができました。
というわけでKerasを使って学習してもらいましょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75
|
""" kerasテスト用プログラム """ import numpy as np import sklearn.cross_validation from keras.callbacks import EarlyStopping from keras.callbacks import LearningRateScheduler from keras.layers.convolutional import Conv2D from keras.layers.core import Activation from keras.layers.core import Dense from keras.layers.core import Dropout from keras.layers.core import Flatten from keras.models import Sequential from keras.optimizers import Adam from keras.optimizers import SGD # シード値を固定 np.random.seed(20171203) images = np.load('x_train.npy') labels = np.load('x_label.npy') # 分類の数 num_class = 29 x_train, x_test, y_train, y_test = sklearn.cross_validation.train_test_split( images, labels) model = Sequential() model.add(Conv2D( 96, kernel_size=(3, 3), padding='same', input_shape=(3, 32, 32))) model.add(Activation('relu')) model.add(Conv2D( 128, kernel_size=(3, 3))) model.add(Activation('relu')) model.add(Dropout(0.5)) model.add(Flatten()) model.add(Dense(1024)) model.add(Activation('relu')) model.add(Dropout(0.5)) model.add(Dense(num_class)) model.add(Activation('softmax')) init_learning_rate = 1e-2 opt = SGD(lr=init_learning_rate, decay=0.0, momentum=0.9, nesterov=False) model.compile( loss='sparse_categorical_crossentropy', optimizer=opt, metrics=["acc"]) early_stopping = EarlyStopping( monitor='val_loss', patience=3, verbose=0, mode='auto') lrs = LearningRateScheduler(0.01) hist = model.fit( x_train, y_train, batch_size=128, epochs=50, validation_split=0.1, verbose=2) model_json = model.to_json() open('model.json', 'w').write(model_json) model.save_weights('weights_param.h5') score = model.evaluate(x_test, y_test, verbose=0) print('Test score:', score[0]) print('Test accuracy:', score[1]) |
以下解説。
19行目~24行目
先ほど作った画像データと正解ラベルを読み込んで訓練用とテスト用のデータに分けています。
x_train…訓練に使う画像群
x_test…テストに使う画像群
y_train…訓練に使う正解ラベル
y_test…テストに使う正解ラベル
といった感じで格納されます。
分類数(num_class)は初代~フレッシュプリキュアまでのプリキュアの変身前、変身後と全然関係ないその他キャラクターなので29になります。プリキュアおじさんじゃないので抜け漏れがあるかもしれませんが文句や苦情は受け付けませぬ。
26行目~51行目
ニューラルネットワークを作ってます。畳み込んで畳み込んでドロップアウトさせて一次元にしてドロップアウトさせて29分類させてます。
この辺もうちょっと詳しいこと説明しようと思ったんですが、機械学習について基本的な知識がないと意味不明なので割愛します。読みましょう、ゼロから作るDeepLearning。お試しなのでベタ書きしてますがこの辺は関数化してmodelを返すようにするとよさげですね。
53行目~67行目
作ったネットワークを用いて訓練させています。
正直この辺はコピペもいいところなので何やってるかは解説したくてもできないのであります。
69行目~71行目
学習した重みと今回作成したニューラルネットワークの情報を保存してます。
73行目~
テスト用の画像群を使って最終的な精度を図っています。
最終的な精度は80%程度でした。雑なデータセットに雑なネットワークにしては中々いいんじゃないでしょうか。フレームワーク使ってなかったときは14分類くらいで精度がMAX60%だったので非常に喜ばしいです。
最後に認識結果を視覚的に分かりやすく出力してくれるプログラムを作りました。

結果は14人中11人正解。中々の精度です、大したプリキュアおじさんだ。
あとやっぱりスプラッシュスターの子とキュアブラックは同じに見えるよね。俺だって間違う。
話は全然変わるんですが本当は「ゼロから作るDeepLearning」とかをamazonアソシエイトで貼りたかったわけですが、
審査を受けたところ「コンテンツ全然ないから審査できねーよハゲ」とあっさり振られてしました。さっさと投稿を充実させてはやくアフィアフィの実の全身広告人間になりたいです。