Connect with us

SGLang: Execuția eficientă a programelor de model de limbaj structurat

Inteligență artificială

SGLang: Execuția eficientă a programelor de model de limbaj structurat

mm
SGLang: Efficient Execution of Structured Language Model Programs

Modelele de limbaj de mari dimensiuni (LLM) sunt din ce în ce mai utilizate pentru sarcini complexe care necesită multiple apeluri de generare, tehnici avansate de promptare, flux de control și intrări/ieșiri structurate. Cu toate acestea, sistemele eficiente pentru programarea și executarea acestor aplicații lipsesc. SGLang, un sistem nou introdus, își propune să abordeze acest lucru prin furnizarea execuției eficiente a programelor complexe de model de limbaj. SGLang cuprinde un limbaj frontal și un runtime. Limbajul frontal simplifică programarea cu primitive pentru generare și control al paralelismului, în timp ce runtime-ul accelerează executia prin optimizări noi, cum ar fi RadixAttention pentru reutilizarea cache-ului KV și mașini finite comprimate pentru decodarea mai rapidă a ieșirilor structurate. Experimentele demonstrează că SGLang atinge până la 6,4 ori mai multă eficiență în comparație cu sistemele de inferență de ultimă generație pe diverse modele de limbaj de mari dimensiuni și multimodale, abordând sarcini precum controlul agenților, raționamentul logic, benchmark-urile de învățare în câteva exemple, decodarea JSON, pipeline-urile de generare augmentate cu recuperare și chat-ul multi-turn.

Progresele recente în capacitățile LLM au extins utilitatea lor, permițându-le să gestioneze o gamă mai largă de sarcini generale și să funcționeze ca agenți autonomi. În aceste aplicații, LLM-urile se angajează în planificarea multi-rundă, raționament și interacțiune cu mediile externe. Acest lucru este facilitat prin utilizarea unor instrumente, multiple modalități de intrare și diverse tehnici de promptare, cum ar fi învățarea în câteva exemple, auto-consistența, scheletul de gândire și arborele de gândire. Aceste noi cazuri de utilizare necesită multiple apeluri LLM, adesea dependente, indicând o tendință de utilizare a structurilor multi-apele pentru a finaliza sarcini complexe.

Această schimbare marchează o tranziție de la simpla conversație la o utilizare mai sofisticată și programatică a LLM-urilor, unde programele planifică și controlează procesele de generare ale LLM-urilor. Aceste programe sunt denumite “Programe de model de limbaj” (LM Programe). Tehnicile avansate de promptare și fluxurile de lucru agenților se încadrează în sfera programelor LM. Există două proprietăți comune ale programelor LM: (1) Programele LM implică de obicei multiple apeluri LLM, interspersate cu flux de control pentru a finaliza sarcini complexe și a îmbunătăți calitatea generală. (2) Programele LM primesc intrări structurate și produc ieșiri structurate, permițând compunerea programelor LM și integrarea lor în sisteme software existente.

În acest articol, vom face o analiză mai profundă a cadrului SGLang, explorând arhitectura sa, analizând performanța sa și comparându-l cu cadrele de ultimă generație. Deci, să începem.

Introducere în SGLang

