Schneller, kleiner, besser – Performanceoptimierung von KI-Modellen

Neue riesige neuronale Netzwerke stellen auf Grund ihrer Größe und der dadurch benötigten Rechenleistung viele Anforderungen an die darunterliegende Hardware. Ein Beispiel für solche großen Netzwerke sind vortrainierte Transformermodelle. Diese neue Modellart wurde durch die Einführung der Transformerarchitektur[1] 2017 begründet und konnte seitdem viele Fortschritte im Feld der natürlichen Sprachverarbeitung erzielen. Zu ihren Vertretern zählen unter anderen die Modelle BERT[2], RoBERTa[3] oder T5[4]. Dabei können sich die einzelnen Transformermodelle untereinander im Aufbau, in den Methoden zum Vortrainieren und in den verwendeten Trainingsdaten deutlich unterscheiden. Eines haben sie jedoch meist gemeinsam: Sie sind sehr groß und benötigen viel Rechenleistung. So wurde das 2018 veröffentlichte BERTLARGE-Modell vier Tage lang auf 16 Cloud TPUs vortrainiert[2].  

Im Vergleich zum Training wird für die Inferenz deutlich weniger Rechenleistung benötigt. Um schnelle Antworten zu liefern, werden jedoch auch in der Produktion häufig GPUs eingesetzt. Doch ist das zwingend notwendig?

Intel stellt verschiedene Frameworks und Bibliotheken bereit, um Modelle für viele Intel-CPUs und -GPUs zu optimieren. Durch die Optimierungen steigt der Durchsatz, sodass es möglich ist, günstigere Hardware einzusetzen. Um zu prüfen, wie stark die Performance durch eine solche Optimierung gesteigert werden kann, unterzogen sich verschiedene Ansätze eines Vergleiches anhand eines konkreten Beispiels.

Vorgehen der Performanceoptimierung

Für den Vergleich wurde die Aufgabe des Question-Answering ausgewählt. Dabei werden Fragen zu einem Dokument gestellt. Das Modell muss die Antworten aus dem Text extrahieren oder aber erkennen, dass der Text die gesuchten Antworten nicht enthält. Als Versuchsmodell wurde RoBERTa-base-squad2[5] verwendet, welches von Deepset auf dem Stanford Question Answering Dataset 2.0[6] trainiert wurde.

Insgesamt sind fünf Kombinationen verglichen worden: Als Referenz wurde zunächst das PyTorch-Modell ohne Optimierung ausgewertet. Dieses nicht optimierte Modell wurde außerdem mit zwei Frameworks für die Intel Hardware optimiert: Hierfür kam einmal die Intel® Extension for PyTorch (IPEX)[7] sowie die OpenVino Integration with Torch-ORT[8] zum Einsatz.

Eine weitere Optimierung, die einmal mit dem reinen PyTorch-Modell und einmal in Kombination mit IPEX durchgeführt wurde, ist die Quantisierung mit Hilfe der Intel-Neural-Compressor-Bibliothek[9]. Dabei werden die Modelle komprimiert. Sie nutzen in diesem Fall statt des FP32-Formats ein INT8-Format. Dies hat zur Folge, dass die Inferenz schneller wird. Ein Nachteil der Kompression ist jedoch, dass die Genauigkeit der Modelle sinken kann.

Diese wurde mit dem F1-Wert bewertet, während der Durchsatz mit der Anzahl an Samples pro Sekunde gemessen wird. Zu Ermittlung der beiden Werte wurde der von Hugging Face zur Verfügung gestellte Code[10] angepasst und verwendet.

Um die Ergebnisse vergleichbar zu machen, wurden alle Modell-Varianten auf einem Xeon Gold 6128 CPU-Prozessor in der Intel DevCloud[11] evaluiert. Das Referenzmodell ohne Optimierungen lief zusätzlich auf den NVIDIA A100- und V100-GPUs.

Ergebnisse

Tabelle 1 fasst die Ergebnisse der Messungen zusammen. Die erste Spalte beinhaltet das verwendete Framework, während der zweiten entnommen werden kann, ob das Modell mit Hilfe des Intel Neural Compressors quantisiert (INT8) oder keine Quantisierung durchgeführt wurde (FP32). Die dritte Spalte enthält den Namen der CPU oder GPU, auf der die Evaluation stattgefunden hat.

