Entre em contato

Otimização de preferência direta: um guia completo

Inteligência artificial

Otimização de preferência direta: um guia completo

mm
LLM DPO matemática e código

Alinhar grandes modelos de linguagem (LLMs) com valores e preferências humanas é um desafio. Métodos tradicionais, como Aprendizagem por Reforço com Feedback Humano (RLHF), abriram caminho integrando informações humanas para refinar os resultados do modelo. No entanto, o RLHF pode ser complexo e consumir muitos recursos, exigindo poder computacional e processamento de dados substanciais. Otimização de preferência direta (DPO) surge como uma abordagem nova e mais simplificada, oferecendo uma alternativa eficiente a estes métodos tradicionais. Ao simplificar o processo de otimização, o DPO não apenas reduz a carga computacional, mas também aumenta a capacidade do modelo de se adaptar rapidamente às preferências humanas

Neste guia, nos aprofundaremos no DPO, explorando seus fundamentos, implementação e aplicações práticas.

A necessidade de alinhamento de preferências

Para entender o DPO, é crucial entender por que alinhar LLMs com preferências humanas é tão importante. Apesar de suas capacidades impressionantes, LLMs treinados em vastos conjuntos de dados podem, às vezes, produzir resultados inconsistentes, tendenciosos ou desalinhados com valores humanos. Esse desalinhamento pode se manifestar de várias maneiras:

  • Geração de conteúdo inseguro ou prejudicial
  • Fornecer informações imprecisas ou enganosas
  • Exibindo vieses presentes nos dados de treinamento

Para resolver esses problemas, os pesquisadores desenvolveram técnicas para ajustar os LLMs usando feedback humano. A mais proeminente dessas abordagens foi a RLHF.

Compreendendo o RLHF: o precursor do DPO

A Aprendizagem por Reforço com Feedback Humano (RLHF) tem sido o método preferido para alinhar LLMs com as preferências humanas. Vamos analisar o processo RLHF para entender suas complexidades:

a) Ajuste fino supervisionado (SFT): O processo começa com o ajuste fino de um LLM pré-treinado em um conjunto de dados de respostas de alta qualidade. Esta etapa ajuda o modelo a gerar resultados mais relevantes e coerentes para a tarefa alvo.

b) Modelagem de recompensa: Um modelo de recompensa separado é treinado para prever as preferências humanas. Isso envolve:

  • Gerando pares de respostas para determinados prompts
  • Fazer com que os humanos avaliem qual resposta eles preferem
  • Treinando um modelo para prever essas preferências

c) Aprendizagem por Reforço: O LLM ajustado é então otimizado ainda mais usando aprendizagem por reforço. O modelo de recompensa fornece feedback, orientando o LLM a gerar respostas que se alinhem com as preferências humanas.

Aqui está um pseudocódigo Python simplificado para ilustrar o processo RLHF:

Embora eficaz, o RLHF tem várias desvantagens:

  • Requer treinamento e manutenção de vários modelos (SFT, modelo de recompensa e modelo otimizado para RL)
  • O processo RL pode ser instável e sensível a hiperparâmetros
  • É computacionalmente caro, exigindo muitas passagens para frente e para trás através dos modelos

Estas limitações motivaram a busca por alternativas mais simples e eficientes, levando ao desenvolvimento do DPO.

Otimização de preferência direta: conceitos básicos

Otimização de preferência direta https://arxiv.org/abs/2305.18290

Otimização de preferência direta https://arxiv.org/abs/2305.18290

Esta imagem contrasta duas abordagens distintas para alinhar os resultados do LLM com as preferências humanas: Aprendizagem por Reforço com Feedback Humano (RLHF) e Otimização de Preferência Direta (DPO). O RLHF depende de um modelo de recompensa para orientar a política do modelo de linguagem por meio de ciclos de feedback iterativos, enquanto o DPO otimiza diretamente os resultados do modelo para corresponder às respostas preferidas pelos humanos usando dados de preferência. Esta comparação destaca os pontos fortes e as aplicações potenciais de cada método, fornecendo insights sobre como os futuros LLMs podem ser treinados para se alinharem melhor com as expectativas humanas.