În ciuda utilizării extinse a programelor LM, sistemele actuale pentru exprimarea și executarea lor rămân ineficiente. SGLang identifică două provocări principale asociate cu utilizarea eficientă a programelor LM:

  • Complexitatea programării: Dezvoltarea programelor LM este o sarcină laborioasă și dificilă datorită naturii nededeterminate a LLM-urilor. Acest lucru implică manipularea extinsă a șirurilor de caractere, reglarea experimentală a prompturilor, analiza fragilă a ieșirilor, gestionarea multiplelor modalități de intrare și implementarea mecanismelor de paralelism. Această complexitate reduce semnificativ lizibilitatea chiar și a programelor simple.
  • Ineficiența execuției: Executarea programelor LM este ineficientă din cauza calculului redundant și a utilizării memoriei. Motoarele de inferență de ultimă generație, optimizate pentru a reduce latența și a îmbunătăți debitul, lipsesc cunoștințe directe despre sarcină, rezultând în ineficiențe semnificative. Un exemplu notabil este reutilizarea cache-ului KV, care constă în tensori intermediari reutilizabili esențiali pentru inferența generativă. Sistemele actuale lipsesc mecanisme eficiente pentru a facilita reutilizarea cache-ului KV în cadrul multiplelor apeluri LLM care împărtășesc un prefix comun, conducând la calcule inutile și memoria irosită. De asemenea, decodarea constrânsă pentru ieșiri structurate, cum ar fi modul JSON, este suboptimă, deoarece sistemele existente decodează doar un token odată.

Pentru a aborda aceste provocări, SGLang introduce un limbaj de generare structurat pentru LLM-uri. Ideea de bază este să exploateze sistematic structura multi-apele în programele LM pentru execuție eficientă. Așa cum se arată în figura următoare, SGLang are două părți: un limbaj frontal și un runtime.

Limbajul frontal simplifică programarea programelor LM, iar runtime-ul accelerează executia lor. Aceste părți pot lucra împreună pentru o performanță mai bună sau pot funcționa independent.

SGLang este un limbaj specific de domeniu încorporat în Python, oferind primitive pentru generare (de exemplu, extinde, gen, selectează) și control al paralelismului (de exemplu, fork, join). Este compatibil cu fluxul de control și bibliotecile Python, permițând utilizatorilor să dezvolte fluxuri de lucru avansate de promptare cu sintaxă Python nativă. SGLang include un interpretor și un compilator. Interpretorul gestionează starea promptului ca un flux și trimite operațiuni primitive către flux pentru executare asincronă, asigurând controlul corect asupra sincronizării și paralelismului intra-program. De asemenea, programele SGLang pot fi urmărite și compilate pentru optimizări suplimentare. Runtime-ul SGLang propune câteva optimizări noi pentru a accelera executia programelor LM:

  • RadixAttention: Această tehnică permite reutilizarea automată a cache-ului KV în cadrul multiplelor apeluri de generare. În motoarele de inferență existente, cache-ul KV al unei cereri este eliminat după procesare, împiedicând reutilizarea în cadrul multiplelor apeluri și încetinind executia. SGLang menține un cache LRU al cache-ului KV într-un arbore radix, gestionând cache-ul KV ca un cache tradițional și utilizând arborele radix pentru încărcare, inserare și evacuare eficientă. Acest lucru permite runtime-ului să gestioneze diverse modele de reutilizare în mod eficient.
  • Mașină finită comprimată: Această tehnică permite decodarea mai rapidă a ieșirilor structurate. Sistemele existente urmează constrângerile doar pentru următorul token, putând decoda doar un token odată. În schimb, SGLang analizează constrângerile și construiește o mașină finită comprimată pentru a le reprezenta, comprimând un drum multi-token într-un drum cu un singur pas, atunci când este posibil, permițând decodarea mai multor tokeni deodată pentru o viteză mai mare.
  • Execuția speculativă API: Pentru modelele API, cum ar fi OpenAI’s GPT-4, SGLang introduce execuția speculativă API pentru a optimiza programele multi-apele.

Utilizând SGLang, diverse aplicații LLM au fost implementate, incluzând controlul agenților, raționamentul logic, benchmark-urile de învățare în câteva exemple, decodarea JSON, pipeline-urile de generare augmentate cu recuperare, chat-ul multi-turn și procesarea multi-modală. Performanța a fost testată pe modele, incluzând Llama-7B/70B, Mistral-8x7B, LLaVA-v1.5-7B (imagine) și LLaVA-NeXT-34B (video) pe GPU-uri NVIDIA A10G și A100. Rezultatele experimentale arată că SGLang atinge până la 6,4 ori mai multă eficiență în comparație cu sistemele de programare și inferență existente, incluzând Guidance, vLLM și LMQL.

