Pressemitteilungen
Modelle
API
keyboard_arrow_down
Leser
Lesen Sie URLs und suchen Sie im Internet nach fundierteren LLMs.
Einbettungen
Multimodale und mehrsprachige Einbettungen von Weltklasse.
Reranker
Neural Retriever der Weltklasse zur Maximierung der Suchrelevanz.
MCP terminalCLIarticlellms.txtsmart_toyAgentendata_objectSchemamenu_bookDokumente



Einloggen
login
Base- und quantisierte GGUFs
Verwendung und Vorbehalte
Effiziente Vektorabbildungen über llama-embedding
Benchmark
Fazit
Tech-Blog
August 13, 2025

GGUFs für Decoder-Only 向量模型 optimieren

4000 Tokens/Sekunde für ein 3B-Parameter-Vektor-Modell auf einer L4-GPU ist wahrscheinlich das Schnellste, was man mit llama.cpp erreichen kann. Oder etwa nicht?
Han Xiao
Han Xiao • 15 Minuten gelesen
Vor zwei Wochen haben wir GGUF-Formate von jina-embeddings-v4 veröffentlicht – einem universellen 向量模型 für multimodale, mehrsprachige Suche – mit verschiedenen quantisierten Versionen. Unsere Motivation war einfach: Als Modell mit 3,75 Milliarden Parametern skaliert die Vanilla-Transformer-Version von jina-embeddings-v4 nicht gut auf unseren GCP G2 (L4 GPU) API-Instanzen. Daher wollten wir die Inferenz mithilfe dieser kleineren, schnelleren GGUF-Versionen beschleunigen. Während unserer Experimente haben wir einige interessante Erkenntnisse bei der Konvertierung und Ausführung von GGUF 向量模型n gewonnen. Da sich der Großteil der llama.cpp-Community auf 大模型n konzentriert, hielten wir es für wertvoll, dies aus der Perspektive eines 向量模型-Anbieters zu teilen. Besonders relevant ist, dass die heutigen 向量模型n fast identisch mit 大模型n sind – zum Beispiel basiert jina-embeddings-v4 auf Qwen2.5-VL-3B-instruct und jina-reranker-m0 basiert auf Qwen2-VL-2B. Der einzige wirkliche Unterschied ist die Ausgabe: 大模型n sind generativ, die 向量模型n und 重排器 sind diskriminativ. Dies schafft sowohl Chancen als auch Herausforderungen: Einerseits können wir die effiziente Implementierung von llama.cpp (z. B. ubatch_size) nutzen, um 向量模型/重排器 Modelle zu bedienen; andererseits wurden die 向量模型-Implementierungen von llama.cpp hauptsächlich für ältere Encoder-Only-Architekturen (wie RoBERTa-basierte Modelle) entwickelt und haben noch nicht vollständig mit modernen Decoder-Only 向量模型/重排器 Modellen aufgeholt. Dieser Artikel beschreibt, was wir beim Anpassen moderner 向量模型 an die Arbeit mit dem GGUF-Format und den llama.cpp-Tools, z. B. llama-embedding und llama-serving, gelernt haben.

tagBase- und quantisierte GGUFs

jina-embeddings-v4 basiert auf Qwen2.5-VL-3B-instruct mit drei LoRA-Adaptern: retrieval (optimiert für Retrieval-Aufgaben), text-matching (optimiert für Satzähnlichkeitsaufgaben) und code (optimiert für Code-Retrieval-Aufgaben). Es ist außerdem stark für visuelle Dokumentenabruf- und Late-Interaction-Style-Multi-Vektor-Ausgabe trainiert. Die Idee ist hier also, die bestehende Graph-Implementierung von Qwen2.5-VL-3B in llama.cpp zu nutzen und llama-embedding für die Inferenz zu verwenden. Das erste, was uns jedoch auffiel, war ein fehlerhaftes Verhalten in der mmproj- oder Vision-Transformer-Implementierung in llama.cpp, die bei gleicher Bildeingabe unterschiedliche 向量模型n im Vergleich zur Torch-Implementierung von Qwen2.5-VL-3B erzeugt. Während wir dieses Problem in unserem Fork beheben, haben wir beschlossen, den Vision Tower vorerst aus den GGUF-Versionen auszuschließen. Weitere Details zu dieser Diskussion finden Sie hier.
Multi-modal embeddings for jinaai/jina-embeddings-v4 · ggml-org llama.cpp · Discussion #14851
Hey folks! I’m working on getting multimodal embeddings working with jina-embeddings-v4 (based on Qwen 2.5 VL) through llama.cpp server. I’ve hit an issue with mtmd inconsistencies and was hoping s…
GitHubggml-org

