Co się dzieje, gdy lokalne usługi AI rywalizują o pamięć akceleratora?

Eva Wong jest Technicznym pisarzem i stałym majsterkowiczem w ZimaSpace. Całe życie geek z pasją do homelabów i oprogramowania open-source, specjalizuje się w tłumaczeniu skomplikowanych koncepcji technicznych na przystępne, praktyczne przewodniki. Eva wierzy, że samodzielne hostowanie powinno być zabawą, a nie czymś onieśmielającym. Poprzez swoje samouczki umożliwia społeczności rozwiewanie tajemnic konfiguracji sprzętu, od budowy pierwszego NAS po opanowanie kontenerów Docker.

Gdy lokalne usługi AI konkurują o pamięć akceleratora, każdy runtime zmniejsza pojemność dostępną dla innych modeli, żądań, pamięci podręcznych i tensorów tymczasowych.

Domowy serwer może obsługiwać czat, embeddingi, generowanie obrazów, rozpoznawanie mowy, syntezę mowy, wykrywanie obiektów i analizę obrazu z kamer za pośrednictwem oddzielnych kontenerów lub procesów. Ich pulpity mogą wyglądać na bezczynne, podczas gdy wagi modeli i pule alokatora pozostają załadowane w tej samej pamięci GPU, NPU lub akceleratora ze współdzieloną pamięcią. Nowe żądanie potrzebuje wtedy miejsca na stan promptu, aktywacje i bufory wyjściowe, których statyczny rozmiar modelu nie ujawniał. Poniższe sekcje wyjaśniają, jak oddzielne usługi zmieniają nominalną pojemność akceleratora w błędy przyjmowania żądań i niestabilne opóźnienia.

Każda usługa wnosi więcej niż tylko wagi modelu

Załadowany model zajmuje pamięć na parametry, ale aktywne wnioskowanie wymaga również bibliotek runtime, kontekstów wykonania, tymczasowych obszarów roboczych, buforów wejściowych, aktywacji i stanu zależnego od konkretnego żądania.

Badania nad obsługą dużych modeli językowych wskazują na pamięć podręczną KV jako główne ograniczenie współbieżności, ponieważ rośnie ona wraz z liczbą aktywnych sekwencji i długością kontekstu. Model, który mieści się w pamięci podczas bezczynności, może przestać działać, gdy aktywnych stanie się kilka długich żądań.

Usługi wizyjne, dyfuzyjne, głosowe i embeddingowe wykorzystują różne wzorce zużycia pamięci tymczasowej. Ich szczytowe alokacje mogą się nakładać, nawet gdy średnie wykorzystanie pozostaje niskie.

Oddzielne procesy powielają kontekst i narzut runtime

Uruchamianie każdej funkcji AI we własnym kontenerze poprawia separację operacyjną, ale oddzielne procesy mogą tworzyć osobne konteksty akceleratora, biblioteki, pule alokatora i kopie współdzielonych komponentów modeli.

Systemy wielomodelowe badają obsługę wielu modeli, ponieważ naiwne rozmieszczenie jednego modelu na usługę marnuje zarówno pamięć, jak i moc obliczeniową. Skoordynowane współlokowanie może skuteczniej wykorzystywać pojemność niż niezależne runtime’y, z których każdy zakłada, że kontroluje urządzenie.

Dwie usługi korzystające z tego samego tokenizera, enkodera obrazu lub modelu językowego nie współdzielą automatycznie jednej fizycznej kopii. Współdzielenie wymaga obsługi po stronie runtime’u i zgodnych granic procesów.

Kara za duplikację jest najbardziej widoczna na małych akceleratorach, gdzie kilkaset megabajtów pamięci kontekstu i narzutu bibliotek może przesądzić o tym, czy uruchomi się kolejny model.

Zarezerwowane pule mogą ukrywać pamięć przed innymi runtime’ami

Frameworki często zachowują zwolnione bloki, aby kolejne żądania mogły uniknąć kosztownej alokacji urządzenia i synchronizacji. Usługa zgłasza mniejszą ilość aktywnie przydzielonej pamięci, jednak inny proces nadal nie może użyć zarezerwowanej pamięci fizycznej.

Systemy takie jak multipleksowanie statystyczne traktują rozmieszczanie modeli i wzorce skokowego obciążenia jako problem globalny, zamiast pozwalać każdemu serwerowi modeli rezerwować zasoby na własny najgorszy przypadek. Niezależne usługi lokalne nie mają takiego globalnego wglądu, chyba że narzuci go orkiestrator.

Wyjaśnia to, dlaczego akcelerator może wykazywać niskie wykorzystanie obliczeniowe, a mimo to odrzucać nowy model. Pojemność zajmują wagi, zarezerwowane bloki lub pofragmentowane wolne obszary, a nie aktywne kernele.

