Deep Learningを使って衛星画像に写った船を認識してみた

プログラミング

はじめに

近年、宇宙ビジネスが熱を帯びています。

日本国内でも大手重工メーカの他にもスタートアップ企業が続々と参入しています。

宇宙ビジネスの市場規模はどんどん大きくなっていますが、その中でも人工衛星で撮られた画像を利用したサービスが注目されています。
理由は大きく分けて二つあります。
・低コストで短期開発可能な超小型衛星の登場
・AI(特にディープラーニング)ブーム

今後、小型衛星の打上げ頻度や観測頻度が多くなってくるに伴い、衛星画像のデータも更にビッグデータ化してくるでしょう。
そんな状態において衛星画像の高精度解析の自動化が期待されています。

今回は衛星画像解析の一例として、畳み込みニューラルネットワーク(CNN)を使って下図のような衛星画像から船かどうかを自動認識してみます。

データセット

今回はこちらのkaggleコンペのデータセットを用いて、モデルの学習および評価を行います。

このデータセットは、米国のカリフォルニアのサンフランシスコ湾とサンペドロ湾の地域で収集された衛星画像から構成されています。

各々の衛星画像は「船」もしくは「船無し」のどちらかに分類されており、サイズ 80 x 80のRGBイメージとなっています。
画像の合計枚数は4000枚です。

また、データセットはJSON形式のテキストファイル(shipset.json)としても配布されています。
中身は下記のような情報で構成されています。
・ラベル(1 : 船、2:船無し)
・シーンid
・位置

ラベル(船)は下図のような画像になります。

一方でラベル(船無し)では下図のように船が写っていなかったり、写っていても途切れてしまっているものは船ではないとラベル付けされています。

ライブラリの準備

CNNを実装するためのライブラリとしてkerasを用います。
その他必要なライブラリをインポートします。

import json
import numpy as np
from PIL import Image, ImageDraw
from matplotlib import pyplot as plt
import pandas as pd

from keras.models import Sequential
from keras.layers import Conv2D, MaxPooling2D
from keras.layers import Activation, Dropout, Flatten, Dense
from keras.utils import np_utils
import keras

データセットの確認

はじめにデータセットの確認をします。

f = open('../input/shipsnet.json')
dataset = json.load(f)
f.close()

input_data = np.array(dataset['data']).astype('uint8')
output_data = np.array(dataset['labels']).astype('uint8')

# check data of content
print('Total number of images : {}'.format(len(input_data)))
print('Number of NoShipe images : {}'.format(np.sum(output_data==0)))
print('Number of Ship images : {}'.format(np.sum(output_data==1)))
print('Image shape : {}'.format(input_data.shape[1]))

 

データセットの準備

データセットを整形し、”船”か”船無し”のカテゴリデータに対するワンホットベクトル化します。

# reshape data
num_classes = 2
n_spectrum = 3 #color channel (RGB)
weight = 80
height = 80

# reshape input_data
X = input_data.reshape([-1, n_spectrum, weight, height]).transpose([0,2,3,1])
print(X.shape)

# label to categorize (one hot vector)
y = np_utils.to_categorical(output_data, num_classes)
print(y.shape)

# shuffle all indexes
indexes = np.arange(4000)
np.random.shuffle(indexes)

#Shuffling Images and Labels by same shuffled index
X = X[indexes]
y = y[indexes]

イメージの確認

イメージの確認をします。

plt.figure(figsize=(20,10))
for i in range(5):
    plt.subplot(1,10,i+1)
    plt.xticks([])
    plt.yticks([])
    plt.grid(False)
    plt.imshow(X[i].reshape(80, 80, 3), cmap=plt.cm.binary)

データの前処理

データの規格化を行い、ホールドアウト法でトレーニング用とテスト用に8:2に分割します。

# normalization
X = X/255

# hold out
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X,
                                                    y,
                                                    test_size=0.20,
                                                    random_state=1)

 

CNNモデルの定義

畳み込みステップの後、活性化関数としてReLU(Rectified Linear Unit)を用いています。

また、出力層の活性化関数にはソフトマックス関数を用いています。

# model set up
model = Sequential()
model.add(Conv2D(32, (3, 3), padding='same', input_shape=(80, 80, 3)))
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(2))
model.add(Activation('softmax'))

CNNの学習

定義したモデルを使って学習してみます。
今回はOptimizerとしてRMSpropを用いて、損失関数としてクロスエントロピーを用いて学習します。
また、バッチサイズは32に設定しました。

# optimization set up
opt = keras.optimizers.rmsprop(lr=0.0001, decay=1e-6)
model.compile(loss='categorical_crossentropy', optimizer=opt, metrics=['accuracy'])

# training
history = model.fit(X_train, y_train, batch_size=32, epochs=20)

出力した学習曲線は下図のようになりました。

テストデータで評価

学習済モデルを使ってテストデータで評価してみます。

# evaluation
scores = model.evaluate(X_test, y_test, verbose=1)
print('Test Loss : ', scores[0])
print('Test Accuracy : ', scores[1])

まとめ

kaggleのオープンデータを使って衛星画像から船を自動認識するCNNを学習しました。

そして、その学習モデルを使ってテストデータの評価をkerasに実装されているmodel.evaluate()関数で行いました。

その結果、Lossは0.0572、Accuracyは0.986の精度で分類出来ることが確認出来ました。

今回のデータセットはあらかじめ船とそうでない画像を分けられていたのですが、実務においては船の検出処理まで含めてやる必要がありそうですね。

ということで、時間が出来たら次は物体検出に挑戦してみようと思います。

タイトルとURLをコピーしました