Ideias principais por trás do DPO:

a) Modelagem de recompensa implícita: O DPO elimina a necessidade de um modelo de recompensa separado, tratando o próprio modelo de linguagem como uma função de recompensa implícita.

b) Formulação Baseada em Políticas: Em vez de otimizar uma função de recompensa, o DPO otimiza diretamente a política (modelo de linguagem) para maximizar a probabilidade de respostas preferidas.

c) Solução de formulário fechado: o DPO aproveita uma visão matemática que permite uma solução fechada para a política ideal, evitando a necessidade de atualizações iterativas de RL.

Implementando DPO: um passo a passo prático do código

A imagem abaixo mostra um trecho de código que implementa a função de perda de DPO usando PyTorch. Esta função desempenha um papel crucial no refinamento de como os modelos de linguagem priorizam os resultados com base nas preferências humanas. Aqui está uma análise dos principais componentes:

  • Assinatura de Função: O dpo_loss A função aceita vários parâmetros, incluindo probabilidades de log de política (pi_logps), probabilidades de log do modelo de referência (ref_logps) e índices que representam conclusões preferenciais e não preferidas (yw_idxs, yl_idxs). Além disso, um beta parâmetro controla a força da penalidade KL.
  • Extração de probabilidade de log: o código extrai as probabilidades de log para conclusões preferenciais e não preferidas dos modelos de política e de referência.
  • Cálculo da razão logarítmica: a diferença entre as probabilidades de log para conclusões preferenciais e não preferenciais é calculada para os modelos de política e de referência. Essa proporção é crítica para determinar a direção e a magnitude da otimização.
  • Cálculo de Perdas e Recompensas: A perda é calculada usando o logsigmoid função, enquanto as recompensas são determinadas pelo dimensionamento da diferença entre a política e as probabilidades do log de referência por beta.
Função de perda DPO usando PyTorch

Função de perda DPO usando PyTorch

Vamos mergulhar na matemática por trás do DPO para entender como ele atinge esses objetivos.

A Matemática do DPO

DPO é uma reformulação inteligente do problema de aprendizagem de preferências. Aqui está uma análise passo a passo:

a) Ponto de partida: Maximização de recompensa restrita por KL

O objetivo original do RLHF pode ser expresso como:

A fórmula matemática complexa na próxima imagem representa a função de perda usada na Otimização de Preferência Direta (DPO), um método de treinamento de ponta que refina como os LLMs alinham seus resultados com as preferências humanas.

Onde:
  • πθ é a política (modelo de linguagem) que estamos otimizando
  • r(x,y) é a função de recompensa
  • πref é uma política de referência (geralmente o modelo SFT inicial)
  • β controla a força da restrição de divergência KL

b) Formulário de política ideal: Pode-se mostrar que a política ótima para este objetivo assume a forma:

π_r(y|x) = 1/Z(x) * πref(y|x) * exp(1/β * r(x,y))

Onde Z(x) é uma constante de normalização.

c) Dualidade política de recompensa: O principal insight do DPO é expressar a função de recompensa em termos da política ideal:

r(x,y) = β * log(π_r(y|x) / πref(y|x)) + β * log(Z(x))

d) Modelo de Preferência Supondo que as preferências sigam o modelo de Bradley-Terry, podemos expressar a probabilidade de preferir y1 a y2 como:

p*(y1 ≻ y2 | x) = σ(r*(x,y1) - r*(x,y2))

Onde σ é a função logística.

e) Objetivo do DPO Substituindo a nossa dualidade política de recompensas no modelo de preferência, chegamos ao objetivo do DPO:

L_DPO(πθ; πref) = -E_(x,y_w,y_l)~D [log σ(β * log(πθ(y_w|x) / πref(y_w|x)) - β * log(πθ(y_l|x) / πref(y_l|x)))]

