VyntriVyntri

Getting Started

Get Vyntri up and running in under 5 minutes.

Get Vyntri up and running in under 5 minutes.

Installation

Terminal
pip install vyntri

This installs Vyntri and all required dependencies (PyTorch ≥ 2.0, torchvision ≥ 0.15, NumPy ≥ 1.24, Pillow ≥ 10.0). Requires Python ≥ 3.9.

Requirements

  • Python 3.9 or higher
  • No GPU required — works on CPU by default
  • ~500 MB disk for PyTorch + backbone weights (downloaded on first use)
  • Tested on Windows, macOS, Linux, and Raspberry Pi OS

Prepare Your Dataset

Organize your images into folders where each folder name is the class label:

Folder structure
my_dataset/
├── cat/
│   ├── photo1.jpg
│   ├── photo2.jpg
│   └── ...
├── dog/
│   ├── photo1.jpg
│   └── ...
└── bird/
    └── ...

Vyntri supports JPG, JPEG, PNG, BMP, TIFF, and WebP image formats.

Split Your Data

Before fitting, explicitly split your dataset into train, validation, and test sets:

split.py
from vyntri.data import split

# Split into train (70%), test (20%), validation is computed as 10%
s = split("./my_dataset", train=0.7, test=0.2, seed=42)

print(f"Train: {s.counts['train']} images")
print(f"Val:   {s.counts['val']} images")
print(f"Test:  {s.counts['test']} images")

The split is deterministic — same seed always produces the same partition. The split manifest is stored for reproducibility.

Why split? Vyntri does not automatically create a validation split. Using split() gives you full control over your train/val/test roles.

Fit Your First Model

Option A: Default Config

train.py
from vyntri import Vyntri
from vyntri.data import split

# Split your dataset
s = split("./my_dataset", train=0.7, test=0.2, seed=42)

# Initialize with default config (CPU, MobileNetV3, FK adaptation)
model = Vyntri()

# Fit: pass train and val explicitly
model.fit(train=s.train, val=s.val)

# View training summary
model.summary()

# Save the trained model
model.save("my_model.vyntri")

Option B: Training Only (No Validation)

If you don't need validation (e.g. you have a separate test set and want all training data used):

train_only.py
from vyntri import Vyntri

# All images in this folder become training data
model = Vyntri()
model.fit("./my_dataset")

# All images are used for fitting — no automatic split
model.summary()

Option C: Auto Backbone Selection

auto_backbone.py
from vyntri import Vyntri
from vyntri.data import split

s = split("./my_dataset", train=0.7, test=0.2, seed=42)

# Auto-select the best backbone for your dataset
model = Vyntri(backbone="auto")
model.fit(train=s.train, val=s.val)

# Selection results are logged and stored
print(model.summary())

Note: backbone="auto" requires a validation dataset. Pass val=... to fit(), or use vyntri.data.split() to create one.

Option D: Auto with Candidate Control

Limit which backbones are evaluated during auto-selection. Excluded backbones are never initialized or evaluated.

candidates.py
from vyntri import Vyntri
from vyntri.data import split

s = split("./my_dataset", train=0.7, test=0.2, seed=42)

# Only evaluate two fast backbones
model = Vyntri(
    backbone="auto",
    candidates=["mobilenet_v3_small", "resnet18"],
)
model.fit(train=s.train, val=s.val)

# View which backbone was selected
sel = model.metadata_["selection"]
print(f"Selected: {sel['selected']}")

Supported Backbones

BackboneFeaturesSpeedNotes
mobilenet_v3_small576⚡ FastDefault. Great for edge devices.
resnet18512FastGood balance of speed and accuracy.
resnet502048ModerateHigher capacity.
efficientnet_b01280FastEfficient architecture.
convnext_tiny768FastConvNeXt architecture.
autoVariesSelects the best for your data.

Evaluate

evaluate.py
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)

# Evaluate on the test set
result = model.evaluate(s.test)
print(f"Accuracy: {result.accuracy:.1%}")
print(f"Macro F1: {result.macro_f1:.3f}")

Make Predictions

predict.py
from vyntri import Vyntri

# Load trained model
model = Vyntri.load("my_model.vyntri")

# Predict single image
prediction = model.predict("test_photo.jpg")
print(f"Predicted class: {prediction.label}")
print(f"Confidence: {prediction.confidence}")

# Batch predictions
result = model.predict_batch("./images")
print(result.labels)  # list of predicted labels

Add New Data (Continual Learning)

Vyntri supports incremental updates — add new images or even new classes without retraining from scratch:

update.py
from vyntri import Vyntri

model = Vyntri.load("my_model.vyntri")

# Update with new data (adds new classes automatically)
result = model.update("./new_data")
print(f"New classes: {result.new_classes}")

# Save updated model
model.save("my_model.vyntri")

The update() method maintains sufficient statistics and re-solves — sequential matches joint.

Inspect Your Model

After fitting, you can inspect what the model learned:

inspect.py
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)

# What classes does the model know?
print(model.classes_)        # ['cats', 'dogs', 'birds']
print(model.class_to_idx_)   # {'cats': 0, 'dogs': 1, 'birds': 2}

# Model details
print(model.feature_dim_)    # 576 (backbone feature dimension)
print(model.validation_accuracy_)  # 0.92 (None if no validation set)
print(model.state)           # 'fitted'

# Full summary
print(model.summary())

Next Steps

  • Explore solvers — Compare adaptation and shrinkage options in the Solvers Guide
  • Full API — See all classes and methods in the API Reference
  • Fine-tuning — Optional gradient fine-tuning for higher accuracy (see API Reference)