{"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":"markdown","source":"Подготовка данных","metadata":{}},{"cell_type":"code","source":"import os\nimport time\nimport copy\nimport random\n\nimport pandas as pd\nimport numpy as np\nimport matplotlib.pyplot as plt\nimport PIL\n\nimport torch\nimport torch.nn as nn\nimport torch.optim as optim\n\nfrom tabulate import tabulate\nfrom torch.utils.data import Dataset, DataLoader\nfrom torchvision import models, transforms\nfrom skimage import io","metadata":{"execution":{"iopub.status.busy":"2022-05-22T23:56:43.304441Z","iopub.execute_input":"2022-05-22T23:56:43.305137Z","iopub.status.idle":"2022-05-22T23:56:43.310754Z","shell.execute_reply.started":"2022-05-22T23:56:43.305102Z","shell.execute_reply":"2022-05-22T23:56:43.309898Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"data_root = '/kaggle/input/airbus-ship-detection'\ntrain_root = f'{data_root}/train_v2'\nvalidation_root = f'{data_root}/test_v2'","metadata":{"execution":{"iopub.status.busy":"2022-05-22T23:56:25.686419Z","iopub.execute_input":"2022-05-22T23:56:25.687158Z","iopub.status.idle":"2022-05-22T23:56:25.691237Z","shell.execute_reply.started":"2022-05-22T23:56:25.687107Z","shell.execute_reply":"2022-05-22T23:56:25.690491Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df_for_count = pd.read_csv(f'{data_root}/train_ship_segmentations_v2.csv')\nprint(f\"Count images in segmentation file {df_for_count['ImageId'].value_counts().shape[0]}\")","metadata":{"execution":{"iopub.status.busy":"2022-05-22T23:10:25.724227Z","iopub.execute_input":"2022-05-22T23:10:25.724567Z","iopub.status.idle":"2022-05-22T23:10:26.508654Z","shell.execute_reply.started":"2022-05-22T23:10:25.724527Z","shell.execute_reply":"2022-05-22T23:10:26.507610Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"with_ships = df_for_count.dropna()\nwith_ships = with_ships.groupby('ImageId').size().reset_index(name='counts')\nwithout_ships = df_for_count[df_for_count['EncodedPixels'].isna()]","metadata":{"execution":{"iopub.status.busy":"2022-05-22T23:10:28.932342Z","iopub.execute_input":"2022-05-22T23:10:28.932663Z","iopub.status.idle":"2022-05-22T23:10:29.091004Z","shell.execute_reply.started":"2022-05-22T23:10:28.932629Z","shell.execute_reply":"2022-05-22T23:10:29.090057Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plt.figure(figsize=(15, 6))\nplt.subplot(1,2,1)\nplt.bar(['With ships','Without ships'], [len(with_ships),len(without_ships)], color = ['blue','green'])\nplt.ylabel('Number of images')\nplt.title('Train availability comparison')\nplt.grid()","metadata":{"execution":{"iopub.status.busy":"2022-05-22T23:10:32.179530Z","iopub.execute_input":"2022-05-22T23:10:32.179843Z","iopub.status.idle":"2022-05-22T23:10:32.324384Z","shell.execute_reply.started":"2022-05-22T23:10:32.179813Z","shell.execute_reply":"2022-05-22T23:10:32.323721Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"counts = with_ships['counts'].value_counts(sort=False)\nprint(tabulate([(i, counts[i]) for i in range(1,16)], headers=['num of ships','num of images']))","metadata":{"execution":{"iopub.status.busy":"2022-05-22T23:10:56.388084Z","iopub.execute_input":"2022-05-22T23:10:56.388393Z","iopub.status.idle":"2022-05-22T23:10:56.398159Z","shell.execute_reply.started":"2022-05-22T23:10:56.388358Z","shell.execute_reply":"2022-05-22T23:10:56.397290Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"w, h = 3, 3\nload_img = lambda filename: np.array(PIL.Image.open(f\"{train_root}/{filename}\").resize((200, 200)))\n_, axes_list = plt.subplots(h, w, figsize=(2*w, 2*h))\n\nfor axes in axes_list:\n    for ax in axes:\n        ax.axis('off')\n        img = np.random.choice(os.listdir(train_root))\n        ax.imshow(load_img(img))\n        ax.set_title(img)","metadata":{"execution":{"iopub.status.busy":"2022-05-22T23:12:41.289380Z","iopub.execute_input":"2022-05-22T23:12:41.289755Z","iopub.status.idle":"2022-05-22T23:12:43.657523Z","shell.execute_reply.started":"2022-05-22T23:12:41.289719Z","shell.execute_reply":"2022-05-22T23:12:43.656550Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"DataLoader","metadata":{}},{"cell_type":"code","source":"def make_classes(csv_file, start, lenght):\n    img_labels = pd.read_csv(csv_file, index_col=0)\n    img_labels['Class'] = img_labels['EncodedPixels'].notnull()\n    img_labels = img_labels.groupby(\"ImageId\").agg(['first'])\n    img_labels = img_labels.drop(['EncodedPixels'], axis = 1)\n    img_labels.columns = ['Class']\n    return img_labels[start: start + lenght + 1]\n\nclass ShipsDataset(Dataset):\n    def __init__(self, csv_file, data_folder, start, lenght, transform=None):\n        self.labels = make_classes(csv_file, start, lenght)\n        self.transform = transform\n        self.data_folder = data_folder\n        \n    def __len__(self):\n        return len(self.labels)\n    \n    def __getitem__(self, idx):\n        if torch.is_tensor(idx):\n            idx = idx.tolist()\n        img_name = os.path.join(self.data_folder,\n                            self.labels.index[idx])\n        image = io.imread(img_name)\n        label = self.labels.iloc[idx][0]\n        label = label.astype('int')\n        if self.transform:\n            image = self.transform(image)\n        return image, label","metadata":{"execution":{"iopub.status.busy":"2022-05-22T23:13:32.335147Z","iopub.execute_input":"2022-05-22T23:13:32.335440Z","iopub.status.idle":"2022-05-22T23:13:32.348122Z","shell.execute_reply.started":"2022-05-22T23:13:32.335410Z","shell.execute_reply":"2022-05-22T23:13:32.346921Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Данные для моделки","metadata":{}},{"cell_type":"code","source":"num_classes = 2\nbatch_size = 30\nnum_epochs = 4\nfeature_extract = True","metadata":{"execution":{"iopub.status.busy":"2022-05-22T23:30:14.335818Z","iopub.execute_input":"2022-05-22T23:30:14.336165Z","iopub.status.idle":"2022-05-22T23:30:14.341811Z","shell.execute_reply.started":"2022-05-22T23:30:14.336126Z","shell.execute_reply":"2022-05-22T23:30:14.340920Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def train_model(model, dataloaders, criterion, optimizer, num_epochs=25):\n    since = time.time()\n    val_acc_history = []\n    best_model_wts = copy.deepcopy(model.state_dict())\n    best_acc = 0.0\n    for epoch in range(num_epochs):\n        print('Epoch {}/{}'.format(epoch, num_epochs - 1))\n        print('-' * 10)\n        for phase in ['train', 'val']:\n            if phase == 'train':\n                model.train()\n            else:\n                model.eval()\n            running_loss = 0.0\n            running_corrects = 0\n            for (inputs, labels) in dataloaders[phase]:\n                inputs = inputs.to(device)\n                labels = labels.to(device)\n                optimizer.zero_grad()\n                with torch.set_grad_enabled(phase == 'train'):\n                    outputs = model(inputs)\n                    loss = criterion(outputs, labels)\n                    _, preds = torch.max(outputs, 1)\n                    if phase == 'train':\n                        loss.backward()\n                        optimizer.step()\n                running_loss += loss.item() * inputs.size(0)\n                running_corrects += torch.sum(preds == labels.data)\n            epoch_loss = running_loss / len(dataloaders[phase].dataset)\n            epoch_acc = running_corrects.double() / len(dataloaders[phase].dataset)\n            print('{} Loss: {:.4f} Acc: {:.4f}'.format(phase, epoch_loss, epoch_acc))\n            if phase == 'val' and epoch_acc > best_acc:\n                best_acc = epoch_acc\n                best_model_wts = copy.deepcopy(model.state_dict())\n            if phase == 'val':\n                val_acc_history.append(epoch_acc)\n        print()\n    time_elapsed = time.time() - since\n    print(f'Training time: {time_elapsed // 60}m {time_elapsed % 60}s')\n    print(f'Best score: {best_acc}')\n    model.load_state_dict(best_model_wts)\n    \n    return model, val_acc_history","metadata":{"execution":{"iopub.status.busy":"2022-05-22T23:13:41.208745Z","iopub.execute_input":"2022-05-22T23:13:41.209347Z","iopub.status.idle":"2022-05-22T23:13:41.223902Z","shell.execute_reply.started":"2022-05-22T23:13:41.209310Z","shell.execute_reply":"2022-05-22T23:13:41.223226Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Делаем модельку","metadata":{}},{"cell_type":"code","source":"def set_parameter_requires_grad(model, feature_extracting):\n    if feature_extracting:\n        for param in model.parameters():\n            param.requires_grad = False\n\ndef initialize_model(num_classes, feature_extract, use_pretrained=True):\n    model_ft = models.densenet121(pretrained=use_pretrained)\n    set_parameter_requires_grad(model_ft, feature_extract)\n    num_ftrs = model_ft.classifier.in_features\n    model_ft.classifier = nn.Linear(num_ftrs, num_classes)\n    input_size = 224\n    return model_ft, input_size\n\nmodel_ft, input_size = initialize_model(num_classes, feature_extract, use_pretrained=True)","metadata":{"execution":{"iopub.status.busy":"2022-05-22T23:14:52.173368Z","iopub.execute_input":"2022-05-22T23:14:52.173702Z","iopub.status.idle":"2022-05-22T23:14:52.467027Z","shell.execute_reply.started":"2022-05-22T23:14:52.173665Z","shell.execute_reply":"2022-05-22T23:14:52.466105Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"data_transforms = transforms.Compose([\n        transforms.ToPILImage(),\n        transforms.Resize(input_size),\n        transforms.CenterCrop(input_size),\n        transforms.ToTensor(),\n        transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])\n    ])\n\ndata = {\n    'train':\n    ShipsDataset(f'{data_root}/train_ship_segmentations_v2.csv', train_root, 0, 1500,  transform=data_transforms),\n    'val':\n    ShipsDataset(f'{data_root}/train_ship_segmentations_v2.csv', train_root, 1500, 500,  transform=data_transforms)\n\n}\n\ndataloaders_dict = {\n    'train': DataLoader(data['train'], batch_size=batch_size, shuffle=True),\n    'val': DataLoader(data['val'], batch_size=batch_size, shuffle=True)\n}\n\ndevice = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")","metadata":{"execution":{"iopub.status.busy":"2022-05-22T23:16:38.097515Z","iopub.execute_input":"2022-05-22T23:16:38.098127Z","iopub.status.idle":"2022-05-22T23:16:40.101578Z","shell.execute_reply.started":"2022-05-22T23:16:38.098088Z","shell.execute_reply":"2022-05-22T23:16:40.100685Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model_ft = model_ft.to(device)\nparams_to_update = model_ft.parameters()\noptimizer_ft = optim.SGD(params_to_update, lr=0.001, momentum=0.9)","metadata":{"execution":{"iopub.status.busy":"2022-05-22T23:17:17.468829Z","iopub.execute_input":"2022-05-22T23:17:17.469593Z","iopub.status.idle":"2022-05-22T23:17:17.483123Z","shell.execute_reply.started":"2022-05-22T23:17:17.469543Z","shell.execute_reply":"2022-05-22T23:17:17.482023Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Тренируем модельку","metadata":{}},{"cell_type":"code","source":"criterion = nn.CrossEntropyLoss()\nmodel_ft, hist = train_model(model_ft, dataloaders_dict, criterion, optimizer_ft, num_epochs=num_epochs)","metadata":{"execution":{"iopub.status.busy":"2022-05-22T23:30:19.503246Z","iopub.execute_input":"2022-05-22T23:30:19.503976Z","iopub.status.idle":"2022-05-22T23:52:58.355795Z","shell.execute_reply.started":"2022-05-22T23:30:19.503925Z","shell.execute_reply":"2022-05-22T23:52:58.354488Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Сохраняем","metadata":{}},{"cell_type":"code","source":"save_path = './ships_model.pth'\ntorch.save(model_ft.state_dict(), save_path)","metadata":{"execution":{"iopub.status.busy":"2022-05-22T23:53:42.431171Z","iopub.execute_input":"2022-05-22T23:53:42.431772Z","iopub.status.idle":"2022-05-22T23:53:42.547886Z","shell.execute_reply.started":"2022-05-22T23:53:42.431731Z","shell.execute_reply":"2022-05-22T23:53:42.547000Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Тестируем","metadata":{}},{"cell_type":"code","source":"model = initialize_model(num_classes, feature_extract, use_pretrained=True)[0]\nmodel_dict = torch.load('ships_model.pth')\nmodel.load_state_dict(model_dict)\nmodel.eval()\n\nfilenames = os.listdir(validation_root)\npreds_list = []\nimages_list = []\n\nfor i in range(16):\n    id = random.randint(0, 2024)\n    input_image = PIL.Image.open(f'{validation_root}/{filenames[id]}')\n    \n    preprocess = transforms.Compose([\n        transforms.Resize(256),\n        transforms.CenterCrop(224),\n        transforms.ToTensor(),\n        transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]),\n    ])\n    input_tensor = preprocess(input_image)\n    input_batch = input_tensor.unsqueeze(0)\n\n    if torch.cuda.is_available():\n        input_batch = input_batch.to('cuda')\n        model.to('cuda')\n\n    with torch.no_grad():\n        output = model(input_batch)\n    _, preds = torch.max(output, 1)\n\n    preds_list.append(preds[0])\n    images_list.append(input_image)\n\nw, h = 4, 4\n_, axes_list = plt.subplots(h, w, figsize=(2*w, 2*h))\nphoto_index = 0\nfor axes in axes_list:\n    for ax in axes:\n        ax.axis('off')\n        ax.imshow(images_list[photo_index])\n        ax.set_title(f'{preds_list[photo_index] == 1}')\n        photo_index += 1","metadata":{"execution":{"iopub.status.busy":"2022-05-22T23:56:48.993900Z","iopub.execute_input":"2022-05-22T23:56:48.994209Z","iopub.status.idle":"2022-05-22T23:56:53.600995Z","shell.execute_reply.started":"2022-05-22T23:56:48.994174Z","shell.execute_reply":"2022-05-22T23:56:53.599915Z"},"trusted":true},"execution_count":null,"outputs":[]}]}