Ulepszenia WebAssembly i WebGPU umożliwiające szybsze działanie sztucznej inteligencji, część 1

Dowiedz się, jak ulepszenia WebAssembly i WebGPU poprawiają wydajność systemów uczących się w internecie.

Austin Eng
Austin Eng
Deepti Gandluri
Deepti Gandluri
François Beaufort
François Beaufort

Wnioskowanie z AI w internecie

Wszyscy znamy tę historię: AI zmienia nasz świat. Internet nie jest wyjątkiem.

W tym roku Chrome dodał funkcje generatywnej AI, takie jak tworzenie niestandardowych motywów lub pomoc w napisaniu pierwszej wersji tekstu. Sztuczna inteligencja to jednak znacznie więcej. AI może wzbogacić też same aplikacje internetowe.

Na stronach internetowych mogą być osadzone inteligentne komponenty związane z rozpoznawaniem twarzy, np. rozpoznawanie twarzy lub gestów, klasyfikacja dźwięku czy wykrywanie języka. W zeszłym roku zaobserwowaliśmy ogromny wzrost popularności generatywnej AI, w tym w internecie imponujące prezentacje dużych modeli językowych (LLM). Zapoznaj się z artykułem Praktyczna sztuczna inteligencja na urządzeniu dla programistów stron internetowych.

W internecie wnioskowanie z AI jest dostępne na dużej liczbie urządzeń, a przetwarzanie AI może odbywać się na samej stronie internetowej i wykorzystywane jest przy użyciu sprzętu zainstalowanego na urządzeniu użytkownika.

Jest to przydatne z kilku powodów:

  • Niższe koszty: wnioskowanie na kliencie przeglądarki znacznie zmniejsza koszty serwera i może być szczególnie przydatne w przypadku zapytań generatywnej AI, które mogą być znacznie droższe niż zwykłe zapytania.
  • Opóźnienie: w przypadku aplikacji szczególnie wrażliwych na opóźnienia, takich jak aplikacje audio lub wideo, całe przetwarzanie odbywa się na urządzeniu, co skraca czas oczekiwania.
  • Prywatność: działanie po stronie klienta może również przyczynić się do odblokowania nowej klasy aplikacji wymagających większej prywatności, przez co dane nie mogą być wysyłane na serwer.

Jak zadania AI działają obecnie w internecie

Obecnie deweloperzy aplikacji i badacze budują modele za pomocą platform, a modele uruchamiają się w przeglądarce przy użyciu środowiska wykonawczego, takiego jak Tensorflow.js czy ONNX Runtime Web, a środowiska wykonawcze korzystają z internetowych interfejsów API.

Wszystkie te środowiska wykonawcze ostatecznie zaczynają działać na procesorach przez JavaScript lub WebAssembly albo na GPU przez WebGL lub WebGPU.

Schemat działania zadań AI, które obecnie działają w internecie

Zadania systemów uczących się

Zadania systemów uczących się przesuwają tensory przez wykres węzłów obliczeniowych. Tensory to dane wejściowe i wyjściowe tych węzłów, które wykonują duże obliczenia na danych.

To ważne, ponieważ:

  • Tensoryzuje bardzo duże struktury danych i wykonują obliczenia na modelach, które mogą mieć miliardy wag.
  • Skalowanie i wnioskowanie może prowadzić do równoległości danych. Oznacza to, że na wszystkich elementach tensorów są wykonywane te same operacje.
  • Systemy uczące się nie wymagają precyzji. Do wylądowania na Księżycu może być potrzebna 64-bitowa liczba zmiennoprzecinkowa, ale do rozpoznawania twarzy niezbędna może być jedynie całe morze 8-bitowych liczb.

Na szczęście projektanci układów scalonych dodali funkcje, dzięki którym modele działają szybciej i chłodniej, a nawet umożliwiają ich uruchamianie.

Tymczasem w zespołach WebAssembly i WebGPU pracujemy nad udostępnieniem tych nowych możliwości programistom stron internetowych. Jeśli tworzysz aplikacje internetowe, raczej nie będziesz często korzystać z niskich elementów podstawowych. Spodziewamy się, że łańcuchy narzędzi i platformy, z których korzystasz, będą obsługiwać nowe funkcje i rozszerzenia, dzięki czemu nie musisz wprowadzać żadnych zmian w swojej infrastrukturze. Jeśli jednak wolisz ręcznie dostosowywać wydajność aplikacji, te funkcje przydadzą Ci się w Twojej pracy.

WebAssembly

WebAssembly (Wasm) to kompaktowy i wydajny format kodu bajtowego, który środowiska wykonawcze mogą interpretować i wykonywać. Został on stworzony z myślą o wykorzystaniu podstawowych możliwości sprzętowych, dzięki czemu może działać z szybkością niemal całkowitą. Kod jest weryfikowany i uruchamiany w bezpiecznym środowisku piaskownicy.

