Modele i platformy AI

SGLang: Wydajna Wykonywanie Programów Modeli Językowych

mm
Dodaj Unite.AI do preferowanych źródeł w Google

Duże modele językowe (LLM) są coraz częściej wykorzystywane do złożonych zadań wymagających wielu wywołań generacji, zaawansowanych technik promptowania, sterowania przepływem i strukturalnych danych wejściowych/wyjściowych. Jednak efektywne systemy do programowania i wykonywania tych aplikacji są niedostateczne. SGLang, nowo wprowadzony system, ma na celu rozwiązanie tego problemu, zapewniając wydajną wykonywanie złożonych programów modeli językowych. SGLang składa się z frontendu i środowiska wykonawczego. Frontend ułatwia programowanie dzięki prymitywom generacji i kontroli paralelizmu, podczas gdy środowisko wykonawcze przyspiesza wykonywanie dzięki nowym optymalizacjom, takim jak RadixAttention do ponownego użycia pamięci podręcznej KV i skompresowanym maszynom stanu skończonego dla szybszego dekodowania strukturalnych danych wyjściowych. Eksperymenty pokazują, że SGLang osiąga nawet 6,4-krotnie wyższą wydajność w porównaniu z systemami inferencyjnymi na różnych dużych modelach językowych i multimodalnych, rozwiązując zadania takie jak kontrola agenta, rozumność logiczna, benchmarki few-shot learning, dekodowanie JSON, potok generacji z uzupełnieniem i rozmowa wieloobrotowa.

Niedawne postępy w możliwościach LLM rozszerzyły ich przydatność, umożliwiając im obsługę szerszego zakresu zadań ogólnych i funkcjonowanie jako autonomiczne agenci. W tych aplikacjach LLM angażują się w wieloetapowe planowanie, rozumność i interakcje z zewnętrznymi środowiskami. Jest to ułatwione dzięki użyciu narzędzi, wielu modalności wejściowych i różnych technik promptowania, takich jak few-shot learning, samokonsystencja, szkielet myśli i drzewo myśli. Te nowe przypadki użycia wymagają wielu, często zależnych, wywołań generacji LLM, wskazując na tendencję do używania struktur wielowyzwań do wykonania złożonych zadań.

Ta zmiana oznacza przejście od prostych rozmów do bardziej zaawansowanego programowego użycia LLM, gdzie programy planują i kontrolują procesy generacji LLM. Te programy nazywane są “Programami Modeli Językowych” (LM Programy). Zaawansowane techniki promptowania i przepływy agenci należą do zakresu LM programów. Istnieją dwie wspólne właściwości LM programów: (1) LM programy zwykle obejmują wiele wywołań LLM przeplatanych z kontrolą przepływu, aby wykonać złożone zadania i poprawić jakość. (2) LM programy otrzymują strukturalne dane wejściowe i wytwarzają strukturalne dane wyjściowe, umożliwiając kompozycję LM programów i integrację z istniejącymi systemami oprogramowania.

W tym artykule będziemy się głębiej zajmować ramą SGLang, eksplorując jego architekturę, analizując jego wydajność i porównując go z ramami stanu sztuki. Zatem zacznijmy.

Wprowadzenie do SGLang

Pomimo powszechnego użycia LM programów, obecne systemy do ich wyrażania i wykonywania są niewydajne. SGLang identyfikuje dwa podstawowe wyzwania związane z efektywnym użyciem LM programów:

  • Złożoność programowania: Tworzenie LM programów jest uciążliwe i trudne ze względu na nieprzewidywalną naturę LLM. Obejmuje to obszerną manipulację ciągami, eksperymentalne dostosowywanie promptów, kruche parsowanie danych wyjściowych, obsługę wielu modalności wejściowych i wdrażanie mechanizmów paralelizmu. Ta złożoność znacznie redukuje czytelność nawet prostych programów.
  • Niewydajność wykonywania: Wykonywanie LM programów jest niewydajne ze względu na zbędne obliczenia i użycie pamięci. Systemy inferencyjne stanu sztuki, zoptymalizowane w celu zmniejszenia opóźnień i poprawy wydajności, nie mają bezpośredniej wiedzy o obciążeniu, co skutkuje znacznymi niewydajnościami. Godny uwagi przykład jest ponowne użycie pamięci podręcznej Key-Value (KV), która składa się z ponownie używalnych pośrednich tensorów niezbędnych do inferencji generatywnej. Obecne systemy nie mają skutecznych mechanizmów umożliwiających ponowne użycie pamięci podręcznej KV między wieloma wywołaniami LLM, które dzielą wspólny prefiks, co prowadzi do niepotrzebnych obliczeń i marnowania pamięci. Ponadto, dekodowanie z ograniczeniami dla strukturalnych danych wyjściowych, takich jak tryb JSON, jest nieoptymalne, ponieważ istniejące systemy dekodują tylko jeden token na raz.

