Otimização de Prompt em Tempo de Teste para Generalização Zero-Shot em Model model model model Modelos Visão-Linguagem

Este artigo explora uma técnica inovadora para aprimorar a capacidade de generalização zero-shot de modelos pré-treinados de visão e linguagem, como o CLIP. Em vez de depender de prompts elaborados manualmente ou de dados de treinamento específicos para cada tarefa, propomos um método para otimizar dinamicamente os prompts usando um único exemplo de teste. Essa abordagem demonstrou melhorias significativas no desempenho zero-shot em cenários com desvios de distribuição natural, tarefas inter-dataset e raciocínio visual.

  1. Introdução

Modelos de visão e linguagem (VLMs) pré-treinados, como o CLIP, são poderosos para tarefas de generalização zero-shot. No entanto, seu desempenho depende fortemente da qualidade dos prompts (instruções textuais) utilizados. Métodos existentes para criar ou ajustar esses prompts têm limitações:

1.1. Prompt Engineering Manual

Essa abordagem envolve a criação manual de prompts, o que requer conhecimento especializado e experiência. Embora prompts como "uma foto de um" sejam comuns, eles não são universalmente eficazes. Diferentes tarefas podem exigir prompts personalizados, tornando o processo trabalhoso e limitado em termos de desempenho máximo alcançável, especialmente em cenários com desvios de distribuição.

1.2. Fine-tuning de Prompt com Dados de Downstream

Esta técnica trata os prompts como parâmetros treináveis e os ajusta usando dados de treinamento rotulados da tarefa downstream (por exemplo, ImageNet). Embora melhore o desempenho em tarefas específicas, essa abordagem falha em manter o espírito do zero-shot, pois requer dados rotulados. Além disso, o prompt ajustado para um domínio pode ter desempenho ruim em outros, diminuindo a capacidade de generalização.

1.3. Outras Abordagens

Existem outras técnicas como aprendizado de prompt não supervisionado, que geralmente requerem múltiplos exemplos de treinamento ou teste. Métodos de adaptação em tempo de teste, como o TENT, focam na adaptação de modelos a novos dados em tempo de teste, mas também geralmente necessitam de múltiplos exemplos de teste. O ajuste fino dos codificadores visual ou textual do VLM pode prejudicar o conhecimento pré-treinado.

1.4. Proposta: Test-Time Prompt Tuning (TPT)

O TPT aborda essas limitações ao propor a otimização de prompts em tempo de teste usando apenas um único exemplo. Isso evita a necessidade de dados de treinamento downstream, prevenindo o viés de distribuição e mantendo a capacidade de generalização. Para lidar com o ruído introduzido pelo aprimoramento de dados em um único exemplo, o TPT incorpora um mecanismo de filtragem baseado em confiança para remover amostras de alta entropia. O método é projetado para funcionar com VLMs pré-treinados como o CLIP e identifica quais partes do prompt são mais eficazes para otimização.

  1. Análise do Algoritmo TPT

O TPT otimiza dinamicamente os prompts em tempo de teste para um único exemplo. O processo anvolve as seguintes etapas:

1. Geração de Vistas Aprimoradas: Um único exemplo de teste é submetido a várias transformações de aprimoramento de dados (como corte e rotação) para gerar N vistas. Essas vistas são alimentadas no codificador de imagem do VLM.

2. Processamento do Prompt: Um prompt textual inicial é convertido em um vetor de incorporação. Esse vetor é concatenado com o conteúdo textual e alimentado no codificador de texto do VLM.

3. Previsão Consistente: O modelo faz previsões para as N vistas aprimoradas. O objetivo é garantir que as previsões para todas as vistas do mesmo exemplo sejam consistentes. Para isso, a entropia de cada previsão é calculada.

4. Filtragem Baseada em Confiança: As previsões são classificadas por sua entropia. Um limiar é aplicado para filtrar amostras de alta entropia (baixa confiança), mantendo apenas as vistas mais confiáveis.

5. Otimização do Prompt: A probabilidade média de previsão das vistas selecionadas é calculada. A meta é minimizar a entropia dessa probabilidade média, otimizando assim os parâmetros de encorporação do prompt através de retropropagação.

