refactor(benchmark): delegate model loading to tasks and support CIFAR-100

- Extract model loading logic from benchmark CLI into task-owned prepare_benchmark
- Add RetrievalEncoder class wrapping DINO with optional hash compression
- Add accelerate dependency for device management  
- Switch dataset from CIFAR-10 to CIFAR-100 with fine_label column
This commit is contained in:
2026-05-09 15:12:19 +08:00
parent 0fbcd915bd
commit ab616528b4
7 changed files with 1828 additions and 1226 deletions

View File

@@ -1,18 +1,42 @@
"""Benchmark runner for executing evaluations."""
from pathlib import Path
from typing import Any
from typing import Any, Callable, cast
import lancedb
from benchmarks.datasets import HuggingFaceDataset, LocalDataset
from benchmarks.tasks import get_task
from configs.models import BenchmarkConfig, DatasetSourceConfig
from configs.models import BenchmarkConfig, DatasetSourceConfig, ModelConfig
from rich.console import Console
from rich.table import Table
console = Console()
def _create_task(config: BenchmarkConfig, model_config: ModelConfig | None) -> Any:
"""Create benchmark task with task-specific model settings.
Args:
config: Benchmark configuration.
model_config: Optional model configuration for task-owned loading.
Returns:
Benchmark task instance.
"""
task_kwargs: dict[str, Any] = {"top_k": config.task.top_k}
if config.task.type == "retrieval" and model_config is not None:
task_kwargs.update(
{
"dino_model": model_config.dino_model,
"compression_dim": model_config.compression_dim,
"compressor_path": model_config.compressor_path,
}
)
return get_task(config.task.type, **task_kwargs)
def create_dataset(config: DatasetSourceConfig) -> Any:
"""Create a dataset instance from configuration.
@@ -130,10 +154,30 @@ def _print_benchmark_info(
console.print(table)
def _print_benchmark_results(results: dict[str, Any]) -> None:
"""Print benchmark results using Rich table.
Args:
results: Final benchmark metrics.
"""
table = Table(title="Benchmark Results", show_header=False)
table.add_column("Metric", style="cyan", no_wrap=True)
table.add_column("Value", style="green")
for key, value in results.items():
if isinstance(value, float):
table.add_row(key, f"{value:.4f}")
continue
table.add_row(key, str(value))
console.print(table)
def run_benchmark(
model: Any,
processor: Any,
config: BenchmarkConfig,
model_config: ModelConfig | None = None,
model_name: str = "model",
) -> dict[str, Any]:
"""Run benchmark evaluation.
@@ -148,6 +192,7 @@ def run_benchmark(
model: Feature extraction model.
processor: Image preprocessor.
config: Benchmark configuration.
model_config: Optional model configuration for task-owned loading.
model_name: Model name for table naming.
Returns:
@@ -171,6 +216,23 @@ def run_benchmark(
f"Dataset {config.dataset.path} does not have train/test splits"
)
task = _create_task(config, model_config)
resolver = getattr(task, "prepare_benchmark", None)
if callable(resolver):
prepare_benchmark = cast(
Callable[[Any, Any, str], tuple[Any, Any, str]],
resolver,
)
model, processor, model_name = prepare_benchmark(
model,
processor,
model_name,
)
if model is None or processor is None:
raise ValueError("Benchmark task did not provide a valid model and processor")
# Infer vector dimension from a sample
sample = train_dataset[0]
sample_image = sample["img"]
@@ -191,16 +253,17 @@ def run_benchmark(
f"[yellow]Table '{table_name}' already has {table_count} entries, skipping database build.[/yellow]"
)
else:
# Create and run benchmark task
task = get_task(config.task.type, top_k=config.task.top_k)
console.print(
f"[cyan]Building database[/cyan] with {len(train_dataset)} training samples..."
)
task.build_database(model, processor, train_dataset, table, config.batch_size)
table_count = table.count_rows()
_print_benchmark_info(config, vector_dim, table_name, table_count)
# Run evaluation (results with Rich table will be printed by the task)
task = get_task(config.task.type, top_k=config.task.top_k)
console.print(f"[cyan]Evaluating[/cyan] on {len(test_dataset)} test samples...")
results = task.evaluate(model, processor, test_dataset, table, config.batch_size)
_print_benchmark_results(results)
return results