前提・実現したいこと
現在9人の画像を集めて学習させ、別の写真を見せた時にどの人か特定させるというようなことをしたいと考えています。
乃木坂メンバーの顔をCNNで分類
こちらの記事を参考にKerasのCNNを利用して実装しているのですが、できたモデルで9人のいろんな写真を判定させるとある1人として判定されてしまうことが多いです。
9人をA、B、C...だとして、Aの写真、Bの写真、Cの写真を判定させても90%超えでAさんと判定されてしまうといった感じです。
画像もそこまで量を集められているわけではないので精度が多少悪くなるのは仕方ないとは思うのですが、なぜここまで偏ってしまうのかがわかりません。せめてこの偏った判定は解消したいと考えています。
単純に画像が足りないせいのか、コードの書き方に誤りがあるのか、層が足りないのか、調整が足りないのか...今後どこを改善していけばいいのか悩んでいるところです。
解決方法をご教示ください。
そもそも、CNNではなく最近の画像分類ではこの手法のほうがおすすめなどのアドバイスもあれば教えていただきたいです。
###用意したデータ
集めた画像は、メンバーごとに116枚~124枚
上記記事を参考に、9倍の量に水増し
上記記事を参考に、ランダムに選んだ8割がtrainフォルダに2割がtestフォルダに入っている状態です
該当のソースコード
python
members = ['A','B','C','D','E','F','G','H','I'] TRAIN_FOLDER_PATH = 'D:\train' TEST_FOLDER_PATH = 'D:\test' # 教師データのラベル付け X_train = [] Y_train = [] for i in range(len(members)): images = os.listdir(os.path.join(TRAIN_FOLDER_PATH, members[i])) for image in images: img = cv2.imread(os.path.join(TRAIN_FOLDER_PATH, members[i], image)) b,g,r = cv2.split(img) img = cv2.merge([r,g,b]) X_train.append(img) Y_train.append(i) # テストデータのラベル付け X_test = [] # 画像データ読み込み Y_test = [] # ラベル(名前) for i in range(len(members)): images = os.listdir(os.path.join(TEST_FOLDER_PATH, members[i])) for image in images: img = cv2.imread(os.path.join(TEST_FOLDER_PATH, members[i], image)) b,g,r = cv2.split(img) img = cv2.merge([r,g,b]) X_test.append(img) Y_test.append(i) X_train=np.array(X_train) X_test=np.array(X_test) y_train = to_categorical(Y_train) y_test = to_categorical(Y_test) model = Sequential() model.add(Conv2D(32, (3, 3), activation='relu', input_shape=(64, 64, 3), padding="same")) model.add(MaxPooling2D((2, 2))) model.add(Dropout(0.2)) model.add(Conv2D(64, (3, 3), activation='relu')) model.add(MaxPooling2D((2, 2))) model.add(Dropout(0.2)) model.add(Conv2D(128, (3, 3), activation='relu')) model.add(MaxPooling2D((2, 2))) model.add(Dropout(0.2)) model.add(Conv2D(128, (3, 3), activation='relu')) model.add(MaxPooling2D((2, 2))) model.add(Dropout(0.2)) model.add(Flatten()) model.add(Dense(512, activation='relu')) model.add(Dropout(0.2)) model.add(Dense(9, activation='softmax')) model.compile(loss='categorical_crossentropy', optimizer=optimizers.RMSprop(lr=1e-4), metrics=['accuracy']) # 学習 history = model.fit(X_train, y_train, batch_size=32, epochs=50, verbose=1, validation_data=(X_test, y_test)) # 汎化制度の評価・表示 score = model.evaluate(X_test, y_test, batch_size=32, verbose=0) print('validation loss:{0[0]}\nvalidation accuracy:{0[1]}'.format(score))
###model.summary()
Model:
_________________________________________________________________ Layer (type) Output Shape Param # ================================================================= conv2d (Conv2D) (None, 64, 64, 32) 896 max_pooling2d (MaxPooling2D (None, 32, 32, 32) 0 ) dropout (Dropout) (None, 32, 32, 32) 0 conv2d_1 (Conv2D) (None, 30, 30, 64) 18496 max_pooling2d_1 (MaxPooling (None, 15, 15, 64) 0 2D) dropout_1 (Dropout) (None, 15, 15, 64) 0 conv2d_2 (Conv2D) (None, 13, 13, 128) 73856 max_pooling2d_2 (MaxPooling (None, 6, 6, 128) 0 2D) dropout_2 (Dropout) (None, 6, 6, 128) 0 conv2d_3 (Conv2D) (None, 4, 4, 128) 147584 max_pooling2d_3 (MaxPooling (None, 2, 2, 128) 0 2D) dropout_3 (Dropout) (None, 2, 2, 128) 0 flatten (Flatten) (None, 512) 0 dense (Dense) (None, 512) 262656 dropout_4 (Dropout) (None, 512) 0 dense_1 (Dense) (None, 9) 4617 ================================================================= Total params: 508,105 Trainable params: 508,105 Non-trainable params: 0
###結果
validation loss:0.15804602205753326 validation accuracy:0.9585736989974976
試したこと
他のサイトも参考にして、上記参考記事から以下のような変更を加えてみてます。
活性化関数をsigmoid
-> relu
に変更
オプティマイザをsgd
-> RMSprop
に変更
その他、batchサイズやepoch数を大きくしたり小さくしたりしてみたりしたのですが、偏りはあまり解消されませんでした。
###追記
テストデータに分けてから、訓練データのみ水増し処理するように修正しました。
結果は以下のようになりました。
ただ、特定のメンバーが確率高く出る偏りは解消されないようでした。
validation loss:0.9875603318214417 validation accuracy:0.7211538553237915
まだ回答がついていません
会員登録して回答してみよう