WebAssembly- und WebGPU-Verbesserungen für schnellere Web-KI, Teil 1

Hier erfahren Sie, wie WebAssembly- und WebGPU-Verbesserungen die Leistung des maschinellen Lernens im Web verbessern.

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

KI-Inferenzen im Web

Wir alle haben schon einmal gehört: KI verändert unsere Welt. Das Web ist da keine Ausnahme.

Dieses Jahr wurden Generative AI-Funktionen in Chrome eingeführt, darunter ein benutzerdefiniertes Design und//oder Unterstützung für das Schreiben eines ersten Textentwurfs. Aber KI ist viel mehr als das: KI kann Webanwendungen selbst bereichern.

Webseiten können intelligente Komponenten für das Sehen einbetten, z. B. für die Erkennung von Gesichtern oder Gesten, zur Audioklassifizierung oder zur Spracherkennung. Im letzten Jahr hat Generative AI einen enormen Zulauf erlebt und einige wirklich beeindruckende Demos von Large Language Models im Web. Sehen Sie sich auch Practical On-Device AI for Web Developers an.

KI-Inferenzen im Web sind heute auf einem großen Teil von Geräten verfügbar und die KI-Verarbeitung kann auf der Webseite selbst erfolgen, wobei die Hardware des Nutzergeräts genutzt wird.

Dies ist aus mehreren Gründen hilfreich:

  • Geringere Kosten: Durch das Ausführen von Inferenzen auf dem Browserclient lassen sich die Serverkosten erheblich senken. Dies kann besonders bei generativen KI-Abfragen hilfreich sein, die um einige Größen kostenintensiver sein können als reguläre Abfragen.
  • Latenz: Bei Anwendungen, die besonders empfindlich auf Latenz reagieren, wie Audio- oder Video-Apps, führt die gesamte Verarbeitung auf dem Gerät zu einer geringeren Latenz.
  • Datenschutz: Bei Ausführung auf Clientseite können neue Arten von Anwendungen genutzt werden, die einen erhöhten Datenschutz erfordern und bei denen keine Daten an den Server gesendet werden können.

Wie KI-Arbeitslasten heute im Web ausgeführt werden

Heute erstellen Anwendungsentwickler und -forscher Modelle mithilfe von Frameworks, die im Browser mit einer Laufzeit wie Tensorflow.js oder ONNX Runtime Web ausgeführt werden und Laufzeiten für die Ausführung Web APIs.

All diese Laufzeiten werden am Ende über JavaScript oder WebAssembly auf der CPU oder über WebGL oder WebGPU auf der GPU ausgeführt.

Diagramm der heutigen Ausführung von KI-Arbeitslasten im Web

ML-Arbeitslasten

Arbeitslasten für maschinelles Lernen (ML) drücken Tensoren durch einen Graphen von Rechenknoten. Tensoren sind die Ein- und Ausgaben dieser Knoten, die eine große Menge an Datenberechnungen durchführen.

Das ist aus folgenden Gründen wichtig:

  • Tensoren sind sehr große Datenstrukturen, die Berechnungen an Modellen durchführen, die Milliarden von Gewichtungen haben können.
  • Skalierung und Inferenz kann zu Datenparallelität führen. Dies bedeutet, dass dieselben Operationen für alle Elemente in den Tensoren ausgeführt werden.
  • ML erfordert keine Präzision. Für die Landung auf dem Mond brauchen Sie vielleicht eine 64-Bit-Gleitkommazahl, für die Gesichtserkennung aber nur ein Meer aus 8-Bit-Zahlen oder weniger.

Glücklicherweise haben Chipdesigner Funktionen hinzugefügt, damit Modelle schneller und kühler laufen und sie sogar überhaupt ausgeführt werden können.

In den Teams von WebAssembly und WebGPU arbeiten wir nun daran, Webentwicklern diese neuen Funktionen zur Verfügung zu stellen. Wenn Sie Entwickler von Webanwendungen sind, ist es unwahrscheinlich, dass Sie diese Low-Level-Primitive häufig verwenden. Wir gehen davon aus, dass die von Ihnen verwendeten Toolchains oder Frameworks neue Funktionen und Erweiterungen unterstützen, sodass Sie mit minimalen Änderungen an Ihrer Infrastruktur profitieren können. Wenn Sie jedoch die Leistung Ihrer Anwendungen manuell optimieren möchten, sind diese Funktionen für Ihre Arbeit relevant.

WebAssembly

WebAssembly (Wasm) ist ein kompaktes, effizientes Bytecode-Format, das Laufzeiten verstehen und ausführen können. Er wurde so entwickelt, dass er die zugrunde liegenden Hardwarefunktionen nutzt und nahezu native Geschwindigkeiten bietet. Der Code wird validiert und in einer speichersicheren Sandbox-Umgebung ausgeführt.

Informationen zum Wasm-Modul werden durch eine dichte binäre Codierung dargestellt. Im Vergleich zu einem textbasierten Format bedeutet dies eine schnellere Decodierung, schnellere Ladezeiten und reduzierte Arbeitsspeichernutzung. Es ist in dem Sinne übertragbar, dass keine Annahmen über die zugrunde liegende Architektur aufgestellt werden, die in modernen Architekturen nicht bereits gemeinsam sind.

