セマンティックセグメンテーションできゅうりを認識してみた(U-Net)
セマンティックセグメンテーション
Deep Learning による物体検知はバウンディングボックスという四角い枠で囲んで物体の位置と名称を検知する方法の他にピクセル単位で物体を検知するセマンティックセグメンテーションというアルゴリズムがある。
以前の記事では Jetson Nano で学習済みのモデルを使ってのセマンティックセグメンテーションを試してみた。
※都市の景観が得意な Cityscapes モデルを使用した例

セマンティックセグメンテーションは物体の輪郭を正確に把握したい場合、例えば自動運転や農業で農作物の形状を把握したい時などに利用される事がある。
今回は、学習済みのモデルの利用ではなく独自の物体を学習させる所から試してみた。
学習させた物体
今回はきゅうりを学習させてみた。

知人がきゅうり農家をやっていて、新人や体験者、子供達にも簡単に収穫可能なきゅうりかどうかを見分けられるような装置が欲しいと言っていたので、まずは画像からセマンティックセグメンテーションが可能かどうかを試してみることにした。
画像(映像)からきゅうりの輪郭を正確に認識できれば、収穫の可否、サイズ、等級などの判定にもつながるのではないかと考えた。

U-Net
アルゴリズムは U-Net を使用した。
下記のように U型をしているので U-Net と名付けられたとの事。
左側でエンコード、右側でデコードされる。
※ U-Net: Convolutional Networks for Biomedical Image Segmentation より引用

U-Net のアルゴリズムは 2015年に発表されているので Deep Learning の中では “古め” のアルゴリズムだ。
その後、U-Net の応用の U-Net++、R2U-Net、3D U-Net 等が発表されたが、今回は基本の U-Net で試している。
環境
試した環境は以下の通り。
画像にラベル付けをするアノテーションまでは Windows環境(内のLinux)、その後の学習・予測は Google Colaboratory にて行った。
アノテーション
パソコン | DELL G7 15 7588 CPU:CoreTM i7-8750H メモリ:16GB ビデオカード:NVIDIA GeForce GTX 1060 |
OS | Windows11 Home |
アノテーションツール | CVAT(Computer Vision Annotation Tool)を下記の Linux 環境にインストールして使用した。 マウスで囲みながら多角形でアノテーションが可能なのと、複数の出力形式に対応している。 Windows 環境では動作しないのでWSL、Ubuntu などのインストールが必要。 CVAT の GitHub はこちら。 |
WSL | Windows Subsystem for Linux を設定した。 WSL についてはこちらの記事を参照してほしい。 |
WSL のディストリビューション | Linux ディストリビューション は Ubuntu 20.04 を選択している |
Docker | Windowsアプリの Docker Desktop on Windows をインストールした。 関連記事はこちら。 |
コマンド入力用 | CVAT の起動、終了コマンドの入力の為に git for Windows を使用した。 |
学習・予測
学習、予測のスクリプトは Google Colaboratory 上で実行した。
512 × 512 Pixels の画像を学習させようとした所、自分のパソコンだと “ResourceExhaustedError”(リソース枯渇エラー)で実行出来なかったからだ。
大まかな手順
大まかな手順は以下の通り。
1.環境を整える
Windows11 環境に WSL(Ubuntu 20.04)、Docker Desktop on Windows、git for Windows、CVAT を設定する。
CVAT のインストール&起動は別途記事で紹介する。
2.CVAT でアノテーション
Windows11 環境下の Linux(Ubuntu 20.04)で CVAT を起動して学習用画像のアノテーションを行う。
具体的な手順は後述するが、画像のキュウリ部分を多角形で囲んでキュウリの位置をピクセル単位でラベル付けする作業だ。
これが地味でつらい。
ラベル付をしたら Segmentation Mask 1.1 形式で出力する。
3.学習・予測
CVAT で学習した画像を U-Net モデルで学習する。
元の画像数が少なかったのでデータ拡張(水増し)している。
CVATでアノテーション
プロジェクトの作成
CVAT を起動して上部のメニューから Projects を選択して、Create new project ボタンをクリックする。

Name欄に “Cucumber semantic segmentation” を入力して「Add label」ボタンでラベルを追加する(ラベルは後からでも追加はできる)

cucumber(きゅうり)ラベルを追加して色を指定する。
色は分かりやすように赤にした。
複数のモノをアノテーションしたいのであれば続けてラベルを追加する。
今回はキュウリだけなので「Done」ボタンをクリックする。

