Perfeziona MPT-7B su Amazon SageMaker

'Improve MPT-7B on Amazon SageMaker'

Foto di Jeffery Ho su Unsplash.

Impara come preparare un dataset e creare un job di training per il fine-tuning di MPT-7B su Amazon SageMaker

Ogni settimana vengono annunciati nuovi modelli di grandi dimensioni per il linguaggio (LLM), ognuno cercando di battere il suo predecessore e di conquistare le classifiche di valutazione. Uno degli ultimi modelli disponibili è MPT-7B, rilasciato da MosaicML. A differenza di altri modelli simili, questo modello da 7 miliardi di parametri è open-source e con licenza commerciale (licenza Apache 2.0) 🚀.

I modelli di base come MPT-7B sono preaddestrati su dataset con trilioni di token (100 token ~ 75 parole) raccolti dal web e, quando richiesti in modo adeguato, possono produrre risultati impressionanti. Tuttavia, per sfruttare veramente il valore dei grandi modelli di linguaggio nelle applicazioni del mondo reale, potrebbe non essere sufficiente una semplice manipolazione degli input per adattarli al caso d’uso specifico e, pertanto, è necessario eseguire il fine-tuning di un modello di base su un dataset specifico del dominio.

I LLM hanno miliardi di parametri e, di conseguenza, eseguire il fine-tuning di modelli così grandi è sfidante. La buona notizia è che il fine-tuning è molto più economico e veloce rispetto al preaddestramento del modello di base dato che 1) i dataset specifici del dominio sono “piccoli” e 2) il fine-tuning richiede solo pochi passaggi sui dati di training.

Ecco cosa impareremo in questo articolo:

  • Come creare e strutturare un dataset per il fine-tuning di un grande modello di linguaggio.
  • Cosa è e come configurare un job di training distribuito con fully sharded data parallel.
  • Come definire un 😊 HuggingFace estimator.
  • Come lanciare un job di training in Amazon SageMaker che esegue il fine-tuning di MPT-7B.

1. Installa le dipendenze e imposta i percorsi S3

Cominciamo installando la SageMaker Python SDK e alcune altre librerie. Questo SDK consente di addestrare e distribuire modelli di machine learning su AWS con poche righe di codice Python. Il codice di seguito è disponibile nella notebook sagemaker_finetuning.ipynb su Github. Esegui la notebook in SageMaker Studio, in un’istanza di notebook SageMaker o sul tuo laptop dopo l’autenticazione a un account AWS.

!pip install "sagemaker==2.162.0" s3path boto3 --quietfrom sagemaker.huggingface import HuggingFacefrom sagemaker.inputs import TrainingInputfrom sagemaker import s3_utilsimport sagemakerimport boto3import json

Il passo successivo è definire i percorsi in cui i dati verranno salvati in S3 e creare una sessione SageMaker.

# Definisci i percorsi S3bucket             = "<YOUR-S3-BUCKET>"training_data_path = f"s3://{bucket}/toy_data/train/data.jsonl"test_data_path     = f"s3://{bucket}/toy_data/test/data.jsonl"output_path        = f"s3://{bucket}/outputs"code_location      = f"s3://{bucket}/code"# Crea una sessione SageMakersagemaker_session  = sagemaker.Session()region             = sagemaker_session.boto_region_namerole               = sagemaker.get_execution_role()

2. Costruisci un dataset per il fine-tuning

Ci occuperemo di creare un dataset fittizio per dimostrare come eseguire il fine-tuning di MPT-7B. Poiché addestrare modelli di queste dimensioni su un dataset completo richiede molto tempo e risorse, è una buona idea prima testare e debuggare il job di training su un piccolo dataset e in seguito scalarlo al dataset completo.

  • Formatta il dataset come una lista di dizionari — Il dataset dovrebbe essere formattato come una lista di dizionari, dove ogni esempio ha una struttura chiave-valore, ad esempio:
{    "prompt": "Cosa è un Pastel de Nata?",    "response": "Un Pastel de Nata è un dolce portoghese di pasta sfoglia ripieno di crema di uova, opzionalmente cosparsi di cannella."}

