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

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

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

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

受付中

判定精度が上がらない。

f_matsu_abc
f_matsu_abc

総合スコア0

CNN (Convolutional Neural Network)

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

1回答

0評価

1クリップ

302閲覧

投稿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 (効果なし)

良い質問の評価を上げる

以下のような質問は評価を上げましょう

  • 質問内容が明確
  • 自分も答えを知りたい
  • 質問者以外のユーザにも役立つ

評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

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

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

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

teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

  • プログラミングに関係のない質問
  • やってほしいことだけを記載した丸投げの質問
  • 問題・課題が含まれていない質問
  • 意図的に内容が抹消された質問
  • 過去に投稿した質問と同じ内容の質問
  • 広告と受け取られるような投稿

評価を下げると、トップページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

まだ回答がついていません

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

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

ただいまの回答率
87.20%

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

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

質問する

関連した質問

同じタグがついた質問を見る

CNN (Convolutional Neural Network)

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