🚀 Testen Sie Zilliz Cloud, die vollständig verwaltete Milvus, kostenlos – erleben Sie 10x schnellere Leistung! Jetzt testen>>

milvus-logo
LFAI
  • Home
  • Blog
  • Optimierung von Vektordatenbanken, Verbesserung der RAG-gesteuerten generativen KI

Optimierung von Vektordatenbanken, Verbesserung der RAG-gesteuerten generativen KI

  • Engineering
May 13, 2024
Cathy Zhang, Dr. Malini Bhandaru

Dieser Beitrag wurde ursprünglich auf dem Medium-Kanal von Intel veröffentlicht und wird hier mit Genehmigung wiederveröffentlicht.


Zwei Methoden zur Optimierung Ihrer Vektordatenbank bei Verwendung von RAG

Foto von Ilya Pavlov auf Unsplash

Von Cathy Zhang und Dr. Malini Bhandaru Mitwirkende: Lin Yang und Changyan Liu

Generative KI-Modelle (GenAI), die sich in unserem täglichen Leben exponentiell verbreiten, werden durch Retrieval-Augmented Generation (RAG) verbessert, eine Technik, die zur Verbesserung der Antwortgenauigkeit und -zuverlässigkeit verwendet wird, indem Fakten aus externen Quellen abgerufen werden. RAG hilft einem regulären großen Sprachmodell (LLM), Kontext zu verstehen und Halluzinationen zu reduzieren, indem es eine riesige Datenbank mit unstrukturierten Daten nutzt, die als Vektoren gespeichert sind - eine mathematische Darstellung, die hilft, Kontext und Beziehungen zwischen Daten zu erfassen.

RAG hilft dabei, mehr kontextbezogene Informationen abzurufen und somit bessere Antworten zu generieren, aber die Vektordatenbanken, auf die sie sich stützen, werden immer größer, um reichhaltige Inhalte zu liefern, auf die sie zurückgreifen können. So wie LLMs mit Billionen von Parametern am Horizont auftauchen, sind Vektordatenbanken mit Milliarden von Vektoren nicht mehr weit entfernt. Als Optimierungsingenieure waren wir neugierig, ob wir Vektordatenbanken leistungsfähiger machen, Daten schneller laden und Indizes schneller erstellen könnten, um die Abrufgeschwindigkeit zu gewährleisten, auch wenn neue Daten hinzugefügt werden. Dies würde nicht nur die Wartezeit der Benutzer verkürzen, sondern auch die Nachhaltigkeit von RAG-basierten KI-Lösungen erhöhen.

In diesem Artikel erfahren Sie mehr über Vektordatenbanken und ihre Benchmarking-Frameworks, Datensätze zur Untersuchung verschiedener Aspekte und die für die Leistungsanalyse verwendeten Tools - alles, was Sie für die Optimierung von Vektordatenbanken benötigen. Wir werden auch unsere Optimierungserfolge bei zwei beliebten Vektordatenbanklösungen vorstellen, um Sie auf Ihrer Optimierungsreise zu Leistung und Nachhaltigkeit zu inspirieren.

Verständnis von Vektordatenbanken

Im Gegensatz zu herkömmlichen relationalen oder nicht-relationalen Datenbanken, in denen Daten strukturiert gespeichert werden, enthält eine Vektordatenbank eine mathematische Darstellung einzelner Datenelemente, einen so genannten Vektor, der mithilfe einer Einbettungs- oder Transformationsfunktion erstellt wird. Der Vektor stellt in der Regel Merkmale oder semantische Bedeutungen dar und kann kurz oder lang sein. In Vektordatenbanken erfolgt die Suche nach Vektoren durch eine Ähnlichkeitssuche unter Verwendung einer Abstandsmetrik (wobei näher bedeutet, dass die Ergebnisse ähnlicher sind), z. B. euklidische Ähnlichkeit, Punktprodukt oder Kosinus.

Um den Suchprozess zu beschleunigen, werden die Vektordaten mit Hilfe eines Indexierungsmechanismus organisiert. Beispiele für diese Organisationsmethoden sind u. a. flache Strukturen, invertierte Dateien (IVF), hierarchische navigierbare kleine Welten (HNSW) und ortsabhängiges Hashing (LSH). Jede dieser Methoden trägt dazu bei, ähnliche Vektoren bei Bedarf effizient und effektiv abzurufen.