Il prompt è l’input fornito al modello (ad esempio, una domanda). La response è l’output che il modello è stato addestrato a predire (ad esempio, la risposta alla domanda nel prompt). Il prompt grezzo viene spesso preprocessato per adattarsi a un modello di prompt che aiuti il modello a generare output migliori. Si noti che il modello è addestrato per la modellizzazione del linguaggio causale, quindi è possibile pensarlo come un “completatore di documenti”. È una buona idea progettare il modello di prompt in modo che il modello pensi di completare un documento. Andrej Karpathy spiega bene questo meccanismo nel suo talk Stato di GPT.

prompt_template = """Scrivi una risposta che risponda adeguatamente alla domanda qui sotto.### Domanda:{question}### Risposta:"""dataset = [    {"prompt": "Cos'è un Pastel de Nata?",     "response": "Un Pastel de Nata è un dolce portoghese fatto con crema di uova e pasta sfoglia, opzionalmente spolverato di cannella."},    {"prompt": "Quali musei sono famosi ad Amsterdam?",     "response": "Ad Amsterdam ci sono vari musei famosi in tutto il mondo, e nessun viaggio nella città sarebbe completo senza visitare il Rijksmuseum, il Van Gogh Museum o il Stedelijk Museum."},    {"prompt": "Dove si trova il Parlamento europeo?",     "response": "Strasburgo è la sede ufficiale del Parlamento europeo."},    {"prompt": "Com'è il clima nei Paesi Bassi?",     "response": "I Paesi Bassi sono un paese che vanta un tipico clima marittimo con estati miti e inverni freddi."},    {"prompt": "Cosa sono i Poffertjes?",     "response": "I Poffertjes sono un dolce tradizionale olandese a base di impasto. Somigliano a pancake piccoli e soffici, e sono fatti con lievito e farina di grano saraceno."},]# Formatta il prompt in base al templatead esempio in dataset:    example["prompt"] = prompt_template.format(question=example["prompt"])training_data, test_data = dataset[0:4], dataset[4:]print(f"Dimensione dei dati di addestramento: {len(training_data)}\nDimensione dei dati di test: {len(test_data)}")
  • Carica i dati di addestramento e test su S3 — Una volta che i set di addestramento e test sono pronti e formattati come una lista di dizionari, li caricamo su S3 come righe JSON utilizzando la funzione di utilità qui sotto:
def write_jsonlines_to_s3(data, s3_path):    """Scrivi una lista di dizionari come file di righe JSON su S3"""    json_string = ""    for d in data:        json_string += json.dumps(d) + "\n"    s3_client   = boto3.client("s3")        bucket, key = s3_utils.parse_s3_url(s3_path)    s3_client.put_object(         Body   = json_string,         Bucket = bucket,         Key    = key,    )write_jsonlines_to_s3(training_data, training_data_path)write_jsonlines_to_s3(test_data, test_data_path)

3. Lavoro di addestramento di SageMaker

Con i dataset disponibili su S3, creeremo ora un lavoro di addestramento in Amazon SageMaker. Per questo, dobbiamo creare uno script di ingresso, modificare il file di configurazione specificando le impostazioni di addestramento e definire un estimatore di HuggingFace. Utilizzeremo lo script di addestramento di LLM Foundry e il launcher della CLI della libreria Composer che configura l’ambiente di addestramento distribuito. Entrambi questi pacchetti sono mantenuti da MosaicML, l’azienda alla base di MPT-7B. La cartella di lavoro dovrebbe essere strutturata come segue:

└── fine-tune-mpt-7b-sagemaker/    ├── training_script_launcher.sh    ├── fine_tuning_config.yaml    ├── sagemaker_finetuning.ipynb

Approfondiremo ora ciascuno di questi file.

  • Crea un file di configurazione finetuning_config.yaml — Il template fornito nella repository di LLM Foundry è un buon punto di partenza, in particolare il file mpt-7b-dolly-sft.yaml. Tuttavia, a seconda delle dimensioni del dataset e dell’istanza di addestramento, potrebbe essere necessario regolare alcune di queste configurazioni, come la dimensione del batch. Ho modificato il file per affinare il modello in SageMaker (controllare finetuning_config.yaml). I parametri a cui dovresti prestare attenzione sono i seguenti:
