计算机视觉算法——基于Transformer的目标检测(DETR / Deformable DETR / DETR 3D)

计算机视觉算法——基于Transformer的目标检测(DETR / Deformable DETR / DETR 3D)

DETR是DEtection TRansformer的缩写,该方法发表于2020年ECCV,原论文名为《End-to-End Object Detection with Transformers》。

传统的目标检测是基于Proposal、Anchor或者None Anchor的方法,并且至少需要非极大值抑制来对网络输出的结果进行后处理,涉及到复杂的调参过程。而DETR使用了Transformer Encoder-Decoder的结构,并且通过集合预测损失实现了真正意义上的端到端的目标检测方法。Transformer Encoder-Decoder是怎么实现的?集合预测损失是什么?后文具体介绍。

对于目标检测方向不是很了解的同学可以参考计算机视觉算法——目标检测网络总结

1. DETR

DETR ネットワーク構造を次の図に示します。
ここに画像の説明を挿入
まず、最初のステップとして、CNN を通じて入力画像から特徴を抽出し、その特徴マップを Transformer Encoder-Decoder に直線化します。2 番目のステップの Transformer Encoder 部分は、ネットワークがグローバルな特徴をより適切に学習できるようにすることです。3 番目のステップは、 Transformer Decoder とオブジェクト クエリを使用して、特徴から検出されるオブジェクトを学習します。4番目のステップは、オブジェクト クエリの結果を比較することです。真値二部グラフマッチング(Set-to-Set Loss)を行い、最後にマッチング結果に対して分類 Loss と位置回帰 Loss を計算します。

以上が学習の基本的な処理ですが、推論処理が異なるのは4番目のステップのみで、4番目のステップではオブジェクトクエリに閾値を設定することで最終的な検出結果が出力されます。この結果はポストを必要としません-処理ですが、最終出力として直接使用されます。

以下では、コードを結合して、Transformer Encoder-Decoder と Set-to-Set Loss の詳細を拡張します。

1.1 トランスエンコーダ/デコーダ

Transformer Encoder-Decoder の構造は次の図に示されています。赤いコメントは入力が3 × 800 × 1066 3\times 800\times 1066 であることを示します。3×800×1066サイズの画像の後に、各ステップのフィーチャ サイズが表示されます。
ここに画像の説明を挿入
Transformer Encoder-Decoder の順方向関数は次のとおりです。

def forward(self, src, mask, query_embed, pos_embed):
        # flatten NxCxHxW to HWxNxC
        bs, c, h, w = src.shape
        src = src.flatten(2).permute(2, 0, 1)
        pos_embed = pos_embed.flatten(2).permute(2, 0, 1)
        query_embed = query_embed.unsqueeze(1).repeat(1, bs, 1)
        mask = mask.flatten(1)

        tgt = torch.zeros_like(query_embed)
        memory = self.encoder(src, src_key_padding_mask=mask, pos=pos_embed)
        hs = self.decoder(tgt, memory, memory_key_padding_mask=mask,
                          pos=pos_embed, query_pos=query_embed)
        return hs.transpose(1, 2), memory.permute(1, 2, 0).view(bs, c, h, w)

このうち、
srcは Backbone によって抽出された特徴で、Encoder に入力する前に平坦化する必要があります、
pos_embedは位置コードで、DETR の固定値を持つ位置コードです。詳細については、以下の 1.3 の導入を参照してください。 ;
query_embedは学習可能な位置コード、つまり前述の Object Query であり、Decoder でのその機能は、Feature と Encoder 後の query_embed を通じてクロス アテンションを継続的に実行することであり、query_embed の各次元は検出結果の出力です; マスク
DETR 入力として異なる解像度の画像と互換性を持たせるために、異なる画像は入力中に固定解像度にゼロ パディングされます。ゼロ パディング部分には情報が含まれていないため、アテンションの計算には使用できません。著者はここでゼロパディング部分を予約しています。

次の Encoder-Decoder 部分は、「Attending Is All You Need」とほぼ同じで、Encoder 層の構造は下図のようになります
ここに画像の説明を挿入

def forward_post(self,
                 src,
                 src_mask: Optional[Tensor] = None,
                 src_key_padding_mask: Optional[Tensor] = None,
                 pos: Optional[Tensor] = None):
    q = k = self.with_pos_embed(src, pos)
    src2 = self.self_attn(q, k, value=src, attn_mask=src_mask,
                          key_padding_mask=src_key_padding_mask)[0]
    src = src + self.dropout1(src2)
    src = self.norm1(src)
    src2 = self.linear2(self.dropout(self.activation(self.linear1(src))))
    src = src + self.dropout2(src2)
    src = self.norm2(src)
    return src

