Skip to main content

Samuel_Collins_CV_Benchmarking

Benchmark traditional machine-learning classifiers and modern CNN architectures on one image-classification problem. Give it a labeled image dataset in any of four organizations; it standardizes the images, builds one stratified split, trains every model on that split, and saves comparable metrics, plots and reports.

Sixteen models on a single shared split:

Group Models
Traditional ML Logistic Regression, Decision Tree, Random Forest, SVM
Baseline neural Neural Network (MLP), Simple CNN
Deep CNN AlexNet, VGG16, GoogLeNet, ResNet18, ResNet50, DenseNet121, MobileNetV3-Large, EfficientNet-B0, ConvNeXt-Tiny, YOLO classification

PyPI: https://pypi.org/project/Samuel_Collins_CV_Benchmarking/ · version 2.0.0 · MIT licensed · 545 tests

Installation

pip install Samuel_Collins_CV_Benchmarking

Then:

from samuel_collins_cv_benchmarking import benchmark_image_classification

From a clone, for development. The virtual environment matters on macOS, where the system python3 and a Homebrew python3 are different interpreters with different packages installed:

python3 -m venv .venv
source .venv/bin/activate
pip install -e ".[dev,report,deep]"

The deep extra adds torchvision and the two complexity profilers. It is optional and imported lazily, so a plain pip install Samuel_Collins_CV_Benchmarking does not pull a gigabyte of pretrained-model machinery onto someone who only wants the traditional classifiers.

To reproduce the published numbers rather than install the newest packages, use the pinned set instead:

pip install -r requirements.txt
pip install -e .

Inside the environment, plain python, pytest and twine resolve to the right interpreter, and everything below can be run without a path prefix.

Running everything

python scripts/run_all.py                 # tests, benchmarks, report, PDF
python scripts/run_all.py --report-only   # just rebuild the report

The deep CNN benchmark

python run_benchmark.py                   # all nine torchvision architectures
python run_benchmark.py --model resnet50   # one architecture
python run_benchmark.py --model all        # explicit form of the default
python run_benchmark.py --tables-only      # rebuild tables and plots only

The deep architectures run on the animals10_n500 RGB configuration - the same one Part 1 benchmarked, so the two halves are directly comparable. RGB because every pretrained backbone expects three channels; the grayscale path refuses rather than replicating one channel into three and quietly weakening transfer learning.

Part 1 is not re-run. Its split is reproduced from the same manifest at seed 42 and then verified against Part 1's own published artifacts - the recorded dataset index behind every stored test position, and the exact rows the Simple CNN held back for validation. If the dataset under data/ has changed since Part 1 ran, the benchmark stops with an explanation instead of producing a comparison that looks valid and is not.

# re-run any architecture the protocol learning rate destabilized
python scripts/remediate_unstable.py --dry-run   # report only
python scripts/remediate_unstable.py             # detect and re-run

At the prescribed AdamW learning rate of 0.001, the two pre-BatchNorm architectures do not train: AlexNet collapses to chance and VGG16 is crippled. Every architecture carrying BatchNorm or LayerNorm trains at that rate without difficulty. This script detects the failures by a stated numeric rule, archives the protocol-rate results, re-runs only the affected architectures at a lower rate, and writes deep_lr_deviations.json recording both outcomes. The report reads that file, so the deviation is documented rather than silently applied.

YOLO classification

YOLO needs its own environment. ultralytics cannot be installed alongside the main one: this project runs on Python 3.9, and on macOS ultralytics excludes every numpy 2.0 through 2.3.4 release while numpy >= 2.3.5 requires Python 3.11+. Installing it would resolve numpy down from 2.0.2 and silently change the environment that produced the Part 1 results and the test suite.

python3 -m venv .venv-yolo                 # use a Python 3.11+ interpreter
.venv-yolo/bin/pip install -r requirements-yolo.txt
python scripts/run_yolo.py

It exports the identical split as a symlink tree, trains in the isolated environment as a subprocess, and brings the predictions back to be scored by the same code that scores every other architecture - so the metrics are computed identically even though the training environment differs.

Usage

from samuel_collins_cv_benchmarking import benchmark_image_classification

results = benchmark_image_classification(
    dataset="./data/animals10_n500/images",
    dataset_type="folder",
    target_labels=["cat", "dog", "horse"],
    color_mode="rgb",
)

Parameters

