{"metadata":{"kernelspec":{"name":"python3","display_name":"Python 3","language":"python"},"language_info":{"name":"python","version":"3.10.14","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"gpu","dataSources":[{"sourceId":37852,"databundleVersionId":4070249,"sourceType":"competition"}],"dockerImageVersionId":30787,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import pandas as pd\nimport random\nimport os\nimport sys\nimport numpy as np\nimport timm\nfrom tqdm import tqdm\n\nimport torch\nimport torch.nn as nn\nimport torchvision.models as models\nimport torch.nn.functional as F\nfrom torch.utils.data import DataLoader, Dataset\nfrom torch.optim import Adam, AdamW\nfrom torch.optim.lr_scheduler import CosineAnnealingWarmRestarts, CosineAnnealingLR, ReduceLROnPlateau\nfrom torch.amp import GradScaler\nimport torch.multiprocessing as multiprocessing\nfrom torch.utils.tensorboard import SummaryWriter\nimport datetime\nimport json\nimport cv2\nimport albumentations as A\nfrom albumentations.pytorch.transforms import ToTensorV2\nimport torchvision.transforms\nimport matplotlib.pyplot as plt\nfrom sklearn.model_selection import StratifiedKFold\nfrom PIL import Image","metadata":{"jupyter":{"is_executing":true},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Tensorboard","metadata":{}},{"cell_type":"code","source":"# def gen_Log():\n#     current_time = datetime.datetime.now().strftime(\"%Y-%m-%d_%H-%M-%S\")\n#     log_dir = os.path.join(\"runs\", f\"experiment_{current_time}\")\n#     writer = SummaryWriter(log_dir=log_dir)\n#     return writer\n\n# writer = gen_Log()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-16T08:54:02.482384Z","iopub.execute_input":"2024-12-16T08:54:02.483197Z","iopub.status.idle":"2024-12-16T08:54:02.486690Z","shell.execute_reply.started":"2024-12-16T08:54:02.483166Z","shell.execute_reply":"2024-12-16T08:54:02.485802Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# CFG","metadata":{}},{"cell_type":"code","source":"class CFG:\n    # model\n    model_name = 'convnext_base'\n    # criterion\n    criterion_name = 'CrossEntropyLoss'\n    \n    # optimizer\n    optimizer_name = 'AdamW'\n    max_grad_norm = 1000\n    gradient_accumulation_steps = 1\n    # CosineAnnealingLR\n    T_max = 5\n    \n    # scheduler\n    scheduler_name = 'CosineAnnealingLR'\n    \n    # global settings\n    apex = True\n    seed = 42\n    device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')    \n    n_folds = 5\n    used_folds = 5\n    epochs = 3\n    batch_size = 64\n    num_classes = 44\n    print_freq = 100\n    # image settings\n    width_map= {\n        'tf_efficientnet_b2' :260,\n        'convnext_base': 224,\n        'convnext_small': 224,\n        'convnext_large': 224\n    }\n    height_map ={\n        'tf_efficientnet_b2' :260,\n        'convnext_base': 224,\n        'convnext_small': 224,\n        'convnext_large': 224\n    }\n    width = width_map[model_name]\n    height = height_map[model_name]\n\n    # learning settings\n    lr = 1e-4\n    min_lr = 1e-6\n    weight_decay = 1e-5\n    \ndef set_seed(seed=42):\n    random.seed(seed)\n    os.environ['PYTHONHASHSEED'] = str(seed)\n    np.random.seed(seed)\n    torch.manual_seed(seed)\n    torch.cuda.manual_seed(seed)\n    torch.backends.cudnn.deterministic = True\n\nset_seed(seed=CFG.seed)","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Save CFG","metadata":{}},{"cell_type":"code","source":"# Function to save only relevant CFG attributes to a JSON file\ndef save_cfg_to_json(cfg_class, file_path):\n    relevant_keys = ['model_name', 'criterion_name', 'optimizer_name', 'scheduler_name', 'device',\n                     'epochs', 'batch_size', 'lr', 'min_lr', 'weight_decay', 'width', 'height']\n    cfg_dict = {key: (value if not isinstance(value, torch.device) else str(value))\n                for key, value in cfg_class.__dict__.items() \n                if key in relevant_keys}\n    with open(file_path, 'w') as json_file:\n        json.dump(cfg_dict, json_file, indent=4)\n\n# Usage\nfile_path = 'cfg.json'\nsave_cfg_to_json(CFG, file_path)\nprint(f\"Configuration saved to {file_path}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-16T08:57:28.053617Z","iopub.execute_input":"2024-12-16T08:57:28.054193Z","iopub.status.idle":"2024-12-16T08:57:28.061060Z","shell.execute_reply.started":"2024-12-16T08:57:28.054160Z","shell.execute_reply":"2024-12-16T08:57:28.060098Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# 训练数据读入","metadata":{}},{"cell_type":"code","source":"train = pd.read_csv(\"/kaggle/input/boolart-image-classification/train.csv\")\nFold = StratifiedKFold(n_splits=CFG.n_folds, shuffle=True, random_state=CFG.seed)\n\ntrain['fold'] = int(-1)\nfor fold, (train_index, val_index) in enumerate(Fold.split(train, train['target'])):\n    train.loc[val_index, 'fold'] = fold","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-02T08:18:02.904029Z","iopub.execute_input":"2024-12-02T08:18:02.904412Z","iopub.status.idle":"2024-12-02T08:18:02.967229Z","shell.execute_reply.started":"2024-12-02T08:18:02.904373Z","shell.execute_reply":"2024-12-02T08:18:02.966250Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# 计算训练集各通道的mean和std值 ","metadata":{}},{"cell_type":"code","source":"# def calculate_mean_std(data):\n#     means = []\n#     stds = []\n#     for id in tqdm(data['id']):\n#         train_img_path =f\"/kaggle/input/boolart-image-classification/train_image/{id}.jpg\"\n#         image = Image.open(train_img_path).convert(\"RGB\")\n#         image = np.array(image.resize((CFG.width, CFG.height)))\n#         means.append(np.mean(image,axis=(0,1)))\n#         stds.append(np.std(image, axis=(0,1)))\n#     mean = np.mean(means, axis=0)\n#     std = np.mean(stds,axis=0)\n#     return mean / 255, std / 255\n# mean, std = calculate_mean_std(train)\n# %store mean\n# %store std\nmean, std = ([0.8536320017130206, 0.8362727931350286, 0.8301507008641884],\n             [0.23491626922733028, 0.24977155061784578, 0.25436414956228226])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-02T08:18:02.969364Z","iopub.execute_input":"2024-12-02T08:18:02.969619Z","iopub.status.idle":"2024-12-02T08:18:02.974957Z","shell.execute_reply.started":"2024-12-02T08:18:02.969594Z","shell.execute_reply":"2024-12-02T08:18:02.974095Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# 数据增强","metadata":{}},{"cell_type":"code","source":"def get_transform(isTransform):\n    if isTransform:\n        return A.Compose([\n            A.Resize(CFG.width, CFG.height),\n            # 翻转\n            A.VerticalFlip(p=0.5),\n            A.HorizontalFlip(p=0.5),\n            # 高斯噪声\n            A.GaussNoise(p=0.2),\n            # 模糊\n            A.OneOf([\n                A.Blur(blur_limit=3, p=0.1),\n                A.MedianBlur(blur_limit=3, p=0.1),\n            ], p=0.2),\n            # 变形\n            # A.OneOf([\n            #     A.OpticalDistortion(p=0.3),\n            #     A.GridDistortion(p=0.1),\n            #     A.IAAPiecewiseAffine(p=0.3),\n            # ], p=0.2),\n            # 归一化\n            A.Normalize(mean, std),\n            # 遮挡\n            A.CoarseDropout(max_holes=8,\n                            max_height=int(CFG.height * 0.1),\n                            max_width=int(CFG.width * 0.1),\n                            p=0.5),\n            ToTensorV2()\n        ])\n    else:\n        return A.Compose([\n            A.Resize(CFG.width, CFG.height),\n            A.Normalize(mean, std),\n            ToTensorV2()\n        ])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-02T08:18:02.976019Z","iopub.execute_input":"2024-12-02T08:18:02.976332Z","iopub.status.idle":"2024-12-02T08:18:02.994233Z","shell.execute_reply.started":"2024-12-02T08:18:02.976308Z","shell.execute_reply":"2024-12-02T08:18:02.993335Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def show_transform_images(imgs, rows, cols):\n    _, axes = plt.subplots(rows, cols, figsize=(rows*2, cols*2))\n    axes = axes.flatten()\n    torch_mean = torch.tensor(mean).view(-1, 1, 1).clone().detach()\n    torch_std = torch.tensor(std).view(-1, 1, 1).clone().detach()\n    for i ,(ax, img) in enumerate(zip(axes, imgs)):\n        img = img * torch_std + torch_mean\n        img = img.permute(1,2,0).numpy()\n        ax.imshow(img)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-02T08:18:02.995328Z","iopub.execute_input":"2024-12-02T08:18:02.995628Z","iopub.status.idle":"2024-12-02T08:18:03.008029Z","shell.execute_reply.started":"2024-12-02T08:18:02.995605Z","shell.execute_reply":"2024-12-02T08:18:03.007215Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# TrainDataSet","metadata":{}},{"cell_type":"code","source":"class TrainDataset(Dataset):\n    def __init__(self, data, transform):\n        self.data = data\n        self.labels = data['target'].values\n        self.id = data['id'].values\n        self.transform = transform\n\n    def __len__(self):\n        return len(self.data)\n\n    def __getitem__(self, index):\n        file_path = f\"/kaggle/input/boolart-image-classification/train_image/{self.id[index]}.jpg\"\n        image = np.array(Image.open(file_path).convert(\"RGB\"))\n        image = self.transform(image=image)['image']\n        \n        label = torch.tensor(self.labels[index]).long()\n        return image, label","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-02T08:18:03.008986Z","iopub.execute_input":"2024-12-02T08:18:03.009306Z","iopub.status.idle":"2024-12-02T08:18:03.027945Z","shell.execute_reply.started":"2024-12-02T08:18:03.009282Z","shell.execute_reply":"2024-12-02T08:18:03.027045Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Model","metadata":{}},{"cell_type":"code","source":"def get_model(model_name, pretrained=False):\n    model = timm.create_model(model_name,pretrained=pretrained)\n    \n    if 'convnext_base' == model_name:\n        model.head.fc = nn.Linear(in_features=1024, out_features=CFG.num_classes, bias=True)\n    if 'convnext_small' == model_name:\n        model.head.fc = nn.Linear(in_features=768, out_features=CFG.num_classes, bias=True)\n    if 'tf_efficientnet_b2' == model_name:\n        model.classifier = nn.Linear(in_features=model.classifier.in_features, out_features=CFG.num_classes,bias=True)\n    return model","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-02T08:18:03.029014Z","iopub.execute_input":"2024-12-02T08:18:03.029566Z","iopub.status.idle":"2024-12-02T08:18:03.364474Z","shell.execute_reply.started":"2024-12-02T08:18:03.029529Z","shell.execute_reply":"2024-12-02T08:18:03.363287Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Criterion","metadata":{}},{"cell_type":"code","source":"def get_criterion(criterion_name):\n    if criterion_name == \"CrossEntropyLoss\":\n        return nn.CrossEntropyLoss()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-02T08:18:03.365776Z","iopub.execute_input":"2024-12-02T08:18:03.366186Z","iopub.status.idle":"2024-12-02T08:18:03.556281Z","shell.execute_reply.started":"2024-12-02T08:18:03.366140Z","shell.execute_reply":"2024-12-02T08:18:03.555147Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Scheduler & Optimizer","metadata":{}},{"cell_type":"code","source":"def get_optimizer_scheduler(model, optimizer_name, scheduler_name):\n    optimizer = None\n    scheduler = None\n    \n    if optimizer_name == \"Adam\":\n        optimizer = Adam(model.parameters(), lr=CFG.lr, weight_decay=CFG.weight_decay)\n    if optimizer_name == \"AdamW\":\n        optimizer = AdamW(model.parameters(), lr=CFG.lr, weight_decay=CFG.weight_decay)\n\n    if scheduler_name == \"CosineAnnealingLR\":\n        scheduler = CosineAnnealingLR(optimizer, T_max=CFG.T_max, eta_min=CFG.min_lr)\n    return optimizer, scheduler","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-02T08:18:03.559821Z","iopub.execute_input":"2024-12-02T08:18:03.560145Z","iopub.status.idle":"2024-12-02T08:18:03.566343Z","shell.execute_reply.started":"2024-12-02T08:18:03.560119Z","shell.execute_reply":"2024-12-02T08:18:03.565460Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Train_fn","metadata":{}},{"cell_type":"code","source":"def train_fn(train_loader, model, criterion, optimizer, epoch, device):\n    if CFG.apex:\n        scaler = GradScaler()\n    model.train()\n    \n    for step,(images, labels) in enumerate(train_loader):\n        images = images.to(device)\n        labels = labels.to(device)\n        y_pres = model(images)\n        loss = criterion(y_pres, labels)\n\n        if CFG.gradient_accumulation_steps > 1:\n            loss = loss /gradient_accumulation_steps\n        if CFG.apex:\n            scaler.scale(loss).backward()\n        else:\n            loss.backward()\n        grad_norm = torch.nn.utils.clip_grad_norm_(model.parameters(), CFG.max_grad_norm)\n        if (step + 1) % CFG.gradient_accumulation_steps == 0:\n            if CFG.apex:\n                scaler.step(optimizer)\n                scaler.update()\n            else:\n                optimizer.step()\n            optimizer.zero_grad()\n        if step % CFG.print_freq == 0 or step == (len(train_loader)-1):\n            print('Epoch: [{0}][{1}/{2}] '\n                  'Loss: {loss:.4f}'\n                  .format(\n                   epoch+1, step, len(train_loader),loss=loss.item(),\n                   )) ","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-02T08:18:03.567584Z","iopub.execute_input":"2024-12-02T08:18:03.567951Z","iopub.status.idle":"2024-12-02T08:18:03.584097Z","shell.execute_reply.started":"2024-12-02T08:18:03.567910Z","shell.execute_reply":"2024-12-02T08:18:03.583292Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Valid_fn","metadata":{}},{"cell_type":"code","source":"def valid_fn(valid_loader, model, criterion, device):\n    model.eval()\n    preds = []\n    acc = 0.0\n    total_loss = 0.0  # 累积总损失\n    num_batches = len(valid_loader)  # 计算有多少个批次\n\n    for step, (images, labels) in enumerate(valid_loader):\n        images = images.to(device)\n        labels = labels.to(device)\n        batch_size = labels.size(0)\n        \n        # TTA\n        with torch.no_grad():\n            outputs1 = model(images)\n            outputs2 = model(images.flip(-1))\n            outputs3 = model(images.flip(-2))\n            outputs4 = model(images.flip([-2, -1]))\n            outputs5 = model(images.flip(-1).flip([-2, -1]))\n            outputs6 = model(images.flip(-2).flip([-2, -1]))\n            outputs = (outputs1 + outputs2 + outputs3 + outputs4 + outputs5 + outputs6) / 6\n\n            loss = criterion(outputs, labels.long())\n            total_loss += loss.item()  # 累积每个 batch 的损失\n\n            _, predict_y = torch.max(outputs, dim=1)\n            acc += (predict_y.to(device) == labels.to(device)).sum().item()\n\n        # measure elapsed time\n        if step % CFG.print_freq == 0 or step == (len(valid_loader)-1):\n            print('EVAL: [{0}/{1}] '\n                  'Loss: {loss:.4f}'\n                  .format(step, len(valid_loader), loss=loss.item(),\n                   ))\n\n    avg_loss = total_loss / num_batches  # 计算整个验证集的平均损失\n    return avg_loss, acc\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-02T08:18:03.585227Z","iopub.execute_input":"2024-12-02T08:18:03.585543Z","iopub.status.idle":"2024-12-02T08:18:03.598968Z","shell.execute_reply.started":"2024-12-02T08:18:03.585508Z","shell.execute_reply":"2024-12-02T08:18:03.598035Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Train","metadata":{}},{"cell_type":"code","source":"def train_pipeline(model, criterion, optimizer, scheduler, device):\n    model.to(device)\n    best_score = 0.\n    best_loss = np.inf\n    for fold_id in range(CFG.used_folds):\n        train_index = train[train['fold'] != fold_id].index\n        valid_index = train[train['fold'] == fold_id].index\n\n        train_folds = train.loc[train_index].reset_index(drop=True)\n        valid_folds = train.loc[valid_index].reset_index(drop=True)\n\n        valid_labels = valid_folds['target'].values\n\n        train_dataset = TrainDataset(train_folds,\n                                     transform=get_transform(isTransform=True))\n        valid_dataset = TrainDataset(valid_folds,\n                                     transform=get_transform(isTransform=False))\n\n        train_loader = DataLoader(train_dataset,\n                                  batch_size=CFG.batch_size,\n                                  shuffle=True,\n                                  num_workers=4, pin_memory=True, drop_last=False)\n        valid_loader = DataLoader(valid_dataset,\n                                  batch_size=CFG.batch_size * 2,\n                                  shuffle=False,\n                                  num_workers=4, pin_memory=True, drop_last=False)\n\n        print(f\"FOLD_ID:{fold_id + 1}\")\n        best_score=0.\n        best_loss=np.inf\n        for epoch in range(CFG.epochs):\n            best_score = 0.\n            best_loss = np.inf\n            # train\n            train_fn(train_loader=train_loader,\n                     model=model,\n                     criterion=criterion,\n                     optimizer=optimizer,\n                     epoch=epoch,\n                     device=device)\n            # eval\n            avg_val_loss, acc = valid_fn(valid_loader=valid_loader,\n                                         model=model,\n                                         criterion=criterion,\n                                         device=device)\n            acc = acc / len(valid_dataset)\n            if isinstance(scheduler, ReduceLROnPlateau):\n                scheduler.step(avg_val_loss)\n            elif isinstance(scheduler, CosineAnnealingLR):\n                scheduler.step()\n            elif isinstance(scheduler, CosineAnnealingWarmRestarts):\n                scheduler.step()\n            print(f\"epoch:{epoch + 1}，acc:{acc}\")\n\n            if acc > best_score:\n                best_score = acc\n                torch.save({'model': model.state_dict(),\n                            'preds': acc},\n                           '/kaggle/working/model' + f'{CFG.model_name}_fold{fold_id + 1}_best_score.pth')\n\n            if avg_val_loss < best_loss:\n                best_loss = avg_val_loss\n                torch.save({'model': model.state_dict(),\n                            'preds': acc},\n                           '/kaggle/working/model' + f'{CFG.model_name}_fold{fold_id + 1}_best_loss.pth')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-02T08:18:03.600241Z","iopub.execute_input":"2024-12-02T08:18:03.600574Z","iopub.status.idle":"2024-12-02T08:18:03.620873Z","shell.execute_reply.started":"2024-12-02T08:18:03.600538Z","shell.execute_reply":"2024-12-02T08:18:03.620128Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"model = get_model(CFG.model_name, pretrained=True)\ncriterion = get_criterion(CFG.criterion_name)\noptimizer ,scheduler = get_optimizer_scheduler(model=model, optimizer_name=CFG.optimizer_name, scheduler_name=CFG.scheduler_name)\nprint(model.default_cfg)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-02T08:18:03.622011Z","iopub.execute_input":"2024-12-02T08:18:03.622372Z","iopub.status.idle":"2024-12-02T08:18:06.108657Z","shell.execute_reply.started":"2024-12-02T08:18:03.622337Z","shell.execute_reply":"2024-12-02T08:18:06.107710Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train_pipeline(model, criterion, optimizer, scheduler, CFG.device)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-02T08:18:06.109767Z","iopub.execute_input":"2024-12-02T08:18:06.110042Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Inference","metadata":{}},{"cell_type":"code","source":"test_data = pd.read_csv('/kaggle/input/boolart-image-classification/sample_submission.csv')\n\nclass TestDataset(Dataset):\n    def __init__(self, data, transform):\n        self.data = data['id'].values\n        self.transform = transform\n\n    def __len__(self):\n        return len(self.data)\n\n    def __getitem__(self, idx):\n        self.file_path = f\"/kaggle/input/boolart-image-classification/test_image/{self.data[idx]}.jpg\"\n        image = np.array(Image.open(self.file_path).convert(\"RGB\"))\n        image = self.transform(image=image)['image']\n        return image,self.data[idx]","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def inference(model, models_path, test_loader, device):\n    pre = []\n    image_id = []\n    for i, (images,img_ids) in enumerate(test_loader):\n        image_id += list(img_ids.numpy())\n        images = images.to(device)\n        for model_path in models_path:\n            model.load_state_dict(torch.load(model_path)['model'])\n            model.to(device)\n            model.eval()\n            with torch.no_grad():\n                y_preds1 = F.softmax(model(images))\n                y_preds2 = F.softmax(model(images.flip(-1)))\n                y_preds3 = F.softmax(model(images.flip(-2)))\n                y_preds4 = F.softmax(model(images.flip([-2, -1])))\n                y_preds5 = F.softmax(model(images.flip(-1).flip([-2, -1])))\n                y_preds6 = F.softmax(model(images.flip(-2).flip([-2, -1])))\n            y_preds = (y_preds1.to('cpu').numpy() + y_preds2.to('cpu').numpy() +\n                       y_preds3.to('cpu').numpy() + y_preds4.to('cpu').numpy() + y_preds5.to(\n                        'cpu').numpy() + y_preds6.to('cpu').numpy()) / 6\n        avg_preds = F.softmax(torch.from_numpy(y_preds),dim=1)\n        _,predict_y = torch.max(avg_preds,dim = 1)\n        predict_y = np.array(predict_y).tolist()\n        pre += predict_y\n    return pre,image_id","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"test_dataset = TestDataset(test_data, transform=get_transform(isTransform=False))\ntest_loader = DataLoader(test_dataset, batch_size=CFG.batch_size, shuffle=False,\n                         num_workers=4, pin_memory=True)\ndef get_best_model(model_name):\n    best_acc = 0.\n    best_model_pth = \"\"\n    for fold_id in range(CFG.used_folds):\n        checkpoint = torch.load('/kaggle/working/model' + f'{model_name}_fold{fold_id + 1}_best_score.pth')\n        if(checkpoint['preds'] > best_acc):\n            best_acc = checkpoint['preds']\n            best_model_pth = '/kaggle/working/model' + f'{model_name}_fold{fold_id + 1}_best_score.pth'\n    return best_model_pth\n        \nbest_model_pth = get_best_model(CFG.model_name)","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"best_model_pth","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"predictions,img_id = inference(model, [best_model_pth], test_loader, CFG.device)","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Submission\n","metadata":{}},{"cell_type":"code","source":"df = pd.DataFrame({\n    \"id\": img_id,\n    \"predict\": predictions\n})\ndf.to_csv(\"./submission.csv\", index=False)\ndf","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}