「Submit」ボタンをクリックする。

プロジェクトが追加されたのでクリックする。

タスクの追加
「Create new task」をクリックする。

Name:Cucumber annotation
を入力してアノテーションする画像を “Click or drag file to this area” にドラッグ・アンド・ドロップする。
尚、この際に全ての画像をアノテーションするのでは無く、テスト用の画像は残しておく。
※学習していない画像で正しくキュウリの識別ができるかどうかを検証するため。

30枚の画像を追加した。
「Submit」ボタンをクリックする。

アノテーション
上部のメニューで “Tasks” を選択して先程作成したタスクをオープンする。

Job #数字 をクリックする。

アノテーションはフルスクリーンの方がやりやすいので、右上の “Fullscreen” アイコンをクリックする。
中央上部のナビゲーターをクリックする事で前後の画像に移動が出来る。
またマウスホイールで画像の拡大縮小ができる。
左のメニューから多角形アイコンをクリックする。

右にメニューが現れるので Label は cucumber が選択されているのでそのまま、 “Shape” を選択する。

マウスで左クリックをしながらキュウリを多角形で囲む。
間違えた時は右クリックで一つ前の選択が解除される。
全体を囲ったら “N” キーで選択が確定されて色が変わる。
Ctrl+Zで全体の取り消し。
右上(奥)にもキュウリが写っているので続けてアノテーションを行う。
再び左のメニューから多角形アイコンをクリックしても良いのだが、”N” キーで新たに多角形が選択出来るモードに切り替わるのでそちらの方が簡単だ。

右奥のキュウリもアノテーションした。
アノテーション中もマウスホイールで拡大縮小が出来るので細かい部分は拡大をしながら選択を行う。
注意点としてはカーソルの位置によって拡大縮小する時の中心位置が変わる事だ。(カーソル位置を中心に拡大縮小する)
これは慣れないと中々に難しい。
カーソル位置上下左右に変えながらホイールで拡大縮小をして感覚を掴む必要がある。
また、確定した後でも画面上の赤丸をドラッグ・アンド・ドロップで移動する事で修正できるので、拡大表示をしてみてズレているようであれば後から修正する。

尚、後方に写っている多少ピンボケの画像であっても人の目でキュウリと判別できるものはアノテーションを行った。
こちらにラベル付け時の7つのヒントが載っていたので参考にさせて貰った。
- 画像に写っている全てのオブジェクトにアノテーションする(多少ピントが合っていないモノも含める)
- オブジェクト全体にラベル付けする
- 遮蔽されていて全体が写っていないオブジェクトもラベル付けする(一部でもアノテーション)
- アノテーション領域が重なり合っても良い
- なるべくギリギリを選択する(但しオブジェクトが切り取られてしまっては駄目)
- ラベル名をより一般的な名前にする
- 明確なラベル付けの指示(ルール)を維持する(途中でルールを変えない)
- CVAT、LabelImg、Roboflowなどのラベリングツールを使用する
同じ要領で残りの29枚の画像のアノテーションを行った。
JOB State の変更
アノテーションが終了したら JOB Status の変更を行う。
Menu から “Change job state” ー> completed に変更する。

確認画面が表示されるので “Continue” をクリックする。

タスクのステージの変更
State が Completed に変更されたので、続いてメニューから “Tasks” を選択する。

「Open」ボタンでタスクをオープンする。

“Stage” をプルダウンで “annotation” から “acceptance” に変更して “Job #数字” をクリックする。

Export
ステージを変更することによりデータエクスポートができるようになる。
Menu から “Export task dataset” を選択する。

- Export format:Segmentation mask 1.1
- Save images:チェックした
- Custom name:cucumber(.zip)
で「OK」ボタンをクリックする。

ファイルダイアログボックスが表示されるので保存する。
データ量によってはダイアログ・ボックスが表示されるまで時間がかかるので注意。
アノテーションデータ
ダウンロードした zip ファイルを解凍すると以下のフォルダー構成になっている。
├─cucumber
│ │
│ ├─ImageSets
│ │ ├──Segmentation
│ │ default.txt・・・画像ファイル名の一覧
│ │
│ ├─JPEGImages
│ │ 元画像(Save imagesにチェックした為)
│ │
│ ├─SegmentationClass
│ │ png形式のアノテーションした画像1
│ │
│ ├─SegmentationObject
│ │ png形式のアノテーションした画像2
│ │
今回は SegmentationClass 配下の画像1を使用する。
赤くなっている部分がキュウリの位置だ。