max_seq_len: 512global_seed: 17...# Dataloaderstrain_loader:  name: finetuning  dataset:    hf_name: json    hf_kwargs:        data_dir: /opt/ml/input/data/train/...eval_loader:  name: finetuning  dataset:    hf_name: json    hf_kwargs:        data_dir: /opt/ml/input/data/test/ ...max_duration: 3epeval_interval: 1ep...global_train_batch_size: 128...# FSDPfsdp_config:  sharding_strategy: FULL_SHARD  mixed_precision: PURE  activation_checkpointing: true  activation_checkpointing_reentrant: false  activation_cpu_offload: false  limit_all_gathers: true  verbose: false# Checkpoint to local filesystem or remote object storesave_folder: /tmp/checkpointsdist_timeout: 2000

max_seq_length indica il numero massimo di token dell’input (ricorda che 100 token ~ 75 parole). I dati di training e test saranno caricati utilizzando la libreria 😊 Datasets dalla directory /opt/ml/input/data/{train, test} all’interno del container associato al job di training. Consulta la documentazione di SageMaker Training Storage Folders per capire come sono strutturate le directory del container. max_duration specifica il numero di epoche per il fine-tuning. Di solito, due o tre epoche sono una buona scelta. eval_interval indica con quale frequenza il modello verrà valutato sul test set.

La strategia di training distribuito utilizzata è Fully Sharded Data Parallel (FSDP), che consente l’addestramento efficiente di modelli grandi come MPT-7B. A differenza della strategia di parallelismo dati tradizionale, che mantiene una copia del modello in ogni GPU, FSDP sharda i parametri del modello, gli stati dell’ottimizzatore e i gradienti tra i worker parallelizzati sui dati. Se vuoi saperne di più su FSDP, consulta questo interessante post introduttivo su PyTorch. FSDP è integrato in Composer, la libreria di training distribuito utilizzata da LLM Foundry.

save_folder determina dove verrà salvato il checkpoint del modello (file .pt). Lo impostiamo sulla cartella temporanea /tmp/checkpoints.

  • Crea lo script di entry point launcher.sh — Uno script bash viene utilizzato come entry point. Lo script bash clona la repository di LLM Foundry, installa i requisiti e, soprattutto, esegue lo script di training utilizzando il launcher distribuito della libreria Composer. Nota che, tipicamente, i job di training in SageMaker eseguono lo script di training utilizzando un comando come python train.py. Tuttavia, è possibile passare uno script bash come entry point, il che fornisce maggiore flessibilità nel nostro scenario. Infine, convertiamo il checkpoint del modello salvato in /tmp/checkpoints nel formato del modello HuggingFace e salviamo gli artefatti finali in /opt/ml/model/. SageMaker comprimerà tutti i file in questa directory, creerà un tarball model.tar.gz e lo caricherà su S3. Il tarball è utile per l’infereza.
# Clone llm-foundry package from MosaicML# This is where the training script is hostedgit clone https://github.com/mosaicml/llm-foundry.gitcd llm-foundry# Install required packagespip install -e ".[gpu]"pip install git+https://github.com/mosaicml/composer.git@dev# Run training script with fine-tuning configurationcomposer scripts/train/train.py /opt/ml/code/finetuning_config.yaml# Convert Composer checkpoint to HuggingFace model formatpython scripts/inference/convert_composer_to_hf.py \    --composer_path /tmp/checkpoints/latest-rank0.pt \    --hf_output_path /opt/ml/model/hf_fine_tuned_model \    --output_precision bf16# Print content of the model artifact directoryls /opt/ml/model/
  • Definisci l’Estimator di HuggingFace — L’Estimator imposta il container Docker utilizzato per eseguire il job di training. Utilizzeremo un’immagine con PyTorch 2.0.0 e Python 3.10. Lo script bash e il file di configurazione vengono automaticamente caricati su S3 e resi disponibili all’interno del container (gestiti dal SageMaker Python SDK). Impostiamo l’istanza di training su g5.48xlarge che ha 8 GPU NVIDIA A10G. La p4d.24xlarge è anche una buona scelta. Anche se è più costosa, è dotata di 8 GPU NVIDIA A100. Indichiamo anche le metriche da monitorare sui set di training e test (Cross Entropy e Perplexity). I valori di queste metriche sono catturati tramite espressioni Regex e inviati ad Amazon CloudWatch.
