Migliora Llama 2 utilizzando QLoRA e distribuiscilo su Amazon SageMaker con AWS Inferentia2

Potenzia Llama 2 con QLoRA e distribuiscilo su Amazon SageMaker con AWS Inferentia2

In questo post, presentiamo il raffinamento di un modello Llama 2 utilizzando un metodo di raffinamento efficiente dei parametri (PEFT) e implementiamo il modello raffinato su AWS Inferentia2. Utilizziamo il software development kit (SDK) AWS Neuron per accedere al dispositivo AWS Inferentia2 e beneficiare delle sue alte prestazioni. Successivamente utilizziamo un container di inferenza di grandi dimensioni alimentato da Deep Java Library (DJLServing) come soluzione di servizio del modello.

Panoramica della soluzione

Raffinamento efficiente di Llama2 utilizzando QLoRa

La famiglia di modelli Llama 2 (LLM) è una collezione di modelli di testo generativi preaddestrati e raffinati, che vanno da 7 miliardi a 70 miliardi di parametri. Llama 2 è stato preaddestrato su 2 trilioni di token di dati provenienti da fonti pubblicamente disponibili. A volte i clienti di AWS scelgono di raffinare i modelli Llama 2 utilizzando i propri dati per ottenere migliori prestazioni per attività successive. Tuttavia, a causa del grande numero di parametri del modello Llama 2, il raffinamento completo potrebbe risultare proibitivamente costoso e richiedere molto tempo. L’approccio del raffinamento efficiente dei parametri (PEFT) può affrontare questo problema raffinando solo un piccolo numero di parametri aggiuntivi del modello, lasciando congelati la maggior parte dei parametri del modello preaddestrato. Per ulteriori informazioni su PEFT, si può leggere questo post. In questo post, utilizziamo QLoRa per raffinare un modello Llama 2 7B.

Implementare un modello raffinato su Inf2 utilizzando Amazon SageMaker

AWS Inferentia2 è un acceleratore di machine learning (ML) appositamente progettato per carichi di lavoro di inferenza e offre alte prestazioni fino al 40% in meno di costo per l’intelligenza artificiale generativa e i carichi di lavoro di LLM rispetto ad altre istanze ottimizzate per l’inferenza su AWS. In questo post, utilizziamo l’istanza Amazon Elastic Compute Cloud (Amazon EC2) Inf2, che presenta AWS Inferentia2, i dispositivi di accelerazione Inferentia2 di seconda generazione, ciascuno dei quali contiene due NeuronCores-v2. Ogni NeuronCore-v2 è un’unità eterogenea indipendente, con quattro motori principali: tensori, vettoriali, scalari e motori GPSIMD. Include una memoria SRAM gestita dal software a bordo chip per massimizzare la località dei dati. Dato che sono stati pubblicati diversi articoli su Inf2, il lettore può fare riferimento a questo post e alla nostra documentazione per ulteriori informazioni su Inf2.

Per implementare modelli su Inf2, abbiamo bisogno dell’SDK AWS Neuron come strato software in esecuzione sopra l’hardware Inf2. AWS Neuron è l’SDK utilizzato per eseguire carichi di lavoro di deep learning su AWS Inferentia e AWS Trainium. Consente di sviluppare l’intero ciclo di vita dello sviluppo di ML, per costruire nuovi modelli, addestrarli e ottimizzarli, e implementarli per la produzione. AWS Neuron include un compilatore di deep learning, un runtime e strumenti integrati nativamente con framework popolari come TensorFlow e PyTorch. In questo blog, useremo transformers-neuronx, che fa parte dell’SDK AWS Neuron per i flussi di lavoro di inferenza del decoder del transformer. Questo SDK supporta una serie di modelli popolari, tra cui Llama 2.

Per distribuire modelli su Amazon SageMaker, di solito utilizziamo un contenitore che contiene le librerie richieste, come Neuron SDK e transformers-neuronx, oltre al componente di servizio dei modelli. Amazon SageMaker mantiene contenitori di apprendimento approfondito (DLC) con librerie open source popolari per l’hosting di modelli di grandi dimensioni. In questo post, utilizziamo il Contenitore di inferenza di modelli di grandi dimensioni per Neuron. Questo contenitore contiene tutto ciò di cui hai bisogno per distribuire il tuo modello Llama 2 su Inf2. Per le risorse per iniziare con LMI su Amazon SageMaker, consulta molti dei nostri post esistenti (blog 1, blog 2, blog 3) su questo argomento. In breve, puoi eseguire il contenitore senza scrivere alcun codice aggiuntivo. Puoi utilizzare il gestore predefinito per un’esperienza utente senza interruzioni e passare uno dei nomi di modello supportati e eventuali parametri configurabili durante il caricamento. Questo compila e serve un LLM su un’istanza Inf2. Ad esempio, per distribuire OpenAssistant/llama2-13b-orca-8k-3319, puoi fornire la seguente configurazione (come file serving.properties). In serving.properties, specifichiamo il tipo di modello come llama2-13b-orca-8k-3319, la dimensione del batch come 4, il grado di parallelismo del tensore come 2, e questo è tutto. Per l’elenco completo dei parametri configurabili, consulta Tutte le opzioni di configurazione DJL.

