Nouvelles
Modèles
API
keyboard_arrow_down
Lecteur
Lisez les URL et effectuez des recherches sur le Web pour de meilleurs LLM de base.
Intégrations
Intégrations multimodales et multilingues de classe mondiale.
Reclasseur
Récupérateur neuronal de classe mondiale pour maximiser la pertinence de la recherche.
Service d'inférence élastique
Exécutez les modèles Jina nativement au sein d'Elasticsearch.
MCP terminalCLIarticlellms.txtsmart_toyAgentsdata_objectSchémamenu_bookDocuments



Se connecter
login
GGUF de base et quantifiés
Utilisation et mises en garde
Intégration efficace via llama-embedding
Benchmark
Conclusion
Blog technique
août 13, 2025

Optimisation des GGUF pour les modèles de 向量模型 à décodeur uniquement

4000词元/秒 pour un modèle de 向量模型 de 3 milliards de paramètres sur GPU L4 est probablement la vitesse maximale que vous obtiendrez avec llama.cpp. Ou pas ?
Han Xiao
Han Xiao • 15 minutes lues

Il y a deux semaines, nous avons publié les formats GGUF de jina-embeddings-v4, un modèle de 向量模型 universel pour la recherche multimodale multilingue, avec diverses versions quantifiées. Notre motivation était simple : en tant que modèle de 3,75 milliards de paramètres, la version de transformateur vanilla de jina-embeddings-v4 ne s'adapte pas bien à nos instances d'API GCP G2 (GPU L4). Nous voulions donc accélérer l'inférence en utilisant ces versions GGUF plus petites et plus rapides. Au cours de nos expériences, nous avons fait des découvertes intéressantes lors de la conversion et de l'exécution de modèles de 向量模型 GGUF. Étant donné que la plupart de la communauté llama.cpp se concentre sur les 大模型, nous avons pensé qu'il serait intéressant de partager cela du point de vue d'un fournisseur de 向量模型.

Ce qui est particulièrement pertinent, c'est que les modèles de 向量模型 actuels sont presque identiques aux 大模型. Par exemple, jina-embeddings-v4 est basé sur Qwen2.5-VL-3B-instruct et jina-reranker-m0 est basé sur Qwen2-VL-2B. La seule différence réelle est la sortie : les 大模型 sont génératifs, les 向量模型 et les 重排器 sont discriminatifs. Cela crée à la fois des opportunités et des défis : d'une part, nous pouvons tirer parti de l'implémentation efficace de llama.cpp (par exemple, ubatch_size) pour servir des modèles de 向量模型 / 重排器 ; d'autre part, les implémentations de 向量模型 de llama.cpp ont été principalement développées pour les anciennes architectures d'encodeur uniquement (comme les modèles basés sur RoBERTa) et ne sont pas encore tout à fait au point avec les modèles de 向量模型 / 重排器 modernes à décodeur uniquement. Cet article partage ce que nous avons appris en adaptant les modèles de 向量模型 modernes pour qu'ils fonctionnent avec le format GGUF et l'outillage llama.cpp, par exemple llama-embedding et llama-serving.

tagGGUF de base et quantifiés

jina-embeddings-v4 est basé sur Qwen2.5-VL-3B-instruct avec trois adaptateurs LoRA : retrieval (optimisé pour les tâches de recherche), text-matching (optimisé pour les tâches de similarité de phrases) et code (optimisé pour les tâches de recherche de code). Il est également fortement entraîné pour la recherche de documents visuels et la sortie multi-vecteurs de style interaction tardive. L'idée ici est donc de tirer parti de l'implémentation de graphe existante de Qwen2.5-VL-3B dans llama.cpp et d'utiliser llama-embedding pour l'inférence.

Cependant, la première chose que nous avons remarquée est un comportement bogué dans l'implémentation de mmproj ou de vision transformer dans llama.cpp, qui produit des 向量模型 différents par rapport à l'implémentation torch de Qwen2.5-VL-3B avec la même entrée d'image. Pendant que nous corrigeons ce problème dans notre fork, nous avons décidé d'exclure la tour de vision des versions GGUF pour le moment. Vous pouvez trouver plus de détails sur cette discussion ici.

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