Multi-Vektor-向量模型-Ausgabe wird auch nicht ohne Weiteres unterstützt, aber es ist kein so großes Problem wie die Vision Transformers. Die Multi-Vektor-Ausgabe stammt von einem trainierten MLP am letzten Transformer-Block, sodass wir diesen MLP schlimmstenfalls immer separat nach Numpy exportieren und anwenden können, nachdem wir die 词元-Level-向量模型n von llama.cpp erhalten haben – was wir für jina-reranker-m0-GGUF getan haben. Sicher, es ist nicht sehr effizient, aber es funktioniert, ohne dass wir llama.cpp modifizieren und neu kompilieren müssen.

0:00
/0:04

Wir haben den Vision Transformer und den Multi-Vektor-Projektor entfernt und drei Basis-GGUF-Modelle in F16 erhalten.

Um also die bestehende Qwen2.5-VL-3B-Graph-Implementierung von llama.cpp vollständig zu erfüllen, haben wir den Vision Transformer und den Multi-Vektor-Projektor am letzten Transformer-Block entfernt und alle LoRA-Adapter wieder in das Basis-Sprachmodell integriert. Dies ergab uns drei aufgabenspezifische v4-Modelle mit jeweils 3,09 Milliarden Parametern – gegenüber den ursprünglichen 3,75 Milliarden Parametern von v4:

HuggingFace Repo Task
jinaai/jina-embeddings-v4-text-retrieval-GGUF Text retrieval
jinaai/jina-embeddings-v4-text-code-GGUF Code retrieval
jinaai/jina-embeddings-v4-text-matching-GGUF Sentence similarity

Dann verwendeten wir calibration_data_v5_rc.txt (die hier zu finden ist und von Unsloth empfohlen wird), um alle drei Basis-GGUF-Modelle zu kalibrieren und drei imatrix-Dateien zu erhalten. Anschließend verwendeten wir llama-quantize mit imatrix, um die Modelle wie folgt von float16 zu quantisieren:

# build imatrix
llama-imatrix -m jina-embeddings-v4-text-retrieval-F16.gguf -f calibration_data_v5_rc.txt -ngl 99 --no-ppl -o imatrix-retrieval-512.dat

# quantize
./quantize.sh jina-embeddings-v4-text-retrieval-F16.gguf retrieval-i3 imatrix-retrieval-512.dat jinaai/jina-embeddings-v4-text-retrieval-GGUF

Das quantize.sh-Skript ist unten dargestellt:

#!/bin/bash

F16_MODEL_FILE="$1"
OUTPUT_DIR="$2"
IMATRIX="$3"
HF_REPO="$4"

FILENAME="$(basename "$F16_MODEL_FILE")"
BASE_NAME="${FILENAME%-F16.gguf}"
BASE_NAME="${BASE_NAME%.gguf}"

mkdir -p "$OUTPUT_DIR"

# Array of quantization types
QUANT_TYPES=("IQ1_S" "IQ1_M" "IQ2_XXS" "IQ2_M" "Q2_K" "IQ4_NL" "IQ4_XS"  "IQ3_XXS" "IQ3_S" "IQ3_M" "IQ3_XS" "Q3_K_M" "Q4_K_M" "Q5_K_S" "Q5_K_M" "Q6_K" "Q8_0")

for quant_type in "${QUANT_TYPES[@]}"; do
    llama-quantize --imatrix "${IMATRIX}" "$F16_MODEL_FILE" "${OUTPUT_DIR}/${BASE_NAME}-${quant_type}.gguf" $quant_type 8
done

Schließlich haben wir alle Quantisierungen auf HuggingFace hochgeladen.

Quantisierung BPW Dateigröße (GB)
IQ1_S 2.04 0.73
IQ1_M 2.19 0.79
IQ2_XXS 2.44 0.88
IQ2_M 2.94 1.06
Q2_K 3.29 1.18
IQ3_XXS 3.31 1.19
IQ3_XS 3.59 1.29
IQ3_S 3.76 1.35
IQ3_M 3.84 1.38
Q3_K_M 4.11 1.48
IQ4_NL 4.72 1.69
IQ4_XS 4.49 1.61
Q4_K_M 4.99 1.79
Q5_K_S 5.61 2.02
Q5_K_M 5.75 2.07
Q6_K 6.56 2.36
Q8_0 8.50 3.05
F16 16.00 5.75
v3 (Transformers) 16.00 1.10
v4 (Transformers) 16.00 7.40