# Engine da utilizzare: MXNet, PyTorch, TensorFlow, ONNX, PaddlePaddle, DeepSpeed, ecc.
engine = Python # gestore predefinito per il servizio dei modelli
option.entryPoint = djl_python.transformers_neuronx # L'ID Hugging Face di un modello o l'URL s3 degli artefatti del modello.
option.model_id = meta-llama/Llama-2-7b-chat-hf # la dimensione del batch dinamico, il valore predefinito è 1.
option.batch_size=4 # Questa opzione specifica il numero di partizioni parallelizzate del tensore eseguite sul modello.
option.tensor_parallel_degree=2 # La lunghezza della sequenza di input
option.n_positions=512 # Abilita il batching a livello di iterazione utilizzando uno dei seguenti: "auto", "scheduler", "lmi-dist".
option.rolling_batch=auto # Il tipo di dati a cui prevedi di convertire il modello, tipo di dati predefinito.
option.dtype=fp16 # timeout del modello di caricamento del worker
option.model_loading_timeout=1500

Alternativamente, puoi scrivere il tuo file di gestore del modello come mostrato in questo esempio, ma ciò richiede l’implementazione dei metodi di caricamento del modello e di inferenza per fungere da ponte tra le API di DJLServing.

Prerequisiti

L’elenco seguente illustra i prerequisiti per distribuire il modello descritto in questo post del blog. Puoi implementare entrambi dalla Console di gestione AWS o utilizzando la versione più recente dell’ interfaccia della riga di comando AWS (AWS CLI).

Walkthrough

Nella sezione seguente, esamineremo il codice in due parti:

  1. Perfezionare un modello Llama2-7b e caricare gli artefatti del modello in una posizione specificata di un bucket Amazon S3.
  2. Effettuare il deployment del modello in un Inferentia2 utilizzando un contenitore di servizio DJL ospitato in Amazon SageMaker.

Il codice completo con le istruzioni può essere trovato in questo repository GitHub.

Parte 1: Perfezionare un modello Llama2-7b utilizzando PEFT

Utilizzeremo il metodo recentemente introdotto nel paper QLoRA: Quantization-aware Low-Rank Adapter Tuning for Language Generation di Tim Dettmers et al. QLoRA è una nuova tecnica per ridurre l’impronta di memoria dei modelli di grandi dimensioni durante il perfezionamento, senza compromettere le prestazioni.

Nota: Il perfezionamento del modello llama2-7b mostrato di seguito è stato testato su un notebook Amazon SageMaker Studio con Kernel Python 2.0 GPU Ottimizzato utilizzando un’istanza di tipo ml.g5.2xlarge. Come best practice, consigliamo di utilizzare un Ambiente di Sviluppo Integrato (IDE) basato su Amazon SageMaker Studio lanciato nella propria Amazon Virtual Private Cloud (VPC). Questo ti permette di controllare, monitorare e ispezionare il traffico di rete all’interno e all’esterno della tua VPC utilizzando le funzionalità standard di networking e sicurezza di AWS. Per ulteriori informazioni, consulta Securing Amazon SageMaker Studio connectivity using a private VPC.

Quantizza il modello di base

Prima di tutto carichiamo un modello quantizzato con quantizzazione a 4 bit utilizzando la libreria Huggingface transformers come segue:

# Il modello preaddestrato di base per il perfezionamentomodel_name = "NousResearch/Llama-2-7b-chat-hf"# Il dataset di istruzioni da utilizzare per l'addestramentodataset_name = "mlabonne/guanaco-llama2-1k"# Attiva il caricamento del modello di base con precisione a 4 bituse_4bit = Truebnb_4bit_compute_dtype = "float16"bnb_4bit_quant_type = "nf4"use_nested_quant = Falsecompute_dtype = getattr(torch, bnb_4bit_compute_dtype)bnb_config = BitsAndBytesConfig(load_in_4bit=use_4bit,bnb_4bit_quant_type=bnb_4bit_quant_type,bnb_4bit_compute_dtype=compute_dtype,bnb_4bit_use_double_quant=use_nested_quant,)# Carica il modello di base e il tokenizermodel = AutoModelForCausalLM.from_pretrained(model_name,quantization_config=bnb_config,device_map=device_map)model.config.pretraining_tp = 1tokenizer = AutoTokenizer.from_pretrained(model_name, trust_remote_code=True)

