質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
CNN (Convolutional Neural Network)

CNN (Convolutional Neural Network)は、全結合層のみではなく畳み込み層とプーリング層で構成されるニューラルネットワークです。画像認識において優れた性能を持ち、畳み込みニューラルネットワークとも呼ばれています。

Q&A

1回答

2097閲覧

判定精度が上がらない。

f_matsu_abc

総合スコア0

CNN (Convolutional Neural Network)

CNN (Convolutional Neural Network)は、全結合層のみではなく畳み込み層とプーリング層で構成されるニューラルネットワークです。画像認識において優れた性能を持ち、畳み込みニューラルネットワークとも呼ばれています。

0グッド

1クリップ

投稿2022/04/01 08:28

1.前提・実現したいこと
生産ラインでの異常検知にAIによる画像判定を検討しています。
(検査したい内容)
マスターケースの化粧面にある150 x 150mmの印字領域内にロゴを印字して
いますが、ロゴが印字領域をはみ出していないことを工程で検査します。

2.発生している問題
以下の様に判定精度が上がらない。
その原因についてアドバイスをお願いします。
①学習データの問題でしょうか?
②そもそもCNNで「ロゴの印字位置が印字領域内に納まっているか否か」を
判定するのは難しいのでしょうか?

 (判定精度)
正解率= 0.7758620977401733 loss= 2.1572329998016357

 (データ)
OKデータ:144件
(内訳)
OKレベル1(ロゴが印字領域のセンター位置):48件
OKレベル2(ロゴが印字領域のセンターから少しズレた位置):48件
OKレベル3(ロゴが印字領域の内側ギリギリの位置):48件

NGデータ:144件
(内訳)
NGレベル1(ロゴが印字領域から少しはみ出した位置):48件
NGレベル2(ロゴが印字領域からもう少しはみ出した位置):48件
NGレベル3(ロゴが印字領域からかなりはみ出した位置):48件

※印字領域内にギリギリ納まったロゴはOKデータとしています。
※印字領域から少しでもはみ出したロゴはNGデータとしています。
※学習データを水増しして使用しています (230件 → 5,520件)

 (データのイメージ)
イメージ説明

3.該当のソースコード