Aby rozwiązać te wyzwania, SGLang wprowadza Język Generacji Strukturalnej dla LLM. Podstawową ideą jest systematyczne wykorzystanie struktury wielowyzwań w LM programach do efektywnej realizacji. Jak pokazano na poniższym rysunku, SGLang składa się z dwóch części: frontendu i środowiska wykonawczego.

Frontend ułatwia programowanie LM programów, a środowisko wykonawcze przyspiesza ich wykonywanie. Te części mogą współpracować w celu uzyskania lepszej wydajności lub funkcjonować niezależnie.

SGLang jest językiem specyficznym dla domeny, osadzonym w Pythonie, zapewniającym prymitywy generacji (np. extend, gen, select) i kontroli paralelizmu (np. fork, join). Jest on kompatybilny z kontrolą przepływu i bibliotekami Pythona, umożliwiając użytkownikom łatwe tworzenie zaawansowanych przepływów promptowania z natywną składnią Pythona. SGLang zawiera interpreter i kompilator. Interpreter zarządza stanem promptu jako strumieniem i przesyła operacje prymitywów do strumienia do asynchronicznego wykonywania, zapewniając właściwą kontrolę nad synchronizacją i paralelizmem wewnątrz programu. Ponadto programy SGLang mogą być śledzone i skompilowane w celu dalszych optymalizacji.Środowisko wykonawcze SGLang proponuje kilka nowych optymalizacji w celu przyspieszenia wykonywania LM programów:

  • RadixAttention: Ta technika umożliwia automatyczne ponowne użycie pamięci podręcznej KV między wieloma wywołaniami generacji. W istniejących silnikach inferencyjnych pamięć podręczna KV jest porzucana po przetworzeniu, uniemożliwiając ponowne użycie między wywołaniami i spowalniając wykonywanie. SGLang utrzymuje pamięć podręczną pamięci podręcznej KV wewnątrz drzewa radix, zarządzając pamięcią podręczną KV jako tradycyjną pamięć podręczną i używając drzewa radix do wydajnego dopasowania, wstawiania i usuwania. To pozwala środowisku wykonawczemu na efektywne zarządzanie różnymi wzorcami ponownego użycia.
  • Skompresowana Maszyna Stanu Skończonego: Ta technika umożliwia szybsze dekodowanie z ograniczeniami dla strukturalnych danych wyjściowych. Istniejące systemy dekodują tylko jeden token na raz, podążając za ograniczeniami tylko dla następnego tokenu. Zamiast tego, SGLang analizuje ograniczenia i tworzy skompresowaną maszynę stanu skończonego, aby je reprezentować, kompresując ścieżkę wielu tokenów w jedną ścieżkę, gdy jest to możliwe, umożliwiając dekodowanie wielu tokenów na raz dla szybszej prędkości.
  • Wykonywanie Spekulatywne API: Dla modeli API, takich jak OpenAI GPT-4, SGLang wprowadza wykonywanie spekulatywne API w celu optymalizacji programów wielowyzwań.

Używając SGLang, zaimplementowano różne aplikacje LLM, w tym kontrolę agenta, rozumność logiczną, benchmarki few-shot learning, dekodowanie JSON, potok generacji z uzupełnieniem, rozmowę wieloobrotową i przetwarzanie multimodalne. Wydajność została przetestowana na modelach, w tym Llama-7B/70B, Mistral-8x7B, LLaVA-v1.5-7B (obraz) i LLaVA-NeXT-34B (wideo) na procesorach graficznych NVIDIA (NVDA ) A10G i A100. Wyniki eksperymentów pokazują, że SGLang osiąga nawet 6,4-krotnie wyższą wydajność w porównaniu z istniejącymi systemami programowania i inferencji, w tym Guidance, vLLM i LMQL.