Carica il dataset di addestramento

Successivamente, carichiamo il dataset per alimentare il modello per la fase di perfezionamento come mostrato di seguito:

# Carica il dataset (puoi elaborarlo qui)dataset = load_dataset(dataset_name, split="train")

Aggiungi un livello di adattatore

Qui aggiungiamo un piccolo livello di adattatore addestrabile, configurato come LoraConfig definito nella libreria peft di Hugging Face.

# includi i livelli lineari per applicare LoRA.modules = find_all_linear_names(model)## Configurazione di LoRAlora_r = 64# Parametro alfa per la scalatura di LoRAlora_alpha = 16# Probabilità di dropout per i livelli LoRAlora_dropout = 0.1peft_config = LoraConfig(lora_alpha=lora_alpha,lora_dropout=lora_dropout,r=lora_r,bias="none",task_type="CAUSAL_LM",target_modules=modules)

Allenare un modello

Utilizzando la configurazione LoRA mostrata sopra, effettueremo il fine-tuning del modello Llama2 insieme agli iperparametri. Uno snippet di codice per l’addestramento del modello è mostrato di seguito:

# Imposta i parametri di addestramentotraining_arguments = TrainingArguments(...)trainer = SFTTrainer(model=model,train_dataset=dataset,peft_config=peft_config, # Configurazione LoRAdataset_text_field="text",max_seq_length=max_seq_length,tokenizer=tokenizer,args=training_arguments,packing=packing,)# Addestra il modellotrainer.train()# Salva il modello addestratotrainer.model.save_pretrained(new_model)

Unisci il peso del modello

Il modello fine-tuned eseguito sopra ha creato un nuovo modello contenente i pesi dell’adattatore LoRA addestrato. Nello snippet di codice seguente, uniremo l’adattatore con il modello di base in modo da poter utilizzare il modello fine-tuned per l’inferenza.

# Ricarica il modello in FP16 e uniscilo ai pesi di LoRAbase_model = AutoModelForCausalLM.from_pretrained(model_name,low_cpu_mem_usage=True,return_dict=True,torch_dtype=torch.float16,device_map=device_map,)model = PeftModel.from_pretrained(base_model, new_model)model = model.merge_and_unload()save_dir = "merged_model"model.save_pretrained(save_dir, safe_serialization=True, max_shard_size="2GB")# Ricarica il tokenizer per salvarlotokenizer = AutoTokenizer.from_pretrained(model_name, trust_remote_code=True)tokenizer.pad_token = tokenizer.eos_tokentokenizer.padding_side = "right"tokenizer.save_pretrained(save_dir)

Carica il peso del modello su Amazon S3

Nell’ultimo passo della parte 1, salveremo i pesi del modello unito in una posizione specifica di Amazon S3. Il peso del modello verrà utilizzato da un contenitore di servizio del modello in Amazon SageMaker per ospitare il modello utilizzando un’istanza Inferentia2.

model_data_s3_location = "s3://<bucket_name>/<prefix>/"!cd {save_dir} && aws s3 cp --recursive . {model_data_s3_location}

Parte 2: Ospita il modello QLoRA per l’inferenza con AWS Inf2 utilizzando il contenitore LMI di SageMaker

In questa sezione, illustreremo i passaggi per implementare un modello fine-tuned QLoRA in un ambiente di hosting di Amazon SageMaker. Utilizzeremo un contenitore di DJL serving da SageMaker DLC, che si integra con la libreria transformers-neuronx per ospitare questo modello. La configurazione facilita il caricamento dei modelli sugli acceleratori AWS Inferentia2, parallelizza il modello su più NeuronCores e abilita il servizio tramite endpoint HTTP.

Prepara gli artefatti del modello

DJL supporta molte librerie di ottimizzazione del deep learning, tra cui DeepSpeed, FasterTransformer e altro ancora. Per le configurazioni specifiche del modello, forniamo un file serving.properties con i parametri chiave, come tensor_parallel_degree e model_id, per definire le opzioni di caricamento del modello. Il model_id può essere un ID del modello Hugging Face o un percorso Amazon S3 in cui sono archiviati i pesi del modello. Nel nostro esempio, forniamo la posizione Amazon S3 del nostro modello fine-tuned. Il seguente snippet di codice mostra le proprietà utilizzate per il servizio del modello:

%%writefile serving.propertiesengine=Pythonoption.entryPoint=djl_python.transformers_neuronxoption.model_id=<model data s3 location>option.batch_size=4option.neuron_optimize_level=2option.tensor_parallel_degree=8option.n_positions=512option.rolling_batch=autooption.dtype=fp16option.model_loading_timeout=1500