Informacje o module Wasm są przedstawiane za pomocą gęstego kodowania binarnego. W porównaniu z formatem tekstowym oznacza to szybsze dekodowanie, szybsze wczytywanie i zmniejszenie wykorzystania pamięci. Jest przenośna w tym sensie, że nie uwzględnia przyjęć na temat podstawowej architektury, które nie są jeszcze wspólne dla nowoczesnych architektur.

Specyfikacja WebAssembly jest iteracyjna i jest opracowywana w otwartej grupie społeczności W3C.

Format binarny nie przyjmuje żadnych założeń dotyczących środowiska hosta, dlatego jest zaprojektowany tak, aby dobrze działał także w reprezentacjach poza internetem.

Aplikację można skompilować raz i uruchomić wszędzie – na komputerze stacjonarnym, laptopie, telefonie i innym urządzeniu z przeglądarką. Aby dowiedzieć się więcej, zapoznaj się z artykułem Napisz coś, a uruchom w dowolnym miejscu dzięki WebAssembly.

Ilustracja przedstawiająca laptopa, tablet i telefon

Większość aplikacji produkcyjnych, które uruchamiają wnioskowanie z wykorzystaniem AI w internecie, korzysta z technologii WebAssembly zarówno do obliczeń procesora, jak i współdziałania z obliczeniami specjalnymi. W aplikacjach natywnych masz dostęp do zasobów obliczeniowych zarówno zwykłych, jak i specjalnych, ponieważ aplikacja może uzyskiwać dostęp do funkcji urządzenia.

Pod kątem przenośności i bezpieczeństwa w internecie starannie oceniamy dostępny zestaw podstawowych elementów. Pozwala to zrównoważyć dostępność internetu z maksymalną wydajnością zapewnianą przez sprzęt.

WebAssembly to przenośna abstrakcja procesorów, dlatego całe wnioskowanie Wasm jest uruchamiane na procesorze. Chociaż nie jest to najwydajniejszy wybór, procesory są powszechnie dostępne i działają w większości zadań na większości urządzeń.

W przypadku mniejszych zadań, takich jak obciążenia tekstowe lub audio, GPU może być drogie. Oto kilka najnowszych przykładów, w których Wasm to właściwy wybór:

Możesz odkryć jeszcze więcej w wersjach demonstracyjnych typu open source, np. whisper-tiny, llama.cpp i Gemma2B działająca w przeglądarce.

Przeanalizuj swoje aplikacje w sposób głośny

Podstawowe elementy należy wybrać na podstawie konkretnego modelu ML, infrastruktury aplikacji i ogólnego zamierzonego sposobu korzystania z aplikacji przez użytkowników

Na przykład w przypadku wykrywania punktów orientacyjnych twarzy w MediaPipe wnioskowanie z procesora i GPU jest porównywalne (w przypadku urządzeń Apple M1), ale istnieją modele, w których wariancja może być znacznie większa.

W przypadku zadań systemów uczących się bierzemy pod uwagę kompleksowy widok aplikacji oraz wsłuchujemy się w autorów platform i partnerów aplikacji, aby opracować i wdrożyć najbardziej oczekiwane ulepszenia. Można je podzielić na 3 kategorie:

  • Udostępnij rozszerzenia procesora kluczowe dla wydajności
  • Włącz uruchamianie większych modeli
  • Włącz bezproblemową współpracę z innymi interfejsami API

Szybsze obliczenia

Specyfikacja WebAssembly zawiera tylko określony zestaw instrukcji, które udostępniamy w internecie. Jednak sprzęt stale dodaje nowsze instrukcje, które zwiększają różnicę między wydajnością reklam natywnych a WebAssembly.

Pamiętaj, że modele ML nie zawsze wymagają wysokiego poziomu dokładności. Złagodzenie SIMD to propozycja, która ogranicza niektóre rygorystyczne wymagania niedeterministyczne, co prowadzi do szybszego generowania kodu w przypadku niektórych operacji wektorowych, które są bardzo ważne dla wydajności. Poza tym w ramach swobodnej usługi SIMD są stosowane nowe instrukcje dotyczące usług punktowych i FMA, które przyspieszają istniejące zadania od 1,5 do 3 razy. Ta funkcja została wysłana w Chrome 114.

Format zmiennoprzecinkowy półdokładności wykorzystuje 16-bitowy w przypadku IEEE FP16 zamiast 32-bitowych wartości używanych w przypadku pojedynczych wartości precyzji. W porównaniu z pojedynczymi wartościami precyzji stosowanie wartości o połowie precyzji ma kilka zalet, mniejsze wymagania dotyczące pamięci, które umożliwiają trenowanie i wdrażanie większych sieci neuronowych oraz mniejszą przepustowość pamięci. Niższa dokładność przyspiesza przesyłanie danych i wykonywanie działań matematycznych.

Większe modele

Wskaźniki do pamięci liniowej Wasm są przedstawiane jako 32-bitowe liczby całkowite. Ma to 2 konsekwencje: rozmiar sterty jest ograniczony do 4 GB (gdy komputery mają znacznie więcej fizycznej pamięci RAM), a kod aplikacji kierowany na Wasm musi być zgodny ze wskaźnikiem 32-bitowym (co).