SGLang: Model de programare și metodologie

Modelul de programare SGLang este introdus printr-un exemplu de rulare, descriind primitivele sale de limbaj și modurile de execuție, și schițând oportunitățile de optimizare a runtime-ului. Acest model simplifică operațiunile laborioase în fluxurile de lucru multi-apele (de exemplu, manipularea șirurilor de caractere, apelurile API, specificarea constrângerilor, paralelismul) prin furnizarea de primitive flexibile și compozabile. SGLang este un limbaj specific de domeniu încorporat în Python. Următoarea figură prezintă un program care evaluează un eseu despre o imagine utilizând metoda de promptare ramificată-rezolvată-reunită.

Funcția multi_dimensional_judge primește trei argumente: `s`, `path` și `essay`. s gestionează starea promptului, path este calea fișierului imagine, iar essay este textul eseu. Noi șiruri de caractere și primitive SGLang pot fi adăugate la starea s pentru executare utilizând operatorul +=. Mai întâi, funcția adaugă imaginea și eseu la prompt. Apoi, verifică dacă eseu este legat de imagine utilizând select, stocând rezultatul în s[“related”]. Dacă este legat, promptul este bifurcat în trei copii pentru evaluare paralelă din diferite dimensiuni, utilizând gen pentru a stoca rezultatele în f[“judgment”]. Următorul, combină judecățile, generează un rezumat și atribuie o notă literară. În final, returnează rezultatele în format JSON, urmând un schema definită de o expresie regulată de constrângere regex. SGLang simplifică foarte mult acest program, deoarece un program echivalent utilizând o interfață similară cu OpenAI ar necesita de 2,1 ori mai multe linii de cod din cauza manipulării manuale a șirurilor de caractere și controlului paralelismului.

SGLang oferă primitive pentru controlul stării promptului, generării și paralelismului, care pot fi utilizate cu sintaxă și biblioteci Python. Iată primitivele:

gen: apelează un model pentru a genera și stochează rezultatele într-o variabilă cu numele specificat în primul său argument. Suportă un argument `regex` pentru a constrânge ieșirea să urmeze o gramatică definită de o expresie regulată (de exemplu, un schema JSON).

  • select: apelează un model pentru a alege opțiunea cu cea mai mare probabilitate dintr-o listă.
  • += sau extinde: adaugă un șir de caractere la prompt.
  • [nume_variabilă]: preia rezultatele unei generări.
  • fork: creează ramificări paralele ale stării promptului.
  • join: reunește starea promptului.
  • imagine și video: primesc intrări de imagine și video.

Cea mai simplă modalitate de a executa un program SGLang este prin intermediul unui interpretor, unde un prompt este tratat ca un flux asincron. Primitive precum extinde, gen și select sunt trimise către flux pentru executare asincronă. Aceste apeluri non-blocante permit codului Python să continue rularea fără a aștepta finalizarea generării, similar cu lansarea kernel-urilor CUDA în mod asincron. Fiecare prompt este gestionat de un executor de flux într-un fir de fundal, permițând paralelismul intra-program. Preluarea rezultatelor generării va bloca până când acestea sunt gata, asigurând sincronizarea corectă. Alternativ, programele SGLang pot fi compilate ca grafuri computaționale și executate cu un executor de graf, permițând optimizări suplimentare. Acest articol utilizează modul interpretor implicit și discută rezultatele modului compilator în Anexa D. SGLang suportă modele cu greutăți deschise cu propriul său runtime SGLang (SRT), precum și modele API, cum ar fi OpenAI și Anthropic.