Parameter Meaning
dataset Dataset root directory, CSV/JSON/JSONL manifest path, Pandas DataFrame, or NumPy image array
dataset_type One of "folder", "csv", "json", "array"
target_labels Class-folder names, manifest label-field name, DataFrame label column, or a label vector
color_mode "grayscale" for one channel, "rgb" for three

Image size (64x64), random seed (42), split ratio (80/20) and output location are internal constants — callers configure nothing beyond the four parameters above.

The four dataset organizations

1. Class folders — each subfolder name is the label. PNG, JPG, JPEG, BMP and TIFF are supported.

data/animals10_n500/images/
├── cat/cat_001.jpeg
├── dog/dog_001.jpeg
└── horse/horse_001.jpeg
benchmark_image_classification(
    dataset="./data/animals10_n500/images", dataset_type="folder",
    target_labels=["cat", "dog", "horse"], color_mode="rgb")

2. CSV manifest — an image_path column plus a label column named by target_labels. Relative paths resolve from the manifest's own location.

image_path,class_name
images/cat/cat_001.jpeg,cat
benchmark_image_classification(
    dataset="./data/animals10_n500/labels.csv", dataset_type="csv",
    target_labels="class_name", color_mode="rgb")

3. JSON / JSONL manifest — a JSON list of records, or one JSON record per line. Every record carries image_path and the label field.

[{"image_path": "images/cat/cat_001.jpeg", "class_name": "cat"}]
benchmark_image_classification(
    dataset="./data/animals10_n500/labels.json", dataset_type="json",
    target_labels="class_name", color_mode="rgb")

4. NumPy array / in-memory — dataset is the image tensor, target_labels the label vector. Accepted shapes: (N, H, W), (N, H, W, 1), (N, H, W, 3).

benchmark_image_classification(
    dataset=X_images, dataset_type="array",
    target_labels=y_labels, color_mode="grayscale")

Datasets

RGB - Animals-10. 10 classes. The images are not committed to this repository: Animals-10 is assembled from web-scraped photographs, so redistributing it here is not appropriate. Rebuild it in one command (needs Kaggle API credentials at ~/.kaggle/kaggle.json):

python scripts/download_animals10.py                 # 500/class -> data/animals10_n500
python scripts/download_animals10.py --per-class 10  # fast smoke set
python scripts/download_animals10.py --per-class 100 --out data/custom

Each tier lands in its own directory containing images/ plus labels.csv, labels.json and labels.jsonl, so several sizes coexist:

data/animals10_n500/
├── images/<class>/<class>_001.jpeg
├── labels.csv
├── labels.json
└── labels.jsonl

Sampling method

Reported subset: 500 images per class, 5,000 total, drawn from alessiocorrado99/animals10. Per class, the file list is sorted, shuffled with random.Random(<english class name>), and the first N images that decode successfully are taken. Every file is opened, verified and RGB-converted before selection; undecodable files are skipped and counted.

The seed depends only on the class name, never on N, so the tiers are nested: n10 is byte-identical to the first 10 images of n100, filenames included. A comparison across tiers is therefore a genuine learning curve rather than three unrelated samples.

Source folder names are Italian and are mapped to English (cane->dog, gatto->cat, ragno->spider, ...). The per-class ceiling is set by the smallest class, elephant, at 1,446 images.

Grayscale. The same images through color_mode="grayscale", which is the single-channel demonstration. Running both isolates what color contributes: on Animals-10 it is worth about a quarter of the CNN's macro F1, and it costs the SVM roughly forty times its training run.

Results

Two runs over nested subsets of Animals-10, ten classes, RGB at 64x64. The tiers share one fixed ordering, so n100 is a byte-identical subset of n500 and reading across them is a learning curve rather than a comparison of unrelated samples. Chance for ten classes is 0.100.

Model Macro F1 @ 100/class Macro F1 @ 500/class change
Simple CNN 0.295 0.434 +47%
SVM 0.242 0.352 +45%
Random Forest 0.294 0.319 +9%
Neural Network 0.178 0.281 +58%
Logistic Regression 0.213 0.225 +6%
Decision Tree 0.093 0.180 +94%

At 100 images per class the CNN and Random Forest are tied. At 500 the CNN leads by 36%, and Logistic Regression and Random Forest have nearly flattened while the CNN and SVM are still climbing steeply. Reporting only the smaller run would have supported the conclusion that a CNN and an ensemble of trees are equivalent here - true at that size, and misleading as a finding.

Cost at 500 per class tells a different story from accuracy alone:

