library(kuzco)
library(dplyr)
library(tidyr)
library(purrr)library(kuzco)
library(dplyr)
library(tidyr)
library(purrr)Different vision models have different strengths, speeds, and price tags. Before committing to one for a production workflow, it pays to run them head-to-head on your images and your task. This vignette shows a simple benchmarking pattern: same images, same prompt, several models, one comparison table.
We’ll benchmark image classification across three setups: a local model via Ollama, another local model, and a cloud model. Swap in whatever you actually have pulled.
We’ll classify a small set of images with llm_image_classification(). Use the bundled test image to follow along, or point image_files at your own folder.
image_files <- c(
system.file("img/test_img.jpg", package = "kuzco")
# add more: list.files("path/to/images", full.names = TRUE, pattern = "\\.(jpg|png)$")
)Each contender is just a model + backend + provider combo. Keep the task identical so the comparison is fair.
contenders <- tibble::tibble(
label = c("qwen2.5vl (ollama)", "pixtral-12b (mistral)"),
llm_model = c("qwen2.5vl", "pixtral-12b"),
provider = c("ollama", "mistral")
)Loop over models x images, timing each call. We keep it sequential here so timings are comparable; for real throughput numbers, see the parallel patterns in the batch-image-processing vignette.
benchmark_one <- function(img, llm_model, provider, label) {
tictoc::tic()
res <- kuzco::llm_image_classification(
image = img,
llm_model = llm_model,
provider = provider,
backend = "ellmer"
)
elapsed <- tictoc::toc(quiet = TRUE)
tibble::tibble(
model = label,
file = basename(img),
image_classification = res$image_classification,
primary_object = res$primary_object,
seconds = unname(elapsed$toc - elapsed$tic)
)
}
grid <- tidyr::expand_grid(img = image_files, contenders)
results <- purrr::pmap_dfr(
grid,
~ benchmark_one(..1, ..2, ..3, ..4)
)
resultsWith results in a tidy data frame, the comparison writes itself: do the models agree on the classification? Which is fastest?
# agreement across models per image
results |>
dplyr::select(file, model, image_classification) |>
tidyr::pivot_wider(names_from = model, values_from = image_classification)
# speed comparison
results |>
dplyr::group_by(model) |>
dplyr::summarise(
mean_seconds = mean(seconds),
.groups = "drop"
)res metadata) by your expected volume.llm_image_custom()).Once you’ve picked a winner, the batch-image-processing vignette shows how to scale it up.