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(s)
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/test split (no files copied)
s = split("./my-dataset", train=0.7, test=0.2, seed=42)

model = Vyntri()
model.fit(s)

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",
    whitening="fk",
    shrinkage="diagonal",
    cache_dir="./vyntri-cache",
)

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

Key configuration groups

Group Options What they control
Backbone backbone Feature extraction model
Projection whitening, shrinkage, shrinkage_alpha, projection_dim Dim reduction
Classifier regularization Ridge classification strength
Validation val_fraction Legacy only — 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(s)
model.fine_tune(str(s.train), 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(split_result or path) Fit on dataset
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
model.update(dataset) Add new data/classes
model.analyze(dataset) Inspect dataset
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(s)
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

s = split("./dataset-v1", train=0.7, test=0.2, seed=42)
model = Vyntri()
model.fit(s)
model.update("./dataset-v2")  # 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(s)
    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.2.0 introduces vyntri.data.split() as the recommended way to partition datasets. Passing a folder-per-class path directly to fit() still works but emits a DeprecationWarning.

# Old (deprecated)
model.fit("./my-dataset")

# New (recommended)
from vyntri.data import split
s = split("./my-dataset", train=0.7, test=0.2, seed=42)
model.fit(s)

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.2.0.tar.gz (104.6 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.2.0-py3-none-any.whl (81.5 kB view details)

Uploaded Python 3

File details

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

File metadata

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

File hashes

Hashes for vyntri-1.2.0.tar.gz
Algorithm Hash digest
SHA256 251ef1a7beefdc4158b28ea223090d877b278683cafd69f837303971a3af3fc9
MD5 87705057be51460e1f4080b157f5585a
BLAKE2b-256 e711a1fe208af3007ead89c1e1bbffd433596c8726fae99c3e6efd9483adba32

See more details on using hashes here.

Provenance

The following attestation bundles were made for vyntri-1.2.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.2.0-py3-none-any.whl.

File metadata

  • Download URL: vyntri-1.2.0-py3-none-any.whl
  • Upload date:
  • Size: 81.5 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.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 73a944e2035395d47e5a3e64ce987ce9cda09c7289d8bc0c1e192314d732e044
MD5 7cff6c79d48959d86dae3ca5124b3e07
BLAKE2b-256 555e48684edafd3a35b0da9cf6e961584ed3e007a42a9f78a30d9a4ef63195d6

See more details on using hashes here.

Provenance

The following attestation bundles were made for vyntri-1.2.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

1.4.0

2 files

1.3.2

2 files

1.3.1

2 files

This release

1.2.0 This release

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