ちなみに SegmentationObject 配下のファイルは以下の様になっている。
一つの画像に複数のキュウリがある場合、異なる色(クラス)に分類されているので今回は使用しない。

事前準備
JPEGImages 配下の画像をトレーニングデータ、SegmentationClass 配下の画像を教師データとして U-Netで学習を行う。
U-Net はこちらの GitHub のコードを参考にさせて貰った。
フォルダー構成
上記の GitHub からコード類をダウンロードして Google Drive 上に以下のフォルダを構成する。
メインコードは Google Colaboratory に記述するが学習用画像や model.py、data.py は GitHub のコードを Google Drive に保存して Colaboratory から呼び出して使うことにする。
JPEGImages 配下のファイルを image へ、SegmentationClass 配下のファイルを label へコピーする。
そして推論用にアノテーションしていない画像を適当に見繕って test_org 配下にコピーする。
尚、この画像に対して直接推論を行うのでは無く、グレースケール化やリサイズを行って test フォルダーに格納した後、推論を行っている。
├─Google Drive
│ │
│ ├─unet-master
│ │ │ data.py:各種データ操作用関数(GitHubより)
│ │ │ model.py:U-Netモデル(GitHubより)
│ │ │
│ │ ├──data
│ │ │ │
│ │ │ ├─Cucumber
│ │ │ │ │
│ │ │ │ ├─model:学習済みモデルを格納するフォルダー
│ │ │ │ │
│ │ │ │ ├─test:テスト用画像を推論しやすい様に加工している
│ │ │ │ │
│ │ │ │ ├─test_org:テスト・推論用画像(元データ)
│ │ │ │ │
│ │ │ │ ├─train:学習用画像
│ │ │ │ │ ├─aug:image、labelのデータ拡張後のフォルダ
│ │ │ │ │ │
│ │ │ │ │ ├─image:前述のJPEGImagesフォルダの画像をここに格納する
│ │ │ │ │ │
│ │ │ │ │ ├─label:前述のSegmentationClassフォルダの画像をここに格納する
model.pyの修正と説明
GitHub からダウンロードした model.py に U-Net の構成が定義されている。
15行目から53行目にて U-Net の定義をしている。
また Google Colaboratory の kears のバージョンだとそのままでは動作しないコードがあるので修正する。
55行目をコメントアウトして以下のように修正する。
#model = Model(input = inputs, output = conv10)
model = Model(inputs, outputs = conv10)
また57行目の最適化パラメーターは若干変更した。
#model.compile(optimizer = optimizers.Adam(lr = 1e-4), loss = 'binary_crossentropy', metrics = ['accuracy'])
model.compile(optimizer = optimizers.Adam(lr = 5e-4), loss = 'binary_crossentropy', metrics = ['accuracy'])
Adam は最適化手法の一つで過去の勾配および勾配の2乗の指数関数的減衰平均を使用している。
lr(学習率)のデフォルトは0.001(1e-3) なのだが元々のコードは0.0001(1e-4)が指定されていた。
学習率は高くしすぎると発散して収束しない、一方低くしすぎると収束に時間がかかったり局所解にとらわれる可能性が出てくる。
学習率は最初は低い学習率から学習率を上げていくという手法で何回か試してみて最適な値が得られたらモデルを初期化して得られた学習率でモデルを訓練すると良いとの事。
0.0001 から 0.001 まで一通り試して今回の画像では 0.0005(5e-4) に落ち着いた。
尚、最適なパラメータの検索は RandomizedSearchCV を使う方法もある。
詳しくは以前の記事を参照してほしい。
また最初は高い学習率でスタートして損失(loss)の減少ペースが下がったら学習率を下げる方法もある。
上記の知識は以下の書籍の11章(深層ニューラルネットワークの訓練)から得られた。
分厚くて読み応えがあり途中で挫折してしまいがちだが、基本的な事がしっかりと書いてあるので何回も読み直している。
data.pyの説明
GitHub からダウンロードした data.py にデータ操作用の関数が定義されている。
今回使用した関数について説明をしておく。
trainGenerator
学習用のデータが少ない時にデータ拡張をしてデータの水増しする。
尚、その際に元画像とラベルの両方を拡張する。
デフォルトだと学習用画像のファイル名に “image” 正解ラベルに “mask” のプリフィックスを付加すると同時にグレースケール化する。
色の情報を学習させるかは迷ったのだが周囲の葉、つるがほぼキュウリ本体と同じ色なので色による識別はそれほど重要では無いのでは?と考えた。
また、学習画像の解像度を上げたかったのでリソースを考慮してグレースケール化を行った。
testGenerator
指定された path配下にある pngファイルを順番に読んでリサイズして返す。
デフォルトだと 256 × 256 にリサイズするが、この関数を呼ぶ際に target_size パラメータを指定すればサイズは変更可能だ。
今回は 512 × 512 を使用した。
geneTrainNpy
指定された path配下に imageファイル(トレーニングデータ)とmaskファイル(正解ラベル)をセットにして配列で返す。
学習時に使用する。
saveResult
推論結果を保存する為の関数。
学習・推論
Google Colaboratory の実行スクリプトは以下の通り。
データ拡張
学習用にアノテーションした画像は30枚と少ないのでデータ拡張(水増し)を行うコード。
"""
trainフォルダーのimage、labelフォルダーからデータを読み込んでデータを拡張してaugフォルダーに保存する。
@souichirou kikuchi
"""
OBJ = 'Cucumber' # 学習する物体
GDRIVE = '/content/drive/MyDrive/unet-master' # Google colab
import sys # 自作モジュールへのPathを追加する
ROOT_PATH = GDRIVE
sys.path.append(ROOT_PATH)
from data import *
# データ拡張 trainから読み込んでデータ拡張してaugに保存する
data_gen_args = dict(rotation_range = 0.2, #回転
width_shift_range = 0.05, #水平移動
height_shift_range = 0.05, #垂直移動
shear_range = 0.05, #シアー変換
zoom_range = 0.05, #ズーム
horizontal_flip = True, #左右反転
fill_mode='nearest')
myGenerator = trainGenerator(20,
GDRIVE + '/data/' + OBJ + '/train','image','label',
data_gen_args,
save_to_dir = GDRIVE + '/data/' + OBJ + '/train/aug',
target_size = (512,512))
num_batch = 3 # 3回繰り返す
for i,batch in enumerate(myGenerator):
if(i >= num_batch):
break
補足説明
以下、上記のコードの補足説明。
OBJ = ‘Cucumber’
data フォルダー配下の認識したい物体の定数。
異なる物体を学習したい時に data フォルダ配下に同じ構成で学習用データを格納すれば動作するように定数で指定している。
GDRIVE
Google Colaboratory から Google Drive を参照する時の Path を指定する。
Google Drive のマウントと Path を知る方法は以下の通り。
Google Colaboratory の左のメニューからファイルアイコンを選択して”ドライブをマウント”アイコンをクリックする。
Drive への接続許可の確認が表示されたら「Google ドライブに接続」をクリックする。