2.1. Otimização para Classificação de Imagens

Para classificação de imagens, o TPT visa minimizar a entropia marginal das probabilidades de previsão de um único exemplo de teste em suas diversas vistas aprimoradas. O objetivo é garantir a consistência nas previsões, mesmo com variações nos dados de entrada.

A função de perda para essa tarefa é definida como:

$$ L_{TPT}(X_{test}, p) = \mathbb{E}_{X'_{test} \sim Aug(X_{test})} \left[ -\sum_{c} \bar{p}_c \log(\bar{p}_c) \right] $$

onde $ \bar{p}_c $ representa a probabilidade média de previsão para a classe c sobre as vistas aprimoradas $ X'_{test} $.


# Cálculo da entropia média para medir a consistência das previsões
# Calcula a entropia da "distribuição de probabilidade média" sobre várias vistas aprimoradas.
# Utiliza o espaço logarítmico para estabilidade numérica e evitar problemas com valores extremos.
def calcular_entropia_media(saidas):
   # saidas: [num_vistas_aprimoradas, num_classes]

   # Converte as saídas brutas para probabilidades logarítmicas (log-softmax)
   # log_softmax(x)_i = log(exp(x_i) / Σ(exp(x_j))) = x_i - log(Σ(exp(x_j)))
   log_probs = saidas - saidas.logsumexp(dim=-1, keepdim=True) # log_probs = saidas.log_softmax(dim=1) [N, C]

   # Calcula a média das probabilidades logarítmicas para obter o logaritmo da "probabilidade média"
   # log(Σ(exp(log_prob))) - log(N) = log(Σ(prob)) - log(N) = log(Média(prob))
   media_log_probs = log_probs.logsumexp(dim=0) - torch.log(torch.tensor(log_probs.shape[0], dtype=log_probs.dtype)) # media_log_probs = log_probs.mean(0) [1, C]

   # Garante estabilidade numérica limitando os valores
   min_real = torch.finfo(media_log_probs.dtype).min
   media_log_probs = torch.clamp(media_log_probs, min=min_real)

   # Calcula a entropia da distribuição de probabilidade média
   return -(media_log_probs * torch.exp(media_log_probs)).sum(dim=-1)
 

O TPT também emprega um mecanismo de seleção de amostras confiáveis. Ele calcula a entropia para cada vista aprimorada individual e seleciona apenas as vistas com entropia abaixo de um limiar dinâmico para recalcular a probabilidade média de previsão.


# Função para selecionar amostras com alta confiança (baixa entropia)
def selecionar_amostras_confiantes(log_logits, proporcao_top):
   # Calcula a entropia para cada amostra no batch (dimensão 1)
   probs = torch.softmax(log_logits, dim=1)
   entropia_batch = -(probs * log_logits.log_softmax(dim=1)).sum(1) # Tensor de forma [batch_size]

   # Ordena as amostras pela entropia em ordem crescente e seleciona a proporção especificada
   num_selecionar = int(entropia_batch.size()[0] * proporcao_top)
   indices_selecionados = torch.argsort(entropia_batch, descending=False)[:num_selecionar]

   # Retorna as saídas das amostras selecionadas e seus índices
   return log_logits[indices_selecionados], indices_selecionados
 

O loop de otimização em tempo de teste é implementado da seguinte forma:


# Otimização do prompt em tempo de teste para um único exemplo
def otimizacao_tempo_teste(modelo, entradas, otimizador, scaler, args):
   indices_selecionados = None # Para armazenar os índices das amostras de alta confiança

   # Múltiplas etapas de otimização do prompt
   for _ in range(args.passos_tta):
       with torch.cuda.amp.autocast(): # Usa precisão mista
           if args.usar_cocoop:
               caracteristicas_imagem, contexto_gerador = entradas
               saida = modelo((caracteristicas_imagem, contexto_gerador))
           else:
               saida = modelo(entradas)

           # Seleciona amostras de alta confiança se já tivermos os índices
           if indices_selecionados is not None:
               saida = saida[indices_selecionados]
           else:
               # Primeira iteração ou sem índices prévios: calcula e seleciona
               saida, indices_selecionados = selecionar_amostras_confiantes(saida, args.proporcao_selecao)

           # Calcula a perda de entropia média
           perda = calcular_entropia_media(saida)

       # Retropropagação e atualização do otimizador
       otimizador.zero_grad()
       scaler.scale(perda).backward()
       scaler.step(otimizador)
       scaler.update()

   if args.usar_cocoop:
       return contexto_gerador # Retorna os parâmetros otimizados do gerador de prompt
   return
 

2.2. Raciocínio Visual com Dependência de Contexto

Para tarefas de raciocínio visual que dependem de contexto (como identificar Interações Objeto-Humano - HOI), o TPT introduz um token de classe binário aprendível $ \{cls_0, cls_1\} $. Diferente da classificação de imagens, a função de perda muda de entropia marginal não supervisionada para entrópico cruzado semi-supervisionado, otimizando conjuntamente o prompt $ p $ e o token de classe $ cls $.

A função de perda para esta tarefa é:

$$ L_{TPT\_HOI}(X_P, X_N, X_{query}, p, cls) = CrossEntropy(f(p, cls), y) $$

Onde $ X_P $ são amostras de suporte positivas, $ X_N $ são amostras de suporte negativas, $ X_{query} $ é a imagem de consulta, $ p $ é o prompt, $ cls $ são os tokens de classe aprendíveis, e $ y $ são os rótulos verdadeiros (0 ou 1).

Este método aprende o contexto semântico a partir de suportes positivos e negativos, permitindo que o prompt destaque características interativas relevantes e que os tokens de classe se alinhem com as características visuais aprendidas.

  1. Resultados Experimentais

O TPT foi avaliado em diversos cenários, incluindo robustez a desvios de distribuição, generalização entre datasets e raciocínio visual.

3.1. Robustez a Desvios de Distribuição Natural

Em quatro datasets derivados do ImageNet, o TPT mostrou desempenho promissor mesmo com apenas um único exemplo de teste. Além disso, combinar o TPT com métodos existentes resultou em melhorias adicionais.

3.2. Generalização Entre Datasets

Em 10 datasets de classificação fina cobrindo diversas categorias (flores, animais, cenas, texturas), o TPT demonstrou forte capacidade de generalização. Avaliou-se tanto o cenário de fontes gerais (ImageNet) para alvos específicos quanto o de fontes e alvos sem sobreposição de classes.

3.3. Raciocínio Visual Contextual (Bongard-HOI)

A tarefa Bongard-HOI avalia a capacidade do TPT em entender interações complexas em imagens. Comparado com baselines que requerem treinamento extensivo, o TPT mostrou resultados competitivos, destacando sua eficácia em tarefas de raciocínio visual.

3.4. Experimentos de Ablação

Experimentos de ablação validaram a escolha de otimizar apenas os prompts textuais (em vez de todo o modelo ou codificadores visuais/textuais) e a eficácia do mecanismo de seleção de confiança. Os resultados confirmaram que otimizar prompts textuais é a abordagem mais eficaz, e o mecanismo de seleção de confiança melhora significativamente o desempenho, com um limiar ideal em torno de 0.1.

  1. Conclusão

O TPT apresenta uma solução eficaz e eficiente para o problema da generalização zero-shot em modelos de visão e linguagem. Ao otimizar dinamicamente os prompts em tempo de teste usando um único exemplo, o TPT supera as limitações dos métodos baseados em engenharia manual ou ajuste fino com dados downstream. A introdução de um mecanismo de filtragem baseado em confiança aprimora ainda mais a robustez em cenários com desvios de distribuição. Embora haja um custo computacional em termos de memória e tempo de processamento devido à geração de múltiplas vistas e à retropropagação, o TPT abre novas avanidas para a aplicação de VLMs em cenários com poucos ou nenhum dado rotulado.

Tags: Visão Computacional linguagem natural CLIP Zero-shot Learning prompt tuning

Publicado em 7-13 02:09