tagVerwendung und Vorbehalte

Wir können jetzt llama-server und llama-embedding verwenden, um GGUFs für die Einbettung bereitzustellen. Im Gegensatz zu Transformer-Bibliotheken, bei denen wir die Flexibilität haben, benutzerdefinierten Eingabe-Preprocessing-Code zu schreiben, müssen wir diesen Teil manuell bearbeiten (es sei denn, wir möchten llama-server und llama-embedding neu kompilieren). Um Ergebnisse zu erhalten, die vollständig mit der Verwendung von AutoModel.from_pretrained("jinaai/jina-embeddings-v4")... übereinstimmen, müssen Sie sehr vorsichtig mit Präfixen sein und diese manuell zu Ihren GGUF-Modelleingaben hinzufügen. Hier ist eine Referenztabelle:

Aufgabe prompt_name in der Transformer-Implementierung Tatsächliche Eingabe in das Modell
retrieval query (Standard) Query: {original_text}
retrieval passage Passage: {original_text}
text-matching query (Standard) Query: {original_text}
text-matching passage Query: {original_text} ⚠️
code query (Standard) Query: {original_text}
code passage Passage: {original_text}

Einige Benutzer werden es vielleicht überraschend finden, dass ⚠️ prompt_name='passage' bei Verwendung von text-matching im ursprünglichen AutoModel.from_pretrained("jinaai/jina-embeddings-v4").... in "Query: " überschrieben wird. Dies ist jedoch sinnvoll, da text-matching eine Satzähnlichkeitsaufgabe ohne linke/rechte Rollen ist – die Eingaben sind symmetrisch.

tagVia llama-server

Nach der Installation von llama.cpp können Sie llama-server ausführen, um das Einbettungsmodell als OpenAI API-kompatiblen HTTP-Server zu hosten. Um beispielsweise text-matching mit F16 zu verwenden, können Sie Folgendes tun:

llama-server -hf jinaai/jina-embeddings-v4-text-matching-GGUF:F16 --embedding --pooling mean -ub 8192

--pooling mean ist erforderlich, da v4 Mean-Pooling- Vektormodelle sind.

Senden Sie dann eine Anfrage über:

curl -X POST "http://127.0.0.1:8080/v1/embeddings" \
  -H "Content-Type: application/json" \
  -d '{
    "input": [
      "Query: A beautiful sunset over the beach",
      "Query: Un beau coucher de soleil sur la plage",
      "Query: 海滩上美丽的日落",
      "Query: 浜辺に沈む美しい夕日"
    ]
  }'

Wenn Sie retrieval- und code-Modelle verwenden, fügen Sie Query: oder Passage: vor Ihrer Eingabe hinzu, wie folgt:

curl -X POST "http://127.0.0.1:8080/v1/embeddings" \
  -H "Content-Type: application/json" \
  -d '{
    "input": [
      "Query: A beautiful sunset over the beach",
      "Query: Un beau coucher de soleil sur la plage",
      "Passage: 海滩上美丽的日落",
      "Passage: 浜辺に沈む美しい夕日"
    ]
  }'

tagVia llama-embedding

Für eine schnelle Plausibilitätsprüfung können Sie auch die vorkompilierte llama-embedding für die einmalige Einbettung verwenden. Wir empfehlen nicht, sie für die Masseneinbettung zu verwenden, da sie einige Leistungsprobleme aufweist, die wir im nächsten Abschnitt besprechen werden:

llama-embedding -hf jinaai/jina-embeddings-v4-text-matching-GGUF:F16 --pooling mean -p "Query: jina is awesome" --embd-output-format json  2>/dev/null

Lesen Sie den nächsten Abschnitt für eine performantere Masseneinbettung mit unserer Version von llama-embedding mit einigen Korrekturen und Verbesserungen.

tagZusammenfassung der Vorbehalte

