Modele și platforme AI

Optimizarea implementării LLM: vLLM PagedAttention și viitorul servirii eficiente a IA

mm
Adaugă Unite.AI la sursele tale preferate pe Google

Modelele de limbaj mari (LLM) care rulează aplicații din lumea reală prezintă provocări unice, ÃŪn special ÃŪn ceea ce privește resursele de calcul, latența și eficiența costurilor. În acest ghid cuprinzător, vom explora peisajul servirii LLM, cu un accent deosebit pe vLLM (model de limbaj vectorial), o soluție care reconfigurează modul ÃŪn care implementăm și interacționăm cu aceste modele puternice.

Provocările servirii Modelelor de Limbaj Mari

Înainte de a explora soluții specifice, să examinăm principalele provocări care fac servirea LLM o sarcină complexă:

Resurse de Calcul

LLM-urile sunt notorii pentru numărul lor enorm de parametri, care variază de la miliarde la sute de miliarde. De exemplu, GPT-3 are 175 de miliarde de parametri, ÃŪn timp ce modelele mai recente, cum ar fi GPT-4, se estimează că au și mai mulți. Această dimensiune uriașă se traduce ÃŪn cerințe semnificative de calcul pentru inferență.

Exemplu:
Considerați un LLM relativ modest, cu 13 miliarde de parametri, cum ar fi LLaMA-13B. Chiar și acest model necesită:

– Aproximativ 26 GB de memorie doar pentru a stoca parametrii modelului (presupunÃĒnd precizie de 16 biți)
– Memorare suplimentară pentru activări, mecanisme de atenție și calcule intermediare
– Putere de calcul substanțială pentru inferență ÃŪn timp real

Latență

În multe aplicații, cum ar fi chatbot-urile sau generarea de conținut ÃŪn timp real, latența scăzută este crucială pentru o experiență bună a utilizatorului. Cu toate acestea, complexitatea LLM-urilor poate duce la timpi de procesare semnificativi, ÃŪn special pentru secvențe mai lungi.

Exemplu:
Imaginați-vă un chatbot de asistență pentru clienți alimentat de un LLM. Dacă fiecare răspuns necesită cÃĒteva secunde pentru a fi generat, conversația va părea nefirească și frustrantă pentru utilizatori.

Cost

Hardware-ul necesar pentru a rula LLM-uri la scară poate fi extrem de scump. GPU-urile de ÃŪnaltă performanță sau TPU-urile sunt adesea necesare, iar consumul de energie al acestor sisteme este substanțial.

Exemplu:
Rularea unui cluster de GPU-uri NVIDIA A100 (adesea utilizate pentru inferența LLM) poate costa mii de dolari pe zi ÃŪn taxe de calcul cloud.

Abordări Tradiționale pentru Servirea LLM

Înainte de a explora soluții mai avansate, să trecem ÃŪn revistă unele abordări tradiționale pentru servirea LLM-urilor:

Implementare Simplă cu Hugging Transformers

Biblioteca Hugging Face Transformers oferă o modalitate simplă de a implementa LLM-urile, dar nu este optimizată pentru servire de ÃŪnaltă performanță.

Exemplu de cod:

from transformers import AutoModelForCausalLM, AutoTokenizer
import torch

<p>nume_model = "meta-llama/Llama-2-13b-hf"
model = AutoModelForCausalLM.from_pretrained(nume_model, device_map="auto")
tokenizer = AutoTokenizer.from_pretrained(nume_model)</p>

<p>def generează_text(prompt, max_length=100):
inputs = tokenizer(prompt, return_tensors="pt").to(model.device)
outputs = model.generate(**inputs, max_length=max_length)
return tokenizer.decode(outputs[0], skip_special_tokens=True)</p>

<p>print(generează_text("Viitorul inteligenței artificiale este"))

Deși această abordare funcționează, nu este potrivită pentru aplicații cu trafic ridicat din cauza utilizării ineficiente a resurselor și a lipsei de optimizări pentru servire.

Folosirea TorchServe sau a unor cadre similare