Untersuchen wir nun, wie eine Vektordatenbank in einem GenAI-System verwendet werden kann. Abbildung 1 veranschaulicht sowohl das Laden von Daten in eine Vektordatenbank als auch deren Verwendung im Rahmen einer GenAI-Anwendung. Wenn Sie Ihren Prompt eingeben, durchläuft er einen Transformationsprozess, der identisch mit dem ist, der zur Erzeugung von Vektoren in der Datenbank verwendet wird. Dieser transformierte Vektorprompt wird dann verwendet, um ähnliche Vektoren aus der Vektordatenbank abzurufen. Diese abgerufenen Elemente dienen im Wesentlichen als Gesprächsgedächtnis und liefern eine kontextbezogene Historie für Prompts, ähnlich wie LLMs funktionieren. Diese Funktion erweist sich als besonders vorteilhaft bei der Verarbeitung natürlicher Sprache, beim Computer-Vision, bei Empfehlungssystemen und in anderen Bereichen, die semantisches Verständnis und Datenabgleich erfordern. Ihre ursprüngliche Eingabeaufforderung wird anschließend mit den abgerufenen Elementen "verschmolzen", wodurch der Kontext geliefert wird und der LLM bei der Formulierung von Antworten auf der Grundlage des bereitgestellten Kontexts unterstützt wird, anstatt sich ausschließlich auf seine ursprünglichen Trainingsdaten zu verlassen.

Abbildung 1. Eine RAG-Anwendungsarchitektur.

Vektoren werden gespeichert und für einen schnellen Abruf indiziert. Es gibt zwei Arten von Vektordatenbanken: traditionelle Datenbanken, die für die Speicherung von Vektoren erweitert wurden, und speziell entwickelte Vektordatenbanken. Einige Beispiele für herkömmliche Datenbanken, die Vektoren unterstützen, sind Redis, pgvector, Elasticsearch und OpenSearch. Beispiele für speziell entwickelte Vektordatenbanken sind die proprietären Lösungen Zilliz und Pinecone sowie die Open-Source-Projekte Milvus, Weaviate, Qdrant, Faiss und Chroma. Sie können mehr über Vektordatenbanken auf GitHub über LangChain und OpenAI Cookbook erfahren.

Wir werden uns eine aus jeder Kategorie, Milvus und Redis, genauer ansehen.

Verbesserung der Leistung

Bevor wir uns mit den Optimierungen befassen, wollen wir uns ansehen, wie Vektordatenbanken bewertet werden, einige Bewertungs-Frameworks und verfügbare Tools zur Leistungsanalyse.

Leistungsmetriken

Schauen wir uns die wichtigsten Metriken an, mit denen Sie die Leistung von Vektordatenbanken messen können.

  • DieLadelatenz misst die Zeit, die benötigt wird, um Daten in den Speicher der Vektordatenbank zu laden und einen Index aufzubauen. Ein Index ist eine Datenstruktur, mit der Vektordaten auf der Grundlage ihrer Ähnlichkeit oder Entfernung effizient organisiert und abgerufen werden können. Zu den Arten von speicherinternen Indizes gehören Flat Index, IVF_FLAT, IVF_PQ, HNSW, Scalable Nearest Neighbors (ScaNN)und DiskANN.
  • Recall ist der Anteil der wahren Übereinstimmungen oder relevanten Elemente, die in den Top-K-Ergebnissen gefunden werden, die der Suchalgorithmus abruft. Höhere Recall-Werte deuten auf eine bessere Suche nach relevanten Elementen hin.
  • Abfragen pro Sekunde (QPS) ist die Rate, mit der die Vektordatenbank eingehende Abfragen verarbeiten kann. Höhere QPS-Werte bedeuten eine bessere Abfrageverarbeitungsfähigkeit und einen höheren Systemdurchsatz.

Benchmarking-Rahmenwerke

Abbildung 2. Der Rahmen für das Benchmarking von Vektordatenbanken.

Für das Benchmarking einer Vektordatenbank sind ein Vektordatenbankserver und Clients erforderlich. Für unsere Leistungstests haben wir zwei beliebte Open-Source-Tools verwendet.

  • VectorDBBench: VectorDBBench wurde von Zilliz entwickelt und ist als Open Source verfügbar. Es hilft beim Testen verschiedener Vektordatenbanken mit unterschiedlichen Indextypen und bietet eine komfortable Webschnittstelle.
  • vector-db-benchmark: vector-db-benchmark wurde von Qdrant entwickelt und ist als Open Source verfügbar. Es hilft beim Testen verschiedener typischer Vektordatenbanken für den HNSW-Indextyp. Es führt die Tests über die Befehlszeile aus und bietet eine Docker Compose __Datei, um das Starten von Serverkomponenten zu vereinfachen.

