Im Jahr 2020 haben wir das erste niederländische GPT2-Modell in verschiedenen Größen trainiert und als Open Source zur Verfügung gestellt. Natürlich wollten wir dies mit der Welt teilen, indem wir die Modelle, den Code und eine nette Anwendung, die ihre Verwendung demonstriert, offenlegen.
Aber diese nette Anwendung hat ihren Preis, buchstäblich...
Derzeit wird ein HF-Modell in einer Python-Flask-Anwendung gehostet, die die Pipeline-API der HF-Bibliothek verwendet.
Ein Routing-Microservice leitet je nach Benutzeranfrage zum richtigen Model-Serving-Microservice weiter, wenn er das 117M-Parameter-GPT2-Small-Modell oder das 345M-Parameter-GPT2-Medium-Modell ansprechen möchte.
PS: Falls es Sie interessiert, wie wir dieses niederländische GPT2-Modell trainiert haben: Wir haben es in diesem Blogpost perfekt beschrieben (wenn wir das selbst sagen). Wenn Sie diese niederländischen Modelle selbst ausprobieren möchten, finden Sie sie auf unserer HF Hub-Seite.
Die endgültige Anwendung für den Benutzer sieht wie folgt aus:
Das derzeitige System weist jedoch einige Schwierigkeiten auf:
Die Erstellung der Antworten nimmt einige Zeit in Anspruch, vor allem bei dem mittelgroßen Modell, was die Benutzerfreundlichkeit beeinträchtigt.
Zweitens ist der Container wegen der großen Modelle ziemlich groß, so dass wir entweder:
In diesem Blogpost werden wir also diese Model-Serving-Komponente verbessern, indem wir sie quantisieren, damit sie flüssiger läuft, hoffentlich ohne zu viel an Ausdrucksqualität zu verlieren.
Wir werden nicht im Detail darauf eingehen, was Quantisierung ist. Wenn Sie eine gute Einführung in dieses Thema wünschen: Wir haben hier einen Blogpost zu diesem und anderen Aspekten der Modelleffizienz geschrieben.
TDLR: Durch die Verringerung der Genauigkeit der Gewichte in den linearen und einbettenden Schichten von fp32 auf int8 durch eine Mapping-Aktion wird der Speicherbedarf eines Modells stark reduziert!
Die Quantisierung ist ein recht aktives Feld, so dass eine Reihe von Bibliotheken Optionen zur Quantisierung Ihres Modells anbieten:
Obwohl wir große Fans der Entwicklung von Optimum sind, haben wir in diesem Beitrag die letzte Lösung verwendet, da sie die GPT2-Quantisierung durch Beispiele und spezielle Hilfsprogramme hervorragend unterstützt.
Wenn du nur wegen des Codes hier bist, findest du den gesamten Code unter diesem Blogpost-Link!
Die Quantisierung mit ORT umfasst nur drei einfache Schritte:
Alle anstehenden Transformationen laufen über die ONNXRuntime (ORT)-Bibliothek, daher ist es nur logisch, dass diese Schritte eine ONNX-Binärdatei erfordern. Dies kann leicht mit HF + ORT gemacht werden:
Die Modelloptimierung umfasst einige Operationen, um den Modellgraphen zu straffen. Ein Beispiel dafür ist die Zusammenfassung von aufeinanderfolgenden Operationen in einem einzigen Schritt.
Hier findet die eigentliche Quantisierung statt, oder anders ausgedrückt: die Abbildung der FP32-Gewichtungswerte auf den INT8-Wertebereich.
Um das Modell-Artefakt (ONNX-Binärdatei) tatsächlich nutzen zu können, benötigen wir natürlich eine Laufzeitumgebung, um es zu hosten. Es gibt keine bessere Laufzeitumgebung für ONNX als ONNXRuntime
Zu diesem Zweck können Sie ganz einfach eine ORT-Sitzung erstellen, die mit den typischen Eingaben gefüttert werden kann, die sonst in einem HF-Modell erforderlich sind (Token-IDs, Aufmerksamkeitsmasken usw.), um die Output-Logits zu erzeugen:
Kinderleicht, oder? Nun, es gibt ein paar Aspekte rund um die ORT-Sitzungen, damit es gut funktioniert:
Wir werden nicht auf den gesamten Code eingehen, der für jeden dieser Aspekte benötigt wird, aber Sie können sie alle im Notizbuch(Link wieder) finden, wo sie implementiert sind.
Wir haben also all diese zusätzlichen Aspekte kodiert, um gute Vorhersagen zu erhalten, und unser Modell läuft zufrieden auf einer Cloud-Run-Instanz innerhalb einer Python-App, die die ORT-Sitzung hostet. Glückliche Tage!
Aber taugt es überhaupt etwas...?
Natürlich wollen wir sicherstellen, dass unsere Modelle keinen Müll produzieren, also werden wir die Generierungsqualität aus mehreren Blickwinkeln betrachten:
Die Differenz der Output-Logits
Eine erste schnelle Überprüfung können wir durchführen, indem wir die Output-Logits der Sprachmodellierungsköpfe der beiden Modelle vergleichen.
Wenn das quantisierte Modell tatsächlich ein glaubwürdiger Ersatz für das normale Modell ist, dann sollten die Output-Logits Punkt für Punkt ungefähr der gleichen Werteverteilung folgen.
Durch die Messung des Durchschnitts, des Medians und der maximalen Differenz der Logit-Werte können wir also einen ersten Eindruck von der Qualität des potenziellen Outputs gewinnen:
Wir sehen, dass die Logit-Werte sehr unterschiedlich sein können. Wir können auch sehen, dass die Auswirkungen für den 345M Parameter GPT2-medium geringer sind als für das 117M GPT2-small Modell.
Dies ist zwar ein erster Hinweis darauf, dass wir etwas an Qualität verlieren, sagt aber nichts über die wahren Ausdrucksmöglichkeiten der quantisierten Modelle aus. Lassen Sie uns also fortfahren:
Die Verblüffung
Zum Glück für uns gibt es eine nette Metrik, um die Qualität der Generierung sinnvoller zu messen: Perplexität! Die netten Leute von HuggingFace haben eine sehr schöne Seite darüber geschrieben, was sie tut und wie man sie programmiert (unsere Implementierung finden Sie in unserem Notizbuch).
Wir folgten ihrem Ansatz und maßen die Perplexität an den ersten 1000 Dokumenten der niederländischen Partition des OSCAR-Korpus. Dies ist eine umfangreiche Sammlung verschiedener gecrawlter niederländischer Webseiten.
Interessanterweise ist der Anstieg der Komplexität für das mittlere GPT2-Modell weniger hoch als für das kleine GPT2-Modell. Das bedeutet, dass das mittlere GPT2-Modell anscheinend weniger unter dem Quantisierungsprozess leidet. Dies entspricht dem, was wir beim Logit-Vergleich beobachtet haben!
Die menschliche Bewertung
Der Kicker, der Champion, der wahre Test der generativen Qualität!
Hier sind einige Beispielgenerationen des nicht-quantisierten und des quantisierten Modells nebeneinander dargestellt, wobei wir jedes Modell bitten, die nächsten 20 Token zu produzieren.
Beide Modelle erzeugen durch Stichproben, mit top_p=0,95, top_k=50 und Temperatur=0,95
So wie es aussieht, scheinen beide sehr gut zu funktionieren! Gut genug für die Online-Demo, bei der jedes Mal nur ein paar nächste Token vorhergesagt werden.
Aber ist es schnell...?
Da wir nun wissen, dass die quantisierten Modelle brauchbar sind, können wir damit beginnen, das erste Ärgernis bei der Ist-Bereitstellung zu messen: die Startzeit und die Latenzzeit der Anfragen.
Hier wollen wir zwei Punkte messen:
die Startzeit, wenn der Dienst einen Kaltstart erlebt
Wenn eine serverlose Cloud-Run-Instanz, die auf 0 skaliert ist, anfängt, Anfragen zu erhalten, muss sie einen so genannten "Kaltstart" durchführen, indem sie Ihre Container-Anwendung auf einer verfügbaren Maschineninstanz bereitstellt und ausführt, die Modelle aus dem Cloud-Speicher abruft und sie lädt, um mit der Bedienung der Anfragen zu beginnen. Dies nimmt natürlich etwas Zeit in Anspruch.
Vergleichen wir diese "Aufwärmzeit" zwischen einem Dienst, der die nicht-quantisierten Versionen bedient, und den quantisierten Versionen:
die Latenzzeit der Anfrage
Um die Antwortzeit für jedes eingesetzte Modell zu messen, senden wir eine Flut von einigen hundert aufeinanderfolgenden Anfragen an den eingesetzten Microservice. Diese Latenz beinhaltet Netzwerklatenz, Service-Overhead und Modellvorhersagezeit.
Wir wiederholen dies einige Male, jeweils für eine Zeichenkette mit unterschiedlicher Sequenzlänge, da die Komplexität der Selbstbeobachtung quadratisch mit der Sequenzlänge skaliert !
Wieder eine solide Leistung der quantisierten Modelle! Die Latenz scheint um den Faktor 3-4 reduziert zu sein.
Aber ist es überhaupt billig...?
Da Cloud-Speicher grundsätzlich kostenlos ist, betrachten wir hauptsächlich die Kosten für das Hosting und den Betrieb des Modells in einem Microservice auf Google Cloud Run.
Wir können die Preisdokumentation von Cloud Run nutzen, um einen Kostenvoranschlag zu erhalten:
Das bedeutet, dass wir unsere Cloud-Rechnung für den Serving-Teil um das 2,4-fache reduzieren können!
Und selbst wenn die Kosten für den überarbeiteten Einsatz zu hoch wären, haben wir deutlich gezeigt, dass der kleinere quantisierte Container eine viel geringere Aufwärmzeit hat, so dass die automatische Skalierung auf Null eine echte Option ist.
Die Nutzung von Quantisierung und ORT führt eindeutig zu einer deutlichen Beschleunigung und Kostenreduzierung!
Genießen Sie das Geld, das Sie gerade gespart haben! Und bleiben Sie dran für kommende Blogposts, in denen wir den Triton Inference Server für das vollständige Transformator-Hosting einsetzen, da dies ein empfehlenswerterer Ansatz für den Einsatz von ausgereiften Modellservices ist als die vorgestellte Flask-Option.