Dialogo con Gemini.
Cioa, ho un primo sistema con una nVidia RTX 3060 ed Ubuntu 2026.04 LTS ed Ollama. Vorrei creare delle procedure rigide per eseguire test e confronti con confrontare modelli vari. Cosa suggerisci per cominciare?
Per confrontare modelli in modo metodico e riproducibile su una singola GPU (la RTX 3060 da 12GB offre un buon margine di VRAM, ideale per quantizzazioni a 4 o 8 bit fino a 8B–14B di parametri), è fondamentale separare nettamente due ambiti di misura: le prestazioni hardware/inferenza (throughput e latenza) e la qualità semantica delle risposte (aderenza ai task, accuratezza logica o coding).
1. Standardizzare i Parametri di Inferenza
Un confronto perde validità se i parametri di campionamento variano tra una sessione e l’altra. Per garantire la massima riproducibilità:
- Temperatura e Top-P: Impostare
temperature: 0.0(o fissare un seed deterministico) per eliminare la varianza stocastica tra esecuzioni successive. - Context Window (
num_ctx): Fissare una finestra coerente (es. 4096 o 8192 token), poiché la dimensione del context cache incide direttamente sull’allocazione VRAM. - Offload Layer (
num_gpu): Assicurarsi che tutti i layer risiedano interamente in VRAM. Se un modello effettua offload parziale su RAM di sistema, la velocità di generazione crolla.
2. Metriche Prestazionali (Throughput ed Efficienza)
Invece di affidarsi al tempo totale percepito, l’API nativa di Ollama (POST /api/generate o POST /api/chat) restituisce nel payload finale JSON le metriche granulari per isolare ogni fase:
| Metrica | Significato Operativo | Valore di Riferimento (RTX 3060) |
|---|---|---|
| Prompt Eval Rate | Velocità di elaborazione del contesto di input (prefill in token/s). | Tipicamente 150–300+ tok/s a seconda del modello e quantization. |
| Eval Rate | Velocità di generazione vera e propria (decode in token/s). | Tipicamente 35–55 tok/s su modelli 7B/8B quantizzati Q4. |
| Time to First Token (TTFT) | Latenza tra invio del prompt e primo token emesso. | Cruciale per l’interattività dell’interfaccia. |
| Peak VRAM Usage | Memoria grafica allocata durante la generazione. | Verificabile in tempo reale tramite nvidia-smi. |
Regola aurea del benchmark: Eseguire sempre un prompt di warm-up a vuoto prima di campionare le metriche per caricare completamente i pesi dal disco alla VRAM ed evitare distorsioni da cold-start.
Local AI Master
3. Strutturare il Dataset di Test
Creare un file JSON/JSONL fisso contenente prompt raggruppati per cluster di competenza, ad esempio:
- Logica e Matematica: Problemi di deduzione o calcolo passo-passo con soluzione univoca predeterminata.
- Sintesi ed Estrazione: Testo lungo in input con richiesta di estrarre entità specifiche o generare un formato rigoroso (es. JSON conforme a uno schema schema validation). Download Ollama
- Coding e Scripting: Generazione di funzioni con input/output definiti, verificabili tramite esecuzione di unit test automatici (
pytest). - Ragionamento / Istruzioni complesse: Vincoli negativi (es. “rispondi senza usare la lettera X” o “limita la risposta a esattamente 3 punti”).
4. Harness di Test Minimo in Python
Uno script automatizzato che itera sui modelli, interroga Ollama via HTTP e registra i risultati grezzi su un file di log:
Python
import json
import time
import requests
OLLAMA_URL = "http://127.0.0.1:11434/api/generate"
MODELS = ["llama3.1:8b", "mistral:7b", "qwen2.5:7b"]
TEST_PROMPT = "Calcola il periodo di oscillazione di un pendolo semplice di lunghezza 1 metro con g = 9.81 m/s^2. Mostra formula e passaggi."
def benchmark_model(model: str, prompt: str):
payload = {
"model": model,
"prompt": prompt,
"stream": False,
"options": {
"temperature": 0.0,
"num_ctx": 4096
}
}
# Warm-up run (opzionale o scartato dai log)
requests.post(OLLAMA_URL, json={**payload, "prompt": "warmup"})
t0 = time.perf_counter()
response = requests.post(OLLAMA_URL, json=payload).json()
total_time = time.perf_counter() - t0
# Estrazione metriche interne calcolate dal runner llama.cpp di Ollama
p_eval_rate = response.get("prompt_eval_count", 0) / (response.get("prompt_eval_duration", 1) / 1e9)
eval_rate = response.get("eval_count", 0) / (response.get("eval_duration", 1) / 1e9)
return {
"model": model,
"eval_rate_tok_s": round(eval_rate, 2),
"prompt_eval_rate_tok_s": round(p_eval_rate, 2),
"total_time_s": round(total_time, 2),
"response_text": response.get("response", "")
}
results = [benchmark_model(m, TEST_PROMPT) for m in MODELS]
print(json.dumps(results, indent=2, ensure_ascii=False))
5. Metriche di Valutazione Qualitativa
Per valutare la bontà dei contenuti senza dover leggere manualmente decine di output:
- Verifica Deterministica (RegEx / Assertions / JSON Schema): Se il prompt richiede un formato (es.
{"risultato": float}), il test assegna 1 o 0 in base alla validità sintattica del parsing. - Unit Test Execution: Per task di codice, estrarre il blocco ed eseguirlo in un container isolato verificando il passaggio di asserzioni predefinite. Medium
- LLM-as-a-Judge: Utilizzare un modello di riferimento (un modello locale più pesante via quantizzazione spinta o un’API esterna) a cui passare una rubrica di valutazione standardizzata (chiarezza, correttezza concettuale, aderenza ai vincoli, scala 1-5).
Ecco la suite completa composta da:
- Un dataset standardizzato di benchmark (
benchmark_prompts.json) suddiviso in cluster (Fisica/Matematica, Coding con vincoli algoritmici, Deduzione logica, Formati JSON vincolati), con criteri oggettivi di validazione. - Uno script di automazione (
benchmark_ollama.py) con gestione del warm-up VRAM, campionamento hardware tramitepynvml(NVIDIA Management Library), estrazione delle metriche native di Ollama (eval_rate,prompt_eval_rate) ed esportazione simultanea in CSV (metriche) e JSON (testo completo per revisione).
I file generati:
- Dataset di test:
benchmark_prompts JSON Apri
- Script benchmark Python:
benchmark_ollama PY Apri
1. Il Dataset di Test (benchmark_prompts.json)
Il dataset è concepito per testare le capacità di modelli open source tipici per la RTX 3060 da 12GB (famiglie 7B/8B e 14B Q4):
- Fisica / Matematica Applicata (
MATH_01,MATH_02):- Esempio: Oscillatore armonico smorzato ($m \ddot{x} + \gamma \dot{x} + kx = 0$) con determinazione numerica esatta di pulsazione naturale $\omega_0$, smorzamento $\zeta$, regime e pseudopulsazione $\omega_d$.
- Esempio: Calcolo analitico di autovalori e autovettori normalizzati di una matrice $2 \times 2$.
- Criterio di verifica: Controllo numerico immediato dei valori attesi.
- Coding e Strutture Dati (
CODE_01,CODE_02):- Esempio: Algoritmo per la sottosequenza consecutiva più lunga con vincolo di complessità temporale $O(n)$ senza sorting e inclusione di test con asserzioni.
- Esempio: Funzione di parsing/validazione telemetria con calcolo potenza e gestione delle eccezioni (
ValueError). - Criterio di verifica: Esecuzione autonoma del codice generato o verifica statica dei vincoli di complessità.
- Deduzione Logica (
LOGIC_01):- Problema di associazione multipla (persone, città, linguaggio di programmazione) con vincoli negativi incrociati.
- Criterio di verifica: Confronto con la tupla di soluzione univoca.
- Aderenza al Formato / Schema Vincolato (
SCHEMA_01):- Estrazione entità hardware da linguaggio naturale con output formattato rigorosamente in un JSON privo di testo collaterale o markdown.
- Criterio di verifica: Parsing
json.loads(response)e validazione delle chiavi.
2. Lo Script di Benchmark (benchmark_ollama.py)
Dipendenze necessarie su Ubuntu:
Bash
pip install requests nvidia-ml-py
Funzionalità chiave implementate:
- Isolamento della VRAM con Warm-up: Prima di misurare un modello, invia una richiesta a vuoto (
warmup) per caricare i pesi nella memoria grafica della RTX 3060, evitando che il tempo di caricamento da storage a VRAM alteri il throughput del primo prompt. - Campionamento Hardware Real-time (
pynvml): Rileva e registra la VRAM allocata prima e dopo ciascuna inferenza, consentendo di identificare modelli con elevato consumo di context cache o footprint di memoria instabile. - Estrazione Metriche Native di Ollama: Legge i timestamp ad alta risoluzione (nanosecondi) calcolati internamente dal backend C++ di llama.cpp:
eval_tok_s: Velocità di decodifica/generazione token.prompt_tok_s: Velocità di prefill/valutazione del prompt.wall_time_s: Tempo di risposta totale end-to-end.
- Doppio Output:
ollama_benchmark_results.csv: Tabella compatta per calcolare medie, deviazioni standard o grafici.ollama_benchmark_details.json: Log integrale contenente i testi generati, pronto per una valutazione qualitativa o per un passaggio automatico a un LLM-as-a-judge.
Esecuzione:
Basta posizionare entrambi i file nella stessa directory e avviare:
Bash
python3 benchmark_ollama.py
GeminiNuova chatCerca nelle chatVideoRaccoltaNuovo notebookBenchmark di Modelli LLM con OllamaIl concetto di spazio in matematicaSospensione Assicurazione Scooter ConTeProspettive GPS A-27 e PNRRImpasto per pizza nella macchina del paneOllama con due GPU su UbuntuRyzen 7700X vs 7800X3D per OllamaIndicatori della crisi economica italianaInizio Nomine GPS ScuolaConsumi Frigorifero Trivalente: 230V vs 12VConsumo GPL frigo Adria ActionDisinfettare Serbatoi Acqua Caravan: AmuchinaAlgebra Lineare nell’Intelligenza ArtificialePreparazione Dispense Fisica LiceoCreare Oggetto Globale Python SemplicePython: Linguaggio Chiave nell’AIOttenere lo Stato Matricolare ScolasticoFusione nucleare: svolta tedesca e futuro energeticoFaggin: Microchip, Coscienza e Fisica QuantisticaUso WC Chimico Adria ActionCatene da neve per Renault ZoeAstragalo: Proprietà, Benefici e PrecauzioniVacanza in roulotte: Alto Adige con Park4NightVite spezzata nel cavalletto: soluzioniOpinione su Dispense di Matematica PubblicateOffrirsi come formatore tecnologicoChoquet, Dieudonné e i triangoliRichiesta Articolo Protetto FallitaConfigurazione PC Ollama Ubuntu ServerICME-7: Esperienza Didattica a PadovaConsulenza AI Locale per SistemistiPresa solare per caravan: fisso o portatileAttività
Limena, ItaliaDal tuo indirizzo IPAggiorna posizione
Conversazione con Gemini
Cioa, ho un primo sistema con una nVidia RTX 3060 ed Ubuntu 2026.04 LTS ed Ollama. Vorrei creare delle procedure rigide per eseguire test e confronti con confrontare modelli vari. Cosa suggerisci per cominciare?
Per confrontare modelli in modo metodico e riproducibile su una singola GPU (la RTX 3060 da 12GB offre un buon margine di VRAM, ideale per quantizzazioni a 4 o 8 bit fino a 8B–14B di parametri), è fondamentale separare nettamente due ambiti di misura: le prestazioni hardware/inferenza (throughput e latenza) e la qualità semantica delle risposte (aderenza ai task, accuratezza logica o coding).
1. Standardizzare i Parametri di Inferenza
Un confronto perde validità se i parametri di campionamento variano tra una sessione e l’altra. Per garantire la massima riproducibilità:
- Temperatura e Top-P: Impostare
temperature: 0.0(o fissare un seed deterministico) per eliminare la varianza stocastica tra esecuzioni successive. - Context Window (
num_ctx): Fissare una finestra coerente (es. 4096 o 8192 token), poiché la dimensione del context cache incide direttamente sull’allocazione VRAM. - Offload Layer (
num_gpu): Assicurarsi che tutti i layer risiedano interamente in VRAM. Se un modello effettua offload parziale su RAM di sistema, la velocità di generazione crolla.
2. Metriche Prestazionali (Throughput ed Efficienza)
Invece di affidarsi al tempo totale percepito, l’API nativa di Ollama (POST /api/generate o POST /api/chat) restituisce nel payload finale JSON le metriche granulari per isolare ogni fase:
| Metrica | Significato Operativo | Valore di Riferimento (RTX 3060) |
|---|---|---|
| Prompt Eval Rate | Velocità di elaborazione del contesto di input (prefill in token/s). | Tipicamente 150–300+ tok/s a seconda del modello e quantization. |
| Eval Rate | Velocità di generazione vera e propria (decode in token/s). | Tipicamente 35–55 tok/s su modelli 7B/8B quantizzati Q4. |
| Time to First Token (TTFT) | Latenza tra invio del prompt e primo token emesso. | Cruciale per l’interattività dell’interfaccia. |
| Peak VRAM Usage | Memoria grafica allocata durante la generazione. | Verificabile in tempo reale tramite nvidia-smi. |
Regola aurea del benchmark: Eseguire sempre un prompt di warm-up a vuoto prima di campionare le metriche per caricare completamente i pesi dal disco alla VRAM ed evitare distorsioni da cold-start.
Local AI Master
3. Strutturare il Dataset di Test
Creare un file JSON/JSONL fisso contenente prompt raggruppati per cluster di competenza, ad esempio:
- Logica e Matematica: Problemi di deduzione o calcolo passo-passo con soluzione univoca predeterminata.
- Sintesi ed Estrazione: Testo lungo in input con richiesta di estrarre entità specifiche o generare un formato rigoroso (es. JSON conforme a uno schema schema validation). Download Ollama
- Coding e Scripting: Generazione di funzioni con input/output definiti, verificabili tramite esecuzione di unit test automatici (
pytest). - Ragionamento / Istruzioni complesse: Vincoli negativi (es. “rispondi senza usare la lettera X” o “limita la risposta a esattamente 3 punti”).
4. Harness di Test Minimo in Python
Uno script automatizzato che itera sui modelli, interroga Ollama via HTTP e registra i risultati grezzi su un file di log:
Python
import json
import time
import requests
OLLAMA_URL = "http://127.0.0.1:11434/api/generate"
MODELS = ["llama3.1:8b", "mistral:7b", "qwen2.5:7b"]
TEST_PROMPT = "Calcola il periodo di oscillazione di un pendolo semplice di lunghezza 1 metro con g = 9.81 m/s^2. Mostra formula e passaggi."
def benchmark_model(model: str, prompt: str):
payload = {
"model": model,
"prompt": prompt,
"stream": False,
"options": {
"temperature": 0.0,
"num_ctx": 4096
}
}
# Warm-up run (opzionale o scartato dai log)
requests.post(OLLAMA_URL, json={**payload, "prompt": "warmup"})
t0 = time.perf_counter()
response = requests.post(OLLAMA_URL, json=payload).json()
total_time = time.perf_counter() - t0
# Estrazione metriche interne calcolate dal runner llama.cpp di Ollama
p_eval_rate = response.get("prompt_eval_count", 0) / (response.get("prompt_eval_duration", 1) / 1e9)
eval_rate = response.get("eval_count", 0) / (response.get("eval_duration", 1) / 1e9)
return {
"model": model,
"eval_rate_tok_s": round(eval_rate, 2),
"prompt_eval_rate_tok_s": round(p_eval_rate, 2),
"total_time_s": round(total_time, 2),
"response_text": response.get("response", "")
}
results = [benchmark_model(m, TEST_PROMPT) for m in MODELS]
print(json.dumps(results, indent=2, ensure_ascii=False))
5. Metriche di Valutazione Qualitativa
Per valutare la bontà dei contenuti senza dover leggere manualmente decine di output:
- Verifica Deterministica (RegEx / Assertions / JSON Schema): Se il prompt richiede un formato (es.
{"risultato": float}), il test assegna 1 o 0 in base alla validità sintattica del parsing. - Unit Test Execution: Per task di codice, estrarre il blocco ed eseguirlo in un container isolato verificando il passaggio di asserzioni predefinite. Medium
- LLM-as-a-Judge: Utilizzare un modello di riferimento (un modello locale più pesante via quantizzazione spinta o un’API esterna) a cui passare una rubrica di valutazione standardizzata (chiarezza, correttezza concettuale, aderenza ai vincoli, scala 1-5).
Potresti entrambi? grazie!
Ecco la suite completa composta da:
- Un dataset standardizzato di benchmark (
benchmark_prompts.json) suddiviso in cluster (Fisica/Matematica, Coding con vincoli algoritmici, Deduzione logica, Formati JSON vincolati), con criteri oggettivi di validazione. - Uno script di automazione (
benchmark_ollama.py) con gestione del warm-up VRAM, campionamento hardware tramitepynvml(NVIDIA Management Library), estrazione delle metriche native di Ollama (eval_rate,prompt_eval_rate) ed esportazione simultanea in CSV (metriche) e JSON (testo completo per revisione).
I file generati:
- Dataset di test:
benchmark_prompts JSON
- Script benchmark Python:
benchmark_ollama PY
1. Il Dataset di Test (benchmark_prompts.json)
Il dataset è concepito per testare le capacità di modelli open source tipici per la RTX 3060 da 12GB (famiglie 7B/8B e 14B Q4):
- Fisica / Matematica Applicata (
MATH_01,MATH_02):- Esempio: Oscillatore armonico smorzato (mx¨+γx˙+kx=0) con determinazione numerica esatta di pulsazione naturale ω0, smorzamento ζ, regime e pseudopulsazione ωd.
- Esempio: Calcolo analitico di autovalori e autovettori normalizzati di una matrice 2×2.
- Criterio di verifica: Controllo numerico immediato dei valori attesi.
- Coding e Strutture Dati (
CODE_01,CODE_02):- Esempio: Algoritmo per la sottosequenza consecutiva più lunga con vincolo di complessità temporale O(n) senza sorting e inclusione di test con asserzioni.
- Esempio: Funzione di parsing/validazione telemetria con calcolo potenza e gestione delle eccezioni (
ValueError). - Criterio di verifica: Esecuzione autonoma del codice generato o verifica statica dei vincoli di complessità.
- Deduzione Logica (
LOGIC_01):- Problema di associazione multipla (persone, città, linguaggio di programmazione) con vincoli negativi incrociati.
- Criterio di verifica: Confronto con la tupla di soluzione univoca.
- Aderenza al Formato / Schema Vincolato (
SCHEMA_01):- Estrazione entità hardware da linguaggio naturale con output formattato rigorosamente in un JSON privo di testo collaterale o markdown.
- Criterio di verifica: Parsing
json.loads(response)e validazione delle chiavi.
2. Lo Script di Benchmark (benchmark_ollama.py)
Dipendenze necessarie su Ubuntu:
Bash
pip install requests nvidia-ml-py
Funzionalità chiave implementate:
- Isolamento della VRAM con Warm-up: Prima di misurare un modello, invia una richiesta a vuoto (
warmup) per caricare i pesi nella memoria grafica della RTX 3060, evitando che il tempo di caricamento da storage a VRAM alteri il throughput del primo prompt. - Campionamento Hardware Real-time (
pynvml): Rileva e registra la VRAM allocata prima e dopo ciascuna inferenza, consentendo di identificare modelli con elevato consumo di context cache o footprint di memoria instabile. - Estrazione Metriche Native di Ollama: Legge i timestamp ad alta risoluzione (nanosecondi) calcolati internamente dal backend C++ di llama.cpp:
eval_tok_s: Velocità di decodifica/generazione token.prompt_tok_s: Velocità di prefill/valutazione del prompt.wall_time_s: Tempo di risposta totale end-to-end.
- Doppio Output:
ollama_benchmark_results.csv: Tabella compatta per calcolare medie, deviazioni standard o grafici.ollama_benchmark_details.json: Log integrale contenente i testi generati, pronto per una valutazione qualitativa o per un passaggio automatico a un LLM-as-a-judge.
Esecuzione:
Basta posizionare entrambi i file nella stessa directory e avviare:
Bash
python3 benchmark_ollama.py
Gemini è un’AI e può fare errori, anche in merito a persone. La tua privacy e GeminiSi apre in una nuova finestra
[
{
"id": "MATH_01",
"category": "matematica",
"name": "Oscillatore armonico smorzato",
"prompt": "Un oscillatore armonico smorzato segue l'equazione differenziale m*x''(t) + gamma*x'(t) + k*x(t) = 0. Se m = 1 kg, gamma = 0.4 Ns/m, e k = 4 N/m, determina: 1) La pulsazione naturale omega_0; 2) Il fattore di smorzamento adimensionale zeta; 3) Il regime del moto (sottosmorzato, criticamente smorzato, sovrasmorzato); 4) La pseudopulsazione omega_d. Mostra formule e calcoli numerici esatti.",
"expected_criteria": {
"omega_0": "2.0 rad/s",
"zeta": "0.1",
"regime": "sottosmorzato",
"omega_d": "~1.99 rad/s"
},
"evaluation_type": "exact_or_numeric"
},
{
"id": "MATH_02",
"category": "matematica",
"name": "Algebra lineare e autovalori",
"prompt": "Data la matrice quadrata A = [[3, 1], [1, 3]], calcola gli autovalori e i relativi autovettori normalizzati (di norma unitaria). Mostra il polinomio caratteristico e tutti i passaggi.",
"expected_criteria": {
"eigenvalues": [
4,
2
],
"eigenvectors": "v1 = [1/sqrt(2), 1/sqrt(2)], v2 = [-1/sqrt(2), 1/sqrt(2)]"
},
"evaluation_type": "exact_or_numeric"
},
{
"id": "CODE_01",
"category": "coding",
"name": "Generazione algoritmo con vincoli e complessita'",
"prompt": "Scrivi una funzione Python `def find_longest_consecutive(nums: list[int]) -> int:` che trovi la lunghezza della sottosequenza più lunga di elementi consecutivi in un array non ordinato con complessità temporale strettamente O(n). Non importare librerie esterne. Includi type hinting, docstring e tre asserzioni di test con pytest o doctest.",
"expected_criteria": {
"required_complexity": "O(n) via set lookup",
"must_contain": [
"def find_longest_consecutive",
"set",
"assert"
],
"unit_testable": true
},
"evaluation_type": "code_execution"
},
{
"id": "CODE_02",
"category": "coding",
"name": "Parsing e sanitizzazione JSON strutturato",
"prompt": "Scrivi una funzione Python `def parse_sensor_reading(payload: str) -> dict:` che prenda una stringa JSON rappresentante telemetria (`{'sensor_id': int, 'voltage': float, 'current': float, 'status': str}`) e restituisca un dizionario validato calcolando il campo 'power_w' (voltage * current). Se 'voltage' o 'current' sono negativi, o il JSON non è valido, solleva un `ValueError` con messaggio opportuno.",
"expected_criteria": {
"must_contain": [
"json.loads",
"ValueError",
"power_w"
],
"unit_testable": true
},
"evaluation_type": "code_execution"
},
{
"id": "LOGIC_01",
"category": "logica",
"name": "Deduzione logica con vincoli negativi",
"prompt": "Tre colleghi, Alice, Bruno e Chiara, lavorano ciascuno in una sede diversa tra Milano, Roma e Torino, e usano ciascuno un linguaggio diverso tra Python, C++ e Rust.\n- Chi vive a Milano non programma in C++.\n- Bruno lavora a Roma.\n- Chiara non usa Python.\n- Chi usa Python vive a Torino.\nDetermina sede e linguaggio di ciascuna persona, specificando per ciascuno la deduzione logica passo dopo passo.",
"expected_criteria": {
"Alice": "Torino, Python",
"Bruno": "Roma, C++",
"Chiara": "Milano, Rust"
},
"evaluation_type": "deductive_reasoning"
},
{
"id": "SCHEMA_01",
"category": "formato_vincolato",
"name": "Estrazione JSON rigorosa con schema vincolato",
"prompt": "Estrai le specifiche tecniche dal seguente testo e restituisci ESCLUSIVAMENTE un oggetto JSON valido (senza blocchi markdown, senza commenti, senza testo prima o dopo):\n\"Il nodo server monta un processore AMD Ryzen 7 5700X a 8 core e 16 thread con TDP di 65W, 32 GB di RAM DDR4 a 3200 MHz in dual channel e una GPU Nvidia RTX 3060 con 12 GB di VRAM GDDR6 su bus a 192-bit.\"\n\nLo schema deve avere i campi: 'cpu' (oggetto con 'model', 'cores', 'threads', 'tdp_w'), 'ram' (oggetto con 'capacity_gb', 'type', 'frequency_mhz'), 'gpu' (oggetto con 'model', 'vram_gb', 'bus_bits').",
"expected_criteria": {
"json_valid": true,
"required_keys": [
"cpu",
"ram",
"gpu"
]
},
"evaluation_type": "json_schema_validation"
}
]
benchmark_prompts.json
Visualizzazione di benchmark_prompts.json.
GeminiNuova chatCerca nelle chatVideoRaccoltaNuovo notebookBenchmark di Modelli LLM con OllamaIl concetto di spazio in matematicaSospensione Assicurazione Scooter ConTeProspettive GPS A-27 e PNRRImpasto per pizza nella macchina del paneOllama con due GPU su UbuntuRyzen 7700X vs 7800X3D per OllamaIndicatori della crisi economica italianaInizio Nomine GPS ScuolaConsumi Frigorifero Trivalente: 230V vs 12VConsumo GPL frigo Adria ActionDisinfettare Serbatoi Acqua Caravan: AmuchinaAlgebra Lineare nell’Intelligenza ArtificialePreparazione Dispense Fisica LiceoCreare Oggetto Globale Python SemplicePython: Linguaggio Chiave nell’AIOttenere lo Stato Matricolare ScolasticoFusione nucleare: svolta tedesca e futuro energeticoFaggin: Microchip, Coscienza e Fisica QuantisticaUso WC Chimico Adria ActionCatene da neve per Renault ZoeAstragalo: Proprietà, Benefici e PrecauzioniVacanza in roulotte: Alto Adige con Park4NightVite spezzata nel cavalletto: soluzioniOpinione su Dispense di Matematica PubblicateOffrirsi come formatore tecnologicoChoquet, Dieudonné e i triangoliRichiesta Articolo Protetto FallitaConfigurazione PC Ollama Ubuntu ServerICME-7: Esperienza Didattica a PadovaConsulenza AI Locale per SistemistiPresa solare per caravan: fisso o portatileAttività
Limena, ItaliaDal tuo indirizzo IPAggiorna posizione
Conversazione con Gemini
Cioa, ho un primo sistema con una nVidia RTX 3060 ed Ubuntu 2026.04 LTS ed Ollama. Vorrei creare delle procedure rigide per eseguire test e confronti con confrontare modelli vari. Cosa suggerisci per cominciare?
Per confrontare modelli in modo metodico e riproducibile su una singola GPU (la RTX 3060 da 12GB offre un buon margine di VRAM, ideale per quantizzazioni a 4 o 8 bit fino a 8B–14B di parametri), è fondamentale separare nettamente due ambiti di misura: le prestazioni hardware/inferenza (throughput e latenza) e la qualità semantica delle risposte (aderenza ai task, accuratezza logica o coding).
1. Standardizzare i Parametri di Inferenza
Un confronto perde validità se i parametri di campionamento variano tra una sessione e l’altra. Per garantire la massima riproducibilità:
- Temperatura e Top-P: Impostare
temperature: 0.0(o fissare un seed deterministico) per eliminare la varianza stocastica tra esecuzioni successive. - Context Window (
num_ctx): Fissare una finestra coerente (es. 4096 o 8192 token), poiché la dimensione del context cache incide direttamente sull’allocazione VRAM. - Offload Layer (
num_gpu): Assicurarsi che tutti i layer risiedano interamente in VRAM. Se un modello effettua offload parziale su RAM di sistema, la velocità di generazione crolla.
2. Metriche Prestazionali (Throughput ed Efficienza)
Invece di affidarsi al tempo totale percepito, l’API nativa di Ollama (POST /api/generate o POST /api/chat) restituisce nel payload finale JSON le metriche granulari per isolare ogni fase:
| Metrica | Significato Operativo | Valore di Riferimento (RTX 3060) |
|---|---|---|
| Prompt Eval Rate | Velocità di elaborazione del contesto di input (prefill in token/s). | Tipicamente 150–300+ tok/s a seconda del modello e quantization. |
| Eval Rate | Velocità di generazione vera e propria (decode in token/s). | Tipicamente 35–55 tok/s su modelli 7B/8B quantizzati Q4. |
| Time to First Token (TTFT) | Latenza tra invio del prompt e primo token emesso. | Cruciale per l’interattività dell’interfaccia. |
| Peak VRAM Usage | Memoria grafica allocata durante la generazione. | Verificabile in tempo reale tramite nvidia-smi. |
Regola aurea del benchmark: Eseguire sempre un prompt di warm-up a vuoto prima di campionare le metriche per caricare completamente i pesi dal disco alla VRAM ed evitare distorsioni da cold-start.
Local AI Master
3. Strutturare il Dataset di Test
Creare un file JSON/JSONL fisso contenente prompt raggruppati per cluster di competenza, ad esempio:
- Logica e Matematica: Problemi di deduzione o calcolo passo-passo con soluzione univoca predeterminata.
- Sintesi ed Estrazione: Testo lungo in input con richiesta di estrarre entità specifiche o generare un formato rigoroso (es. JSON conforme a uno schema schema validation). Download Ollama
- Coding e Scripting: Generazione di funzioni con input/output definiti, verificabili tramite esecuzione di unit test automatici (
pytest). - Ragionamento / Istruzioni complesse: Vincoli negativi (es. “rispondi senza usare la lettera X” o “limita la risposta a esattamente 3 punti”).
4. Harness di Test Minimo in Python
Uno script automatizzato che itera sui modelli, interroga Ollama via HTTP e registra i risultati grezzi su un file di log:
Python
import json
import time
import requests
OLLAMA_URL = "http://127.0.0.1:11434/api/generate"
MODELS = ["llama3.1:8b", "mistral:7b", "qwen2.5:7b"]
TEST_PROMPT = "Calcola il periodo di oscillazione di un pendolo semplice di lunghezza 1 metro con g = 9.81 m/s^2. Mostra formula e passaggi."
def benchmark_model(model: str, prompt: str):
payload = {
"model": model,
"prompt": prompt,
"stream": False,
"options": {
"temperature": 0.0,
"num_ctx": 4096
}
}
# Warm-up run (opzionale o scartato dai log)
requests.post(OLLAMA_URL, json={**payload, "prompt": "warmup"})
t0 = time.perf_counter()
response = requests.post(OLLAMA_URL, json=payload).json()
total_time = time.perf_counter() - t0
# Estrazione metriche interne calcolate dal runner llama.cpp di Ollama
p_eval_rate = response.get("prompt_eval_count", 0) / (response.get("prompt_eval_duration", 1) / 1e9)
eval_rate = response.get("eval_count", 0) / (response.get("eval_duration", 1) / 1e9)
return {
"model": model,
"eval_rate_tok_s": round(eval_rate, 2),
"prompt_eval_rate_tok_s": round(p_eval_rate, 2),
"total_time_s": round(total_time, 2),
"response_text": response.get("response", "")
}
results = [benchmark_model(m, TEST_PROMPT) for m in MODELS]
print(json.dumps(results, indent=2, ensure_ascii=False))
5. Metriche di Valutazione Qualitativa
Per valutare la bontà dei contenuti senza dover leggere manualmente decine di output:
- Verifica Deterministica (RegEx / Assertions / JSON Schema): Se il prompt richiede un formato (es.
{"risultato": float}), il test assegna 1 o 0 in base alla validità sintattica del parsing. - Unit Test Execution: Per task di codice, estrarre il blocco ed eseguirlo in un container isolato verificando il passaggio di asserzioni predefinite. Medium
- LLM-as-a-Judge: Utilizzare un modello di riferimento (un modello locale più pesante via quantizzazione spinta o un’API esterna) a cui passare una rubrica di valutazione standardizzata (chiarezza, correttezza concettuale, aderenza ai vincoli, scala 1-5).
Potresti entrambi? grazie!
Ecco la suite completa composta da:
- Un dataset standardizzato di benchmark (
benchmark_prompts.json) suddiviso in cluster (Fisica/Matematica, Coding con vincoli algoritmici, Deduzione logica, Formati JSON vincolati), con criteri oggettivi di validazione. - Uno script di automazione (
benchmark_ollama.py) con gestione del warm-up VRAM, campionamento hardware tramitepynvml(NVIDIA Management Library), estrazione delle metriche native di Ollama (eval_rate,prompt_eval_rate) ed esportazione simultanea in CSV (metriche) e JSON (testo completo per revisione).
I file generati:
- Dataset di test:
benchmark_prompts JSON
- Script benchmark Python:
benchmark_ollama PY
1. Il Dataset di Test (benchmark_prompts.json)
Il dataset è concepito per testare le capacità di modelli open source tipici per la RTX 3060 da 12GB (famiglie 7B/8B e 14B Q4):
- Fisica / Matematica Applicata (
MATH_01,MATH_02):- Esempio: Oscillatore armonico smorzato (mx¨+γx˙+kx=0) con determinazione numerica esatta di pulsazione naturale ω0, smorzamento ζ, regime e pseudopulsazione ωd.
- Esempio: Calcolo analitico di autovalori e autovettori normalizzati di una matrice 2×2.
- Criterio di verifica: Controllo numerico immediato dei valori attesi.
- Coding e Strutture Dati (
CODE_01,CODE_02):- Esempio: Algoritmo per la sottosequenza consecutiva più lunga con vincolo di complessità temporale O(n) senza sorting e inclusione di test con asserzioni.
- Esempio: Funzione di parsing/validazione telemetria con calcolo potenza e gestione delle eccezioni (
ValueError). - Criterio di verifica: Esecuzione autonoma del codice generato o verifica statica dei vincoli di complessità.
- Deduzione Logica (
LOGIC_01):- Problema di associazione multipla (persone, città, linguaggio di programmazione) con vincoli negativi incrociati.
- Criterio di verifica: Confronto con la tupla di soluzione univoca.
- Aderenza al Formato / Schema Vincolato (
SCHEMA_01):- Estrazione entità hardware da linguaggio naturale con output formattato rigorosamente in un JSON privo di testo collaterale o markdown.
- Criterio di verifica: Parsing
json.loads(response)e validazione delle chiavi.
2. Lo Script di Benchmark (benchmark_ollama.py)
Dipendenze necessarie su Ubuntu:
Bash
pip install requests nvidia-ml-py
Funzionalità chiave implementate:
- Isolamento della VRAM con Warm-up: Prima di misurare un modello, invia una richiesta a vuoto (
warmup) per caricare i pesi nella memoria grafica della RTX 3060, evitando che il tempo di caricamento da storage a VRAM alteri il throughput del primo prompt. - Campionamento Hardware Real-time (
pynvml): Rileva e registra la VRAM allocata prima e dopo ciascuna inferenza, consentendo di identificare modelli con elevato consumo di context cache o footprint di memoria instabile. - Estrazione Metriche Native di Ollama: Legge i timestamp ad alta risoluzione (nanosecondi) calcolati internamente dal backend C++ di llama.cpp:
eval_tok_s: Velocità di decodifica/generazione token.prompt_tok_s: Velocità di prefill/valutazione del prompt.wall_time_s: Tempo di risposta totale end-to-end.
- Doppio Output:
ollama_benchmark_results.csv: Tabella compatta per calcolare medie, deviazioni standard o grafici.ollama_benchmark_details.json: Log integrale contenente i testi generati, pronto per una valutazione qualitativa o per un passaggio automatico a un LLM-as-a-judge.
Esecuzione:
Basta posizionare entrambi i file nella stessa directory e avviare:
Bash
python3 benchmark_ollama.py
Gemini è un’AI e può fare errori, anche in merito a persone. La tua privacy e GeminiSi apre in una nuova finestra
#!/usr/bin/env python3
"""
Ollama Benchmark Harness per GPU nVidia RTX (Ubuntu / CUDA)
Raccoglie metriche native di Ollama (decode tok/s, prompt tok/s, TTFT)
e campiona la VRAM tramite pynvml, esportando i risultati aggregati in CSV e JSON.
"""
import csv
import json
import os
import sys
import time
import requests
# Tentativo di importazione di pynvml (nvidia-ml-py)
try:
import pynvml
HAS_NVML = True
except ImportError:
HAS_NVML = False
OLLAMA_API_URL = "http://127.0.0.1:11434/api/generate"
MODELS_TO_TEST = [
"llama3.1:8b",
"qwen2.5:7b",
"mistral:7b",
"deepseek-r1:8b"
]
PROMPT_FILE = "benchmark_prompts.json"
OUTPUT_CSV = "ollama_benchmark_results.csv"
OUTPUT_DETAILS_JSON = "ollama_benchmark_details.json"
DEFAULT_OPTIONS = {
"temperature": 0.0, # Determinismo per confronto riproducibile
"num_ctx": 4096, # Finestra di contesto fissa
"num_gpu": 99 # Forza l'offload totale sulla GPU se VRAM capiente
}
def init_gpu():
if not HAS_NVML:
return None
try:
pynvml.nvmlInit()
handle = pynvml.nvmlDeviceGetHandleByIndex(0)
gpu_name = pynvml.nvmlDeviceGetName(handle)
if isinstance(gpu_name, bytes):
gpu_name = gpu_name.decode("utf-8")
print(f"[NVML] GPU Rilevata: {gpu_name}")
return handle
except Exception as e:
print(f"[NVML] Errore inizializzazione GPU: {e}")
return None
def get_vram_used_mb(gpu_handle):
if not gpu_handle:
return 0.0
try:
mem_info = pynvml.nvmlDeviceGetMemoryInfo(gpu_handle)
return round(mem_info.used / (1024 ** 2), 2)
except Exception:
return 0.0
def run_warmup(model: str):
"""Esegue un prompt minimale a vuoto per forzare il caricamento del modello in VRAM."""
print(f" -> Warm-up caricamento modello {model}...", end="", flush=True)
payload = {
"model": model,
"prompt": "ping",
"stream": False,
"options": {"num_ctx": 2048, "temperature": 0.0}
}
try:
requests.post(OLLAMA_API_URL, json=payload, timeout=120)
print(" completato.")
except Exception as e:
print(f" ERRORE warm-up: {e}")
def run_single_inference(model: str, prompt_item: dict, gpu_handle=None):
prompt_id = prompt_item["id"]
category = prompt_item["category"]
prompt_text = prompt_item["prompt"]
vram_before = get_vram_used_mb(gpu_handle)
payload = {
"model": model,
"prompt": prompt_text,
"stream": False,
"options": DEFAULT_OPTIONS
}
t0 = time.perf_counter()
resp = requests.post(OLLAMA_API_URL, json=payload, timeout=180)
wall_time = time.perf_counter() - t0
vram_after = get_vram_used_mb(gpu_handle)
if resp.status_code != 200:
print(f" [!] Errore {resp.status_code} su {model} - {prompt_id}: {resp.text}")
return None
data = resp.json()
# Ollama calcola i tempi in nanosecondi
prompt_eval_count = data.get("prompt_eval_count", 0)
prompt_eval_dur_ns = data.get("prompt_eval_duration", 0)
eval_count = data.get("eval_count", 0)
eval_dur_ns = data.get("eval_duration", 0)
total_dur_ns = data.get("total_duration", 0)
prompt_tok_s = (prompt_eval_count / (prompt_eval_dur_ns / 1e9)) if prompt_eval_dur_ns > 0 else 0.0
eval_tok_s = (eval_count / (eval_dur_ns / 1e9)) if eval_dur_ns > 0 else 0.0
result_record = {
"timestamp": time.strftime("%Y-%m-%d %H:%M:%S"),
"model": model,
"prompt_id": prompt_id,
"category": category,
"wall_time_s": round(wall_time, 3),
"total_duration_s": round(total_dur_ns / 1e9, 3),
"prompt_tokens": prompt_eval_count,
"prompt_tok_s": round(prompt_tok_s, 2),
"generated_tokens": eval_count,
"eval_tok_s": round(eval_tok_s, 2),
"vram_used_mb": vram_after,
"vram_delta_mb": round(vram_after - vram_before, 2),
"response_text": data.get("response", "").strip()
}
return result_record
def main():
if not os.path.exists(PROMPT_FILE):
print(f"File {PROMPT_FILE} non trovato. Creane uno prima di eseguire.")
sys.exit(1)
with open(PROMPT_FILE, "r", encoding="utf-8") as f:
prompts = json.load(f)
gpu_handle = init_gpu()
csv_fields = [
"timestamp", "model", "prompt_id", "category",
"eval_tok_s", "prompt_tok_s", "generated_tokens",
"prompt_tokens", "wall_time_s", "vram_used_mb", "vram_delta_mb"
]
all_detailed_results = []
# Scrittura intestazione CSV se non esiste
file_exists = os.path.exists(OUTPUT_CSV)
csv_file = open(OUTPUT_CSV, mode="a" if file_exists else "w", newline="", encoding="utf-8")
csv_writer = csv.DictWriter(csv_file, fieldnames=csv_fields)
if not file_exists:
csv_writer.writeheader()
print(f"\n=== AVVIO BENCHMARK ({len(MODELS_TO_TEST)} modelli x {len(prompts)} test) ===")
try:
for model in MODELS_TO_TEST:
print(f"\n------------------------------------------------------------")
print(f"Modello: {model}")
print(f"------------------------------------------------------------")
run_warmup(model)
for item in prompts:
p_id = item["id"]
print(f" Esecuzione test [{p_id}] ({item['category']})... ", end="", flush=True)
res = run_single_inference(model, item, gpu_handle)
if res:
print(f"OK | Decode: {res['eval_tok_s']:5.2f} tok/s | Prompt: {res['prompt_tok_s']:6.2f} tok/s | VRAM: {res['vram_used_mb']} MB")
# Salva su CSV (escludendo il testo lungo)
row = {k: res[k] for k in csv_fields}
csv_writer.writerow(row)
csv_file.flush()
all_detailed_results.append(res)
else:
print("FALLITO")
time.sleep(1) # raffreddamento / stabilizzazione
finally:
csv_file.close()
if HAS_NVML and gpu_handle:
pynvml.nvmlShutdown()
# Salva risposte complete per verifica qualitativa/LLM-as-a-judge
with open(OUTPUT_DETAILS_JSON, "w", encoding="utf-8") as f:
json.dump(all_detailed_results, f, indent=2, ensure_ascii=False)
print(f"\nBenchmark completato con successo!")
print(f" - Metriche aggregate: {OUTPUT_CSV}")
print(f" - Risposte complete: {OUTPUT_DETAILS_JSON}")
if __name__ == "__main__":
main()
benchmark_ollama.py
Visualizzazione di benchmark_ollama.py.