Model Training Inference
SVM 547.4 s 150.1 ms/image
Simple CNN 44.8 s 0.43 ms/image
Decision Tree 20.2 s 0.002 ms/image
Logistic Regression 9.5 s 0.040 ms/image
Random Forest 3.3 s 0.028 ms/image
Neural Network 1.3 s 0.025 ms/image

The SVM buys third place at 75,000 times the Decision Tree's inference cost: classifying a thousand images would take it two and a half minutes against Random Forest's 0.03 seconds for a slightly better score.

Full outputs are under benchmark_results/<tier>/. Reproduce them with:

python scripts/download_animals10.py --per-class 500
python scripts/run_benchmarks.py

The 500/class run takes about 13 minutes, 9 of which are the SVM.

Output layout

One directory per configuration, holding both halves of the benchmark:

benchmark_results/animals10_n500_rgb/
    benchmark_summary.csv                       Part 1 comparison table
    benchmark_metrics.json                      Part 1 full results
    deep_metrics.json                           Part 2 full results
    deep_run_configuration.json                 protocol, environment, deviations
    deep_lr_deviations.json                     learning-rate changes, if any
    combined_ml_cnn_benchmark_results.csv        the master table, all 16 models
    per_class_f1_comparison.csv                 per-class F1, every model
    rankings.json                               rankings A through E
    confusion_matrices/*.png                    one per model, both halves
    classification_reports/*.csv                one per model, both halves
    plots/                                      comparison figures + training curves
    checkpoints/best_*.pt                       selected weights per architecture
    logs/*.jsonl                                one line per epoch, written live

The per-epoch logs are committed - they are the record of what each run actually did. The checkpoints are not: the nine together are about 1.5 GB and VGG16's alone exceeds GitHub's 100 MB per-file limit. They are regenerated by python run_benchmark.py, and their sizes are recorded in deep_metrics.json and the master table, so every reported number survives without the weights being in version control.

N/A appears wherever a metric is not meaningful for a model rather than wherever it was inconvenient to obtain. A Random Forest has no parameter count in the sense a CNN does, no checkpoint on disk and no device memory figure, and a zero in those cells would be a fabricated measurement that looks exactly like a real one.

Tests

pytest tests/

tests/fixtures/ holds small committed datasets so the suite runs in a clean checkout with no downloads:

Fixture Contents
mini/ 3 classes x 5 images, pristine. One image per required extension (.jpeg, .jpg, .png, .bmp, .tiff) at five different dimensions, so resizing and aspect handling are exercised.
broken/ 3 classes x 3 images plus one undecodable file and, in the manifests, one row pointing at a file that is not on disk. Covers the skip-and-report path.

Each tree has matching *_labels.csv, .json and .jsonl manifests, so all four dataset organizations can be tested against committed data.

License

MIT. See LICENSE. The license covers this source code, not the third-party image datasets it consumes.

Release files for Samuel-Collins-CV-Benchmarking 2.0.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for Samuel-Collins-CV-Benchmarking 2.0.0
File Size Uploaded
samuel_collins_cv_benchmarking-2.0.0.tar.gz 399.1 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for Samuel-Collins-CV-Benchmarking 2.0.0
File Interpreter ABI Platform
samuel_collins_cv_benchmarking-2.0.0-py3-none-any.whl Python 3 none any Details

Total release size: 491.6 kB

Release files / samuel_collins_cv_benchmarking-2.0.0.tar.gz

Download URL samuel_collins_cv_benchmarking-2.0.0.tar.gz
Size 399.1 kB
Tags Source
SHA-256 checksum
How to use checksums
32dd8eab48f8f992f076945a8cba45ac7508aab5c6be95a0ed7813d40e9e4c6e
BLAKE2b-256 checksum
How to use checksums
87c1040e9d8d21f6a60cfb85fe3beb30c39d563d556c03273aa2b57b40c58758
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.9.6

Release files / samuel_collins_cv_benchmarking-2.0.0-py3-none-any.whl

Download URL samuel_collins_cv_benchmarking-2.0.0-py3-none-any.whl
Size 92.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
3bd67e624c233cd2e6e1ca3d06d675b4b1299fbad037b86acb4309a6b0c125df
BLAKE2b-256 checksum
How to use checksums
8ce91481d1f94e557f869419e8460de3a7ae1d8dde56310915984190bfe8f0f8
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.9.6

Release history Release notifications | RSS feed

This release

2.0.0 This release

2 release files

1.0.1

2 release files

1.0.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page