Bevor wir zu einer performanteren Implementierung übergehen, fassen wir die Vorbehalte von GGUF-Modellen zusammen:

  • Sie müssen manuell Query: oder Passage: vor den Texteingaben hinzufügen.
  • Sie können derzeit keine Bildeingaben verarbeiten, da wir die Vision-Transformer aus dem GGUF-Modell entfernt haben. Wir mussten sie aufgrund von Fehlern in der Vision-Transformer-/mmproj-Implementierung von Qwen2.5-vl-3b in llama.cpp entfernen, an deren Behebung wir mit Upstream arbeiten.
  • Sie können keine Multi-Vektor- Einbettungen ausgeben, da dies nicht Teil der Qwen2.5-vl-3b-Graphenimplementierung von llama.cpp ist. Die einfachste Problemumgehung, ohne llama.cpp neu zu kompilieren, besteht darin, das MLP zu exportieren und separat auszuführen, nachdem Vektorabbildungen auf Token-Ebene abgerufen wurden, indem --pooling none in llama-embedding festgelegt wird.
  • v4 ist mit Matryoshka-Darstellungslernen trainiert, und die Konvertierung in GGUF behält dieses Merkmal bei. Wenn Sie Vektorabbildungen mit der Form NxD erhalten, können Sie einfach embeddings[:, :truncate_dim] verwenden, um kleinere, abgeschnittene Vektorabbildungen zu erhalten. Allerdings wird nicht jede Dimension trainiert. Für v4 haben wir truncate_dim für diese spezifischen Werte trainiert: [128, 256, 512, 1024, 2048]. Dies bedeutet, dass die Qualität von embeddings[:, :131] keine Interpolation zwischen der Qualität von embeddings[:, :128] und embeddings[:, :256] ist, sondern deutlich schlechter als entweder 128-dim- oder 256-dim- Vektorabbildungen, da 131-dim nicht trainiert ist.
  • Spätes Chunking kann weiterhin als Teil der Nachbearbeitung funktionieren, nachdem Vektorabbildungen auf Token-Ebene über --pooling none abgerufen wurden. So wie wir das MLP vom llama.cpp-Graphen getrennt haben, ist dies nicht besonders effizient, erfordert aber keine Neukompilierung. Es gibt jedoch einen weiteren Vorbehalt: Da v4 ein kausales Modell ist, wird spätes Chunking nicht mehr bidirektional sein – frühere Chunk- Vektorabbildungen enthalten keine Kontextinformationen aus nachfolgenden Chunks. Denken Sie daran, dass in v3 jede Chunk- Vektorabbildung globale Kontextinformationen enthielt, da wir bidirektionale Aufmerksamkeitsmasken in den Transformer-Blöcken verwendet haben. Intern haben wir diskutiert, ob Kausalität spätes Chunking überflüssig macht: Einige argumentieren, dass "Kontext auch kausal ist" – das heißt, ein Leser verarbeitet Text von links nach rechts, sodass der Kontext, der zur Interpretation eines Satzes benötigt wird, aus dem vorhergehenden Text stammen sollte. Andere sagen, dass die Beschränkung von spätem Chunking auf unidirektionale Blöcke die gemeinsame Nutzung von Kontexten zwischen Chunks verhindert. In jedem Fall bleibt die Wirksamkeit von spätem Chunking in v4 fraglich und bedarf weiterer Untersuchungen.

tagEffiziente Vektorabbildungen über llama-embedding

llama-embedding ist ein relativ einfacher C++-Wrapper auf Basis von llama.cpp zur Einbettung von Text mit sehr sauberem I/O: stdin, stdout. Wir konzentrieren uns im Moment darauf, dies zu verbessern, anstatt llama-server, da es unzählige andere Probleme wie Netzwerk-Queuing, Lastverteilung, Multi-Tenancy und Serialisierung gibt, die unserer Meinung nach an dieser Stelle nicht relevant sind. Unsere Frage ist einfach: Wie viel Geschwindigkeit können wir von einer L4 24GB GPU bekommen und wie hoch ist die maximale VRAM-Auslastung für die Einbettung langer Dokumente?

Aber warum L4? Hauptsächlich, weil GCP recht praktische Cloud Run-Funktionen darauf anbietet und es der am weitesten verbreitete und wirtschaftlichste GPU-Typ ist, den Sie für serverlose Inferenz-APIs erhalten können. GCP bietet auf Anfrage A100 und H100 auf Cloud Run an, und wir werden von Zeit zu Zeit vom GCP-Team angesprochen, bessere GPUs zu verwenden. Aber unsere Philosophie ist einfach: Wenn wir A100/H100 benötigen, um ein 3B-Modell zu bedienen, ist das eindeutig ein Problem unsererseits.