Szczególnie w przypadku dużych modeli, takich jak mamy obecnie, wczytywanie ich w WebAssembly może być restrykcyjne. Oferta pakietowa Memory64 eliminuje te ograniczenia, ponieważ pamięć liniowa jest większa niż 4 GB i odpowiada przestrzeni adresowej platform natywnych.

Mamy już w pełni działającą implementację w Chrome i planujemy ją udostępnić jeszcze w tym roku. Na razie możesz przeprowadzać eksperymenty z flagą chrome://flags/#enable-experimental-webassembly-features i przesyłać nam opinię.

Lepsza interoperacyjność z internetem

WebAssembly może być punktem wejścia do specjalnych procesów obliczeniowych w internecie.

WebAssembly może służyć do przenoszenia aplikacji GPU w internecie. Oznacza to, że ta sama aplikacja w C++, która działa na urządzeniu, może być również uruchamiana w przeglądarce – po niewielkich modyfikacjach.

Emscripten, łańcuch narzędzi kompilatora Wasm, ma już powiązania dla WebGPU. Jest to punkt wejścia do wnioskowania przez AI w internecie, dlatego ważne jest, aby Wasm mógł płynnie współpracować z resztą platformy internetowej. Pracujemy nad różnymi propozycjami w tym obszarze.

Integracja obietnicy JavaScript (JSPI)

Typowe aplikacje w językach C i C++ (oraz wiele innych języków) są zwykle zapisywane przy użyciu synchronicznego interfejsu API. Oznacza to, że aplikacja zostanie zatrzymana do czasu zakończenia operacji. Tworzenie takich aplikacji blokujących jest zazwyczaj bardziej intuicyjne niż asynchroniczne.

Gdy kosztowne operacje blokują wątek główny, mogą zablokować wejścia/wyjścia, a zacięcie jest widoczne dla użytkowników. Występuje niezgodność między synchronicznym modelem programowania aplikacji natywnych a asynchronicznym modelem sieciowym. Jest to szczególnie problematyczne w przypadku starszych aplikacji, których przenoszenie jest kosztowne. Emscripten pozwala to osiągnąć za pomocą Asyncify, ale nie zawsze jest to najlepsza opcja, bo kod ma większy rozmiar i nie jest tak wydajna.

W tym przykładzie pokazano obliczenie fibonacci z użyciem dodatkowych funkcji JavaScriptu.

long promiseFib(long x) {
 if (x == 0)
   return 0;
 if (x == 1)
   return 1;
 return promiseAdd(promiseFib(x - 1), promiseFib(x - 2));
}
// promise an addition
EM_ASYNC_JS(long, promiseAdd, (long x, long y), {
  return Promise.resolve(x+y);
});
emcc -O3 fib.c -o b.html -s ASYNCIFY=2

W tym przykładzie zwróć uwagę na następujące kwestie:

  • Makro EM_ASYNC_JS generuje cały niezbędny kod klejnot, dzięki czemu możemy używać JSPI do uzyskiwania dostępu do wyniku obietnicy, tak jak w przypadku normalnej funkcji.
  • Specjalna opcja wiersza poleceń: -s ASYNCIFY=2. Wywołuje to opcję generowania kodu, który wykorzystuje JSPI do obsługi importów JavaScript, które zwracają obietnice.

Więcej informacji o JSPI, sposobie jego używania i zaletach znajdziesz w artykule Wprowadzenie interfejsu WebAssembly JavaScript Promise Integration API w wersji 8.dev. Dowiedz się więcej o bieżącej wersji próbnej origin.

Kontrola pamięci

Programiści mają bardzo małą kontrolę nad pamięcią Wasm – moduł ma własną pamięć. Wszystkie interfejsy API, które potrzebują dostępu do tej pamięci, muszą kopiować lub kopiować, a ich użycie może być liczone łącznie. Na przykład aplikacja graficzna może wymagać kopiowania i kopiowania każdej klatki.

Pakiet Kontrola pamięci ma na celu zapewnienie precyzyjniejszej kontroli nad liniową pamięcią Wasm oraz zmniejszenie liczby kopii w potoku aplikacji. Omawiany projekt znajduje się w fazie 1. Tworzymy go w wersji V8 – silnika JavaScriptu Chrome – aby ukształtować rozwój tego standardu.

Określ, który backend jest dla Ciebie odpowiedni

Procesor jest wszechobecny, ale nie zawsze jest najlepszym rozwiązaniem. Specjalne obliczenia na GPU lub akceleratorach mogą być bardzo wydajne, zwłaszcza w przypadku większych modeli i urządzeń zaawansowanych. Dotyczy to zarówno aplikacji natywnych, jak i internetowych.

Wybór backendu zależy od aplikacji, platformy lub łańcucha narzędzi oraz innych czynników wpływających na wydajność. Nadal jednak inwestujemy w rozwiązania, które umożliwią podstawowej Wasm współpracę dobrze z resztą platformy internetowej, a zwłaszcza z WebGPU.

Czytaj dalej część 2