sample_data と同階層に drive フォルダが表示される。

drive フォルダの階層を辿って unet-master を選択したら、右クリックー>パスをコピーでGoogle Colaboratory から該当の Google Drive までの Path が取得できるので GDRIVE 定数にセットした。

path の追加
9 ~ 11 行目は Google Colaboratory から Google Drive に格納した data.py や model.py を参照する為に Path を通している。
パラメータ
データ拡張の為のパラメータ。
このパラメーターに基づいてランダムに画像を生成して学習用画像のデータ量を増やす。
- rotation_range:画像をランダムに回転する回転範囲
- width_shift_range:ランダムに水平シフトする範囲
- height_shift_range:ランダムに垂直シフトする範囲
- shear_range:シアー強度
- zoom_range:ランダムにズームする範囲
- horizontal_flip:水平方向に入力をランダムに反転
- fill_mode:指定されたモードに応じて入力画像の境界周りを埋める
fill_mode は以下の4種類が指定できる。
※keras のドキュメントより。
“constant”: kkkkkkkk|abcd|kkkkkkkk (cval=k)
“nearest”: aaaaaaaa|abcd|dddddddd
“reflect”: abcddcba|abcd|dcbaabcd
“wrap”: abcdabcd|abcd|abcdabcd
trainGenerator
data.py 内の関数。
内部では keras の ImageDataGenerator クラスを呼び出してデータを拡張している。
デフォルトで生成する画像のサイズは 256×256 なので、target_size = (512,512) を指定して 512×512 Pixel の画像を生成している。
学習
学習用データが揃ったら U-Net で学習を行う。
"""
augフォルダーの画像を学習して最適なモデルを保存する
@souichirou kikuchi
"""
VERSION = '_v01' # モデルのバージョン
OBJ = 'Cucumber' # 学習する物体
GDRIVE = '/content/drive/MyDrive/unet-master' # Google colab
import sys # 自作モジュールへのPathを追加する(colabで必要)
ROOT_PATH = GDRIVE
sys.path.append(ROOT_PATH)
from model import * # u-net model
from data import *
# u-netで学習
model = unet(input_size = (512, 512, 1)) # Input size指定
# チェックポイント
cp = ModelCheckpoint(GDRIVE + '/data/' + OBJ + '/model/unet_' + OBJ + VERSION + '.hdf5', # チェックポイント
monitor = 'val_loss', # 監視する値
verbose = 1, # 結果表示
save_best_only = True)
#過学習を防ぐための早期終了
es = EarlyStopping(monitor = 'val_loss',
patience = 50, # このepoch数、性能が向上しなければストップ
restore_best_weights = True)
imgs_train,imgs_mask_train = geneTrainNpy(GDRIVE + '/data/' + OBJ + '/train/aug/', GDRIVE + '/data/' + OBJ + '/train/aug/')
history = model.fit(imgs_train,
imgs_mask_train,
batch_size = 4,
epochs = 500,
verbose = 1,
validation_split = 0.2,
shuffle = True,
callbacks = # チェックポイント、早期終了
[cp,
es])
import matplotlib.pyplot as plt
# Plot training & validation accuracy values
plt.plot(history.history['accuracy'])
plt.plot(history.history['val_accuracy'])
plt.title('Model accuracy')
plt.ylabel('accuracy')
plt.xlabel('Epoch')
plt.legend(['Train', 'Test'], loc='upper left')
plt.show()
# Plot training & validation loss values
plt.plot(history.history['loss'])
plt.plot(history.history['val_loss'])
plt.title('Model loss')
plt.ylabel('Loss')
plt.xlabel('Epoch')
plt.legend(['Train', 'Test'], loc='upper left')
plt.show()
補足説明
以下、上記のコードの補足説明。
VERSION
学習済みモデルを保存する時のバージョン。
何度かパラメータを変更して学習を繰り返す際に以前のバージョンのモデルを残しつつ新しいパラメータで試したい時がある。
その際にモデルのファイル名に VERSION を埋め込んで管理する。
ModelCheckpoint
学習途中の最良のモデルを保存するためにチェックポイントを指定した。
monitor は監視する値を指定する。
- acc:正解率
- loss:損失(正解との誤差)
- val_acc:バリデーションデータの正解率
- val_loss:バリデーションデータの損失
が指定可能だが val_loss を指定した。(つまり Val_loss が最適なモデルだけを保存する)
後述するが学習用データはトレーニング用に8割、バリデーション(検証)用に2割をランダムに割り当てている。
トレーニングデータでの損失(正解との誤差)が少ないよりもバリデーションデータでの損失が少ないほうが汎用性が高いと判断して val_loss を指定している。
save_best_only は True を指定しているので上記の val_loss が最良のモデルだけを保存する。
この辺の事は先程の書籍の10章(人口ニューラルネットワークとKerasの初歩)に載っている。
EarlyStopping
学習が進まなかった時に早期に終了するように EarlyStopping を指定した。
具体的には patience で指定した 50 エポック連続して val_loss が向上しなった際には学習を停止する。
model.fit
fit メソッドで学習を行う。
epochs は Checkpoint と EarlyStopping を指定しているので最後まで進むことはまず無いと判断して大きめの値(500)を指定した。
validation_split でバリデーション(検証用)データの割合を指定する。
0.2 なのでトレーニング用8割、検証用2割となる。
shuffle = True を指定することでエポックごとに訓練データがシャッフルされてランダムな学習が行われる。
学習結果の表示
45行目以降で学習結果(推移)を表示してる。
正解率の推移