Decoder の構造を下の図に示します。
ここに画像の説明を挿入コードは次のとおりです。

def forward_post(self, tgt, memory,
                 tgt_mask: Optional[Tensor] = None,
                 memory_mask: Optional[Tensor] = None,
                 tgt_key_padding_mask: Optional[Tensor] = None,
                 memory_key_padding_mask: Optional[Tensor] = None,
                 pos: Optional[Tensor] = None,
                 query_pos: Optional[Tensor] = None):
    q = k = self.with_pos_embed(tgt, query_pos)
    tgt2 = self.self_attn(q, k, value=tgt, attn_mask=tgt_mask,
                          key_padding_mask=tgt_key_padding_mask)[0]
    tgt = tgt + self.dropout1(tgt2)
    tgt = self.norm1(tgt)
    tgt2 = self.multihead_attn(query=self.with_pos_embed(tgt, query_pos),
                               key=self.with_pos_embed(memory, pos),
                               value=memory, attn_mask=memory_mask,
                               key_padding_mask=memory_key_padding_mask)[0]
    tgt = tgt + self.dropout2(tgt2)
    tgt = self.norm2(tgt)
    tgt2 = self.linear2(self.dropout(self.activation(self.linear1(tgt))))
    tgt = tgt + self.dropout3(tgt2)
    tgt = self.norm3(tgt)
    return tgt

ここで詳細を説明しますと、query_embed は最初の層を除き、Cross Attendance を行う前に Self Attendance を実行する必要があり、Self Attendant の各 Query は他の Query がマスターした情報を理解します。

結論として、Transformer Encoder-Decoder の利点は何でしょうか? Transformer Encoder-Decoder はSet-to-Set の成功の理由の 1 つで
あるはずだと思います。DETR が登場する前に、実際に Set-to-Set のアイデアを提案する記事がいくつかありましたが、ネットワークが十分に強力ではなかったので、あまりうまく達成できませんでした。Transformer Encoder-Decoder はグローバル機能を学習するため、ある機能がグローバル内の他の機能と相互作用することができ、ネットワークはオブジェクトがどこにあるのか、別のオブジェクトがどこにあるのか、オブジェクトが出力に対応している必要があることをより明確に知ることができます。これは、Set-to-Set の仮定により一致します。

1.2 セット間の損失

いわゆる Set-to-Set Loss は、次の式に示すように、ネットワーク損失を計算する前に 2 部グラフのマッチング プロセスを追加するプロセスです。これにより、最終的な予測結果は、一致する真の値を持つ損失のみが計算されます。 ^ = arg ⁡ min ⁡ σ ∈ SN ∑ i NL match ⁡ ( yi , y ^ σ ( i ) ) \hat{\sigma}=\underset{\sigma \in \mathfrak{S}_{N}}{\ arg \min } \sum_{i }^{N} \mathcal{L}_{\operatorname{match}}\left(y_{i}, \hat{y}_{\sigma(i)}\right)p^=σ SNarg _NL一致( y私はy^σ ( i ))其中 y i y_{i} y私はは true、y ^ σ ( i ) \hat{y}_{\sigma(i)}y^σ ( i )は予測値、L match ⁡ \mathcal{L}_{\operatorname{match}}L一致二部グラフ マッチング アルゴリズムについては、二部グラフ マッチングに慣れていない学生は、「Visual SLAM Summary - SuperPoint / SuperGlue」の概要を参照してください。違いは、scipy ライブラリの Linear_sum_assignment 関数が DETR コードの実装で呼び出されることです。関数入力 A M × NM\times NM×NサイズのコストマトリックスでMMを計算可能MさんNNさんDETR のコスト行列であるN間のマッチング関係は、分類損失 p ^ σ ( i ) ( ci ) \hat{p}_{\sigma(i)}\left(c_{i}\right) で構成されますp^σ ( i )( c私は)和Box损失L box ( bi , b ^ σ ( i ) ) \mathcal{L}_{\mathrm{box}}\left(b_{i}, \hat{b}_{\sigma(i)} \右)Lボックス( b私はb^σ ( i ))は 2 つの部分で構成され、分類損失は負の Softmax の確率であり、ボックス損失は L1 損失と一般化 IOU 損失であり、その 2 つの部分は次のとおりです。