Abbildung 3. Ein Beispiel für einen vector-db-benchmark-Befehl, der zur Ausführung des Benchmark-Tests verwendet wird.

Der Benchmark-Rahmen ist jedoch nur ein Teil der Gleichung. Wir benötigen Daten, mit denen verschiedene Aspekte der Vektordatenbanklösung selbst getestet werden können, z. B. ihre Fähigkeit, große Datenmengen zu verarbeiten, verschiedene Vektorgrößen und die Geschwindigkeit des Abrufs.1 Sehen wir uns daher einige verfügbare öffentliche Datensätze an.

Offene Datensätze zum Testen von Vektordatenbanken

Große Datensätze eignen sich gut, um die Latenzzeit und die Ressourcenzuweisung zu testen. Einige Datensätze haben hochdimensionale Daten und eignen sich gut, um die Geschwindigkeit der Ähnlichkeitsberechnung zu testen.

Die Datensätze reichen von einer Dimension von 25 bis zu einer Dimension von 2048. Der LAION-Datensatz, eine offene Bildsammlung, wurde für das Training sehr großer visueller und sprachlicher tief-neuronaler Modelle wie stabile generative Diffusionsmodelle verwendet. Der OpenAI-Datensatz mit 5 Mio. Vektoren, jeder mit einer Dimension von 1536, wurde von VectorDBBench erstellt, indem OpenAI auf Rohdaten ausgeführt wurde. Da jedes Vektorelement vom Typ FLOAT ist, werden allein für die Speicherung der Vektoren ca. 29 GB (5M * 1536 * 4) Speicherplatz benötigt, plus eine ähnliche Menge zusätzlicher Speicher für Indizes und andere Metadaten, was insgesamt 58 GB Speicherplatz für die Tests ergibt. Wenn Sie das Tool vector-db-benchmark verwenden, sorgen Sie für ausreichenden Plattenspeicher zum Speichern der Ergebnisse.

Um die Latenzzeit zu testen, benötigten wir eine große Sammlung von Vektoren, die deep-image-96-angular bietet. Um die Leistung der Indexerstellung und der Ähnlichkeitsberechnung zu testen, bieten hochdimensionale Vektoren mehr Stress. Zu diesem Zweck wählten wir den 500K-Datensatz mit Vektoren der Dimension 1536.

Leistungstools

Wir haben uns damit beschäftigt, wie das System belastet werden kann, um interessante Metriken zu ermitteln, aber lassen Sie uns nun untersuchen, was auf einer niedrigeren Ebene passiert: Wie stark ist die Recheneinheit ausgelastet, wie hoch ist der Speicherverbrauch, wie lange wird auf Sperren gewartet und vieles mehr? Diese Informationen geben Aufschluss über das Datenbankverhalten und sind besonders nützlich, um Problembereiche zu identifizieren.

Das Linux-Dienstprogramm top liefert Informationen zur Systemleistung. Das Perf-Tool in Linux bietet jedoch eine Reihe von tieferen Einblicken. Um mehr darüber zu erfahren, empfehlen wir die Lektüre von Linux-Perf-Beispielen und der Intel Top-Down-Mikroarchitektur-Analysemethode. Ein weiteres Tool ist der Intel® vTune™ Profiler, der nicht nur bei der Optimierung von Anwendungen, sondern auch bei der Optimierung der Systemleistung und -konfiguration für eine Vielzahl von Workloads in den Bereichen HPC, Cloud, IoT, Medien, Speicher und mehr nützlich ist.

Milvus Vector Datenbank-Optimierungen

Gehen wir einige Beispiele durch, wie wir versucht haben, die Leistung der Milvus-Vektordatenbank zu verbessern.

Verringerung des Overheads für Speicherbewegungen beim Schreiben in den Datenknotenpuffer