Die Anwendung von IPEX steigert den Durchsatz um ca. 14% von 8,46 auf 9,66 Samples pro Sekunde. Durch die OpenVino Integration verdoppelt sich der Durchsatz im Vergleich zum Referenzmodell sogar. Bei beiden Optimierungen bleibt der erzielte F1-Wert identisch.

Durch die Quantisierung mit IPEX zu einem INT8-Modell kann der Durchsatz im Vergleich zum IPEX-F32-Modell von 9,66 Samples pro Sekunde um 34 Prozent auf 12,96 Samples pro Sekunde gesteigert werden. Dabei sank der F1-Wert um lediglich 3,94 Punkte.

Die Quantisierung des PyTorch-Modells erhöht den Durchsatz um rund 80% von 8,46 auf 15,20 Samples pro Sekunde. Dabei verschlechtert sich der F1-Wert nur um 1,70 Punkte.

Alle Optimierungen erhöhen somit den Durchsatz. In unserem Fall liefert das Modell, welches mit Hilfe der OpenVino Integration optimiert wurde, auf demXeon Gold 6128 Prozessor den höchsten Durchsatz. Dicht dahinter liegt das quantisierte PyTorch-Modell.

Den größten Einfluss auf den Durchsatz hat in unserem Vergleich jedoch die verwendete CPU bzw. GPU. So konnte der Durchsatz des PyTorch-Modells allein durch den Wechsel von der CPU auf die GPUs um das rund 14 bzw. 20-fache gesteigert werden.

Framework FormatCPU/GPUF1-WertDurchsatz
PyTorch FP32  NVIDIA A100 82.9231   171.137 samples/sec 
PyTorch FP32 NVIDIA V100 82.9231 121.334 samples/sec   
PyTorch FP32 Xeon Gold 6128 82.9231   8.456 samples/sec 
PyTorch INT8 (via INC) Xeon Gold 6128 81.2244 15.203 samples/sec 
IPEX FP32 Xeon Gold 6128 82.9231 9.662 samples/sec 
IPEX INT8 (via INC) Xeon Gold 6128 78.9859 12.962 samples/sec 
OpenVino Integration with Torch-ORT FP32 Xeon Gold 6128 82.9231   16.901 samples/sec 
F1-Wert und Durchsatz

Tabelle 1 F1-Wert und Durchsatz

Fazit

Die Methoden zur Optimierung der Modelle konnten uns überzeugen. Vor allem die Einbindung der beiden Frameworks benötigt nur minimale Codeanpassungen und kann somit schnell Performancesteigerungen auf der Intel-Hardware erzielen.

Zwar erreichten die nicht-optimierten Modelle in unserem Beispiel auf den GPUs immer noch deutlich höhere Durchsätze als die optimierten Modelle auf CPUs, dennoch kann die Optimierung in manchen Fällen sinnvoll sein:

So ist die Anschaffung von GPUs aufgrund von Anfangsinvestitionen und Personalschulungen mit Kosten verbunden, die sich manche Firmen nicht leisten wollen oder können. In diesen Fällen kann es sinnvoll sein, zu prüfen, ob die Verwendung einer CPU eine ausreichend schnelle Inferenz ermöglicht und somit kosteneffizienter als eine GPU ist.

Zusätzlich unterstützen die beiden Frameworks nicht nur Intel CPUs, sondern auch diskrete beziehungsweise integrierte GPUs[8] [12]. Somit könnte auch die Inferenzzeit auf GPUs durch die Optimierung beschleunigt werden.


[1] https://arxiv.org/abs/1706.03762

[2] https://arxiv.org/abs/1810.04805

[3] https://arxiv.org/abs/1907.11692

[4] https://arxiv.org/abs/1910.10683

[5] https://huggingface.co/deepset/roberta-base-squad2

[6] https://arxiv.org/abs/1806.03822

[7] https://github.com/intel/intel-extension-for-pytorch

[8] https://github.com/pytorch/ort#-inference

[9] https://www.intel.com/content/www/us/en/developer/tools/oneapi/neural-compressor.html

[10] https://github.com/huggingface/transformers/tree/main/examples/pytorch/question-answering

[11] https://www.intel.com/content/www/us/en/developer/tools/devcloud/overview.html

[12] https://github.com/intel/intel-extension-for-pytorch