コード(1)を使用したpy-MDNetの詳細な説明:train

コード(1)を使用したpy-MDNetの詳細な説明:train


それはすべて0202です、なぜあなたはまだMDNet(CVPR2016)のそのような初期のアルゴリズムを見る必要があるのですか?その理由は次のとおりです。

  • このホワイトペーパーには、より古典的なオンライン更新の実装があります。これは、将来そのような手法を理解するためのリファレンスとして使用できます。
  • 本質的に分類されているトラッカとして、それはVOT2015の勝者を得、次いでVOT2018-LT-の勝者MBMDはまたMDNetから借用します

ペーパーリンク:ビジュアルトラッキングのためのマルチドメイン畳み込みニューラルネットワークの学習[国内ミラー]
コード:https//github.com/hyeonseobnam/py-MDNet
この記事では、最初に記事全体の簡単な部分であるtrainを紹介します。

建築

MDNetの全体的なアーキテクチャ
このホワイトペーパーの図は、MDNetの全体的なアーキテクチャを明確に示しています。

  • ネットワークは、共有レイヤーとドメイン固有レイヤーの2つの部分に分かれています。前者はVGG-Mモデルと事前トレーニングパラメーターを使用し、後者はKドメインとも呼ばれるKトレーニングシーケンスに対応するKブランチを持っています(ここではのみconv部分が事前トレーニング済みモデルにロードされ、次にconvとfcの両方がオフライン学習フェーズでトレーニングされます)
  • トレーニングプロセス中に、各反復はシーケンスから32個の正のサンプルと96個の負のサンプルを抽出してミニバッチを形成し、対応するfc 6 k fc6 ^ {k}をトレーニングします。f c 6kブランチ(つまり、すべてのエポック、各fc6ブランチは順番に1回トレーニングされます)
  • fc6の各ブランチは、ターゲットとバックグラウンドのpos_scoreとneg_scoreをそれぞれ表す2次元の特徴を出力します。正のサンプルのラベルは[0、1]、負のサンプルのラベルは[1、0]であり、損失はバイナリクロスエントロピー:バイナリソフトマックスクロスエントロピー損失

次に、これらの重要な部分がコードの観点からどのように実装されているかを見てみましょう。最も重要なことは、正と負のサンプルを生成する方法です。

地域

MDNetは分類を使用してターゲットを判断するため、主に次の2つの文を使用して、分類器をトレーニングするために正と負のサンプルを作成する必要があります。

dataset[k] = RegionDataset(seq['images'], seq['gt'], opts)
# take vot2013/cup sequence for example
# seq['images'] -> 'datasets/VOT/vot2013/cup/00000001.jpg',...
# seq['gt'] -> (303, 4) np.ndarray
# training
pos_regions, neg_regions = dataset[k].next()

また、RegionDatasetクラスの下に__next__()32個のpos_regionsと96個のneg_regions生成する魔法のメソッドがあります。ここでは、8つのフレームがシーケンスで選択され、4つのpos_regionsと12つのneg_regionsが各フレームで生成されます。その中で、pos_regionsはGTのIoUの間にあります。 BBOX [サンプルは0.7の間、1]; neg_regionsは間IOU GTのバウンディングボックスを有するサンプルである[0、0.5]を、紙に記載されているようにFor offline multi-domain learning, we collect 50 positive and 200 negative samples from every frame, where positive and negative examples have ≥ 0.7 and ≤ 0.5 IoU overlap ratios with ground-truth bounding boxes, respectively.

def __next__(self):
    next_pointer = min(self.pointer + self.batch_frames, len(self.img_list)) # 8
    idx = self.index[self.pointer:next_pointer]
    if len(idx) < self.batch_frames:
        self.index = np.random.permutation(len(self.img_list))
        next_pointer = self.batch_frames - len(idx)
        idx = np.concatenate((idx, self.index[:next_pointer]))
    self.pointer = next_pointer

    pos_regions = np.empty((0, 3, self.crop_size, self.crop_size), dtype='float32')
    neg_regions = np.empty((0, 3, self.crop_size, self.crop_size), dtype='float32')
    for i, (img_path, bbox) in enumerate(zip(self.img_list[idx], self.gt[idx])):
        image = Image.open(img_path).convert('RGB')
        image = np.asarray(image)

        n_pos = (self.batch_pos - len(pos_regions)) // (self.batch_frames - i)  # 4 * 8
        n_neg = (self.batch_neg - len(neg_regions)) // (self.batch_frames - i)  # 12 * 8
        pos_examples = self.pos_generator(bbox, n_pos, overlap_range=self.overlap_pos) # [0.7, 1]
        neg_examples = self.neg_generator(bbox, n_neg, overlap_range=self.overlap_neg) # [0, 0.5]

        pos_regions = np.concatenate((pos_regions, self.extract_regions(image, pos_examples)), axis=0)
        neg_regions = np.concatenate((neg_regions, self.extract_regions(image, neg_examples)), axis=0)

    pos_regions = torch.from_numpy(pos_regions)
    neg_regions = torch.from_numpy(neg_regions)
    return pos_regions, neg_regions

