Tiny-YOLOがどうやっても普通の固定小数点化では精度がでない。もうひと工夫いるんだと思います。精度を上げるのに固定小数点化をいろいろ試すのではなく、CNNの部分をVGG16にしてみようと思いました。VGG16にすることで、バッチノーマライゼーションと、Leaky ReLUがなくなるので固定小数点にしたときの精度はコントロールしやすくなります。(多分)
最初の一歩として、Kerasのexampleに含まれているVGG16学習データを、自分のNNに移してみました。最終段の形が違うためそのままでは上手く行かず、結局レイヤー単位で、get_weightsとset_weightsを繰り返しました。多分、もっと良い方法があるはずです。
from keras.models import Sequential from keras.layers import Conv2D, MaxPooling2D, InputLayer, Dropout # 入力サイズ等はここを変更 width = 416 height = 416 r_w = 13 r_h = 13 r_n = 5 classes = 20 def vgg_yolo_model(): model = Sequential() model.add(InputLayer(input_shape=(width, height, 3))) model.add(Conv2D(64, activation='relu', padding='same', kernel_size=(3, 3), strides=(1, 1))) model.add(Conv2D(64, activation='relu', padding='same', kernel_size=(3, 3), strides=(1, 1))) model.add(MaxPooling2D(pool_size=(2, 2), padding='same', strides=(2, 2))) model.add(Conv2D(128, data_format="channels_last", activation='relu', padding='same', kernel_size=(3, 3), strides=(1, 1))) model.add(Conv2D(128, data_format="channels_last", activation='relu', padding='same', kernel_size=(3, 3), strides=(1, 1))) model.add(MaxPooling2D(pool_size=(2, 2), padding='same', strides=(2, 2))) model.add(Conv2D(256, data_format="channels_last", activation='relu', padding='same', kernel_size=(3, 3), strides=(1, 1))) model.add(Conv2D(256, data_format="channels_last", activation='relu', padding='same', kernel_size=(3, 3), strides=(1, 1))) model.add(Conv2D(256, data_format="channels_last", activation='relu', padding='same', kernel_size=(3, 3), strides=(1, 1))) model.add(MaxPooling2D(pool_size=(2, 2), padding='same', strides=(2, 2))) model.add(Conv2D(512, data_format="channels_last", activation='relu', padding='same', kernel_size=(3, 3), strides=(1, 1))) model.add(Conv2D(512, data_format="channels_last", activation='relu', padding='same', kernel_size=(3, 3), strides=(1, 1))) model.add(Conv2D(512, data_format="channels_last", activation='relu', padding='same', kernel_size=(3, 3), strides=(1, 1))) model.add(MaxPooling2D(pool_size=(2, 2), padding='same', strides=(2, 2))) model.add(Conv2D(512, data_format="channels_last", activation='relu', padding='same', kernel_size=(3, 3), strides=(1, 1))) model.add(Conv2D(512, data_format="channels_last", activation='relu', padding='same', kernel_size=(3, 3), strides=(1, 1))) model.add(Conv2D(512, data_format="channels_last", activation='relu', padding='same', kernel_size=(3, 3), strides=(1, 1))) model.add(MaxPooling2D(pool_size=(2, 2), padding='same', strides=(2, 2))) model.add(Dropout(0.25)) model.add(Conv2D(125, use_bias=True, data_format="channels_last", activation='relu', padding='same', kernel_size=(1, 1), strides=(1, 1), kernel_initializer='random_uniform')) return model def transfer_weights(my_model): from keras.applications.vgg16 import VGG16, preprocess_input, decode_predictions def_model = VGG16(include_top=True, weights='imagenet', input_tensor=None, input_shape=None) # レイヤー単位で、17層までコピー。18層は全結合層なので不要。 for i, l in enumerate(def_model.layers): if len(l.weights) == 0: continue # layer[17]までコピー if i >= 18: break w = l.get_weights() my_model.layers[i].set_weights(w) print('set weights layer[%d] %s' % (i, l.name)) # モデルの構築と表示 vgg_yolo_model = vgg_yolo_model() vgg_yolo_model.summary() # データを移す transfer_weights(vgg_yolo_model) # 名前をつけて保存する。 vgg_yolo_model.save_weights('weight/vgg_yolo_def.h5')
これで、weightフォルダーに、vgg_yolo_def.h5が生成されます。
重みデータは、最終層を除きサンプルの値、最終層はランダムに初期化された値になっています。