Notizia
Modelli
Prodotti
keyboard_arrow_down
Lettore
Leggi gli URL e cerca sul web per ottenere LLM più approfonditi.
Incorporamenti
Incorporamenti multilingue multimodali di livello mondiale.
Riclassificazione
Recupero neurale di livello mondiale per massimizzare la pertinenza della ricerca.
Ricerca profonda
Cerca, leggi e ragiona finché non trovi la risposta migliore.
Di più
keyboard_arrow_down
Classificatore
Classificazione zero-shot e few-shot per immagini e testo.
Segmentatore
Tagliare il testo lungo in blocchi ed effettuare la tokenizzazione.

Server MCP
Aggiungi mcp.jina.ai come server MCP per accedere alla nostra API in LLM
open_in_new
Documentazione API
Generazione automatica di codice per il tuo IDE o LLM di Copilot
open_in_new


Azienda
keyboard_arrow_down
Chi siamo
Contatta le vendite
Programma di stagista
Unisciti a noi
open_in_new
Scarica il logo
open_in_new
Termini & Condizioni


Login
login
GGUF di base e quantizzati
Utilizzo e avvertenze
Embedding efficiente tramite llama-embedding
Benchmark
Conclusione
Blog tecnico
agosto 13, 2025

Ottimizzazione dei GGUF per i modelli di Embeddings solo decoder

Ottenere 4000 token/sec per un modello di 向量模型 da 3 miliardi di parametri su GPU L4 è probabilmente il massimo che si possa ottenere con llama.cpp. O forse no?
Han Xiao
Han Xiao • 15 minuti letti

Due settimane fa, abbiamo rilasciato i formati GGUF di jina-embeddings-v4, un modello di embedding universale per il recupero multimodale multilingue, con varie versioni quantizzate. La nostra motivazione era semplice: come modello con parametri da 3,75B, la versione transformer vanilla di jina-embeddings-v4 non scala bene sulle nostre istanze API GCP G2 (GPU L4), quindi volevamo accelerare l'inferenza utilizzando queste versioni GGUF più piccole e veloci. Durante i nostri esperimenti, abbiamo scoperto alcune scoperte interessanti durante la conversione e l'esecuzione di modelli di embedding GGUF. Poiché la maggior parte della community di llama.cpp si concentra sugli LLM, abbiamo pensato che sarebbe stato utile condividere questo punto di vista dal punto di vista di un fornitore di embedding.

Ciò che è particolarmente rilevante è che i modelli di embedding odierni sono quasi identici agli LLM: ad esempio, jina-embeddings-v4 è basato su Qwen2.5-VL-3B-instruct e jina-reranker-m0 è basato su Qwen2-VL-2B. L'unica vera differenza è l'output: gli LLM sono generativi, gli embedding e i reranker sono discriminativi. Questo crea sia opportunità che sfide: da un lato, possiamo sfruttare l'implementazione efficiente di llama.cpp (ad esempio, ubatch_size) per servire modelli di embedding/reranker; dall'altro, le implementazioni di embedding di llama.cpp sono state sviluppate principalmente per architetture encoder-only più vecchie (come i modelli basati su RoBERTa) e non si sono completamente allineate con i moderni modelli di embedding/reranker decoder-only. Questo articolo condivide ciò che abbiamo imparato adattando i moderni modelli di embedding per funzionare con il formato GGUF e gli strumenti di llama.cpp, ad esempio llama-embedding e llama-serving.

tagGGUF di base e quantizzati

jina-embeddings-v4 è basato su Qwen2.5-VL-3B-instruct con tre adattatori LoRA: retrieval (ottimizzato per attività di recupero), text-matching (ottimizzato per attività di similarità di frasi) e code (ottimizzato per attività di recupero di codice). È anche ampiamente addestrato per il recupero di documenti visivi e l'output multi-vettore in stile late-interaction. Quindi l'idea qui è di sfruttare l'implementazione del grafo esistente di llama.cpp di Qwen2.5-VL-3B e utilizzare llama-embedding per l'inferenza.