Für einige Hintergrundinformationen: In llama.cpp ist die logische Batch-Größe (-b) stellt die maximale Anzahl an Tokens dar, die dem Modell in einem einzelnen Auswertungsvorgang übermittelt werden. Bei der Verarbeitung langer Eingaben werden diese in Abschnitte bis zu dieser Größe aufgeteilt. Die physische Batch-Größe (-ub) ist die tatsächliche Anzahl an Tokens, die gleichzeitig in einem Vorwärtsdurchlauf durch die Hardware verarbeitet werden, begrenzt durch den verfügbaren Speicher. Die KV-Cache-Aktualisierungen erfolgen nach Abschluss jedes physischen Batches. Das Kontextfenster (-c) ist die harte Grenze für die Anzahl der Tokens, die das Modell gleichzeitig "sehen" kann - für v4-Modelle sind dies 32.000 Tokens, die die maximale Aufmerksamkeitsspanne des Modells darstellen. Alle Tokens müssen in dieses Kontextfenster passen, um eine kohärente Aufmerksamkeit über die gesamte Sequenz aufrechtzuerhalten. Die folgende Abbildung veranschaulicht ihre Beziehungen.

tagUnsere Korrekturen

GitHub - hanxiao/llama.cpp: LLM inference in C/C++
LLM inference in C/C++. Contribute to hanxiao/llama.cpp development by creating an account on GitHub.
GitHubhanxiao

In unserem obigen Fork haben wir mehrere Optimierungen vorgenommen, um llama-embedding effizienter zu gestalten:

  • Vereinfachte Batch-Verarbeitung: Wir setzen -b automatisch gleich -c, wodurch dieser Parameter faktisch hinfällig wird. Benutzer müssen -b nicht mehr angeben, da wir immer die volle Kontextlänge des Modells für die logische Batch-Verarbeitung nutzen.
  • Flexible Speichersteuerung: Im Gegensatz zur ursprünglichen Implementierung, bei der -ub gezwungen war, gleich -b zu sein (da sie davon ausgingen, dass Einbettungsmodelle nicht kausal sein können), erlauben wir Benutzern, -ub unabhängig festzulegen. Dies ermöglicht eine feinkörnige Kontrolle über die maximale VRAM-Auslastung beim Codieren langer Kontexte - Sie können einen 32K-Kontext mit einem kleinen physischen 512-Token-Batch verarbeiten, um dank der KV-Cache-Implementierung innerhalb der VRAM-Grenzwerte zu bleiben. Beachten Sie, dass diese Änderung nur für kausale Einbettungsmodelle wie jina-embeddings-v4 korrekt ist - für reine Encoder-Architekturen wie v3 wäre dies die falsche Implementierung.
  • Korrigiertes Mean Pooling: Wir haben die Mean-Pooling-Berechnung für Vektormodelle korrigiert, wenn ub < b, die zuvor in der ursprünglichen Implementierung fehlerhaft war.

Diese Änderung erleichtert die Arbeit mit Decoder-only Vektormodellen mit langer Kontextlänge und gleichzeitig effektiver Verwaltung von Speicherbeschränkungen erheblich. Benutzer müssen jetzt nur noch zwei Parameter konfigurieren:

    • -c: Die maximale Kontextlänge (wie viele Tokens das Einbettungsmodell verarbeiten kann)
    • -ub: Die physische Batch-Größe (wie viele Tokens die GPU gleichzeitig verarbeitet)

Der genaue Code für die Ausführung unseres Forks auf L4 lautet wie folgt:

# Compile
git clone https://github.com/hanxiao/llama.cpp.git
cd llama.cpp
cmake -B build -DGGML_CUDA=ON
cmake --build build --config Release -j 8

# Run
INPUT_PREFIX="Query: "  # or "Passage: "

cat big_input.txt | sed "s/^/${INPUT_PREFIX}/" | \
./llama.cpp/build/bin/llama-embedding -f /dev/stdin \
    -hf "jinaai/jina-embeddings-v4-text-retrieval-GGUF:FP16" \
    --pooling mean \
    --no-escape \
    --embd-output-format array \
    --ubatch-size 512 \
    --ctx-size 8192 \
    --flash-attn \
    -ngl 99 \
    > "embeddings.txt" 2> "error.log"

Jede Zeile in big_input.txt ist ein Satz, der eingebettet werden soll. --no-escape sollte gesetzt werden, um zu verhindern, dass \n im Satz als Trennzeichen interpretiert wird. --flash-attn und -ngl 99 sollten für die beste Leistung auf der L4 GPU gesetzt werden.

tagBenchmark

