Il Low-Rank Adaptation (LoRA) è un metodo efficiente di messa a punto che riduce il numero di parametri addestrabili che aumenta la velocità e l'utilizzo delle risorse della formazione mantenendo la stessa qualità degli output. Invece di aggiornare tutti i parametri in una [rete neurale] (https://www.ibm.com/it-it/think/topics/neural-networks) durante la messa a punto, LoRa blocca i pesi pre-addestrati originali e aggiunge matrici low-rank piccole e addestrabili che approssimano le modifiche necessarie per la nuova attività. Questo approccio si basa sull'ipotesi che gli aggiornamenti di peso durante l'adattamento abbiano un "rango intrinseco basso".
Un vantaggio aggiuntivo di LoRa è che, poiché i pesi pre-addestrati vengono mantenuti congelati, l'adattatore generato è leggero e portatile e può essere facilmente memorizzato.
In questo tutorial utilizzerai LLaMa Factory. LLaMa Factory è una piattaforma di formazione e ottimizzazione low e no-code di modelli linguistici di grandi dimensioni (LLM) che consente agli utenti di adattare gli LLM su set di dati personalizzati, valutare le prestazioni e fornire modelli. Ha un'interfaccia utente web e una CLI facili da usare e supporta oltre 100 LLM. La piattaforma supporta set di dati nei formati Alpaca e ShareGPT. LLaMa Factory non è l'unico modo per mettere a punto gli LLM: il PEFT la libreria per la messa a punto efficiente dei parametri è un'altra opzione per l'aggiornamento dei modelli di grandi dimensioni. PEFT offre la possibilità di eseguire LoRA quantizzato (QLoRA) per compattare ulteriormente il modello messo a punto. In questo tutorial, utilizzeremo una versione non quantizzata di Granite 3.3.
Sebbene LLama Factory possa funzionare senza l'uso di ampie risorse di calcolo, richiede una GPU e notevoli risorse di memoria. In questo tutorial, utilizzerai LLaMa Factory su watsonx per fornire risorse GPU e storage per l'adattatore generato.
Configurazione di Watson Studio
a. Accedi a watsonx.ai utilizzando il tuo account IBM® Cloud.
b. Crea un progetto watsonx.ai. Prendi nota dell’ID progetto nel progetto > Gestisci > Generali > ID progetto.
Questo ID sarà necessario per questo tutorial.
c. Crea un’istanza di watsonx.ai Runtime Per questo tutorial, dovrai creare un’istanza a pagamento per accedere a una GPU.
d. Genera un’application programming interface watsonx (chiave API).
e. Associa il servizio watsonx.ai Runtime al progetto creato in watsonx.ai.
Cloud Object Storage
a. Per creare Cloud Object Storage per il tuo notebook, vai su https://cloud.ibm.com/ e seleziona “Crea istanza”.
b. Verrai indirizzato a una finestra di dialogo di creazione in cui potrai selezionare un listino prezzi. Per questo tutorial, basterà un piano standard.
c. Assegna un nome all’istanza di Cloud Object Storage.
d. Dopo aver creato la sua istanza, torna al Progetto e seleziona “ Nuovo asset “, quindi seleziona “Connetti a una fonte di dati”.
e. Seleziona "Cloud Object Storage"
f. Nella finestra di dialogo successiva, seleziona l'istanza creata nei passaggi a–d in base al nome.
g. Seleziona "Crea".
Crea un Jupyter Notebook.
a. Seleziona la scheda Asset nell'ambiente del progetto.
b. Fai clic su Nuova risorsa.
c. Seleziona l'opzione Lavorare con i modelli nel pannello di sinistra.
d. Fai clic su Lavorare con dati e modelli utilizzando notebook Python e R.
e. Inserisci un nome per il tuo notebook nel campo Nome. Selezionare tempo di esecuzione 23.1 su Python (4 vCPU 16 GB RAM) per definire la configurazione.
f. Seleziona Crea.
Successivamente, installerai le dipendenze sul tempo di esecuzione. Prima, llama-factory per generare gli adattatori di basso rango, poi Pandas per formattare il set di dati in formato Alpaca.
!pip install -q llamafactory 2>/dev/null
# pandas needed to format the dataset
!pip install -q --upgrade pandas 2>/dev/null
A seguire, dovrai assicurarti che il tuo ambiente watsonx abbia fornito una GPU compatibile con Torch che sarà necessaria per utilizzare LLaMa-Factory.
import torch
try:
assert torch.cuda.is_available() is True
except AssertionError:
print("No GPU found, please set up a GPU before using LLaMA Factory.")
Se lo snippet di codice precedente non stampa "Nessuna GPU trovata", allora sei a posto.
A seguire, importa librerie per manipolare i dati e per creare il file di configurazione LLaMa Factory usato per l'addestramento.
# Import libraries
import pandas as pd
import json
import yaml
In questo tutorial, userai una parte del set di dati MedReason. MedReason è un set di dati di ragionamento medico di alta qualità e su larga scala, progettato per consentire una risoluzione spiegabile dei problemi medici negli LLM. Mentre MedReason si concentra sul ragionamento di un modello e sulla validazione delle catene di pensiero che un modello utilizza, in questo caso è anche utile fornire un set di dati troppo recente per essere incluso nei dati di addestramento di IBM® Granite 3.3.
Granite 3.3 è stato progettato per imparare attraverso la messa a punto, che verrà eseguita con LLaMa Factory. I modelli Granite possono essere ottimizzati in modo efficiente anche con risorse di calcolo limitate.
Carica una selezione del set di dati MedReason da GitHub:
from datasets import load_dataset
training = pd.read_json("https://raw.githubusercontent.com/UCSC-VLAA/MedReason/refs/heads/main/eval_data/medbullets_op4.jsonl", lines=True)
LLaMa Factory richiede che il set di dati sia preformattato in formati Alpaca o ShareGPT. Pertanto, riformattiamo i campi di domande e risposte del set di dati legale originale per contenere i campi di istruzione, input e output secondo il formato Alpaca.
Alpaca è un formato JSON per rappresentare un'istruzione, un input dell'utente e un output di sistema in questo modo:
{
"instruction": "user instruction (required)",
"input": "user input (optional)",
"output": "model response (required)",
"system": "system prompt (optional)",
}
Poiché MedReason non è formattato in Alpaca, crea un set di dati Alpaca nella cella successiva:
!mkdir -p data
# Format Med Dataset to Alpaca Format
formatted_data = [
{
"instruction": row["question"] + str(row["options"]),
"input": "",
"output": row["answer"]
}
for _, row in training.iterrows()
]
# output formatted MedReason dataset
with open("data/med.json", "w", encoding="utf-8") as f:
json.dump(formatted_data, f, indent=2, ensure_ascii=False)
Llama Factory usa un file specifico per capire come caricare set di dati per l'addestramento. Questo file deve esistere nel percorso data/dataset_info.json. Quindi, dobbiamo creare un file data/dataset_info.json che include il percorso al nuovo set di dati medici formattato che abbiamo creato affinché la CLI di Llama Factory possa accedere al set di dati. Per i dettagli sul file dataset_info.json vedi la documentazione. All'interno del repository Llama Factory ci sono set di dati disponibili, tuttavia, poiché stiamo usando un nostro set di dati personalizzato, dobbiamo aggiungere il nostro set di dati al file JSON.
# "med" will be the identifier for the dataset
# which points to the local file that contains the dataset
dataset_info = {
"med": {
"file_name": "med.json",
}
}
# Create dataset_info.json with legal dataset so can reference with llama factory
with open("data/dataset_info.json", "w", encoding="utf-8") as f:
json.dump(dataset_info, f, indent=2, ensure_ascii=False)
Ora che l'oggetto JSON formattato Alpaca è stato salvato nell'ambiente, sei pronto per iniziare l'addestramento.
Il prossimo passo è impostare le configurazioni di formazione e poi scrivere le configurazioni in un file YAML che LLaMa-Factory utilizzerà per eseguire l'addestramento.
Ora esegui la messa a punto supervisionata (SFT) sul sottoinsieme del set di dati MedReason. LLaMa Factory supporta diversi tipi di addestramento. Alcuni dei più comunemente usati sono:
Pre-addestramento: quando un modello viene sottoposto a un addestramento iniziale utilizzando un set di dati ampio per generare risposte al linguaggio e alle idee fondamentali.
Ottimizzazione supervisionata (SFT): quando un modello riceve una formazione aggiuntiva con dati annotati per migliorare la precisione per una particolare funzione o su un argomento specifico.
Modellazione delle ricompense: laddove il modello acquisisce conoscenze su come ottenere uno specifico incentivo o ricompensa che influirà sull'ottimizzazione della politica prossimale (PPO) del suo output.
Addestramento: una tecnica di rapprendimento per rinforzo (RL) in cui il modello viene ulteriormente affinato attraverso tecniche di gradiente politico per aumentarne l'efficacia in un contesto specifico.
Esistono numerose impostazioni utilizzate per configurare LoRA, ma alcune delle più importanti e comunemente utilizzate sono:
Tasso di apprendimento (LR): il tasso di apprendimento determina la significatività con cui ciascun parametro del modello viene aggiornato durante ogni iterazione di addestramento. Un LR più alto può accelerare la convergenza consentendo aggiornamenti più grandi, ma rischia di superare la soluzione ottimale o di oscillare intorno ad essa. Un LR più basso porta a una convergenza più lenta ma più stabile, riducendo il rischio di instabilità vicino alla soluzione ottimale.
loraplus_lr_ratio: questo passaggio imposta il rapporto tra i tassi di apprendimento. In genere, dovrebbe essere > 1, ma la scelta ottimale di loraplus_lr_ratio dipende dal modello e dall'attività. Come linea guida, loraplus_lr_ratio dovrebbe essere più grande quando l'attività è più difficile e il modello deve aggiornare le sue caratteristiche per imparare bene. In questo caso, aiuta a ridurre leggermente il tasso di apprendimento (ad esempio, di un fattore 2) rispetto ai tipici tassi di apprendimento LoRa.
**Dimensione effettiva del batch **: configurare correttamente la dimensione del batch è fondamentale per bilanciare la stabilità dell'allenamento con le limitazioni della VRAM della GPU che sta utilizzando. La dimensione effettiva del batch è impostata dal prodotto di per_device_train_batch_size * gradient_accumulation_steps. In genere, maggiore è la dimensione effettiva del batch, più fluido e stabile è l'addestramento, ma potrebbe anche richiedere più VRAM di quella contenuta nella GPU. Una dimensione effettiva del batch più piccola può introdurre una maggiore varianza.
Ecco il codice che configura l'addestramento:
# setup training configurations
args = dict(
stage="sft", # do supervised fine-tuning
do_train=True, # we're actually training
model_name_or_path="ibm-granite/granite-3.3-2b-instruct", # use IBM Granite 3.3 2b instruct model
dataset="med", # use medical datasets we created
template="granite3", # use granite3 prompt template
finetuning_type="lora", # use LoRA adapters to save memory
lora_target="all", # attach LoRA adapters to all linear layers
loraplus_lr_ratio=16.0, # use LoRA+ algorithm with lambda=16.0
output_dir="granite3_lora", # the path to save LoRA adapters
per_device_train_batch_size=4, # the batch size
gradient_accumulation_steps=2, # the gradient accumulation steps
learning_rate=1e-4, # the learning rate
num_train_epochs=3.0, # the epochs of training
max_samples=500, # use 500 examples in each dataset
fp16=True, # use float16 mixed precision training
report_to="none", # disable wandb logging
)
# create training config file to run with llama factory
with open("train_granite3_lora_med.yaml", "w", encoding="utf-8") as file:
yaml.dump(args, file, indent=2)
La cella successiva addestrerà il modello e può impiegare fino a 10 minuti per essere eseguita:
!llamafactory-cli train train_granite3_lora_med.yaml;
A seguire, crea due metodi per caricare e scaricare dati da IBM Cloud Object Storage:
from ibm_botocore.client import Config
import ibm_boto3
def upload_file_cos(credentials, local_file_name, key):
cos = ibm_boto3.client(service_name='s3',
ibm_api_key_id=credentials['IBM_API_KEY_ID'],
ibm_service_instance_id=credentials['IAM_SERVICE_ID'],
ibm_auth_endpoint=credentials['IBM_AUTH_ENDPOINT'],
config=Config(signature_version='oauth'),
endpoint_url=credentials['ENDPOINT'])
try:
res=cos.upload_file(Filename=local_file_name, Bucket=credentials['BUCKET'],Key=key)
except Exception as e:
print(Exception, e)
else:
print(' File Uploaded')
def download_file_cos(credentials,local_file_name,key):
cos = ibm_boto3.client(service_name='s3',
ibm_api_key_id=credentials['IBM_API_KEY_ID'],
ibm_service_instance_id=credentials['IAM_SERVICE_ID'],
ibm_auth_endpoint=credentials['IBM_AUTH_ENDPOINT'],
config=Config(signature_version='oauth'),
endpoint_url=credentials['ENDPOINT'])
try:
res=cos.download_file(Bucket=credentials['BUCKET'],Key=key,Filename=local_file_name)
except Exception as e:
print(Exception, e)
else:
print('File Downloaded')
La cella successiva contiene le credenziali di Cloud Object Storage.
Nel tuo notebook, clicca sulla scheda Snippet di codice nell'angolo destro. Questo passaggio apre un menu con diverse opzioni per i frammenti di codice generati. Seleziona "Leggi dati":
Questo passaggio apre un menu per selezionare un file di dati. Se non hai caricato nulla sulla tua istanza di Cloud Object Storage, dovrai caricare qualcosa per generare le credenziali. Può essere un set di dati classico come wine.csv.
Dopo aver fatto clic su "Seleziona", puoi generare lo snippet delle credenziali con l'opzione "Carica come". Scegli "Inserisci codice nella cella":
Questo passaggio genera una cella simile alla seguente con credenziali contenenti gli ID corretti e gli endpoint generati:
# @hidden_cell
# The following code contains metadata for a file in your project storage.
# You might want to remove secret properties before you share your notebook.
storage_metadata = {
'IAM_SERVICE_ID': '',
'IBM_API_KEY_ID': '',
'ENDPOINT': '',
'IBM_AUTH_ENDPOINT': '',
'BUCKET': '',
'FILE': ''
}
Ora la cartella zip contenente l'adattatore e le informazioni sull'adattatore stesso:
!zip -r "granite3_lora.zip" "granite3_lora"
Controlla di aver creato correttamente lo zip:
!ls
Ora è il momento di eseguire l'inferenza. L'inferenza sarà supportata dalla generazione di HuggingFace, che fornisce un metodo model.generate() per la generazione di testo utilizzando PyTorch.
Questo tutorial mostra porre al modello base una domanda medica tratta dal set di dati MedReason. È ragionevole pensare che il modello base non sia in grado di rispondere a questa domanda perché è un modello a uso generale addestrato su grandi e diversificati set di dati.
Per prima cosa, imposta le configurazioni di inferenza:
# setup inference configurations
args = dict(
model_name_or_path="ibm-granite/granite-3.3-2b-instruct", # use IBM Granite 3.3 2b instruct model
template="granite3", # set to the same one used in training, template for constructing prompts
infer_backend="huggingface" # choices: [huggingface, vllm]
)
# create inference config file to run with llama factory
with open("inference_config.yaml", "w", encoding="utf-8") as file:
yaml.dump(args, file, indent=2)
Ora poni al chatbot una delle domande del set di dati MedReason:
from llamafactory.chat import ChatModel
chat_model = ChatModel(args)
messages = []
# run inference chatbot
question = '''
A 1-year-old girl is brought to a neurologist due to increasing seizure frequency over the past 2 months.
She recently underwent a neurology evaluation which revealed hypsarrhythmia on electroencephalography (EEG) with a mix of slow waves, multifocal spikes, and asynchrony.
Her parents have noticed the patient occasionally stiffens and spreads her arms at home. She was born at 38-weeks gestational age without complications.
She has no other medical problems. Her medications consist of lamotrigine and valproic acid. Her temperature is 98.3\u00b0F (36.8\u00b0C), blood pressure is 90/75 mmHg, pulse is 94/min, and respirations are 22/min.
Physical exam reveals innumerable hypopigmented macules on the skin and an irregularly shaped, thickened, and elevated plaque on the lower back.
Which of the following is most strongly associated with this patient's condition?"
"A": "Cardiac rhabdomyoma", "B": "Glaucoma", "C": "Optic glioma", "D": "Polyostotic fibrous dysplasia"
'''
Crea un nuovo messaggio usando la domanda e passalo al modello base:
messages.append({"role": "user", "content": question})
response = ""
for new_text in chat_model.stream_chat(messages):
response += new_text
print(response)
messages.append({"role": "assistant", "content": response})
Ecco l'output campione del modello base Granite 3.3
Utente:
A 1-year-old girl is brought to a neurologist due to increasing seizure frequency over the past 2 months.
She recently underwent a neurology evaluation which revealed hypsarrhythmia on electroencephalography (EEG) with a mix of slow waves, multifocal spikes, and asynchrony.
Her parents have noticed the patient occasionally stiffens and spreads her arms at home. She was born at 38-weeks gestational age without complications.
She has no other medical problems. Her medications consist of lamotrigine and valproic acid. Her temperature is 98.3\F (36.8\C), blood pressure is 90/75 mmHg, pulse is 94/min, and respirations are 22/min.
Physical exam reveals innumerable hypopigmented macules on the skin and an irregularly shaped, thickened, and elevated plaque on the lower back.
Which of the following is most strongly associated with this patient's condition?"
"A": "Cardiac rhabdomyoma", "B": "Glaucoma", "C": "Optic glioma", "D": "Polyostotic fibrous dysplasia"
Risposta:
The most strongly associated condition with this patient's condition is "C": "Optic glioma".
The patient's symptoms of hypsarrhythmia on EEG, seizure frequency increase, and the presence of hypopigmented macules and a thickened plaque on the lower back are indicative of a neurological disorder. Optic glioma is a type of brain tumor that can present with these symptoms, including seizures and visual disturbances.
Option A, "Cardiac rhabdomyoma", typically presents with cardiac involvement and is not associated with the described EEG findings or skin manifestations.
Option B, "Glaucoma", is an eye disease that can lead to vision loss but is not associated with the EEG findings or skin lesions described.
Option D, "Polyostotic fibrous dysplasia", is a bone disorder characterized by multiple bone lesions and is not associated with the neurological symptoms and EEG findings presented.
Therefore, based on the clinical presentation, the most likely diagnosis is an optic glioma.
La risposta corretta dal set di dati è:
answer: Cardiac rhabdomyoma
Quindi il modello base non ha generato la risposta corretta.
Confrontiamo i risultati con il modello di base e l'adattatore ottimizzato LoRA. Poi poniamo la stessa domanda per vedere come la sintonizzazione con il set di dati legali ha permesso al modello di comprendere meglio e rispondere alle domande mediche.
La seguente cella non sarà necessaria se hai eseguito LoRA nella stessa sessione. Tuttavia, se stai tornando al Jupyter Notebook e non vuoi riaddestrare, puoi scaricare gli adattatori ottimizzati dalla tua istanza COS.
download_file_cos(credentials, "granite3_lora.zip", "granite3_lora.zip")
!unzip granite3_lora.zip
Ora configura le opzioni per ChatModel in modo che incorpori gli adattatori.
# setup inference configurations
args = dict(
model_name_or_path="ibm-granite/granite-3.3-2b-instruct", # use IBM Granite 3.3 2b instruct model
adapter_name_or_path="granite3_lora", # load the saved LoRA adapters
template="granite3", # set to the same one used in training, template for constructing prompts
finetuning_type="lora", # which fine-tuning technique used in training
infer_backend="huggingface" # choices: [huggingface, vllm]
)
# create inference config file to run with llama factory
with open("inference_config.yaml", "w", encoding="utf-8") as file:
yaml.dump(args, file, indent=2)
from llamafactory.chat import ChatModel
chat_model = ChatModel(args)
Ora possiamo testare la stessa sfida di ragionamento al modello messo a punto:
messages = []
# run inference chatbot
question = '''
A 1-year-old girl is brought to a neurologist due to increasing seizure frequency over the past 2 months.
She recently underwent a neurology evaluation which revealed hypsarrhythmia on electroencephalography (EEG) with a mix of slow waves, multifocal spikes, and asynchrony.
Her parents have noticed the patient occasionally stiffens and spreads her arms at home. She was born at 38-weeks gestational age without complications.
She has no other medical problems. Her medications consist of lamotrigine and valproic acid. Her temperature is 98.3\u00b0F (36.8\u00b0C), blood pressure is 90/75 mmHg, pulse is 94/min, and respirations are 22/min.
Physical exam reveals innumerable hypopigmented macules on the skin and an irregularly shaped, thickened, and elevated plaque on the lower back.
Which of the following is most strongly associated with this patient's condition?"
"A": "Cardiac rhabdomyoma", "B": "Glaucoma", "C": "Optic glioma", "D": "Polyostotic fibrous dysplasia"
'''
Creare un nuovo messaggio usando la domanda e passarlo al modello messo a punto:
messages.append({"role": "user", "content": question})
response = ""
for new_text in chat_model.stream_chat(messages):
response += new_text
print(response)
messages.append({"role": "assistant", "content": response})
Cardiac rhabdomyoma
Utente:
A 1-year-old girl is brought to a neurologist due to increasing seizure frequency over the past 2 months.
She recently underwent a neurology evaluation which revealed hypsarrhythmia on electroencephalography (EEG) with a mix of slow waves, multifocal spikes, and asynchrony.
Her parents have noticed the patient occasionally stiffens and spreads her arms at home. She was born at 38-weeks gestational age without complications.
She has no other medical problems. Her medications consist of lamotrigine and valproic acid. Her temperature is 98.3\u00b0F (36.8\u00b0C), blood pressure is 90/75 mmHg, pulse is 94/min, and respirations are 22/min.
Physical exam reveals innumerable hypopigmented macules on the skin and an irregularly shaped, thickened, and elevated plaque on the lower back.
Which of the following is most strongly associated with this patient's condition?"
"A": "Cardiac rhabdomyoma", "B": "Glaucoma", "C": "Optic glioma", "D": "Polyostotic fibrous dysplasia"
Risposta:
Cardiac rhabdomyoma
Questa volta il modello ha generato la risposta corretta, grazie all'adattatore addestrato.
Un aspetto da notare: il modello non risponde più con il suo ragionamento. Questo risultato è dovuto al fatto che il set di dati utilizzato per LoRA ha solo la risposta corretta come output previsto del modello. La messa a punto della LoRA può essere utilizzata sia per fornire nuove informazioni che per istruire il modello su come rispondere.
In questo tutorial LoRA ha perfezionato il modello IBM® Granite-3.3-2b-Instruct con nuove conoscenze mediche e un modello dettagliato su come rispondere. Hai visto la capacità di apprendimento di Granite 3.3 anche con un modello piccolo e campioni limitati dal set di dati.
Esplora la libreria IBM di foundation model nel portfolio di watsonx per scalare in sicurezza l'AI generativa per la tua azienda.
Metti l'AI al servizio della tua azienda grazie all'esperienza leader di settore e alla gamma di soluzioni di IBM nel campo dell'AI.
Reinventa i flussi di lavoro e le operazioni critiche aggiungendo l'AI per massimizzare le esperienze, il processo decisionale in tempo reale e il valore aziendale.