La sortie de 向量模型 multi-vecteurs n'est pas non plus prise en charge d'emblée, mais ce n'est pas un problème aussi important que les vision transformers. La sortie multi-vecteurs provient d'un MLP entraîné au dernier bloc de transformateur, donc au pire, nous pouvons toujours exporter ce MLP séparément vers numpy et l'appliquer après avoir obtenu les 向量模型 au niveau des 词元 à partir de llama.cpp - ce que nous avons fait pour jina-reranker-m0-GGUF. Bien sûr, ce n'est pas très efficace, mais cela fonctionne sans avoir à modifier et recompiler llama.cpp.

0:00
/0:04

Nous avons supprimé le vision transformer et le projecteur multi-vecteurs et avons obtenu trois modèles GGUF de base en F16.

Ainsi, pour nous conformer pleinement à l'implémentation de graphe existante de Qwen2.5-VL-3B dans llama.cpp, nous avons supprimé le vision transformer et le projecteur multi-vecteurs au dernier bloc de transformateur et avons fusionné tous les adaptateurs LoRA dans le modèle de langage de base. Cela nous a donné trois modèles v4 spécifiques à une tâche avec 3,09 milliards de paramètres chacun, contre 3,75 milliards de paramètres pour le v4 original :

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

Ensuite, nous avons utilisé calibration_data_v5_rc.txt (que vous pouvez trouver ici et qui est recommandé par Unsloth) pour calibrer les trois modèles GGUF de base et avons obtenu trois fichiers imatrix, puis nous avons utilisé llama-quantize avec imatrix pour quantifier les modèles de float16 comme suit :

# 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

Le script quantize.sh est présenté ci-dessous :

#!/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

Finalement, nous avons téléchargé toutes les quantifications sur HuggingFace.

Quantification BPW Taille du fichier (Go)
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

tagUtilisation et mises en garde

Nous pouvons maintenant utiliser llama-server et llama-embedding pour servir les GGUF pour l'intégration. Contrairement aux bibliothèques de transformateurs où nous avons la flexibilité d'écrire du code de prétraitement d'entrée personnalisé, nous devons gérer cette partie manuellement (à moins que nous ne voulions recompiler llama-server et llama-embedding). Plus précisément, pour obtenir des résultats qui sont entièrement cohérents avec l'utilisation de AutoModel.from_pretrained("jinaai/jina-embeddings-v4")..., vous devez être très prudent quant aux préfixes et les ajouter manuellement à vos entrées de modèle GGUF. Voici un tableau de référence :

Tâche prompt_name dans l'implémentation Transformer Entrée réelle du modèle
retrieval query (par défaut) Query: {original_text}
retrieval passage Passage: {original_text}
text-matching query (par défaut) Query: {original_text}
text-matching passage Query: {original_text} ⚠️
code query (par défaut) Query: {original_text}
code passage Passage: {original_text}

Certains utilisateurs pourraient trouver surprenant que ⚠️ prompt_name='passage' soit remplacé par "Query: " lors de l'utilisation de text-matching dans le AutoModel.from_pretrained("jinaai/jina-embeddings-v4").... d'origine. Mais cela a en fait du sens car text-matching est une tâche de similarité de phrases sans rôles gauche/droite : les entrées sont symétriques.

tagVia llama-server

Après avoir installé llama.cpp, vous pouvez exécuter llama-server pour héberger le modèle d'intégration en tant que serveur HTTP compatible avec l'API OpenAI. Par exemple, pour utiliser text-matching avec F16, vous pouvez faire :

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

--pooling mean est requis car v4 est une intégration de mise en commun moyenne.

Ensuite, envoyez la requête via :

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: 浜辺に沈む美しい夕日"
    ]
  }'

Lorsque vous utilisez les modèles retrieval et code, ajoutez Query: ou Passage: devant votre entrée, comme ceci :

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

Pour une vérification rapide, vous pouvez également utiliser llama-embedding précompilé pour l'intégration unique. Nous ne recommandons pas de l'utiliser pour l'intégration en masse car il présente des problèmes de performances dont nous discuterons dans la section suivante :

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

Lisez la section suivante pour une intégration en masse plus performante avec notre build de llama-embedding avec quelques corrections et améliorations.

tagRésumé des mises en garde

