{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"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":"nvidiaTeslaT4","dataSources":[{"sourceId":52254,"databundleVersionId":9674523,"sourceType":"competition"},{"sourceId":6211844,"sourceType":"datasetVersion","datasetId":3567114}],"isInternetEnabled":false,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"Hi I tried convert Keras team's code to Pytorch including all training pipeline as well.","metadata":{}},{"cell_type":"code","source":"#!pip install iterative-stratification","metadata":{"execution":{"iopub.status.busy":"2024-10-07T14:58:51.219843Z","iopub.execute_input":"2024-10-07T14:58:51.220149Z","iopub.status.idle":"2024-10-07T14:58:51.224727Z","shell.execute_reply.started":"2024-10-07T14:58:51.220116Z","shell.execute_reply":"2024-10-07T14:58:51.223951Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import os\nimport torch\nfrom torch.utils.data import Dataset, DataLoader\nfrom torchvision import transforms\nfrom PIL import Image\nimport torch.optim as optim\nfrom torch import nn\n\n\nimport numpy as np\nimport pandas as pd\nfrom matplotlib import pyplot as plt\nfrom sklearn.model_selection import train_test_split","metadata":{"execution":{"iopub.status.busy":"2024-10-07T14:58:51.226541Z","iopub.execute_input":"2024-10-07T14:58:51.226839Z","iopub.status.idle":"2024-10-07T14:58:58.022404Z","shell.execute_reply.started":"2024-10-07T14:58:51.226807Z","shell.execute_reply":"2024-10-07T14:58:58.021576Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class Config:\n    SEED = 42\n    IMAGE_SIZE = [256, 256]\n    BATCH_SIZE = 32\n    EPOCHS = 100\n    TARGET_COLS  = [\n        \"bowel_injury\", \"extravasation_injury\",\n        \"kidney_healthy\", \"kidney_low\", \"kidney_high\",\n        \"liver_healthy\", \"liver_low\", \"liver_high\",\n        \"spleen_healthy\", \"spleen_low\", \"spleen_high\",\n    ]\n\nconfig = Config()\nprint(f\"Số lượng nhãn mục tiêu: {len(Config.TARGET_COLS)}\")\ntorch.manual_seed(Config.SEED)\n","metadata":{"execution":{"iopub.status.busy":"2024-10-07T14:58:58.023672Z","iopub.execute_input":"2024-10-07T14:58:58.024209Z","iopub.status.idle":"2024-10-07T14:58:58.041721Z","shell.execute_reply.started":"2024-10-07T14:58:58.024167Z","shell.execute_reply":"2024-10-07T14:58:58.040877Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"BASE_PATH = f\"/kaggle/input/rsna-atd-512x512-png-v2-dataset\"","metadata":{"execution":{"iopub.status.busy":"2024-10-07T14:58:58.043983Z","iopub.execute_input":"2024-10-07T14:58:58.044675Z","iopub.status.idle":"2024-10-07T14:58:58.048229Z","shell.execute_reply.started":"2024-10-07T14:58:58.044631Z","shell.execute_reply":"2024-10-07T14:58:58.04735Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# train\ndataframe = pd.read_csv(f\"{BASE_PATH}/train.csv\")\ndataframe[\"image_path\"] = f\"{BASE_PATH}/train_images\"\\\n                    + \"/\" + dataframe.patient_id.astype(str)\\\n                    + \"/\" + dataframe.series_id.astype(str)\\\n                    + \"/\" + dataframe.instance_number.astype(str) +\".png\"\ndataframe = dataframe.drop_duplicates()\n\ndataframe.head(10)","metadata":{"execution":{"iopub.status.busy":"2024-10-07T14:58:58.049535Z","iopub.execute_input":"2024-10-07T14:58:58.050036Z","iopub.status.idle":"2024-10-07T14:58:58.201132Z","shell.execute_reply.started":"2024-10-07T14:58:58.049993Z","shell.execute_reply":"2024-10-07T14:58:58.200223Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Function to handle the split for each group\ndef split_group(group, test_size=0.2):\n    if len(group) == 1:\n        return (group, pd.DataFrame()) if np.random.rand() < test_size else (pd.DataFrame(), group)\n    else:\n        return train_test_split(group, test_size=test_size, random_state=42)\n\n# Initialize the train and validation datasets\ntrain_data = pd.DataFrame()\nval_data = pd.DataFrame()\n\n# Iterate through the groups and split them, handling single-sample groups\nfor _, group in dataframe.groupby(config.TARGET_COLS):\n    train_group, val_group = split_group(group)\n    train_data = pd.concat([train_data, train_group], ignore_index=True)\n    val_data = pd.concat([val_data, val_group], ignore_index=True)","metadata":{"execution":{"iopub.status.busy":"2024-10-07T14:58:58.202242Z","iopub.execute_input":"2024-10-07T14:58:58.202567Z","iopub.status.idle":"2024-10-07T14:58:58.282766Z","shell.execute_reply.started":"2024-10-07T14:58:58.202535Z","shell.execute_reply":"2024-10-07T14:58:58.281867Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_data.shape, val_data.shape","metadata":{"execution":{"iopub.status.busy":"2024-10-07T14:58:58.283876Z","iopub.execute_input":"2024-10-07T14:58:58.284198Z","iopub.status.idle":"2024-10-07T14:58:58.290235Z","shell.execute_reply.started":"2024-10-07T14:58:58.284164Z","shell.execute_reply":"2024-10-07T14:58:58.289189Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"paths  = train_data.image_path.tolist()\nlabels = train_data[config.TARGET_COLS].values\n\nclass CustomDataset(Dataset):\n    def __init__(self, paths, labels, transform=None):\n        self.paths = paths\n        self.labels = labels\n        self.transform = transform\n\n    def __len__(self):\n        return len(self.paths)\n\n    def __getitem__(self, idx):\n        image = Image.open(self.paths[idx]).convert('RGB')\n        label = torch.tensor(self.labels[idx], dtype=torch.float32)\n\n        if self.transform:\n            image = self.transform(image)\n\n        return image, label\n\n# Define any image transformations you want to apply, here we also add augmentation. \ntransform = transforms.Compose([\n    transforms.Resize((256, 256)),\n    transforms.RandomResizedCrop(256),   # Random crop and resize\n    transforms.RandomHorizontalFlip(),    # Random horizontal flip\n    transforms.ColorJitter(brightness=0.2, contrast=0.2, saturation=0.2, hue=0.1),  # Color jitter\n    transforms.ToTensor(),\n    transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]),\n])","metadata":{"execution":{"iopub.status.busy":"2024-10-07T14:58:58.291474Z","iopub.execute_input":"2024-10-07T14:58:58.291757Z","iopub.status.idle":"2024-10-07T14:58:58.302455Z","shell.execute_reply.started":"2024-10-07T14:58:58.291726Z","shell.execute_reply":"2024-10-07T14:58:58.301703Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":" #Dataloader setup\ntrain_paths = train_data.image_path.tolist()\ntrain_labels = train_data[config.TARGET_COLS].values\nval_paths = val_data.image_path.tolist()\nval_labels = val_data[config.TARGET_COLS].values\n\ndataset_train = CustomDataset(train_paths, train_labels, transform=transform)\ntrain_dataloader = DataLoader(dataset_train, batch_size=config.BATCH_SIZE, shuffle=True)\n\ndataset_val = CustomDataset(val_paths, val_labels, transform=transform)\nval_dataloader = DataLoader(dataset_val, batch_size=config.BATCH_SIZE, shuffle=True)\n\n","metadata":{"execution":{"iopub.status.busy":"2024-10-07T14:58:58.306212Z","iopub.execute_input":"2024-10-07T14:58:58.306527Z","iopub.status.idle":"2024-10-07T14:58:58.317515Z","shell.execute_reply.started":"2024-10-07T14:58:58.306489Z","shell.execute_reply":"2024-10-07T14:58:58.316814Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Dataloader setup\ntrain_paths = train_data.image_path.tolist()\ntrain_labels = train_data[config.TARGET_COLS].values\nval_paths = val_data.image_path.tolist()\nval_labels = val_data[config.TARGET_COLS].values\n\ndataset_train = CustomDataset(train_paths, train_labels, transform=transform)\ntrain_dataloader = DataLoader(dataset_train, batch_size=config.BATCH_SIZE, shuffle=True)\n\ndataset_val = CustomDataset(val_paths, val_labels, transform=transform)\nval_dataloader = DataLoader(dataset_val, batch_size=config.BATCH_SIZE, shuffle=True)\n\n","metadata":{"execution":{"iopub.status.busy":"2024-10-07T14:58:58.318582Z","iopub.execute_input":"2024-10-07T14:58:58.318876Z","iopub.status.idle":"2024-10-07T14:58:58.330254Z","shell.execute_reply.started":"2024-10-07T14:58:58.318845Z","shell.execute_reply":"2024-10-07T14:58:58.329474Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Residual Block Definition\nclass ResidualBlock(nn.Module):\n    def __init__(self, in_channels, out_channels, stride=1):\n        super(ResidualBlock, self).__init__()\n        self.conv1 = nn.Conv2d(in_channels, out_channels, kernel_size=3, stride=stride, padding=1)\n        self.bn1 = nn.BatchNorm2d(out_channels)\n        self.relu = nn.ReLU(inplace=True)\n        self.conv2 = nn.Conv2d(out_channels, out_channels, kernel_size=3, padding=1)\n        self.bn2 = nn.BatchNorm2d(out_channels)\n\n        # If the input and output channels do not match, apply a 1x1 convolution\n        self.shortcut = nn.Sequential()\n        if stride != 1 or in_channels != out_channels:\n            self.shortcut = nn.Sequential(\n                nn.Conv2d(in_channels, out_channels, kernel_size=1, stride=stride),\n                nn.BatchNorm2d(out_channels)\n            )\n\n    def forward(self, x):\n        identity = x\n        out = self.conv1(x)\n        out = self.bn1(out)\n        out = self.relu(out)\n        out = self.conv2(out)\n        out = self.bn2(out)\n\n        # Add the shortcut to the output\n        out += self.shortcut(identity)\n        out = self.relu(out)\n        return out\n\n# Residual CNN Model Definition\nclass ResidualCNN(nn.Module):\n    def __init__(self, num_classes):\n        super(ResidualCNN, self).__init__()\n        self.conv1 = nn.Conv2d(3, 64, kernel_size=3, stride=1, padding=1)\n        self.bn1 = nn.BatchNorm2d(64)\n        self.relu = nn.ReLU(inplace=True)\n        \n        # Residual Blocks\n        self.res_block1 = ResidualBlock(64, 64)\n        self.res_block2 = ResidualBlock(64, 128, stride=2)\n        self.res_block3 = ResidualBlock(128, 256, stride=2)\n        self.res_block4 = ResidualBlock(256, 512, stride=2)\n\n        # Fully connected layers\n        self.fc = nn.Linear(512 * (256 // 32) * (256 // 32), num_classes)\n\n    def forward(self, x):\n        x = self.conv1(x)\n        x = self.bn1(x)\n        x = self.relu(x)\n\n        # Residual blocks\n        x = self.res_block1(x)\n        x = self.res_block2(x)\n        x = self.res_block3(x)\n        x = self.res_block4(x)\n\n        # Global average pooling (optional)\n        x = nn.functional.adaptive_avg_pool2d(x, (1, 1))\n\n        # Flatten the output\n        x = torch.flatten(x, 1)\n        x = self.fc(x)\n        return x\n\n# Check if GPU is available\ndevice = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\nprint(f\"Using device: {device}\")\n\n# Model, criterion, optimizer, and scheduler\nmodel = ResidualCNN(num_classes=len(config.TARGET_COLS)).to(device)\ncriterion = nn.BCEWithLogitsLoss()\noptimizer = torch.optim.Adam(model.parameters(), lr=1e-5)\nscheduler = torch.optim.lr_scheduler.CosineAnnealingLR(optimizer, T_max=config.EPOCHS)\n\n","metadata":{"execution":{"iopub.status.busy":"2024-10-07T14:58:58.331385Z","iopub.execute_input":"2024-10-07T14:58:58.331733Z","iopub.status.idle":"2024-10-07T14:58:58.762328Z","shell.execute_reply.started":"2024-10-07T14:58:58.3317Z","shell.execute_reply":"2024-10-07T14:58:58.760717Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Loading Data","metadata":{}},{"cell_type":"code","source":"for img, label in train_dataloader:\n  print(img.shape)\n  break","metadata":{"execution":{"iopub.status.busy":"2024-10-07T14:58:58.764916Z","iopub.execute_input":"2024-10-07T14:58:58.765961Z","iopub.status.idle":"2024-10-07T14:58:59.556215Z","shell.execute_reply.started":"2024-10-07T14:58:58.765878Z","shell.execute_reply":"2024-10-07T14:58:59.555141Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#a function to display images\ndef show_images(images, labels):\n    fig, axes = plt.subplots(1, len(images), figsize=(15, 5))\n    for idx, (image, label) in enumerate(zip(images, labels)):\n        image = image.permute(1, 2, 0)  # Convert from (C, H, W) to (H, W, C) for displaying\n        axes[idx].imshow(image)\n        label_str = \", \".join([str(val) for val in label])  # Convert label tensor to string\n        axes[idx].set_title(f\"Labels: {label_str}\")\n        axes[idx].axis(\"off\")\n    plt.show()\n\n# Load a few images for visualization\nnum_images_to_display = 5\nsample_indices = torch.randint(len(dataset_train), size=(num_images_to_display,))\nsample_images = [dataset_train[i][0] for i in sample_indices]\nsample_labels = [dataset_train[i][1] for i in sample_indices]\n\n# Convert label tensors to numpy arrays for display\nsample_labels_np = [label.numpy() for label in sample_labels]\n\n# Display the sample images\nshow_images(sample_images, sample_labels_np)","metadata":{"execution":{"iopub.status.busy":"2024-10-07T14:58:59.557477Z","iopub.execute_input":"2024-10-07T14:58:59.557843Z","iopub.status.idle":"2024-10-07T14:59:00.290474Z","shell.execute_reply.started":"2024-10-07T14:58:59.557805Z","shell.execute_reply":"2024-10-07T14:59:00.289613Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class SimpleCNN(nn.Module):\n    def __init__(self, num_classes=11):\n        super(SimpleCNN, self).__init__()\n        \n        self.conv_layers = nn.Sequential(\n            nn.Conv2d(in_channels=3, out_channels=32, kernel_size=5, stride=1, padding=1),\n            nn.ReLU(),\n            nn.MaxPool2d(kernel_size=2, stride=2),\n            \n            nn.Conv2d(in_channels=32, out_channels=64, kernel_size=5, stride=1, padding=1),\n            nn.ReLU(),\n            nn.MaxPool2d(kernel_size=2, stride=2),\n            \n            nn.Conv2d(in_channels=64, out_channels=128, kernel_size=5, stride=1, padding=1),\n            nn.ReLU(),\n            nn.MaxPool2d(kernel_size=2, stride=2)\n        )\n        \n        # Temporary dummy input to compute the size of the flattened output\n        dummy_input = torch.randn(1, 3, 256, 256)  # A single input image of size (256, 256)\n        conv_output = self.conv_layers(dummy_input)\n        flattened_size = conv_output.view(1, -1).size(1)  # Flatten the conv output\n        \n        print(f\"Flattened size: {flattened_size}\")  # Inspect the flattened size\n        \n        # Use the computed flattened size for the Linear layer\n        self.fc_layers = nn.Sequential(\n            nn.Linear(flattened_size, 128),\n            nn.ReLU(),\n            nn.Linear(128, num_classes)\n        )\n        \n    def forward(self, x):\n        x = self.conv_layers(x)\n        x = x.view(x.size(0), -1)  # Flatten the output for the fully connected layers\n        x = self.fc_layers(x)\n        return x\n\n# Initialize the model to print the flattened size\nmodel = SimpleCNN(num_classes=len(config.TARGET_COLS)).to(device)\n","metadata":{"execution":{"iopub.status.busy":"2024-10-07T14:59:00.291688Z","iopub.execute_input":"2024-10-07T14:59:00.292005Z","iopub.status.idle":"2024-10-07T14:59:00.574334Z","shell.execute_reply.started":"2024-10-07T14:59:00.291972Z","shell.execute_reply":"2024-10-07T14:59:00.573356Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from sklearn.model_selection import KFold\n# Số lượng folds\nK = 4  # Bạn có thể chọn 5 hoặc 10 tùy ý\n\n# Khởi tạo K-Fold splitter\nkf = KFold(n_splits=K, shuffle=True, random_state=config.SEED)\n\n# Chuẩn bị dữ liệu\nX = dataframe.image_path.values\ny = dataframe[config.TARGET_COLS].values\n\n# Khởi tạo danh sách để lưu trữ các chỉ số và metric của từng fold\nfold_train_losses = []\nfold_val_losses = []\nfold_val_accuracies = []\nfold_val_f1_scores = []","metadata":{"execution":{"iopub.status.busy":"2024-10-07T14:59:00.575598Z","iopub.execute_input":"2024-10-07T14:59:00.57597Z","iopub.status.idle":"2024-10-07T14:59:00.583281Z","shell.execute_reply.started":"2024-10-07T14:59:00.575937Z","shell.execute_reply":"2024-10-07T14:59:00.582345Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Chia dữ liệu cho từng fold\nfor fold, (train_idx, val_idx) in enumerate(kf.split(X)):\n    X_train, X_val = X[train_idx], X[val_idx]\n    y_train, y_val = y[train_idx], y[val_idx]\n\n    # Tạo dataset và dataloader cho fold hiện tại\n    train_dataset = CustomDataset(paths=X_train, labels=y_train, transform=transform)\n    val_dataset = CustomDataset(paths=X_val, labels=y_val, transform=transform)\n\n    train_dataloader = DataLoader(train_dataset, batch_size=16, shuffle=True, num_workers=4, pin_memory=True)\n    val_dataloader = DataLoader(val_dataset, batch_size=16, shuffle=False, num_workers=4, pin_memory=True)\n\n    # Huấn luyện và đánh giá cho fold hiện tại\n    for epoch in range(config.EPOCHS):\n        # Vòng lặp huấn luyện và validation tương tự như trước\n        ...\n","metadata":{"execution":{"iopub.status.busy":"2024-10-07T14:59:00.584483Z","iopub.execute_input":"2024-10-07T14:59:00.584793Z","iopub.status.idle":"2024-10-07T14:59:00.604168Z","shell.execute_reply.started":"2024-10-07T14:59:00.584759Z","shell.execute_reply":"2024-10-07T14:59:00.603157Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Kiểm tra nếu có GPU thì sử dụng, nếu không sẽ sử dụng CPU\ndevice = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\nprint(f\"Using device: {device}\")","metadata":{"execution":{"iopub.status.busy":"2024-10-07T14:59:00.605361Z","iopub.execute_input":"2024-10-07T14:59:00.605662Z","iopub.status.idle":"2024-10-07T14:59:00.61158Z","shell.execute_reply.started":"2024-10-07T14:59:00.605625Z","shell.execute_reply":"2024-10-07T14:59:00.610536Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model = SimpleCNN(num_classes=len(config.TARGET_COLS)).to(device)\ncriterion = nn.BCEWithLogitsLoss()\noptimizer = torch.optim.Adam(model.parameters(), lr=1e-4)\nscheduler = torch.optim.lr_scheduler.CosineAnnealingLR(optimizer, T_max=config.EPOCHS)\nscaler = torch.amp.GradScaler(\"cuda\")  # Sử dụng cho mixed precision","metadata":{"execution":{"iopub.status.busy":"2024-10-07T14:59:00.612763Z","iopub.execute_input":"2024-10-07T14:59:00.613059Z","iopub.status.idle":"2024-10-07T14:59:00.805301Z","shell.execute_reply.started":"2024-10-07T14:59:00.613025Z","shell.execute_reply":"2024-10-07T14:59:00.804219Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"accumulation_steps = 4  # Accumulate gradients over 4 batches\n\nfor i, (images, labels) in enumerate(train_dataloader):\n    images, labels = images.to(device), labels.to(device)\n\n    with torch.amp.autocast(device_type=device.type):\n        outputs = model(images)\n        loss = criterion(outputs, labels) / accumulation_steps  # Accumulate loss\n\n    scaler.scale(loss).backward()\n\n    # Only step optimizer after accumulation\n    if (i + 1) % accumulation_steps == 0:\n        scaler.unscale_(optimizer)  # Unscale gradients before optimizer step\n        scaler.step(optimizer)\n        scaler.update()\n        optimizer.zero_grad()\n\n# After the last batch, check for remaining gradient updates\nif (i + 1) % accumulation_steps != 0:\n    scaler.unscale_(optimizer)\n    scaler.step(optimizer)\n    scaler.update()\n    optimizer.zero_grad()\n","metadata":{"execution":{"iopub.status.busy":"2024-10-07T14:59:00.806721Z","iopub.execute_input":"2024-10-07T14:59:00.807197Z","iopub.status.idle":"2024-10-07T14:59:56.791419Z","shell.execute_reply.started":"2024-10-07T14:59:00.807152Z","shell.execute_reply":"2024-10-07T14:59:56.790186Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import torch.utils.checkpoint as checkpoint\n\ndef forward(self, x):\n    x = checkpoint.checkpoint(self.conv_layers, x)\n    x = x.view(x.size(0), -1)\n    x = checkpoint.checkpoint(self.fc_layers, x)\n    return x\nif (epoch + 1) % 10 == 0:  # Lưu sau mỗi 10 epoch\n    torch.save(model.state_dict(), f\"model_checkpoint_epoch_{epoch+1}.pth\")\n","metadata":{"execution":{"iopub.status.busy":"2024-10-07T14:59:56.792983Z","iopub.execute_input":"2024-10-07T14:59:56.793451Z","iopub.status.idle":"2024-10-07T14:59:56.918859Z","shell.execute_reply.started":"2024-10-07T14:59:56.793403Z","shell.execute_reply":"2024-10-07T14:59:56.917867Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from sklearn.metrics import f1_score\n\n# ...\n# Training and validation loop\nfor epoch in range(config.EPOCHS):\n    model.train()\n    running_loss = 0.0\n    optimizer.zero_grad()\n\n    for i, (images, labels) in enumerate(train_dataloader):\n        images, labels = images.to(device), labels.to(device)\n\n        with torch.amp.autocast(device_type=device.type):\n            outputs = model(images)\n            loss = criterion(outputs, labels)\n        \n        scaler.scale(loss).backward()\n\n        if (i + 1) % 4 == 0:\n            scaler.step(optimizer)\n            scaler.update()\n            optimizer.zero_grad()\n\n        running_loss += loss.item() * images.size(0)\n\n    epoch_train_loss = running_loss / len(train_dataloader.dataset)\n\n    # Validation\n    model.eval()\n    val_loss, correct, total = 0.0, 0, 0\n    all_preds, all_targets = [], []\n\n    with torch.no_grad():\n        for images, labels in val_dataloader:\n            images, labels = images.to(device), labels.to(device)\n\n            with torch.amp.autocast(device_type=device.type):\n                outputs = model(images)\n                loss = criterion(outputs, labels)\n\n            val_loss += loss.item() * images.size(0)\n            preds = torch.sigmoid(outputs) > 0.5\n            correct += (preds.int() == labels.int()).sum().item()\n            total += labels.numel()\n\n            all_preds.append(preds.cpu().numpy())\n            all_targets.append(labels.cpu().numpy())\n\n    epoch_val_loss = val_loss / len(val_dataloader.dataset)\n    epoch_val_accuracy = 100.0 * correct / total\n    all_preds_np = np.vstack(all_preds)\n    all_targets_np = np.vstack(all_targets)\n    epoch_f1 = f1_score(all_targets_np, all_preds_np, average='macro')\n\n    print(f\"Epoch [{epoch + 1}/{config.EPOCHS}] - Train Loss: {epoch_train_loss:.4f} - Val Loss: {epoch_val_loss:.4f} - Val Acc: {epoch_val_accuracy:.2f}% - Val F1: {epoch_f1:.4f}\")","metadata":{"execution":{"iopub.status.busy":"2024-10-07T14:59:56.920601Z","iopub.execute_input":"2024-10-07T14:59:56.921166Z","iopub.status.idle":"2024-10-07T16:46:51.42465Z","shell.execute_reply.started":"2024-10-07T14:59:56.9211Z","shell.execute_reply":"2024-10-07T16:46:51.423582Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import matplotlib.pyplot as plt\nimport numpy as np\n\n# Set the model to evaluation mode\nmodel.eval()\n\n# Select a random image from the validation dataset\nrandom_index = np.random.randint(len(dataset_val))\nimage, label = dataset_val[random_index]\n\n# Move the image to the GPU if available\nimage = image.to('cuda')\n\n# Pass the image through the model\nwith torch.no_grad():\n    output = model(image.unsqueeze(0))  # Unsqueeze to add batch dimension\n\n# Convert the output logits to probabilities using sigmoid function\npredicted_probs = torch.sigmoid(output)[0]\n\n# Convert predicted probabilities to binary predictions\npredicted_labels = (predicted_probs > 0.5).int()\n\n\n# Display the image, actual labels, and predicted labels\nplt.imshow(image.permute(1, 2, 0).cpu())  # Move image to CPU and change channel order\n#plt.title(f\"Actual Labels: {label}\\nPredicted Labels: {predicted_labels}\")\nplt.title(f\"Actual Labels: {label}\\nPredicted Labels: {predicted_labels}\")\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2024-10-07T16:46:51.426153Z","iopub.execute_input":"2024-10-07T16:46:51.426508Z","iopub.status.idle":"2024-10-07T16:46:51.848735Z","shell.execute_reply.started":"2024-10-07T16:46:51.426469Z","shell.execute_reply":"2024-10-07T16:46:51.84782Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df_sub = pd.read_csv(\"/kaggle/input/rsna-atd-512x512-png-v2-dataset/sample_submission.csv\")\ndf_sub","metadata":{"execution":{"iopub.status.busy":"2024-10-07T16:46:51.849977Z","iopub.execute_input":"2024-10-07T16:46:51.850259Z","iopub.status.idle":"2024-10-07T16:46:51.876806Z","shell.execute_reply.started":"2024-10-07T16:46:51.850228Z","shell.execute_reply":"2024-10-07T16:46:51.875974Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"submission_paths= [\"/kaggle/input/rsna-atd-512x512-png-v2-dataset/test_images/48843/62825/30.png\",\n                \"/kaggle/input/rsna-atd-512x512-png-v2-dataset/test_images/50046/24574/30.png\",\n                \"/kaggle/input/rsna-atd-512x512-png-v2-dataset/test_images/63706/39279/30.png\"\n               ]\nid_list = [48843, 50046, 63706]","metadata":{"execution":{"iopub.status.busy":"2024-10-07T16:46:51.881647Z","iopub.execute_input":"2024-10-07T16:46:51.88196Z","iopub.status.idle":"2024-10-07T16:46:51.886408Z","shell.execute_reply.started":"2024-10-07T16:46:51.881926Z","shell.execute_reply":"2024-10-07T16:46:51.885581Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#random_seed = 42  # You can use any number\n#np.random.seed(random_seed)\n\nimport torch.nn.functional as F\ndef predict_classes(image_paths):\n    predictions = []\n    for image_path in image_paths:\n        image = Image.open(image_path).convert('RGB')\n        input_image = transform(image).unsqueeze(0).to(\"cuda\")\n        with torch.no_grad():\n            output = model(input_image)\n        predicted_probs = F.sigmoid(output)[0]\n        predicted_class_index = (predicted_probs > 0.5).int()\n        predictions.append({'Image Path': image_path, 'Predicted Class Index': predicted_class_index.cpu().numpy()})\n    return pd.DataFrame(predictions)\n\ndf = predict_classes(submission_paths)\ndf[\"patient_id\"] = id_list\ndf[config.TARGET_COLS] = df['Predicted Class Index'].apply(pd.Series)\ndf.drop([\"Image Path\", \"Predicted Class Index\"], axis=1, inplace=True)","metadata":{"execution":{"iopub.status.busy":"2024-10-07T16:46:51.887536Z","iopub.execute_input":"2024-10-07T16:46:51.887839Z","iopub.status.idle":"2024-10-07T16:46:51.982193Z","shell.execute_reply.started":"2024-10-07T16:46:51.887805Z","shell.execute_reply":"2024-10-07T16:46:51.981335Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df","metadata":{"execution":{"iopub.status.busy":"2024-10-07T16:46:51.98325Z","iopub.execute_input":"2024-10-07T16:46:51.983564Z","iopub.status.idle":"2024-10-07T16:46:51.995506Z","shell.execute_reply.started":"2024-10-07T16:46:51.983532Z","shell.execute_reply":"2024-10-07T16:46:51.994453Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Khởi tạo fold_organ_accuracies ngoài vòng lặp epoch để chỉ khởi tạo một lần\nfold_organ_accuracies = { organ: [] for organ in [\"Bowel\", \"Extravasation\", \"Liver\", \"Kidney\", \"Spleen\"] }\n\n# Validation loop\nmodel.eval()\nval_loss, correct, total = 0.0, 0, 0\ncorrect_per_organ = { \"Bowel\": 0, \"Extravasation\": 0, \"Liver\": 0, \"Kidney\": 0, \"Spleen\": 0 }\ntotal_per_organ = { \"Bowel\": 0, \"Extravasation\": 0, \"Liver\": 0, \"Kidney\": 0, \"Spleen\": 0 }\n\nwith torch.no_grad():\n    for images, labels in val_dataloader:\n        images, labels = images.to(device), labels.to(device)\n\n        # Sử dụng cú pháp mới của autocast trong validation\n        with torch.amp.autocast(device_type=device.type):\n            outputs = model(images)\n            loss = criterion(outputs, labels)\n\n        val_loss += loss.item() * images.size(0)\n\n        preds = torch.sigmoid(outputs) > 0.5\n\n        # Cập nhật đúng và tổng số cho từng bộ phận\n        for organ_idx, organ_name in enumerate([\"Bowel\", \"Extravasation\", \"Liver\", \"Kidney\", \"Spleen\"]):\n            correct_per_organ[organ_name] += (preds[:, organ_idx].int() == labels[:, organ_idx].int()).sum().item()\n            total_per_organ[organ_name] += labels[:, organ_idx].numel()\n\n# Tính toán accuracy cho từng bộ phận\naccuracies_per_organ = { organ: 100.0 * correct_per_organ[organ] / total_per_organ[organ] for organ in correct_per_organ }","metadata":{"execution":{"iopub.status.busy":"2024-10-07T16:46:51.996821Z","iopub.execute_input":"2024-10-07T16:46:51.997106Z","iopub.status.idle":"2024-10-07T16:47:08.119821Z","shell.execute_reply.started":"2024-10-07T16:46:51.997074Z","shell.execute_reply":"2024-10-07T16:47:08.118525Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# In ra độ chính xác (accuracy) cho từng bộ phận sau mỗi epoch\nfor organ, accuracy in accuracies_per_organ.items():\n    print(f\"{organ} Accuracy: {accuracy:.2f}%\")","metadata":{"execution":{"iopub.status.busy":"2024-10-07T16:47:08.121519Z","iopub.execute_input":"2024-10-07T16:47:08.12247Z","iopub.status.idle":"2024-10-07T16:47:08.127875Z","shell.execute_reply.started":"2024-10-07T16:47:08.122409Z","shell.execute_reply":"2024-10-07T16:47:08.126962Z"},"trusted":true},"execution_count":null,"outputs":[]}]}