オレンジ色の test と表示されているのは Validation データの事(紛らわしいラベル名にしてしまった)
ある一定の所で train(学習用)データの正解率が向上しても Validation データの正解率が向上しなくなってしまっている事が分かる。
損失の推移

val_loss が指数関数的にゼロに近づいて収束するようなグラフになるのが理想なのだが、残念ながらそうならなかった。
学習データの量など様々な要因が考えられるのでもう少し試行錯誤が必要だと思う。
特に60 エポックを過ぎた辺りから train データの損失が減っているのにも関わらず Validation データの損失が上がるという過学習の傾向が出ている。
テスト画像変換
未学習の画像を10枚ピックアップして学習済みモデルでキュウリを正しく認識できるかを試す。
その前に元画像は 5472 x 3080 Pixels の RGB、JPG画像なので推論しやすい様に 512 × 512 のグレースケール、pngファイルに変換する。
test_org フォルダー内の JPG画像を全て読み込んでリサイズして test フォルダーに出力している。
またその際にファイル名を 0.png、1.png と数値の連番のファイル名に変更している。
"""
test_org配下の画像を読み込んでリサイズ、グレースケール化してtestフォルダに保存する
@souichirou kikuchi
"""
OBJ = 'Cucumber' # 学習する物体
GDRIVE = '/content/drive/MyDrive/unet-master' # Google colab
import argparse
import cv2
import os
import glob
input_dir = GDRIVE + '/data/' + OBJ + '/test_org'
output_dir = GDRIVE + '/data/' + OBJ + '/test/'
try:
files = glob.glob(input_dir + '/*.JPG')
i = 0
for file in files:
infile = cv2.imread(file)
ofile_name = output_dir + str(i) + '.png' # ファイル名を0からの連番、拡張子をpngに変更
infile = cv2.resize(infile, dsize=(512, 512)) # リサイズ
otfile = cv2.cvtColor(infile, cv2.COLOR_BGR2GRAY) # グレースケール
cv2.imwrite(ofile_name, otfile)
print('ofile_name = ', ofile_name)
i += 1
finally:
pass
推論
保存しておいた学習済みモデルを呼び出して推論(画像からキュウリの位置を判別する)を行う。
"""
test配下の画像を読み込んで推論する
@souichirou kikuchi
"""
VERSION = '_v01' # モデルのバージョン
OBJ = 'Cucumber' # 学習する物体
SAMPLE = 10 # ファイル数
GDRIVE = '/content/drive/MyDrive/unet-master' # Google colab
import sys # 自作モジュールへのPathを追加する(colabで必要)
ROOT_PATH = GDRIVE
sys.path.append(ROOT_PATH)
from model import * # u-net model
from data import *
# 学習済みモデルの読み込み
from tensorflow import keras
model = keras.models.load_model(GDRIVE + '/data/' + OBJ + '/model/unet_' + OBJ + VERSION + '.hdf5')
# testフォルダーのデータを呼び出す
testGene = testGenerator(GDRIVE + '/data/' + OBJ + '/test',
target_size = (512, 512))
results = model.predict(testGene,
steps = SAMPLE, # サンプルの総数
verbose = 1)
# 予測結果を_predict.pngで保存
saveResult(GDRIVE + '/data/' + OBJ + '/test', results)
補足説明
以下、上記のコードの補足説明。
SAMPLE
推論したい画像のファイル数。
load_model
保存しておいた val_loss が最適なモデルを呼び出す。
testGenerator
test フォルダー配下の png ファイルを順番に読んでリサイズして返す。
predict
予測を行う。
saveResult
予測した結果画像を保存する関数。
結果
10枚の画像を予測させてみた所、「まぁまぁ」の精度で予測が出来た。
まぁまぁと言うのは精度が良い画像とそうでない画像でばらつきが出てしまったからだ。
精度が良い画像の例