def forward(self, outputs, targets):
        """ Performs the matching

        Params:
            outputs: This is a dict that contains at least these entries:
                 "pred_logits": Tensor of dim [batch_size, num_queries, num_classes] with the classification logits
                 "pred_boxes": Tensor of dim [batch_size, num_queries, 4] with the predicted box coordinates

            targets: This is a list of targets (len(targets) = batch_size), where each target is a dict containing:
                 "labels": Tensor of dim [num_target_boxes] (where num_target_boxes is the number of ground-truth
                           objects in the target) containing the class labels
                 "boxes": Tensor of dim [num_target_boxes, 4] containing the target box coordinates

        Returns:
            A list of size batch_size, containing tuples of (index_i, index_j) where:
                - index_i is the indices of the selected predictions (in order)
                - index_j is the indices of the corresponding selected targets (in order)
            For each batch element, it holds:
                len(index_i) = len(index_j) = min(num_queries, num_target_boxes)
        """
        bs, num_queries = outputs["pred_logits"].shape[:2]

        # We flatten to compute the cost matrices in a batch
        out_prob = outputs["pred_logits"].flatten(0, 1).softmax(-1)  # [batch_size * num_queries, num_classes]
        out_bbox = outputs["pred_boxes"].flatten(0, 1)  # [batch_size * num_queries, 4]

        # Also concat the target labels and boxes
        tgt_ids = torch.cat([v["labels"] for v in targets])
        tgt_bbox = torch.cat([v["boxes"] for v in targets])

        # Compute the classification cost. Contrary to the loss, we don't use the NLL,
        # but approximate it in 1 - proba[target class].
        # The 1 is a constant that doesn't change the matching, it can be ommitted.
        cost_class = -out_prob[:, tgt_ids]

        # Compute the L1 cost between boxes
        cost_bbox = torch.cdist(out_bbox, tgt_bbox, p=1)

        # Compute the giou cost betwen boxes
        cost_giou = -generalized_box_iou(box_cxcywh_to_xyxy(out_bbox), box_cxcywh_to_xyxy(tgt_bbox))

        # Final cost matrix
        C = self.cost_bbox * cost_bbox + self.cost_class * cost_class + self.cost_giou * cost_giou
        C = C.view(bs, num_queries, -1).cpu()

        sizes = [len(v["boxes"]) for v in targets]
        indices = [linear_sum_assignment(c[i]) for i, c in enumerate(C.split(sizes, -1))]
        return [(torch.as_tensor(i, dtype=torch.int64), torch.as_tensor(j, dtype=torch.int64)) for i, j in indices]

マッチング結果を得た後σ ^ \hat{\sigma}p^方程式によると:L ハンガリー語 ( y , y ^ ) = ∑ i = 1 N [ − log ⁡ p ^ σ ^ ( i ) ( ci ) + 1 { ci ≠ ∅ } L box ( bi , b ^ σ ^ ( i ) ) ] \mathcal{L}_{\text {ハンガリー語}}(y, \hat{y})=\sum_{i=1}^{N}\left[-\log \hat{ p} _{\hat{\sigma}(i)}\left(c_{i}\right)+\mathbb{1}_{\left\{c_{i}\right\varnothing\right\}}\ mathcal{ L}_{\mathrm{box}}\left(b_{i}, \hat{b}_{\hat{\sigma}}(i)\right)\right]Lハンガリー語 ( y ,y^)=i = 1N[ログ_p^p^ ()( c私は)+1{ c私は= }Lボックス( b私はb^p^( i ) ) ] はマッチング処理で使用される損失とは少し異なります。ここでの分類損失は一般的なクロスエントロピー損失を使用します。なぜこのような違いがあるのでしょうか? 論文では言及されていないようです。前述したように、バイナリ マッチング プロセスはトレーニング プロセス中にのみ発生し、最終的な出力結果は、テスト プロセス中にネットワークの出力結果を直接しきい値を超えることによって取得されます。

1.3 位置埋め込み

DETR の Positional Embedding は固定値であり、Positional Embedding のコードは次のとおりです。