Este objetivo pode ser otimizado usando técnicas padrão de gradiente descendente, sem a necessidade de algoritmos RL.

Implementando DPO

Agora que entendemos a teoria por trás do DPO, vamos ver como implementá-lo na prática. Nós usaremos Python e PyTorch para este exemplo:

import torch
import torch.nn.functional as F

class DPOTrainer:
    def __init__(self, model, ref_model, beta=0.1, lr=1e-5):
        self.model = model
        self.ref_model = ref_model
        self.beta = beta
        self.optimizer = torch.optim.AdamW(self.model.parameters(), lr=lr)
    
    def compute_loss(self, pi_logps, ref_logps, yw_idxs, yl_idxs):
        """
        pi_logps: policy logprobs, shape (B,)
        ref_logps: reference model logprobs, shape (B,)
        yw_idxs: preferred completion indices in [0, B-1], shape (T,)
        yl_idxs: dispreferred completion indices in [0, B-1], shape (T,)
        beta: temperature controlling strength of KL penalty

        Each pair of (yw_idxs[i], yl_idxs[i]) represents the indices of a single preference pair.
        """

        # Extract log probabilities for the preferred and dispreferred completions
        pi_yw_logps, pi_yl_logps = pi_logps[yw_idxs], pi_logps[yl_idxs]
        ref_yw_logps, ref_yl_logps = ref_logps[yw_idxs], ref_logps[yl_idxs]

        # Calculate log-ratios
        pi_logratios = pi_yw_logps - pi_yl_logps
        ref_logratios = ref_yw_logps - ref_yl_logps

        # Compute DPO loss
        losses = -F.logsigmoid(self.beta * (pi_logratios - ref_logratios))
        rewards = self.beta * (pi_logps - ref_logps).detach()

        return losses.mean(), rewards

    def train_step(self, batch):
        x, yw_idxs, yl_idxs = batch
        self.optimizer.zero_grad()

        # Compute log probabilities for the model and the reference model
        pi_logps = self.model(x).log_softmax(-1)
        ref_logps = self.ref_model(x).log_softmax(-1)

        # Compute the loss
        loss, _ = self.compute_loss(pi_logps, ref_logps, yw_idxs, yl_idxs)
        loss.backward()
        self.optimizer.step()

        return loss.item()

# Usage
model = YourLanguageModel()  # Initialize your model
ref_model = YourLanguageModel()  # Load pre-trained reference model
trainer = DPOTrainer(model, ref_model)

for batch in dataloader:
    loss = trainer.train_step(batch)
    print(f"Loss: {loss}")

Desafios e Direções Futuras

Embora o DPO ofereça vantagens significativas em relação às abordagens tradicionais de RLHF, ainda existem desafios e áreas para futuras pesquisas:

a) Escalabilidade para modelos maiores:

À medida que os modelos de linguagem continuam a crescer em tamanho, a aplicação eficiente do DPO a modelos com centenas de bilhões de parâmetros continua sendo um desafio em aberto. Os pesquisadores estão explorando técnicas como:

  • Métodos eficientes de ajuste fino (por exemplo, LoRA, ajuste de prefixo)
  • Otimizações de treinamento distribuído
  • Checkpoint de gradiente e treinamento de precisão mista

Exemplo de uso de LoRA com DPO:

from peft import LoraConfig, get_peft_model

class DPOTrainerWithLoRA(DPOTrainer):
    def __init__(self, model, ref_model, beta=0.1, lr=1e-5, lora_rank=8):
        lora_config = LoraConfig(
            r=lora_rank,
            lora_alpha=32,
            target_modules=["q_proj", "v_proj"],
            lora_dropout=0.05,
            bias="none",
            task_type="CAUSAL_LM"
        )
        self.model = get_peft_model(model, lora_config)
        self.ref_model = ref_model
        self.beta = beta
        self.optimizer = torch.optim.AdamW(self.model.parameters(), lr=lr)

# Usage
base_model = YourLargeLanguageModel()
dpo_trainer = DPOTrainerWithLoRA(base_model, ref_model)