Die WebAssembly-Spezifikation ist iterativ und wird in einer offenen W3C-Community-Gruppe bearbeitet.

Beim Binärformat werden keine Annahmen über die Hostumgebung getroffen. Daher eignet es sich auch für Einbettungen, die nicht im Web eingebettet sind.

Sie können Ihre Anwendung nur einmal kompilieren und überall ausführen: auf einem Desktop, Laptop, Telefon oder jedem anderen Gerät mit Browser. Weitere Informationen dazu finden Sie unter WriteOnce, runwhere soon Reald with WebAssembly.

Illustration eines Laptops, Tablets und Smartphones

Die meisten Produktionsanwendungen, die KI-Inferenzen im Web ausführen, nutzen WebAssembly, sowohl für die CPU-Berechnung als auch für die Schnittstelle zu Spezialberechnungen. Bei nativen Anwendungen können Sie sowohl auf Computing für allgemeine als auch auf Spezialzwecke zugreifen, da die Anwendung auf Gerätefunktionen zugreifen kann.

Aus Gründen der Übertragbarkeit und Sicherheit im Web evaluieren wir sorgfältig, welche Primitiven zugänglich sind. Dadurch wird ein Gleichgewicht zwischen der Zugänglichkeit des Internets und der bestmöglichen Leistung der Hardware hergestellt.

WebAssembly ist eine portable Abstraktion von CPUs, daher werden alle Wasm-Inferenzen auf der CPU ausgeführt. CPUs sind zwar nicht die leistungsstärkste Wahl, aber sie sind allgemein verfügbar und funktionieren auf den meisten Geräten bei den meisten Arbeitslasten.

Bei kleineren Arbeitslasten wie Text- oder Audioarbeitslasten wäre eine GPU teuer. Es gibt eine Reihe aktueller Beispiele, in denen Wasm die richtige Wahl war:

In Open-Source-Demos können Sie noch mehr entdecken, z. B. whisper-tiny, llama.cpp und Gemma2B im Browser.

Ganzheitlicher Ansatz für Anwendungen nutzen

Sie sollten Primitiven basierend auf dem jeweiligen ML-Modell, der Anwendungsinfrastruktur und der allgemein beabsichtigten Anwendungserfahrung für die Nutzer auswählen

Bei der Erkennung von Gesichtserkennungspunkten von MediaPipe sind beispielsweise CPU- und GPU-Inferenz vergleichbar (auf einem Apple M1-Gerät), es gibt jedoch Modelle, bei denen die Abweichung erheblich höher sein kann.

Wenn es um ML-Arbeitslasten geht, berücksichtigen wir eine ganzheitliche Anwendungsansicht und hören dabei von Framework-Autoren und Anwendungspartnern, um die am häufigsten gewünschten Verbesserungen zu entwickeln und bereitzustellen. Sie lassen sich grob in drei Kategorien unterteilen:

  • Entscheidende CPU-Erweiterungen für die Leistung bereitstellen
  • Ausführung größerer Modelle aktivieren
  • Nahtlose Interoperabilität mit anderen Web-APIs ermöglichen

Schnelleres Computing

So wie es steht, enthält die WebAssembly-Spezifikation nur eine bestimmte Reihe von Anweisungen, die wir dem Web zur Verfügung stellen. Für die Hardware werden jedoch neuere Anweisungen hinzugefügt, die den Unterschied zwischen der nativen Leistung und der WebAssembly-Leistung vergrößern.

Denken Sie daran, dass ML-Modelle nicht immer ein hohes Maß an Präzision erfordern. Locked SIMD ist ein Vorschlag, der einige der strengen Anforderungen ohne Determinismus reduziert, was zu einer schnelleren Codegenerierung bei einigen Vektorvorgängen führt, die für die Leistung Hotspots sind. Darüber hinaus führt Locker SIMD ein neues Punktprodukt und FMA-Anweisungen ein, mit denen bestehende Arbeitslasten um das 1,5- bis 3-Fache beschleunigt werden. Es wurde in Chrome 114 ausgeliefert.

Beim Gleitkommaformat mit halber Genauigkeit werden 16 Bit für IEEE FP16 anstelle der 32 Bit für Werte mit einfacher Genauigkeit verwendet. Die Verwendung von Werten mit halber Genauigkeit und die Verwendung reduzierter Speicheranforderungen, die das Training und die Bereitstellung größerer neuronaler Netzwerke ermöglichen und die Speicherbandbreite ermöglichen, bietet im Vergleich zu Werten mit einfacher Genauigkeit mehrere Vorteile. Geringere Präzision beschleunigt die Datenübertragung und mathematische Operationen.

Größere Modelle

Zeiger in den linearen Wasm-Speicher werden als 32-Bit-Ganzzahlen dargestellt. Dies hat zwei Konsequenzen: Die Heap-Größe ist auf 4 GB beschränkt (wenn Computer viel mehr physischen Arbeitsspeicher haben) und Anwendungscode, der auf Wasm ausgerichtet ist, muss mit einer 32-Bit-Zeigergröße kompatibel sein (was).

