{"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":"from fastai.vision.all import *\n\nlabels = pd.read_csv(\"../input/dog-breed-identification/labels.csv\")\nlabels","metadata":{"execution":{"iopub.status.busy":"2021-06-30T06:25:14.564772Z","iopub.execute_input":"2021-06-30T06:25:14.565357Z","iopub.status.idle":"2021-06-30T06:25:15.473211Z","shell.execute_reply.started":"2021-06-30T06:25:14.565212Z","shell.execute_reply":"2021-06-30T06:25:15.472346Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Get the data","metadata":{}},{"cell_type":"markdown","source":"split the data into training and validation sets","metadata":{}},{"cell_type":"code","source":"from sklearn.model_selection import StratifiedShuffleSplit\n\nsplit = StratifiedShuffleSplit(n_splits=1, test_size=0.2, random_state=42)\ntrain_ids, valid_ids = next(split.split(labels, labels[\"breed\"]))\nlabels[\"is_valid\"] = [i in valid_ids for i in range(len(labels))]\n\nlabels[\"id\"] = labels[\"id\"].apply(lambda x: x + \".jpg\")","metadata":{"execution":{"iopub.status.busy":"2021-06-30T06:25:15.474739Z","iopub.execute_input":"2021-06-30T06:25:15.475082Z","iopub.status.idle":"2021-06-30T06:25:15.563268Z","shell.execute_reply.started":"2021-06-30T06:25:15.475044Z","shell.execute_reply":"2021-06-30T06:25:15.562425Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"get images, resize each image, add data augmentation and normalize image tensors","metadata":{}},{"cell_type":"code","source":"path = \"../input/dog-breed-identification/train\"\n\ndls = ImageDataLoaders.from_df(labels, path,\n                               item_tfms=Resize(460, method=\"squeeze\"),\n                               batch_tfms=[*aug_transforms(size=300),\n                                           Normalize.from_stats(*imagenet_stats)],\n                               bs=32, valid_col=\"is_valid\")\ndls.show_batch()","metadata":{"execution":{"iopub.status.busy":"2021-06-30T06:25:15.565048Z","iopub.execute_input":"2021-06-30T06:25:15.565423Z","iopub.status.idle":"2021-06-30T06:25:19.965925Z","shell.execute_reply.started":"2021-06-30T06:25:15.565386Z","shell.execute_reply":"2021-06-30T06:25:19.965073Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Extracting feature using various pretrained CNN","metadata":{}},{"cell_type":"markdown","source":"downloading trained CNNs as feature extractor: inception, resnet50","metadata":{}},{"cell_type":"code","source":"from torchvision.models import inception_v3, mobilenet_v2\n\ninception = inception_v3(pretrained=True, aux_logits=False)\ninception = nn.Sequential(*list(inception.children())[:-2],\n                          nn.Flatten()).eval()","metadata":{"execution":{"iopub.status.busy":"2021-06-30T06:25:19.967247Z","iopub.execute_input":"2021-06-30T06:25:19.967663Z","iopub.status.idle":"2021-06-30T06:25:20.324798Z","shell.execute_reply.started":"2021-06-30T06:25:19.967615Z","shell.execute_reply":"2021-06-30T06:25:20.323872Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"resnet = nn.Sequential(*list(resnet50(pretrained=True).children())[:-1], \n                          nn.Flatten()).eval()","metadata":{"execution":{"iopub.status.busy":"2021-06-30T06:25:20.326193Z","iopub.execute_input":"2021-06-30T06:25:20.326577Z","iopub.status.idle":"2021-06-30T06:25:20.968660Z","shell.execute_reply.started":"2021-06-30T06:25:20.326538Z","shell.execute_reply":"2021-06-30T06:25:20.967770Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"mobile = nn.Sequential(*list(mobilenet_v2(pretrained=True).children())[:-1],\n                       nn.AdaptiveAvgPool2d((1,1)),\n                       nn.Flatten()).eval()","metadata":{"execution":{"iopub.status.busy":"2021-06-30T06:25:20.969922Z","iopub.execute_input":"2021-06-30T06:25:20.970571Z","iopub.status.idle":"2021-06-30T06:25:21.082347Z","shell.execute_reply.started":"2021-06-30T06:25:20.970524Z","shell.execute_reply":"2021-06-30T06:25:21.081470Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"combine these CNNs and add a classifier","metadata":{}},{"cell_type":"code","source":"class NeuralNet(Module):\n    def __init__(self, extractors, hidden_size, vocab_size, device):\n        \n        self.extractors = extractors\n        for conv in self.extractors:\n            conv.to(device)\n                  \n        self.classifier = nn.Sequential(\n            nn.BatchNorm1d(hidden_size),\n            nn.Dropout(0.25),\n            nn.Linear(hidden_size, 1024),\n            nn.ReLU(),\n            nn.BatchNorm1d(1024),\n            nn.Dropout(0.5),\n            nn.Linear(1024, vocab_size)\n        )\n        \n    def forward(self, x):\n        \n        features = torch.cat([conv(x) for conv in self.extractors], dim=1)\n        \n        return self.classifier(features)","metadata":{"execution":{"iopub.status.busy":"2021-06-30T06:25:21.083729Z","iopub.execute_input":"2021-06-30T06:25:21.084271Z","iopub.status.idle":"2021-06-30T06:25:21.091112Z","shell.execute_reply.started":"2021-06-30T06:25:21.084216Z","shell.execute_reply":"2021-06-30T06:25:21.090335Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Train our model","metadata":{}},{"cell_type":"code","source":"extractors = [inception, resnet, mobile]\nhidden_size = 2048 + 2048 + 1280\ndevice = \"cuda\" if torch.cuda.is_available() else \"cpu\"\nmodel = NeuralNet(extractors, hidden_size, len(dls.vocab), device)","metadata":{"execution":{"iopub.status.busy":"2021-06-30T06:25:21.093173Z","iopub.execute_input":"2021-06-30T06:25:21.093685Z","iopub.status.idle":"2021-06-30T06:25:21.236342Z","shell.execute_reply.started":"2021-06-30T06:25:21.093646Z","shell.execute_reply":"2021-06-30T06:25:21.235456Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"weights = [labels.shape[0] / (120 * labels[\"breed\"].value_counts()[breed]) for breed in dls.vocab]\nweights = tensor(weights, device=device)","metadata":{"execution":{"iopub.status.busy":"2021-06-30T06:25:21.238298Z","iopub.execute_input":"2021-06-30T06:25:21.238904Z","iopub.status.idle":"2021-06-30T06:25:21.557665Z","shell.execute_reply.started":"2021-06-30T06:25:21.238863Z","shell.execute_reply":"2021-06-30T06:25:21.556698Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"learn = Learner(dls, model, metrics=accuracy, path=\".\").to_fp16()\nlearn.lr_find()","metadata":{"execution":{"iopub.status.busy":"2021-06-30T06:25:21.558931Z","iopub.execute_input":"2021-06-30T06:25:21.559315Z","iopub.status.idle":"2021-06-30T06:26:38.259879Z","shell.execute_reply.started":"2021-06-30T06:25:21.559272Z","shell.execute_reply":"2021-06-30T06:26:38.258984Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"learn.fit_one_cycle(3, 1e-3)","metadata":{"execution":{"iopub.status.busy":"2021-06-30T06:27:09.014826Z","iopub.execute_input":"2021-06-30T06:27:09.015161Z","iopub.status.idle":"2021-06-30T06:38:01.783142Z","shell.execute_reply.started":"2021-06-30T06:27:09.015129Z","shell.execute_reply":"2021-06-30T06:38:01.782277Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Get predictions","metadata":{}},{"cell_type":"code","source":"torch.cuda.empty_cache()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"test_files = get_image_files(\"../input/dog-breed-identification/test\")\ntest_dl = dls.test_dl(test_files, bs=32)","metadata":{"execution":{"iopub.status.busy":"2021-06-30T06:39:48.068913Z","iopub.execute_input":"2021-06-30T06:39:48.069243Z","iopub.status.idle":"2021-06-30T06:39:48.153166Z","shell.execute_reply.started":"2021-06-30T06:39:48.069211Z","shell.execute_reply":"2021-06-30T06:39:48.152345Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"preds, targs = learn.get_preds(dl=test_dl)","metadata":{"execution":{"iopub.status.busy":"2021-06-30T06:39:49.762861Z","iopub.execute_input":"2021-06-30T06:39:49.763219Z","iopub.status.idle":"2021-06-30T06:41:22.632093Z","shell.execute_reply.started":"2021-06-30T06:39:49.763188Z","shell.execute_reply":"2021-06-30T06:41:22.631168Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"sub = pd.DataFrame({\"id\":test_files.map(lambda x:x.stem)})\nsub[list(dls.vocab)] = preds\nsub.to_csv(\"submission.csv\", index=False)","metadata":{"execution":{"iopub.status.busy":"2021-06-30T06:41:38.233874Z","iopub.execute_input":"2021-06-30T06:41:38.234224Z","iopub.status.idle":"2021-06-30T06:41:41.669915Z","shell.execute_reply.started":"2021-06-30T06:41:38.234187Z","shell.execute_reply":"2021-06-30T06:41:41.668907Z"},"trusted":true},"execution_count":null,"outputs":[]}]}