Cadrele precum TorchServe oferă capacități de servire mai robuste, inclusiv echilibrare a ÃŪncărcării și gestionare a versiunilor modelului. Cu toate acestea, ele nu abordează ÃŪncă provocările specifice ale servirii LLM, cum ar fi gestionarea eficientă a memoriei pentru modele mari.

Înțelegerea Gestionării Memoriei ÃŪn Servirea LLM

Gestionarea eficientă a memoriei este critică pentru servirea modelelor de limbaj mari (LLM) din cauza resurselor de calcul extinse necesare. Următoarele imagini ilustrează diverse aspecte ale gestionării memoriei, care sunt integrale pentru optimizarea performanței LLM.

Memorie Segmentată vs. Paginată

Aceste două diagrame compară tehnici de gestionare a memoriei segmentate și paginate, utilizate ÃŪn mod obișnuit ÃŪn sisteme de operare (OS).

  • Memorie Segmentată: Această tehnică ÃŪmparte memoria ÃŪn segmente diferite, fiecare corespunzÃĒnd unui program sau proces diferit. De exemplu, ÃŪntr-un context de servire LLM, segmente diferite ar putea fi alocate pentru diverse componente ale modelului, cum ar fi tokenizare, ÃŪncorporare și mecanisme de atenție. Fiecare segment poate crește sau scădea independent, oferind flexibilitate, dar potențial conducÃĒnd la fragmentare dacă segmentele nu sunt gestionate corespunzător.
  • Memorie Paginată: Aici, memoria este ÃŪmpărțită ÃŪn pagini de dimensiune fixă, care sunt mapate pe memoria fizică. Paginile pot fi schimbate ÃŪn și ieșit ÃŪn funcție de nevoi, permițÃĒnd o utilizare eficientă a resurselor de memorie. În servirea LLM, acest lucru poate fi crucial pentru gestionarea cantităților mari de memorie necesare pentru stocarea parametrilor modelului și calculelor intermediare.

Gestionarea Memoriei ÃŪn OS vs. vLLM

Această imagine prezintă o comparație ÃŪntre gestionarea tradițională a memoriei ÃŪn sisteme de operare și abordarea de gestionare a memoriei utilizată ÃŪn vLLM.

  • Gestionarea Memoriei ÃŪn OS: În sistemele de operare tradiționale, procesele (de exemplu, Proces A și Proces B) sunt alocate pagini de memorie (Pagină 0, Pagină 1, etc.) ÃŪn memoria fizică. Alocarea aceasta poate duce la fragmentare ÃŪn timp, pe măsură ce procesele solicită și eliberează memorie.
  • Gestionarea Memoriei vLLM: Cadru vLLM utilizează o cache KV (cheie-valoare) pentru a gestiona memoria mai eficient. Solicitările (de exemplu, Solicitare A și Solicitare B) sunt alocate blocuri ale cache-ului KV (Bloc KV 0, Bloc KV 1, etc.). Această abordare ajută la minimizarea fragmentării și optimizează utilizarea memoriei, permițÃĒnd o servire mai rapidă și mai eficientă a modelului.

Mecanismul de Atenție ÃŪn LLM

Mecanismul de Atenție ÃŪn LLM

Mecanismul de Atenție ÃŪn LLM

Mecanismul de atenție este o componentă fundamentală a modelelor de transformare, care sunt utilizate ÃŪn mod obișnuit pentru LLM. Această diagramă ilustrează formula de atenție și componentele sale:

  • Cerere (Q): Un token nou ÃŪn pasul decodificării sau ultimul token pe care modelul l-a văzut.
  • Cheie (K): Contextul anterior la care modelul ar trebui să se concentreze.
  • Valoare (V): Suma ponderată a contextului anterior.

Formula calculează scorurile de atenție prin produsul punctului dintre cerere și chei, scalat cu rădăcina pătrată a dimensiunii cheii, aplicÃĒnd o funcție softmax și, ÃŪn final, prin produsul punctului cu valorile. Acest proces permite modelului să se concentreze pe părți relevante ale secvenței de intrare la generarea fiecărui token.

Comparație a Debitului de Servire