Avant de passer à une implémentation plus performante, résumons les mises en garde des modèles GGUF :

  • Vous devez ajouter manuellement Query: ou Passage: devant les entrées de texte.
  • Ils ne peuvent pas gérer les entrées d'image pour le moment car nous avons supprimé les transformateurs de vision du modèle GGUF. Nous avons dû les supprimer en raison de bogues dans l'implémentation du transformateur de vision/mmproj de Qwen2.5-vl-3b de llama.cpp, que nous nous efforçons de corriger avec l'amont.
  • Ils ne peuvent pas générer d'intégrations multi-vecteurs car cela ne fait pas partie de l'implémentation du graphe Qwen2.5-vl-3b de llama.cpp. La solution de contournement la plus simple sans recompiler llama.cpp consiste à exporter et à exécuter le MLP séparément après avoir obtenu des intégrations au niveau des Tokens en définissant --pooling none dans llama-embedding.
  • v4 est formé avec l'apprentissage de la représentation Matryoshka, et la conversion en GGUF préserve cette fonctionnalité. Si vous obtenez des intégrations avec la forme NxD, vous pouvez simplement utiliser embeddings[:, :truncate_dim] pour obtenir des intégrations tronquées plus petites. Cependant, toutes les dimensions ne sont pas entraînées. Pour v4, nous avons formé truncate_dim pour ces valeurs spécifiques : [128, 256, 512, 1024, 2048]. Cela signifie que la qualité de embeddings[:, :131] ne sera pas une interpolation entre la qualité de embeddings[:, :128] et embeddings[:, :256], mais sera considérablement pire que les intégrations à 128 dimensions ou à 256 dimensions car 131 dimensions ne sont pas entraînées.
  • Le chunking tardif peut toujours fonctionner dans le cadre du post-traitement après avoir obtenu des intégrations au niveau des Tokens via --pooling none. Tout comme ce que nous avons fait en séparant le MLP du graphe llama.cpp, ce n'est pas très efficace mais ne nécessite pas de recompilation. Cependant, il y a une autre mise en garde : étant donné que v4 est un modèle causal, le chunking tardif ne sera plus bidirectionnel - les intégrations de chunk antérieures ne contiendront pas d'informations contextuelles provenant des chunks suivants. N'oubliez pas que dans v3, chaque intégration de chunk avait des informations contextuelles globales car nous utilisions des masques d'attention bidirectionnels dans les blocs de transformateur. En interne, nous avons discuté de la question de savoir si la causalité rend le chunking tardif obsolète : certains soutiennent que "le contexte est également causal" - ce qui signifie qu'un lecteur traite le texte de gauche à droite, de sorte que le contexte nécessaire pour interpréter une phrase devrait provenir du texte précédent. D'autres disent que la restriction du chunking tardif à un bloc unidirectionnel le partage de contexte entre les chunks. Quoi qu'il en soit, l'efficacité du chunking tardif dans v4 reste discutable et nécessite une étude plus approfondie.

tagIntégration efficace via llama-embedding

llama-embedding est un wrapper C++ relativement simple au-dessus de llama.cpp pour intégrer du texte avec des E/S très propres : stdin, stdout. Nous nous concentrons sur l'amélioration de cela plutôt que sur llama-server pour le moment car il existe des tonnes d'autres problèmes tels que la mise en file d'attente réseau, l'équilibrage de charge, la multi-location et la sérialisation que nous pensons être hors de portée à ce stade. Notre question est simple : quelle vitesse pouvons-nous obtenir d'un GPU L4 24 Go, et quelle est l'utilisation maximale de la VRAM pour intégrer de longs documents ?

Mais pourquoi L4 ? Principalement parce que GCP offre des fonctions Cloud Run assez pratiques au-dessus, et c'est le type de GPU le plus largement disponible et économique que vous pouvez obtenir pour les API d'inférence sans serveur. GCP offre A100 et H100 sur Cloud Run sur demande, et l'équipe GCP nous propose de temps en temps d'utiliser de meilleurs GPU. Mais notre philosophie est simple : si nous avons besoin d'A100/H100 pour servir un modèle 3B, c'est clairement un problème de compétences de notre part.