SGLang: Model Programowania i Metodologia

Model programowania SGLang jest wprowadzony za pomocą uruchomionego przykładu, opisującego językowe prymitywy i tryby wykonywania, oraz przedstawiającego możliwości optymalizacji środowiska wykonawczego. Ten model upraszcza uciążliwe operacje w przepływach wielowyzwań (np. manipulację ciągami, wywołania API, określanie ograniczeń, paralelizm) poprzez dostarczanie elastycznych i komponowalnych prymitywów. SGLang jest językiem specyficznym dla domeny, osadzonym w Pythonie. Poniższy rysunek przedstawia program, który ocenia esej o obrazie przy użyciu metody promptowania gałęzi-rozwiązywania-łączenia.

Funkcja multi_dimensional_judge przyjmuje trzy argumenty: `s`, `path` i `essay`. s zarządza stanem promptu, path jest ścieżką pliku obrazu, a essay jest tekstem eseju. Nowe ciągi i prymitywy SGLang mogą być dołączane do stanu s do asynchronicznego wykonywania przy użyciu operatora +=. Najpierw funkcja dodaje obraz i esej do promptu. Następnie sprawdza, czy esej jest związany z obrazem przy użyciu select, zapisując wynik w s[“related”]. Jeśli są związane, prompt jest rozwidlany w trzy kopie do oceny równoległej z różnych wymiarów, używając gen do zapisania wyników w f[“judgment”]. Następnie łączy oceny, generuje podsumowanie i przypisuje ocenę literową. Na końcu zwraca wyniki w formacie JSON, postępując zgodnie ze schematem określonym przez wyrażenie regularne regex. SGLang znacznie upraszcza ten program, ponieważ równoważny program przy użyciu interfejsu podobnego do OpenAI wymagałby 2,1-krotnie więcej linii kodu ze względu na ręczną manipulację ciągami i kontrolę paralelizmu.

SGLang dostarcza prymitywy do kontroli stanu promptu, generacji i paralelizmu, które mogą być używane z składnią Pythona i bibliotekami. Oto prymitywy:

gen: Wywołuje model w celu generacji i zapisuje wyniki w zmiennej o nazwie określonej w pierwszym argumencie. Obsługuje argument regex, aby ograniczyć dane wyjściowe do postaci gramatyki określonej przez wyrażenie regularne (np. schemat JSON).

  • select: Wywołuje model w celu wyboru najbardziej prawdopodobnej opcji z listy.
  • += lub extend: Dołącza ciąg do promptu.
  • [nazwa_zmiennej]: Pobiera wyniki generacji.
  • fork: Tworzy równoległe rozwidlenia stanu promptu.
  • join: Ponownie łączy stan promptu.
  • obraz i wideo: Przyjmują dane wejściowe obrazu i wideo.

Najprostszy sposób wykonywania programu SGLang to przez interpreter, gdzie prompt jest traktowany jako strumień asynchroniczny. Prymitywy takie jak extend, gen i select są przesyłane do strumienia do asynchronicznego wykonywania. Te nieblokujące wywołania pozwalają kodowi Pythona na kontynuowanie wykonywania bez oczekiwania na zakończenie generacji, podobnie jak uruchamianie jąder CUDA w sposób asynchroniczny. Każdy prompt jest zarządzany przez wykonawcę strumienia w wątku tła, umożliwiając paralelizm wewnątrz programu. Pobieranie wyników generacji zablokuje wykonanie do momentu, aż będą gotowe, zapewniając poprawną synchronizację. Alternatywnie, programy SGLang mogą być skompilowane jako grafy obliczeniowe i wykonywane z wykonywaniem grafu, umożliwiając dalsze optymalizacje. Ten artykuł używa trybu interpretera domyślnie i omawia wyniki trybu kompilatora w Dodatku D. SGLang obsługuje modele o otwartych wagach za pomocą własnego środowiska wykonawczego SGLang (SRT), a także modele API, takie jak OpenAI i Anthropic.