プログラム名:read_image_ok_ng.jpynb # 画像ファイルを読んでNumpy形式に変換 import numpy as np from PIL import Image import os, glob, random outfile = "image/photos.npz" # 保存ファイル名 max_ok_photo = 144 # 利用するOK写真の枚数 max_ng_photo = 144 # 利用するNG写真の枚数 photo_size = 256 # 画像サイズ x = [] # 画像データ y = [] # ラベルデータ def main(): # 各画像のフォルダを読む --- (*1) glob_ok_files("./image/ok", 0) glob_ng_files("./image/ng", 1) # ファイルへ保存 --- (*2) np.savez(outfile, x=x, y=y) print("保存しました:" + outfile, len(x)) # path以下の画像を読み込む --- (*3) def glob_ok_files(path, label): files = glob.glob(path + "/*.png") random.shuffle(files) # 各ファイルを処理 num = 0 for f in files: if num >= max_ok_photo: break num += 1 # 画像ファイルを読む img = Image.open(f) img = img.convert("RGB") # 色空間をRGBに img = img.resize((photo_size, photo_size)) # サイズ変更 img = np.asarray(img) x.append(img) y.append(label) def glob_ng_files(path, label): files = glob.glob(path + "/*.png") random.shuffle(files) # 各ファイルを処理 num = 0 for f in files: if num >= max_ng_photo: break num += 1 # 画像ファイルを読む img = Image.open(f) img = img.convert("RGB") # 色空間をRGBに img = img.resize((photo_size, photo_size)) # サイズ変更 img = np.asarray(img) x.append(img) y.append(label) if __name__ == '__main__': main() ------------------------------------------------------------------ (実行結果) 保存しました:image/photos.npz 288 ------------------------------------------------------------------ プログラム名:cnn2_ok_ng.jpynb import cnn_model import keras import matplotlib.pyplot as plt import numpy as np from sklearn.model_selection import train_test_split import cv2 # 入力と出力を指定 im_rows = 256 # 画像の縦ピクセルサイズ im_cols = 256 # 画像の横ピクセルサイズ im_color = 3 # 画像の色空間 in_shape = (im_rows, im_cols, im_color) nb_classes = 2 # 写真データを読み込み photos = np.load('image/photos.npz') x = photos['x'] y = photos['y'] # 読み込んだデータをの三次元配列に変換 x = x.reshape(-1, im_rows, im_cols, im_color) x = x.astype('float32') / 255 # ラベルデータをone-hotベクトルに直す y = keras.utils.to_categorical(y.astype('int32'), nb_classes) # 学習用とテスト用に分ける x_train, x_test, y_train, y_test = train_test_split( x, y, train_size=0.8) # 学習用データを水増しする --- (*1) x_new = [] y_new = [] for i, xi in enumerate(x_train): yi = y_train[i] for ang in range(-30, 30, 5): # 回転させる --- (*2) center = (128, 128) # 回転の中心点 mtx = cv2.getRotationMatrix2D(center, ang, 1.0) xi2 = cv2.warpAffine(xi, mtx, (256, 256)) x_new.append(xi2) y_new.append(yi) # さらに左右反転させる --- (*3) xi3 = cv2.flip(xi2, 1) x_new.append(xi3) y_new.append(yi) # 水増しした画像を学習用に置き換える print('水増し前=', len(y_train)) x_train = np.array(x_new) y_train = np.array(y_new) print('水増し後=', len(y_train)) # CNNモデルを取得 --- (*6) model = cnn_model.get_model(in_shape, nb_classes) # 学習を実行 --- (*8) hist = model.fit(x_train, y_train, batch_size=64, epochs=20, verbose=1, validation_data=(x_test, y_test)) # モデルを評価 --- (*9) score = model.evaluate(x_test, y_test, verbose=1) print('正解率=', score[1], 'loss=', score[0]) # 学習の様子をグラフへ描画 --- (*10) # 正解率の推移をプロット plt.plot(hist.history['accuracy']) plt.plot(hist.history['val_accuracy']) plt.title('Accuracy') plt.legend(['train', 'test'], loc='upper left') plt.show() # ロスの推移をプロット plt.plot(hist.history['loss']) plt.plot(hist.history['val_loss']) plt.title('Loss') plt.legend(['train', 'test'], loc='upper left') plt.show() model.save_weights('./image/photos-model.hdf5') プログラム名:cnn_model.py import keras from keras.models import Sequential from keras.layers import Dense, Dropout, Flatten from keras.layers import Conv2D, MaxPooling2D from keras.optimizers import RMSprop # CNNのモデルを定義する def def_model(in_shape, nb_classes): model = Sequential() model.add(Conv2D(32, kernel_size=(3, 3), activation='relu', input_shape=in_shape)) model.add(Conv2D(32, (3, 3), activation='relu')) model.add(MaxPooling2D(pool_size=(2, 2))) model.add(Dropout(0.25)) model.add(Conv2D(64, (3, 3), activation='relu')) model.add(Conv2D(64, (3, 3), activation='relu')) model.add(MaxPooling2D(pool_size=(2, 2))) model.add(Dropout(0.25)) model.add(Flatten()) model.add(Dense(512, activation='relu')) model.add(Dropout(0.5)) model.add(Dense(nb_classes, activation='softmax')) return model # コンパイル済みのCNNのモデルを返す def get_model(in_shape, nb_classes): model = def_model(in_shape, nb_classes) model.compile( loss='categorical_crossentropy', optimizer=RMSprop(), metrics=['accuracy']) return model ----------------------------------------------------------------------------------------- (実行結果) 水増し前= 230 水増し後= 5520 Epoch 1/20 87/87 [==============================] - 683s 8s/step - loss: 1.8068 - accuracy: 0.5118 - val_loss: 0.6993 - val_accuracy: 0.4138 Epoch 2/20 87/87 [==============================] - 685s 8s/step - loss: 0.7036 - accuracy: 0.5257 - val_loss: 0.7010 - val_accuracy: 0.4138 Epoch 3/20 87/87 [==============================] - 673s 8s/step - loss: 0.7160 - accuracy: 0.5216 - val_loss: 0.7018 - val_accuracy: 0.4138 Epoch 4/20 87/87 [==============================] - 649s 7s/step - loss: 0.7048 - accuracy: 0.5158 - val_loss: 0.6955 - val_accuracy: 0.4483 Epoch 5/20 87/87 [==============================] - 680s 8s/step - loss: 0.7004 - accuracy: 0.5216 - val_loss: 0.6965 - val_accuracy: 0.4310 Epoch 6/20 87/87 [==============================] - 649s 7s/step - loss: 0.6824 - accuracy: 0.5676 - val_loss: 0.7078 - val_accuracy: 0.5517 Epoch 7/20 87/87 [==============================] - 649s 7s/step - loss: 0.6243 - accuracy: 0.6447 - val_loss: 0.7247 - val_accuracy: 0.5517 Epoch 8/20 87/87 [==============================] - 667s 8s/step - loss: 0.5192 - accuracy: 0.7292 - val_loss: 0.6559 - val_accuracy: 0.6034 Epoch 9/20 87/87 [==============================] - 652s 7s/step - loss: 0.4018 - accuracy: 0.8074 - val_loss: 0.8061 - val_accuracy: 0.6552 Epoch 10/20 87/87 [==============================] - 656s 8s/step - loss: 0.3168 - accuracy: 0.8560 - val_loss: 0.8276 - val_accuracy: 0.6724 Epoch 11/20 87/87 [==============================] - 665s 8s/step - loss: 0.2377 - accuracy: 0.8967 - val_loss: 1.0177 - val_accuracy: 0.7241 Epoch 12/20 87/87 [==============================] - 665s 8s/step - loss: 0.1745 - accuracy: 0.9277 - val_loss: 1.4920 - val_accuracy: 0.7069 Epoch 13/20 87/87 [==============================] - 648s 7s/step - loss: 0.1457 - accuracy: 0.9475 - val_loss: 1.2854 - val_accuracy: 0.7069 Epoch 14/20 87/87 [==============================] - 656s 8s/step - loss: 0.1164 - accuracy: 0.9611 - val_loss: 1.3863 - val_accuracy: 0.6897 Epoch 15/20 87/87 [==============================] - 652s 7s/step - loss: 0.0739 - accuracy: 0.9774 - val_loss: 1.2557 - val_accuracy: 0.7241 Epoch 16/20 87/87 [==============================] - 653s 8s/step - loss: 0.0486 - accuracy: 0.9828 - val_loss: 1.5092 - val_accuracy: 0.6379 Epoch 17/20 87/87 [==============================] - 649s 7s/step - loss: 0.0688 - accuracy: 0.9786 - val_loss: 0.9388 - val_accuracy: 0.7414 Epoch 18/20 87/87 [==============================] - 654s 8s/step - loss: 0.0389 - accuracy: 0.9857 - val_loss: 1.6616 - val_accuracy: 0.7069 Epoch 19/20 87/87 [==============================] - 653s 8s/step - loss: 0.0431 - accuracy: 0.9868 - val_loss: 2.0116 - val_accuracy: 0.7069 Epoch 20/20 87/87 [==============================] - 660s 8s/step - loss: 0.0375 - accuracy: 0.9866 - val_loss: 2.1572 - val_accuracy: 0.7759 2/2 [==============================] - 1s 377ms/step - loss: 2.1572 - accuracy: 0.7759 正解率= 0.7758620977401733 loss= 2.1572329998016357 -----------------------------------------------------------------------------------------