Pour un peu de contexte, dans llama.cpp, la taille de lot logique (-b) représente le nombre maximum de 词元 envoyé au modèle lors d'un seul appel d'évaluation. Lors du traitement d'entrées longues, elles sont divisées en morceaux jusqu'à cette taille. La taille de lot physique (-ub) est le nombre réel de 词元 traités simultanément en une seule passe avant à travers le matériel, limité par la mémoire disponible. Les mises à jour du cache KV ont lieu après chaque lot physique. La fenêtre contextuelle (-c) est la limite stricte du nombre de 词元 que le modèle peut "voir" à la fois - pour les modèles v4, il s'agit de 32 000 词元, ce qui représente la portée d'attention maximale du modèle. Tous les 词元 doivent tenir dans cette fenêtre contextuelle pour maintenir une attention cohérente sur l'ensemble de la séquence. La figure suivante illustre leurs relations.

tagNos corrections

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

Dans notre fork ci-dessus, nous avons apporté plusieurs optimisations pour rendre llama-embedding plus efficace :

  • Gestion simplifiée des lots : nous définissons automatiquement -b comme égal à -c, ce qui rend ce paramètre obsolète. Les utilisateurs n'ont plus besoin de spécifier -b puisque nous exploitons toujours la longueur de contexte complète du modèle pour le traitement par lots logique.
  • Contrôle flexible de la mémoire : contrairement à l'implémentation d'origine où -ub était forcé d'être égal à -b (car ils supposaient que les modèles de 向量模型 ne pouvaient pas être causals), nous permettons aux utilisateurs de définir -ub indépendamment. Cela donne un contrôle précis sur l'utilisation maximale de la VRAM lors du codage de contextes longs - vous pouvez traiter un contexte de 32K avec un petit lot physique de 512 词元 pour rester dans les limites de la VRAM grâce à l'implémentation du cache KV. Notez que cette modification n'est correcte que pour les modèles de 向量模型 causals comme jina-embeddings-v4 - pour les architectures à codeur uniquement comme v3, ce serait la mauvaise implémentation.
  • Mise en commun moyenne fixe : nous avons corrigé le calcul de la mise en commun moyenne pour les 向量模型 lorsque ub < b, ce qui était auparavant cassé dans l'implémentation d'origine.

Cette modification facilite grandement l'utilisation de modèles de 向量模型 à décodage uniquement à contexte long tout en gérant efficacement les contraintes de mémoire. Les utilisateurs n'ont plus besoin de configurer que deux paramètres :

    • -c : la longueur de contexte maximale (combien de 词元 le modèle de 向量模型 peut traiter)
    • -ub : la taille du lot physique (combien de 词元 le GPU traite à la fois)

Voici donc le code exact pour exécuter notre fork sur L4 :

# 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"

Chaque ligne dans big_input.txt est une phrase à intégrer. --no-escape doit être défini pour empêcher que \n dans la phrase ne soit interprété comme des séparateurs. --flash-attn et -ngl 99 doivent être définis pour obtenir les meilleures performances sur le GPU L4.

tagBenchmark

Nous voulons comprendre les questions suivantes grâce à des benchmarks :

  • Quelle est la qualité de notre quantification par rapport au v4 Float16 d'origine ? À quel moment se dégrade-t-elle tellement qu'il serait préférable d'utiliser simplement les 向量模型 v3 ?
  • Quelle est la vitesse d'exécution de chaque quantification sur L4 et quelle est l'utilisation maximale de la VRAM ?
  • Comment la taille du lot physique -ub et la longueur du contexte -c affectent-elles la vitesse et l'utilisation maximale de la VRAM ?

Les ensembles de données que nous avons utilisés dans les benchmarks sont :

Tâche Documents Requêtes Paires pertinentes Longueur moyenne du document Longueur maximale du document Longueur moyenne de la requête
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

Nous avons utilisé notre build personnalisé de llama-embedding pour les benchmarks.

tagQualité des quantifications

La version quantifiée la plus performante est IQ3_M (3.84 BPW) - les quantifications inférieures à 2 bits sont moins performantes que v3, il est donc peu utile de les utiliser.

Quantification 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

tagVitesse et VRAM

