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

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

新規登録して質問してみよう
ただいま回答率
85.35%
Keras

Kerasは、TheanoやTensorFlow/CNTK対応のラッパーライブラリです。DeepLearningの数学的部分を短いコードでネットワークとして表現することが可能。DeepLearningの最新手法を迅速に試すことができます。

YOLO

YOLOとは、画像検出および認識用ニューラルネットワークです。CベースのDarknetというフレームワークを用いて、画像や動画からオブジェクトを検出。リアルタイムでそれが何になるのかを認識し、分類することができます。

CNN (Convolutional Neural Network)

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

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

0回答

2407閲覧

YOLOv3のKeras版のloss計算がわからない

kyokio

総合スコア560

Keras

Kerasは、TheanoやTensorFlow/CNTK対応のラッパーライブラリです。DeepLearningの数学的部分を短いコードでネットワークとして表現することが可能。DeepLearningの最新手法を迅速に試すことができます。

YOLO

YOLOとは、画像検出および認識用ニューラルネットワークです。CベースのDarknetというフレームワークを用いて、画像や動画からオブジェクトを検出。リアルタイムでそれが何になるのかを認識し、分類することができます。

CNN (Convolutional Neural Network)

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

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

0グッド

0クリップ

投稿2021/01/09 15:59

Keras版のYOLOv3のlossがわからない

YOLOv3を実際に使ってみました。
エンジニアの眠れない夜さん、という方がKerasでYolov3を実装したもの少し改良したものこのサイトで解説していたのでそれを使いました。

本家:https://github.com/qqwweee/keras-yolo3
使用したもの(エンジニアの眠れない夜さんが改良したもの):https://github.com/sleepless-se/keras-yolo3
エンジニアの眠れない夜さんの解説ページ:https://sleepless-se.net/2019/06/21/how-to-train-keras%E2%88%92yolo3/

lossを表示するようにした

本家のものも元々epoch毎にloss(train,evaluation)を表示するようになっていました。
しかし、コードをみているとさらに詳しくlossを表示できるようになっていました。

keras-yolo3/yolo3/model.py

python

1 2def yolo_loss(args, anchors, num_classes, ignore_thresh=.5, print_loss=False): 3 '''Return yolo_loss tensor 4 Parameters 5 ---------- 6 yolo_outputs: list of tensor, the output of yolo_body or tiny_yolo_body 7 y_true: list of array, the output of preprocess_true_boxes 8 anchors: array, shape=(N, 2), wh 9 num_classes: integer 10 ignore_thresh: float, the iou threshold whether to ignore object confidence loss 11 Returns 12 ------- 13 loss: tensor, shape=(1,) 14 ''' 15 num_layers = len(anchors)//3 # default setting 16 yolo_outputs = args[:num_layers] 17 y_true = args[num_layers:] 18 anchor_mask = [[6,7,8], [3,4,5], [0,1,2]] if num_layers==3 else [[3,4,5], [1,2,3]] 19 input_shape = K.cast(K.shape(yolo_outputs[0])[1:3] * 32, K.dtype(y_true[0])) 20 grid_shapes = [K.cast(K.shape(yolo_outputs[l])[1:3], K.dtype(y_true[0])) for l in range(num_layers)] 21 loss = 0 22 m = K.shape(yolo_outputs[0])[0] # batch size, tensor 23 mf = K.cast(m, K.dtype(yolo_outputs[0])) 24 25 for l in range(num_layers): 26 object_mask = y_true[l][..., 4:5] 27 true_class_probs = y_true[l][..., 5:] 28 29 grid, raw_pred, pred_xy, pred_wh = yolo_head(yolo_outputs[l], 30 anchors[anchor_mask[l]], num_classes, input_shape, calc_loss=True) 31 pred_box = K.concatenate([pred_xy, pred_wh]) 32 33 # Darknet raw box to calculate loss. 34 raw_true_xy = y_true[l][..., :2]*grid_shapes[l][::-1] - grid 35 raw_true_wh = K.log(y_true[l][..., 2:4] / anchors[anchor_mask[l]] * input_shape[::-1]) 36 raw_true_wh = K.switch(object_mask, raw_true_wh, K.zeros_like(raw_true_wh)) # avoid log(0)=-inf 37 box_loss_scale = 2 - y_true[l][...,2:3]*y_true[l][...,3:4] 38 39 # Find ignore mask, iterate over each of batch. 40 ignore_mask = tf.TensorArray(K.dtype(y_true[0]), size=1, dynamic_size=True) 41 object_mask_bool = K.cast(object_mask, 'bool') 42 def loop_body(b, ignore_mask): 43 true_box = tf.boolean_mask(y_true[l][b,...,0:4], object_mask_bool[b,...,0]) 44 iou = box_iou(pred_box[b], true_box) 45 best_iou = K.max(iou, axis=-1) 46 ignore_mask = ignore_mask.write(b, K.cast(best_iou<ignore_thresh, K.dtype(true_box))) 47 return b+1, ignore_mask 48 _, ignore_mask = K.control_flow_ops.while_loop(lambda b,*args: b<m, loop_body, [0, ignore_mask]) 49 ignore_mask = ignore_mask.stack() 50 ignore_mask = K.expand_dims(ignore_mask, -1) 51 52 # K.binary_crossentropy is helpful to avoid exp overflow. 53 xy_loss = object_mask * box_loss_scale * K.binary_crossentropy(raw_true_xy, raw_pred[...,0:2], from_logits=True) 54 wh_loss = object_mask * box_loss_scale * 0.5 * K.square(raw_true_wh-raw_pred[...,2:4]) 55 confidence_loss = object_mask * K.binary_crossentropy(object_mask, raw_pred[...,4:5], from_logits=True)+ \ 56 (1-object_mask) * K.binary_crossentropy(object_mask, raw_pred[...,4:5], from_logits=True) * ignore_mask 57 class_loss = object_mask * K.binary_crossentropy(true_class_probs, raw_pred[...,5:], from_logits=True) 58 59 xy_loss = K.sum(xy_loss) / mf 60 wh_loss = K.sum(wh_loss) / mf 61 confidence_loss = K.sum(confidence_loss) / mf 62 class_loss = K.sum(class_loss) / mf 63 loss += xy_loss + wh_loss + confidence_loss + class_loss 64 if print_loss: 65 loss = tf.Print(loss, [loss, xy_loss, wh_loss, confidence_loss, class_loss, K.sum(ignore_mask)], message='loss: ') 66 return loss