class PositionEmbeddingSine(nn.Module):
    """
    This is a more standard version of the position embedding, very similar to the one
    used by the Attention is all you need paper, generalized to work on images.
    """
    def __init__(self, num_pos_feats=64, temperature=10000, normalize=False, scale=None):
        super().__init__()
        self.num_pos_feats = num_pos_feats
        self.temperature = temperature
        self.normalize = normalize
        if scale is not None and normalize is False:
            raise ValueError("normalize should be True if scale is passed")
        if scale is None:
            scale = 2 * math.pi
        self.scale = scale

    def forward(self, tensor_list: NestedTensor):
        x = tensor_list.tensors
        mask = tensor_list.mask
        assert mask is not None
        not_mask = ~mask
        y_embed = not_mask.cumsum(1, dtype=torch.float32)
        x_embed = not_mask.cumsum(2, dtype=torch.float32)
        if self.normalize:
            eps = 1e-6
            y_embed = y_embed / (y_embed[:, -1:, :] + eps) * self.scale
            x_embed = x_embed / (x_embed[:, :, -1:] + eps) * self.scale

        dim_t = torch.arange(self.num_pos_feats, dtype=torch.float32, device=x.device)
        dim_t = self.temperature ** (2 * (dim_t // 2) / self.num_pos_feats)

        pos_x = x_embed[:, :, :, None] / dim_t
        pos_y = y_embed[:, :, :, None] / dim_t
        pos_x = torch.stack((pos_x[:, :, :, 0::2].sin(), pos_x[:, :, :, 1::2].cos()), dim=4).flatten(3)
        pos_y = torch.stack((pos_y[:, :, :, 0::2].sin(), pos_y[:, :, :, 1::2].cos()), dim=4).flatten(3)
        pos = torch.cat((pos_y, pos_x), dim=3).permute(0, 3, 1, 2)
        return pos

ネットワークにさまざまな入力の位置情報を認識させるための最も直感的な方法は、最初のフィーチャーに1 1を割り当てることです。1、2 番目の機能割り当て2 22ですが、この割り当て方法は大きな入力には不向きなので、誰かが正弦関数を使用して値を− 1 -111 11ですが、サイン関数は周期的であるため、異なる位置で同じ値が発生する可能性があります。

そこで著者は正弦関数をddに拡張しました。d次元ベクトル、異なるチャネルは次のように異なる波長を持ちます:
PE ( pos , 2 i ) = sin ⁡ ( pos / 1000 0 2 i / d model ) P E_{(pos, 2 i)}=\sin \left ( pos / 10000^{2 i / d_{\text {モデル }}}\right)PE _( pos , 2 i ) _=( pos / 1000 02i / d _モデル ) PE ( pos , 2 i + 1 ) = cos ⁡ ( pos / 1000 0 2 i / d モデル ) P E_{(\text {pos }, 2 i+1)}=\cos \left(pos / 10000^ {2 i / d_{\text {モデル }}}\right)PE _( pos  , 2 i + 1 )=コス( pos / 1000 02i / d _モデル )其中 i i iはチャネルの数です。たとえば、d = 6 d=6d=6那么: i = [ 1 , 2 , 3 , 4 , 5 , 6 ] {i}=[1,2,3,4,5,6] =[ 1 2 3 4 5 6 ] wi = [ 1 1000 0 1 / 6 , 1 1000 0 2 / 6 , 1 1000 0 3 / 6 , 1 1000 0 4 / 6 , 1 1000 0 5 / 6 , 1 1000 0 6 / 6 ] w_i=\左[\frac{1}{10000^{1 / 6}}、\frac{1}{10000^{2 / 6}}、\frac{1}{10000^{3 / 6}}、\frac{ 1}{10000^{4 / 6}}、\frac{1}{10000^{5 / 6}}、\frac{1}{10000^{6 / 6}}\right]w私は=[1000 01/611000 02/611000 03/611000 04/611000 05/611000 06/61]P oision = 2 Poision = 2ポジション_ _ _ _ _ _=2回、得られる:位置エンコーディング = [ sin ⁡ ( 2 w 0 ) , cos ⁡ ( 2 w 1 ) , sin ⁡ ( 2 w 2 ) , cos ⁡ ( 2 w 3 ) , sin ⁡ ( 2 w 4 ) , cos ⁡ ( 2 w 5 ) ] 位置エンコーディング=\left[\sin \left(2 w_{0}\right), \cos \left(2 w_{1}\right), \sin \left(2 w_ {2}\right)、\cos \left(2 w_{3}\right)、\sin \left(2 w_{4}\right)、\cos \left(2 w_{5}\right)\right ]位置エンコーディング_ _ _ _ _ _ _ _ _ _ _=[( 2w _0)コス( 2w _1)( 2w _2)コス( 2w _3)( 2w _4)コス( 2w _5このようにして得られた、異なる位置で同じになることは困難であるため、異なる位置を符号化する効果が得られます。

DETRは、そのシンプルな構造で提案されてからすぐに注目を集めましたが、DETR自体も学習の収束速度が十分ではない、SOTAの結果が十分ではない、小さな物体の検出効果が低いなど多くの問題を抱えています。他にも問題はたくさんありますが、Deformable DETR、Anchor DETR などの DETR 関連アルゴリズムや、自動運転分野などに応用されている DETR3D などのアルゴリズムの一部を簡単にまとめます。

2. 変形可能なDETR

変形可能な DETR は、元の DETR の学習速度の遅さ小さな物体に対する検出効果の低さの問題を主に解決します。DETR の収束速度が遅いのは主に、一様分布から疎​​分布へのアテンション マップのトレーニング プロセスに時間のかかることが原因です。小さなオブジェクトの検出効果が低いのは主に、Backbone にマルチスケール機能がないことが原因です。ありますが、 Transformer の計算量は O ( n 2 ) O(n^2) であるため、マルチスケールの特徴を Transformer に入力するのは非現実的です。O ( n2 )、高解像度機能は大量のメモリと時間を消費します。

この目的を達成するために、Deformable DETR は、上記の問題をうまく解決する Defomer Attendance モジュールを提案します。

2.1 変形可能なアテンションモジュール

著者は最初に、オリジナルの Transformer におけるマルチヘッド アテンション メカニズムの式を論文で導入しました。  MultiHeadAttn ( zq , x ) = ∑ m = 1 MW m [ ∑ k ∈ Ω k A mqk ⋅ W m ′ xk ] \text { MultiHeadAttn }\ left(z_{q}, x\right)=\sum_{m=1}^{M} W_{m}\left[\sum_{k \in \Omega_{k}} A_{mqk} \cdot W_{ m}^{\prime} x_{k}\right] マルチヘッドアト ( zq× =m = 1MWメートル[k Ωm q kWメートルバツこれは私たちが普段目にする公式と同じですが、表現が少し異なります。ここで、 zq , x z_{q}, xzqxは、注意のための 2 つのベクトルのセット、V mx V_{m} xVメートルx得到達キー埋め込み、U mzq U_{m} z_{q}Uメートルzqクエリ埋め込みの取得、A mqk A_{mqk}m q k重みはクエリ埋め込みとキー埋め込みのドット乗算後の正規化で取得され、exp ⁡ { zq TU m TV mxk C v } \exp \left\{\frac{z_{q}^{T} U_ に比例します。 {m} ^{T} V_{m} x_{k}}{\sqrt{C_{v}}}\right\}経験値{ Cv zqTUメートルTVメートルバツW m ' xk W_{m}^{\prime} x_{k}Wメートルバツ値の埋め込み、W m W_{m}WメートルConcate の後にマルチヘッドの結果を集約する役割を果たします。ここで、 U m 、 V m 、 W m ' 、 W m U_{m}、 V_{m}、 W_{m}^{\prime}、 W_{m}UメートルVメートルWメートルWメートルは学習されたパラメータです。DETRでは、このような独自のマルチヘッドアテンション機構をEncoderのSelf-AttendanceとDecoderのCross-Attendanceに応用しています。

次に、著者は変形可能な注意モジュールの原理を紹介しました。その式は次のとおりです: DeformAttn ⁡ ( zq , pq , x ) = ∑ m = 1 MW m [ ∑ k = 1 KA mqk ⋅ W m ′ x ( pq + Δ pmqk ) ] \operatorname{DeformAttn}\left(\boldsymbol{z}_{q}, \boldsymbol{p}_{q}, \boldsymbol{x}\right)=\sum_{m=1}^{M} \boldsymbol {W}_{m}\left[\sum_{k=1}^{K} A_{mqk} \cdot \boldsymbol{W}_{m}^{\prime} \boldsymbol{x}\left (\boldsymbol{p}_{q}+\Delta \boldsymbol{p}_{mqk}\right)\right]変形属性( zqpq× =m = 1MWメートル[k = 1Km q kWメートルバツ( pq+p_ _m q k) ]ここで、δ pmqk \delta p_{mqk}p_ _m q kはクエリ埋め込みから取得された位置オフセットであり、式内のA mqk A_{mqk}m q kこれは、Query Embedding と Key Embedding のドット積を通じて取得される重みではなく、Query Embedding から直接取得される重みです。このプロセスは、次の図から理解できます: DETR で使用されるマルチヘッド アテンション メカニズムとの違いは、
ここに画像の説明を挿入
:

  1. DETR で使用されるマルチヘッド アテンション メカニズムは、グローバル特徴をキー値として使用しますが、変形可能なアテンションは各クエリの近くにあり、クエリ埋め込みを通じて独立してKKを選択します。K 個のキー値。
  2. DETR で使用されるマルチヘッド アテンション メカニズムは、キー エンベディングとクエリ エンベディングの内積を通じて重みを取得しますが、デフォーマブル アテンションは線形層を通じてクエリ エンベディングから直接取得されます。

また、上記 2 つの違いにより、変形可能なアテンションが元のアテンション メカニズムよりも効率的になりますさらに、デフォーマブル アテンションとデフォーマブル コンボリューションも異なります。デフォーマブル アテンションはクエリ位置の点における複数のオフセットを直接予測するのに対し、デフォーマブル コンボリューションはコンボリューション カーネル内の各ピクセルのバイアスを予測します。

変形可能な注意モジュールに基づいて、著者はさらにマルチスケール変形可能な注意モジュールを提案しました。式は次のとおりです: MSDeformAttn ⁡ ( zq , p ^ q , { xl } l = 1 L ) = ∑ m = 1 MW m [ ∑ l = 1 L ∑ k = 1 KA mlqk ⋅ W m ′ xl ( ϕ l ( p ^ q ) + Δ pmlqk ) ] \operatorname{MSDeformAttn}\left(z_{q}, \hat{\boldsymbol{p}} _{ q},\left\{x^{l}\right\}_{l=1}^{L}\right)=\sum_{m=1}^{M} W_{m}\left[ \sum_ {l=1}^{L} \sum_{k=1}^{K} A_{mlqk} \cdot \boldsymbol{W}_{m}^{\prime} \boldsymbol{x}^{l }\ left(\phi_{l}\left(\hat{\boldsymbol{p}}_{q}\right)+\Delta \boldsymbol{p}_{mlqk}\right)\right]MSDeformAttn( zqp^q{ ×l }l = 1L)=m = 1MWメートル[l = 1Lk = 1Km lq kWメートルバツ( ϕ(p^q)+p_ _m lq k) ]デフォーマブル アテンション モジュールと比較した主な違いは、デフォーマブル アテンション モジュールがKKKポジション、マルチスケール変形アテンション モジュールはLLL層の各層サンプルKKKポジション、合計LK LKL K 個のサンプリング位置。このようにして、ネットワークは低コストでマルチスケールの機能の融合を実現します

2.2 変形可能なトランスフォーマーエンコーダー/デコーダー

Deformable Transformer のエンコーダとデコーダの構造を次の図に示します。
ここに画像の説明を挿入
エンコーダ では、作成者はすべてのセルフ アテンション モジュールを変形可能なアテンション モジュールに置き換え、各エンコーダの入力と出力は同じ解像度のマルチスケール フィーチャ マップです。マルチスケール特徴マップは、ResNet の最後の 3 つのステージから直接取得されます。以下の図に示すように、
ここに画像の説明を挿入
さらに、位置埋め込みの保持に基づいて、フィーチャ レイヤーの数に関連する学習可能なスケール レベル 埋め込みが追加されます。

Decoder では、著者はセルフ アテンションを変更せず、クロス アテンションを変形可能なアテンションに置き換えます。オブジェクト クエリの埋め込みごとに、線形層とシグモイドは対応する参照点を学習し、エンコーダーによって出力された特徴に対してクエリを実行します。対応する値の埋め込みが取得されます。 、そして最後に、線形層とソフトマックスによって学習された重みに基づいて重み付けされた合計が実行されます。初めてこれを読んだとき、私は疑問を抱きました。Object Query Embedding から基準点の位置と重みが推測される場合、Object Query Embedding はプリセット値です (DETR では、それらはすべて取得された Encoder Feature に関連付けられます)。検出対象が正しいことを確認するにはどうすればよいでしょうか? よく考えてみると、Decode Layer の最初の層の参照点または重みは、確かに固定値またはランダムな値である可能性がありますが、Encoder Feature 情報は、Decode Layer の最初の層が出力する Object Query Embedding に既に含まれています。デコーダ層によって生成された参照点の位置は画像と相関し始め、デコーダ層の重ね合わせにより、この相関はますます強くなります。

さらに、DETR とは少し異なりますが、Deformable DETR は、重みと参照点の位置がすべて同じオブジェクト クエリから取得されるため、バウンディング ボックスがオブジェクト クエリから絶対座標を直接回帰するのではなく、参照点までの距離を回帰すると予測します。埋め込みは推論されるため、参照点を基準とした回帰方法により収束を高速化できます

2.3 結論

Deformable DETR に関する知識は、この記事で上にまとめた 2 つのポイントよりもはるかに多くあります。Deformable DETR の論文では、Two-Stage Defomable DETR などの他のネットワーク構造も紹介されており、より深く掘り下げることができます。ここでは、Deformable DETR の改善を相対的に比較します。 DETR との比較:
以下は学習速度の比較です Deformable DETR の学習収束速度は大幅に向上しました:
ここに画像の説明を挿入
下の表から、Deformable は小さな物体の検出精度が大幅に向上していることがわかります:
ここに画像の説明を挿入
DETR の提案端末のネットワーク構造は主にエンドツーエンドに基づいています。端末のネットワーク構造は範囲外ですが、そのパフォーマンスは当時SOTAに達していなかったかもしれませんが、変形可能なDETRのサポートにより、このタイプの方法はすでにSOTAと競合できますSOTA方式との比較結果は以下の通りです。
ここに画像の説明を挿入

3.DETR3D

DETR3D は、下図に示すように、DETR を自動運転の分野に適用し、マルチカメラ入力 BEV の観点で 3D 物体検出を実現します: その原理は、前述の変形可能トランスと非常によく似ていますここに画像の説明を挿入
。パースペクティブ タスクの下のアプリケーションは、後で学習する別のブログ投稿のようなものです。

ネットワークの構造図は以下の図に示されています:
ここに画像の説明を挿入
ネットワークはまず、ResNet と FPN を介して入力された各カメラのマルチスケール特徴を抽出します (図の画像特徴抽出部分)。さらに詳しく学習していただくために、以下にこの部分について詳しく説明します。

3.1 2D から 3D への変換

カメラ入力ごとに 4 つのスケールの特徴を抽出します。これらはF 1 、 F 2 、 F 3 、 F 4 \mathcal{F}_{1}、\mathcal{F}_{2}、\mathcal{ として記録されます。 F }_{3}、\mathcal{F}_{4}F1F2F3F4論文の構成では、合計 6 つのカメラ入力があります: F k = { fk 1 , … , fk 6 } ⊂ RH × W × C \mathcal{F}_{k}=\left\{\ボールドシンボル{f} _{k 1}, \ldots, \boldsymbol{f}_{k 6}\right\} \subset \mathbb{R}^{H \times W \times C}F={ fk1 _fk6 _}R高さ××高さ

DETR3D アルゴリズムには、Transformer ベースの Encoder 部分はありませんが、上記で抽出された画像特徴は Decoder 部分に直接入力されます。原因としては、Encoder 部分の計算量が多すぎることと、Decoder 部分が DETR または Deformable DETR と同じであることが考えられます。Object Query Embedding と入力フィーチャーを介してクロスアテンションが実行され、対応するオブジェクトが返されます。最終出力オブジェクトクエリ埋め込み DETR3D では、最大の違いは回帰の 3D 空間内の位置であり、入力は 2D 画像のフィーチャであるため、このような 2D から 3D への変換デコーダが必要です。

DETR3D のデコーダは依然としてセルフ アテンションとクロス アテンションで構成されています。セルフ アテンションと DETR のメソッドは基本的に同じです。主な機能は、各クエリが他のクエリの実行内容を確実に把握し、クエリの繰り返し抽出を避けることです。クロスアテンションはまったく異なりますので、以下の具体的な手順を見てみましょう。

  1. まず独立したネットワークを経由しますΦ ref \Phi^{\text {ref }}ファイref は、 オブジェクト クエリの埋め込みから 3D 位置を返します。これは、変形可能な DETR の操作に似ています。c ℓ i = Φ ref ( q ℓ i ) \boldsymbol{c}_{\ell i}=\Phi^{\mathrm {ref}}\left(\boldsymbol{q}_{\ell i}\right)cℓi _=ファイ参照( qℓi _)ここで、c ℓ i \boldsymbol{c}_{\ell i}cℓi _iiと考えられるi Boxの中心位置。
  2. カメラパラメータを通じて、位置c ℓ i \boldsymbol{c}_{\ell i}cℓi _各カメラのフィーチャに投影して、キーの埋め込みと値の埋め込みに使用されるボックスの 3D 位置を取得して、予測を精緻化します: c ℓ i ∗ = c ℓ i ⊕ 1 \boldsymbol{c}_{\ell i}^{* }= \boldsymbol{c}_{\ell i} \oplus 1cℓi _=cℓi _1 c ℓ mi = T mc ℓ i ∗ \boldsymbol{c}_{\ell mi}=T_{m} \boldsymbol{c}_{\ell i}^{*}c=Tメートルcℓi _ここでT m T_{m}Tメートルはカメラパラメータです。
  3. 各入力はマルチスケールの特徴マップであるため、異なるスケールの特徴解像度の影響を避けるために、双一次補間を使用して特徴マップを補間し、座標が画像の外にある場合はゼロを埋めます。 f ℓ kmi = f双線形 ( F km , c ℓ mi ) \boldsymbol{f}_{\ell kmi}=f^{\text {双線形 }}\left(\mathcal{F}_{km}, \boldsymbol{c}_ {\エルミ}\そうです)fℓkm _=f双線形 ( Fkmc)
  4. 上記の特徴を追加し、最終的に絞り込みのためのオブジェクト クエリ埋め込みに追加します。f ℓ i = 1 ∑ k ∑ m σ ℓ kmi + ϵ ∑ k ∑ mf ℓ kmi σ ℓ kmi \boldsymbol{f}_{\ell i }= \frac{1}{\sum_{k} \sum_{m} \sigma_{\ell kmi}+\epsilon} \sum_{k} \sum_{m} \boldsymbol{f}_{\ell kmi} \sigma_ {\エルキロミ}fℓi _=メートルpℓkm _+ϵ1kメートルfℓkm _pℓkm _q ( ℓ + 1 ) i = f ℓ i + q ℓ i \boldsymbol{q}_{(\ell+1) i}=\boldsymbol{f}_{\ell i}+\boldsymbol{q}_{ \えー、私}q( + 1 ) i=fℓi _+qℓi _これは実際には Cross Attendance の重み付け加算に相当するステップだと思うのですが、DETR では Value Embedding の値に Query Embedding と Key Embedding の重みを乗じて重み付けして Query を更新するステップです。Deformable では、Query Embedding と Key Embedding のポイント乗算のステップが省略され、Query Embedding を通じて回帰重みが直接実行され、その後 Value Embedding が重み付けされます。ここでは、Value Embedding と Query Embedding を追加したことに相当し、さらに計算量を省略しています。(この部分は論文の説明や他のブログのまとめを元に私が結論付けたものです。コードの実装とは異なる可能性があります。間違いがあれば読者の方に指摘してください。)
  5. 上記の操作を何度も繰り返した後、最終的にカテゴリと位置がクエリ埋め込みから回帰されます。b ^ ℓ i = Φ ℓ reg ( q ℓ i ) \hat{\boldsymbol{b}}_{\ell i}=\ Phi_ {\ell}^{\mathrm{reg}}\left(\boldsymbol{q}_{\ell i}\right)b^ℓi _=ファイ登録( qℓi _) c ^ ℓ i = Φ ℓ cls ( q ℓ i ) \hat{c}_{\ell i}=\Phi_{\ell}^{\mathrm{cls}}\left(\boldsymbol{q}_{ \えー、私}\そうです)c^ℓi _=ファイCLS( qℓi _)

以上が DETR3D Decoder 部分の理解ですが、ソースコードを読む時間がないため、理解が十分ではなく、細部を無視している可能性があります。昨年の Tesla AI Day 以来、自動運転分野での Transformer の応用について、皆さんが多くの研究を行ってきましたが、今後さらに進めていきたいと考えており、2D の特徴を 3D でどのように関連付けるかは非常に興味深いです。

この記事のDETR関連の概要はとりあえずここにありますが、時間があれば追加しますので、質問があればアドバイスや交換をお願いします〜

おすすめ

転載: blog.csdn.net/weixin_44580210/article/details/125951431
おすすめ