Skip to main content

Vyntri

Classify images without training. Extract features from a pretrained backbone, project them analytically, and classify -- all in 4 lines of Python.

from vyntri import Vyntri
from vyntri.data import split

s = split("./my-dataset", train=0.7, test=0.2, seed=42)
model = Vyntri()
model.fit(train=s.train, val=s.val)
model.predict("./image.jpg")  # Prediction(label=cat, confidence=0.94)

No GPU required. No training loops. Useful defaults require little or no tuning.


Table of Contents


Why Vyntri?

Training-based Vyntri
Time to first prediction Minutes to hours ~4 seconds
Data needed Hundreds+ per class Works with 10-50 per class
GPU required Essentially yes No
Hyperparameters to tune Dozens Few (sensible defaults)
Overfitting risk High on small data Low (analytic, no gradient loops)

Vyntri replaces the training loop with analytic (closed-form) projection and classification. The result is fast to fit, resistant to overfitting (no gradient loops to memorize noise), and works on small datasets where traditional training fails.


Quick Start

1. Prepare your dataset

Organize images into folders by class name:

my-dataset/
  cats/
    cat_001.jpg
    cat_002.jpg
  dogs/
    dog_001.jpg
  birds/
    bird_001.jpg

Recommended: At least 10 images per class for good results.

2. Split, fit, and predict

from vyntri import Vyntri
from vyntri.data import split

# Create an explicit train/val/test split (no files copied)
s = split("./my-dataset", train=0.7, test=0.2, seed=42)

model = Vyntri()
model.fit(train=s.train, val=s.val)

result = model.predict("./test-photo.jpg")
print(result.label)       # cats
print(result.confidence)  # 0.94

3. Evaluate on the held-out test set

result = model.evaluate(s.test)
print(result.accuracy)    # 0.91
print(result.macro_f1)    # Per-class F1 (macro-averaged)
print(result.per_class)   # Per-class precision/recall/F1

4. Save and reload

model.save("./my-model.vyntri")
model = Vyntri.load("./my-model.vyntri")
model.predict("./new-image.jpg")

How It Works

Image
  |
Pretrained backbone (frozen)    <- extracts features, no training
  |
Analytic projection              <- closed-form dim reduction
  |
Shrinkage estimation             <- stabilizes covariance
  |
Analytic Ridge classifier        <- closed-form weights
  |
Prediction

Every step is analytic -- mathematically derived, not learned through gradient descent:

  • Low overfitting risk -- analytic fitting avoids iterative gradient-based optimization
  • No GPU needed -- CPU matrix ops are fast enough
  • Sensible defaults -- few or no parameters to tune for common workflows
  • Designed for determinism -- analytic fitting on fixed data and config produces consistent results

The pretrained backbone provides general visual features. Vyntri never modifies it -- it only learns the projection and classifier on top.


After Fitting

Model info

model.classes_           # ["cats", "dogs", "birds"]
model.class_to_idx_      # {"cats": 0, "dogs": 1, "birds": 2}
model.feature_dim_       # 576 (backbone feature dimension)
model.state              # "fitted", "fine_tuned", etc.

Predictions

result = model.predict("./image.jpg")
result.label            # cats
result.confidence       # 0.94

Batch predictions

results = model.predict_batch(["./img1.jpg", "./img2.jpg", "./img3.jpg"])
for path, label, conf in zip(results.paths, results.labels, results.confidences):
    print(f"{label}: {conf:.1%}")

Inspect internals

model.config             # Current configuration
model.fitted_config      # Config that produced this fit
model.projection_        # Learned projection matrix
model.classifier_        # Learned classifier weights
model.validation_accuracy_

Configuration

from vyntri import Vyntri
from vyntri.data import split

# All parameters can be passed directly as kwargs
model = Vyntri(
    backbone="auto",
    adaptation="fk",
    shrinkage="diagonal",
    cache_dir="./vyntri-cache",
)

s = split("./dataset", train=0.7, test=0.2, seed=42)
model.fit(train=s.train, val=s.val)
Config.describe()  # Returns structured docs for all parameters

Key configuration groups

Group Options What they control
Backbone backbone Feature extraction model
Projection adaptation, shrinkage, shrinkage_alpha, projection_dim Dim reduction
Classifier regularization Ridge classification strength
Validation val_fraction Deprecated — use split() instead
Cache cache_dir, cache_enabled Feature caching
Execution batch_size, num_workers, device, dtype Runtime behavior

Custom Backbones

from vyntri import Vyntri
from vyntri.data import split

# Use a larger backbone by name
s = split("./dataset", train=0.7, test=0.2, seed=42)
model = Vyntri(backbone="resnet50")
model.fit(s)

Fine-Tuning

For the highest accuracy on your specific domain:

from vyntri.data import split

s = split("./dataset", train=0.7, test=0.2, seed=42)
model.fit(train=s.train, val=s.val)
model.fine_tune(s, epochs=10, lr=1e-3, scope="last_layer")
Scope What unfreezes When to use
last_layer Final classification head Default -- safe, fast
last_block Final feature extraction block 50+ images/class
full Entire backbone 1000+ images/class

Note: Fine-tuning requires a GPU for reasonable speed.


API Reference