イメージ説明
イメージ説明
4.自分で調べたことや試したこと
①CNNでoptimizer=Adamを使用 (効果なし)
②畳込み層の前にmodel.add(BatchNormalization())を追加 (効果なし)
③model.add(Conv2D(32, (3, 3), activation='relu'))のフィルター数を半減
32 → 16、64 → 32 (効果なし)
④model.add(Dense(512, activation='relu'))の出力を削減 512 → 128
(効果なし)
⑤学習アルゴリズムをSVMに変更し、入力データをグレースケールに変換
→ 正解率=0.578 (正解率低下)
⑤OKデータとNGデータをレベルの異なる両極端だけにする
→ 正解率=0.95 (暫定データで効果あり)
OKデータは印字領域に対してロゴがセンター位置
NGデータは印字領域に対してロゴが大きくはみ出している
⑥上記⑤のデータに残りのレベルのNGデータを全て追加
→ 正解率=0.948 (暫定データで効果あり)
OKデータは印字領域に対してロゴがセンター位置
NGデータは印字領域に対してロゴのはみ出し方が各3レベル(大/中/小)
⑦上記⑥のデータにOKデータの中レベル(センターから少しズレた位置)を
追加 → 正解率=0.729 (効果なし)
⑧OKデータの中レベルに問題があると推測しデータを調べると、
中レベルは画像のサイズが他のレベルより少し大きかったので全データを
同じサイズで再作成して確認(OKデータ各3レベル、NGデータ各3レベル)
→ 正解率=0.775 (効果なし)

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

学習データに対して出力層の数が多すぎるのではないでしょうか。
私ならば複数のモデルを作成して階層化します。
モデル1
(okレベル1〜3、NGレベル1〜2),(NGレベル3)
モデル2
(okレベル1〜3、NGレベル1),(ngレベル2)
モデル3
(okレベル1〜3),(ngレベル1)

分類器に複数のモデルを搭載して対象物の判定を絞り込
むことで分類の数を減らします。
推論用のデバイスがどういったものかわかりませんが、
tensorflowliteなどの軽量版なら判定速度も問題ないかと思います。

投稿2022/04/13 03:24

west0792

総合スコア4

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問