Faça o ajuste de um modelo Granite em Python com o watsonx

Autora

Anna Gutowska

AI Engineer, Developer Advocate

IBM

O que é ajuste de prompts?

Neste tutorial, ajustaremos os prompts de um modelo IBM Granite usando um conjunto de dados sintético contendo avaliações de clientes de uma empresa de cuidados com animais de estimação.

O ajuste de prompts é uma maneira eficiente e de baixo custo de adaptar um modelo de base de inteligência artificial (IA) a novas tarefas posteriores sem treinar novamente todo o modelo e atualizar seus pesos.

Visão geral da otimização do LLM

Os modelos de base são baseados em grandes modelos de linguagem (LLMs) e recebem grandes quantidades de dados de treinamento. Casos de uso comuns de modelos de base são chatbots e assistentes virtuais.

Há várias maneiras de melhorar a interpretação das entradas e a qualidade das respostas de um modelo de base. Para entender melhor essas nuances, vamos comparar alguns dos métodos.

  • Engenharia de prompts é a otimização das respostas de um modelo pré-treinado, fornecendo um prompt bem projetado. Nenhum dado novo é introduzido usando essa técnica, e o modelo permanece como está. Usando esse método, o modelo recebe um prompt de entrada e um prompt projetado na frente dele. Por exemplo, você pode usar o prompt: "Traduzir inglês para espanhol," com a entrada: "bom dia." Esse método exige mais trabalho do usuário. No entanto, esse esforço humano manual para formular prompts eficazes ajuda os modelos de IA generativa a produzir respostas específicas à tarefa sem treinar novamente todo o modelo de base.
  • O ajuste fino de grandes modelos de linguagem envolve ajustar o mesmo modelo fornecendo um grande número de conjuntos de dados rotulados. O ajuste fino altera os pesos do modelo e se torna difícil de gerenciar à medida que as tarefas se diversificam. Isso exige uma quantidade significativa de recursos computacionais. Por sua vez, esse método tende a ter a melhor precisão, pois o modelo pode ser treinado para casos de uso muito específicos.
  • Diferentemente do ajuste fino, o ajuste de prompts não altera os pesos do modelo pré-treinado. Em vez disso, essa técnica é eficiente em termos de parâmetros, ajustando parâmetros de prompts para orientar as respostas do modelo na direção preferida. O modelo é fornecido com uma entrada e prompts ajustáveis gerados pela própria IA. Esse contexto específico da tarefa orienta o modelo maciço para adaptar suas respostas a uma tarefa restrita, mesmo com dados limitados.
  • De forma semelhante ao ajuste de prompts, o ajuste de prefixosenvolve o modelo recebendo vários exemplos de saídas preferenciais. A diferença aqui é que um prefixo, uma série de vetores específicos da tarefa, também está incluído. O ajuste de prefixos envolve prompts flexíveis e prompts injetados em camadas do modelo de deep learning. Esses chamados "tokens" permitem que o modelo ajustado tenha flexibilidade para ser compatível com uma variedade de novas tarefas de uma só vez. Esse método alcança desempenho semelhante ao do ajuste fino de todas as camadas e treina apenas cerca de 0,1% dos parâmetros. O ajuste de prefixos supera até mesmo o ajuste fino em configurações de poucos dados.

Prompts flexíveis versus prompts rígidos

Os prompts rígidos são voltadas para o usuário e exigem ação do usuário. Um prompt rígido pode ser considerado como um modelo ou instruções para o LLM gerar respostas. Um exemplo de prompt rígido será apresentado a seguir. Incentivamos você a consultar a página de documentação da IBM para obter mais informações sobre esse tipo de prompt e vários outros.

###For demonstration purposes only. It is not necessary to run this code block.
hard_prompt_template = """Generate a summary of the context that answers the question. Explain the answer in multiple steps if possible.
Answer style should match the context. Ideal Answer length is 2-3 sentences.\n\n{context}\nQuestion: {question}\nAnswer:
"""

Usando este modelo de prompt rígido, um LLM pode receber instruções específicas sobre a estrutura e o estilo de saída preferidos. Por meio desse prompt explícito, seria mais provável que o LLM produzisse respostas desejáveis de maior qualidade.

Os prompts flexíveis, ao contrário dos prompts rígidos, não são escritos em linguagem natural. Em vez disso, os prompts são inicializados como vetores numéricos gerados por IA anexados ao início da embedding de cada entrada que destila o conhecimento do modelo maior. Essa falta de interpretabilidade se estende à IA que escolhe prompts otimizados para uma determinada tarefa. Muitas vezes, a IA é incapaz de explicar por que escolheu essas embeddings. Em comparação com outros métodos de prompts, esses tokens são menos caros em termos de computação do que o ajuste fino, pois o próprio modelo permanece congelado com pesos fixos. Os prompts flexíveis também tendem a superar os prompts rígidos projetados por seres humanos.

