みなさん,こんにちは。
シンノユウキ(shinno1993)です。
今回は学習済みCNNモデル:VGG16を用いて,一般的な画像の分類を行ってみたいと思います.理論などの説明は割愛し,道具としてこれを使えるようになることを目指します.では行きましょう!
VGG16とは?
VGG16というのは,「ImageNet」と呼ばれる大規模画像データセットで学習された,16層からなるCNNモデルのことです.2014年に発表されました.様々な研究で利用されている,有名な学習済みモデルの1つです.ImageNetで学習されたモデルには他にAlexNet,GoogLeNet,ResNetがあります.
このVGG16に関する論文は以下で公開されています.
VGG16では,出力層(最終的に分類される層)が1000あるため,入力された画像などを1000のクラスに分類することができます.
Kerasで使ってみる
ではさっそく,KerasでVGG16を使ってみましょう.
以下のコードを実行してください.
import numpy as np from keras.applications.vgg16 import VGG16, preprocess_input, decode_predictions model = VGG16(include_top=True, weights='imagenet', input_tensor=None, input_shape=None)
1-2行目では必要なライブラリなどをインポートしています.VGG16はKerasにすでに実装されているため,それを呼び出すことで簡単に使用できます.
3行目で実際にVGG16の学習済みモデルを取り込んでいます.引数の意味は以下の通りです.
引数 | 説明 |
---|---|
include_top | 1000クラスに分類するフル結合層を含むかどうか. True:含む(元の1000分類に使う場合はこちら) False:含まない(カスタマイズする場合はこちら) |
weights | 重みの種類 imagenet:ImageNetを使って学習した重み None:ランダム |
input_tensor | モデル画像を入力する場合に使用 任意の画像データ:それを使用 None:使用しない |
input_shape | 入力画像の形状を指定 任意の形状:それを使用 None:(224, 224, 3)が使用される |
ではせっかくなのでモデルの中身をみてみましょう.以下のコードでその中身を見ることができます.
model.summary()
以下のようなモデルの構造が表示されるかと思います.
Layer (type) Output Shape Param # ================================================================= input_1 (InputLayer) (None, 224, 224, 3) 0 _________________________________________________________________ block1_conv1 (Conv2D) (None, 224, 224, 64) 1792 _________________________________________________________________ block1_conv2 (Conv2D) (None, 224, 224, 64) 36928 _________________________________________________________________ block1_pool (MaxPooling2D) (None, 112, 112, 64) 0 _________________________________________________________________ block2_conv1 (Conv2D) (None, 112, 112, 128) 73856 _________________________________________________________________ block2_conv2 (Conv2D) (None, 112, 112, 128) 147584 _________________________________________________________________ block2_pool (MaxPooling2D) (None, 56, 56, 128) 0 _________________________________________________________________ block3_conv1 (Conv2D) (None, 56, 56, 256) 295168 _________________________________________________________________ block3_conv2 (Conv2D) (None, 56, 56, 256) 590080 _________________________________________________________________ block3_conv3 (Conv2D) (None, 56, 56, 256) 590080 _________________________________________________________________ block3_pool (MaxPooling2D) (None, 28, 28, 256) 0 _________________________________________________________________ block4_conv1 (Conv2D) (None, 28, 28, 512) 1180160 _________________________________________________________________ block4_conv2 (Conv2D) (None, 28, 28, 512) 2359808 _________________________________________________________________ block4_conv3 (Conv2D) (None, 28, 28, 512) 2359808 _________________________________________________________________ block4_pool (MaxPooling2D) (None, 14, 14, 512) 0 _________________________________________________________________ block5_conv1 (Conv2D) (None, 14, 14, 512) 2359808 _________________________________________________________________ block5_conv2 (Conv2D) (None, 14, 14, 512) 2359808 _________________________________________________________________ block5_conv3 (Conv2D) (None, 14, 14, 512) 2359808 _________________________________________________________________ block5_pool (MaxPooling2D) (None, 7, 7, 512) 0 _________________________________________________________________ flatten (Flatten) (None, 25088) 0 _________________________________________________________________ fc1 (Dense) (None, 4096) 102764544 _________________________________________________________________ fc2 (Dense) (None, 4096) 16781312 _________________________________________________________________ predictions (Dense) (None, 1000) 4097000 ================================================================= Total params: 138,357,544 Trainable params: 138,357,544 Non-trainable params: 0
畳み込み層(convolution2dの部分)が13層,全結合層(fc1, fc2, predictions)が3層で全部で16層であることがわかります.畳み込み層やそれを集約するプーリング層で画像の特徴を見出し,それを全結合層で分類するという構造をしています.
画像を認識してみよう!
では早速,VGG16を用いて画像認識をしてみましょう.
なお,今回の使用しているコードは以下の記事を参考にしました.
分かりやすい記事で,私の記事でいまいち?な場合はぜひご参照ください!
from keras.applications.vgg16 import VGG16, preprocess_input, decode_predictions from keras.preprocessing import image import requests import numpy as np model = VGG16(include_top=True, weights='imagenet', input_tensor=None, input_shape=None) #画像をダンロードするための関数 def download_img(url, file_name): r = requests.get(url, stream=True) if r.status_code == 200: with open(file_name, 'wb') as f: f.write(r.content) if __name__ == '__main__': #画像のダウンロード url = 'https://cdn.pixabay.com/photo/2016/03/05/19/02/hamburger-1238246_1280.jpg' file_name = 'hamburger.jpg' download_img(url, file_name) img = image.load_img(file_name, target_size=(224, 224)) # 読み込んだPIL形式の画像をarrayに変換 ary = image.img_to_array(img) #サンプル数の次元を1つ増やし四次元テンソルに ary = np.expand_dims(ary, axis=0) #上位5を出力 preds = model.predict(preprocess_input(ary)) results = decode_predictions(preds, top=5)[0] for result in results: print(result)
では,コードを解説していきます.
1-5行目では必要なライブラリをインポートし,5行目で先述したVGG16を学習済みモデルとしてインポートしています.
9-13行目では画像を今回画像認識に使用する画像をダウンロードするための関数を定義しています.画像をダウンロードするためのURLと,保存するためのファイル名を引数とした関数です.ちなみに,今回選択した画像は以下のハンバーガーの画像です!(かなりわかりやすい,ノイズのない良い画像ですね)
https://cdn.pixabay.com/photo/2017/02/20/18/03/cat-2083492_1280.jpg
16-33行目が今回の画像認識のメインの部分です.
18-21行目で画像のダウンロードを行っています.URLと保存するファイル名を指定し,先ほど定義したdownload_img関数を実行しています.そして保存されたファイルをimage.load_img関数でロードしています.画像サイズはVGG16のデフォルサイズである224×224を指定します.
24行目では読み込んだ画像を配列形式に変換しています.このように配列形式に変換することで機械学習に画像を投入することができるようになります.
27行目では4次元テンソルに変換しています.VGG16で画像を入力する際には以下の4つの次元をもったテンソルに変換する必要があります:
(samples, rows, cols, channels)
元のaryはsamplesの次元を持っていないので,その次元を追加しています.今回は画像を1枚しか使わないので,これで問題ありません.
30-33行目ではモデルに画像を入力し,予測させ,その結果を出力しています.30行目ではモデルに画像を入力しています.そして,decode_predictionで予測結果を文字列に変換しています.top=5とすること予測された上位5つを返してくれます.そして32行目で上位5つを1つずつ出力しています.結果,以下の5つが出力されるかと思います.
('n07697313', 'cheeseburger', 0.99998677) ('n07693725', 'bagel', 1.2767959e-05) ('n02776631', 'bakery', 3.881851e-07) ('n07697537', 'hotdog', 9.392271e-08) ('n07613480', 'trifle', 7.705837e-09)
1位がチーズバーガーになっています.99.9%の確率となっていますので,かなり強く区別していることがわかりました!
まとめ
今回は学習済みモデルのVGG16を持ちいて画像認識をしてみました.面倒な学習が不要ということで,この程度の精度でよければ非エンジニアでも簡単に使用できるのではないでしょうか.近々,このVGG16をFine-tuningする方法をアップしてみたいと思います.ご期待ください!