Algoritmo de visão computacional - Detecção de alvo baseada em transformador (DETR / DETRable Deformable / DETR 3D)
Algoritmo de visão computacional - Detecção de alvo baseada em transformador (DETR / DETRable Deformable / DETR 3D)
DETR é a abreviação de DEtection TRansformer. Este método foi publicado no ECCV em 2020. O artigo original foi intitulado "End-to-End Object Detection with Transformers".
A detecção de alvo tradicional é baseada nos métodos Proposta, Âncora ou Nenhuma Âncora e requer pelo menos supressão não máxima para pós-processar os resultados da saída da rede, que envolve um processo complexo de ajuste de parâmetros. O DETR usa a estrutura Transformer Encoder-Decoder e realiza um verdadeiro método de detecção de ponta a ponta por meio da perda de previsão coletiva . Como o Transformer Encoder-Decoder é implementado? Qual é a perda de previsão do conjunto? Os detalhes serão dados posteriormente.
Os alunos que não estão muito familiarizados com a direção da detecção de alvos podem consultar o algoritmo de visão computacional - resumo da rede de detecção de alvos .
1. DETR
A estrutura da rede DETR é mostrada na figura abaixo:
Primeiro, o primeiro passo é extrair recursos da imagem de entrada por meio de uma CNN e, em seguida, endireitar o mapa de recursos no Transformer Encoder-Decoder. A parte do Transformer Encoder da segunda etapa é fazer com que a rede aprenda melhor os recursos globais; a terceira etapa usa o Transformer Decoder e o Object Query para aprender o objeto a ser detectado a partir dos recursos; a quarta etapa é comparar os resultados do Object Query com a correspondência do gráfico bipartido do valor real (perda de conjunto para conjunto) e, finalmente, calcule a perda de classificação e a perda de regressão de posição nos resultados correspondentes.
O descrito acima é o processo básico de treinamento. A única diferença no processo de raciocínio está na quarta etapa. Na quarta etapa, o resultado final da detecção é gerado definindo um valor limite para a consulta de objeto. Esse resultado não precisa de nenhuma postagem -processing, mas é usado diretamente como saída final.
Abaixo combinamos o código para expandir os detalhes do Transformer Encoder-Decoder e Set-to-Set Loss:
1.1 Transformador Codificador-Decodificador
A estrutura do Codificador-Decodificador do Transformer é mostrada na figura abaixo, onde o comentário vermelho é a entrada é 3 × 800 × 1066 3\times 800\times 10663×800×Após a imagem de tamanho 1066 , o tamanho do recurso de cada etapa.
A função de encaminhamento do Transformer Encoder-Decoder é a seguinte:
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)
Entre eles ,
src é o recurso extraído pelo Backbone, que precisa ser nivelado antes de ser inserido no Codificador;
pos_embed é o código de posição, que é um código de posição com um valor fixo no DETR. Para obter detalhes, consulte a introdução em 1.3 abaixo ;
query_embed é um código de posição apreensível, ou seja, a consulta de objeto mencionada acima, sua função no decodificador é fazer atenção cruzada continuamente por meio do recurso e query_embed após o codificador, e cada dimensão do query_embed é a saída de um resultado de detecção ; a máscara
é DETR Para ser compatível com diferentes imagens de resolução como entrada, diferentes imagens serão Zero Padding em uma resolução fixa durante a entrada. A parte Zero Padding não contém nenhuma informação, portanto não pode ser usada para calcular Atenção, então o autor reserva a parte de Zero Padding aqui. Digite src_key_padding_mask.
A parte do Codificador-Decodificador a seguir é quase a mesma que em "Atenção é tudo que você precisa". A estrutura da camada do Codificador é mostrada na figura abaixo: o
código é o seguinte:
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
A estrutura do Decoder é mostrada na figura abaixo:
o código é o seguinte:
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
Aqui um detalhe, Exceto pela primeira camada, query_embed precisa fazer uma Auto Atenção antes de fazer Atenção Cruzada, cada Consulta de Auto Atenção entende a informação dominada por outra Consulta.
Em conclusão, quais são os benefícios do Transformer Encoder-Decoder?
Acho que o Transformer Encoder-Decoder deve ser um dos motivos do sucesso do Set-to-Set . a rede não era forte o suficiente, não funcionou muito bem. O Transformer Encoder-Decoder aprende os recursos globais, o que pode fazer com que um dos recursos interaja com outros recursos no global, e a rede pode saber com mais clareza onde está um objeto, onde está outro objeto, um objeto deve corresponder a uma saída , que está mais de acordo com a suposição de Set-to-Set.
1.2 Perda Set-to-Set
A chamada Perda Set-to-Set é o processo de adicionar um processo de correspondência de gráfico bipartido antes de calcular a perda da rede, de modo que o resultado final da previsão calcule apenas a perda com o valor verdadeiro correspondente, conforme mostrado na seguinte fórmula: σ ^ = 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^=σ ∈ Snar gmineu∑neupartida( yeu,y^σ ( i )) dos quaisyi y_{i}yeué verdadeiro, y ^ σ ( i ) \hat{y}_{\sigma(i)}y^σ ( i )é o valor previsto, L match \mathcal{L}_{\operatorname{match}}eupartidaPara o algoritmo de correspondência de gráfico bipartido, os alunos que não estão familiarizados com a correspondência de gráfico bipartido podem consultar a introdução em Visual SLAM Summary - SuperPoint / SuperGlue . A diferença é que a função linear_sum_assignment na biblioteca scipy é chamada na implementação do código DETR código. A entrada da função A M × NM\vezes NM×Matriz de custo de tamanho N pode calcularMMM eNNA relação de correspondência entre N , a matriz Custo no DETR é composta pela perda de classificaçãop ^ σ ( i ) ( ci ) \hat{p}_{\sigma(i)}\left(c_{i}\right)p^σ ( i )( ceu) e Box损失L box ( bi , b ^ σ ( i ) ) \mathcal{L}_{\mathrm{box}}\left(b_{i}, \hat{b}_{\sigma(i)} \certo)eucaixa( beu,b^σ ( i )) consiste em duas partes, a perda de classificação é a probabilidade de Softmax negativo e a perda de caixa é a perda de L1 e a perda de IOU generalizada. As duas partes são as seguintes:
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]
Depois de obter o resultado correspondente σ ^ \hat{\sigma}p^ De acordo com a equação:L Húngaro ( y , y ^ ) = ∑ i = 1 N [ − log p ^ σ ^ ( i ) ( ci ) + 1 { ci ≠ ∅ } L caixa ( bi , b ^ σ ^ ( i ) ) ] \mathcal{L}_{\text {húngaro}}(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]euHúngaro ( s ,y^)=eu = 1∑n[ -pouco tempop^p^ (eu)( ceu)+1{ ceu= ∅ }eucaixa( beu,b^p^( i ) ) ] é ligeiramente diferente da perda usada no processo de correspondência. A perda de classificação aqui usa a perda geral de entropia cruzada. Por que existe essa diferença? O artigo parece não mencioná-la. Conforme mencionado acima, o processo de correspondência binária ocorre apenas durante o processo de treinamento e o resultado final da saída é obtido passando diretamente o resultado da saída da rede por um limite durante o processo de teste.
1.3 Incorporação Posicional
O Positional Embedding no DETR é um valor fixo. O código do Positional Embedding é o seguinte. Vamos analisá-lo brevemente:
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
Para fazer com que a rede perceba as informações de localização de diferentes entradas, a maneira mais intuitiva é atribuir 1 1 ao primeiro Recurso1 , a segunda atribuição de recursos2 22 , mas esse método de atribuição não é amigável para entradas maiores, então alguém propõe usar a função seno para controlar o valor em− 1 -1− 1 e1 11 , mas a função seno é periódica, o que pode ocasionar o mesmo valor em posições diferentes.
Assim, o autor estendeu a função seno para ddd- vetor dimensional, diferentes canais possuem diferentes comprimentos de onda, como segue:
PE ( pos , 2 i ) = sin ( pos / 1000 0 2 i / d model ) P E_{(pos, 2 i)}=\sin \left (pos / 10000^{2 i / d_{\texto {modelo}}}\direita)P E( pos , 2 i ) _=pecado( p os /1000 02i / d _modelo ) PE ( pos , 2 i + 1 ) = cos ( pos / 1000 0 2 i / d modelo ) P E_{(\text {pos }, 2 i+1)}=\cos \left(pos / 10000^ {2 i / d_{\texto {modelo}}}\direita)P E( pos , 2 i + 1 )=porque( p os /1000 02i / d _modelo ) dos quaisiii é o número de canais, por exemplo, definimosd = 6 d=6d=6N : i = [1, 2, 3, 4, 5, 6] {i}=[1,2,3,4,5,6]eu=[ 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=\ esquerda[\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}}\direita]ceu=[1000 01/61,1000 02/61,1000 03/61,1000 04/61,1000 05/61,1000 06/61]当P oision = 2 Poision = 2P oi s i n o _=2时,得到: Codificação de posição = [ sin ( 2 w 0 ) , cos ( 2 w 1 ) , sin ( 2 w 2 ) , cos ( 2 w 3 ) , sin ( 2 w 4 ) , cos ( 2 w 5 ) ] Codificação de posição=\esquerda[\sen \esquerda(2 w_{0}\direita), \cos \esquerda(2 w_{1}\direita), \sin \esquerda(2 w_ {2}\direita), \cos \left(2 w_{3}\direita), \sin \left(2 w_{4}\direita), \cos \left(2 w_{5}\direita)\direita ]Codificação de posição _ _ _ _ _ _ _ _ _ _=[ pecado( 2 w0),porque( 2 w1),pecado( 2 w2),porque( 2 w3),pecado( 2 w4),porque( 2 w5) ] Um vetor multidimensional obtido desta formaé difícil de ser o mesmo em diferentes posições, então o efeito de codificação de diferentes posições é alcançado.
Depois que o DETR foi apresentado, ele rapidamente atraiu a atenção de todos com sua estrutura simples. O próprio DETR também tem muitos problemas, como a velocidade de convergência de treinamento não é rápida o suficiente, o resultado não é SOTA suficiente e o efeito de detecção em objetos pequenos é ruim , então existem muitos outros problemas. Algoritmos relacionados ao DETR, como DETRable Deformable, Anchor DETR, etc., bem como DETR3D aplicado ao campo de direção autônoma, etc., aqui eu resumi brevemente alguns dos algoritmos.
2. DETR deformável
O DETR deformável resolve principalmente os problemas de baixa velocidade de treinamento do DETR original e efeito de detecção ruim em objetos pequenos . A lenta velocidade de convergência do DETR se deve principalmente ao processo de treinamento demorado do Mapa de Atenção, da distribuição uniforme à distribuição esparsa, e o efeito de detecção ruim para objetos pequenos ocorre principalmente porque o Backbone não possui recursos multiescala, mas mesmo se existem, não é realista inserir recursos multiescala no Transformer , porque a complexidade computacional do Transformer é O ( n 2 ) O(n^2)O ( n2 ), os recursos de alta resolução trarão grande consumo de memória e tempo.
Para isso, o Deformable DETR propõe o módulo Defomer Attention, que resolve bem os problemas acima.
2.1 Módulo de Atenção Deformável
O autor introduziu pela primeira vez a fórmula do mecanismo de atenção multicabeçal no Transformer original no artigo: 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}\direita] MultiHeadAttn ( zq,x )=m = 1∑mCm[k ∈ Ωk∑Am q k⋅Cm′xk] É a mesma fórmula que costumamos ver, mas a expressão é um pouco diferente. ondezq , x z_{q}, xzq,x são dois conjuntos de vetores para Atenção,V mx V_{m} xVmx得到Key Embedding,U mzq U_{m} z_{q}vocêmzqObter incorporação de consulta, A mqk A_{mqk}Am q kO peso é obtido pela normalização após a multiplicação de pontos de Query Embedding e Key Embedding, que é proporcional a exp { zq TU m TV mxk C v } \exp \left\{\frac{z_{q}^{T} U_ {m} ^{T} V_{m} x_{k}}{\sqrt{C_{v}}}\direita\}exp{ CvzqTvocêmTVmxk}。W m ′ xk W_{m}^{\prime} x_{k}Cm′xk为 Incorporação de valor, W m W_{m}CmEle é responsável por agregar os resultados multi-head após o Concate. onde U m , V m , W m ′ , W m U_{m}, V_{m}, W_{m}^{\prime}, W_{m}vocêm,Vm,Cm′,Cmsão os parâmetros aprendidos. No DETR, esse mecanismo de atenção multicabeça original é aplicado à autoatenção do codificador e à atenção cruzada do decodificador.
Em seguida, o autor introduziu o princípio do Módulo de Atenção Deformável, cuja fórmula de expressão é: 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}\direita)\direita]DeformAttn( zq,pq,x )=m = 1∑mCm[k = 1∑KAm q k⋅Cm′x( pq+p_ _m q k) ] ondeδ pmqk \delta p_{mqk}p_ _m q ké o deslocamento de posição obtido de Query Embedding e A mqk A_{mqk} na fórmulaAm q kNão é mais o peso obtido através do produto escalar do Query Embedding e Key Embedding, mas sim o peso obtido diretamente do Query Embedding. Este processo pode ser entendido através da figura a seguir:
:
- O mecanismo de atenção multicabeçal usado no DETR usa recursos globais como o valor da chave, enquanto a atenção deformável está próxima a cada consulta e seleciona independentemente KK por meio da incorporação de consultasK valores-chave;
- O mecanismo de atenção multi-head usado no DETR obtém pesos através do produto interno de Key Embedding e Query Embedding, enquanto Deformable Attention é obtido diretamente de Query Embedding através de uma camada linear.
São também as duas diferenças acima que tornam a Atenção Deformável mais eficiente do que o mecanismo de Atenção original . Além disso, Atenção Deformável e Convolução Deformável também são diferentes.Atenção Deformável é prever diretamente vários deslocamentos em um ponto na posição da Consulta, enquanto a Convolução Deformável é prever um viés para cada pixel no kernel da convolução.
Com base no Módulo de Atenção Deformável, o autor propôs ainda o Módulo de Atenção Deformável em Multiescala, a fórmula é a seguinte: 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},\esquerda\{x^{l}\direita\}_{l=1}^{L}\direita)=\sum_{m=1}^{M} W_{m}\esquerda[ \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( zq,p^q,{ xeu }l = 1L)=m = 1∑mCm[l = 1∑Lk = 1∑KAm lq k⋅Cm′xeu( ϕeu(p^q)+p_ _m lq k) ] Comparado com o Módulo de Atenção Deformável, a principal diferença é que o Módulo de Atenção Deformável amostraKKPosições K , enquanto o Módulo de Atenção Deformável Multiescala é daLLCada camada da camada L amostra KKK posições, totalLK LKL K posições de amostragem. Dessa forma, a rede realiza a fusão de recursos multiescalaa um custo pequeno.
2.2 Codificador-Decodificador do Transformador Deformável
A estrutura do Codificador-Decodificador do Transformador Deformável é mostrada na figura abaixo:
No Codificador , o autor substitui todos os Módulos de Auto-Atenção por Módulos de Atenção Deformáveis, e a entrada e saída de cada Codificador são mapas de recursos multiescala de mesma resolução. O mapa de recursos multiescala vem diretamente dos últimos três estágios do ResNet. Conforme mostrado na figura abaixo:
Além disso, com base na retenção da incorporação posicional, é adicionada uma incorporação de nível de escala que pode ser aprendida relacionada ao número de camadas de feição.
No Decoder , o autor mantém a auto-atenção inalterada e substitui a atenção cruzada pela atenção deformável. Para cada incorporação de consulta de objeto, a camada linear e o sigmóide aprendem seu ponto de referência correspondente e consultam a saída de recursos do codificador. A incorporação de valor correspondente é obtida , e finalmente a soma ponderada é realizada com base nos pesos aprendidos pela camada linear e Softmax. Quando li isso pela primeira vez, tive uma pergunta: Object Query Embedding é um valor predefinido, se a posição e o peso do ponto de referência forem inferidos a partir de Object Query Embedding (no DETR, todos eles estão associados ao Encoder Feature obtido), como podemos garantir que o alvo de detecção está correto? Depois de pensar sobre isso com cuidado, o ponto de referência ou peso da primeira camada de Decode Layer pode realmente ser um valor fixo ou um valor aleatório, mas as informações do Encoder Feature já estão incluídas na saída Object Query Embedding pela primeira camada de Decode Layer A posição do ponto de referência gerado pelo Decoder Layer começará a se correlacionar com a imagem, e com a superposição do Decoder Layer, essa correlação ficará cada vez mais forte.
Além disso, um pouco diferente do DETR é que o Deformable DETR prevê que o Bounding Box não regride diretamente as coordenadas absolutas do Object Query, mas regride a distância ao ponto de referência, porque o peso e a posição do ponto de referência são todos do mesmo Object Query A incorporação é inferida, portanto, o método de regressão relativo ao ponto de referência pode acelerar a convergência .
2.3 Conclusão
O conhecimento sobre DETRable Deformable é muito mais do que os dois pontos resumidos acima neste artigo. O artigo DETRable Deformable também apresenta outras estruturas de rede, como DETR Defomable de dois estágios, e você pode ir mais fundo. Aqui, comparamos a melhoria do DETR Deformable relativo para DETR:
A seguir, uma comparação da velocidade de treinamento. A velocidade de convergência de treinamento do Deformable DETR melhorou muito:
Pela tabela abaixo, podemos ver que o Deformable melhorou muito na precisão da detecção de objetos pequenos: A
proposta do DETR baseia-se principalmente em seu fim-a-fim A estrutura de rede do terminal está fora do círculo, mas seu desempenho pode não ter atingido o SOTA naquele momento, mas com o suporte do Deformable DETR, esse tipo de método já pode competir com o método SOTA. Os resultados da comparação são os seguintes:
3. DETR3D
O DETR3D aplica o DETR ao campo da direção autônoma para realizar a detecção de objetos 3D sob a perspectiva da entrada multicâmera BEV, conforme mostrado na figura abaixo: seu princípio é muito semelhante
ao transformador deformável mencionado acima. Vamos resumir brevemente o transformador em BEV O aplicativo sob a tarefa de perspectiva é como outra postagem de blog para aprender mais tarde.
O diagrama de estrutura da rede é mostrado na figura abaixo:
a rede primeiro extrai recursos multiescala para cada entrada de câmera por meio de ResNet e FPN, que é a parte de extração de recursos de imagem na figura. A entrada de recursos 2D para transformação de recursos 3D para estudo mais aprofundado, o que se segue é uma introdução detalhada a esta parte.
3.1 Transformador 2D para 3D
Para cada entrada de câmera, extraímos características de quatro escalas, que são registradas como F 1 , F 2 , F 3 , F 4 \mathcal{F}_{1}, \mathcal{F}_{2}, \mathcal{ F }_{3}, \mathcal{F}_{4}F1,F2,F3,F4, sob a configuração do papel, há um total de seis entradas de câmera: F k = { fk 1 , … , fk 6 } ⊂ RH × W × C \mathcal{F}_{k}=\left\{\ boldsymbol{f} _{k 1}, \ldots, \boldsymbol{f}_{k 6}\right\} \subset \mathbb{R}^{H \times W \times C}Fk={ fk 1,…,fk 6}⊂RA × L × C. _
No algoritmo DETR3D, não há parte do codificador baseado no Transfomer, mas os recursos de imagem extraídos acima são inseridos diretamente na parte do decodificador. Acho que o motivo deve ser que a parte do codificador tem muito cálculo e a parte do decodificador é a mesma que DETR ou DETR deformável. Atenção cruzada é realizada por meio da incorporação de consulta de objeto e do recurso de entrada e, em seguida, o objeto correspondente é retornado do saída final Object Query Embedding.No DETR3D, a maior diferença é a posição no espaço 3D da regressão, e a entrada é o recurso da imagem 2D, portanto, é necessário um decodificador de transformador 2D para 3D.
O Decodificador do DETR3D ainda é composto por Auto-Atenção e Atenção Cruzada. Os métodos em Auto-Atenção e DETR são basicamente os mesmos. A função principal é garantir que cada consulta saiba o que a outra está fazendo e evitar extração repetida do mesmos recursos. Atenção cruzada é bem diferente, vejamos as etapas específicas abaixo:
- Primeiro através de uma rede independente Φ ref \Phi^{\text {ref }}Phiref retorna uma posição 3D do Object Query Embedding, que é um pouco semelhante à operação de Deformable DETR:c ℓ i = Φ ref ( q ℓ i ) \boldsymbol{c}_{\ell i}=\Phi^{\mathrm {ref}}\left(\boldsymbol{q}_{\ell i}\right)cℓ eu=Phiref( qℓ eu) ondec ℓ i \boldsymbol{c}_{\ell i}cℓ eupode ser considerado como iiA posição central da i Box.
- Através dos parâmetros da câmera, a posição c ℓ i \boldsymbol{c}_{\ell i}cℓ euProjete para o recurso de cada câmera para obter a posição 3D da caixa usada para incorporação de chave e incorporação de valor para refinar a previsão: c ℓ i ∗ = c ℓ i ⊕ 1 \boldsymbol{c}_{\ell i}^{* }= \boldsymbol{c}_{\ell i} \oplus 1cℓ eu∗=cℓ eu⊕1 c ℓ mi = T mc ℓ i ∗ \boldsymbol{c}_{\ell mi}=T_{m} \boldsymbol{c}_{\ell i}^{*}cℓ milhas=Tmcℓ eu∗onde T m T_{m}Tmé o parâmetro da câmera.
- Como cada entrada é um mapa de recursos multiescala, para evitar a influência de diferentes resoluções de recursos de escala, a interpolação bilinear é usada para interpolar o mapa de recursos e, se as coordenadas estiverem fora da imagem, preencha com zeros: f ℓ kmi = f bilinear ( F km , c ℓ mi ) \boldsymbol{f}_{\ell kmi}=f^{\text {bilinear }}\left(\mathcal{F}_{km}, \boldsymbol{c}_ {\ ell mi}\direita)fℓ km=fbilinear ( Fkm,cℓ milhas)
- Adicione os recursos acima e, finalmente, adicione-os ao Object Query Embedding para refinamento: 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_ {\bem kmi}fℓ eu=∑k∑mpℓ km+ϵ1k∑m∑fℓ kmpℓ kmq ( ℓ + 1 ) i = f ℓ i + q ℓ i \boldsymbol{q}_{(\ell+1) i}=\boldsymbol{f}_{\ell i}+\boldsymbol{q}_{ \bem eu}q( ℓ + 1 ) eu=fℓ eu+qℓ euAcho que este é realmente o passo equivalente ao somatório ponderado de atenção cruzada.No DETR, este passo é atualizar a consulta ponderando o valor de incorporação de valor multiplicando o peso de incorporação de consulta e incorporação de chave. Em Deformable, a etapa de Query Embedding e Key Embedding ponto de multiplicação é omitida, e o peso da regressão é realizado diretamente através do Query Embedding, e então o Value Embedding é ponderado. Aqui, o autor equivale a adicionar Value Embedding e Query Embedding , omitindo ainda mais a quantidade de cálculo. (Esta parte é minha conclusão com base na descrição do artigo e no resumo de outros blogs. Pode ser diferente da implementação do código. Se houver algum erro, por favor, indique ao leitor)
- Depois de iterar as operações acima muitas vezes, a categoria e a posição são finalmente regredidas da Incorporação de Consulta: b ^ ℓ i = Φ ℓ reg ( q ℓ i ) \hat{\boldsymbol{b}}_{\ell i}=\ Phi_ {\ell}^{\mathrm{reg}}\left(\boldsymbol{q}_{\ell i}\right)b^ℓ eu=Phiℓregular( qℓ eu) c ^ ℓ i = Φ ℓ cls ( q ℓ i ) \hat{c}_{\ell i}=\Phi_{\ell}^{\mathrm{cls}}\left(\boldsymbol{q}_{ \ bem i} \ certo)c^ℓ eu=Phiℓcls( qℓ eu)
O acima é o entendimento da parte do decodificador DETR3D. Como não há tempo para ler o código-fonte, o entendimento pode não ser suficiente e muitos detalhes podem ser ignorados. Desde o Tesla AI Day no ano passado, todo mundo tem feito muita pesquisa sobre a aplicação do Transformer no campo da direção autônoma. Pretendo ir mais longe no futuro. Como associar recursos 2D em 3D é muito interessante.
O resumo relevante do DETR neste artigo está aqui por enquanto, e irei adicioná-lo mais tarde quando tiver tempo. Se você tiver alguma dúvida, dê conselhos e troque ~