トレーニングデータが利用可能になった後、損失関数の基準と評価器が構築され、トレーニングが収束したかどうかが評価されます。オプティマイザーオプティマイザーは次のとおりです。

損失関数

ここでの損失関数は非常に単純で、直接2つのカテゴリのクロスエントロピーです。

class BCELoss(nn.Module):
    def forward(self, pos_score, neg_score, average=True):
        # pos_score:(32, 2) | neg_score:(96, 2)
        pos_loss = -F.log_softmax(pos_score, dim=1)[:, 1]
        neg_loss = -F.log_softmax(neg_score, dim=1)[:, 0]

        loss = pos_loss.sum() + neg_loss.sum()
        if average:
            loss /= (pos_loss.size(0) + neg_loss.size(0))
        return loss

それはF.log_softmaxしなければならなかったF.nll_lossで使用することが併せて、とても1で乗算することはここでは省略されています。このことから、陽性サンプルのラベルは[0、1]であり、陰性サンプルのラベルは[1、0]であることがわかります。

評価者

トレーニングが効果的に実行されているかどうかを確認するための指標は、次のように定義される精度です。

class Precision():
    def __call__(self, pos_score, neg_score):
        scores = torch.cat((pos_score[:, 1], neg_score[:, 1]), 0)
        topk = torch.topk(scores, pos_score.size(0))[1]
        # torch.topk -> (values, indexes)
        prec = (topk < pos_score.size(0)).float().sum() / (pos_score.size(0) + 1e-8)
        return prec.item()

これは、pos_regionsの最小ターゲットスコアがneg_regionsの最大ターゲットスコアよりも大きいため、Precision = 1です。傾向があります。pos_regionsのターゲットスコアがneg_regionsよりも高いほど、精度が高くなります。

ハイパーパラメータ

ペーパーとコードで使用されているいくつかのハイパーパラメータは次のとおりです。

より良い 論文 コード
オフライン学習の反復 100K 50K
コンバージョンのlr 0.0001 0.0001
fcのlr 0.001 0.001
posサンプルのIoU範囲 [0.7、1] [0.7、1]
ネガティブサンプルのIoU範囲 [0、0.5] [0、0.5]

数字

次の図は、トレーニングフェーズのポジティブサンプルとネガティブサンプルを視覚化したものです(ここでは16個のサンプルを選択しました)。赤はpos_examples、青はneg_examples、緑はGTbboxです。
元の画像でのポジティブサンプルとネガティブサンプルの視覚化

以下は、ネットワークの入力である上記の2つの正と負のサンプルでトリミングした後のpos_regionsとneg_regionsの視覚化です。ここでパッチデータの拡張を実行できます。
ネットワーク学習に送信される正と負の領域
以下はトレーニングプロセスのスクリーンショットですが、設定コード内は最大精度ではありませんが、モデルは保存されますが、各サイクルは上書きされて保存されます。
トレーニングプロセスのスクリーンショット

話し合います

MDNetの鍵はトレーニング段階ではなく、オンライン追跡段階でさらに多くのトリックがありますが、トレーニングの部分から議論するいくつかのポイントがあります。

  • トレーニングはR-CNNと非常に似ています。これは、元の画像のトリミングが共有レイヤーに一緒に送信されるため、冗長で非効率的です。
  • このような分類方法では、シーケンスを使用してドメインをトレーニングします。オンライン更新部分がない場合、私は個人的に、見たオブジェクトを追跡する方が正確だと感じています。もちろん、オンライン更新部分の方がはるかに優れており、速度は間違いなく遅くなります。詳細については、次の部分を参照してください。

おすすめ

転載: blog.csdn.net/laizi_laizi/article/details/107475865