Die Schreibpfad-Proxys von Milvus schreiben Daten über MsgStream in einen Log-Broker. Die Datenknoten verbrauchen dann die Daten, konvertieren und speichern sie in Segmente. Die Segmente fügen die neu eingefügten Daten zusammen. Die Zusammenführungslogik weist einen neuen Puffer zu, um sowohl die alten als auch die neu einzufügenden Daten aufzunehmen/zu verschieben, und gibt dann den neuen Puffer als alte Daten für die nächste Datenzusammenführung zurück. Dies führt dazu, dass die alten Daten sukzessive größer werden, was wiederum die Datenbewegung langsamer macht. Die Leistungsprofile zeigten einen hohen Overhead für diese Logik.

Abbildung 4. Das Zusammenführen und Verschieben von Daten in der Vektordatenbank verursacht einen hohen Leistungsaufwand.

Wir änderten die Logik des Zusammenführungspuffers so, dass die neuen Daten direkt an die alten Daten angehängt werden, wodurch die Zuweisung eines neuen Puffers und das Verschieben der großen alten Daten vermieden wird. Perf-Profile bestätigen, dass diese Logik keinen Overhead verursacht. Die Microcode-Metriken metric_CPU operating frequency und metric_CPU utilization zeigen eine Verbesserung an, die darauf zurückzuführen ist, dass das System nicht mehr auf die langen Speicherbewegungen warten muss. Die Ladelatenz verbesserte sich um mehr als 60 Prozent. Die Verbesserung ist auf GitHub festgehalten.

Abbildung 5. Mit weniger Kopiervorgängen sehen wir eine Leistungsverbesserung von mehr als 50 Prozent bei der Ladelatenz.

Invertierter Indexaufbau mit reduziertem Speicherzuweisungs-Overhead

Die Milvus-Suchmaschine Knowhere verwendet den Elkan k-means-Algorithmus zum Trainieren von Clusterdaten für die Erstellung von invertierten Dateiindizes (IVF). Jede Runde des Datentrainings definiert eine Iterationszahl. Je größer die Anzahl ist, desto besser sind die Trainingsergebnisse. Dies bedeutet jedoch auch, dass der Elkan-Algorithmus häufiger aufgerufen wird.

Der Elkan-Algorithmus führt bei jeder Ausführung Speicherzuweisungen und -freigaben durch. Insbesondere weist er Speicher zu, um die Hälfte der Größe der symmetrischen Matrixdaten zu speichern, wobei die Diagonalelemente ausgeschlossen werden. In Knowhere ist die vom Elkan-Algorithmus verwendete Dimension der symmetrischen Matrix auf 1024 festgelegt, was zu einer Speichergröße von etwa 2 MB führt. Das bedeutet, dass Elkan für jede Trainingsrunde wiederholt 2 MB Speicher zuweist und freigibt.

Die Perf-Profiling-Daten zeigten, dass häufig große Speicherzuweisungen vorgenommen wurden. Sie lösten die Zuweisung eines virtuellen Speicherbereichs (VMA), die Zuweisung einer physischen Seite, die Einrichtung einer Seitenübersicht und die Aktualisierung der Speicher-C-Gruppen-Statistik im Kernel aus. Dieses Muster großer Speicherzuweisungs- und -freigabeaktivitäten kann in manchen Situationen auch die Speicherfragmentierung verschlimmern. Dies ist eine erhebliche Steuer.

Die IndexFlatElkan-Struktur wurde speziell für die Unterstützung des Elkan-Algorithmus entwickelt und aufgebaut. Bei jedem Datentrainingsprozess wird eine IndexFlatElkan-Instanz initialisiert. Um die Auswirkungen der häufigen Speicherzuweisung und -freigabe im Elkan-Algorithmus auf die Leistung zu verringern, haben wir die Codelogik überarbeitet und die Speicherverwaltung außerhalb der Elkan-Algorithmusfunktion in den Konstruktionsprozess von IndexFlatElkan verlagert. Dadurch kann die Speicherzuweisung nur einmal während der Initialisierungsphase erfolgen, während alle nachfolgenden Funktionsaufrufe des Elkan-Algorithmus aus dem aktuellen Datentrainingsprozess heraus bedient werden, was zu einer Verbesserung der Ladelatenz um etwa 3 Prozent führt. Den Knowhere-Patch finden Sie hier.

Beschleunigung der Vektorsuche in Redis durch Software Prefetch

Redis, ein beliebter traditioneller In-Memory-Schlüsselwert-Datenspeicher, unterstützt seit kurzem die Vektorsuche. Um über einen typischen Key-Value-Speicher hinauszugehen, bietet er Erweiterungsmodule; das RediSearch-Modul ermöglicht die Speicherung und Suche von Vektoren direkt in Redis.

