{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"pygments_lexer":"ipython3","nbconvert_exporter":"python","version":"3.6.4","file_extension":".py","codemirror_mode":{"name":"ipython","version":3},"name":"python","mimetype":"text/x-python"}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import torch\nimport torch.nn as nn\nfrom torch.utils.data import Dataset, DataLoader\nimport torchvision.transforms as transforms\nimport torch.optim as optim\nfrom torchvision.datasets import ImageFolder\n\nimport seaborn as sns\nimport pandas as pd\nimport numpy as np\n","metadata":{"execution":{"iopub.status.busy":"2023-10-18T12:58:09.458659Z","iopub.execute_input":"2023-10-18T12:58:09.458956Z","iopub.status.idle":"2023-10-18T12:58:09.463182Z","shell.execute_reply.started":"2023-10-18T12:58:09.458935Z","shell.execute_reply":"2023-10-18T12:58:09.462508Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class DogCatClassification(Dataset):\n    def __init__(self, data_dir, transforms = None):\n        self.data = ImageFolder(data_dir, transform = transforms)\n    def __len__(self):\n        return len(self.data)\n    def __getitem__(self, idx):\n        return self.data[idx]\n    @property\n    def classes(self):\n        return self.data.classes\n        ","metadata":{"execution":{"iopub.status.busy":"2023-10-18T12:58:09.464514Z","iopub.execute_input":"2023-10-18T12:58:09.464940Z","iopub.status.idle":"2023-10-18T12:58:09.484279Z","shell.execute_reply.started":"2023-10-18T12:58:09.464918Z","shell.execute_reply":"2023-10-18T12:58:09.483495Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"data_dir = ('/kaggle/input/dog-vs-cat-classification')\ntransform = transforms.Compose(\n[\n    transforms.Resize((224, 224)),\n    transforms.ToTensor()\n])\n\ndataset = DogCatClassification(data_dir, transform)\n\nlen(dataset)\n\nname_of_classes = {v: k for v, k in ImageFolder(data_dir).class_to_idx.items()}\nname_of_classes","metadata":{"execution":{"iopub.status.busy":"2023-10-18T12:58:09.540392Z","iopub.execute_input":"2023-10-18T12:58:09.540951Z","iopub.status.idle":"2023-10-18T12:58:19.458131Z","shell.execute_reply.started":"2023-10-18T12:58:09.540927Z","shell.execute_reply":"2023-10-18T12:58:19.457513Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Depthwise Convolution Module\nclass DepthWise_Conv(nn.Module):\n    def __init__(self, in_fts, stride=(1,1)) -> None:\n        super().__init__()\n        self.conv = nn.Sequential(\n            nn.Conv2d(in_fts, in_fts, kernel_size=(3,3), stride=stride, padding=(1,1), groups=in_fts, bias=False),\n            nn.BatchNorm2d(in_fts),\n            nn.ReLU6(inplace=True)\n        )\n\n    def forward(self, input_image):\n        x = self.conv(input_image)\n        return x\n\n","metadata":{"execution":{"iopub.status.busy":"2023-10-18T12:58:19.459360Z","iopub.execute_input":"2023-10-18T12:58:19.459571Z","iopub.status.idle":"2023-10-18T12:58:19.464828Z","shell.execute_reply.started":"2023-10-18T12:58:19.459553Z","shell.execute_reply":"2023-10-18T12:58:19.464260Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# PointWise Convolution Module\nclass Pointwise_Conv(nn.Module):\n    def __init__(self, in_fts, out_fts) -> None:\n        super().__init__()\n        self.conv = nn.Sequential(\n            nn.Conv2d(in_fts, out_fts, kernel_size=(1,1), bias=False),\n            nn.BatchNorm2d(out_fts)\n        )\n    def forward(self, input_image):\n        x = self.conv(input_image)\n        return x\n        ","metadata":{"execution":{"iopub.status.busy":"2023-10-18T12:58:19.465732Z","iopub.execute_input":"2023-10-18T12:58:19.466433Z","iopub.status.idle":"2023-10-18T12:58:19.477824Z","shell.execute_reply.started":"2023-10-18T12:58:19.466412Z","shell.execute_reply":"2023-10-18T12:58:19.477084Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Bottleneck Layer when Stride is 1\nclass NetForStrideOne(nn.Module):\n    def __init__(self, in_fts, out_fts, expansion) -> None:\n        super().__init__()\n        self.conv1 = nn.Sequential(\n            nn.Conv2d(in_fts, expansion*in_fts, kernel_size=(1,1), bias=False),\n            nn.BatchNorm2d(expansion*in_fts),\n            nn.ReLU6(inplace=True)\n        )\n        self.dw = DepthWise_Conv(expansion*in_fts)\n        self.pw = Pointwise_Conv(expansion*in_fts, out_fts)\n\n        self.in_fts = in_fts\n        self.out_fts = out_fts\n        self.expansion = expansion\n\n    def forward(self, input_image):\n        if self.expansion == 1:\n            x = self.dw(input_image)\n            x = self.pw(x)\n        else:\n            x = self.conv1(input_image)\n            x = self.dw(x)\n            x = self.pw(x)\n\n        # If input channel and output channel are same, then perform add\n        # residual part\n        if self.in_fts == self.out_fts:\n            x = input_image + x          \n\n        return x","metadata":{"execution":{"iopub.status.busy":"2023-10-18T12:58:19.478648Z","iopub.execute_input":"2023-10-18T12:58:19.479048Z","iopub.status.idle":"2023-10-18T12:58:19.492702Z","shell.execute_reply.started":"2023-10-18T12:58:19.479026Z","shell.execute_reply":"2023-10-18T12:58:19.491834Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Bottleneck layer when Stride is 2\nclass NetForStrideTwo(nn.Module):\n    def __init__(self, in_fts, out_fts, expansion) -> None:\n        super().__init__()\n        self.conv1 = nn.Sequential(\n            nn.Conv2d(in_fts, expansion*in_fts, kernel_size=(1,1), bias=False),\n            nn.BatchNorm2d(expansion*in_fts),\n            nn.ReLU6(inplace=True)\n        )\n        self.dw = DepthWise_Conv(expansion*in_fts, stride=(2,2))\n        self.pw = Pointwise_Conv(expansion*in_fts, out_fts)\n\n        self.expansion = expansion\n\n    def forward(self, input_image):\n        if self.expansion == 1:\n            x = self.dw(input_image)\n            x = self.pw(x)\n        else:\n            x = self.conv1(input_image)\n            x = self.dw(x)\n            x = self.pw(x)      \n\n        return x","metadata":{"execution":{"iopub.status.busy":"2023-10-18T12:58:19.494177Z","iopub.execute_input":"2023-10-18T12:58:19.494487Z","iopub.status.idle":"2023-10-18T12:58:19.507587Z","shell.execute_reply.started":"2023-10-18T12:58:19.494467Z","shell.execute_reply":"2023-10-18T12:58:19.506694Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from collections import OrderedDict\n\n# MobileNetV2 architecture\nclass MyMobileNet_v2(nn.Module):\n    def __init__(self, bottleneckLayerDetails, in_fts=3, numClasses=1000, width_multiplier=1) -> None:\n        super().__init__()\n        self.bottleneckLayerDetails = bottleneckLayerDetails\n        self.width_multiplier = width_multiplier\n\n        self.conv1 = nn.Sequential(\n            nn.Conv2d(in_fts, round(width_multiplier*32), kernel_size=(3,3), stride=(2,2), padding=(1,1), bias=False),\n            nn.BatchNorm2d(round(width_multiplier*32)),\n            nn.ReLU6(inplace=True)\n        )\n        self.in_fts = round(width_multiplier*32)\n        \n        # Defined bottleneck layer as per Table 2\n        self.layerConstructed = self.constructLayer()\n\n        # Top layers after bottleneck\n        self.feature = nn.Sequential(\n            nn.Conv2d(self.in_fts, round(width_multiplier*1280), kernel_size=(1,1), bias=False),\n            nn.BatchNorm2d(round(width_multiplier*1280)),\n            nn.ReLU6(inplace=True)\n        )\n\n        self.avgpool = nn.AdaptiveAvgPool2d(output_size=(1,1))\n\n        self.outputLayer = nn.Sequential(\n            nn.Dropout2d(),\n            nn.Conv2d(round(width_multiplier*1280), numClasses, kernel_size=(1,1)),\n        )\n\n    def forward(self, input_image):\n        x = self.conv1(input_image)\n        x = self.layerConstructed(x)\n        x = self.feature(x)\n        x = self.avgpool(x)\n        x = self.outputLayer(x)\n        return x\n\n    # Defined function to construct the layer based on bottleneck layer defined in Table 2\n    def constructLayer(self):\n        itemIndex = 0\n        block = OrderedDict()\n        # iterating the defined layer details\n        for lItem in self.bottleneckLayerDetails:\n            # each items assigned corresponding values\n            t, out_fts, n, stride = lItem\n            # If width multipler is mentioned then perform this line\n            out_fts = round(self.width_multiplier*out_fts)\n            # for stride value 1\n            if stride == 1:\n                # constructedd the NetForStrideOne module by n times\n                for nItem in range(n):\n                    block[str(itemIndex)+\"_\"+str(nItem)] = NetForStrideOne(self.in_fts, out_fts, t)\n                    self.in_fts = out_fts\n            # for stride value 2\n            elif stride == 2:\n                # First layer constructed for NetForStrideTwo module once only\n                block[str(itemIndex)+\"_\"+str(0)] = NetForStrideTwo(self.in_fts, out_fts, t)\n                self.in_fts = out_fts\n                # Remaining will be NetForStrideOne module (n-1) times\n                for nItem in range(1,n):\n                    block[str(itemIndex)+\"_\"+str(nItem)] = NetForStrideOne(self.in_fts, out_fts, t)\n            itemIndex += 1\n\n        return nn.Sequential(block)","metadata":{"execution":{"iopub.status.busy":"2023-10-18T12:58:19.508740Z","iopub.execute_input":"2023-10-18T12:58:19.508972Z","iopub.status.idle":"2023-10-18T12:58:19.521004Z","shell.execute_reply.started":"2023-10-18T12:58:19.508952Z","shell.execute_reply":"2023-10-18T12:58:19.520261Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from torchinfo import summary\nif __name__ == \"__main__\":\n    \n    bottleneckLayerDetails = [\n            (1,16,1,1),\n            (6,24,2,2),\n            (6,32,3,2),\n            (6,64,4,2),\n            (6,96,3,1),\n            (6,160,3,2),\n            (6,320,1,1)\n        ]\n    \n    m = MyMobileNet_v2(bottleneckLayerDetails, width_multiplier=1)\n    print(summary(m, (1,3,224,224)))\n    ","metadata":{"execution":{"iopub.status.busy":"2023-10-18T13:07:43.093528Z","iopub.execute_input":"2023-10-18T13:07:43.094091Z","iopub.status.idle":"2023-10-18T13:07:43.190106Z","shell.execute_reply.started":"2023-10-18T13:07:43.094063Z","shell.execute_reply":"2023-10-18T13:07:43.189520Z"},"trusted":true},"execution_count":null,"outputs":[]}]}