Generation / Anomaly Detection — MVTec (PyTorch)¶
Example: weightslab/examples/PyTorch/wl-generation/main.py
Task: Unsupervised anomaly detection on MVTec capsule images with a multi-task UNet (classification head + reconstruction head + contrastive loss).
This example introduces two advanced patterns:
compute_dependencies=Falsewhen wrapping a complex generative model.wl.save_group_signalsfor signals computed over pairs of samples.
Integration walkthrough¶
1. Multi-task model wrapping¶
model = wl.watch_or_edit(
_model,
flag="model",
device=device,
compute_dependencies=False,
)
compute_dependencies=False skips the static dependency graph computation
for the wrapped model. Use this when the model has dynamic control flow,
multiple outputs, or cannot be traced by torch.fx — common in
encoder-decoder architectures.
2. Dataset with paired samples¶
The dataset yields two images per item (an anchor and a randomly paired image) so the contrastive loss can be computed in-batch:
train_loader = wl.watch_or_edit(
train_dataset,
flag="data",
loader_name="train_loader",
batch_size=parameters["batch_size"],
shuffle=True,
compute_hash=False,
)
# Loader yields: [img1, img2], [uid1, uid2], [label1, label2], metadata
The dataset’s __getitem__ returns a pair so each WeightsLab batch
contains two groups of sample IDs.
3. Per-sample signals for individual losses¶
with guard_training_context:
[img1, img2], [uid1, uid2], [label1, label2], _ = next(train_loader)
cls_out, recon_out = model([img1, img2])
cls_loss_per = wl.save_signals({"train/cls_loss": cls_loss_per_sample},
batch_ids=uid1, origin="train_loader")
recon_loss_per = wl.save_signals({"train/recon_loss": recon_loss_per_sample},
batch_ids=uid1, origin="train_loader")
4. Group signals for contrastive (pair-level) losses¶
wl.save_group_signals(
signals={"train/contrastive_loss": contrastive_per_pair},
group_ids=list(zip(uid1, uid2)),
origin="train_loader",
)
wl.save_group_signals stores signals that are defined over groups of
samples rather than individual ones. Each group_id is a tuple of sample
UIDs. The studio can display the contrastive loss for every pair and lets you
filter by pair distance to find the hardest negatives.
Tip
This example is bundled with WeightsLab (uses a synthetic dataset):
weightslab start # 1. deploy the studio
weightslab start example --gen # 2. start the generation / anomaly demo