例えばkerasを使えば、VGG16のアーキテクチャで、imagenetをベースに訓練された1000種類の物体を判別できるモデルを即使える。
https://keras.io/ja/applications/#vgg16
同じように、物体検知でも、SSDなどのアーキテクチャで、MSCOCOとかPASCAL VOCとかの物体を検知できるモデルが発表されている。
https://github.com/pierluigiferrari/ssd_keras#download-the-original-trained-model-weights
このレポジトリの方はcaffeのモデルをkerasで使えるようh5ファイルに変換して提供しているので、これをベースにお話しする。
このh5ファイルに入っているのは、ちょっと特殊なアクセス方法を取らなければいけない多次元配列であり、辞書のようにデータに名前がついていて、アクセスするには名前で呼び出さなければいけない。
import h5py
WEIGHT_PATH = 'weights.h5'
weights_file = h5py.File(WEIGHT_PATH, 'r')
weight = weights_file['conv6_3']['conv6_3']['kernel:0'].value
このようにh5pyでファイルを読みだして、それに対して名前を鍵に中身を出力していく。
このh5ファイルは、SSDのアーキテクチャで
kernel:0 という鍵を最後にネットワークの重みを格納していて、バイアスに関しては同じ位置から
bias:0 で呼び出せる。
この出力は普通に多次元配列で、かつこのモデルが作られた際の設定を確認すると、背景を含め81種類のMSCOCOの画像を認識検知できるモデルということがわかり、さらにMSCOCOの画像の種類順にcx, cy, w, hの四値の予測を格納していることがわかるので、
それを切り出して一種類の重みのみとして扱うことができる。
MSCOCOの画像の種類に対応するIDは、例えば止まれ標識は12番であり、
http://cocodataset.org/#explore
こちらで並んでいる順である。
なので12番を指定して重みを切り出すことができる。
また、全部で81種類のため、四値それぞれ切り出すには81個間を開けながら切りださなければいけない。
classes_of_interest = [0, 12] # background, stop sign
n_classes_source = 81
subsampling_indices = []
out_channels = weight.shape[3]
for i in range(int(out_channels/n_classes_source)):
indices = np.array(classes_of_interest) + i * n_classes_source
subsampling_indices.append(indices)
subsampling_indices = list(np.concatenate(subsampling_indices))
new_weight = weight[:,:,:,subsampling_indices]
そしてh5ファイルはデータに対して消去処理や作成処理、さらにflush()など特殊な処理をしないといけない。
DESTINATION_WEIGHT_PATH = 'subsampled.h5'
weights_destination_file = h5py.File(DESTINATION_WEIGHT_PATH)
del weights_destination_file['conv6_3']['conv6_3']['kernel:0']
weights_destination_file['conv6_3']['conv6_3'].create_dataset(name='kernel:0', data=new_weight)
weights_destination_file.flush()
これでこのSSDのconv6_3の層のカテゴリー判別ようの重みに関しては、背景と止まれ標識しか認知しなくなった。