Method Description
vyntri.data.split(path, train, test, seed) Create explicit train/val/test split
Vyntri(**kwargs) Create model instance
model.fit(train=..., val=...) Fit on dataset (accepts FolderDataset, Path, or str)
model.predict(image) Classify single image
model.predict_batch(images) Batch classify
model.evaluate(path or FolderDataset) Evaluate on test set
model.save(path) / Vyntri.load(path) Serialize/deserialize
model.fine_tune(dataset, scope, epochs, lr) Optional fine-tuning (accepts SplitResult/FolderDataset/path)
model.update(dataset) Add new data/classes (accepts FolderDataset/Path/path)
model.analyze(dataset) Inspect dataset (accepts FolderDataset/Path/path)
model.select_backbone(dataset) Auto-select backbone
model.clear_cache() Remove feature cache
Property Description
model.classes_ Class names list
model.class_to_idx_ Class to index mapping
model.state Current model state
model.config Current configuration
model.fitted_config Config used for last fit
model.feature_dim_ Backbone feature dimension
model.validation_accuracy_ Validation accuracy from fit

Examples

Image classification

from vyntri import Vyntri
from vyntri.data import split

s = split("./flowers", train=0.7, test=0.2, seed=42)
model = Vyntri()
model.fit(train=s.train, val=s.val)
print(model.classes_)  # ["daisy", "rose", "sunflower", "tulip"]

result = model.predict("./test-rose.jpg")
print(result.label, result.confidence)

Incremental learning

from vyntri import Vyntri
from vyntri.data import split
from vyntri.data.dataset import FolderDataset

s = split("./dataset-v1", train=0.7, test=0.2, seed=42)
model = Vyntri()
model.fit(train=s.train, val=s.val)

# update() accepts FolderDataset, Path, or string
new_data = FolderDataset("./dataset-v2")
model.update(new_data)  # Adds new data without forgetting

Comparing backbones

from vyntri import Vyntri
from vyntri.data import split

s = split("./dataset", train=0.7, test=0.2, seed=42)
for name, bb in [("mobile", "mobilenet_v3_small"), ("resnet", "resnet50")]:
    model = Vyntri(backbone=bb)
    model.fit(train=s.train, val=s.val)
    print(name, model.validation_accuracy_)

Installation

pip install vyntri

Requirements: Python 3.9+, PyTorch, torchvision

Optional for fine-tuning: CUDA-capable GPU


Migrating from v1.1.x

v1.4.0: Explicit dataset roles and adaptation

fit() now requires explicit train= and optional val= parameters. SplitResult is no longer accepted directly — use s.train and s.val explicitly. adaptation= replaces whitening= as the canonical config name (old name still works with deprecation warning).

# v1.3.x (deprecated)
s = split("./my-dataset", train=0.7, test=0.2, seed=42)
model = Vyntri(whitening="fk")
model.fit(s)

# v1.4.0 (recommended)
s = split("./my-dataset", train=0.7, test=0.2, seed=42)
model = Vyntri(adaptation="fk")
model.fit(train=s.train, val=s.val)

v1.2.0: Explicit dataset splitting

vyntri.data.split() replaces implicit automatic splitting.

v1.3.0: API consistency and stability

  • update(), fine_tune(), and analyze() accept FolderDataset, Path, or strings.
  • save()/load() preserves training history and class registry.
  • loaded.state reflects the pre-save state ("fitted", "updated", or "fine_tuned").
  • Scheduled fit with no validation set no longer crashes.
  • Corrupt images raise DatasetError instead of raw PIL tracebacks.

Vyntri -- classify images without training.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

vyntri-1.4.0.tar.gz (111.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

vyntri-1.4.0-py3-none-any.whl (83.8 kB view details)

Uploaded Python 3

File details

Details for the file vyntri-1.4.0.tar.gz.

File metadata

  • Download URL: vyntri-1.4.0.tar.gz
  • Upload date:
  • Size: 111.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for vyntri-1.4.0.tar.gz
Algorithm Hash digest
SHA256 2bdf07113fa9689e263d98e798ae412111621370c111492f649b357bf880d2fc
MD5 a21629d3054ddbeb4d1464560c9df9a1
BLAKE2b-256 e3157fd44c44bcc1d2374c61d5e5ea7a4b08ab27698ad942a2258faba4a394d5

See more details on using hashes here.

Provenance

The following attestation bundles were made for vyntri-1.4.0.tar.gz:

Publisher: workflow.yml on AreebShahid07/vyntri

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file vyntri-1.4.0-py3-none-any.whl.

File metadata

  • Download URL: vyntri-1.4.0-py3-none-any.whl
  • Upload date:
  • Size: 83.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for vyntri-1.4.0-py3-none-any.whl
Algorithm Hash digest
SHA256 573f7c78d04d5b8c17399e81ec1d6deef845393d6ab5cf40a29f0a7b5f4a928f
MD5 1120a5d3e993335ea743f1c16a1343ac
BLAKE2b-256 c98f88a5887956df13a9bd5ac7e188f0bd539f2ef123367f45a744599f17e5af

See more details on using hashes here.

Provenance

The following attestation bundles were made for vyntri-1.4.0-py3-none-any.whl:

Publisher: workflow.yml on AreebShahid07/vyntri

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

1.5.0

2 files

This release

1.4.0 This release

2 files

1.3.2

2 files

1.3.1

2 files

1.2.0

2 files

1.1.5

2 files

1.0.0

2 files

0.5.0

2 files

0.1.0

2 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