-15% OFF

Konkurencja zmienia opóźnienia, zanim doprowadzi do błędu braku pamięci

Runtime może reagować na niski poziom pamięci przez zmniejszenie rozmiaru partii, dopuszczanie mniejszej liczby równoległych sekwencji, ponowne obliczanie eksmitowanego stanu, przenoszenie warstw do pamięci RAM procesora lub wyładowanie innego modelu.

Aegaeon wykorzystuje harmonogramowanie na poziomie tokenów do koordynowania wielu modeli przy zmiennym zapotrzebowaniu. Domowy serwer bez porównywalnej koordynacji często ujawnia niedobór jako wolniejsze generowanie pierwszych tokenów, przerwy, przełączanie modeli lub nieprzewidywalne oczekiwanie w kolejce.

Artykuł ZimaSpace o współbieżności rodzinnej pokazuje tę samą granicę na poziomie żądań: aktywne rozmowy konkurują o pamięć i uwagę harmonogramu, nawet gdy testy jednego użytkownika są szybkie.

Wyjątek braku pamięci to tylko końcowy tryb awarii. Niestabilność opóźnień i spadek przepustowości często pojawiają się wcześniej.

Eksmisja modelu zamienia natychmiastową odpowiedź na pojemność

Wyładowanie nieaktywnego modelu zwalnia duży, ciągły obszar dla innej usługi. Kolejne żądanie do eksmitowanej usługi musi ponownie załadować wagi i odbudować stan runtime’u, zamieniając presję na pamięć w opóźnienie zimnego startu.

WarmServe bada rozmieszczanie uwzględniające eksmisję, ponieważ częste przełączanie pogarsza czas do wygenerowania pierwszego tokena. Utrzymywanie każdego modelu w stanie gotowości jest szybsze tylko wtedy, gdy akcelerator ma wystarczająco dużo pamięci na łączne stany rezydentne i aktywne.

W przypadku domowego serwera właściwa polityka zależy od obciążenia. Sterowanie głosowe może zasługiwać na stałą obecność w pamięci, podczas gdy okazjonalne generowanie obrazów może tolerować ponowne ładowanie.

Jeden menedżer zasobów może egzekwować rzeczywiste granice pojemności

W miarę możliwości koordynuj usługi za pośrednictwem jednego serwera wnioskowania albo przypisuj im wyraźne limity pamięci, widoczność urządzeń, zasady rezydencji modeli, limity współbieżności i priorytety.

Najnowsze prace nad balonowaniem pamięci pokazują, dlaczego statyczna alokacja marnuje pojemność, gdy popularność modeli i obciążenie żądaniami się zmieniają. Dynamiczne współdzielenie może poprawić wykorzystanie, ale wymaga jednego systemu obserwującego wszystkie konkurujące obciążenia.

Mierz dla każdej usługi wagi, zarezerwowaną pamięć, aktywne alokacje, pamięć podręczną KV, współbieżność żądań, długość kontekstu, rozmiar partii i częstotliwość przełączania modeli. Globalna suma dla urządzenia bez przypisania zasobów do poszczególnych usług nie wyjaśni kolizji.

W pierwszej kolejności chroń usługi wrażliwe na opóźnienia, planuj embeddingi i indeksowanie w oknach konserwacyjnych oraz pozostaw niezarezerwowany zapas na tymczasowe szczyty. Celem nie jest zapełnienie każdego bajtu w stanie bezczynności, lecz utrzymanie stabilnego zestawu usług przy jednoczesnym zapotrzebowaniu.

FAQ

Dlaczego pamięć akceleratora jest pełna, gdy wykorzystanie GPU jest niskie?

Wykorzystanie obliczeniowe mierzy aktywne wykonywanie, podczas gdy wagi modeli, konteksty, pamięci podręczne i zarezerwowane bloki alokatora mogą zajmować pamięć między żądaniami.

Czy kontenery mogą automatycznie egzekwować limity pamięci GPU?

Nie w każdym runtime’ie działa to niezawodnie. Przypisanie urządzeń i izolacja procesów nie gwarantują, że kilka frameworków skoordynuje swoje wewnętrzne rezerwacje.

Czy jeden współdzielony serwer wnioskowania jest zawsze lepszy?

Nie. Może ograniczyć duplikację i poprawić harmonogramowanie, ale izolacja usług, zgodność frameworków, bezpieczeństwo, odzyskiwanie po awarii i obsługa modeli mogą uzasadniać korzystanie z oddzielnych runtime’ów.

Centrum Technologii i Sztucznej Inteligencji

Więcej do przeczytania

Get More Builds Like This

Stay in the Loop

Get updates from Zima - new products, exclusive deals, and real builds from the community.

Stay in the Loop preferences

We respect your inbox. Unsubscribe anytime.