Sistemele de programare pentru LLM-uri pot fi clasificate în sisteme de nivel înalt (de exemplu, LangChain, DSPy) și sisteme de nivel scăzut (de exemplu, LMQL, Guidance, SGLang). Sistemele de nivel înalt oferă prompturi predefinite sau generate automat, cum ar fi optimizatorul de prompturi DSPy. Sistemele de nivel scăzut nu alterează în general prompturile, dar permit manipularea directă a prompturilor și a primitivelor. SGLang este un sistem de nivel scăzut, asemănător cu LMQL și Guidance. Următoarea tabelă compară caracteristicile lor.

SGLang se concentrează mai mult pe eficiența runtime și vine cu propriul său runtime co-proiectat, permițând optimizări noi. Limbajele de nivel înalt (de exemplu, DSPy) pot fi compilate în limbaje de nivel scăzut (de exemplu, SGLang). Integrarea SGLang ca backend în DSPy pentru o eficiență mai bună a runtime-ului este demonstrată mai târziu.

Exemplul de mai sus ilustrează operațiunile RadixAttention cu o politică de evacuare LRU la nouă puncte de timp, prezentând evoluția dinamică a arborelui radix în răspuns la diverse solicitări. Aceste solicitări includ două sesiuni de chat, o serie de întrebări de învățare în câteva exemple și mostre de auto-consistență. Fiecare muchie a arborelui poartă o etichetă care denotă un șir de caractere sau o secvență de tokeni. Nodurile sunt codificate cu culori pentru a reflecta stări diferite: verde pentru noduri nou adăugate, albastru pentru noduri cache accesate în timpul punctului de timp și roșu pentru noduri evacuate.

Pasul 1: Arborele radix este inițial gol.

Pasul 2: Serverul procesează un mesaj de intrare al utilizatorului “Hello” și răspunde cu ieșirea LLM “Hi”. Promptul sistemului “You are a helpful assistant”, mesajul utilizatorului “Hello!” și răspunsul LLM “Hi!” sunt consolidate în arbore ca o muchie legată de un nod nou.

Pasul 3: O nouă promptă ajunge, și serverul găsește prefixul promptei (adică prima tură a conversației) în arborele radix și reutilizează cache-ul KV. Noua tură este adăugată la arbore ca un nod nou.

Pasul 4: O nouă sesiune de chat începe. Nodul din Pasul 3 este divizat în două noduri pentru a permite celor două sesiuni de chat să împărtășească promptul sistemului.

Pasul 5: A doua sesiune de chat continuă. Cu toate acestea, din cauza limitărilor de memorie, un nod din Pasul 4 trebuie evacuat. Noua tură este adăugată după nodul rămas din Pasul 4.

Pasul 6: Serverul primește o întrebare de învățare în câteva exemple, o procesează și o inserează în arbore. Nodul rădăcină este divizat deoarece noua întrebare nu împărtășește niciun prefix cu nodurile existente.

Pasul 7: Serverul primește o serie de întrebări suplimentare de învățare în câteva exemple. Aceste întrebări împărtășesc același set de exemple, astfel încât un nod din Pasul 6 este divizat pentru a permite împărtășirea.

Pasul 8: Serverul primește un nou mesaj de la prima sesiune de chat. Evacuează toate nodurile din a doua sesiune de chat, deoarece acestea sunt cele mai puțin recent utilizate.

Pasul 9: Serverul primește o solicitare de a genera mai multe răspunsuri pentru întrebările dintr-un nod din Pasul 8, probabil pentru promptarea auto-consistenței. Pentru a face loc pentru aceste solicitări, multiple noduri sunt evacuate.

Acest exemplu demonstrează modul în care RadixAttention gestionează alocarea dinamică și evacuarea nodurilor în răspuns la diverse solicitări, asigurând reutilizarea eficientă a cache-ului KV și gestionarea memoriei.

SGLang: Evaluare și rezultate

Rezultate pe modele cu greutăți deschise

Rezultatele latenței și debitului sunt prezentate în figurile următoare. SGLang îmbunătățește debitul cu până la 6,4 ori și reduce latența cu până la 3,7 ori. Aceste îmbunătățiri rezultă din reutilizarea cache-ului KV, exploatarea paralelismului în cadrul unui singur program și decodarea mai rapidă a ieșirilor structurate.