Wir möchten durch Benchmarking die folgenden Fragen beantworten:

  • Wie gut ist unsere Quantisierung im Vergleich zum ursprünglichen v4 Float16? Ab welchem Punkt verschlechtert sie sich so stark, dass wir besser dran wären, nur v3 Vektormodelle zu verwenden?
  • Wie schnell kann jede Quantisierung auf L4 laufen und wie hoch ist die maximale VRAM-Auslastung?
  • Wie beeinflussen die physische Batch-Größe -ub und die Kontextlänge -c die Geschwindigkeit und die maximale VRAM-Auslastung?

Datensätze, die wir im Benchmarking verwendet haben, sind:

Task Documents Queries Relevant Pairs Avg Doc Length Max Doc Length Avg Query Length
NanoHotpotQA 5,090 50 100 57.3 345 14.9
NanoSciFact 2,919 50 56 205.8 1524 13.5
NanoArguAna 3,635 50 50 164.5 1058 193.0
NanoNFCorpus 2,953 50 2,518 223.3 1460 3.3
NanoFiQA2018 4,598 50 123 159.1 1882 10.2

Wir haben unseren benutzerdefinierten Build von llama-embedding für das Benchmarking verwendet.

tagQualität der Quantisierungen

Die am besten abschneidende quantisierte Version ist IQ3_M (3.84 BPW) - Quantisierungen unter 2 Bit schneiden schlechter ab als v3, daher ist es wenig sinnvoll, sie zu verwenden.

Quantisierung NanoHotpotQA NanoFiQA2018 NanoArguAna NanoNFCorpus NanoSciFact
IQ1_S 0.6369 0.3178 0.3798 0.2933 0.5934
IQ1_M 0.6316 0.3313 0.5167 0.3256 0.6114
IQ2_XXS 0.7236 0.4582 0.4584 0.4067 0.7392
IQ2_M 0.7427 0.5869 0.5090 0.4468 0.7880
Q2_K 0.7683 0.5744 0.5168 0.4183 0.7546
IQ3_XXS 0.7780 0.5991 0.4811 0.4267 0.7610
IQ3_XS 0.7727 0.5615 0.5195 0.4439 0.7726
IQ3_S 0.8002 0.5505 0.4886 0.4381 0.7690
IQ3_M 0.8106 0.5387 0.5091 0.4462 0.7760
Q3_K_M 0.7567 0.5267 0.4486 0.4092 0.7775
IQ4_NL 0.7930 0.5598 0.4911 0.4285 0.7794
IQ4_XS 0.7979 0.5627 0.4947 0.4258 0.7789
Q4_K_M 0.8029 0.5569 0.4883 0.4226 0.7877
Q5_K_S 0.7969 0.5581 0.4721 0.4288 0.7842
Q5_K_M 0.7927 0.5601 0.4745 0.4247 0.7873
Q6_K 0.7951 0.5636 0.4822 0.4337 0.7846
Q8_0 0.7938 0.5687 0.4784 0.4335 0.7851
F16 0.7940 0.5610 0.4931 0.4343 0.7963
v3 (Transformers) 0.7393 0.5144 0.4600 0.4068 0.7820
v4 (Transformers) 0.7977 0.5571 0.4844 0.4351 0.7963

tagGeschwindigkeit und VRAM

Wir legen nun den Benchmark-Datensatz auf NanoHotpotQA fest und stellen alle Quantisierungen nach ihren Bits pro Gewichtung im Vergleich zur Geschwindigkeit (gemessen in Tokens pro Sekunde) und dem VRAM-Verbrauch dar. Wir haben festgestellt, dass GGUF-Versionen bei FP16 etwas schneller sind als die Vanilla-Version (2023 vs. 1865 Tokens/Sek.). Die meisten Quantisierungen gruppieren sich um 2000-2100 Tokens/Sek. Mit aktivierter Flash-Attention erhalten wir eine Geschwindigkeitssteigerung von ~77 % über alle Quantisierungen hinweg (3000+ vs. 2000+ Tokens/Sek.). Die am besten abschneidende Quantisierung Q8_0 mit etwa 3700 Tokens pro Sekunde liegt jedoch immer noch weit hinter Vanilla v3 (572M Parameter) zurück, die 16000 Tokens/Sek. erreicht. Quantisierte Versionen sparen erheblich VRAM und nähern sich mit IQ3 fast dem Niveau des v3 FP16-Modells.

