Desmistificando o fine tuning de LLMs na prática: PEFT, LoRA, QLORA e Hambúrgueres

Hugo Zanini
Data Hackers
Published in
9 min readMay 13, 2024

--

Imagem gerada pelo DALL·E 3

A possibilidade de utilização de grandes modelos de linguagem (LLMs) para a realização de tarefas que podem gerar ganhos de produtividade tem despertado o interesse de diversas indústrias. Recentemente, o CEO da TCS, maior provedora de serviços e produtos de TI no mundo, disse acreditar que, por conta avanços em AI, as operações de call centers devem se tornar obsoletas em menos de um ano.

Em sua entrevista, K Krithivasan diz acreditar que em breve chatbots serão capazes de analisar dados de clientes e fazer a maioria do trabalho feito por um call center hoje — respondendo solicitações e até antecipando problemas.

Eu acredito neste futuro. Agentes de AI já são capazes de realizar boa parte das tarefas repetitivas de um call-center, mas a indústria ainda esbarra em alguns desafios.

O principal deles relaciona-se com o desenvolvimento de modelos. Atualmente, as soluções mais poderosas são fechadas e encontram-se nas mãos de empresas como OpenAI, Anthropic e Google.

Treinar um LLM do zero requer muito investimento em engenharia, GPUs, energia elétrica e coleta de dados. São poucas as organizações que têm capacidade de fazer tais investimentos. Portanto, para criar soluções, empresas menores acabam indo por dois caminhos: Pagam pela utilização soluções fechadas como o GPT-4 ou Gemini, ou tentam adaptar e evoluir modelos open-source.

Meta e Google têm liderado o movimento de disponibilização de tais modelos — só para o treino do Llama2, por exemplo, estima-se que a meta investiu aproximadamente 20 milhões de dólares. Estas soluções apresentam limitações quando comparadas com os modelos fechados, mas funcionam muito bem o objetivo é utilizá-las como base para trabalhar em tarefas mais específicas.

Voltando ao exemplo do call center, se quisermos criar um chatbot para responder perguntas relacionadas a um produto especifico e para um perfil de clientes pré-determinado, a utilização de um modelo open-source como base é um caminho muito interessante.

Com poucas amostras de interações entre atendentes e clientes seria possível adaptar um modelo para adotar um estilo de comunicação e absorver informações para a resolução de problemas e execução de tarefas. Este tipo de abordagem é conhecida como fine-tuning e é o que iremos explorar neste post.

Definindo um pipeline de fine-tuning

A ideia básica por trás de um fine tuning é aproveitar o conhecimento e capacidade de generalização de grandes modelos e adaptar a uma tarefa ou domínio específico. O diagrama a seguir mostrar um pipeline genérico de treinamento.

O modelo base é pré-treinado em grandes volumes de dados de texto para prever a próxima palavra em uma sentença. Estes modelos são genéricos - não possuem conhecimento profundo em um determinado domínio ou tarefa.

Um modelo fine-tuned é construído a partir de um treinamento adicional em cima de um modelo base, para executar uma tarefa específica ou absorver conhecimento sobre um domínio. Os casos de uso geralmente envolvem datasets de classificação de texto, perguntas e respostas e tradução.

A ideia central do processo de fine tuning é aproveitar o conhecimento presente nos modelos base e suas capacidades de generalização. Como os modelos já sabem realizar múltiplas tarefas, o processo de especialização se torna mais fácil - com pequenos volumes de dados é possível obter resultados razoáveis.

Durante um fine-tuning, os pesos e parâmetros do modelo base são ajustados a partir do dataset de treino. Neste processo, as camadas iniciais do modelo, as quais capturam features mais genéricas, geralmente se mantém congeladas. Isso faz com que o modelo mantenha seu conhecimento anterior e se adapte as novas tasks.

Atualmente, o método mais comum para fazer o fine tuning de modelos é Parameter Efficient Fine-Tuning (PEFT).

Parameter Efficient Fine-Tuning