b) Adaptação multitarefa e de poucas fotos:

O desenvolvimento de técnicas de DPO que possam se adaptar eficientemente a novas tarefas ou domínios com dados de preferência limitados é uma área ativa de pesquisa. As abordagens que estão sendo exploradas incluem:

  • Estruturas de meta-aprendizagem para adaptação rápida
  • Ajuste fino baseado em prompt para DPO
  • Transferir o aprendizado de modelos de preferência geral para domínios específicos

c) Lidar com preferências ambíguas ou conflitantes:

Os dados de preferências do mundo real muitas vezes contêm ambiguidades ou conflitos. É crucial melhorar a robustez do DPO relativamente a esses dados. As soluções potenciais incluem:

  • Modelagem de preferência probabilística
  • Aprendizagem ativa para resolver ambigüidades
  • Agregação de preferências multiagentes

Exemplo de modelagem de preferência probabilística:

class ProbabilisticDPOTrainer(DPOTrainer):
    def compute_loss(self, pi_logps, ref_logps, yw_idxs, yl_idxs, preference_prob):
        # Compute log ratios
        pi_yw_logps, pi_yl_logps = pi_logps[yw_idxs], pi_logps[yl_idxs]
        ref_yw_logps, ref_yl_logps = ref_logps[yw_idxs], ref_logps[yl_idxs]
        
        log_ratio_diff = pi_yw_logps.sum(-1) - pi_yl_logps.sum(-1)
        loss = -(preference_prob * F.logsigmoid(self.beta * log_ratio_diff) +
                 (1 - preference_prob) * F.logsigmoid(-self.beta * log_ratio_diff))
        return loss.mean()

# Usage
trainer = ProbabilisticDPOTrainer(model, ref_model)
loss = trainer.compute_loss(pi_logps, ref_logps, yw_idxs, yl_idxs, preference_prob=0.8)  # 80% confidence in preference

d) Combinando DPO com Outras Técnicas de Alinhamento:

A integração do DPO com outras abordagens de alinhamento poderia levar a sistemas mais robustos e capazes:

  • Princípios constitucionais de IA para satisfação explícita de restrições
  • Modelagem de debate e recompensa recursiva para elicitação de preferências complexas
  • Aprendizagem por reforço inverso para inferir funções de recompensa subjacentes

Exemplo de combinação de DPO com IA constitucional:

class ConstitutionalDPOTrainer(DPOTrainer):
    def __init__(self, model, ref_model, beta=0.1, lr=1e-5, constraints=None):
        super().__init__(model, ref_model, beta, lr)
        self.constraints = constraints or []

    def compute_loss(self, pi_logps, ref_logps, yw_idxs, yl_idxs):
        base_loss = super().compute_loss(pi_logps, ref_logps, yw_idxs, yl_idxs)
        
        constraint_loss = 0
        for constraint in self.constraints:
            constraint_loss += constraint(self.model, pi_logps, ref_logps, yw_idxs, yl_idxs)
        
        return base_loss + constraint_loss

# Usage
def safety_constraint(model, pi_logps, ref_logps, yw_idxs, yl_idxs):
    # Implement safety checking logic
    unsafe_score = compute_unsafe_score(model, pi_logps, ref_logps)
    return torch.relu(unsafe_score - 0.5)  # Penalize if unsafe score > 0.5

constraints = [safety_constraint]
trainer = ConstitutionalDPOTrainer(model, ref_model, constraints=constraints)

Considerações Práticas e Melhores Práticas

Ao implementar o DPO para aplicativos do mundo real, considere as dicas a seguir:

a) Qualidade de dados: A qualidade dos seus dados de preferência é crucial. Certifique-se de que seu conjunto de dados:

  • Abrange uma ampla gama de entradas e comportamentos desejados
  • Possui anotações de preferências consistentes e confiáveis
  • Equilibra diferentes tipos de preferências (por exemplo, factualidade, segurança, estilo)