Quantisierung BPW Dateigröße (GB) Spitzen-VRAM (GB) Token/s mit FA Token/s ohne FA
IQ1_S 2.04 0.73 4.04 3625 2050
IQ1_M 2.19 0.79 4.09 3349 1997
IQ2_XXS 2.44 0.88 4.19 3701 2071
IQ2_M 2.94 1.06 4.37 3407 1989
Q2_K 3.29 1.18 4.49 3173 1905
IQ3_XXS 3.31 1.19 4.50 3668 2067
IQ3_XS 3.59 1.29 4.60 3604 2053
IQ3_S 3.76 1.35 4.66 3599 2049
IQ3_M 3.84 1.38 4.69 3603 2053
Q3_K_M 4.11 1.48 4.78 3450 2008
IQ4_NL 4.72 1.69 5.00 3571 2039
IQ4_XS 4.49 1.61 4.92 3585 2046
Q4_K_M 4.99 1.79 5.10 3558 2045
Q5_K_S 5.61 2.02 5.32 3567 2044
Q5_K_M 5.75 2.07 5.38 3528 2034
Q6_K 6.56 2.36 5.66 3334 1981
Q8_0 8.50 3.05 6.36 3767 2101
F16 16.00 5.75 9.70 3399 2023
v3 (Transformers) 16.00 1.10 2.82 16505
v4 (Transformers) 16.00 7.40 14.45 1865

Zum Erweitern der Systeminfo klicken

load_tensors: loading model tensors, this can take a while... (mmap = true)
load_tensors: offloading 36 repeating layers to GPU
load_tensors: offloading output layer to GPU
load_tensors: offloaded 37/37 layers to GPU
load_tensors: CUDA0 model buffer size = 3127.61 MiB
load_tensors: CPU_Mapped model buffer size = 315.30 MiB
...................................................................................
llama_context: constructing llama_context
llama_context: n_seq_max = 1
llama_context: n_ctx = 4096
llama_context: n_ctx_per_seq = 4096
llama_context: n_batch = 4096
llama_context: n_ubatch = 4096
llama_context: causal_attn = 1
llama_context: flash_attn = 1 // 1 for w/ FA in the table; 0 for w/o FA
llama_context: kv_unified = true
llama_context: freq_base = 1000000.0
llama_context: freq_scale = 1
llama_context: n_ctx_per_seq (4096) < n_ctx_train (128000) -- the full capacity of the model will not be utilized
llama_context: CUDA_Host output buffer size = 0.59 MiB
llama_kv_cache_unified: CUDA0 KV buffer size = 144.00 MiB
llama_kv_cache_unified: size = 144.00 MiB ( 4096 cells, 36 layers, 1/1 seqs), K (f16): 72.00 MiB, V (f16): 72.00 MiB
llama_context: CUDA0 compute buffer size = 2470.16 MiB
llama_context: CUDA_Host compute buffer size = 96.17 MiB
llama_context: graph nodes = 1234
llama_context: graph splits = 2
common_init_from_params: added <|endoftext|> logit bias = -inf
common_init_from_params: added <|im_end|> logit bias = -inf
common_init_from_params: added <|fim_pad|> logit bias = -inf
common_init_from_params: added <|repo_name|> logit bias = -inf
common_init_from_params: added <|file_sep|> logit bias = -inf
common_init_from_params: setting dry_penalty_last_n to ctx_size = 4096
common_init_from_params: warming up the model with an empty run - please wait ... (--no-warmup to disable)

system_info: n_threads = 4 (n_threads_batch = 4) / 8 | CUDA : ARCHS = 890 | USE_GRAPHS = 1 | PEER_MAX_BATCH_SIZE = 128 | CPU : SSE3 = 1 | SSSE3 = 1 | AVX = 1 | AVX2 = 1 | F16C = 1 | FMA = 1 | BMI2 = 1 | AVX512 = 1 | AVX512_VNNI = 1 | LLAMAFILE = 1 | OPENMP = 1 | REPACK = 1 |
main: n_tokens in batch = 0
main: number of embeddings = 5090

tagOptimale physische Batch- und Kontextgröße

Wir legen nun den Quantisierungstyp auf IQ3_S fest und untersuchen, wie sich die physische Batchgröße (-ub) und die Kontextgröße (-c) auf die Geschwindigkeit und den VRAM auswirken. Die Ergebnisse auf der L4-GPU zeigen, dass -ub=512 mit -c=2048 die optimale Konfiguration darstellt, die 4.143 Tokens/Sek. liefert und dabei 2.025 MB VRAM verbraucht. Die Erkenntnis ist intuitiv: Wenn Sie die maximale Länge eines einzelnen Dokuments in Ihrer Eingabe kennen, verwenden Sie eine kleinere Kontextgröße, die gerade ausreicht, um es abzudecken. Für die physische Batchgröße scheinen 512 Tokens der Sweet Spot auf der L4-GPU zu sein.