Si prega di fare riferimento a questa documentazione per ulteriori informazioni sulle opzioni configurabili disponibili tramite serving.properties. Si noti che utilizziamo option.n_position=512 in questo blog per una compilazione più rapida di AWS Neuron. Se si desidera provare una lunghezza maggiore per i token di input, quindi consigliamo al lettore di pre-compilare il modello in anticipo (vedi AOT Pre-Compile Model on EC2). In caso contrario, potresti incorrere in un errore di timeout se il tempo di compilazione è troppo lungo.

Dopo aver definito il file serving.properties, impacchetteremo il file in formato tar.gz, come segue:

%%shmkdir mymodelmv serving.properties mymodel/tar czvf mymodel.tar.gz mymodel/rm -rf mymodel

Successivamente, caricheremo il tar.gz in una posizione del bucket Amazon S3:

s3_code_prefix = "large-model-lmi/code"bucket = sess.default_bucket()  # bucket per gli artefatticode_artifact = sess.upload_data("mymodel.tar.gz", bucket, s3_code_prefix)print(f"Caricato tarball S3 Code o Model in --- > {code_artifact}")

Crea un endpoint del modello Amazon SageMaker

Per utilizzare un’istanza Inf2 per il servizio, utilizziamo un container Amazon SageMaker LMI con supporto per DJL neuronX. Consulta questo post per ulteriori informazioni sull’utilizzo di un container DJL NeuronX per le inferenze. Il codice seguente mostra come distribuire un modello utilizzando Amazon SageMaker Python SDK:

# Recupera l'URI dell'immagine del docker DJL-neuronximage_uri = image_uris.retrieve(framework="djl-neuronx",region=sess.boto_session.region_name,version="0.24.0")# Define il tipo di istanza inf2 da utilizzare per il servizioinstance_type = "ml.inf2.48xlarge"endpoint_name = sagemaker.utils.name_from_base("lmi-model")# Deploy il modello per le inferenzemodel.deploy(initial_instance_count=1,instance_type=instance_type,container_startup_health_check_timeout=1500,volume_size=256,endpoint_name=endpoint_name)# le nostre richieste e risposte saranno in formato json quindi specificare il serializzatore e il deserializzatorepredictor = sagemaker.Predictor(endpoint_name=endpoint_name,sagemaker_session=sess,serializer=serializers.JSONSerializer(),)

Test del modello endpoint

Dopo che il modello è stato distribuito con successo, possiamo convalidare l’endpoint inviando una richiesta campione al predictor:

prompt="Che cos'è il machine learning?"input_data = f"<s>[INST] <<SYS>>\nCome data scientist\n<</SYS>>\n{prompt} [/INST]"response = predictor.predict({"inputs": input_data, "parameters": {"max_new_tokens":300, "do_sample":"True"}})print(json.loads(response)['generated_text'])

L’output di esempio viene mostrato di seguito:

Nel contesto dell’analisi dei dati, il Machine Learning (ML) si riferisce a una tecnica statistica in grado di estrarre potenziale predittivo da un dataset con una complessità e accuratezza crescenti, restringendo iterativamente l’ambito di una statistica.

Il Machine Learning non è una nuova tecnica statistica, ma piuttosto una combinazione di tecniche esistenti. Inoltre, non è stato progettato per essere utilizzato con un dataset specifico o per produrre un risultato specifico. È stato piuttosto progettato in modo flessibile per adattarsi a qualsiasi dataset e per fare previsioni su qualsiasi risultato.

Pulizia

Se decidi di non voler più mantenere in esecuzione l’endpoint SageMaker, puoi eliminarlo utilizzando AWS SDK per Python (boto3), AWS CLI o Amazon SageMaker Console. Inoltre, puoi anche arrestare le risorse di Amazon SageMaker Studio che non sono più necessarie.

Conclusioni

In questo post, ti abbiamo mostrato come ottimizzare un modello Llama2-7b utilizzando l’adattatore LoRA con quantizzazione a 4 bit utilizzando un’istanza GPU singola. Successivamente abbiamo distribuito il modello su un’istanza Inf2 ospitata in Amazon SageMaker utilizzando un container di servizio DJL. Infine, abbiamo convalidato l’endpoint del modello Amazon SageMaker con una previsione di generazione di testo utilizzando SageMaker Python SDK. Prova tu stesso, siamo ansiosi di sentire il tuo feedback. Resta sintonizzato per ulteriori aggiornamenti sulle funzionalità e le nuove innovazioni con AWS Inferentia.

Per ulteriori esempi su AWS Neuron, consulta aws-neuron-samples.