vLLM: Servire LLM Ușoară, Rapidă și Ieftină cu PagedAttention

vLLM: Servire LLM Ușoară, Rapidă și Ieftină cu PagedAttention

Această imagine prezintă o comparație a debitului de servire ÃŪntre diferite cadre (HF, TGI și vLLM) utilizÃĒnd modele LLaMA pe diverse configurații de hardware.

  • LLaMA-13B, A100-40GB: vLLM atinge un debit de 14x – 24x mai mare decÃĒt Hugging Face Transformers (HF) și 2,2x – 2,5x mai mare decÃĒt Hugging Face Text Generation Inference (TGI).
  • LLaMA-7B, A10G: Se observă tendințe similare, cu vLLM depășindu-le pe ambele, HF și TGI.

vLLM: O Nouă Arhitectură de Servire LLM

vLLM, dezvoltat de cercetători de la UC Berkeley, reprezintă un salt semnificativ ÃŪnainte ÃŪn tehnologia de servire LLM. Să explorăm caracteristicile sale cheie și inovațiile:

PagedAttention

În inima vLLM se află PagedAttention, un algoritm de atenție inovator inspirat de gestionarea memoriei virtuale ÃŪn sisteme de operare. Iată cum funcționează:

– Împărțirea Cache-ului KV: În loc de a stoca ÃŪntregul cache KV ÃŪn mod contiguu ÃŪn memorie, PagedAttention ÃŪl ÃŪmparte ÃŪn blocuri de dimensiune fixă.
– Stocare Necontiguă: Aceste blocuri pot fi stocate ÃŪn mod necontiguu ÃŪn memorie, permițÃĒnd o gestionare mai flexibilă a memoriei.
– Alocare la Cerere: Blocurile sunt alocate doar atunci cÃĒnd sunt necesare, reducÃĒnd risipa de memorie.
– Partajare Eficientă: Mai multe secvențe pot partaja blocuri, permițÃĒnd optimizări pentru tehnici precum eşantionarea paralelă și căutarea cu fascicul.

Ilustrație:

“`
Cache KV Traditional:
[Token 1 KV][Token 2 KV][Token 3 KV]â€Ķ[Token N KV]
(Alocare contiguă de memorie)
“`

