Pre-trained Models in torchvision: ResNet, EfficientNet, and ViT
Learners will load a ResNet-50 pre-trained on ImageNet, inspect its architecture, and make an inference on a new image to verify the pre-learned representations.
Pre-trained Models in torchvision: ResNet, EfficientNet, and ViT is a free Machine Learning Academy lesson on CoddyKit — lesson 1 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the Machine Learning Academy learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.
Why Use Pre-trained Models?
Training a deep neural network on ImageNet from scratch requires millions of labelled images and weeks of GPU compute. Pre-trained models have already learned general visual features — edges, textures, shapes, and high-level object parts — from this enormous dataset.
By reusing these weights, you benefit from the learning done on 1.2 million images without paying the training cost. This is the core idea of transfer learning: features learned on one large task transfer well to related smaller tasks. torchvision.models provides dozens of pre-trained architectures ready to download and use.
import torchvision.models as models
# List some available pre-trained models
print(dir(models)) # Shows resnet50, efficientnet_b0, vit_b_16, etc.
# Loading weights pre-trained on ImageNet-1k
resnet = models.resnet50(weights=models.ResNet50_Weights.IMAGENET1K_V1)
print('ResNet-50 loaded, parameters:', sum(p.numel() for p in resnet.parameters()))ResNet-50: Architecture Overview
ResNet-50 (Residual Network with 50 layers) introduced skip connections that add the input of a block directly to its output: output = F(x) + x. This allows gradients to flow directly through the addition, enabling training of very deep networks without vanishing gradients.
ResNet-50 has approximately 25 million parameters and consists of: one initial 7×7 convolutional layer, max pooling, four residual blocks (layer1–layer4), and a global average pooling layer followed by a 1000-class fully connected head for ImageNet classification. The final fc layer is what we replace for custom tasks.
import torchvision.models as models
import torch
resnet = models.resnet50(weights=models.ResNet50_Weights.IMAGENET1K_V1)
print(resnet) # Prints the full architecture
# Key layers
print('Final FC layer:', resnet.fc) # Linear(2048, 1000)
print('Layer4 output channels:', 2048) # Feature dimension before FCRunning Inference with ResNet-50
Before running inference, inputs must match the preprocessing used during ImageNet training: resize to at least 224×224, normalise with ImageNet mean and standard deviation. The torchvision.transforms API handles this. Always call model.eval() before inference to disable dropout and batch normalisation training mode.
The model outputs 1000 logits, one per ImageNet class. We apply softmax to get probabilities and pick the top-k classes. torchvision.models now includes category names in the weights metadata, eliminating the need for a separate labels file.
import torch
from torchvision import transforms
from PIL import Image
import torchvision.models as models
weights = models.ResNet50_Weights.IMAGENET1K_V1
resnet = models.resnet50(weights=weights)
resnet.eval()
# Preprocessing transforms from the weights metadata
preprocess = weights.transforms()
# Load and preprocess an image
img = Image.open('cat.jpg')
tensor = preprocess(img).unsqueeze(0) # Add batch dimension
with torch.no_grad():
logits = resnet(tensor)
probs = torch.softmax(logits, dim=1)
top5 = torch.topk(probs, 5)
print('Top-5 probabilities:', top5.values)EfficientNet: Compound Scaling
EfficientNet (2019) introduced compound scaling: systematically scaling network width, depth, and input resolution together using a single compound coefficient. Instead of arbitrarily making networks wider or deeper, EfficientNet balances all three dimensions for optimal accuracy-efficiency trade-offs.
The EfficientNet family ranges from efficientnet_b0 (5M parameters) to efficientnet_b7 (66M parameters). EfficientNet-B0 achieves comparable accuracy to ResNet-50 while using 8× fewer parameters and 6× fewer FLOPs, making it ideal for mobile and edge deployment. PyTorch provides all eight variants.
import torchvision.models as models
import torch
# EfficientNet-B0: lightweight but accurate
eff_b0 = models.efficientnet_b0(weights=models.EfficientNet_B0_Weights.IMAGENET1K_V1)
print('EfficientNet-B0 params:', sum(p.numel() for p in eff_b0.parameters()))
print('EfficientNet-B0 classifier:', eff_b0.classifier)
# Compare with ResNet-50
resnet50 = models.resnet50(weights=None) # No weights to count params only
print('ResNet-50 params:', sum(p.numel() for p in resnet50.parameters()))Vision Transformer (ViT): Attention Without Convolutions
Vision Transformers (ViT) (2020) apply the transformer architecture directly to images, without any convolution. The image is split into a grid of fixed-size patches (e.g., 16×16 pixels), each flattened and projected to an embedding vector. These patch embeddings are treated like word tokens in NLP.
A CLS (classification) token is prepended to the patch sequence. After passing through multiple transformer encoder blocks with self-attention, the CLS token's output is used for classification. ViT requires large training datasets to outperform CNNs, but pre-trained ViT models from torchvision bring this power to your tasks immediately.
import torchvision.models as models
import torch
# ViT-B/16: Base model with 16x16 patches
vit = models.vit_b_16(weights=models.ViT_B_16_Weights.IMAGENET1K_V1)
print('ViT-B/16 params:', sum(p.numel() for p in vit.parameters()))
print('ViT patch size: 16x16 pixels')
print('ViT sequence length for 224x224 image:', (224 // 16) ** 2 + 1, '(196 patches + 1 CLS token)')
print('ViT head:', vit.heads) # Linear(768, 1000)Comparing ResNet, EfficientNet, and ViT
Choosing among these architectures depends on your constraints and task. ResNet-50 is the reliable default: well understood, strong baseline, many tutorials and implementations. EfficientNet-B0/B2 wins when inference speed and model size matter — mobile apps, real-time systems, or edge hardware.
ViT excels on large-scale tasks and benefits from self-supervised pre-training (DINO, CLIP). It requires more compute and memory than CNNs of similar accuracy. For most custom image classification tasks with moderate-sized datasets, start with EfficientNet-B2 or ResNet-50, then try ViT if you have the resources to fine-tune it.
# Rough comparison on ImageNet top-1 accuracy
comparison = {
'ResNet-50': {'params': '25M', 'top1': '76.1%', 'year': 2015},
'EfficientNet-B0': {'params': '5M', 'top1': '77.7%', 'year': 2019},
'EfficientNet-B4': {'params': '19M', 'top1': '83.4%', 'year': 2019},
'ViT-B/16': {'params': '86M', 'top1': '81.1%', 'year': 2020},
'ViT-L/16': {'params': '307M','top1': '85.1%', 'year': 2020},
}
for name, info in comparison.items():
print(f'{name}: {info["params"]} params, {info["top1"]} top-1')Inspecting Model Internals
Before modifying a pre-trained model for your task, inspect its architecture to understand which layers to replace. Use print(model) to see the layer tree, and named_modules() or named_children() to iterate programmatically.
The key insight: every torchvision model ends with a classification head sized for 1000 ImageNet classes. To adapt the model to your task with num_classes different from 1000, you replace this final layer. The feature extractor (everything before the head) retains ImageNet-learned features.
import torchvision.models as models
resnet = models.resnet50(weights=models.ResNet50_Weights.IMAGENET1K_V1)
# Find the names of top-level children
for name, module in resnet.named_children():
print(name, '->', type(module).__name__)
# Output:
# conv1 -> Conv2d
# bn1 -> BatchNorm2d
# relu -> ReLU
# maxpool -> MaxPool2d
# layer1 -> Sequential (Residual blocks)
# layer2 -> Sequential
# layer3 -> Sequential
# layer4 -> Sequential
# avgpool -> AdaptiveAvgPool2d
# fc -> Linear <-- This is what we replaceFeature Vector Size for Each Architecture
When you replace the classification head, you need to know the feature dimension output by the backbone (everything except the final layer). This dimension is the input size of your new classification head.
Common backbone output dimensions: ResNet-50 outputs 2048, EfficientNet-B0 outputs 1280, and ViT-B/16 outputs 768. These feature vectors are computed by global average pooling over the spatial feature maps, producing a single vector per image. Your replacement head takes this vector as input.
import torch
import torchvision.models as models
# Feature dimensions before the classification head
feature_dims = {
'resnet50': 2048,
'efficientnet_b0': 1280,
'efficientnet_b2': 1408,
'efficientnet_b4': 1792,
'vit_b_16': 768,
'vit_l_16': 1024,
}
# Verify for ResNet-50 by running a dummy forward pass without the head
resnet = models.resnet50(weights=None)
resnet.fc = torch.nn.Identity() # Remove FC layer
x = torch.randn(1, 3, 224, 224)
features = resnet(x)
print('ResNet-50 feature size:', features.shape) # (1, 2048)Checking Pre-trained Weight Quality
You can quickly verify that a pre-trained model's weights are correct by running it on a well-known test image and checking whether the top prediction matches the expected label. This sanity check ensures the weights loaded correctly and the preprocessing pipeline is correct.
Beyond this test, it is good practice to always check the expected input format from the weights metadata: input size (224×224 for most models), channel order (RGB, not BGR), and normalisation constants (ImageNet mean and std). Using wrong normalisation is a common bug that causes poor transfer learning results.
import torchvision.models as models
weights = models.ResNet50_Weights.IMAGENET1K_V1
print('Expected input size:', weights.meta['min_size']) # (1, 1)
print('Transforms:', weights.transforms())
# Includes Resize(232), CenterCrop(224), Normalize(mean, std)
# ImageNet normalisation constants
IMAGENET_MEAN = [0.485, 0.456, 0.406]
IMAGENET_STD = [0.229, 0.224, 0.225]
# Always use these EXACT values with ImageNet pre-trained modelsPreparing for Fine-Tuning Your Own Task
The typical workflow for using pre-trained models on custom tasks is: (1) load the pre-trained model with weights=...IMAGENET1K..., (2) replace the final classification head with a new nn.Linear sized for your number of classes, (3) optionally freeze the backbone weights initially, and (4) train using a lower learning rate than you would use from scratch.
The new classification head starts with random weights and needs to learn from your data. The backbone starts with excellent features and needs only minor adjustments. This is why differential learning rates — a very low rate for the backbone and a higher rate for the head — often improve convergence speed and final accuracy.
import torchvision.models as models
import torch.nn as nn
# Example: Adapt ResNet-50 for 5-class flower classification
model = models.resnet50(weights=models.ResNet50_Weights.IMAGENET1K_V1)
# Replace the final FC layer
num_classes = 5
model.fc = nn.Linear(model.fc.in_features, num_classes)
# Differential learning rates
optimizer = torch.optim.Adam([
{'params': model.fc.parameters(), 'lr': 1e-3}, # High LR for new head
{'params': [p for n, p in model.named_parameters() if 'fc' not in n], 'lr': 1e-5} # Low LR for backbone
])Quick Check
Test your understanding of pre-trained torchvision models from this lesson.
Lesson Recap
In this lesson you learned: ResNet-50 uses skip connections to train very deep networks and outputs 2048-dimensional features, EfficientNet achieves better accuracy-efficiency trade-offs through compound scaling of width, depth, and resolution, and ViT applies transformer self-attention to image patches without convolutions. Next up we learn feature extraction — freezing the pre-trained backbone and training only a new classification head on your custom dataset.
Frequently asked questions
Is the “Pre-trained Models in torchvision: ResNet, EfficientNet, and ViT” lesson free?
Yes — the full text of “Pre-trained Models in torchvision: ResNet, EfficientNet, and ViT” is free to read here on the web, and the Machine Learning Academy course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the Machine Learning Academy course, upgrade to CoddyKit PRO.
What will I learn in “Pre-trained Models in torchvision: ResNet, EfficientNet, and ViT”?
Learners will load a ResNet-50 pre-trained on ImageNet, inspect its architecture, and make an inference on a new image to verify the pre-learned representations. You practise Machine Learning Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.
Do I need any experience to start Machine Learning Academy?
No prior experience is required. Machine Learning Academy on CoddyKit is structured for beginners through advanced learners; this is — lesson 1 of 4, so you can start here or from the beginning and move at your own pace.
How long does the “Pre-trained Models in torchvision: ResNet, EfficientNet, and ViT” lesson take?
Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.
Can I write and run code in this Machine Learning Academy lesson?
Yes. Every Machine Learning Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.
All lessons in this course
- Pre-trained Models in torchvision: ResNet, EfficientNet, and ViT
- Feature Extraction: Freezing the Backbone
- Fine-Tuning: Unfreezing and Low Learning Rates
- Domain Adaptation: Medical Imaging with Scarce Labels