Pe aceste benchmark-uri, rata de lovire a cache-ului variază de la 50% la 99%. Figura 13 (Anexa) listează ratele de lovire a cache-ului atinse și optime pentru toate, arătând că abordarea de programare conștientă de cache a SGLang se apropie de 96% de rata de lovire optimă în medie.

Rezultate pe modele mai mari cu paralelism de tensori

Modelele mai mari, Mixtral-8x7B și Llama-70B, au fost testate cu paralelism de tensori pe același set de benchmark-uri, și rezultatele sunt raportate în figura următoare. Îmbunătățirea pe modelele mai mari arată o tendință similară cu cea observată pe modelele mai mici, indicând că optimizarea SGLang se generalizează bine la modelele mai mari. Guidance și LMQL au fost omise din cauza lipsei de implementări eficiente ale paralelismului de tensori.

Rezultate pe modele multimodale

SGLang are suport nativ pentru modele multimodale cu primitivele de imagine și video. Optimizările din acest articol sunt compatibile cu modelele multimodale. Pentru RadixAttention, hash-ul intrărilor de imagine este calculat și utilizat ca cheie în arborele radix, permițând reutilizarea cache-ului KV al tokenilor de imagine din aceeași imagine. LLaVA-v1.5-7B (imagine) a fost rulat pe llava-bench-in-the-wild și LLaVA-NeXT-34B (video) pe ActivityNet. Deoarece aceste modele nu sunt bine suportate de alte sisteme de referință, implementarea originală a autorilor de modele în Hugging Face Transformers a fost utilizată ca referință. Așa cum se arată în tabela următoare, SGLang oferă un debit de până la 6 ori mai mare pe aceste benchmark-uri. În llava-bench-in-the-wild, au fost gestionate multiple întrebări despre aceeași imagine, și SGLang a reutilizat cache-ul KV în acest caz.

Implementare de producție

SGLang a fost implementat în Chatbot Arena pentru a servi modele cu greutăți deschise. Din cauza traficului scăzut pentru unele modele, doar un singur lucrător SGLang deservește fiecare. După o lună, s-a observat o rată de lovire a cache-ului RadixAttention de 52,4% pentru LLaVA-Next-34B și 74,1% pentru Vicuna-33B. Lovirile cache-ului proveneau din mesaje sistem comune, exemple de imagini reutilizate frecvent și istoricul conversațiilor multi-tur. Acest lucru a redus latența primului token cu o medie de 1,7 ori pentru Vicuna-33B.

Gânduri finale

În acest articol, am discutat despre SGLang, un sistem nou introdus, care își propune să abordeze această problemă prin furnizarea execuției eficiente a programelor complexe de model de limbaj. SGLang cuprinde un limbaj frontal și un runtime. Limbajul frontal simplifică programarea cu primitive pentru generare și control al paralelismului, în timp ce runtime-ul accelerează executia prin optimizări noi, cum ar fi RadixAttention pentru reutilizarea cache-ului KV și mașini finite comprimate pentru decodarea mai rapidă a ieșirilor structurate. Experimentele demonstrează că SGLang atinge până la 6,4 ori mai multă eficiență în comparație cu sistemele de inferență de ultimă generație pe diverse modele de limbaj de mari dimensiuni și multimodale, abordând sarcini precum controlul agenților, raționamentul logic, benchmark-urile de învățare în câteva exemple, decodarea JSON, pipeline-urile de generare augmentate cu recuperare și chat-ul multi-turn.

"Un inginer de profesie, un scriitor din inimă". Kunal este un scriitor tehnic cu o dragoste și o înțelegere profundă a inteligenței artificiale și a învățării automate, dedicat simplificării conceptelor complexe din aceste domenii prin documentația sa captivantă și informativă.