PagedAttention Cache KV:
[Block 1] -> Adresă Fizică A
[Block 2] -> Adresă Fizică C
[Block 3] -> Adresă Fizică B
â€Ķ
(Alocare necontiguă de memorie)
“`

Această abordare reduce semnificativ fragmentarea memoriei și permite o utilizare mult mai eficientă a memoriei GPU.

Loturi Continue

vLLM implementează loturi continue, care procesează dinamic solicitările pe măsură ce acestea sosesc, ÃŪn loc de a aștepta să formeze loturi de dimensiune fixă. Acest lucru conduce la o latență mai scăzută și un debit mai mare.

Exemplu:
Imaginați-vă un flux de solicitări care sosesc:

“`
Timp 0ms: Solicitare A sosește
Timp 10ms: Începe procesarea Solicitării A
Timp 15ms: Solicitare B sosește
Timp 20ms: Începe procesarea Solicitării B (ÃŪn paralel cu A)
Timp 25ms: Solicitare C sosește
â€Ķ
“`

Cu loturi continue, vLLM poate ÃŪncepe procesarea fiecărei solicitări imediat, ÃŪn loc de a aștepta să le grupeze ÃŪn loturi predefinite.

Eșantionare Paralelă Eficientă

Pentru aplicații care necesită mai multe exemple de ieșire pe prompt (de exemplu, asistenți de scriere creativă), capacitățile de partajare a memoriei vLLM strălucesc. Poate genera mai multe ieșiri ÃŪn timp ce reutilizează cache-ul KV pentru prefixe comune.

Exemplu de cod utilizÃĒnd vLLM:


from vllm import LLM, SamplingParams

<p>llm = LLM(model="meta-llama/Llama-2-13b-hf")
prompturi = ["Viitorul inteligenței artificiale este"]</p>

<p># Generează 3 exemple pe prompt
sampling_params = SamplingParams(n=3, temperatura=0.8, max_tokens=100)
ieșiri = llm.generate(prompturi, sampling_params)</p>

<p>pentru ieșire ÃŪn ieșiri:
print(f"Prompt: {ieșire.prompt}")
pentru i, iesire in enumerate(ieșire.ieșiri):
print(f"Exemplu {i + 1}: {iesire.text}")

Acest cod generează eficient mai multe exemple pentru promptul dat, valorificÃĒnd optimizările vLLM.

Testarea Performanței vLLM

Pentru a aprecia cu adevărat impactul vLLM, să examinăm cÃĒteva comparații de performanță:

Comparație a Debitului

Pe baza informațiilor furnizate, vLLM depășește semnificativ alte soluții de servire:

– PÃĒnă la 24x debit mai mare ÃŪn comparație cu Hugging Face Transformers
– 2,2x – 3,5x debit mai mare decÃĒt Hugging Face Text Generation Inference (TGI)

Ilustrație:

“`
Debit (Tokeni pe secundă)
|
| ****
| ****
| ****
| **** ****
| **** **** ****
| **** **** ****
|————————
HF TGI vLLM
“`

Eficiență a Memoriei

PagedAttention din vLLM conduce la o utilizare aproape optimă a memoriei:

– Doar aproximativ 4% pierdere de memorie, comparativ cu 60-80% ÃŪn sistemele tradiționale
– Această eficiență permite servirea unor modele mai mari sau gestionarea unui număr mai mare de solicitări concurente cu același hardware

Începerea cu vLLM

Acum că am explorat beneficiile vLLM, să trecem la procesul de configurare și utilizare a acestuia ÃŪn proiectele dvs.

6.1 Instalare

Instalarea vLLM este simplă utilizÃĒnd pip:


!pip install vllm

6.2 Utilizare de Bază pentru Inferență Offline

Iată un exemplu simplu de utilizare a vLLM pentru generarea de text offline:

from vllm import LLM, SamplingParams

<p># Inițializați modelul
llm = LLM(model="meta-llama/Llama-2-13b-hf")</p>

<p># Pregătiți prompturile
prompturi = [
"Scrieți un scurt poem despre inteligența artificială:",
"Explicați calculul cuantic ÃŪn termeni simpli:"
]</p>

<p># Setări parametri de eşantionare
sampling_params = SamplingParams(temperatura=0.8, max_tokens=100)</p>

<p># Generează răspunsuri
ieșiri = llm.generate(prompturi, sampling_params)</p>

<p># Printați rezultatele
pentru ieșire ÃŪn ieșiri:
print(f"Prompt: {ieșire.prompt}")
print(f"Text generat: {ieșire.ieșiri[0].text}\n")

Acest script demonstrează cum să ÃŪncărcați un model, să setați parametri de eşantionare și să generați text pentru mai multe prompturi.

6.3 Configurarea unui Server vLLM

Pentru servirea online, vLLM oferă un server API compatibil cu OpenAI. Iată cum să ÃŪl configurați:

1. Porniți serverul:

python -m vllm.entrypoints.openai.api_server --model meta-llama/Llama-2-13b-hf

2. Interogați serverul utilizÃĒnd curl:

curl http://localhost:8000/v1/completions \
-H "Content-Type: application/json" \
-d '{"model": "meta-llama/Llama-2-13b-hf", "prompt": "Beneficiile inteligenței artificiale includ:", "max_tokens": 100, "temperatura": 0.7}'

Această configurare vă permite să serviți LLM cu o interfață compatibilă cu API-ul OpenAI, facilitÃĒnd integrarea ÃŪn aplicații existente.

Subiecte Avansate despre vLLM

Deși vLLM oferă ÃŪmbunătățiri semnificative ÃŪn servirea LLM, există considerații și subiecte avansate de explorat:

7.1 Cuantificarea Modelului

Pentru o servire și mai eficientă, ÃŪn special pe hardware cu memorie limitată, pot fi utilizate tehnici de cuantificare. Deși vLLM ÃŪnsuși nu suportă ÃŪn prezent cuantificarea, poate fi utilizat ÃŪn conjuncție cu modele cuantificate:

from transformers import AutoModelForCausalLM, AutoTokenizer
import torch

<p># Încărcați un model cuantificat
nume_model = "meta-llama/Llama-2-13b-hf"
model = AutoModelForCausalLM.from_pretrained(nume_model, device_map="auto", load_in_8bit=True)
tokenizer = AutoTokenizer.from_pretrained(nume_model)</p>

<p># Utilizați modelul cuantificat cu vLLM
from vllm import LLM</p>

<p>llm = LLM(model=model, tokenizer=tokenizer)

7.2 Inferență Distribuită

Pentru modele extrem de mari sau aplicații cu trafic ridicat, inferența distribuită pe mai multe GPU-uri sau mașini poate fi necesară. Deși vLLM nu suportă ÃŪn mod nativ acest lucru, poate fi integrat ÃŪn sisteme distribuite utilizÃĒnd cadre precum Ray:

import ray
from vllm import LLM

<p>@ray.remote(num_gpus=1)
class DistributedLLM:
def __init__(self, nume_model):
self.llm = LLM(model=nume_model)</p>

<p>def generează(self, prompt, parametri):
return self.llm.generate(prompt, parametri)</p>

<p># Inițializați LLM-uri distribuite
llm1 = DistributedLLM.remote("meta-llama/Llama-2-13b-hf")
llm2 = DistributedLLM.remote("meta-llama/Llama-2-13b-hf")</p>

<p># Utilizați-le ÃŪn paralel
rezultat1 = llm1.generate.remote("Prompt 1", parametri_de_eșantionare)
rezultat2 = llm2.generate.remote("Prompt 2", parametri_de_eșantionare)</p>

<p># Obțineți rezultatele
print(ray.get([rezultat1, rezultat2]))

7.3 Monitorizare și Observabilitate

Atunci cÃĒnd serviți LLM ÃŪn producție, monitorizarea este crucială. Deși vLLM nu oferă monitorizare ÃŪncorporată, poate fi integrat cu unelte precum Prometheus și Grafana:

from prometheus_client import start_http_server, Summary
from vllm import LLM

<p># Definiți metrici
TIMP_DE_PROCESARE = Summary('timp_de_procesare_secunde', 'Timp petrecut procesÃĒnd solicitarea')</p>

<p># Inițializați vLLM
llm = LLM(model="meta-llama/Llama-2-13b-hf")</p>

<p># Expuneți metrici
start_http_server(8000)</p>

<p>@TIMP_DE_PROCESARE.time()
def procesează_solicitare(prompt):
return llm.generate(prompt)</p>

# Ciclul dvs. de servire aici

Această configurare vă permite să urmăriți metrici precum timpul de procesare a solicitărilor, care pot fi visualizate ÃŪn dashboarde Grafana.

Concluzie

Servirea eficientă a Modelelor de Limbaj Mari este o sarcină complexă, dar crucială, ÃŪn era inteligenței artificiale. vLLM, cu algoritmul său inovator PagedAttention și implementarea optimizată, reprezintă un pas semnificativ ÃŪnainte ÃŪn direcția facilitării implementării și cost-eficienței LLM.

Prin ÃŪmbunătățirea dramatică a debitului, reducerea pierderilor de memorie și oferirea unor opțiuni de servire mai flexibile, vLLM deschide noi posibilități pentru integrarea modelelor de limbaj puternice ÃŪntr-o gamă largă de aplicații. Indiferent dacă construiți un chatbot, un sistem de generare de conținut sau orice altă aplicație alimentată de NLP, ÃŪnțelegerea și valorificarea unor unelte precum vLLM va fi cheia succesului.

Am petrecut ultimii cinci ani scufundÃĒndu-mă ÃŪn lumea fascinantă a Machine Learning și Deep Learning. Pasinea și expertiza mea m-au condus să contribui la peste 50 de proiecte diverse de inginerie software, cu un focus deosebit pe AI/ML. Curiozitatea mea ÃŪn continuare m-a atras și spre Natural Language Processing, un domeniu pe care sunt dornic să ÃŪl explorez mai departe.