torchvision
torchvision is PyTorch's official computer vision library: pretrained model architectures (ResNet, ViT, Faster R-CNN and friends), common datasets (CIFAR, ImageNet wrappers, COCO), and image transforms that run on both PIL images and tensors. It is versioned in lockstep with torch itself, so torchvision 0.28 requires exactly torch 2.13, and it is the default starting point for training or fine-tuning vision models in PyTorch.
If you train vision models with PyTorch you will almost certainly have torchvision installed, and its weights-plus-transforms bundling is genuinely good engineering. Treat it as the reliable baseline and reach for timm or albumentations when you outgrow its model zoo or its augmentation speed.
Use it if
- You are training or fine-tuning a vision model in PyTorch and want pretrained weights with the exact preprocessing pipeline bundled next to them (weights.transforms())
- You need standard datasets like CIFAR-10 or COCO wired into a DataLoader without writing download and parsing code yourself
- You want detection, segmentation, or keypoint models (Faster R-CNN, Mask R-CNN, DeepLab) that plug straight into torch training loops
- You use transforms v2 to augment images together with their bounding boxes and masks, which plain image libraries cannot do
- You are doing classic image processing (thresholding, filters, measurement) without a neural net: installing the multi-hundred-MB torch stack for that is absurd next to scikit-image or opencv-python
- You want the strongest pretrained classifiers: the timm package tracks new architectures and weights far faster, and most modern papers release timm checkpoints, not torchvision ones
- Your augmentation pipeline is the bottleneck: albumentations covers more augmentations and is generally faster on CPU-bound preprocessing
- You cannot control the torch version: torchvision pins an exact torch release (0.28 pins torch==2.13.0), and any mismatch fails with confusing C++ operator errors, which hurts in shared or locked-down environments
Setup reality
pip install torchvision pulls in the exact matching torch wheel, which is hundreds of MB, and CUDA builds come from a separate index URL you must pass explicitly (the PyPI default wheel is CUDA for Linux, CPU for Mac), so follow the pytorch.org selector rather than guessing. The version lockstep table in the README is not optional reading: torch and torchvision upgrade together or not at all. Datasets download at import-and-run time, sometimes gigabytes, and the project explicitly does not vouch for dataset licenses; some pretrained weights (SWAG) are CC-BY-NC and unusable commercially.
Patterns
Classify an image with a pretrained modelpretrained-classification
import torch
from torchvision.models import resnet50, ResNet50_Weights
weights = ResNet50_Weights.DEFAULT
model = resnet50(weights=weights).eval()
preprocess = weights.transforms()
batch = preprocess(img).unsqueeze(0)
with torch.no_grad():
probs = model(batch).softmax(dim=1)
idx = probs.argmax().item()
print(weights.meta["categories"][idx])The old models.resnet50(pretrained=True) style is gone; weights enums replaced it. Always use weights.transforms() for preprocessing, because wrong resize or normalization silently tanks accuracy instead of erroring.
Modern transforms v2 preprocessingtransforms-v2-pipeline
import torch
from torchvision.transforms import v2
transform = v2.Compose([
v2.ToImage(),
v2.RandomResizedCrop(224, antialias=True),
v2.RandomHorizontalFlip(),
v2.ToDtype(torch.float32, scale=True),
v2.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]),
])v2.ToImage plus v2.ToDtype(scale=True) replaces the old ToTensor. Import from torchvision.transforms.v2, not torchvision.transforms, or you get the legacy versions with the same class names.
Train on a folder of images per classimagefolder-dataloader
from torch.utils.data import DataLoader
from torchvision import datasets
ds = datasets.ImageFolder("data/train", transform=transform)
loader = DataLoader(ds, batch_size=32, shuffle=True, num_workers=4)
print(ds.classes) # folder names become class labelsClass indices come from alphabetical folder order, not creation order. If train and val folders differ in which classes exist, the index mapping silently diverges between them.
Fine-tune only the head of a pretrained modelfine-tune-classifier
import torch.nn as nn
from torchvision.models import resnet50, ResNet50_Weights
model = resnet50(weights=ResNet50_Weights.DEFAULT)
for p in model.parameters():
p.requires_grad = False
model.fc = nn.Linear(model.fc.in_features, num_classes) # new head, grads onReplacing model.fc after freezing works because the new Linear defaults to requires_grad=True. For other architectures the head attribute differs (classifier, heads), so print the model first.
Read an image file straight to a tensordecode-image
from torchvision.io import decode_image
img = decode_image("cat.jpg") # uint8 tensor, shape [C, H, W]
print(img.shape, img.dtype)decode_image is the current API; read_image is the deprecated older name. Output is uint8 in [0, 255], so pass it through v2.ToDtype(torch.float32, scale=True) before feeding a model.
Download and use a built-in datasetbuiltin-dataset
from torchvision import datasets
train = datasets.CIFAR10(root="data", train=True, download=True,
transform=transform)
img, label = train[0]download=True fetches to root on first run and is a no-op afterwards. The project does not host these datasets and explicitly leaves license compliance to you, which matters for commercial use.
Run a pretrained detector on one imageobject-detection-inference
from torchvision.models.detection import (
fasterrcnn_resnet50_fpn, FasterRCNN_ResNet50_FPN_Weights)
weights = FasterRCNN_ResNet50_FPN_Weights.DEFAULT
model = fasterrcnn_resnet50_fpn(weights=weights).eval()
pred = model([weights.transforms()(img)])[0]
keep = pred["scores"] > 0.8
print(pred["boxes"][keep], pred["labels"][keep])Detection models take a list of image tensors, not a batched 4D tensor, and return one dict per image. Filter by score yourself; the model happily returns near-zero-confidence boxes.
Visualize detection resultsdraw-bounding-boxes
from torchvision.utils import draw_bounding_boxes
from torchvision.transforms.v2.functional import to_pil_image
annotated = draw_bounding_boxes(img, boxes=pred["boxes"][keep],
labels=names, width=3)
to_pil_image(annotated).show()draw_bounding_boxes wants the uint8 image, not the normalized float tensor you fed the model. Keep a copy of the original around for visualization.
Augment image and bounding boxes togetherjoint-transform-boxes
from torchvision import tv_tensors
from torchvision.transforms import v2
boxes = tv_tensors.BoundingBoxes(raw_boxes, format="XYXY",
canvas_size=img.shape[-2:])
transform = v2.Compose([v2.RandomHorizontalFlip(p=1.0)])
out_img, out_boxes = transform(img, boxes)This is the headline feature of transforms v2: wrapping boxes in tv_tensors.BoundingBoxes makes flips and crops update coordinates too. Plain tensors passed alongside are treated as images and transformed independently.
Semantic segmentation with DeepLabV3segmentation-inference
from torchvision.models.segmentation import (
deeplabv3_resnet50, DeepLabV3_ResNet50_Weights)
weights = DeepLabV3_ResNet50_Weights.DEFAULT
model = deeplabv3_resnet50(weights=weights).eval()
out = model(weights.transforms()(img).unsqueeze(0))["out"]
mask = out.argmax(1)[0] # [H, W] class index per pixelThe model returns a dict; the logits live under the out key (plus aux when training). The 21 classes are the PASCAL VOC set, so anything else gets folded into background.
Install a compatible torch and torchvision pairmatch-torch-version
# torchvision 0.28.x requires torch 2.13.x, exactly
pip install torch==2.13.0 torchvision==0.28.0
# CUDA builds come from the pytorch index, e.g.:
pip install torch torchvision --index-url https://download.pytorch.org/whl/cu126Mismatched pairs fail at import or with cryptic undefined-operator errors at runtime, not at install. The compatibility table in the README is the source of truth when pinning.
Alternatives
| Package | Registry | Pick it when |
|---|---|---|
| timm | PyPI | You mainly want a large, current zoo of pretrained image classifiers and backbones |
| albumentations | PyPI | Augmentation speed and variety matter more than staying inside the torch API |
| kornia | PyPI | You need differentiable, GPU-batched image operations inside the training graph |
| opencv-python | PyPI | Classic image processing or video handling without any deep learning stack |