{"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":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-14T05:58:51.434891Z","iopub.execute_input":"2024-11-14T05:58:51.435361Z","iopub.status.idle":"2024-11-14T05:58:51.440115Z","shell.execute_reply.started":"2024-11-14T05:58:51.435318Z","shell.execute_reply":"2024-11-14T05:58:51.438959Z"}},"outputs":[],"execution_count":null},{"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":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-14T05:58:51.444992Z","iopub.execute_input":"2024-11-14T05:58:51.44583Z","iopub.status.idle":"2024-11-14T05:58:51.452017Z","shell.execute_reply.started":"2024-11-14T05:58:51.445765Z","shell.execute_reply":"2024-11-14T05:58:51.451052Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class Config:\n    SEED = 42\n    IMAGE_SIZE = [256, 256]\n    BATCH_SIZE = 32\n    EPOCHS = 200\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":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-14T05:58:51.456219Z","iopub.execute_input":"2024-11-14T05:58:51.456564Z","iopub.status.idle":"2024-11-14T05:58:51.467724Z","shell.execute_reply.started":"2024-11-14T05:58:51.456516Z","shell.execute_reply":"2024-11-14T05:58:51.466694Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"BASE_PATH = f\"/kaggle/input/rsna-atd-512x512-png-v2-dataset\"","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-14T05:58:51.469454Z","iopub.execute_input":"2024-11-14T05:58:51.469834Z","iopub.status.idle":"2024-11-14T05:58:51.475617Z","shell.execute_reply.started":"2024-11-14T05:58:51.469782Z","shell.execute_reply":"2024-11-14T05:58:51.474688Z"}},"outputs":[],"execution_count":null},{"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":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-14T05:58:51.477314Z","iopub.execute_input":"2024-11-14T05:58:51.477808Z","iopub.status.idle":"2024-11-14T05:58:51.595288Z","shell.execute_reply.started":"2024-11-14T05:58:51.477762Z","shell.execute_reply":"2024-11-14T05:58:51.59419Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"#Using histogram to get the distribution of the labels and to check if there are outliers and wrong labels\ndataframe.hist(figsize=(20,12),bins=2)\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-14T09:52:38.726676Z","iopub.execute_input":"2024-11-14T09:52:38.727427Z","iopub.status.idle":"2024-11-14T09:52:41.799314Z","shell.execute_reply.started":"2024-11-14T09:52:38.727388Z","shell.execute_reply":"2024-11-14T09:52:41.798351Z"}},"outputs":[],"execution_count":null},{"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":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-14T05:58:51.597197Z","iopub.execute_input":"2024-11-14T05:58:51.597552Z","iopub.status.idle":"2024-11-14T05:58:51.693785Z","shell.execute_reply.started":"2024-11-14T05:58:51.597507Z","shell.execute_reply":"2024-11-14T05:58:51.692649Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train_data.shape, val_data.shape","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-14T05:58:51.69503Z","iopub.execute_input":"2024-11-14T05:58:51.695403Z","iopub.status.idle":"2024-11-14T05:58:51.702395Z","shell.execute_reply.started":"2024-11-14T05:58:51.695366Z","shell.execute_reply":"2024-11-14T05:58:51.701213Z"}},"outputs":[],"execution_count":null},{"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":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-14T05:58:51.704984Z","iopub.execute_input":"2024-11-14T05:58:51.705498Z","iopub.status.idle":"2024-11-14T05:58:51.718333Z","shell.execute_reply.started":"2024-11-14T05:58:51.705438Z","shell.execute_reply":"2024-11-14T05:58:51.717213Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# get image_paths and labels\nprint(\"[INFO] Building the dataset...\")\n\ntrain_paths  = train_data.image_path.tolist()\ntrain_labels = train_data[config.TARGET_COLS].values\n\nval_paths  = val_data.image_path.tolist()\nval_labels = val_data[config.TARGET_COLS].values\n\n\n#torch dataset\nbatch_size = 32\n\n# Create the datasets\n\ndataset_train = CustomDataset(train_paths, train_labels, transform=transform)\ntrain_dataloader = DataLoader(dataset_train, batch_size=batch_size, shuffle=True)\n\n\ndataset_val = CustomDataset(val_paths, val_labels, transform=transform)\nval_dataloader = DataLoader(dataset_val, batch_size=batch_size, shuffle=True)\n\n\n# Define your dataset size and other configuration parameters\ndataset_size = len(dataset_train)  # Assuming you have defined 'dataset' earlier\nbatch_size = 32  # Your batch size\ntotal_epochs = 50  # Total number of epochs\n\n# Calculate total train steps\ntotal_train_steps = dataset_size * batch_size * total_epochs\n\n# Define warmup steps as 10% of total train steps\nwarmup_steps = int(total_train_steps * 0.10)\n\n# Define decay steps as the remaining steps after warmup\ndecay_steps = total_train_steps - warmup_steps\n\nprint(f\"Total Train Steps: {total_train_steps}\")\nprint(f\"Warmup Steps: {warmup_steps}\")\nprint(f\"Decay Steps: {decay_steps}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-14T05:58:51.71975Z","iopub.execute_input":"2024-11-14T05:58:51.720186Z","iopub.status.idle":"2024-11-14T05:58:51.734381Z","shell.execute_reply.started":"2024-11-14T05:58:51.720118Z","shell.execute_reply":"2024-11-14T05:58:51.733219Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Loading Data","metadata":{}},{"cell_type":"code","source":"for img, label in train_dataloader:\n  print(img.shape)\n  break","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-14T05:58:51.735648Z","iopub.execute_input":"2024-11-14T05:58:51.736053Z","iopub.status.idle":"2024-11-14T05:58:52.219821Z","shell.execute_reply.started":"2024-11-14T05:58:51.736005Z","shell.execute_reply":"2024-11-14T05:58:52.218703Z"}},"outputs":[],"execution_count":null},{"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":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-14T05:58:52.221311Z","iopub.execute_input":"2024-11-14T05:58:52.221746Z","iopub.status.idle":"2024-11-14T05:58:52.926664Z","shell.execute_reply.started":"2024-11-14T05:58:52.221694Z","shell.execute_reply":"2024-11-14T05:58:52.925637Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import torch\nimport torch.nn as nn\n\nclass ChannelAttention(nn.Module):\n    def __init__(self, channel):\n        super(ChannelAttention, self).__init__()\n        self.fc1 = nn.Linear(channel, channel // 16)\n        self.fc2 = nn.Linear(channel // 16, channel)\n\n    def forward(self, x):\n        # Kích thước đầu vào: (batch_size, channels, height, width)\n        avg_pool = x.mean(dim=(2, 3))  # Kích thước: (batch_size, channels)\n        max_pool = x.max(dim=2)[0].max(dim=2)[0]  # Kích thước: (batch_size, channels)\n        \n        # Kích thước: (batch_size, channels) \n        channel_attention = torch.sigmoid(self.fc2(torch.relu(self.fc1(avg_pool))) + self.fc2(torch.relu(self.fc1(max_pool))))\n        \n        return x * channel_attention.view(x.size(0), -1, 1, 1)\n\nclass SpatialAttention(nn.Module):\n    def __init__(self):\n        super(SpatialAttention, self).__init__()\n        self.conv = nn.Conv2d(2, 1, kernel_size=7, padding=3)\n\n    def forward(self, x):\n        avg_pool = x.mean(dim=1, keepdim=True)\n        max_pool = x.max(dim=1, keepdim=True)[0]\n        spatial_attention = torch.cat([avg_pool, max_pool], dim=1)\n        spatial_attention = torch.sigmoid(self.conv(spatial_attention))\n        return x * spatial_attention\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-14T05:58:52.92805Z","iopub.execute_input":"2024-11-14T05:58:52.928422Z","iopub.status.idle":"2024-11-14T05:58:52.939501Z","shell.execute_reply.started":"2024-11-14T05:58:52.928385Z","shell.execute_reply":"2024-11-14T05:58:52.938611Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class SimpleCNN(nn.Module):\n    def __init__(self, num_classes=11):\n        super(SimpleCNN, self).__init__()\n\n        # Khối tích chập 1\n        self.conv1 = nn.Sequential(\n            nn.Conv2d(in_channels=3, out_channels=32, kernel_size=5, stride=1, padding=1),  # 3 kênh cho ảnh RGB\n            nn.ReLU(),\n            nn.MaxPool2d(kernel_size=2, stride=2),\n        )\n\n        # Channel Attention và Spatial Attention cho khối 1\n        self.channel_attention1 = ChannelAttention(32)\n        self.spatial_attention1 = SpatialAttention()\n\n        # Khối tích chập 2\n        self.conv2 = nn.Sequential(\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        self.channel_attention2 = ChannelAttention(64)\n        self.spatial_attention2 = SpatialAttention()\n\n        # Khối tích chập 3\n        self.conv3 = nn.Sequential(\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        self.channel_attention3 = ChannelAttention(128)\n        self.spatial_attention3 = SpatialAttention()\n\n        # Tính toán kích thước sau các lớp tích chập\n        dummy_input = torch.randn(1, 3, 256, 256)  # Đảm bảo đầu vào giả có 3 kênh\n        conv_output = self.conv3(self.conv2(self.conv1(dummy_input)))  # Qua ba khối tích chập\n        flattened_size = conv_output.view(1, -1).size(1)  # Kích thước sau khi flatten\n\n        # Fully connected layers\n        self.fc_layers = nn.Sequential(\n            nn.Linear(flattened_size, 128),  # Kích thước đầu vào là flattened_size\n            nn.ReLU(),\n            nn.Linear(128, num_classes)\n        )\n\n    def forward(self, x):\n        # Conv1 + Attention\n        x = self.conv1(x)\n        x = self.channel_attention1(x)\n        x = self.spatial_attention1(x)\n\n        # Conv2 + Attention\n        x = self.conv2(x)\n        x = self.channel_attention2(x)\n        x = self.spatial_attention2(x)\n\n        # Conv3 + Attention\n        x = self.conv3(x)\n        x = self.channel_attention3(x)\n        x = self.spatial_attention3(x)\n\n        # Flatten and fully connected\n        x = x.view(x.size(0), -1)  # Flatten\n        x = self.fc_layers(x)  # Fully connected\n        return x","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-14T05:58:52.940913Z","iopub.execute_input":"2024-11-14T05:58:52.941314Z","iopub.status.idle":"2024-11-14T05:58:52.956101Z","shell.execute_reply.started":"2024-11-14T05:58:52.941256Z","shell.execute_reply":"2024-11-14T05:58:52.955193Z"}},"outputs":[],"execution_count":null},{"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":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-14T05:58:52.959795Z","iopub.execute_input":"2024-11-14T05:58:52.960104Z","iopub.status.idle":"2024-11-14T05:58:52.968347Z","shell.execute_reply.started":"2024-11-14T05:58:52.960073Z","shell.execute_reply":"2024-11-14T05:58:52.967417Z"}},"outputs":[],"execution_count":null},{"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":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-14T05:58:52.969585Z","iopub.execute_input":"2024-11-14T05:58:52.969972Z","iopub.status.idle":"2024-11-14T05:58:52.986373Z","shell.execute_reply.started":"2024-11-14T05:58:52.969928Z","shell.execute_reply":"2024-11-14T05:58:52.985523Z"}},"outputs":[],"execution_count":null},{"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":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-14T05:58:52.987536Z","iopub.execute_input":"2024-11-14T05:58:52.987844Z","iopub.status.idle":"2024-11-14T05:58:52.993313Z","shell.execute_reply.started":"2024-11-14T05:58:52.987811Z","shell.execute_reply":"2024-11-14T05:58:52.992369Z"}},"outputs":[],"execution_count":null},{"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-3)\nscheduler = torch.optim.lr_scheduler.CosineAnnealingLR(optimizer, T_max=config.EPOCHS)\nscaler = torch.amp.GradScaler(\"cuda\")  # Sử dụng cho mixed precision","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-14T05:58:52.994602Z","iopub.execute_input":"2024-11-14T05:58:52.994905Z","iopub.status.idle":"2024-11-14T05:58:53.208642Z","shell.execute_reply.started":"2024-11-14T05:58:52.994872Z","shell.execute_reply":"2024-11-14T05:58:53.207709Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"accumulation_steps = 4  # ví dụ: cập nhật sau mỗi 4 batch\nfor i, (images, labels) in enumerate(train_dataloader):\n    images, labels = images.to(device), labels.to(device)\n    with torch.amp.autocast(device_type=device.type):\n        outputs = model(images)\n        loss = criterion(outputs, labels) / accumulation_steps\n    scaler.scale(loss).backward()\n\n    if (i + 1) % accumulation_steps == 0:\n        scaler.step(optimizer)\n        scaler.update()\n        optimizer.zero_grad()  # reset lại gradient","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-14T05:58:53.210005Z","iopub.execute_input":"2024-11-14T05:58:53.210639Z","iopub.status.idle":"2024-11-14T05:59:47.254335Z","shell.execute_reply.started":"2024-11-14T05:58:53.210584Z","shell.execute_reply":"2024-11-14T05:59:47.253132Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class DenseBlock(nn.Module):\n    def __init__(self, in_channels, growth_rate, num_layers):\n        super(DenseBlock, self).__init__()\n        self.layers = nn.ModuleList()\n        for i in range(num_layers):\n            layer = nn.Sequential(\n                nn.BatchNorm2d(in_channels + i * growth_rate),\n                nn.ReLU(inplace=True),\n                nn.Conv2d(in_channels + i * growth_rate, growth_rate, kernel_size=3, padding=1)\n            )\n            self.layers.append(layer)\n\n    def forward(self, x):\n        for layer in self.layers:\n            new_features = layer(x)\n            x = torch.cat([x, new_features], 1)  # Concatenating input with new features\n        return x","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-14T05:59:47.256056Z","iopub.execute_input":"2024-11-14T05:59:47.256491Z","iopub.status.idle":"2024-11-14T05:59:47.265298Z","shell.execute_reply.started":"2024-11-14T05:59:47.256448Z","shell.execute_reply":"2024-11-14T05:59:47.264205Z"}},"outputs":[],"execution_count":null},{"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":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-14T05:59:47.266671Z","iopub.execute_input":"2024-11-14T05:59:47.267041Z","iopub.status.idle":"2024-11-14T05:59:47.400448Z","shell.execute_reply.started":"2024-11-14T05:59:47.267004Z","shell.execute_reply":"2024-11-14T05:59:47.39957Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from sklearn.metrics import f1_score, confusion_matrix\n\n# Vòng lặp huấn luyện cho mỗi fold\nfor epoch in range(config.EPOCHS):\n    model.train()\n    running_loss = 0.0\n    optimizer.zero_grad()  # Reset optimizer\n\n    # Training loop\n    for i, (images, labels) in enumerate(train_dataloader):\n        images, labels = images.to(device), labels.to(device)\n\n        # In kích thước batch chỉ một lần\n        if i == 0:  # Chỉ in cho batch đầu tiên\n            print(\"Kích thước batch trong training:\", images.size())\n        \n        # Sử dụng cú pháp mới của autocast\n        with torch.amp.autocast(device_type=device.type):\n            outputs = model(images)\n            loss = criterion(outputs, labels) / accumulation_steps  # Chia loss theo accumulation steps\n        \n        scaler.scale(loss).backward()  # Tích lũy gradient\n        \n        # Thực hiện bước optimizer mỗi accumulation_steps batch\n        if (i + 1) % accumulation_steps == 0:\n            scaler.step(optimizer)\n            scaler.update()\n            optimizer.zero_grad()  # Reset lại gradient\n\n        running_loss += loss.item() * images.size(0)  # Không nhân với accumulation_steps ở đây\n\n    # Lưu lại train loss\n    epoch_train_loss = running_loss / len(train_dataloader.dataset)\n    fold_train_losses.append(epoch_train_loss)\n\n    # Cập nhật learning rate\n    scheduler.step()\n\n    # Validation loop\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            # In kích thước batch chỉ một lần\n            if total == 0:  # Chỉ in cho batch đầu tiên\n                print(\"Kích thước batch trong validation:\", images.size())\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            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    # Lưu lại validation loss và accuracy\n    epoch_val_loss = val_loss / len(val_dataloader.dataset)\n    fold_val_losses.append(epoch_val_loss)\n\n    epoch_val_accuracy = 100.0 * correct / total\n    fold_val_accuracies.append(epoch_val_accuracy)\n\n    # Tính F1 score\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    fold_val_f1_scores.append(epoch_f1)\n\n    # Tính các chỉ số khác: độ nhạy và độ đặc hiệu cho từng nhãn\n    sensitivity_per_class = []\n    specificity_per_class = []\n\n    for class_idx in range(all_targets_np.shape[1]):\n        tn, fp, fn, tp = confusion_matrix(all_targets_np[:, class_idx], all_preds_np[:, class_idx]).ravel()\n\n        sensitivity = tp / (tp + fn) if (tp + fn) > 0 else 0\n        specificity = tn / (tn + fp) if (tn + fp) > 0 else 0\n\n        sensitivity_per_class.append(sensitivity * 100)\n        specificity_per_class.append(specificity * 100)\n\n    # In các chỉ số sau mỗi epoch\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}\")\n    \n    for class_idx, organ in enumerate([\"Bowel\", \"Extravasation\", \"Liver\", \"Kidney\", \"Spleen\"]):\n        print(f\"{organ} - Sensitivity: {sensitivity_per_class[class_idx]:.2f}%, Specificity: {specificity_per_class[class_idx]:.2f}%\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-14T05:59:47.402191Z","iopub.execute_input":"2024-11-14T05:59:47.402574Z","iopub.status.idle":"2024-11-14T09:43:04.967021Z","shell.execute_reply.started":"2024-11-14T05:59:47.402536Z","shell.execute_reply":"2024-11-14T09:43:04.965785Z"},"collapsed":true,"jupyter":{"outputs_hidden":true}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Calculate and print average metrics\navg_sensitivity = np.mean(sensitivity_per_class)\navg_specificity = np.mean(specificity_per_class)\navg_accuracy = epoch_val_accuracy  # Average accuracy for this epoch\navg_f1 = epoch_f1  # Macro F1 score for this epoch\n\n# Print average values\nprint(f\"Average Sensitivity: {avg_sensitivity:.2f}%\")\nprint(f\"Average Specificity: {avg_specificity:.2f}%\")\nprint(f\"Average Accuracy: {avg_accuracy:.2f}%\")\nprint(f\"Average F1 Score (Macro): {avg_f1:.2f}%\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-14T09:43:04.968727Z","iopub.execute_input":"2024-11-14T09:43:04.969082Z","iopub.status.idle":"2024-11-14T09:43:04.976034Z","shell.execute_reply.started":"2024-11-14T09:43:04.969044Z","shell.execute_reply":"2024-11-14T09:43:04.975173Z"}},"outputs":[],"execution_count":null},{"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 }\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-14T09:43:04.97754Z","iopub.execute_input":"2024-11-14T09:43:04.977917Z","iopub.status.idle":"2024-11-14T09:43:21.321098Z","shell.execute_reply.started":"2024-11-14T09:43:04.977872Z","shell.execute_reply":"2024-11-14T09:43:21.319944Z"}},"outputs":[],"execution_count":null},{"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}%\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-14T09:43:21.322634Z","iopub.execute_input":"2024-11-14T09:43:21.32297Z","iopub.status.idle":"2024-11-14T09:43:21.329129Z","shell.execute_reply.started":"2024-11-14T09:43:21.322934Z","shell.execute_reply":"2024-11-14T09:43:21.327988Z"}},"outputs":[],"execution_count":null},{"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":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-14T09:43:21.330238Z","iopub.execute_input":"2024-11-14T09:43:21.330545Z","iopub.status.idle":"2024-11-14T09:43:21.703376Z","shell.execute_reply.started":"2024-11-14T09:43:21.330511Z","shell.execute_reply":"2024-11-14T09:43:21.702446Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import matplotlib.pyplot as plt\n\n# Sau khi huấn luyện, bạn sẽ có dữ liệu cho `fold_train_losses`, `fold_val_losses`, `fold_val_accuracies`, và `fold_val_f1_scores`\n# Dữ liệu này đã được tính trong vòng lặp huấn luyện\n\nepochs = range(1, config.EPOCHS + 1)\n\n# Đồ thị cho Loss, Accuracy và F1 Score\nplt.figure(figsize=(20, 10))  # Kích thước đồ thị lớn hơn để dễ nhìn\n\n# Vẽ đồ thị cho Validation Accuracy\nplt.subplot(2, 2, 1)\nplt.plot(epochs, fold_val_accuracies, label='Validation Accuracy', color='green', linewidth=2)\nplt.title('Validation Accuracy over Epochs', fontsize=14)\nplt.xlabel('Epochs', fontsize=12)\nplt.ylabel('Accuracy (%)', fontsize=12)\nplt.grid(True)\nplt.legend()\n\n# Vẽ đồ thị cho F1 Score\nplt.subplot(2, 2, 2)\nplt.plot(epochs, fold_val_f1_scores, label='Validation F1 Score', color='purple', linewidth=2)\nplt.title('Validation F1 Score over Epochs', fontsize=14)\nplt.xlabel('Epochs', fontsize=12)\nplt.ylabel('F1 Score', fontsize=12)\nplt.grid(True)\nplt.legend()\n\n# Vẽ đồ thị cho Sensitivity và Specificity\nplt.subplot(2, 2, 3)\nplt.plot(epochs, [np.mean(sensitivity_per_class)] * len(epochs), label='Average Sensitivity', color='orange', linewidth=2)\nplt.plot(epochs, [np.mean(specificity_per_class)] * len(epochs), label='Average Specificity', color='brown', linewidth=2)\nplt.title('Average Sensitivity and Specificity', fontsize=14)\nplt.xlabel('Epochs', fontsize=12)\nplt.ylabel('Percentage (%)', fontsize=12)\nplt.grid(True)\nplt.legend()\n\n# Hiển thị tất cả các đồ thị\nplt.tight_layout()\nplt.show()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-14T09:57:40.900805Z","iopub.execute_input":"2024-11-14T09:57:40.901224Z","iopub.status.idle":"2024-11-14T09:57:41.756319Z","shell.execute_reply.started":"2024-11-14T09:57:40.901184Z","shell.execute_reply":"2024-11-14T09:57:41.755373Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"np.sum(all_targets_np, axis=0)  # Đếm số lượng mẫu cho mỗi lớp trong nhãn thực tế\nnp.sum(all_preds_np, axis=0)  # Đếm số lượng mẫu cho mỗi lớp trong dự đoán\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-14T09:43:22.921621Z","iopub.execute_input":"2024-11-14T09:43:22.921939Z","iopub.status.idle":"2024-11-14T09:43:22.930204Z","shell.execute_reply.started":"2024-11-14T09:43:22.921905Z","shell.execute_reply":"2024-11-14T09:43:22.929088Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from sklearn.metrics import confusion_matrix\n\n# Giả sử bạn đã có all_preds_np và all_targets_np\n# Thực hiện tính toán ma trận nhầm lẫn cho từng lớp\nfor i in range(all_targets_np.shape[1]):\n    cm_i = confusion_matrix(all_targets_np[:, i], all_preds_np[:, i], labels=[0, 1])\n    TN, FP, FN, TP = cm_i.ravel()  # Lấy các giá trị trong ma trận nhầm lẫn\n\n    # Tính độ nhạy và độ đặc hiệu\n    sensitivity = TP / (TP + FN) if (TP + FN) > 0 else 0\n    specificity = TN / (TN + FP) if (TN + FP) > 0 else 0\n    \n    print(f\"Class: {class_names[i]}\")\n    print(f\"Confusion Matrix for {class_names[i]}:\")\n    print(cm_i)\n    print(f\"Sensitivity: {sensitivity:.4f}\")\n    print(f\"Specificity: {specificity:.4f}\")\n    print(\"-\" * 50)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-14T09:43:22.931433Z","iopub.execute_input":"2024-11-14T09:43:22.93179Z","iopub.status.idle":"2024-11-14T09:43:22.953633Z","shell.execute_reply.started":"2024-11-14T09:43:22.931738Z","shell.execute_reply":"2024-11-14T09:43:22.952769Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import numpy as np\nfrom sklearn.metrics import confusion_matrix\nimport seaborn as sns\nimport matplotlib.pyplot as plt\n\n# Các lớp bao gồm \"Khỏe mạnh\" và \"Tổn thương\" cho từng cơ quan\nclass_names = [\n    \"Bowel_Healthy\", \"Bowel_Injury\", \n    \"Extravasation_Healthy\", \"Extravasation_Injury\", \n    \"Liver_Healthy\", \"Liver_Low\", \"Liver_High\", \n    \"Kidney_Healthy\", \"Kidney_Low\", \"Kidney_High\", \n    \"Spleen_Healthy\", \"Spleen_Low\", \"Spleen_High\"\n]\n\n# Hàm tính toán ma trận nhầm lẫn cho tất cả các lớp\ndef compute_combined_confusion_matrix(all_preds, all_targets):\n    # Khởi tạo ma trận nhầm lẫn 13x13\n    cm = np.zeros((len(class_names), len(class_names)), dtype=int)\n\n    # Lặp qua từng lớp và tính toán ma trận nhầm lẫn\n    for i in range(len(class_names)):\n        # Tính toán ma trận nhầm lẫn cho từng lớp\n        cm_i = confusion_matrix(all_targets[:, i], all_preds[:, i], labels=[0, 1])\n        \n        # Cập nhật ma trận nhầm lẫn chung cho tất cả các lớp\n        cm[i, i] = cm_i[0, 0]  # True Negatives (TN)\n        cm[i, i] = cm_i[0, 1]  # False Positives (FP)\n        cm[i, i] = cm_i[1, 0]  # False Negatives (FN)\n        cm[i, i] = cm_i[1, 1]  # True Positives (TP)\n\n    return cm\n\n# Giả sử all_preds và all_targets là kết quả dự đoán và nhãn thật từ validation\n# all_preds và all_targets là dữ liệu multilabel, chuyển về mảng một chiều\n\n# Tạo dữ liệu giả định (thay thế bằng dữ liệu thực tế từ mô hình của bạn)\nall_preds_np = np.random.randint(0, 2, (100, 13))  # Dự đoán (100 mẫu, 13 lớp)\nall_targets_np = np.random.randint(0, 2, (100, 13))  # Nhãn thực tế (100 mẫu, 13 lớp)\n\n# Tính toán ma trận nhầm lẫn chung cho tất cả các lớp\ncombined_cm = compute_combined_confusion_matrix(all_preds_np, all_targets_np)\n\n# Vẽ ma trận nhầm lẫn chung\nplt.figure(figsize=(10, 8))\nsns.heatmap(combined_cm, annot=True, fmt=\"d\", cmap=\"Blues\", xticklabels=class_names, yticklabels=class_names, cbar=False)\nplt.xlabel('Predicted')\nplt.ylabel('True')\nplt.title('Combined Confusion Matrix for all Classes')\nplt.show()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-14T09:43:22.95485Z","iopub.execute_input":"2024-11-14T09:43:22.955161Z","iopub.status.idle":"2024-11-14T09:43:23.609355Z","shell.execute_reply.started":"2024-11-14T09:43:22.955108Z","shell.execute_reply":"2024-11-14T09:43:23.608447Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Kiểm tra số lượng mẫu dự đoán cho từng lớp\nprint(\"Predicted class distribution:\")\nprint(np.sum(all_preds_np, axis=0))\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-14T09:43:23.61067Z","iopub.execute_input":"2024-11-14T09:43:23.611031Z","iopub.status.idle":"2024-11-14T09:43:23.617269Z","shell.execute_reply.started":"2024-11-14T09:43:23.610992Z","shell.execute_reply":"2024-11-14T09:43:23.616211Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import matplotlib.pyplot as plt\nimport numpy as np\n\n# Giả sử bạn đã có các dữ liệu về Accuracy cho từng bộ phận từ các fold (được tính trong vòng lặp huấn luyện)\n# Tạo dữ liệu giả (có thể thay thế bằng dữ liệu thực tế từ quá trình huấn luyện)\nepochs = range(1, config.EPOCHS + 1)\n\n# Giả sử bạn có độ chính xác (accuracy) của các bộ phận theo từng epoch\naccuracy_bowel = np.random.uniform(0.7, 0.9, config.EPOCHS)  # Accuracy của Bowel\naccuracy_extravasation = np.random.uniform(0.6, 0.85, config.EPOCHS)  # Accuracy của Extravasation\naccuracy_liver = np.random.uniform(0.8, 0.95, config.EPOCHS)  # Accuracy của Liver\naccuracy_kidney = np.random.uniform(0.75, 0.9, config.EPOCHS)  # Accuracy của Kidney\naccuracy_spleen = np.random.uniform(0.7, 0.88, config.EPOCHS)  # Accuracy của Spleen\n\n# Tạo đồ thị\nplt.figure(figsize=(14, 10))\n\n# Vẽ Accuracy cho từng bộ phận\nplt.plot(epochs, accuracy_bowel, label='Bowel Accuracy', color='blue', linewidth=2)\nplt.plot(epochs, accuracy_extravasation, label='Extravasation Accuracy', color='red', linewidth=2)\nplt.plot(epochs, accuracy_liver, label='Liver Accuracy', color='green', linewidth=2)\nplt.plot(epochs, accuracy_kidney, label='Kidney Accuracy', color='purple', linewidth=2)\nplt.plot(epochs, accuracy_spleen, label='Spleen Accuracy', color='orange', linewidth=2)\n\n# Thêm tiêu đề, nhãn và lưới\nplt.title('Accuracy for Each Organ Over Epochs', fontsize=16)\nplt.xlabel('Epochs', fontsize=12)\nplt.ylabel('Accuracy (%)', fontsize=12)\nplt.grid(True)\nplt.legend()\n\n# Hiển thị đồ thị\nplt.tight_layout()\nplt.show()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-14T09:48:02.035039Z","iopub.execute_input":"2024-11-14T09:48:02.03547Z","iopub.status.idle":"2024-11-14T09:48:02.561841Z","shell.execute_reply.started":"2024-11-14T09:48:02.035433Z","shell.execute_reply":"2024-11-14T09:48:02.560944Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import matplotlib.pyplot as plt\n\n# Giả sử bạn đã có dữ liệu `fold_train_losses` và `fold_val_losses` từ quá trình huấn luyện mô hình\n# Tạo dữ liệu giả (thay thế bằng dữ liệu thực tế của bạn)\nepochs = range(1, config.EPOCHS + 1)\nfold_train_losses = np.random.uniform(0.2, 1.0, config.EPOCHS)  # Training Loss\nfold_val_losses = np.random.uniform(0.2, 1.0, config.EPOCHS)  # Validation Loss\n\n# Vẽ đồ thị Training Loss và Validation Loss\nplt.figure(figsize=(10, 6))\n\n# Vẽ đường cho Training Loss\nplt.plot(epochs, fold_train_losses, label='Training Loss', color='blue', linewidth=2)\n\n# Vẽ đường cho Validation Loss\nplt.plot(epochs, fold_val_losses, label='Validation Loss', color='red', linewidth=2)\n\n# Thêm tiêu đề, nhãn và lưới\nplt.title('Training and Validation Loss Over Epochs', fontsize=16)\nplt.xlabel('Epochs', fontsize=12)\nplt.ylabel('Loss', fontsize=12)\nplt.grid(True)\nplt.legend()\n\n# Hiển thị đồ thị\nplt.tight_layout()\nplt.show()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-14T09:48:46.018372Z","iopub.execute_input":"2024-11-14T09:48:46.019027Z","iopub.status.idle":"2024-11-14T09:48:46.39077Z","shell.execute_reply.started":"2024-11-14T09:48:46.018985Z","shell.execute_reply":"2024-11-14T09:48:46.389861Z"}},"outputs":[],"execution_count":null}]}