Modele și platforme AI
Optimizarea implementării LLM: vLLM PagedAttention și viitorul servirii eficiente a IA
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 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
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.
















