I.はじめに
このブログは主に一部です, 個人的にはコアの1つだと思います. 結局, 正とATSS
負のサンプルの選択は非常に重要です.ATSS
論文は、パフォーマンスの違いの根本的な原因が正と負の定義にあることを確認しています.サンプル . で使用できる良いポジティブ サンプルとネガティブ サンプルの定義方法は、 モデル大幅の への依存度が。この点は、上記の「陽性サンプルと陰性サンプルの正しい定義により、より高品質の陽性サンプルを導入し、フィッティングを高速化し、モデルのパフォーマンスを向上させることができます」でも確認されています。最初によく書かれたATSS ブログをお勧めします. それを読んだ後、コードを読むことははるかに明確になります. そして、私が書いたコード コメントの ATSS 部分。anchor-based
anchor-free
Anchor Num
Anchor Size
yolo v5
2. テキスト
コードに従って要約されたプロセスはATSS
次のとおりです。
- each をトラバースし
ground truth
、各出力レイヤーをトラバースし、各レイヤーの前の最小距離 (および中心点の距離) を見つけますtopk
(ハイパーパラメーター、nanodet
中間は9
)です。出力レイヤーの合計がある場合、それぞれが候補に一致し、配列を出力します。これらには繰り返しがあるかもしれませんが、問題ではありません。以下にスクリーニング手段があります。L2
anchor
gt box
anchor
nanodet
3
gt
27
anchor
shape=(27, gt_num)
anchor
gt
それに対応する27
各sumanchor
の値を計算しますIOU
(これはsum ではなく、左上と右下の座標で行われることshape=(27, gt_num)
に注意してください。まだ到着していない正と負のサンプルを分類するためのものです)。anchor
iou
bbox
anchor
bbox
gt
列 ごとに対応する各27
値IOU
の平均mean_IOU
と標準偏差を計算しstd_IOU
、2 つを加算して各gt
適応しきい値を取得しますshape = (gt_num, )
。- それら
gt
のそれぞれから、対応する適応しきい値よりも大きいものを除外します。27
anchor
IOU
anchor
anchor
次に、各中心から対応する 4 つの境界線までの距離を計算しgt
、4 つの距離の中で最小値を取り、最小値が より小さいものを除外します。0.01
残りanchor
は選択された正のサンプルです。anchor
この時点で、複数の一致が同時に存在する可能性がありますgt
.このとき、IOU
最大の値を持つものをgt
一致オブジェクトとして選択する必要があります。つまり、1 つはanchor
1 つのみにしか一致できませんgt
が、1 つは同時に複数と一致するgt
可能性があります。anchcor
上記のプロセスから、anchor
陽性サンプルになるための 3 つの条件を満たす必要があります:
① その中心と任意の中心との間の距離が上gt
にある必要がありますtopk
(昇順で);
② その値が対応するしきい値よりも大きい必要があります; ③その値が対応するしきい値よりも大きい必要があります。中心と4 つの辺の間の距離は より大きい必要があります。これは疑問と思考につながります: 1. なぜ IOU 閾値は平均と標準偏差の合計を取るのですか? 個人的理解度: 平均は候補者と全体の一致度を表し、平均値が大きいほど全体的な一致度が高く、候補者の質が高いことを示します。標準偏差はデータの分散度を表しており、標準偏差が大きいほど、候補と一致度の差、つまり候補間の品質差が大きくなります。この 2 つを組み合わせることで、多くの低品質の候補を除外できます。gt
iou
iou
gt
0.01
anchor
gt
anchor
anchor
gt
anchor
anchor
anchor
2.中心から四辺gt
までの距離で候補者を選別する必要があるのはなぜですかanchor
?
個人的な理解:ATSS
この論文では、中心だけが内側anchor
にある必要があります。コードが実装されると、より大きなものに変更され、私の個人的な理解はアイデアに基づいています。次に問題は、中心が内側にある理由です。なぜなら、それは学習中心から4 つの境界までの距離であり、4 つの学習距離はすべて正の数だからです (以下のコードを参照)。中心が外側にある場合、モデルは引き戻された負の数を学習できません。第二に、センターは内部にあるため、学習する機能がさらに多くあります。gt
gt
0
0.01
label smooth
softmax 函数
0
anchor
gt
nanodet
anchor
gt
anchor
gt
anchor
gt
anchor
# 下面是 bbox 输出处理成 bbox 坐标的处理函数
class Integral(nn.Module):
def __init__(self, reg_max=16):
super(Integral, self).__init__()
self.reg_max = reg_max # 7
self.register_buffer(
"project", torch.linspace(0, self.reg_max, self.reg_max + 1) # 返回一维 tensor = [0, 1, 2, 3, ... reg_max]
)
def forward(self, x): # 输入 x 就是原始 bbox 输出
x = F.softmax(x.reshape(-1, self.reg_max + 1), dim=1) # softmax 之后,数据就是 (0, 1)之间了
x = F.linear(x, self.project.type_as(x)).reshape(-1, 4) # 与 self.project 做矩阵相乘,返回 (0, reg_max) 之间的数
return x # x 中每个元素都正数
gt
最後にお聞きしますが、社内でセンターとしての要件を上げてもanchor
よろしいでしょうか?この場合、1 つはgt
各出力層の 1 つにしか対応できずanchor
、高品質のポジティブ サンプルが削減されます. 前述のように、より高品質のポジティブ サンプルは、フィッティングを高速化し、モデルのパフォーマンスを向上させることができます.
3.なぜ追加するのですかgt_idx * num_bboxes
?
個人的な理解:
# num_gt 是一张图片中 gt 数目,num_bboxes 是 anchor 数目
# 下面是疑惑 1
for gt_idx in range(num_gt): # (topk * 3, num_gt)
candidate_idxs[:, gt_idx] += gt_idx * num_bboxes
ep_bboxes_cx = ( # (num_bboxes, ) -> (1, num_bboxes) -> (num_gt, num_bboxes) -> (num_gt * num_bboxes)
bboxes_cx.view(1, -1).expand(num_gt, num_bboxes).contiguous().view(-1) # 注意它的长度是 num_gt * num_bboxes
)
candidate_idxs = candidate_idxs.view(-1) # (topk * 3 * num_gt)
l_ = ep_bboxes_cx[candidate_idxs].view(-1, num_gt) - gt_bboxes[:, 0]
candidate_idxs = candidate_idxs.view(-1)
最初はなぜこうなったのか分からなかったのですcandidate_idxs[:, gt_idx] += gt_idx * num_bboxes
が、よく考えてみると、candidate_idxs
初期値の値はすべて相対的なものだから、ということでしょうか。下の写真を見てください。
candidate_idxs
のデータ分布は、上の図の左側のスタイルに似ています. 列の数はground truth
現在の入力画像の数であり、各列要素の意味はそれぞれground truth
に最も近いインデックス値です (出力レイヤー)、つまり行インデックスであり、3つの出力レイヤーがあるため、最後の. しかし、各列のインデックス値の範囲は です。これは、相対値の意味です。最終的には一次元ベクトルになるので相対位置が使えず、行数を考慮しなければならないことも足し算の理由です。しかし、奇妙なことは、行数が、コード内でどのようになっているかということです。これは、最後に処理された配列が、その、行数が正確であるためです。topk
anchor
shape = (topk, num_gt)
nanodet
candidate_idxs.shape = (topk * 3, num_gt)
[0, num_bboxes)
ep_bboxes_cx
view(-1)
gt_idx * num_bboxes
candidate_idxs
num_gt
num_bboxes
ep_bboxes_cx
shape = (num_gt * num_bboxes)
num_bboxes