Trabalharemos com prompts flexíveis para ajuste de prompts neste tutorial.

Pré-requisitos

Você precisa de uma conta do IBM® Cloud para criar um projeto do watsonx.ai .

Etapas

Etapa 1. Configure seu ambiente

Embora você possa escolher entre várias ferramentas, este tutorial explica como configurar uma conta da IBM para usar um Jupyter Notebook.

  1. Faça login no  watsonx.ai  usando sua conta do IBM Cloud.

  2. Criar um projeto do watsonx.ai.

    Você pode obter a ID do projeto a partir de seu projeto. Clique na guia Gerenciar . Em seguida, copie a ID do projeto da seção Detalhes da página Geral . Você precisa dessa ID para este tutorial.

  3. Crie um Jupyter Notebook.

    Esta etapa abrirá um ambiente do Notebook onde você pode copiar o código deste tutorial para implementar o ajuste de prompts por conta própria. Ou então, você pode baixar esse Notebook em seu sistema local e carregá-lo como um ativo em seu projeto do watsonx.ai. Esse Jupyter Notebook , juntamente com os conjuntos de dados utilizados, pode ser encontrado no GitHub.

Etapa 2. Configure uma instância do watsonx.ai Runtime e uma chave de API

  1. Crie uma instância do serviço do watsonx.ai Runtime (tempo de execução) (selecione a região apropriada e escolha o plano Lite, que é uma instância gratuita).

  2. Gere uma chave de API.

  3. Associe a instância do serviço do watsonx.ai Runtime ao projeto que você criou no watsonx.ai.

Etapa 3. Instale e importe bibliotecas relevantes e configure suas credenciais

Precisaremos de algumas bibliotecas e módulos para este tutorial. Não deixe de importar os seguintes itens; se eles não estiverem instalados, você poderá resolver isso com uma instalação rápida.

#installations
%pip install ibm-watsonx-ai | tail -n 1
%pip install pandas | tail -n 1
%pip install wget | tail -n 1
%pip install scikit-learn | tail -n 1
%pip install matplotlib | tail -n 1 #imports
import wget
import pandas as pd

from ibm_watsonx_ai import APIClient
from ibm_watsonx_ai.foundation_models.utils.enums import ModelTypes
from ibm_watsonx_ai.experiment import TuneExperiment
from ibm_watsonx_ai.helpers import DataConnection
from ibm_watsonx_ai.foundation_models import ModelInference
from sklearn.metrics import accuracy_score, f1_score
from datetime import datetime

Configure suas credenciais. Insira a chave de API e o ID do projeto.

credentials = {
    "url": "https://us-south.ml.cloud.ibm.com",
    "apikey": "YOUR_API_KEY_HERE"
}

project_id = "YOUR_PROJECT_ID_HERE"

Etapa 4. Estabelecer o ambiente e importe o conjunto de dados

Como primeira etapa para estabelecer o ambiente, crie uma instância do APIClient com seus detalhes de autenticação e defina seu project_id .

client = APIClient(credentials)
client.set.default_project(project_id)

Saída

'SUCCESS'

Para este tutorial, usaremos um conjunto de dados sintético que consiste em avaliações de empresas de cuidados com os animais. Usando a URL apropriada, podemos conectar o conjunto de dados ao cliente da API.

Você é livre para usar qualquer conjunto de dados de sua escolha. Vários conjuntos de dados de código aberto estão disponíveis em plataformas, como a HuggingFace.

train_filename = 'dog_grooming_reviews_train_data.json'

url = "https://raw.githubusercontent.com/AnnaGutowska/think/main/tutorials/prompt-tuning-tutorial/" + train_filename
wget.download(url)

asset_details = client.data_assets.create(name=train_filename, file_path=train_filename)
asset_id = client.data_assets.get_id(asset_details)

Saídas:

Criando ativo de dados...

SUCCESS

print(asset_id)

Saída

3b1db894-8d9e-428d-8fee-d96f328c7726

Para obter alguns insights sobre a formatação dessas avaliações de clientes, vamos carregar os dados em um dataframe do Pandas e imprimir algumas linhas que mostram avaliações positivas e negativas. Uma saída de "1" denota avaliações positivas, e "0" é usado para avaliações negativas.

pd.set_option('display.max_colwidth', None)
df = pd.read_json(train_filename)
df[5:10]

Saídas:

captura de tela de um conjunto de dados de treinamento com exemplos de comentários e valores associados 1 e 0, sendo 1 um comentário positivo e 0 um negativo Conjunto de dados de treinamento

Etapa 5. Ajuste o modelo.

