あさの畑

プログラミングが好きな大学生のブログ。統計学や機械学習の勉強記録と、SIGNATE/Kaggle/AtCoderのお話。

Deep Learningを用いた樹皮画像による樹種同定(Keras, CNN, 転移学習, VGG16)

ディープラーニング(Deep Learning、深層学習)を用いて樹皮の画像から樹種を同定しようという試みのまとめです。

 

全くのゼロからディープラーニングの勉強をした僕の奮闘記はこちら

・前編

【Deep Learning勉強編】僕はDeep Learningに魅せられて勉強を始めた

・後編

【Deep Learning実践編】ひたすら調べて自分でなんとか画像認識をしてみた

 

樹皮の画像で樹木の種類を特定したいと思った理由についてはこちら

Deep Learningを用いて樹皮による樹種同定を行なおうと思ったわけ

 

 

そしてこの記事では総まとめとして全体を振り返りたいと思います。

 

目的

Deep Learningによる画像認識で、樹皮画像からコナラとイチョウを見分ける。

 

※コナラとイチョウを試料として用いた理由は、身近に生育していて写真を集めやすいことと、どちらの樹種も幹が縦に裂けていて樹皮画像から2種を見分けるのはそれなりに難易度が高いことがある。

 

準備した画像データ

僕が撮影した、吉田山(京都市内)とその周辺に生育しているコナラとイチョウの樹皮写真(サイズは2448 x 3264)

 

以下に樹皮写真の一例を示します。

どちらも縦に裂けていますが、慣れればなんとか見分けることができるようになります。 (ちなみにイチョウの樹皮には弾力があるので触ってみれば一瞬でわかるんですけどね、笑)

f:id:gadada:20180531091614j:plain
f:id:gadada:20180531091641j:plain
樹皮写真(左はコナラ、右はイチョウ)

 

方法と結果1

データ

データ画像数(訓練データ、テストデータの合計)はコナラ110枚、イチョウ87枚

画像サイズは128×128

全体の8割を訓練データとして使用

 

実装したCNNモデル

よくわからなかったので簡単なCNNモデルを作ってみました。

from keras.models import Sequential
from keras.layers import Conv2D, MaxPooling2D
from keras.layers import Activation, Dropout, Flatten, Dense
from keras.optimizers import RMSprop

model = Sequential()
model.add(Conv2D(64, 3, input_shape=(128,128,3)))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))

model.add(Conv2D(64, 3))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))

model.add(Flatten())
model.add(Dense(512))
model.add(Activation('relu'))
model.add(Dropout(0.5))
model.add(Dense(2))
model.add(Activation('softmax'))

model.summary()
model.compile(loss='categorical_crossentropy', optimizer=RMSprop(), metrics=['accuracy'])
history = model.fit(x_train, y_train, batch_size=32, epochs=5, validation_split=0.1)

open('bark_model.json', 'w').write(model.to_json())
model.save_weights('bark_weight.hdf5')

score = model.evaluate(x_test, y_test, verbose=0)
print('Test loss:', score[0])
print('Test accuracy:', score[1])

 

精度

正解率:4割程度

うまく学習が進んでいない。

 

方法と結果2

データ

1枚の写真から3枚の正方形画像を切り出し、それぞれにおいて「ランダム水平シフト、ランダム垂直シフト、ランダムズーム、水平方向ランダム反転、垂直方向ランダム反転」により10枚の画像を生成。

よってデータ画像数(訓練データ、テストデータの合計)は、もともとの写真数の30倍であるコナラ3300枚、イチョウ2610枚に増やす。

 

データディレクトリはこんな感じです。

f:id:gadada:20180629081126j:plain

 

画像サイズは224×224

全体の8割を訓練データとして使用

 

実装したCNNモデル

「方法と結果1」で示したモデルと同じものを使用 

 

精度

正解率:4~6割程度

データ数を増やしても学習がうまく進んでいない。

 

方法と結果3

データ数をこれだけ増やしてもうまく学習されない。CNNモデルを改善する必要があると思い、検討した結果、転移学習をしてみることに。VGG16を使いました。

 

転移学習に関して勉強させていただいたサイト

Aidemy「CNNを用いた画像認識」の転移学習ページ

https://aidemy.net/courses/5100

 

人工知能に関する断創録「VGG16のFine-tuningによる17種類の花の分類」

http://aidiary.hatenablog.com/entry/20170131/1485864665

 

どちらもモデルを構築するときにとても参考になりました。 

Aidemyでは「CNNを用いた画像認識」の他にも「Python入門」「機械学習概論」「ディープラーニング基礎」を受講しました。どれも大変わかりやすかったので、1ヶ月と少しという短い時間でも画像認識をできるようになったのだと思います。

 

データ

用いた画像データは「方法と結果2」と同じでコナラ3300枚、イチョウ2610枚

画像サイズは224×224

全体の8割を訓練データとして使用

 

実装したCNNモデル

from keras import optimizers
from keras.applications.vgg16 import VGG16
from keras.models import Sequential, Model
from keras.layers import Dropout, Flatten, Dense, Input

input_tensor = Input(shape=(224,224,3))
vgg16 = VGG16(include_top=False, weights='imagenet', input_tensor=input_tensor)

top_model = Sequential()
top_model.add(Flatten(input_shape=vgg16.output_shape[1:]))
top_model.add(Dense(256, activation='relu'))
top_model.add(Dropout(0.5))
top_model.add(Dense(2, activation='softmax'))

model = Model(inputs=vgg16.input, outputs=top_model(vgg16.output))

for layer in model.layers[:15]:
    layer.trainable = False

model.summary()
model.compile(loss='categorical_crossentropy', optimizer=optimizers.SGD(lr=1e-4, momentum=0.9), metrics=['accuracy'])
history = model.fit(x_train, y_train, batch_size=32, epochs=3, verbose=0, validation_split=0.1)

open('bark3_model.json', 'w').write(model.to_json())
model.save_weights('bark3_weight.hdf5')

score = model.evaluate(x_test, y_test, verbose=0)
print('Test loss:', score[0])
print('Test accuracy:', score[1])

plt.plot(history.history["acc"], label="acc", ls="-", marker="o")
plt.plot(history.history["val_acc"], label="val_acc", ls="-", marker="x")
plt.ylabel("accuracy")
plt.xlabel("epoch")
plt.legend(loc="best")
plt.show()

 

精度

正解率:97.8%

うまく学習が進んでいる。

f:id:gadada:20180602140041p:plain

 

今後に向けて

・「方法と結果3」ではエポック数3であったがこれを10程度まで増やせば精度がさらに良くなる可能性があるので試してみる。

 

・樹種の種類を増やす。今回は2種で行ったがもっと樹種を増やしてもうまくいくのか調べてみたい。ただ、データ収集が大変…。

ネットで収集するのは、樹皮と樹種が間違っている可能性があるので危険だし、自分で写真を撮りに行くとなると時間がかかるわけで…。

 

・画像データ数をどれだけなら少なくしても精度を保てるかを実験してみる。

 

・精度についてしっかり検討する。今回写真を撮影した地域に特化している可能性が少々あり不安なので、全国どこに生育している樹木に対しても有効なのかを調べたい。

 

 

 

以上、「ディープラーニング(Deep Learning、深層学習)を用いて樹皮の画像から樹種を同定する」でした。お読みいただきありがとうございました。

 

まだまだ勉強中で分からないことばっかりですので、コメント等あればぜひぜひよろしくお願いします!