-------【2017.11.2 更新】------------SSD ポータル ----------
http://blog.csdn.net/renhanchi/article/details/78411095
------- 【2017.10.30 更新】------------ いくつか言いたいこと -----------
このブログを書いた後、ほとんど darknet と yolo を使用していませんが、この半年以上、私はこのブログを更新し続け、皆さんの問題を解決するために努力してきました。
このブログを通じて darknet と yolo の使用方法、特に detection に関する知識を学びたい方は、本文の一言一言を注意深く、真剣に読んでいただければと思います。
最近、著者のコードが大幅に変更され、多くの部分が私が書いたブログの内容と異なっています。今、私は当初ダウンロードした darknet を皆さんに提供します。
** 新旧バージョンの違いはコードにありますが、アルゴリズムの構造は同じなので、古いバージョンを安心して使用してください。
**
解凍後、ディレクトリに入り、Makefile を設定したら、直接 make all を実行すれば大丈夫です。
https://pan.baidu.com/s/1jIR2oTo
1. 前言#
yolo を使って自分の VOC 形式データをトレーニングするブログは本当にたくさんありますが、彼らの方法に従って一歩一歩進んでいくと、他の著者が言及していない問題が発生しました。ここでは、私自身の経験を基に、自分のデータセットをトレーニングする方法についてお話しします。
2. データセット#
ここでは、VOC と ILSVRC コンペティションのデータセットを使用することをお勧めします。なぜなら、xml ファイルがすでに用意されているので、多くの手間が省けるからです。
自分でラベル付けしたい方は、github で labelImg を検索し、make をダウンロードして直接実行すれば大丈夫です。具体的な使用方法についてはここでは詳しく述べません。
既存のデータセットを直接ダウンロードすることもできます。
ILSVRC2015 コンペティションのアドレスは: http://image-net.org/challenges/LSVRC/2015/download-images-3j16.php
VOC コンペティションのアドレスは: http://host.robots.ox.ac.uk/pascal/VOC/index.html
私のデータセットは、VOC2007、VOC2012、ILSVRC2013、ILSVRC2014 のすべての人に関するデータセットを単独で取り出したもので、私は人を単独で検出するトレーニングを行いたいと思っています。ILSVRC の拡張子は JPEG ですが、jpg に変更しても変更しなくても大丈夫です。darknet のコードは JPEG 形式にも対応しています。しかし、将来的に手間を省くために、私はすべて jpg の拡張子に変更しました。
VOC のすべての人に関するデータセットを単独で取り出す方法については、以下のシェルスクリプトを使用できます。少し変更すれば ILSVRC のデータを抽出するのにも使えます。ILSVRC データセット内の人のカテゴリは person ではなく、n00007846 です。これは xml ファイル内で後のトレーニングに影響しないので、特に n00007846 を person に変更する必要はありません。理由は、labels.txt ファイル内ではカテゴリが数字 0,1,2,3 などで表されており、単語ではないからです。これらの数字は data/names.list 内のカテゴリのインデックスに対応しています。
#!/bin/sh
year="VOC2012"
mkdir /your_path/VOCperson/${year}_Anno/ #フォルダを作成
mkdir /your_path/VOCperson/${year}_Image/
cd /your_path/VOCdevkit/$year/Annotations/
grep -H -R "<name>person</name>" > /your_path/VOCperson/temp.txt #キーワードを含む行を見つけ、これらの行を一時文書に保存
cd /your_path/VOCperson/
cat temp.txt | sort | uniq > $year.txt #名前でソートし、隣接する同じ内容の余分な行を削除。
find -name $year.txt | xargs perl -pi -e 's|.xml:\t\t<name>person</name>||g' #文書内の拡張子と他の無駄な情報を削除し、拡張子のないファイル名のみを保持
cat $year.txt | xargs -i cp /your_path/VOCdevkit/$year/Annotations/{}.xml /your_path/VOCperson/${year}_Anno/ #ファイル名に基づいて注釈ファイルをコピー
cat $year.txt | xargs -i cp /your_path/VOCdevkit/$year/JPEGImages/{}.jpg /your_path/VOCperson/${year}_Image/ #ファイル名に基づいてデータセットをコピー
rm temp.txt
3. トレーニングファイル#
3.1 フォルダ設定#
Annotations ---- このフォルダにはすべての xml 記述ファイルを置きます。
JPEGImages ---- このフォルダにはすべての jpg 画像ファイルを置きます。
ImageSets -> Main ----
このフォルダには names.txt 文書(私のこの文書の名前は:train.txt、注意:この名前は下記の python コードのリスト sets の第二要素の内容と一致する必要があります)、文書の内容はすべてのトレーニングセット画像の名前で、拡張子はありません。
PS:公式に付属のトレーニング VOC 方法では、画像は 2007 年と 2012 年の 2 つの異なるパスにそれぞれ置かれていますが、私は面倒だと思ったので、すべてのファイルを 1 つのフォルダにまとめました。
3.2 txt 文書#
合計で 3 種類の txt 文書を準備する必要があります:
まずは上記で言及した ImageSets フォルダ内のすべてのトレーニングデータ名の names.txt 文書。
次に、すべての画像に対応する labels.txt。この文書は scripts/voc_label.py
というファイルによって生成されますが、パスは少し変更する必要があります。私はすべての画像ファイルと xml ファイルをそれぞれ 1 つのフォルダに置き、トレーニングカテゴリは person のみです。したがって、最初の sets と classes も変更する必要があります。ここで注意すべき点は、ILSVRC データセットを使用している場合、私と同じように xml ファイル内の n00007846 を人に変更していない場合、classes を n00007846 に変更する必要があることです。そうしないと、このカテゴリの bbox 情報を見つけることができません。また、ILSVRC データセットの xml ファイルには difficult という情報がないため、.py ファイル内のこの点に関する内容はコメントアウトしておけば大丈夫です。
最後に、すべてのトレーニング画像の絶対パスを保存した paths.txt 文書。注意:この文書内の画像ファイル名には jpg の拡張子が含まれています。上記の labels.txt 文書を生成する際に、最後に自動的に paths.txt が生成されます。
以下は私の.py ファイルです。
import xml.etree.ElementTree as ET
import pickle
import os
from os import listdir, getcwd
from os.path import join
sets=[('person','train')]
classes = ["n00007846"]
def convert(size, box):
dw = 1./(size[0])
dh = 1./(size[1])
x = (box[0] + box[1])/2.0 - 1
y = (box[2] + box[3])/2.0 - 1
w = box[1] - box[0]
h = box[3] - box[2]
x = x*dw
w = w*dw
y = y*dh
h = h*dh
return (x,y,w,h)
def convert_annotation(year, image_id):
in_file = open('/home/hans/darknet/person/VOC%s/Annotations/%s.xml'%(year, image_id))
out_file = open('/home/hans/darknet/person/VOC%s/labels/%s.txt'%(year, image_id), 'w')
tree=ET.parse(in_file)
root = tree.getroot()
size = root.find('size')
w = int(size.find('width').text)
h = int(size.find('height').text)
for obj in root.iter('object'):
# difficult = obj.find('difficult').text
cls = obj.find('name').text
if cls not in classes: # or int(difficult)==1:
continue
cls_id = classes.index(cls)
xmlbox = obj.find('bndbox')
b = (float(xmlbox.find('xmin').text), float(xmlbox.find('xmax').text), float(xmlbox.find('ymin').text),
float(xmlbox.find('ymax').text))
bb = convert((w,h), b)
out_file.write(str(cls_id) + " " + " ".join([str(a) for a in bb]) + '\n')
wd = getcwd()
for year, image_set in sets:
if not os.path.exists('/home/hans/darknet/person/VOC%s/labels/'%(year)):
os.makedirs('/home/hans/darknet/person/VOC%s/labels/'%(year))
image_ids = open('/home/hans/darknet/person/VOC%s/ImageSets/Main/%s.txt'%(year, image_set)).read().strip().split()
list_file = open('%s_%s.txt'%(year, image_set), 'w')
for image_id in image_ids:
list_file.write('%s/VOC%s/JPEGImages/%s.jpg\n'%(wd, year, image_id))
convert_annotation(year, image_id)
list_file.close()
3.3 トレーニング設定ファイル#
まず、data フォルダ内に person.names ファイルを作成し、内容は person のみです。
次に、cfg フォルダ内の voc.data ファイルを修正し、classes を 1 に変更します。train に対応するパスは上記の paths.txt です。
names に対応するパスは person.names ファイルです。backup に対応するパスはトレーニング重みファイルのバックアップです。
最後に.cfg ネットワークを選択します。darknet の公式サイトや多くのブログでは yolo-
voc.cfg を使用していますが、私はこのネットワークでトレーニングしても常に失敗しました。トレーニングが長時間行われた後、test を行っても bbox や predict 結果が出ません。このような問題が発生する理由は 2 つあります。1 つはトレーニングが発散したこと、もう 1 つはトレーニングが不十分で、predict 結果の信頼度が低すぎることです。トレーニングが発散した場合は、トレーニング中にイテレーション回数の後ろにある 2 つの loss 値を観察することで簡単に発見できます。この 2 つの値が何百も増加し続ける場合は、トレーニングが発散していることを示しています。learning
rate を下げたり、batch 数を増やしたりすることでこの問題を解決できます。パラメータの変更とトレーニング出力がそれぞれ何を意味するのかについては、後で触れます。
トレーニングが不十分な場合に predict 結果を表示するには、test 時に threshold を設定できます。darknet のデフォルトは.25 ですが、この値を徐々に下げて効果を見てみることができます。
./darknet detector test cfg/voc.data cfg/yolo_voc.cfg -thresh 0.25
当時、darknet の理解がまだ不十分だったため、上記の問題を解決できなかったとき、私は現在使用している yolo-voc.2.0.cfg というネットワークに切り替えました。この中のパラメータについて簡単に説明します:
batch:
各イテレーションでネットワークに送信される画像の数、バッチ数とも呼ばれます。これを増やすことで、ネットワークは少ないイテレーション数で 1 つの epoch を完了できます。最大イテレーション数が固定されている前提で、batch を増やすとトレーニング時間が延長されますが、勾配降下の方向をより良く見つけることができます。十分な GPU メモリがある場合は、この値を適度に増やしてメモリの利用率を向上させることができます。この値は皆さんが試行錯誤して選択する必要があります。小さすぎるとトレーニングが収束しなくなり、大きすぎると局所最適に陥ります。
subdivision:
このパラメータは非常に興味深いもので、各バッチを一度にネットワークに投入するのではなく、subdivision に対応する数の部分に分けて、各部分を完了した後にまとめて 1 回のイテレーションとして計算します。これにより、GPU メモリの使用量が減少します。このパラメータを 1 に設定すると、すべてのバッチの画像を一度にネットワークに投入します。2 に設定すると、半分を一度に投入します。
angle: 画像の回転角度で、トレーニング効果を高めるために使用されます。本質的には、画像を回転させることでトレーニングサンプルセットを間接的に増やすことを目的としています。
saturation,exposure,hue: 彩度、露出、色調は、すべてトレーニング効果を高めるために使用されます。
learning_rate: 学習率で、トレーニングが発散した場合は learning_rate を下げます。学習が行き詰まって loss が変わらない場合も learning_rate を下げます。
max_batches: 最大イテレーション数。
policy: 学習ポリシーで、一般的には step という段階的なものです。
step,scales: この 2 つは組み合わせて使用されます。例えば:learn_rate: 0.001, step:100,25000,35000
scales: 10, .1, .1 というデータの意味は、0-100 イテレーションの間は learning
rate が元の 0.001 であり、100-25000 イテレーションの間は learning
rate が元の 10 倍の 0.01 であり、25000-35000 イテレーションの間は learning rate が現在の 0.1 倍、つまり 0.001 であり、35000 から最大イテレーションの間は learning
rate が現在の 0.1 倍、つまり 0.0001 になります。イテレーションが増えるにつれて learning rate を下げることで、モデルがより効果的に学習し、train loss をより良く減少させることができます。
最後の畳み込み層の filters の数値は 5×(クラス数 + 5)です。具体的な理由はここでは多くを語りませんが、知っておいてください。
region 内の classes を自分のクラス数に変更する必要があります。
最後の行の random
はスイッチです。1 に設定すると、トレーニング中に各バッチの画像が 320-640(32 の倍数)サイズの画像にランダムに変更されます。目的は上記の彩度、露出などと同じです。0 に設定すると、すべての画像はデフォルトのサイズ 416*416 にのみ変更されます。(2018.04.08 更新、コメントで友人が言っていたように、ここを 1 に設定すると、トレーニング中に obj と noobj がすべて 0 になる場合があり、0 に設定するとすべて正常になります。)
3.4 トレーニング開始#
自分のトレーニング効率を向上させるために、pre_trained ファイルをダウンロードすることができます。
以上のすべての準備が整ったら、自分のモデルをトレーニングすることができます。
ターミナルで実行:
./darknet detector train cfg/voc.data cfg/yolo_voc.cfg darknet19_448.conv.23
-------- 【2017.06.29 更新】 --------- 新バージョンのソースコードが大幅に変更され、古いバージョンは以下の内容を参照できます --------------------------------------
ここで一つ言いたいのは、他のブログには.c ソースファイルを変更するように書かれていますが、実際、私たちのような怠け者には変更する必要はありません。理由は、公式サイトに test を実行するためのコードがあり、以下のようになります:
./darknet detect cfg/yolo.cfg yolo.weights data/dog.jpg
これは簡略化された実行文です。その完全な形式は以下の通りです:
./darknet detector test cfg/coco.data cfg/yolo.cfg yolo.weights data/dog.jpg
実際、.c ファイルを変更する目的は、簡略化された test 実行文を使用できるようにするためで、プログラムは自動的に.c 内に設定されたパスの内容を呼び出します。私個人としては、これはあまり必要ないと思います。また、最新のバージョンでは yolo.cu というファイルはすでに存在しません。
4. トレーニング出力#
ここでは、出力に関するものが何であるかについてお話ししますが、私もあまり理解していないので、有用なものだけを選んでお話しします。
Region Avg IOU: これは予測された bbox と実際にラベル付けされた bbox の交差部分を彼らの合併部分で割ったものです。明らかに、この数値が大きいほど、予測結果が良いことを示します。
Avg Recall: これは平均再現率を示し、物体の検出数をラベル付けされたすべての物体の数で割ったものです。
count: ラベル付けされたすべての物体の数です。 count = 6、 recall = 0.66667 の場合、これは合計で 6 つの物体(異なるカテゴリが含まれる可能性がありますが、カテゴリは関係ありません)があり、私は 4 つを予測したので、Recall は 4 を 6 で割った値、すなわち 0.66667 です。
最初の行は上記と異なり、最初にイテレーション回数、次に train loss、次に avg train loss、次に学習率、次に 1 バッチの処理時間、次にすでに処理した画像の数が表示されます。重点的に注目すべきは train loss と avg train
loss で、これらの 2 つの値はイテレーションが増えるにつれて徐々に減少するべきです。もし loss が何百も増加した場合、それはトレーニングが発散していることを示します。もし loss が一定の期間変わらない場合、learning
rate を下げるか、batch を変更して学習効果を強化する必要があります。もちろん、トレーニングがすでに十分である可能性もあります。これは自分で判断する必要があります。
5. 可視化#
ここでは、loss の可視化に関する matlab コードを共有します。loss の変化曲線を直感的に見ることができます。
まず、トレーニング中に script コマンドを使用してターミナルの出力をすべて txt 文書に記録できます。
script -a log.txt
./darknet detector train cfg/voc.data cfg/yolo_voc.cfg darknet19_448.conv.23
トレーニングが完了したら、ctrl+D を押すか exit と入力して画面録画を終了することを忘れないでください。
以下は matlab コードです:
clear;
clc;
close all;
train_log_file = 'log.txt';
[~, string_output] = dos(['cat ', train_log_file, ' | grep "avg," | awk ''{print $3}''']);
train_loss = str2num(string_output);
n = 1:length(train_loss);
idx_train = (n-1);
figure;plot(idx_train, train_loss);
grid on;
legend('Train Loss');
xlabel('iterations');
ylabel('avg loss');
title(' Train Loss Curve');
私が描いたのは avg train
loss の曲線図です。ここで batch は 8 で、曲線の振動幅は非常に大きいです。学習率は 0.0001 で、25000 回のイテレーション後に 0.00001 に下げました。皆さんは後半の loss が 7-8 の範囲で安定し、減少が明らかでなくなったことに注意してください。私の理解では、これは 2 つの状況に直面している可能性があります。1 つは局所最適に陥っていること、もう 1 つは学習が行き詰まっていることです。しかし、この問題を解決することはできませんでした。batch を減らして学習効果を高めると、loss は変わらず、batch を増やすとネットワークが全体を考慮し、loss がわずかに減少します。learning rate を下げて学習効果を高めると、わずかに減少し、変わらず。希望する方がこの文を見て、指導していただければ幸いです。25000 回のイテレーション後にわずかに減少したのは、learning
rate を下げたからですが、減少は明らかではなく、すぐに再び安定しました。トレーニングセットは 4.3W + で、ILSVRC2015 トレーニングセットと VOC2012 トレーニングセットから人に関するすべてのデータを選び出したものです。
----------- 【2017.09.26 更新】 -----------------
ずっと怠けていてこの補足説明を書いていませんでしたが、上記で局所最適に陥っている可能性があると述べました。多くの作業を行っても改善されませんでした。私はずっと caffe の loss 基準を darknet に適用していましたが、実際にはこれは大きな問題です。なぜなら、2 つのフレームワークの出力 loss は必ずしも同じ単位ではないからです。実際、上記でトレーニングしたモデルの実際の使用効果は非常に良好で、遠くの小さな人の頭も検出できます。
また、今振り返ってみると、上記のトレーニングパラメータは改善の余地があると思います。ここに記録しておきますので、今後 darknet を使用する際に便利です。ファインチューニングを行っているため、learning rate は非常に低いのは問題ありませんが、相応の momentum を適度に増やすことを検討できます。0.9 から 0.99 に調整することができます。また、学習ポリシーを poly に変更することも考えられます。
----------- 【2017.10.30 更新】 ------------------------
最近、いくつかの detection に関する作業に取り組み始め、darknet を振り返ってみると、もう一つ訂正したいことがあります。detection に関しては、モデルの良し悪しを盲目的に loss で判断すべきではありません。loss はトレーニングが正常に行われているかどうかを判断するために使用されるべきです。例えば、トレーニングの最初に loss がずっと上昇し、最終的に NAN になる場合は、learning rate が大きすぎることを示しています。では、どの数値を使用してモデルの良し悪しを評価すべきでしょうか?それは mAP であるべきです。これは現在の主流基準で、実際には平均精度を示します。darknet のトレーニングプロセスでは精度の結果が出力されないため、再現率を通じて判断することもできます。再現率が 1.0 に近いほど、モデルが実際の物体の数をより正確に検出していることを示します。古いバージョンの darknet を使用している場合、ソースコードを変更することで、テスト段階で精度を出力することができます。具体的な内容は本文中に記載しています。
----------- 【2017.11.30 更新】IOU を追加 --------------
IOU の出力は以前は無視していましたが、この出力はトレーニング段階でモデルが正しくトレーニングされているかどうか、また最終的な効果がどうであるかを判断するためにも使用できます。
----------------- 【 2017.09.19 更新】 python 可視化コード --------------------------------------------
最初は caffe 用に書いたものですが、理屈は同じなので、これも更新します。
#!/usr/bin/env python2
# -*- coding: utf-8 -*-
"""
Created on Tue Aug 29 10:05:13 2017
@author: hans
http://blog.csdn.net/renhanchi
"""
import matplotlib.pyplot as plt
import numpy as np
import commands
train_log_file = "vegetable_squeezenet.log"
display = 10 #solver
test_interval = 100 #solver
train_output = commands.getoutput("cat " + train_log_file + " | grep 'avg,' | awk '{print $3}'") #train loss
train_loss = train_output.split("\n")
_,ax1 = plt.subplots()
l1, = ax1.plot(display*np.arange(len(train_loss)), train_loss)
ax1.set_xlabel('Iteration')
ax1.set_ylabel('Train Loss')
plt.legend([l1], ['Train Loss'], loc='upper right')
plt.show()
もし変動が大きすぎて、変化の傾向が見にくい場合は、
http://blog.csdn.net/renhanchi/article/details/78411095
の可視化コードを参考にして、少し変更すれば大丈夫です。
6. モデルの評価#
-------- 【2017.07.03 更新】 -------------------------------------------------------------------------
以下のコマンドは新バージョンの darknet には適用されません( もしあなたが上記の百度クラウドから古いバージョンの darknet をダウンロードした場合、以下のコマンドは適用されます )
まず、以下のコマンドを使用します:
./darknet detector recall cfg/xxx.data cfg/xxx.cfg backup/xxx.weights
以下のコマンドは新バージョンに適用されます
xxxx.data ファイル内の train の下に次の一文を追加します: valid=path/to/valid/images.txt
./darknet detector valid cfg/.....data cfg/.....cfg backup/....weights
その後、一連の数字が出力されますが、これは何でしょうか??
------ 【2017.06.29 更新】 --- ソースコードが大幅に変更され、新バージョンでは以下の内容は適用されません - -----------
もしあなたが上記の百度クラウドから古いバージョンの darknet をダウンロードした場合、以下のコマンドは適用されます
出力は累積され、結果は recall のみで、precision はありません。なぜなら、第一世代の yolo には一定の欠陥があり、precision は他の方法と比較して非常に低いため、著者は threshold を特に低く設定し、recall のみを見て precision を放棄したからです。第二世代の yolo はこの欠陥を修正したため、コードを変更して precision を出力することができます。皆さんは src/detector.c を開き、validate_detector_recall 関数を見つけて、float thresh = .25;
を設定して threshold を変更します。ここでは 0.25 に変更しました。元の著者の値は 0.0001 でした。最初の precision は 1% 程度でした -0-。
次に、以下の文を見つけてください。
fprintf(stderr, "%5d\t%5d\t%5d\tRPs/Img: %.2f\tIOU: %.2f%%\tRecall:%.2f%%\t", i, correct, total, (float)proposals/(i+1),
avg_iou*100/total, 100.*correct/total);
これを以下の文に変更します。
fprintf(stderr, "Number: %5d\tCorrect: %5d\tTotal: %5d\tRPs/Img: %.2f\tIOU: %.2f%%\tRecall:%.2f%%\tProposals: %5d\t
Precision: %.2f%%\n", i, correct, total, (float)proposals/(i+1), avg_iou*100/total, 100.*correct/total, proposals,
100.*correct/(float)proposals);
~~
~~
再度 make を実行し、recall コマンドを再度実行すると、precision が得られます。
------ 【2017.12.22 更新】 --- correct の再表現 -----------------------------------------
Correct は正しく認識された bbox の数を示します。この値の計算手順は以下の通りです。ネットワークに 1 枚の画像を投入すると、ネットワークは各クラスの物体に対して多くの bbox を予測します。各 bbox には信頼度があり、確率が threshold を超える特定のクラスの物体の bbox と実際の bbox(labels 内の txt の内容)を IOU で計算し、現在のクラスの物体の IOU が最大の bbox を見つけます。この最大値が設定された IOU の threshold を超える場合、現在のクラスの物体が正しく分類されたことを示し、correct が 1 増えます。
もう少し言うと、bbox の threshold はコマンドラインで -
thres を通じて調整でき、上記で述べた precision を出力するための threshold でもあります。IOU の threshold はソースコードを通じてのみ調整できます。
出力パラメータについて、私の理解は以下の通りです。
Number は処理された画像の数を示します。
Correct
は正しく認識された bbox の数を示します。この値の計算手順は以下の通りです。ネットワークに 1 枚の画像を投入すると、ネットワークは多くの bbox を予測し、各 bbox には信頼度があり、確率が threshold を超える bbox と実際の bbox(labels 内の txt の内容)を IOU で計算し、IOU が最大の bbox を見つけ、最大値が設定された IOU の threshold を超える場合、correct が 1 増えます。
Total は実際に存在する bbox の数を示します。
Rps/img は平均して各画像が予測する bbox の数を示します。
IOU は上記で説明した通りです。
Recall は上記で説明した通りで、Correct を Total で割った値です。
Proposal はすべての予測された bbox の中で、threshold を超える bbox の数を示します。
Precision は精度を示し、Correct を Proposal で割った値です。
予測された bbox と recall、precision に関する論理的なことについて、もう少し詳しく説明します。
例えば、人を認識する場合
-
画像内に実際に n 人がいて、それに対応する n 個の bbox 情報があります。この n の値が Total の値です。
-
画像をネットワークに投入すると、N 個の bbox が予測されます。この N 個の bbox の中で、信頼度が threshold を超える bbox の数が Proposal の値、記号として Npro です。
-
n 個の実際の bbox と Npro 個の bbox を IOU で計算し、n 個の IOU が最大の bbox を得ます。この n 個の IOU が最大の bbox は IOU threshold と比較され、nCor 個の IOU threshold を超える bbox が得られます。nCor は Correct の値です。nCor は n 以下です。
-
Total、Proposal、Correct が得られたら、Recall と Precision を計算できます。
要約すると、画像をネットワークに投入すると、Npro 個の物体が予測されますが、予測が正しいものもあれば、間違っているものもあります。nCor は予測が正しい物体の数です。Recall は予測が正しい物体の数(nCor)と実際の物体の数(Total)の比率を示します。Precision は予測が正しい物体の数(nCor)とすべての予測された物体の数(Proposal)の比率を示します。上記で述べたように、著者が threshold を 0.0001 に設定した場合、Proposal の値(Npro)は非常に大きくなり、Correct の値(nCor)もそれに応じて大きくなります。これにより、計算された Recall 値は非常に大きくなりますが、Precision 値は非常に低くなります。
注:上記の内容は一部 http://blog.csdn.net/hysteric314/article/details/54097845
を参考にしています。
recall、precision、IOU に関する詳細は、こちらの記事を参照してください
http://blog.csdn.net/hysteric314/article/details/54093734