# Define container image for the training jobtraining_image_uri = f"763104351884.dkr.ecr.{region}.amazonaws.com/huggingface-pytorch-training:2.0.0-transformers4.28.1-gpu-py310-cu118-ubuntu20.04-v1.1"# Define metrics to send to CloudWatchmetrics = [    # On training set    {"Name": "train:LanguageCrossEntropy",     "Regex": "Train metrics\/train\/LanguageCrossEntropy: ([+-]?((\d+\.?\d*)|(\.\d+)))"},    {"Name": "train:LanguagePerplexity",     "Regex": "Train metrics\/train\/LanguagePerplexity: ([+-]?((\d+\.?\d*)|(\.\d+)))"},    # On test set    {"Name": "test:LanguageCrossEntropy",     "Regex": "Eval metrics\/eval\/LanguageCrossEntropy: ([+-]?((\d+\.?\d*)|(\.\d+)))"},    {"Name": "test:LanguagePerplexity",     "Regex": "Eval metrics\/eval\/LanguagePerplexity: ([+-]?((\d+\.?\d*)|(\.\d+)))"},]estimator_args = {    "image_uri": training_image_uri,     # Immagine del container di training    "entry_point": "launcher.sh",        # Script bash launcher    "source_dir": ".",                   # Directory con lo script launcher e il file di configurazione    "instance_type": "ml.g5.48xlarge",   # Tipo di istanza    "instance_count": 1,                 # Numero di istanze di training    "base_job_name": "fine-tune-mpt-7b", # Prefisso del nome del job di training    "role": role,                        # Ruolo IAM    "volume_size": 300,                  # Dimensione del volume EBS collegato all'istanza (in GB)    "py_version": "py310",               # Versione di Python    "metric_definitions": metrics,       # Metriche da monitorare    "output_path": output_path,          # Posizione S3 dove l'artefatto del modello verrà caricato    "code_location": code_location,      # Posizione S3 dove il codice sorgente verrà salvato    "disable_profiler": True,            # Non creare un'istanza di profiler    "keep_alive_period_in_seconds": 240, # Abilita Warm Pools durante la sperimentazione}huggingface_estimator = HuggingFace(**estimator_args)

⚠️ Assicurati di richiedere le rispettive quote per il training su SageMaker, insieme alla quota di Warm Pools nel caso in cui stai facendo uso di questa fantastica funzionalità. Se prevedi di eseguire molti lavori su SageMaker, dai un’occhiata ai SageMaker Saving Plans.

  • Avvia il lavoro di training 🚀 — Abbiamo tutto pronto per avviare il lavoro di training su Amazon SageMaker:
huggingface_estimator.fit({    "train": TrainingInput(        s3_data=training_data_path,        content_type="application/jsonlines"),    "test": TrainingInput(        s3_data=test_data_path,        content_type="application/jsonlines"),}, wait=True)

Il tempo di training dipenderà dalle dimensioni del tuo dataset. Con il nostro dataset di esempio, il training richiede circa 20 minuti per essere completato. Una volta che il modello è stato addestrato e convertito nel formato 😊 HuggingFace, SageMaker caricherà il pacchetto modello ( model.tar.gz ) nell’ output_path di S3. In pratica ho riscontrato che l’operazione di caricamento richiede molto tempo (>1h), che potrebbe essere dovuto alle dimensioni degli artefatti del modello da comprimere (~25GB).

4. Riassunto

In questo articolo ho mostrato come preparare un dataset e creare un lavoro di training in SageMaker per il fine-tuning di MPT-7B per il tuo caso d’uso. L’implementazione sfrutta lo script di training di LLM Foundry e utilizza il launcher di training distribuito della libreria Composer. Una volta che hai fatto il fine-tuning del tuo modello e vuoi distribuirlo, consiglio di dare un’occhiata ai post del blog di Philipp Schmid ; ci sono molti esempi su come distribuire LLM in SageMaker. Divertiti con il tuo modello MPT-7B a fine-tuning! 🎉

Tutto il codice utilizzato in questo articolo è disponibile su Github:

GitHub – jpcpereira/sagemaker-fine-tune-mpt-7b

github.com

— João Pereira

Ti ringrazio per aver letto. Spero che questo articolo ti aiuti a iniziare con il fine-tuning di grandi modelli di lingua come MPT-7B su Amazon SageMaker. Se vuoi leggere i miei futuri articoli, seguimi per favore. Il feedback è molto apprezzato! Lascia un commento qui sotto se hai domande o contattami direttamente via email o su LinkedIn.