Testing ResNets
Having undertstood the very core of residual learning and implemented the very essentials of ResNet, let's play around with dummy inputs and actual image inputs as we close the course in this section, for what it's worth. Getting to play around with a random input to the models implemented, we should get an output of 1000, since the original ResNets were built with classifying ImageNet datasets in mind.
# recommended to use .eval and torch.no_grad in actual inference
in_ = torch.randn(1, 3, 224, 224)
out_ = resnet18(in_)
print(out_.shape)
out_ = resnet34(in_)
print(out_.shape)
out_ = resnet50(in_)
print(out_.shape)
out_ = resnet101(in_)
print(out_.shape)
out_ = resnet152(in_)
print(out_.shape)
            torch.Size([1, 1000])
torch.Size([1, 1000])
torch.Size([1, 1000])
torch.Size([1, 1000])
torch.Size([1, 1000])
          
Pre-trained variants
Most of the common well known pioneering papers have their pretrained models hosted within PyTorch's pipeline for training and inferenece. Hence, the above variants of ResNets can also be loaded with or without their pretrained weights.
# clear memory 
del resnet18, resnet34, resnet50, resnet101, resnet152
# import required modules
from torchvision.models import (
    resnet18, resnet34, resnet50, resnet101, resnet152,
    ResNet18_Weights, ResNet34_Weights, ResNet50_Weights,
    ResNet101_Weights, ResNet152_Weights
)
# LOADING PRE-TRAINED VERSIONS
tiny_resnet = resnet18(weights=ResNet18_Weights.DEFAULT)
small_resnet = resnet34(weights=ResNet34_Weights.DEFAULT)
regular_resnet = resnet50(weights=ResNet50_Weights.DEFAULT)
large_resnet = resnet101(weights=ResNet101_Weights.DEFAULT)
very_large_resnet = resnet152(weights=ResNet152_Weights.DEFAULT)
# testing a dummy input
in_ = torch.randn(1, 3, 224, 224)
def inference(model, x):
    model.eval()
    with torch.no_grad():
        out = model(x)
        print(out.shape)
inference(tiny_resnet, in_)
inference(small_resnet, in_)
inference(regular_resnet, in_)
inference(large_resnet, in_)
inference(very_large_resnet, in_)
            torch.Size([1, 1000])
torch.Size([1, 1000])
torch.Size([1, 1000])
torch.Size([1, 1000])
torch.Size([1, 1000])
          
Testing the downloaded models with a test image of a cat from huggingface datasets, this is the programmatic implementation
from torchvision.transforms.v2 import (
    ToTensor, Compose, Lambda, Resize, CenterCrop, Normalize
)
import os 
os.system("pip install -q datasets") # huggingface datasets
from datasets import load_dataset

compose = Compose([
        Resize(256), CenterCrop(224), ToTensor(),
        Normalize(mean=(0.485, 0.456, 0.406),
        std=(0.229, 0.224, 0.225))])

def load_image():
    dataset = load_dataset("huggingface/cats-image")
    image = dataset["test"]["image"][0]
    return image

def preprocess_input(x, transforms):
    x = transforms(x) # HWC to preprocessed CHW 
    x = torch.unsqueeze(x, 0) # CHW to BCHW
    return x 

def inference(model, x):
    model.eval()
    with torch.no_grad():
        out = model(x)[0]
        max_i = torch.argmax(out)
        print(f"Predicted: {max_i}")

image = load_image()
image = preprocess_input(image, compose)
print(f"{image.shape = }")
inference(tiny_resnet, image)
inference(small_resnet, image)
inference(regular_resnet, image)
inference(large_resnet, image)
inference(very_large_resnet, image)
            image.shape = torch.Size([1, 3, 224, 224])
Predicted: 281
Predicted: 281
Predicted: 281
Predicted: 281
Predicted: 281
          
The above predicted class, as can be seen from theImageNet classes, maps to the tabby, tabby cat, which is correct.
Resnets paved the way for serving as backbones to many computer vision models in real world applications, serving as the backbone to famous models like YOLO, an object detector model, a single-stage pipeline of object detection that transformed the domain as we see today. Despite implementation of new architectures and hence models for ViT, Vision Transformers, ResNets still have a much bigger impact compared to such. This course has led us to where we are now and with that, we can say the objective has been met. Understanding all the way to implementing the residual network variants has been a pleasure! This is just but the beginning to the scale of building deep learning models and pipelines.
And with gladness, I now conclude this course!