Systemy programowania dla LLM można klasyfikować jako wysokopoziomowe (np. LangChain, DSPy) i niskopoziomowe (np. LMQL, Guidance, SGLang). Systemy wysokopoziomowe dostarczają predefiniowane lub automatycznie generowane prompty, takie jak optymalizator promptów DSPy. Systemy niskopoziomowe zwykle nie modyfikują promptów, ale pozwalają na bezpośrednią manipulację promptami i prymitywami. SGLang jest systemem niskopoziomowym, podobnym do LMQL i Guidance. Poniższa tabela porównuje ich funkcje.

SGLang koncentruje się bardziej na efektywności środowiska wykonawczego i jest wyposażony w własne współprojektowane środowisko wykonawcze, umożliwiające nowe optymalizacje. Języki wysokopoziomowe (np. DSPy) mogą być skompilowane do języków niskopoziomowych (np. SGLang). Integracja SGLang jako backendu w DSPy w celu poprawy efektywności środowiska wykonawczego jest pokazana później.

Powyższy przykład ilustruje operacje RadixAttention z polityką usuwania LRU w dziewięciu punktach czasowych, pokazując dynamiczną ewolucję drzewa radix w odpowiedzi na różne żądania. Żądania te obejmują dwie sesje czatu, partię pytań few-shot learning i próbkowanie samokonsystencji. Każdy krawędź drzewa nosi etykietę oznaczającą podciąg lub sekwencję tokenów. Węzły są kodowane kolorami, aby odzwierciedlić różne stany: zielony dla nowo dodanych węzłów, niebieski dla węzłów pamięci podręcznej dostępu w czasie punktu i czerwony dla węzłów, które zostały usunięte.

Krok 1: Drzewo radix jest początkowo puste.

Krok 2: Serwer przetwarza przychodzącą wiadomość użytkownika “Cześć” i odpowiada dane wyjściowe LLM “Witaj”. Systemowy prompt “Jesteś pomocnym asystentem”, wiadomość użytkownika “Cześć!” i odpowiedź LLM “Witaj!” są skonsolidowane w drzewie jako jeden krawędź połączony z nowym węzłem.

Krok 3: Nowy prompt przychodzi, a serwer znajduje prefiks promptu (tj. pierwszy obrót rozmowy) w drzewie radix i ponownie używa jego pamięci podręcznej KV. Nowy obrót jest dołączany do drzewa jako nowy węzeł.

Krok 4: Nowa sesja czatu zaczyna się. Węzeł z kroku 3 jest podzielony na dwa węzły, aby umożliwić dwóm sesjom czatu współdzielenie systemowego promptu.

Krok 5: Druga sesja czatu kontynuuje. Jednak ze względu na ograniczenia pamięci, węzeł z kroku 4 musi być usunięty. Nowy obrót jest dołączany po pozostałym węźle z kroku 4.

Krok 6: Serwer otrzymuje zapytanie few-shot learning, przetwarza je i wstawia do drzewa. Węzeł korzeniowy jest podzielony, ponieważ nowe zapytanie nie dzieli prefiksu z istniejącymi węzłami.

Krok 7: Serwer otrzymuje partię dodatkowych zapytań few-shot learning. Zapytania te dzielą ten sam zestaw przykładów few-shot, więc węzeł z kroku 6 jest podzielony, aby umożliwić współdzielenie.

Krok 8: Serwer otrzymuje nową wiadomość z pierwszej sesji czatu. Usuwa wszystkie węzły z drugiej sesji czatu, ponieważ są one najmniej niedawno używane.

Krok 9: Serwer otrzymuje żądanie próbkowania więcej odpowiedzi na pytania w węźle z kroku 8, prawdopodobnie do celów promptowania samokonsystencji. Aby zrobić miejsce dla tych żądań, wiele węzłów jest usuwanych.

Ten przykład pokazuje, jak RadixAttention zarządza dynamicznym przydziałem i usuwaniem węzłów w odpowiedzi na różne typy żądań, zapewniając efektywne ponowne użycie pamięci podręcznej KV i zarządzanie pamięcią.

SGLang: Ocena i Wyniki

Wyniki na Modelach Otwartych

Wyniki opóźnienia i wydajności są przedstawione na poniższych rysunkach. SGLang poprawia wydajność nawet o 6,4-krotnie i redukuje opóźnienie nawet o 3,7-krotnie. Te poprawy wynikają z ponownego użycia pamięci podręcznej KV, wykorzystania paralelizmu wewnątrz programu i szybszego dekodowania z ograniczeniami.