引数print_lossTrueにすることで座標のlossや物体らしさのlossも表示できるよになっていました。
実際にTrueにして学習を始めました。

デフォルトのバッチ毎のlossがどう算出されているのかわからない

デフォルトでepoch毎にlossが表示されるようになっていました。
これに、各lossの要素を表示させるようにしたのですが、デフォルトで表示されていたlossがどう算出されているのかわからなくなりました。

バッチサイズが8なので、イテレーション数が45と少し大きくなってしまっています。
イテレーション毎に,追加で表示できるようにした3行と、デフォルトで表示される1行が表示されています。
また、2イテレーション目からはデフォルトの1行と、追加した3行の1行目がくっついてしまって少し見にくいです。

terminal

1Epoch 77/100 2loss: [0.00112403429][0][0][0.00112403429][0][4056] 3loss: [0.483635962][0.295098901][0.0329719149][0.151521251][0.00291984482][16211] 4loss: [5.05912161][3.7965045][0.0914081484][0.687040329][0.000532431][64813] 5 1/45 [..............................] - ETA: 6:07 - loss: 14.3107loss: [0.841492653][0.756406605][0.0261997879][0.0572859][0.00160039612][4045] 6loss: [1.05437315][0][0][0.212880522][0][16224] 7loss: [4.07512856][2.57389355][0.0328956842][0.413899839][6.65246407e-05][64856] 8 2/45 [>.............................] - ETA: 5:53 - loss: 13.8186loss: [0.00565941678][0][0][0.00565941678][0][4056] 9loss: [1.14869869][0.946963608][0.00321356696][0.190572932][0.00228901906][16198] 10loss: [3.88160229][2.08619761][0.0900533348][0.55626595][0.000387060485][64874] 11 3/45 [=>............................] - ETA: 5:43 - loss: 13.5901 12 13〜〜〜〜〜〜〜〜〜〜途中省略〜〜〜〜〜〜〜〜〜〜〜〜〜〜 14 15 1643/45 [===========================>..] - ETA: 17s - loss: 14.1779loss: [0.00286830892][0][0][0.00286830892][0][4056] 17loss: [0.419551402][0.272743404][0.00488948636][0.139018714][3.15062789e-05][16214] 18loss: [5.39081669][3.6976409][0.110790402][1.16261017][0.000223787909][64836] 1944/45 [============================>.] - ETA: 8s - loss: 14.1884 loss: [0.00183403213][0][0][0.00183403213][0][4056] 20loss: [0.100811586][0][0][0.0989775509][0][16224] 21loss: [6.96580219][4.60197926][0.119364366][2.14344907][0.000198043243][64863] 22loss: [0.00504041463][0][0][0.00504041463][0][4056] 23loss: [0.549805641][0.517534375][0.00138717762][0.0257636961][7.99672271e-05][16209] 24loss: [8.85879135][5.16708231][0.291379839][2.84919119][0.00133269036][64833] 25loss: [0.00155577867][0][0][0.00155577867][0][4056] 26loss: [0.516083777][0.494381607][0.00781512354][0.0121710934][0.000160135503][16207] 27loss: [5.35356617][3.19009471][0.09591043][1.55138481][9.22834297e-05][64864] 28loss: [0.273381025][0.25835669][0.00896113645][0.00550535647][0.000557833351][4049] 29loss: [0.278297663][0][0][0.00491663907][0][16224] 30loss: [5.53169441][3.86541033][0.142269686][1.2454083][0.00030882383][64860] 31loss: [0.00295466022][0][0][0.00295466022][0][4056] 32loss: [0.700160801][0.639695644][0.00319249812][0.0542003289][0.000117667536][16208] 33loss: [3.56559706][2.27359366][0.0472999066][0.544217169][0.000325717556][64852] 34loss: [0.328914076][0.238022715][0.00885274261][0.0818304718][0.000208131823][4054] 35loss: [1.10997081][0.538047314][0.00582101][0.237138301][5.01370305e-05][16204] 36loss: [5.01714611][3.136446][0.0846415386][0.685577154][0.000510753947][64856] 3745/45 [==============================] - 397s 9s/step - loss: 14.2335 - val_loss: 14.9158