Tuttavia, la prima cosa che abbiamo notato è stato un comportamento difettoso nell'implementazione di mmproj o vision transformer in llama.cpp, che produce embedding diversi rispetto all'implementazione torch di Qwen2.5-VL-3B dato lo stesso input di immagine. Mentre stiamo risolvendo questo problema nel nostro fork, abbiamo deciso di escludere la vision tower dalle versioni GGUF per ora. Puoi trovare maggiori dettagli su questa discussione qui.

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

L'output di embedding multi-vettore non è supportato immediatamente, ma non è un problema così grande come i vision transformer. L'output multi-vettore proviene da un MLP addestrato all'ultimo blocco transformer, quindi nel peggiore dei casi possiamo sempre esportare questo MLP separatamente in numpy e applicarlo dopo aver ottenuto gli embedding a livello di token da llama.cpp - che è quello che abbiamo fatto per jina-reranker-m0-GGUF. Certo, non è molto efficiente, ma funziona senza dover modificare e ricompilare llama.cpp.

0:00
/0:04

Abbiamo rimosso il vision transformer e il proiettore multi-vettore e abbiamo ottenuto tre modelli GGUF di base in F16.

Quindi, per conformarsi pienamente all'implementazione del grafo esistente di llama.cpp di Qwen2.5-VL-3B, abbiamo rimosso il vision transformer e il proiettore multi-vettore all'ultimo blocco transformer e abbiamo unito tutti gli adattatori LoRA di nuovo nel modello linguistico di base. Questo ci ha dato tre modelli v4 specifici per attività a 3,09B di parametri ciascuno, rispetto ai 3,75B parametri originali di v4:

Repository HuggingFace Attività
jinaai/jina-embeddings-v4-text-retrieval-GGUF Recupero di testo
jinaai/jina-embeddings-v4-text-code-GGUF Recupero di codice
jinaai/jina-embeddings-v4-text-matching-GGUF Similarità di frasi

Quindi abbiamo usato calibration_data_v5_rc.txt (che può essere trovato qui ed è raccomandato da Unsloth) per calibrare tutti e tre i modelli GGUF di base e abbiamo ottenuto tre file imatrix, quindi abbiamo usato llama-quantize con imatrix per quantizzare i modelli da float16 come segue:

# 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

Lo script quantize.sh è mostrato di seguito:

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

Alla fine, abbiamo caricato tutte le quantizzazioni su HuggingFace.

