{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"pygments_lexer":"ipython3","nbconvert_exporter":"python","version":"3.6.4","file_extension":".py","codemirror_mode":{"name":"ipython","version":3},"name":"python","mimetype":"text/x-python"}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"Hi I tried convert Keras team's code to Pytorch including all training pipeline as well.","metadata":{}},{"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":"2023-10-16T05:31:29.874876Z","iopub.execute_input":"2023-10-16T05:31:29.875381Z","iopub.status.idle":"2023-10-16T05:31:30.950196Z","shell.execute_reply.started":"2023-10-16T05:31:29.875344Z","shell.execute_reply":"2023-10-16T05:31:30.9492Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class Config:\n    SEED = 42\n    IMAGE_SIZE = [256, 256]\n    BATCH_SIZE = 16\n    EPOCHS = 10\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()\nlen(Config.TARGET_COLS)","metadata":{"execution":{"iopub.status.busy":"2023-10-16T05:31:30.952022Z","iopub.execute_input":"2023-10-16T05:31:30.952708Z","iopub.status.idle":"2023-10-16T05:31:30.965483Z","shell.execute_reply.started":"2023-10-16T05:31:30.952675Z","shell.execute_reply":"2023-10-16T05:31:30.964721Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"torch.manual_seed(Config.SEED)","metadata":{"execution":{"iopub.status.busy":"2023-10-16T05:31:30.966897Z","iopub.execute_input":"2023-10-16T05:31:30.96813Z","iopub.status.idle":"2023-10-16T05:31:30.981743Z","shell.execute_reply.started":"2023-10-16T05:31:30.9681Z","shell.execute_reply":"2023-10-16T05:31:30.980853Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Loading Data","metadata":{}},{"cell_type":"code","source":"BASE_PATH = f\"/kaggle/input/rsna-atd-512x512-png-v2-dataset\"","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2023-10-16T05:31:30.98511Z","iopub.execute_input":"2023-10-16T05:31:30.986993Z","iopub.status.idle":"2023-10-16T05:31:30.994778Z","shell.execute_reply.started":"2023-10-16T05:31:30.986963Z","shell.execute_reply":"2023-10-16T05:31:30.993521Z"},"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":"2023-10-16T05:31:30.996166Z","iopub.execute_input":"2023-10-16T05:31:30.996986Z","iopub.status.idle":"2023-10-16T05:31:31.204672Z","shell.execute_reply.started":"2023-10-16T05:31:30.996942Z","shell.execute_reply":"2023-10-16T05:31:31.20385Z"},"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":"2023-10-16T05:31:31.208421Z","iopub.execute_input":"2023-10-16T05:31:31.210629Z","iopub.status.idle":"2023-10-16T05:31:31.321671Z","shell.execute_reply.started":"2023-10-16T05:31:31.210597Z","shell.execute_reply":"2023-10-16T05:31:31.320853Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_data.shape, val_data.shape","metadata":{"execution":{"iopub.status.busy":"2023-10-16T05:31:31.322967Z","iopub.execute_input":"2023-10-16T05:31:31.32355Z","iopub.status.idle":"2023-10-16T05:31:31.331585Z","shell.execute_reply.started":"2023-10-16T05:31:31.32352Z","shell.execute_reply":"2023-10-16T05:31:31.330022Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# torch dataloader with augmentation","metadata":{}},{"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":"2023-10-16T05:31:31.333421Z","iopub.execute_input":"2023-10-16T05:31:31.33529Z","iopub.status.idle":"2023-10-16T05:31:31.352113Z","shell.execute_reply.started":"2023-10-16T05:31:31.335261Z","shell.execute_reply":"2023-10-16T05:31:31.351093Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Converting Dataframe to dataloader","metadata":{}},{"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":{"execution":{"iopub.status.busy":"2023-10-16T05:31:31.353971Z","iopub.execute_input":"2023-10-16T05:31:31.354663Z","iopub.status.idle":"2023-10-16T05:31:31.36845Z","shell.execute_reply.started":"2023-10-16T05:31:31.354635Z","shell.execute_reply":"2023-10-16T05:31:31.367434Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"for img, label in train_dataloader:\n  print(img.shape)\n  break","metadata":{"execution":{"iopub.status.busy":"2023-10-16T05:31:31.375894Z","iopub.execute_input":"2023-10-16T05:31:31.376449Z","iopub.status.idle":"2023-10-16T05:31:32.14595Z","shell.execute_reply.started":"2023-10-16T05:31:31.376421Z","shell.execute_reply":"2023-10-16T05:31:32.145042Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## display some images","metadata":{}},{"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)\n","metadata":{"execution":{"iopub.status.busy":"2023-10-16T05:31:32.147351Z","iopub.execute_input":"2023-10-16T05:31:32.147657Z","iopub.status.idle":"2023-10-16T05:31:32.752193Z","shell.execute_reply.started":"2023-10-16T05:31:32.147628Z","shell.execute_reply":"2023-10-16T05:31:32.751325Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Simple CNN","metadata":{}},{"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=3, stride=1, padding=1),\n            nn.ReLU(),\n            nn.MaxPool2d(kernel_size=2, stride=2),\n            nn.Conv2d(in_channels=32, out_channels=64, kernel_size=3, stride=1, padding=1),\n            nn.ReLU(),\n            nn.MaxPool2d(kernel_size=2, stride=2)\n        )\n        \n        self.fc_layers = nn.Sequential(\n            nn.Linear(64 * 64 * 64, 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)\n        x = self.fc_layers(x)\n        return x\n\n# Instantiate the model\nmodel = SimpleCNN(num_classes=11).to('cuda')","metadata":{"execution":{"iopub.status.busy":"2023-10-16T05:31:32.753106Z","iopub.execute_input":"2023-10-16T05:31:32.753396Z","iopub.status.idle":"2023-10-16T05:31:36.12096Z","shell.execute_reply.started":"2023-10-16T05:31:32.753368Z","shell.execute_reply":"2023-10-16T05:31:36.120061Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## training the model","metadata":{}},{"cell_type":"code","source":"import torch\nimport torch.nn as nn\n\n\n# Instantiate the model\nmodel = SimpleCNN(num_classes=11).to('cuda')\n\n# Define loss function and optimizer\ncriterion = nn.BCEWithLogitsLoss()  # Use BCEWithLogitsLoss for binary classification\noptimizer = torch.optim.Adam(model.parameters(), lr=1e-4)\nscheduler = torch.optim.lr_scheduler.CosineAnnealingLR(optimizer, T_max=5)\n\ntotal_epochs = 25  # Replace with the total number of epochs\n\n\ntrain_losses = []  # To store training losses\nval_losses = []    # To store validation losses\nval_accuracies = []  # To store validation accuracies\n\nfor epoch in range(total_epochs):\n    model.train()  # Set the model to training mode\n    for images, labels in train_dataloader:\n        optimizer.zero_grad()\n        \n        # Move data to GPU\n        images = images.to('cuda')\n        labels = labels.to('cuda')\n        \n        outputs = model(images)\n        \n        loss = criterion(outputs, labels)\n        \n        loss.backward()\n        optimizer.step()\n    \n    # Update learning rate using the scheduler\n    scheduler.step()\n    \n    # Validation loop\n    model.eval()  # Set the model to evaluation mode\n    val_loss = 0.0\n    correct = 0\n    total = 0\n    with torch.no_grad():\n        for images, labels in val_dataloader:\n            images = images.to('cuda')\n            labels = labels.to('cuda')\n            \n            outputs = model(images)\n            val_loss += criterion(outputs, labels).item()\n            \n            predicted = (outputs > 0.5).int()  # Convert logits to binary predictions\n            total += labels.size(0) * labels.size(1)  # Total number of predictions\n            correct += (predicted == labels).sum().item()\n    \n    val_loss /= len(val_dataloader)\n    val_accuracy = 100.0 * correct / total\n    \n     # Append loss and accuracy values to lists\n    train_losses.append(loss.item())\n    val_losses.append(val_loss)\n    val_accuracies.append(val_accuracy)\n    print(f\"Epoch [{epoch+1}/{total_epochs}] - Loss: {loss:.4f} - Val Loss: {val_loss:.4f} - Val Acc: {val_accuracy:.2f}%\")","metadata":{"execution":{"iopub.status.busy":"2023-10-16T05:31:36.122452Z","iopub.execute_input":"2023-10-16T05:31:36.122781Z","iopub.status.idle":"2023-10-16T06:29:36.261651Z","shell.execute_reply.started":"2023-10-16T05:31:36.12275Z","shell.execute_reply":"2023-10-16T06:29:36.260641Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Plot training and validation progress\nplt.figure(figsize=(12, 4))\nplt.subplot(1, 2, 1)\nplt.plot(train_losses, label='Train')\nplt.plot(val_losses, label='Validation')\nplt.xlabel('Epoch')\nplt.ylabel('Loss')\nplt.legend()\nplt.title('Training and Validation Loss')\n\nplt.subplot(1, 2, 2)\nplt.plot(val_accuracies, label='Validation')\nplt.xlabel('Epoch')\nplt.ylabel('Accuracy (%)')\nplt.legend()\nplt.title('Validation Accuracy')\n\nplt.tight_layout()\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2023-10-16T06:29:36.263065Z","iopub.execute_input":"2023-10-16T06:29:36.263965Z","iopub.status.idle":"2023-10-16T06:29:36.796282Z","shell.execute_reply.started":"2023-10-16T06:29:36.263928Z","shell.execute_reply":"2023-10-16T06:29:36.795399Z"},"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":"2023-10-16T06:29:36.797435Z","iopub.execute_input":"2023-10-16T06:29:36.798273Z","iopub.status.idle":"2023-10-16T06:29:37.116684Z","shell.execute_reply.started":"2023-10-16T06:29:36.798242Z","shell.execute_reply":"2023-10-16T06:29:37.115864Z"},"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":"2023-10-16T06:29:37.117858Z","iopub.execute_input":"2023-10-16T06:29:37.118696Z","iopub.status.idle":"2023-10-16T06:29:37.143904Z","shell.execute_reply.started":"2023-10-16T06:29:37.118665Z","shell.execute_reply":"2023-10-16T06:29:37.142877Z"},"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":"2023-10-16T06:29:37.145038Z","iopub.execute_input":"2023-10-16T06:29:37.14534Z","iopub.status.idle":"2023-10-16T06:29:37.150774Z","shell.execute_reply.started":"2023-10-16T06:29:37.145309Z","shell.execute_reply":"2023-10-16T06:29:37.149951Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"","metadata":{}},{"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":"2023-10-16T06:29:37.152131Z","iopub.execute_input":"2023-10-16T06:29:37.15312Z","iopub.status.idle":"2023-10-16T06:29:37.257177Z","shell.execute_reply.started":"2023-10-16T06:29:37.153089Z","shell.execute_reply":"2023-10-16T06:29:37.25626Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df","metadata":{"execution":{"iopub.status.busy":"2023-10-16T06:29:37.258472Z","iopub.execute_input":"2023-10-16T06:29:37.258762Z","iopub.status.idle":"2023-10-16T06:29:37.26907Z","shell.execute_reply.started":"2023-10-16T06:29:37.258733Z","shell.execute_reply":"2023-10-16T06:29:37.267944Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df.to_csv(\"submission.csv\")","metadata":{"execution":{"iopub.status.busy":"2023-10-16T06:29:37.270355Z","iopub.execute_input":"2023-10-16T06:29:37.2713Z","iopub.status.idle":"2023-10-16T06:29:37.281824Z","shell.execute_reply.started":"2023-10-16T06:29:37.27127Z","shell.execute_reply":"2023-10-16T06:29:37.28086Z"},"trusted":true},"execution_count":null,"outputs":[]}]}