追加で表示してるlossが3行なのは、YOLOv3は3つのスケールで検出を行うことで制度を向上させているからです。
先ほどのコードの以下の部分からもわかるように、各スケールで出したlossを足していき3つのスケールのlossの総和を返す関数のはずです。

terminal

1xy_loss = K.sum(xy_loss) / mf 2 wh_loss = K.sum(wh_loss) / mf 3 confidence_loss = K.sum(confidence_loss) / mf 4 class_loss = K.sum(class_loss) / mf 5 loss += xy_loss + wh_loss + confidence_loss + class_loss 6 if print_loss: 7 loss = tf.Print(loss, [loss, xy_loss, wh_loss, confidence_loss, class_loss, K.sum(ignore_mask)], message='loss: ')

実際に以下の部分を見てみるとその通りになっています。

1項目がlossで6項目がmaskなので、1行目の25項目を足すと1項目にちゃんとなっています。
また、2行目の2
5項目を1行目の1項目に足すと2行目の1項目にちゃんとなっています。

なので、4行目(デフォルトで表示される行)のlossは3行目の1項目が返り値として返されるはずでずが、3倍ほどの大きな数が返されています。

loss: [0.00761187][0][0][0.00761187][0][4056] loss: [0.403536707][0.375777543][0.00191301759][0.0181565415][7.77586756e-05][16205] loss: [4.43683815][2.7867403][0.0958145261][1.15047038][0.000276135019][64869] 27/45 [=================>............] - ETA: 2:34 - loss: 14.2255loss: [0.00143866753]

試したこと

Kerasのサイトを見たのですが、やはりmodel.compailで渡されたlossが表示されるはずなのですがそうなっていません。

コードを見てみましたが、わかりませんでした。
コード見てデフォルトのlossがどう算出されているかわかる方がいましたら教えていただけるとありがたいです。

補足情報(FW/ツールのバージョンなど)

デフォルトの場合の出力はこんな感じで、1epochで1行表示されイテレーション毎に書き変わります。

terminal

1Epoch 22/50 2 52 45/45 [==============================] - 97s 2s/step - loss: 29.0213 - val_loss: 31.3032 3 53 Epoch 23/50 4 54 45/45 [==============================] - 98s 2s/step - loss: 29.0296 - val_loss: 30.0432 5 55 Epoch 24/50 6 56 45/45 [==============================] - 98s 2s/step - loss: 28.4512 - val_loss: 29.5296 7 57 Epoch 25/50 8 58 45/45 [==============================] - 97s 2s/step - loss: 28.0364 - val_loss: 30.4988

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

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

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

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

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

guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

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

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

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問