その2

上記の画像についてはほぼ正しいキュウリの位置が判別出来ている。
全体の 7 ~ 8割の画像が上記のような精度だった。
精度が悪い画像の例

こちらは手で掴んで横にしている。
元々キュウリを横にした時の画像は学習していないのと、前述の rotation_range でも 0.2 を指定していて、縦に上からぶら下がったキュウリのみを学習しているのでこれは致し方ない所。
この画像を正しく判別するには学習用画像を工夫する必要がある。

こちらの画像も精度が悪い例。
キュウリの右側に光が当たって反射している部分がキュウリの本体として認識されていない。
学習用データを見直した所、上記の様な光を反射して明るくなっている画像は見当たらなかった。
学習用データのバリエーションをもっと増やして学習させる必要がある。
その他
U-Net でも試行錯誤を繰り返すことで精度を向上させる事が可能だと分かった。
またU-Net以外では、SegNet や PSPNet(Pyramid Scene Parsing Network)は試してみたい。
以上で今回の記事は終了とする。
この記事が何処かで誰かの役に立つことを願っている。
尚、当記事中の商品へのリンクはAmazonアソシエイトへのリンクが含まれています。Amazonのアソシエイトとして、当メディアは適格販売により収入を得ていますのでご了承ください。
最近のコメント