Besonders bei großen Modellen, die wir heute kennen, kann das Laden dieser Modelle in WebAssembly eingeschränkt sein. Durch das Angebot Memory64 werden diese Einschränkungen aufgehoben, da der lineare Arbeitsspeicher größer als 4 GB ist und dem Adressbereich nativer Plattformen entspricht.

Wir haben eine voll funktionsfähige Implementierung in Chrome und werden voraussichtlich im Laufe des Jahres verfügbar sein. Vorerst können Sie Tests mit der Kennzeichnung chrome://flags/#enable-experimental-webassembly-features durchführen und uns Feedback senden.

Bessere Web-Interoperabilität

WebAssembly könnte der Einstiegspunkt für spezielle Computing-Daten im Web sein.

Mit WebAssembly lassen sich GPU-Anwendungen im Web bereitstellen. Dies bedeutet, dass die gleiche C++-Anwendung, die auf dem Gerät ausgeführt werden kann, mit kleinen Änderungen auch im Web ausgeführt werden kann.

Emscripten, die Wasm-Compiler-Toolchain, hat bereits Bindungen für WebGPU. Er ist der Einstiegspunkt für KI-Inferenzen im Web, daher ist es wichtig, dass Wasm nahtlos mit dem Rest der Webplattform zusammenarbeiten kann. In diesem Bereich arbeiten wir an verschiedenen Vorschlägen.

JavaScript Promise-Integration (JSPI)

Typische C- und C++-Anwendungen (sowie viele andere Programmiersprachen) werden häufig für eine synchrone API geschrieben. Das bedeutet, dass die Anwendung die Ausführung stoppt, bis der Vorgang abgeschlossen ist. Solche blockierenden Anwendungen lassen sich in der Regel intuitiver schreiben als solche, die asynchron reagieren.

Wenn teure Vorgänge den Hauptthread blockieren, können sie E/A blockieren und die Verzögerung ist für Nutzer sichtbar. Ein synchrones Programmiermodell nativer Anwendungen stimmt nicht mit dem asynchronen Modell des Webs überein. Dies ist besonders bei Legacy-Anwendungen problematisch, deren Portierung teuer wäre. Mit Emscripten kann dies mit Asyncify erreicht werden. Dies ist jedoch nicht immer die beste Option – der Code ist größer und weniger effizient.

Im folgenden Beispiel wird Fibonacci mithilfe von JavaScript-Versprechen für Additionen berechnet.

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

Achten Sie bei diesem Beispiel auf Folgendes:

  • Das EM_ASYNC_JS-Makro generiert den gesamten erforderlichen Glue-Code, sodass wir mitJSPI auf das Promise-Ergebnis zugreifen können, genau wie bei einer normalen Funktion.
  • Die spezielle Befehlszeilenoption -s ASYNCIFY=2. Dadurch wird die Option zur Generierung von Code aufgerufen, der mit JavaScriptI die Verbindung zu JavaScript-Importen herstellt, die Promise zurückgeben.

Weitere Informationen zur Verwendung und zu den Vorteilen von JSPI finden Sie unter Introducing the WebAssembly JavaScript Promise Integration API on v8.dev. Erfahren Sie mehr über den aktuellen Ursprungstest.

Speichersteuerung

Entwickler haben nur sehr wenig Kontrolle über den Wasm-Arbeitsspeicher. Das Modul besitzt einen eigenen Arbeitsspeicher. Alle APIs, die auf diesen Arbeitsspeicher zugreifen müssen, müssen ein- oder herauskopiert werden. Diese Nutzung kann sich wirklich summieren. Eine Grafikanwendung kann beispielsweise für jeden Frame ein- und auskopieren müssen.

Der Vorschlag zur Arbeitsspeichersteuerung zielt darauf ab, eine genauere Kontrolle über den linearen Wasm-Arbeitsspeicher zu ermöglichen und die Anzahl der Kopien in der Anwendungspipeline zu reduzieren. Dieser Vorschlag befindet sich in Phase 1. Wir erstellen dafür einen Prototyp in V8, der JavaScript-Engine von Chrome, um die Weiterentwicklung des Standards voranzutreiben.

Entscheiden, welches Backend das richtige für Sie ist

CPU ist allgegenwärtig, aber nicht immer die beste Option. Spezialisiertes Computing auf der GPU oder an Beschleunigern kann eine um Größenordnung höhere Leistung bieten, insbesondere bei größeren Modellen und auf High-End-Geräten. Dies gilt sowohl für native Anwendungen als auch für Webanwendungen.

Welches Back-End Sie auswählen, hängt von der Anwendung, dem Framework oder der Toolchain sowie anderen Faktoren ab, die die Leistung beeinflussen. Dennoch investieren wir weiter in Lösungen, die es Core Wasm ermöglichen, gut mit dem Rest der Webplattform zu arbeiten, und insbesondere mit WebGPU.

Teil 2 weiterlesen