import torch
import torch.nn as nn
from torch.nn import functional as F
import sys
sys.path.append('/home/jovyan/work/d2l_solutions/notebooks/exercises/d2l_utils/')
import d2l
from torchsummary import summary
class AnyNet(d2l.Classifier):
def stem(self, num_channels):
return nn.Sequential(
nn.LazyConv2d(num_channels, kernel_size=3, stride=2, padding=1),
nn.LazyBatchNorm2d(), nn.ReLU())
def stage(self, depth, num_channels, groups, bot_mul):
blk = []
for i in range(depth):
if i == 0:
blk.append(d2l.ResNeXtBlock(num_channels, groups, bot_mul,
use_1x1conv=True, strides=2))
else:
blk.append(d2l.ResNeXtBlock(num_channels, groups, bot_mul))
return nn.Sequential(*blk)
def __init__(self, arch, stem_channels, lr=0.1, num_classes=10):
super(AnyNet, self).__init__()
self.save_hyperparameters()
self.net = nn.Sequential(self.stem(stem_channels))
for i, s in enumerate(arch):
self.net.add_module(f'stage{i+1}', self.stage(*s))
self.net.add_module('head', nn.Sequential(
nn.AdaptiveAvgPool2d((1, 1)), nn.Flatten(),
nn.LazyLinear(num_classes)))
self.net.apply(d2l.init_cnn)
class RegNetX32(AnyNet):
def __init__(self, lr=0.1, num_classes=10):
stem_channels, groups, bot_mul = 32, 16, 1
depths, channels = (4, 6, 8, 16), (32, 80, 128, 256)
super().__init__(
# ((depths[0], channels[0], groups, bot_mul),
# (depths[1], channels[1], groups, bot_mul)),
[(depths[i], channels[i], groups, bot_mul) for i in range(len(depths))],
stem_channels, lr, num_classes)
model = RegNetX32(lr=0.05)
# summary(model,(1,224,224))
trainer = d2l.Trainer(max_epochs=10, num_gpus=1)
data = d2l.FashionMNIST(batch_size=128, resize=(224, 224))
trainer.fit(model, data)
class DeAnyNet(d2l.Classifier):
def stem(self, num_channels):
return nn.Sequential(
nn.LazyConv2d(num_channels, kernel_size=3, stride=2, padding=1),
nn.LazyBatchNorm2d(), nn.ReLU())
def stage(self, depth, num_channels):
blk = []
for i in range(depth):
if i == 0:
blk.append(d2l.Residual(num_channels, use_1x1conv=True, strides=2))
else:
blk.append(d2l.Residual(num_channels))
return nn.Sequential(*blk)
def __init__(self, arch, stem_channels, lr=0.1, num_classes=10):
super().__init__()
self.save_hyperparameters()
self.net = nn.Sequential(self.stem(stem_channels))
for i, s in enumerate(arch):
self.net.add_module(f'stage{i+1}', self.stage(*s))
self.net.add_module('head', nn.Sequential(
nn.AdaptiveAvgPool2d((1, 1)), nn.Flatten(),
nn.LazyLinear(num_classes)))
self.net.apply(d2l.init_cnn)
class DeResNeXt(DeAnyNet):
def __init__(self, lr=0.1, num_classes=10):
stem_channels, groups, bot_mul = 32, 16, 1
depths, channels = (5, 6), (32, 80)
super().__init__(
((depths[0], channels[0]),
(depths[1], channels[1])),
stem_channels, lr, num_classes)
model = DeResNeXt(lr=0.05)
trainer = d2l.Trainer(max_epochs=10, num_gpus=1)
trainer.fit(model, data)
class VioNet(AnyNet):
def __init__(self, lr=0.1, num_classes=10, depths=(4, 6), channels=(32, 80),
stem_channels=32, groups=(16, 16), bot_mul=(1, 1)):
super().__init__(
[(depths[i], channels[i], groups[i], bot_mul[i]) for i in range(len(depths))],
stem_channels, lr, num_classes)
VioNet_d = VioNet(depths=(6, 4))
trainer = d2l.Trainer(max_epochs=10, num_gpus=1)
trainer.fit(VioNet_d, data)
VioNet_c = VioNet(channels=(80, 32))
trainer = d2l.Trainer(max_epochs=10, num_gpus=1)
trainer.fit(VioNet_c, data)
VioNet_g = VioNet(groups=(16, 32))
trainer = d2l.Trainer(max_epochs=10, num_gpus=1)
trainer.fit(VioNet_g, data)
VioNet_b = VioNet(bot_mul=(1, 2))
trainer = d2l.Trainer(max_epochs=10, num_gpus=1)
trainer.fit(VioNet_b, data)
Designing the "perfect" Multilayer Perceptron (MLP) involves careful consideration of architectural choices to achieve high performance on a specific task. The paper "On Network Design Spaces for Visual Recognition" discusses several design principles that can be applied to create effective neural network architectures for visual recognition. Here's how you can use these design principles to design an effective MLP:
Depth and Width:
Skip Connections:
Kernel Sizes:
Pooling Strategies:
Normalization:
Activation Functions:
Dropout:
Initialization:
Normalization Layers:
Optimizers and Learning Rates:
Regularization Techniques:
Task-Specific Architectures:
Ensemble Learning:
Hyperparameter Search:
Transfer Learning:
Data Augmentation:
Regularly Evaluate Performance:
Remember that designing the "perfect" MLP involves an iterative process of experimentation, evaluation, and refinement. The choice of architecture and design principles should align with the specific requirements and constraints of your task and dataset.