A classe TuneExperiment é usada para criar experimentos e agendar ajustes. Vamos usá-la para inicializar nosso experimento e definir nosso modelo de base, dados de treinamento e parâmetros. O objetivo deste prompt é que o LLM adapte suas respostas de acordo com os índices de satisfação do cliente extraídos do nosso conjunto de dados. Esta é uma tarefa de classificação, pois as avaliações podem ser classificadas como positivas ("1") ou negativas ("0").

Para este tutorial, sugerimos o uso de um modelo IBM Granite como o grande modelo de linguagem para obter resultados semelhantes.

experiment = TuneExperiment(credentials,
    project_id=project_id
)

prompt_tuner = experiment.prompt_tuner(name="prompt tuning tutorial",
    task_id=experiment.Tasks.CLASSIFICATION,
    base_model="ibm/granite-3-8b-instruct",
    accumulate_steps=16,
    batch_size=8,
    learning_rate=0.001,
    max_input_tokens=128,
    max_output_tokens=2,
    num_epochs=12,
    tuning_type=experiment.PromptTuningTypes.PT,
    init_text="Extract the satisfaction from the comment. Return simple '1' for satisfied customer or '0' for unsatisfied. Comment:",
    init_method="text",
    verbalizer="classify {0, 1} {{input}}",
    auto_update_model=True
)

Agora que temos nosso experimento de ajuste configurado, precisamos vinculá-lo ao nosso conjunto de dados. Para isso, vamos usar a classe DataConnection. Isso requer o asset_id que produzimos anteriormente ao iniciar o ativo de dados com nosso cliente de API.

data_conn = DataConnection(data_asset_id=asset_id)

Você é livre para usar qualquer modelo de IA de sua escolha. Os modelos de base disponíveis para ajuste no watsonx podem ser encontrados aqui ou executando o comando a seguir.

client.foundation_models.PromptTunableModels.show()

Saídas:

{'FLAN_T5_XL': 'google/flan-t5-xl', 'GRANITE_13B_INSTRUCT_V2': 'ibm/granite-13b-instruct-v2', 'LLAMA_2_13B_CHAT': 'meta-llama/llama-2-13b-chat'}

tuning_details = prompt_tuner.run(
    training_data_references=[data_conn],
    background_mode=False)

Saídas:

##############################################

Running '20671f17-ff53-470b-9bfe-04318ecb91d9'

##############################################


pending......
running....................................................................................................................................
completed
Training of '20671f17-ff53-470b-9bfe-04318ecb91d9' finished successfully.

Etapa 6. Avalie os resultados do ajuste.

Para garantir que nosso ajuste de prompts tenha sido concluído, podemos verificar o status. Se o status impresso for diferente de "completed", aguarde o ajuste terminar antes de continuar.

status = prompt_tuner.get_run_status()
print(status)

Saída

finalizado

Agora podemos recuperar o resumo do ajuste de prompts. Neste resumo, você verá um valor de perda. Para cada execução de treinamento, a função de perda mede a diferença entre os resultados previstos e reais. Portanto, é preferível um valor de perda menor.

prompt_tuner.summary()

Também podemos plotar a curva de aprendizado do nosso ajuste de modelo usando a função plot_learning_curve() . Uma curva inclinada descendente que se nivela perto de zero indica que o modelo está melhorando a geração da saída esperada. Para saber mais sobre como interpretar gráficos de função de perda, consulte a documentação relevante do IBM watsonx.

prompt_tuner.plot_learning_curve()

Saídas:

Gráficos de curvas de aprendizado Gráficos de curvas de aprendizado

Etapa 7. Implemente o modelo ajustado.

Esta etapa da implementação do modelo ajustado é crítica para concluir a próxima etapa de comparação do desempenho do modelo ajustado com o modelo pré-ajustado.

Observação: o SERVING_NAME é definido com a data e hora atuais, pois deve ser um valor único.

model_id = prompt_tuner.get_model_id()

meta_props = {
    client.deployments.ConfigurationMetaNames.NAME: "PROMP TUNE DEPLOYMENT",
    client.deployments.ConfigurationMetaNames.ONLINE: {},
    client.deployments.ConfigurationMetaNames.SERVING_NAME : datetime.now().strftime('%Y_%m_%d_%H%M%S')
}

deployment_details = client.deployments.create(model_id, meta_props)

Saída

######################################## ##################################

Criação de implementação síncrona para id: '6aa5dd5c-0cc4-44e0-9730 -18303e88e14a'started

################################# ######################################


inicializando......... ..—pronto———————— --——————————— ————— Criação
da


implementação concluída com sucesso, deployment_id='24a97b84-47d0-4490-9f5f-21ed2376fdd6'
————— --——————————— -————

Etapa 8. Teste o modelo ajustado.

