Transfer learning in computer vision typically employs convolutional neural networks pre-trained on massive datasets such as ImageNet, which contains 1.2 million annotated images spanning 1,000 object categories. These pre-trained models capture hierarchical visuall representations transferable to specialized downstream tasks.
Two fundamental approaches govern transfer learning workflows:
Feature Extraction: Treat the pre-trained convolutional backbone as a static feature extractor by excising the final fully-connected classification layer. The network generates dense feature embeddings that feed into a freshly initialized classifier trained exclusively on the target dataset parameters.
Fine-Tuning: Extend beyond feature extraction by enabling gradient flow through the pre-trained architecture via backpropagation. Practitioners often implement selective freezing—preserving early-layer weights (encoding universal patterns like edges and color blobs) while updating deeper layers to accommodate domain-specific visual semantics.
Stratgey selection depends on dataset volume and domain divergence:
| Target Dataset Size | Domain Similarity | Optimization Strategy |
|---|---|---|
| Limited samples | High resemblance | Linear classifier on frozen convolutional features |
| Extensive samples | High resemblance | End-to-end network fine-tuning |
| Limited samples | Low resemblance | Classifier trained on intermediate layer activations (e.g., SVM) |
| Extensive samples | Low resemblance | Comprehensive fine-tuning with augmented regularization |
Binary Classification Implementation
The following demonstration addresses wolf versus dog classification using the Canidae subset derived from ImageNet, comprising 120 training images and 30 validation images per category.
BATCH_SIZE = 16
INPUT_DIM = 224
MAX_EPOCHS = 5
LR = 0.001
MOMENTUM = 0.9
NUM_WORKERS = 4
IMAGENET_MEAN = [0.485 * 255, 0.456 * 255, 0.406 * 255]
IMAGENET_STD = [0.229 * 255, 0.224 * 255, 0.225 * 255]
Data Loading and Augmentation Pipeline
import mindspore.dataset as ds
import mindspore.dataset.vision as vision
def build_dataloader(data_root, phase='train'):
data_source = ds.ImageFolderDataset(
data_root,
num_parallel_workers=NUM_WORKERS,
shuffle=(phase == 'train')
)
if phase == 'train':
augmentations = [
vision.RandomCropDecodeResize(INPUT_DIM, scale=(0.08, 1.0), ratio=(0.75, 1.333)),
vision.RandomHorizontalFlip(probability=0.5),
vision.Normalize(mean=IMAGENET_MEAN, std=IMAGENET_STD),
vision.HWC2CHW()
]
else:
augmentations = [
vision.Decode(),
vision.Resize(INPUT_DIM + 32),
vision.CenterCrop(INPUT_DIM),
vision.Normalize(mean=IMAGENET_MEAN, std=IMAGENET_STD),
vision.HWC2CHW()
]
data_source = data_source.map(
operations=augmentations,
input_columns='image',
num_parallel_workers=NUM_WORKERS
)
return data_source.batch(BATCH_SIZE, drop_remainder=True)
train_loader = build_dataloader(train_path, 'train')
val_loader = build_dataloader(val_path, 'val')
Residual Block Architecture
import mindspore.nn as nn
from mindspore import dtype as mstype
from typing import Optional, TypeVar
T = TypeVar('T', bound=nn.Cell)
class BasicResidualBlock(nn.Cell):
expansion: int = 1
def __init__(self, input_ch: int, output_ch: int,
stride: int = 1, norm_layer: Optional[T] = None,
downsample: Optional[T] = None) -> None:
super(BasicResidualBlock, self).__init__()
self.normalization = norm_layer if norm_layer else nn.BatchNorm2d(output_ch)
self.downsample_layer = downsample
self.conv_3x3_1 = nn.Conv2d(
input_ch, output_ch, kernel_size=3,
stride=stride, padding=1, pad_mode='pad',
weight_init='he_uniform'
)
self.conv_3x3_2 = nn.Conv2d(
output_ch, output_ch, kernel_size=3,
stride=1, padding=1, pad_mode='pad',
weight_init='he_uniform'
)
self.activation = nn.ReLU()
def construct(self, input_tensor):
residual = input_tensor if self.downsample_layer is None else self.downsample_layer(input_tensor)
x = self.conv_3x3_1(input_tensor)
x = self.normalization(x)
x = self.activation(x)
x = self.conv_3x3_2(x)
x = self.normalization(x)
x = x + residual
return self.activation(x)