b) Ajuste de hiperparâmetros: embora o DPO tenha menos hiperparâmetros que o RLHF, o ajuste ainda é importante:

  • β (beta): Controla o trade-off entre satisfação de preferência e divergência do modelo de referência. Comece com valores ao redor 0.1-0.5.
  • Taxa de aprendizagem: Use uma taxa de aprendizagem mais baixa do que o ajuste fino padrão, normalmente na faixa de 1e-6 a 1e-5.
  • Tamanho do lote: Tamanhos de lote maiores (32-128) geralmente funcionam bem para aprendizagem preferencial.

c) Refinamento Iterativo: O DPO pode ser aplicado iterativamente:

  1. Treine um modelo inicial usando DPO
  2. Gere novas respostas usando o modelo treinado
  3. Colete novos dados de preferência sobre essas respostas
  4. Treine novamente usando o conjunto de dados expandido

 

Otimização de preferência direta

Desempenho de otimização de preferência direta

Esta imagem mostra o desempenho de LLMs como GPT-4 em comparação com julgamentos humanos em várias técnicas de treinamento, incluindo Direct Preference Optimization (DPO), Supervised Fine-Tuning (SFT) e Proximal Policy Optimization (PPO). A tabela revela que as saídas do GPT-4 estão cada vez mais alinhadas com as preferências humanas, especialmente em tarefas de sumarização. O nível de concordância entre o GPT-4 e os revisores humanos demonstra a capacidade do modelo de gerar conteúdo que ressoa com avaliadores humanos, quase tão próximo quanto o conteúdo gerado por humanos.

Estudos de caso e aplicações

Para ilustrar a eficácia do DPO, vejamos algumas aplicações do mundo real e algumas de suas variantes:

  • DPO Iterativo: Desenvolvida por Snorkel (2023), esta variante combina amostragem de rejeição com DPO, possibilitando um processo de seleção mais refinado para dados de treinamento. Ao iterar em várias rodadas de amostragem de preferência, o modelo é mais capaz de generalizar e evitar ajuste excessivo a preferências ruidosas ou tendenciosas.
  • IPO (Otimização de preferência iterativa): Introduzido por Azar et al. (2023), o IPO adiciona um termo de regularização para evitar overfitting, que é um problema comum na otimização baseada em preferências. Esta extensão permite que os modelos mantenham um equilíbrio entre aderir às preferências e preservar as capacidades de generalização.
  • KTO (Otimização da transferência de conhecimento): Uma variante mais recente de Ethayarajh et al. (2023), KTO dispensa totalmente as preferências binárias. Em vez disso, centra-se na transferência de conhecimento de um modelo de referência para o modelo político, optimizando para um alinhamento mais suave e consistente com os valores humanos.
  • DPO multimodal para aprendizagem entre domínios por Xu et al. (2024): uma abordagem em que o DPO é aplicado em diferentes modalidades – texto, imagem e áudio – demonstrando sua versatilidade no alinhamento de modelos com preferências humanas em diversos tipos de dados. Esta pesquisa destaca o potencial do DPO na criação de sistemas de IA mais abrangentes, capazes de lidar com tarefas complexas e multimodais.

Conclusão

A Otimização de Preferência Direta representa um avanço significativo no alinhamento dos modelos de linguagem com as preferências humanas. Sua simplicidade, eficiência e eficácia fazem dele uma ferramenta poderosa para pesquisadores e profissionais.

Ao aproveitar o poder da Otimização de Preferência Direta e manter esses princípios em mente, você pode criar modelos de linguagem que não apenas exibem capacidades impressionantes, mas também se alinham estreitamente com os valores e intenções humanas.

Passei os últimos cinco anos mergulhando no fascinante mundo do Machine Learning e Deep Learning. Minha paixão e experiência me levaram a contribuir para mais de 50 projetos diversos de engenharia de software, com foco particular em AI/ML. Minha curiosidade contínua também me atraiu para o Processamento de Linguagem Natural, um campo que estou ansioso para explorar mais.