Nous fixons maintenant l'ensemble de données de référence à NanoHotpotQA et traçons toutes les quantifications par leurs bits par poids par rapport à la vitesse (mesurée en nombre de jetons par seconde) et à la consommation de VRAM. Nous avons constaté que les versions GGUF sont légèrement plus rapides que la version vanilla en FP16 (2023 contre 1865 jetons/sec). La plupart des quantifications se regroupent autour de 2000 à 2100 jetons/sec. Avec la flash attention activée, nous obtenons une accélération d'environ 77 % sur toutes les quantifications (plus de 3000 contre plus de 2000 jetons/sec). Cependant, la quantification la plus performante, Q8_0, à environ 3700 jetons par seconde, est encore loin de la version vanilla v3 (572 millions de paramètres), qui atteint 16 000 jetons/sec. Les versions quantifiées permettent d'économiser une quantité considérable de VRAM et s'approchent presque du niveau du modèle v3 FP16 avec IQ3.

Quantification BPW Taille du fichier (Go) VRAM maximale (Go) Jeton/s avec FA Jeton/s sans 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

Cliquez pour afficher les informations système

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

tagTaille de lot physique et taille de contexte optimales

Nous fixons maintenant le type de quantification à IQ3_S et examinons comment la taille de lot physique (-ub) et la taille de contexte (-c) affectent la vitesse et la VRAM. Les résultats sur le GPU L4 montrent que -ub=512 avec -c=2048 fournit la configuration optimale, offrant 4 143 tokens/seconde tout en utilisant 2 025 Mo de VRAM. La conclusion est intuitive : lorsque vous connaissez la longueur maximale d’un seul document dans votre entrée, utilisez une taille de contexte plus petite, juste assez pour le couvrir. Pour la taille de lot physique, 512 tokens semblent être le point idéal sur le GPU L4.

Performance en Tokens par Seconde

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

Utilisation maximale de la VRAM (Mo)

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

tagConclusion

Pour les utilisateurs de v4 qui souhaitent exécuter GGUF quantifié efficacement sur des GPU à faible coût, choisissez IQ3_S ou IQ3_M avec notre version personnalisée de llama-embedding ; cela devrait vous donner 4 000 tokens/seconde sur des ensembles de données standard (où la longueur des phrases est < 2 048 tokens). Pour l’intégration de documents plus longs, augmentez la taille du contexte -c et contrôlez la taille de lot physique -ub pour réduire l’empreinte VRAM. Avec notre version personnalisée, vous pouvez encoder des documents très longs (> 32 000 tokens) en utilisant seulement 3 Go de VRAM en définissant -ub sur un petit nombre comme 1 024, ce qui n’était pas possible avec l’implémentation d’origine ou les transformateurs vanille.

La quête de l’optimisation de la vitesse ne se termine jamais. Il y a toujours de la place pour des implémentations plus rapides et plus légères avec un débit plus élevé. 4 000 tokens/seconde n’est probablement pas notre plafond ; il reste encore beaucoup de travail à faire. Au-delà de la correction de l’implémentation du transformateur mmproj/vision qwen2.5-vl-3b dans llama.cpp, nous explorons également des optimisations plus approfondies au niveau de llama.graph et du cache KV, améliorant la logique de traitement par lots llama-serving et ajoutant des options de diffusion en continu aux API d’intégration. Notre objectif est de faire en sorte que llama.cpp prenne en charge nativement les intégrations multimodales modernes avec décodeur uniquement pour nos versions de re-classement actuelles et futures.

Catégories:
Blog technique
rss_feed

En savoir plus
mars 11, 2026 • 7 minutes lues
Bootstrapping d'embeddings audio à partir de LLM multimodaux
Han Xiao
Abstract illustration of a sound wave or heartbeat, formed by blue, orange, and gray dots on a white background.
mars 06, 2026 • 6 minutes lues
Identifier les modèles d'embeddings à partir de valeurs numériques brutes
Han Xiao
Fingerprint illustration made from numbers, showcasing digital and high-tech design on a light background.
septembre 09, 2025 • 11 minutes lues
Les Embeddings multimodaux dans Llama.cpp et 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
Fondation Recherche
Lecteur
Intégrations
Reclasseur
Service d'inférence élastique
open_in_new
Obtenir la clé API Jina
Limite de taux
Statut de l'API
Entreprise
À propos de nous
Contacter le service commercial
Rédaction
Programme de stage
Télécharger le logo Jina
open_in_new
Télécharger le logo Elastic
open_in_new
Termes
Sécurité
termes et conditions
Confidentialité
Gérer les cookies
email
Élastique © 2020-2026.