O PEFT é um método projetado para ajustar grandes modelos sem a necessidade de retreinar todos os seus parâmetros, que geralmente estão na ordem de grandeza de bilhões.

Nesta abordagem, não é necessário grandes volumes de dados e muitos recursos computacionais. O PEFT faz um congelamento dos parâmetros de treino do modelo base e adiciona novos parâmetros que serão treinados em um conjunto de dados nunca visto.

Neste tipo de abordagem, prevenimos situações como um esquecimento de todas as informações que o modelo absorveu durante seu treinamento anterior. Essa é uma ótima escolha quando estamos lidando com tarefas relacionadas a um domínio específico, como o caso do call center que mencionei no início.

O PEFT utiliza técnicas como LoRa e Q-Lora para fazer o fine tuning dos parâmetros. A seguir, uma breve explicação de ambas :)

LoRa

O Low Rank Adaption é um método em que adicionamos pequenos módulos de adaptação no modelo base e então treinamos somente os parâmetros destes módulos.

Na arquitetura de transformers, presentes nas LLMs, temos grandes módulos lineares, chamados de attention vectors e feed foward layers. Ambos, possuem um grande número de parâmetros e podemos escolher em qual camada adicionar os módulos LoRa que serão adaptados durante o fine tuning.

Os módulos lineares do modelo base são grandes matrizes e os adaptadores LoRa são matrizes pequenas capazes de receber a mesma entrada e produzir uma saída compatível com a arquitetura existente. Como você já deve esperar, a computação dos parâmetros destes adaptadores é muito mais rápida do que as dos módulos originais do modelo.

QLoRa

Quantized Low Rank Adaptation, QLoRa é uma extensão do LoRa que adiciona uma camada de quantização no processamento dos parâmetros. Basicamente, reduzimos a quantidade de bits disponíveis para a armazenar os números que representam os parâmetros.

Por exemplo, imagine que tenhamos um parâmetro com o valor 128.64 e gostaríamos de quantizá-lo para 8 bits (podendo representar apenas 8 dígitos de informação). Neste caso, os passos seriam os seguintes:

  1. Converter o número de ponto flutuante para binário: 128 em binário é 10000000 e 0.64 em binário é 0.101.
  2. Descartar os números que excedem os 8 dígitos: 128 em binário já consome todos os dígitos disponíveis, portanto, qualquer valor que vier depois dele será descartado. No nosso caso, 0.101 — que corresponde a 0.64.

Dessa forma, a versão quantizada de 128.64 em um sistema de 8 bits seria 128.

Com esse tipo de operação, o modelo torna-se mais compacto e as operações mais rápidas. Consequentemente, os resultados ficam mais imprecisos, mas a capacidade de generalização do modelo pode melhorar 🤔. É um caso típico em que a experimentação é necessária.

Em seus benchmarkings, o QLoRa mostrou ser capaz em reduzir de 780GB para 48GB a memória de GPU necessária para fazer o fine tuning de um modelo de linguagem de 65 bilhões de parâmetros. Neste caso, sem nenhuma perda mensurável de performance comparada com a versão com precisão completa dos parâmetros.

Como isso tudo funciona na prática?

Para aplicar todos estes conceitos, vamos realizar o fine tuning do Gemma 7B, uma LLM disponibilizada gratuitamente pelo Google. Ela será o base model citado anteriormente.

Nota: Você pode utilizar qualquer outro modelo como Llama, Mixtral e etc. A única modificação será no nome dos módulos em que você irá inserir os adaptadores LoRa.

Como base de dados, iremos utilizar tweets do Burger King Brasil 🍔. A conta deles tem um estilo próprio ao realizar publicações e responder clientes, o nosso objetivo será ajustar o Gemma para que ele responda a mensagens de usuários como se fosse o administrador da conta da empresa no X.

Exemplo de interação no X do Burger King Brasil

Para isso, extraí 468 interações da conta da empresa e usei o Gemini Pro para me ajudar a anonimizar os dados e definir quais fatos que geraram a interação.