Tokens pro Sekunde Leistung

ubatch_size ctx_size=64 ctx_size=128 ctx_size=256 ctx_size=512
64 2233 2093 2128 2125
128 N/A 2866 2821 2877
256 N/A N/A 3287 3349
512 N/A N/A N/A 3469
ubatch_size ctx_size=2048 ctx_size=4096 ctx_size=8192 ctx_size=16384
256 3971 3630 3593 2766
512 4143 3797 3758 2852
1024 4059 3742 3707 2822
2048 3957 3631 3603 2762
4096 N/A 3450 3410 2625

Maximale VRAM-Nutzung (MB)

ubatch_size ctx_size=64 ctx_size=128 ctx_size=256 ctx_size=512
64 1691 1689 1689 1697
128 N/A 1729 1727 1737
256 N/A N/A 1803 1811
512 N/A N/A N/A 1963
ubatch_size ctx_size=2048 ctx_size=4096 ctx_size=8192 ctx_size=16384
256 1885 1947 2099 2409
512 2025 2101 2257 2577
1024 2329 2407 2571 2917
2048 2933 3025 3203 3597
4096 N/A 4285 4497 4985

tagFazit

Für v4-Benutzer, die quantisierte GGUF effizient auf kostengünstigen GPUs ausführen möchten, wählen Sie IQ3_S oder IQ3_M mit unserem benutzerdefinierten Build von llama-embedding - dies sollte Ihnen 4000 Tokens/Sek. auf regulären Datensätzen (bei denen die Satzlänge <2048 Tokens beträgt) liefern. Um längere Dokumente einzubetten, erhöhen Sie die Kontextgröße -c und steuern Sie die physische Batchgröße -ub, um den VRAM-Fußabdruck zu reduzieren. Mit unserem benutzerdefinierten Build können Sie super lange Dokumente (>32K Tokens) mit nur 3 GB VRAM kodieren, indem Sie -ub auf eine kleine Zahl wie 1024 setzen - etwas, das mit der ursprünglichen Implementierung oder Vanilla-Transformern nicht möglich war.

Die Suche nach Geschwindigkeitsoptimierung endet nie. Es gibt immer Raum für schnellere, schlankere Implementierungen mit höherem Durchsatz. 4000 Tokens/Sek. sind wahrscheinlich nicht unsere Obergrenze - es gibt noch viel zu tun. Neben der Behebung der qwen2.5-vl-3b mmproj/Vision-Transformer-Implementierung in llama.cpp untersuchen wir auch tiefere Optimierungen auf Llama.graph- und KV-Cache-Ebene, verbessern die Batching-Logik von llama-serving und fügen Streaming-Optionen zu Embedding-APIs hinzu. Unser Ziel ist es, dass llama.cpp nativ moderne, reine Dekoder-Multimodal- Embeddings für unsere aktuellen und zukünftigen Reranker-Releases unterstützt.

Kategorien:
Tech-Blog
rss_feed

Weiterlesen
März 11, 2026 • 7 Minuten gelesen
Bootstrapping von Audio-Embeddings aus multimodalen LLMs
Han Xiao
Abstract illustration of a sound wave or heartbeat, formed by blue, orange, and gray dots on a white background.
März 06, 2026 • 6 Minuten gelesen
Identifizierung von Einbettungsmodellen anhand numerischer Rohwerte
Han Xiao
Fingerprint illustration made from numbers, showcasing digital and high-tech design on a light background.
September 09, 2025 • 11 Minuten gelesen
Multimodale Vektormodelle in Llama.cpp und GGUF
Andrei Ungureanu
Alex C-G
Cartoon llama in the center of a white background, emitting laser-like beams from its eyes. The illustration creates a playfu
Büros
location_on
Sunnyvale, Kalifornien
710 Lakeway Dr, Ste 200, Sunnyvale, CA 94085, USA
location_on
Berlin, Deutschland
Prinzessinnenstraße 19-20, 10969 Berlin, Deutschland
Stiftung durchsuchen
Leser
Einbettungen
Reranker
Jina API-Schlüssel abrufen
Ratenbegrenzung
API-Status
Unternehmen
Über uns
Kontaktieren Sie unseren Vertrieb
Pressemitteilungen
Praktikantenprogramm
Jina-Logo herunterladen
open_in_new
Elastic-Logo herunterladen
open_in_new
Bedingungen
Sicherheit
Terms & amp; Bedingungen
Privatsphäre
Cookie-Einstellungen
email
Jina AI von Elastic © 2020-2026.