Quantizzazione BPW Dimensione File (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

tagUtilizzo e avvertenze

Ora possiamo usare llama-server e llama-embedding per servire i GGUF per l'incorporamento. A differenza delle librerie transformer dove abbiamo la flessibilità di scrivere codice di pre-elaborazione dell'input personalizzato, dobbiamo gestire questa parte manualmente (a meno che non vogliamo ricompilare llama-server e llama-embedding). In particolare, per ottenere risultati che siano completamente coerenti con l'utilizzo di AutoModel.from_pretrained("jinaai/jina-embeddings-v4")..., devi essere molto attento ai prefissi e aggiungerli manualmente ai tuoi input del modello GGUF. Ecco una tabella di riferimento:

Compito prompt_name nell'implementazione Transformer Input effettivo al modello
retrieval query (predefinito) Query: {original_text}
retrieval passage Passage: {original_text}
text-matching query (predefinito) Query: {original_text}
text-matching passage Query: {original_text} ⚠️
code query (predefinito) Query: {original_text}
code passage Passage: {original_text}

Alcuni utenti potrebbero trovare sorprendente che ⚠️ prompt_name='passage' venga sovrascritto in "Query: " quando si utilizza text-matching nell'originale AutoModel.from_pretrained("jinaai/jina-embeddings-v4").... Ma questo ha effettivamente senso poiché text-matching è un compito di similarità di frase senza ruoli di sinistra/destra: gli input sono simmetrici.

tagTramite llama-server

Dopo aver installato llama.cpp, puoi eseguire llama-server per ospitare il modello di embedding come un server HTTP compatibile con l'API OpenAI. Ad esempio, per usare text-matching con F16, puoi fare:

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

--pooling mean è richiesto poiché v4 è un embedding di mean-pooling.

Quindi invia la richiesta tramite:

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

Quando si utilizzano i modelli retrieval e code, aggiungi Query: o Passage: davanti all'input, in questo modo:

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

tagTramite llama-embedding

Per un rapido controllo di integrità, puoi anche usare il llama-embedding precompilato per l'embedding one-shot. Non raccomandiamo di usarlo per l'embedding di massa poiché ha alcuni problemi di prestazioni che discuteremo nella prossima sezione:

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

Leggi la prossima sezione per un embedding di massa più performante con la nostra build di llama-embedding con alcune correzioni e miglioramenti.

tagRiepilogo delle avvertenze

Prima di passare a un'implementazione più performante, riassumiamo le avvertenze dei modelli GGUF:

  • Devi aggiungere manualmente Query: o Passage: davanti agli input di testo.
  • Non possono gestire l'input di immagini in questo momento perché abbiamo rimosso i transformer di visione dal modello GGUF. Abbiamo dovuto rimuoverli a causa di bug nell'implementazione del transformer di visione/mmproj di Qwen2.5-vl-3b di llama.cpp, che stiamo lavorando per risolvere con l'upstream.
  • Non possono emettere embedding multi-vettore poiché non fa parte dell'implementazione del grafico Qwen2.5-vl-3b di llama.cpp. La soluzione più semplice senza ricompilare llama.cpp è esportare ed eseguire l'MLP separatamente dopo aver ottenuto gli embedding a livello di token impostando --pooling none in llama-embedding.
  • v4 è addestrato con l'apprendimento della rappresentazione Matryoshka e la conversione in GGUF preserva questa caratteristica. Se ottieni embedding con forma NxD, puoi semplicemente usare embeddings[:, :truncate_dim] per ottenere embedding troncati più piccoli. Tuttavia, non ogni dimensione è addestrata. Per v4, abbiamo addestrato truncate_dim per questi valori specifici: [128, 256, 512, 1024, 2048]. Ciò significa che la qualità di embeddings[:, :131] non sarà una sorta di interpolazione tra la qualità di embeddings[:, :128] e embeddings[:, :256], ma sarà significativamente peggiore degli embedding a 128 dimensioni o a 256 dimensioni perché 131 dimensioni non è addestrato.
  • La chunking tardiva può ancora funzionare come parte della post-elaborazione dopo aver ottenuto gli embedding a livello di token tramite --pooling none. Proprio come abbiamo fatto con la separazione dell'MLP dal grafico llama.cpp, questo non è super efficiente ma non richiede la ricompilazione. Tuttavia, c'è un'altra avvertenza: poiché v4 è un modello causale, la chunking tardiva non sarà più bidirezionale: gli embedding di chunk precedenti non conterranno informazioni contestuali dai chunk successivi. Ricorda che in v3, ogni embedding di chunk aveva informazioni di contesto globale perché abbiamo usato maschere di attenzione bidirezionali nei blocchi transformer. Internamente, abbiamo discusso se la causalità renda obsoleta la chunking tardiva: alcuni sostengono che "il contesto è anche causale", il che significa che un lettore elabora il testo da sinistra a destra, quindi il contesto necessario per interpretare una frase dovrebbe provenire dal testo precedente. Altri dicono che limitare la chunking tardiva per essere unidirezionale blocca la condivisione del contesto tra i chunk. In ogni caso, l'efficacia della chunking tardiva in v4 rimane discutibile e necessita di ulteriori studi.

tagEmbedding efficiente tramite llama-embedding

llama-embedding è un wrapper C++ relativamente semplice sopra llama.cpp per incorporare testo con I/O molto pulito: stdin, stdout. Ci stiamo concentrando sul miglioramento di questo piuttosto che su llama-server in questo momento perché ci sono un sacco di altri problemi come la coda di rete, il bilanciamento del carico, il multi-tenancy e la serializzazione che riteniamo siano fuori dal campo di applicazione a questo punto. La nostra domanda è semplice: quanta velocità possiamo ottenere da una GPU L4 da 24 GB e qual è l'utilizzo massimo di VRAM per incorporare documenti lunghi?

Ma perché L4? Principalmente perché GCP offre funzioni Cloud Run piuttosto convenienti sopra di esso, ed è il tipo di GPU più ampiamente disponibile ed economico che puoi ottenere per le API di inferenza serverless. GCP offre A100 e H100 su Cloud Run su richiesta, e il team di GCP ci propone di tanto in tanto di usare GPU migliori. Ma la nostra filosofia è semplice: se abbiamo bisogno di A100/H100 per servire un modello 3B, questo è chiaramente un problema di abilità da parte nostra.

Per un po' di background, in llama.cpp, la dimensione del batch logico (-b) rappresenta il numero massimo di token inviati al modello in una singola chiamata di valutazione. Quando si elaborano input lunghi, questi vengono suddivisi in blocchi fino a questa dimensione. La dimensione fisica del batch (-ub) è il numero effettivo di token elaborati simultaneamente in un singolo passaggio attraverso l'hardware, vincolato dalla memoria disponibile. La cache KV si aggiorna al completamento di ogni batch fisico. La Finestra di Contesto (-c) è il limite massimo per il numero di token che il modello può "vedere" contemporaneamente: per i modelli v4 è di 32.000 token, che rappresenta la massima estensione dell'attenzione del modello. Tutti i token devono rientrare in questa finestra di contesto per mantenere un'attenzione coerente sull'intera sequenza. La figura seguente illustra le loro relazioni.

tagLe nostre correzioni

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

Nella nostra fork di cui sopra, abbiamo apportato diverse ottimizzazioni per rendere llama-embedding più efficiente:

  • Gestione semplificata dei batch: abbiamo impostato automaticamente -b uguale a -c, rendendo di fatto obsoleto questo parametro. Gli utenti non devono più specificare -b poiché sfruttiamo sempre la lunghezza del contesto completo del modello per il batch logico.
  • Controllo flessibile della memoria: a differenza dell'implementazione originale in cui -ub era forzato a essere uguale a -b (poiché si presumeva che i modelli di embedding non potessero essere causali), consentiamo agli utenti di impostare -ub in modo indipendente. Ciò offre un controllo preciso sull'utilizzo massimo della VRAM durante la codifica di contesti lunghi: è possibile elaborare un contesto di 32K con un piccolo batch fisico di 512 token per rimanere entro i limiti della VRAM grazie all'implementazione della cache KV. Si noti che questa modifica è corretta solo per i modelli di embedding causali come jina-embeddings-v4; per le architetture solo encoder come v3, questa sarebbe l'implementazione errata.
  • Pooling medio fisso: abbiamo corretto il calcolo del pooling medio per gli embedding quando ub < b, che in precedenza era errato nell'implementazione originale.

Questa modifica semplifica notevolmente l'utilizzo di modelli di embedding solo decoder con contesto lungo, gestendo efficacemente i vincoli di memoria. Gli utenti devono ora configurare solo due parametri:

    • -c: la lunghezza massima del contesto (quanti token può elaborare il modello di embedding)
    • -ub: la dimensione fisica del batch (quanti token vengono elaborati contemporaneamente dalla GPU)

Quindi, il codice esatto per eseguire la nostra fork su L4 è il seguente:

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

Ogni riga in big_input.txt è una frase da incorporare. --no-escape deve essere impostato per impedire che \n all'interno della frase venga interpretato come separatore. --flash-attn e -ngl 99 devono essere impostati per ottenere le migliori prestazioni sulla GPU L4.

tagBenchmark

Vogliamo capire le seguenti domande attraverso il benchmarking:

  • Quanto è buona la nostra quantizzazione rispetto alla v4 Float16 originale? A che punto si degrada così tanto che sarebbe meglio usare gli embedding v3?
  • Quanto velocemente può essere eseguita ogni quantizzazione su L4 e qual è l'utilizzo massimo della VRAM?
  • In che modo la dimensione fisica del batch -ub e la lunghezza del contesto -c influiscono sulla velocità e sull'utilizzo massimo della VRAM?

I set di dati che abbiamo utilizzato nel benchmarking sono:

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

Abbiamo utilizzato la nostra build personalizzata di llama-embedding per il benchmarking.

tagQualità delle quantizzazioni

La versione quantizzata con le migliori prestazioni è IQ3_M (3,84 BPW): le quantizzazioni inferiori a 2 bit hanno prestazioni peggiori della v3, quindi è inutile utilizzarle.

Quantization 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

tagVelocità e VRAM

Ora fissiamo il dataset di benchmark a NanoHotpotQA e tracciamo tutte le quantizzazioni in base ai loro bit per peso rispetto alla velocità (misurata in token al secondo) e al consumo di VRAM. Abbiamo scoperto che le versioni GGUF sono leggermente più veloci della versione vanilla a FP16 (2023 vs 1865 token/sec). La maggior parte delle quantizzazioni si raggruppa intorno a 2000-2100 token/sec. Con l'abilitazione di flash attention, otteniamo un aumento di velocità di circa il 77% su tutte le quantizzazioni (3000+ vs 2000+ token/sec). Tuttavia, la quantizzazione con le migliori prestazioni Q8_0 a circa 3700 token al secondo è ancora molto indietro rispetto alla v3 vanilla (572M di parametri), che raggiunge i 16000 token/sec. Le versioni quantizzate risparmiano notevolmente VRAM e si avvicinano quasi al livello del modello v3 FP16 con IQ3.

Quantization BPW File Size (GB) Peak VRAM (GB) Token/s w FA Token/s w/o 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

Fare clic per espandere le informazioni di sistema

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

tagDimensione ottimale del batch fisico e dimensione del contesto

Ora fissiamo il tipo di quantizzazione a IQ3_S ed esaminiamo come la dimensione del batch fisico (-ub) e la dimensione del contesto (-c) influiscano su velocità e VRAM. I risultati sulla GPU L4 mostrano che -ub=512 con -c=2048 fornisce la configurazione ottimale, offrendo 4.143 token/sec utilizzando 2.025 MB di VRAM. La conclusione è intuitiva: quando si conosce la lunghezza massima di un singolo documento nell'input, utilizzare una dimensione del contesto più piccola, sufficiente a coprirlo. Per quanto riguarda la dimensione del batch fisico, 512 token sembra essere il punto ideale sulla GPU L4.

Prestazioni in termini di token al secondo

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

Utilizzo massimo di VRAM (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

tagConclusione

Per gli utenti di v4 che desiderano eseguire GGUF quantizzato in modo efficiente su GPU economiche, scegliete IQ3_S o IQ3_M con la nostra build personalizzata di llama-embedding: questo dovrebbe fornire 4000 token/sec su dataset normali (dove la lunghezza della frase è <2048 token). Per incorporare documenti più lunghi, aumentate la dimensione del contesto -c e controllate la dimensione del batch fisico -ub per ridurre l'impronta di VRAM. Con la nostra build personalizzata, potete codificare documenti super lunghi (>32K token) utilizzando solo 3 GB di VRAM impostando -ub su un numero piccolo come 1024, cosa che non era possibile con l'implementazione originale o con i transformer vanilla.

La ricerca dell'ottimizzazione della velocità non finisce mai. C'è sempre spazio per implementazioni più veloci e snelle con una produttività maggiore. 4000 token/sec probabilmente non è il nostro limite massimo: c'è ancora molto lavoro da fare. Oltre a correggere l'implementazione di mmproj/vision transformer di qwen2.5-vl-3b in llama.cpp, stiamo anche esplorando ottimizzazioni più approfondite a livello di grafo di llama e cache KV, migliorando la logica di batching di llama-serving e aggiungendo opzioni di streaming alle API di embedding. Il nostro obiettivo è far sì che llama.cpp supporti nativamente embedding multimodali moderni solo decoder per le nostre versioni future e attuali di Reranker.

Categorie:
Blog tecnico
rss_feed
Uffici
location_on
Sunnyvale, California
710 Lakeway Dr, Ste 200, Sunnyvale, CA 94085, Stati Uniti
location_on
Berlino, Germania (sede centrale)
Prinzessinnenstraße 19-20, 10969 Berlino, Germania
location_on
Pechino, Cina
Livello 5, Edificio 6, No.48 Haidian West St. Pechino, Cina
location_on
Shenzen, Cina
402 Piano 4, Fu'an Technology Building, Shenzhen, Cina
Fondazione di ricerca
Lettore
Incorporamenti
Riclassificazione
Ricerca profonda
Classificatore
Segmentatore
Documentazione API
Ottieni la chiave API Jina
Limite di velocità
Stato dell'API
Azienda
Chi siamo
Contatta le vendite
Sala stampa
Programma di stagista
Unisciti a noi
open_in_new
Scarica il logo
open_in_new
Termini
Sicurezza
Termini & Condizioni
Privacy
Gestisci i cookie
email
Jina AI © 2020-2025.