Agora, vamos testar o desempenho do modelo ajustado e do modelo de base original para ver os impactos do nosso processo de ajuste. Primeiro, vamos carregar o conjunto de dados de teste. Esse conjunto de dados deve ser um subconjunto de dados que não estava presente durante o ajuste. Frequentemente, o conjunto de teste também é menor que o conjunto de treinamento. Além disso, cada entrada no conjunto de dados de teste tem o prompt como prefixo do comentário do usuário.

test_filename = 'dog_grooming_reviews_test_data.json'
url = "https://raw.githubusercontent.com/AnnaGutowska/think/main/tutorials/prompt-tuning-tutorial/" + test_filename
wget.download(url)
data = pd.read_json(test_filename)

Vamos exibir uma pequena parte do conjunto de dados para entender melhor sua estrutura.

data.head()

Saídas:

captura de tela de um conjunto de dados de treinamento com exemplos de comentários e valores associados 1 e 0, sendo 1 um comentário positivo e 0 um negativo Conjunto de dados de teste

Ao carregar o conjunto de dados de teste, vamos extrair as entradas e saídas.

prompts = list(data.input)
satisfaction = list(data.output)
prompts_batch = ["\n".join([prompt]) for prompt in prompts]

Também podemos imprimir um exemplo de entrada e saída de teste para entender melhor como extraímos o conteúdo do conjunto de dados.

prompts[0]

Saídas:

"Extraia a satisfação do comentário. Retorne simplesmente 1 para cliente satisfeito ou 0 para insatisfeito.\nComment: Tempos de espera longos.\nSatisfaction:\n"

Neste exemplo, o prompt é introduzido, seguido pela avaliação do cliente sobre os longos tempos de espera e, por fim, a satisfação é 0 para indicar uma avaliação negativa.

satisfaction[0]

Saída

0

Agora que temos o conjunto de dados de teste, vamos testar a precisão e a pontuação F1 do nosso modelo ajustado. A pontuação F1 é a média da precisão e do recall do modelo. Precisaremos do deployment_id para fazer isso. Observe que o concurrency_limit é definido como 2 para evitar atingir o limite de taxa da API. Este é o número de solicitações que serão enviadas em paralelo.

deployment_id = deployment_details['metadata']['id']

tuned_model = ModelInference(
    deployment_id=deployment_id,
    api_client=client
)

tuned_model_results = tuned_model.generate_text(prompt=prompts_batch, concurrency_limit=2)
print(f'accuracy_score: {accuracy_score(satisfaction, [int(float(x)) for x in tuned_model_results])}, f1_score: {f1_score(satisfaction, [int(float(x)) for x in tuned_model_results])}')

Saídas:

accuracy_score: 0.9827586206896551, f1_score: 0.9827586206896551

Dada a alta precisão e a pontuação F1 do nosso modelo, vamos testar o desempenho do mesmo modelo Granite sem nenhum ajuste.

base_model = ModelInference(
    model_id="ibm/granite-3-8b-instruct",
    api_client=client
)

base_model_results = base_model.generate_text(prompt=prompts_batch, concurrency_limit=2)

print(f'base model accuracy_score: {accuracy_score(satisfaction, [int(x) for x in base_model_results])}, base model f1_score: {f1_score(satisfaction, [int(x) for x in base_model_results])}')

Saídas:

base model accuracy_score: 0.9310344827586207, base model f1_score: 0.9298245614035088

Nosso modelo ajustado supera o desempenho do modelo de base pré-ajustado. Como o modelo ajustado é especializado na extração de pontuações de satisfação, ele pode ser usado para outras tarefas de extração de satisfação. Ótimo trabalho!

Resumo

Neste tutorial, você realizou o ajuste de prompts em um modelo do IBM Granite com a API do watsonx. Seu modelo ajustado e implementado superou com sucesso o modelo de base com precisão cerca de 5% maior.

Soluções relacionadas
IBM® watsonx.ai

Treine, valide, ajuste e implemente recursos de IA generativa, modelos de base e recursos de aprendizado de máquina com o IBM watsonx.ai, um estúdio empresarial de última geração para construtores de IA. Crie aplicações de IA em menos tempo com menos dados.

Explore o watsonx.ai
Soluções de inteligência artificial

Coloque a IA em ação na sua empresa com a experiência em IA líder do setor e com o portfólio de soluções da IBM.

Explore as soluções de IA
Consultoria e serviços em inteligência artificial (IA)

Os serviços de IA da IBM Consulting ajudam a reinventar a forma como as empresas trabalham com IA para gerar transformação.

Explore os serviços de IA
Dê o próximo passo

Ao utilizar a IA, o IBM Concert revela insights cruciais sobre suas operações e fornece recomendações específicas para cada aplicação com foco em melhorias. Descubra como o Concert pode impulsionar sua empresa.

Explorar Concert Explore as soluções de automação de processos de negócios