From 7c251af7a8f6dc6459d8ddcab7f550ac7b57b5b3 Mon Sep 17 00:00:00 2001 From: James Betker Date: Fri, 4 Jun 2021 17:29:07 -0600 Subject: [PATCH] Support cifar100 with resnet --- codes/data/torch_dataset.py | 9 +- codes/models/cifar_resnet.py | 166 ++++++++++++++++++++++ codes/models/resnet_with_checkpointing.py | 1 - 3 files changed, 171 insertions(+), 5 deletions(-) create mode 100644 codes/models/cifar_resnet.py diff --git a/codes/data/torch_dataset.py b/codes/data/torch_dataset.py index 920a1392..ca259e8f 100644 --- a/codes/data/torch_dataset.py +++ b/codes/data/torch_dataset.py @@ -13,6 +13,7 @@ class TorchDataset(Dataset): "mnist": datasets.MNIST, "fmnist": datasets.FashionMNIST, "cifar10": datasets.CIFAR10, + "cifar100": datasets.CIFAR100, "imagenet": datasets.ImageNet, "imagefolder": datasets.ImageFolder } @@ -48,12 +49,12 @@ if __name__ == '__main__': opt = { 'flip': True, 'crop_sz': None, - 'dataset': 'imagefolder', - 'resize': 256, - 'center_crop': 224, + 'dataset': 'cifar100', + 'image_size': 32, 'normalize': True, 'kwargs': { - 'root': 'F:\\4k6k\\datasets\\images\\imagenet_2017\\val', + 'root': 'E:\\4k6k\\datasets\\images\\cifar100', + 'download': True } } set = TorchDataset(opt) diff --git a/codes/models/cifar_resnet.py b/codes/models/cifar_resnet.py new file mode 100644 index 00000000..79fac29e --- /dev/null +++ b/codes/models/cifar_resnet.py @@ -0,0 +1,166 @@ +"""resnet in pytorch + + + +[1] Kaiming He, Xiangyu Zhang, Shaoqing Ren, Jian Sun. + + Deep Residual Learning for Image Recognition + https://arxiv.org/abs/1512.03385v1 +""" + +import torch +import torch.nn as nn + +from trainer.networks import register_model + + +class BasicBlock(nn.Module): + """Basic Block for resnet 18 and resnet 34 + + """ + + #BasicBlock and BottleNeck block + #have different output size + #we use class attribute expansion + #to distinct + expansion = 1 + + def __init__(self, in_channels, out_channels, stride=1): + super().__init__() + + #residual function + self.residual_function = nn.Sequential( + nn.Conv2d(in_channels, out_channels, kernel_size=3, stride=stride, padding=1, bias=False), + nn.BatchNorm2d(out_channels), + nn.ReLU(inplace=True), + nn.Conv2d(out_channels, out_channels * BasicBlock.expansion, kernel_size=3, padding=1, bias=False), + nn.BatchNorm2d(out_channels * BasicBlock.expansion) + ) + + #shortcut + self.shortcut = nn.Sequential() + + #the shortcut output dimension is not the same with residual function + #use 1*1 convolution to match the dimension + if stride != 1 or in_channels != BasicBlock.expansion * out_channels: + self.shortcut = nn.Sequential( + nn.Conv2d(in_channels, out_channels * BasicBlock.expansion, kernel_size=1, stride=stride, bias=False), + nn.BatchNorm2d(out_channels * BasicBlock.expansion) + ) + + def forward(self, x): + return nn.ReLU(inplace=True)(self.residual_function(x) + self.shortcut(x)) + +class BottleNeck(nn.Module): + """Residual block for resnet over 50 layers + + """ + expansion = 4 + def __init__(self, in_channels, out_channels, stride=1): + super().__init__() + self.residual_function = nn.Sequential( + nn.Conv2d(in_channels, out_channels, kernel_size=1, bias=False), + nn.BatchNorm2d(out_channels), + nn.ReLU(inplace=True), + nn.Conv2d(out_channels, out_channels, stride=stride, kernel_size=3, padding=1, bias=False), + nn.BatchNorm2d(out_channels), + nn.ReLU(inplace=True), + nn.Conv2d(out_channels, out_channels * BottleNeck.expansion, kernel_size=1, bias=False), + nn.BatchNorm2d(out_channels * BottleNeck.expansion), + ) + + self.shortcut = nn.Sequential() + + if stride != 1 or in_channels != out_channels * BottleNeck.expansion: + self.shortcut = nn.Sequential( + nn.Conv2d(in_channels, out_channels * BottleNeck.expansion, stride=stride, kernel_size=1, bias=False), + nn.BatchNorm2d(out_channels * BottleNeck.expansion) + ) + + def forward(self, x): + return nn.ReLU(inplace=True)(self.residual_function(x) + self.shortcut(x)) + +class ResNet(nn.Module): + + def __init__(self, block, num_block, num_classes=100): + super().__init__() + + self.in_channels = 64 + + self.conv1 = nn.Sequential( + nn.Conv2d(3, 64, kernel_size=3, padding=1, bias=False), + nn.BatchNorm2d(64), + nn.ReLU(inplace=True)) + #we use a different inputsize than the original paper + #so conv2_x's stride is 1 + self.conv2_x = self._make_layer(block, 64, num_block[0], 1) + self.conv3_x = self._make_layer(block, 128, num_block[1], 2) + self.conv4_x = self._make_layer(block, 256, num_block[2], 2) + self.conv5_x = self._make_layer(block, 512, num_block[3], 2) + self.avg_pool = nn.AdaptiveAvgPool2d((1, 1)) + self.fc = nn.Linear(512 * block.expansion, num_classes) + + def _make_layer(self, block, out_channels, num_blocks, stride): + """make resnet layers(by layer i didnt mean this 'layer' was the + same as a neuron netowork layer, ex. conv layer), one layer may + contain more than one residual block + + Args: + block: block type, basic block or bottle neck block + out_channels: output depth channel number of this layer + num_blocks: how many blocks per layer + stride: the stride of the first block of this layer + + Return: + return a resnet layer + """ + + # we have num_block blocks per layer, the first block + # could be 1 or 2, other blocks would always be 1 + strides = [stride] + [1] * (num_blocks - 1) + layers = [] + for stride in strides: + layers.append(block(self.in_channels, out_channels, stride)) + self.in_channels = out_channels * block.expansion + + return nn.Sequential(*layers) + + def forward(self, x): + output = self.conv1(x) + output = self.conv2_x(output) + output = self.conv3_x(output) + output = self.conv4_x(output) + output = self.conv5_x(output) + output = self.avg_pool(output) + output = output.view(output.size(0), -1) + output = self.fc(output) + + return output + +@register_model +def register_cifar_resnet18(opt_net, opt): + """ return a ResNet 18 object + """ + return ResNet(BasicBlock, [2, 2, 2, 2]) + +def resnet34(): + """ return a ResNet 34 object + """ + return ResNet(BasicBlock, [3, 4, 6, 3]) + +def resnet50(): + """ return a ResNet 50 object + """ + return ResNet(BottleNeck, [3, 4, 6, 3]) + +def resnet101(): + """ return a ResNet 101 object + """ + return ResNet(BottleNeck, [3, 4, 23, 3]) + +def resnet152(): + """ return a ResNet 152 object + """ + return ResNet(BottleNeck, [3, 8, 36, 3]) + + diff --git a/codes/models/resnet_with_checkpointing.py b/codes/models/resnet_with_checkpointing.py index eafea4ea..95901e74 100644 --- a/codes/models/resnet_with_checkpointing.py +++ b/codes/models/resnet_with_checkpointing.py @@ -197,4 +197,3 @@ def register_resnet50(opt_net, opt): if opt_net['custom_head_logits']: model.fc = nn.Linear(512 * 4, opt_net['custom_head_logits']) return model -