Na tych benchmarkach współczynnik trafień w pamięci podręcznej wynosi od 50% do 99%. Rysunek 13 (w Dodatku) wymienia osiągnięte i optymalne współczynniki trafień w pamięci podręcznej dla wszystkich z nich, pokazując, że podejście SGLang do planowania zorientowanego na pamięć podręczną osiąga średnio 96% optymalnego współczynnika trafień.

Wyniki na Większych Modelach z Paralelizmem Tensorowym

Większe modele, Mixtral-8x7B i Llama-70B, zostały przetestowane z paralelizmem tensorowym na tym samym zestawie benchmarków, a wyniki są przedstawione na poniższym rysunku. Przewaga na większych modelach pokazuje tendencję podobną do tej obserwowanej na mniejszych modelach, wskazując, że optymalizacja SGLang dobrze skaluje się na większe modele. Guidance i LMQL zostały pominięte ze względu na brak efektywnych implementacji paralelizmu tensorowego.

Wyniki na Modelach Wielomodalnych

SGLang ma natywny wsparcie dla modeli wielomodalnych dzięki prymitywom obrazu i wideo. Optymalizacje w tym artykule są kompatybilne z modelami wielomodalnymi. Dla RadixAttention, hash danych wejściowych obrazu jest obliczany i używany jako klucz w drzewie radix, umożliwiając ponowne użycie pamięci podręcznej KV tokenów obrazu z tego samego obrazu. LLaVA-v1.5-7B (obraz) został uruchomiony na llava-bench-in-the-wild, a LLaVA-NeXT-34B (wideo) na ActivityNet. Ponieważ te modele nie są dobrze obsługiwane przez inne systemy bazowe, użyto oryginalnej implementacji autorów modelu w Hugging Face Transformers jako bazę. Jak pokazano w poniższej tabeli, SGLang zapewnia wydajność nawet o 6-krotnie wyższą na tych benchmarkach. W llava-bench-in-the-wild, wiele pytań o ten sam obraz było obsługiwanych, a środowisko wykonawcze SGLang ponownie używało pamięci podręcznej KV w tym przypadku.

Wdrożenie Produkcyjne

SGLang został wdrożony w Chatbot Arena do obsługi modeli o otwartych wagach. Ze względu na niski ruch dla niektórych modeli, tylko jeden robot SGLang obsługuje każdy. Po miesiącu zaobserwowano współczynnik trafień pamięci podręcznej RadixAttention wynoszący 52,4% dla LLaVA-Next-34B i 74,1% dla Vicuna-33B. Trafienia w pamięci podręcznej pochodziły z wspólnych wiadomości systemowych, często ponownie używanych przykładów obrazów i historii rozmów wieloobrotowych. To zmniejszyło opóźnienie pierwszego tokenu o średnio 1,7-krotnie dla Vicuna-33B.

Końcowe Myśli

W tym artykule omówiliśmy SGLang, nowo wprowadzony system, który ma na celu zapewnienie wydajnej realizacji złożonych programów modeli językowych. SGLang składa się z frontendu i środowiska wykonawczego. Frontend ułatwia programowanie dzięki prymitywom generacji i kontroli paralelizmu, podczas gdy środowisko wykonawcze przyspiesza wykonywanie dzięki nowym optymalizacjom, takim jak RadixAttention do ponownego użycia pamięci podręcznej KV i skompresowanym maszynom stanu skończonego dla szybszego dekodowania strukturalnych danych wyjściowych. Eksperymenty pokazują, że SGLang osiąga nawet 6,4-krotnie wyższą wydajność w porównaniu z systemami inferencyjnymi na różnych dużych modelach językowych i multimodalnych, rozwiązując zadania takie jak kontrola agenta, rozumność logiczna, benchmarki few-shot learning, dekodowanie JSON, potok generacji z uzupełnieniem i rozmowę wieloobrotową.

"Inżynier z zawodu, pisarz z serca". Kunal jest technicznym pisarzem z głęboką miłością i zrozumieniem AI i ML, poświęconym uproszczeniu złożonych pojęć w tych dziedzinach poprzez swoje angażujące i informacyjne dokumentacje.