Amostra dos dados sendo utilizados no treinamento

Para o treinamento, utilizei uma Tesla T4, que é disponibilizada gratuitamente no Google Colab. A seguir vou caminhar por cada etapa do processo de preparação dos dados, definição dos adaptadores com Lora, fine tuning, inferência e disponibilização do modelo no Hugging Face 🤗. No entanto, se você quiser pular direto para o notebook, clique aqui.

Configurando o ambiente

Vamos começar instalando e importando as bibliotecas necessárias e fazendo login no Hugging Face, que é de onde vamos baixar o Gemma 7B e posteriormente fazer o upload do nosso modelo treinado. Para isso, siga estas etapas para gerar seu próprio token.

Preparando os dados

Nesta etapa, vamos carregar os dados, fazer algumas transformações e converter para o formato aceito pelo Hugging Face.

Baixando e testando o modelo base

Vamos baixar o gemma-7b via hugging face. Para isso, é necessário que você acesse este link e aceite a licença do modelo.

Com a licença aceita no hugging face, vamos utilizar a biblioteca bitsandbites para carregar o modelo com quantização de 4-bits, o que significa metade da precisão original para as computações. Como mencionado anteriormente, esta modificação fará com que seja necessário menos recursos computacionais durante o fine tuning.

Com o modelo carregado, vamos fazer um teste com o mesmo prompt que será utilizado depois do fine tuning.

Definindo os parâmetros de treino e começando o fine tuning

A primeira célula do código abaixo realiza a configuração do adaptador LoRa. Para o nosso exemplo, vamos inserir adaptadores logo após todas as camadas lineares do Gemma, definidas pelo parâmetro taget_modules.

O valor de r está relacionado com a quantidade de parâmetros que serão adaptados durante o treinamento. O task_type indica pra qual tarefa o modelo está sendo adaptado. Neste exemplo, estaremos trabalhando com geração de texto, então escolhemos a opção de Causal Language Model.

Para saber mais sobre os parâmetros do LoRA, recomendo a leitura do paper do método.

Iremos utilizar o método de supervised fine-tuning (SFT) disponibilizado pelo Hugging Face para configurar o treinamento. Ele implementa o PEFT, que mencionamos anteriormente. Para saber mais sobre os parâmetros escolhidos, recomendo acessar esta documentação do hugging face.

A última célula do notebook é onde o treinamento é iniciado. Usando uma Tesla T4 no Colab, o execução durou aproximadamente três horas. Este tempo vai variar de acordo com os parâmetros escolhidos e o o volume dados sendo utilizado.

Os pesos treinados foram salvos na pasta gemma-tunned. Vamos pegar o último checkpoint disponível, fazer a junção dos adaptadores LoRa treinados com o modelo base (gemma-7b),e salvar na pasta gemma-7b-tuned-merged.

Pronto! Já temos o nosso próprio fine tuning do gemma-7b :)

Agora, vamos fazer um teste com o mesmo prompt que usamos com o modelo antes do fine-tuning para checar os resultados.

Claramente, o modelo desenvolveu a capacidade de receber um fato e gerar um tweet com o estilo de comunicação do Burger King 🍔 !

Para não deixar o post ̶a̶i̶n̶d̶a̶ ̶m̶a̶i̶s̶ longo, vamos seguir para a última etapa do tutorial: salvar o modelo e o tokenizador em um repositório no hugging face hub para facilitar a reutilização.

Por fim, vamos carregar o modelo diretamente do hugging face hub e executar um teste novamente para garantir que tudo está funcionando bem.

Tudo certo! Tivemos mais uma resposta satisfatória com o modelo que simula o comportamento do administrador do X do Burger King.

Espero que você tenha curtido este post e que ela tenha sido útil. Se gostou, não se esqueça de adicionar algumas 👏 aqui no medium. Para qualquer dúvida/sugestão, adicione um comentário aqui, ou me chame no Likedin :)

--

--

Hugo Zanini
Data Hackers

GDE in Machine Learning| Electrical Engineer | Technical Product Manager