Notebooks
03 — Adaptation & Shrinkage
Compare FK, SLCE, and Ledoit-Wolf methods.
Before the analytic classifier, Vyntri can transform the frozen features. Two knobs control that stage:
- adaptation — the projection:
fk(default),slce(advanced), ornone - shrinkage — covariance regularization:
diagonal(default),ledoit_wolf(data-estimated), ornone
Setup
from pathlib import Path
import numpy as np
from PIL import Image
from vyntri import Vyntri
def make_noise(root, classes, per_class, seed=0):
root = Path(root)
rng = np.random.default_rng(seed)
for i, name in enumerate(classes):
folder = root / name
folder.mkdir(parents=True, exist_ok=True)
shift = i * 0.7
for j in range(per_class):
img = (rng.normal(shift, 1.0, (32, 32, 3)) * 40 + 128).clip(0, 255)
Image.fromarray(img.astype(np.uint8)).save(folder / f'{name}_{j:02d}.png')
return root
DATA = Path('whitening_data')
train = make_noise(DATA / 'train', ['cats', 'dogs', 'birds'], per_class=20, seed=1)
test = make_noise(DATA / 'test', ['cats', 'dogs', 'birds'], per_class=12, seed=99)Adaptation comparison
Same backbone, same data, same seed — only adaptation changes.
from vyntri.data import split
s = split(str(train), train=0.7, val=0.1, test=0.2, seed=42)
def fit_and_report(**config):
model = Vyntri(seed=42, **config)
model.fit(train=s.train, val=s.val, progress=False)
test_acc = model.evaluate(s.test).accuracy
label = ', '.join(f'{k}={v}' for k, v in config.items())
print(f'{label:<44} val={model.validation_accuracy_:.3f} test={test_acc:.3f}')
return model
for adaptation in ['fk', 'none', 'slce']:
fit_and_report(adaptation=adaptation, shrinkage='none')Shrinkage comparison
Now fix adaptation="fk" and vary the shrinkage target.
for shrinkage in ['diagonal', 'ledoit_wolf', 'none']:
m = fit_and_report(adaptation='fk', shrinkage=shrinkage)
alpha = getattr(m.projection_, 'shrinkage_alpha_', None)
if alpha is not None:
print(f' -> estimated shrinkage alpha: {alpha:.3f}')