Für die Vektorähnlichkeitssuche unterstützt Redis zwei Algorithmen, nämlich Brute-Force und HNSW. Der HNSW-Algorithmus wurde speziell für die effiziente Suche nach ungefähren nächsten Nachbarn in hochdimensionalen Räumen entwickelt. Er verwendet eine Prioritätswarteschlange namens candidate_set, um alle Vektorkandidaten für die Abstandsberechnung zu verwalten.

Jeder Vektorkandidat enthält zusätzlich zu den Vektordaten umfangreiche Metadaten. Wenn ein Kandidat aus dem Speicher geladen wird, kann dies zu Fehlern im Datencache führen, was Verzögerungen bei der Verarbeitung zur Folge hat. Unsere Optimierung führt ein Software-Prefetching ein, um proaktiv den nächsten Kandidaten zu laden, während der aktuelle verarbeitet wird. Diese Verbesserung hat zu einer Durchsatzsteigerung von 2 bis 3 Prozent bei der Suche nach Vektorähnlichkeit in einer Redis-Einzelinstanz geführt. Der Patch wird derzeit in den Upstream eingespielt.

GCC-Standardverhaltensänderung zur Vermeidung von Strafen für gemischten Assemblercode

Um eine maximale Leistung zu erzielen, werden häufig verwendete Codeabschnitte oft von Hand in Assembler geschrieben. Wenn jedoch verschiedene Codesegmente entweder von verschiedenen Personen oder zu verschiedenen Zeitpunkten geschrieben werden, können die verwendeten Anweisungen aus inkompatiblen Assembler-Befehlssätzen wie Intel® Advanced Vector Extensions 512 (Intel® AVX-512) und Streaming SIMD Extensions (SSE) stammen. Wenn der gemischte Code nicht entsprechend kompiliert wird, führt dies zu einer Leistungseinbuße. Weitere Informationen zum Mischen von Intel AVX- und SSE-Anweisungen finden Sie hier.

Sie können leicht feststellen, ob Sie Mixed-Mode-Assemblercode verwenden und den Code nicht mit VZEROUPPER kompiliert haben, was zu Leistungseinbußen führt. Sie können dies mit einem Perf-Befehl wie sudo perf stat -e 'assists.sse_avx_mix/event/event=0xc1,umask=0x10/' <workload> feststellen . Wenn Ihr Betriebssystem keine Unterstützung für das Ereignis bietet, verwenden Sie cpu/event=0xc1,umask=0x10,name=assists_sse_avx_mix/.

Der Clang-Compiler fügt standardmäßig VZEROUPPER ein und vermeidet so jegliche Mixed-Mode-Strafe. Der GCC-Compiler fügt VZEROUPPER jedoch nur ein, wenn die Compilerflags -O2 oder -O3 angegeben wurden. Wir haben uns mit dem GCC-Team in Verbindung gesetzt und das Problem erläutert, und nun wird Assembler-Code im gemischten Modus standardmäßig korrekt behandelt.

Optimieren Sie Ihre Vektordatenbanken

Vektordatenbanken spielen eine wesentliche Rolle in GenAI, und sie werden immer größer, um qualitativ hochwertigere Antworten zu erzeugen. Im Hinblick auf die Optimierung unterscheiden sich KI-Anwendungen nicht von anderen Softwareanwendungen, da sie ihre Geheimnisse preisgeben, wenn man Standardwerkzeuge zur Leistungsanalyse zusammen mit Benchmark-Frameworks und Stress-Input einsetzt.

Mit diesen Tools haben wir Leistungsfallen aufgedeckt, die mit unnötiger Speicherzuweisung, fehlenden Prefetch-Anweisungen und der Verwendung falscher Compiler-Optionen zusammenhängen. Auf der Grundlage unserer Erkenntnisse haben wir Verbesserungen an Milvus, Knowhere, Redis und dem GCC-Compiler vorgenommen, um KI ein wenig leistungsfähiger und nachhaltiger zu machen. Vektordatenbanken sind eine wichtige Anwendungsklasse, die es wert ist, dass Sie sich um ihre Optimierung bemühen. Wir hoffen, dass dieser Artikel Ihnen bei den ersten Schritten hilft.

Like the article? Spread the word

Weiterlesen