1 Transfer learning β borrowing a trained brain
Imagine someone spent ten years learning to draw β they got really good at hands, faces, light, and shadow. Now you want to learn to draw cartoon cats. Do you start from scratch with a crayon? No! You ask that expert to teach you, and because they already know edges, curves, and shapes, you only need to show them a few cats and they pick it up fast. Transfer learning is exactly this: take a model that already learned to "see," and teach it your new thing with just a little practice.
In Session 10 we saw that training a deep CNN like ResNet on a giant dataset takes enormous data and compute. Transfer learning is the trick of reusing a model that was already pre-trained on a big dataset and adapting it to your own, usually much smaller, task.
The standard pre-training dataset: ImageNet
The most common starting point is a model pre-trained on ImageNet β a dataset of about 1.2 million labelled images across 1,000 categories (dogs, cars, mushrooms, guitarsβ¦). A model that has learned to tell those 1,000 classes apart has, as a side effect, learned to recognise an enormous vocabulary of visual patterns. We reuse that.
Why early features are general
Recall from Session 10 that a CNN learns features in layers, and they get more abstract the deeper you go. This is the key insight that makes transfer learning work:
| Layer depth | What it learns | How task-specific? |
|---|---|---|
| Early layers | Edges, colours, simple textures, gradients. | Very general β every image task needs these. An edge is an edge whether it's a cat or an X-ray. |
| Middle layers | Corners, blobs, repeating patterns, simple parts (an eye, a wheel). | Fairly general β reusable across many tasks. |
| Late layers | Whole-object concepts ("this looks like a dog's face"). | Very specific to the original task's classes. |
The early layers of any vision model learn the same generic building blocks β edges and textures. Those are exactly what your new task needs too. So instead of relearning "what is an edge" from scratch, you keep the borrowed early layers and only retrain the task-specific end.
This isn't just hand-waving β Yosinski et al. (2014) measured it directly, showing that features in the first layers transfer almost perfectly between tasks, while the last layers are specialised and transfer poorly. The deeper you go, the less general the features.
Two flavours: feature extraction vs fine-tuning
There are two main ways to do transfer learning, differing in how much of the borrowed model you let change.
| Feature extraction | Fine-tuning | |
|---|---|---|
| Idea | Freeze the pre-trained layers; use them as a fixed "feature factory." Train only a new head. | Start from pre-trained weights, but let some (or all) of them keep learning on your data. |
| What's trainable | Only the new final classifier layer(s). | The new head plus some upper layers of the backbone. |
| Best when | Small dataset, or your task is similar to ImageNet. | Larger dataset, or your task differs a lot from ImageNet. |
| Speed / risk | Fast, little risk of overfitting. | Slower; can overfit on tiny datasets, so use a small learning rate. |
We call the borrowed network (minus its final classifier) the backbone or feature extractor. The small new piece you bolt on for your task is the head. Transfer learning = keep the backbone, replace the head.
A simple recipe for choosing
Say you want to classify 5 kinds of flowers with only ~2,000 photos. Far too few to train a deep CNN from scratch. Here's the standard PyTorch pattern using a ResNet-18 pre-trained on ImageNet. The whole trick is in two lines: freeze the backbone, then replace the final layer so it outputs 5 classes instead of 1,000.
import torch import torch.nn as nn from torchvision import models # 1. Load a model pre-trained on ImageNet model = models.resnet18(weights=models.ResNet18_Weights.DEFAULT) # 2. FEATURE EXTRACTION: freeze every borrowed parameter for param in model.parameters(): param.requires_grad = False # 3. Replace the head. resnet18's classifier is `model.fc`, # a Linear(512 -> 1000). Swap in a fresh Linear(512 -> 5). # New layers default to requires_grad=True, so ONLY these train. num_features = model.fc.in_features # 512 model.fc = nn.Linear(num_features, 5) # 5 flower classes # 4. Only the new head's params reach the optimizer optimizer = torch.optim.Adam(model.fc.parameters(), lr=1e-3) criterion = nn.CrossEntropyLoss() # 5. Train as usual β but it's fast: few params, few epochs. for images, labels in train_loader: optimizer.zero_grad() loss = criterion(model(images), labels) loss.backward() optimizer.step()
To switch from feature extraction to fine-tuning, you'd simply set
requires_grad = True on the top layers too and pass their parameters to
the optimizer with a small learning rate (e.g. 1e-5), so the precious
pre-trained weights only nudge gently rather than getting wrecked.
1. Match the preprocessing. A pretrained model expects inputs normalised exactly how it was trained (ImageNet's mean/std, a specific input size like 224Γ224). Feed it raw differently scaled images and accuracy tanks. 2. Don't fine-tune with a big learning rate β you'll blow away the very knowledge you borrowed. Always go gentle when unfreezing.
model.fc with a fresh
layer sized to your number of classes.
2 Object detection β not just "what," but "where"
Classification is like asking "Is there a dog in this photo?" and getting a yes/no. Object detection is like handing a friend a highlighter and saying "draw a box around every dog, every cat, and every person, and label each box." Now you don't just know what's in the picture β you know where each thing is and how many there are.
So far our CNNs answered "which single class is this image?" Object detection goes further: it finds multiple objects in one image and, for each, predicts both a class label and a bounding box β a rectangle (x, y, width, height) that frames the object.
Two families of detectors
Almost every detector falls into one of two camps, trading accuracy vs speed.
| Two-stage (R-CNN family) | One-stage (YOLO, SSD) | |
|---|---|---|
| How it works | Stage 1: propose regions that might hold an object. Stage 2: classify + refine each box. | Look once: a single network predicts all boxes and classes directly across a grid. |
| Members | R-CNN β Fast R-CNN β Faster R-CNN. | YOLO ("You Only Look Once"), SSD ("Single Shot Detector"). |
| Speed | Slower β two passes. | Fast β real-time (great for video, robots, self-driving). |
| Accuracy | Historically a bit higher, especially small objects. | Very competitive now, and far faster. |
R-CNN ran a CNN on ~2,000 cropped region proposals β accurate but painfully slow. Fast R-CNN ran the CNN once over the whole image and shared the features. Faster R-CNN added a learned Region Proposal Network so even the "where to look" step became a neural net. Each step made it faster.
YOLO divides the image into a grid. Each grid cell predicts a few boxes, the class in them, and a confidence score β all in one forward pass. That's why it's fast enough to run on live video. It's the go-to when latency matters.
How do we measure "is this box correct?" β IoU
A predicted box is rarely pixel-perfect. IoU (Intersection over Union) measures overlap between the predicted box and the true box:
IoU = area(overlap) / area(union)
- IoU = 1.0 β perfect overlap (boxes identical).
- IoU = 0 β no overlap at all.
- A common rule: a detection "counts as correct" if its IoU with a true box is β₯ 0.5.
Say the true box is the square from (0,0) to (10,10) β area 100. The predicted box is (5,0) to (15,10) β also area 100. They overlap in the strip (5,0)β(10,10), area = 5Γ10 = 50.
Union = 100 + 100 β 50 = 150. So IoU = 50 / 150 β 0.33 β below 0.5, so this prediction would not count as a correct detection.
def iou(boxA, boxB): # boxes as (x1, y1, x2, y2) # intersection rectangle xi1, yi1 = max(boxA[0], boxB[0]), max(boxA[1], boxB[1]) xi2, yi2 = min(boxA[2], boxB[2]), min(boxA[3], boxB[3]) inter = max(0, xi2 - xi1) * max(0, yi2 - yi1) areaA = (boxA[2]-boxA[0]) * (boxA[3]-boxA[1]) areaB = (boxB[2]-boxB[0]) * (boxB[3]-boxB[1]) return inter / (areaA + areaB - inter) # overlap / union
Scoring a whole detector β mAP
To grade a detector across a whole dataset we use mAP (mean Average Precision). At a high level: for each class you plot how precise (few false boxes) and how complete (found all objects) the detector is, summarise that curve into one number called Average Precision, then average it across all classes. Higher mAP = better detector. You'll see scores like "mAP@0.5" meaning "AP computed using the IoU β₯ 0.5 rule."
Detectors often fire several overlapping boxes on the same object. A step called Non-Maximum Suppression (NMS) keeps the highest-confidence box and deletes its near-duplicates (those with high IoU to it). Without NMS you'd "detect" the same dog five times.
3 Segmentation β labelling every single pixel
A bounding box is a rough rectangle around an object β it includes a lot of background in the corners. Segmentation is like giving the picture to a careful kid with coloured crayons and saying "colour every road pixel grey, every car pixel blue, every tree pixel green." No rectangles β you trace the exact shape of everything. That's pixel-level labelling.
Detection gives you boxes; segmentation goes finer and assigns a label to every pixel. There are two important kinds:
| Type | What it does | Three dogs in a photo β |
|---|---|---|
| Semantic segmentation | Labels each pixel by class. All dogs are just "dog." | One big "dog" coloured region (they're not told apart). |
| Instance segmentation | Labels each pixel and separates individual objects. | Three separately coloured dogs: dog-1, dog-2, dog-3. |
The encoderβdecoder shape (and U-Net)
Classification CNNs keep shrinking the image down to a tiny feature map, then output one label. But segmentation needs an output that's the same size as the input (one label per pixel). So we use an encoderβdecoder architecture: first squeeze the image down to learn what's there, then expand it back up to recover where exactly.
The classic example is U-Net (Ronneberger et al., 2015), born in medical imaging. Drawn out, it makes a U shape: the encoder going down the left, the decoder climbing the right. Its signature trick is skip connections that hand the sharp, high-resolution details from each encoder level straight across to the matching decoder level β so fine edges aren't lost during the squeeze.
input
β βββββββββββββββββ skip ββββββββββββββββ
βΌ β βΌ
[enc1] ββββββββββββ skip βββββββββββββββΊ [dec1] ββΊ output map
β βββββββββ skip βββββββββ β²
βΌ β βΌ β
[enc2] ββββ skip βββββΊ [dec2]ββββββββββββββββ
β β²
βΌ β
[enc3] βββββββββββββββΊ [dec3]
β β²
βββββ bottleneck βββββββ
(encoder down) (decoder up)
the "U" shape
The decoder has to grow a small feature map back to full resolution. It does this with operations like transposed convolution (sometimes loosely called "deconvolution") or simple interpolation followed by a normal conv. Think of it as the reverse of the pooling that shrank the image on the way down.
Instance segmentation: Mask R-CNN
For instance segmentation, the most famous model is Mask R-CNN (He et al., 2017). The idea is beautifully simple: take Faster R-CNN (the two-stage detector from Topic 2) and add a third output branch that, for each detected box, predicts a small binary mask β a per-pixel "object / not object" map inside that box.
torchvision ships a Mask R-CNN pre-trained on the COCO dataset. With transfer learning (Topic 1!) you load it and run instance segmentation in a few lines:
import torch from torchvision.models.detection import maskrcnn_resnet50_fpn # Pretrained on COCO (80 everyday object classes) model = maskrcnn_resnet50_fpn(weights="DEFAULT") model.eval() # inference mode with torch.no_grad(): out = model([image_tensor])[0] # one image in, dict out # out["boxes"] -> bounding boxes (N, 4) # out["labels"] -> class id per object # out["scores"] -> confidence per object # out["masks"] -> per-pixel masks (N, 1, H, W) keep = out["scores"] > 0.7 # keep confident detections
Notice the output bundles boxes + labels + masks together β that's detection and segmentation in one model. To adapt it to your own classes, you'd replace its box and mask heads (exactly the transfer-learning move from Topic 1) and fine-tune.
4 A tour of other computer-vision applications
Once a machine can "see" β finding edges, shapes, and objects β you can point that skill at almost anything. Unlock your phone with your face, let a game read your dance moves, help a doctor spot something on an X-ray, or even ask a computer to paint a picture that never existed. Same CNN superpowers, aimed at different jobs.
The same convolutional machinery β often via transfer learning from a big pretrained backbone β powers a huge range of real applications. Here's a quick guided tour of four major areas.
Face recognition
The trick here isn't to classify "which of 1,000 fixed people is this" β you can't retrain every time a new person joins. Instead, a CNN turns each face into an embedding: a vector of numbers where the same person's faces sit close together and different people sit far apart (recall embeddings give similar things similar codes). Recognition then becomes "is this new face's vector close to a stored one?"
Phone face-unlock stores one embedding of your face at setup. Each unlock attempt is embedded and compared by distance β close enough β unlock. Models like FaceNet are trained with a triplet loss that explicitly pulls same-person faces together and pushes different-person faces apart.
Pose estimation
Pose estimation locates a person's keypoints β joints like elbows, knees, wrists, and shoulders β and connects them into a stick-figure skeleton. The model predicts a heatmap for each joint (where is it most likely?), then links them up.
This powers fitness apps that count your squats, motion capture in films, sign-language reading, and gesture controls. OpenPose and the keypoint variant of Mask R-CNN are well-known examples.
Medical imaging
CNNs (and U-Net especially, from Topic 3) read X-rays, CT and MRI scans, and microscope slides β detecting tumours, segmenting organs, or flagging fractures. The encoderβdecoder shape is ideal because doctors often need the exact outline of a region, not just a box.
Medical data is scarce and privacy-sensitive, so transfer learning is essential β you rarely have millions of labelled scans. And mistakes carry real-world cost, so these models assist clinicians rather than replace them, and demand careful validation.
Generative vision
Generative models don't classify images β they create them. Two families dominate: GANs (Generative Adversarial Networks), where a "generator" tries to fool a "discriminator" that judges real vs fake, and diffusion models, which learn to turn random noise into an image step by step (the engine behind tools like Stable Diffusion).
Text-to-image tools ("a cat astronaut, oil painting"), photo super-resolution, removing objects from photos, and style transfer are all generative vision. We won't go deep here β generative models get their own treatment later β but know they share the same convolutional roots.
Every application above reuses the same idea: a CNN backbone that has learned to see, adapted with a task-specific head β classification, boxes, masks, keypoints, embeddings, or pixel generation. Master the backbone-plus-head pattern and the whole field opens up.
β Putting it all together
This session was about using the CNNs you built in Session 10 β not training from scratch, and not just classifying. Here's the one-paragraph story connecting all four topics:
Because a CNN's early layers learn general features (edges, textures) and only its late layers are task-specific, you can transfer-learn: take a model pre-trained on ImageNet, keep the backbone, and swap in a new head β freezing for feature extraction or gently unfreezing for fine-tuning. That same backbone-plus-head recipe scales up: bolt on a detection head and you get object detection (two-stage R-CNN vs one-stage YOLO/SSD), scored with IoU and mAP; bolt on an encoderβdecoder (U-Net) and you get pixel-level segmentation; add a mask branch (Mask R-CNN) and you separate every instance. Point that "see-then-head" machinery anywhere and you get face recognition, pose estimation, medical imaging, and generative vision. Next session we leave images behind and learn to model sequences with RNNs.
Quick self-check
Why do the early layers of a CNN transfer well to a new task?
Because they learn generic, low-level features β edges, colours, simple textures β that almost every vision task needs. Only the late layers are specialised to the original task's classes.
What's the difference between feature extraction and fine-tuning?
Feature extraction freezes the pretrained backbone and trains only a new head. Fine-tuning also lets some/all backbone layers keep learning (at a small learning rate). Use extraction for small or similar datasets; fine-tuning for larger or more different ones.
In transfer learning code, why do we replace model.fc?
The pretrained final layer outputs the original 1,000 ImageNet classes. We swap it for a fresh Linear layer sized to our number of classes, and (for feature extraction) it's the only part that trains.
One-stage vs two-stage detectors β which is faster and why?
One-stage (YOLO, SSD) is faster because it predicts all boxes and classes in a single forward pass. Two-stage (R-CNN family) first proposes regions, then classifies them β two passes, slower but historically a touch more accurate.
What does IoU measure, and what's a typical "correct" threshold?
IoU = area of overlap Γ· area of union between a predicted and true box. It ranges 0 (no overlap) to 1 (perfect). A detection is commonly counted correct at IoU β₯ 0.5.
Semantic vs instance segmentation β three dogs in one photo?
Semantic segmentation paints all three as one "dog" region. Instance segmentation separates them into dog-1, dog-2, dog-3. Mask R-CNN does the instance version.
Why does U-Net use skip connections?
The encoder loses fine spatial detail as it downsamples. Skip connections pass the high-resolution features straight from each encoder level to the matching decoder level, so sharp edges and precise locations are recovered in the output.
π References & Further Reading
Class material
- SST Deep Learning handout (Session 11) β your course handout for this session.
Papers, docs & deep dives
- SST Deep Learning handout (online) β the companion notes for this course, covering transfer learning and CNN applications.
- Yosinski et al. β "How transferable are features in deep neural networks?" β the paper that measured exactly why early layers transfer and late layers don't.
- PyTorch transfer learning tutorial β hands-on official walkthrough of feature extraction and fine-tuning, mirroring the code in Topic 1.
- Redmon et al. β "You Only Look Once" (YOLO) β the original one-stage, real-time object detection paper.
- Ronneberger et al. β "U-Net" β the encoderβdecoder with skip connections that defined modern segmentation.
- He et al. β "Mask R-CNN" β adds a per-object mask branch to Faster R-CNN for instance segmentation.