{"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":"gpu","dataSources":[{"sourceId":11848,"databundleVersionId":862157,"sourceType":"competition"}],"dockerImageVersionId":30761,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import numpy as np \nimport pandas as pd \nimport os\n# for dirname, _, filenames in os.walk('/kaggle/input'):\n#     for filename in filenames:\n#         print(os.path.join(dirname, filename))\n\n","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2024-09-13T06:19:37.186231Z","iopub.execute_input":"2024-09-13T06:19:37.186539Z","iopub.status.idle":"2024-09-13T06:19:37.543576Z","shell.execute_reply.started":"2024-09-13T06:19:37.186506Z","shell.execute_reply":"2024-09-13T06:19:37.542765Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# PyTorch for Histopathology image classification","metadata":{}},{"cell_type":"code","source":"import os\nimport torch\nimport torch.nn as nn\nimport torch.optim as optim\nfrom torch.utils.data import DataLoader, Dataset\nfrom torchvision import transforms, models\nfrom PIL import Image\nimport matplotlib.pyplot as plt\n\ndevice = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\n\n\n\nclass HistopathologyDataset(Dataset):\n    def __init__(self, data_dir, transform=None):\n        self.data_dir = data_dir\n        self.transform = transform\n        self.image_files = [f for f in os.listdir(data_dir) if f.endswith('.tif')]\n\n    def __len__(self):\n        return len(self.image_files)\n\n    def __getitem__(self, idx):\n        img_path = os.path.join(self.data_dir, self.image_files[idx])\n        image = Image.open(img_path)\n        \n        # Transformations\n        if self.transform:\n            image = self.transform(image)\n        \n        # Binary classification; label is derived from the file name\n        label = 1 if 'positive' in self.image_files[idx] else 0\n        \n        return image, label\n\n    \n    \n    \n# Transformations for train & validation set\ndata_transforms = transforms.Compose([\n    transforms.Resize((224, 224)),\n    transforms.RandomHorizontalFlip(),\n    transforms.ToTensor(),\n    transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])\n])\n\n\ntrain_dataset = HistopathologyDataset(data_dir='/kaggle/input/histopathologic-cancer-detection/train', transform=data_transforms)\n\n# Creating Dataloaders\ntrain_loader = DataLoader(train_dataset, batch_size=32, shuffle=True)\n\n\n\n\n# ResNet-18 model\nmodel = models.resnet18(pretrained=True)\n\n# Fully connected layer for binary classification\nnum_features = model.fc.in_features\nmodel.fc = nn.Linear(num_features, 2)\n\n# Model to GPU\nmodel = model.to(device)\n\n\n\n# Loss & Optimizer\ncriterion = nn.CrossEntropyLoss()\noptimizer = optim.Adam(model.parameters(), lr=0.001)\n\n\n\ndef train_model(model, criterion, optimizer, num_epochs=5):\n    model.train()  # Model to training mode\n    for epoch in range(num_epochs):\n        running_loss = 0.0\n        \n        for inputs, labels in train_loader:\n            inputs, labels = inputs.to(device), labels.to(device)\n            \n            # Zero Parameter Gradients\n            optimizer.zero_grad()\n            \n            # Forward pass\n            outputs = model(inputs)\n            loss = criterion(outputs, labels)\n            \n            # Backward pass and optimize\n            loss.backward()\n            optimizer.step()\n            \n            running_loss += loss.item()\n        \n        print(f'Epoch {epoch + 1}/{num_epochs}, Loss: {running_loss / len(train_loader)}')\n\n# Train for 5 epochs\ntrain_model(model, criterion, optimizer, num_epochs=5)\n","metadata":{"execution":{"iopub.status.busy":"2024-09-13T06:28:36.255848Z","iopub.execute_input":"2024-09-13T06:28:36.256235Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def evaluate_model(model, val_loader):\n    model.eval()  # Evaluation Mode\n    correct = 0\n    total = 0\n    \n    with torch.no_grad():\n        for inputs, labels in val_loader:\n            inputs, labels = inputs.to(device), labels.to(device)\n            outputs = model(inputs)\n            _, predicted = torch.max(outputs, 1)\n            total += labels.size(0)\n            correct += (predicted == labels).sum().item()\n    \n    print(f'Validation Accuracy: {100 * correct / total}%')\n\n\nevaluate_model(model, val_loader)\n\ntorch.save(model.state_dict(), '/kaggle/working/histopathology_model.pth')\n\n\n\ndef imshow(inp, title=None):\n    inp = inp.numpy().transpose((1, 2, 0))\n    mean = np.array([0.485, 0.456, 0.406])\n    std = np.array([0.229, 0.224, 0.225])\n    inp = std * inp + mean\n    inp = np.clip(inp, 0, 1)\n    plt.imshow(inp)\n    if title is not None:\n        plt.title(title)\n    plt.pause(0.001)  # Pause to update plot\n\n# Batch of validation data\ninputs, labels = next(iter(train_loader))\n\n# Prediction\noutputs = model(inputs.to(device))\n_, preds = torch.max(outputs, 1)\n\n# Plot\nplt.figure(figsize=(10, 10))\nfor i in range(4):\n    plt.subplot(2, 2, i + 1)\n    imshow(inputs[i])\n    plt.title(f'Predicted: {preds[i].item()}')\nplt.show()\n","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"labels_df = pd.read_csv('/kaggle/input/histopathologic-cancer-detection/train_labels.csv')\n\nprint(labels_df.head())\n","metadata":{"execution":{"iopub.status.busy":"2024-09-14T06:34:26.359334Z","iopub.execute_input":"2024-09-14T06:34:26.359637Z","iopub.status.idle":"2024-09-14T06:34:27.029989Z","shell.execute_reply.started":"2024-09-14T06:34:26.359602Z","shell.execute_reply":"2024-09-14T06:34:27.029028Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import os\nimport torch\nimport torch.nn as nn\nimport torch.optim as optim\nfrom torch.utils.data import DataLoader, Dataset\nfrom torchvision import models, transforms\nfrom PIL import Image\nimport pandas as pd\nfrom sklearn.model_selection import train_test_split\n\nlabels_df = pd.read_csv('/kaggle/input/histopathologic-cancer-detection/train_labels.csv')\n\n# Transformations\ndata_transforms = transforms.Compose([\n    transforms.Resize((224, 224)),\n    transforms.RandomHorizontalFlip(),\n    transforms.ToTensor(),\n    transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])\n])\n\n# Dataset Class\nclass HistopathologyDataset(Dataset):\n    def __init__(self, data_dir, labels_df, transform=None):\n        self.data_dir = data_dir\n        self.labels_df = labels_df\n        self.transform = transform\n        self.image_files = [f for f in os.listdir(data_dir) if f.endswith('.tif')]\n        self.labels_map = {row['id']: row['label'] for _, row in labels_df.iterrows()}  # Dictionary of labels\n\n    def __len__(self):\n        return len(self.image_files)\n\n    def __getitem__(self, idx):\n        img_path = os.path.join(self.data_dir, self.image_files[idx])\n        image = Image.open(img_path)\n        image_id = self.image_files[idx].split('.')[0]\n\n        # Check if image_id exists in labels_map dictionary\n        if image_id not in self.labels_map:\n            # Logging missing label & skip this image\n            print(f\"Label for image ID {image_id} not found. Skipping.\")\n            return None, None\n        \n        # Get label\n        label = self.labels_map[image_id]\n\n        if self.transform:\n            image = self.transform(image)\n\n        return image, label\n\n# Train and Validation\ntrain_ids, val_ids = train_test_split(labels_df['id'], test_size=0.2, random_state=42)\ntrain_df = labels_df[labels_df['id'].isin(train_ids)]\nval_df = labels_df[labels_df['id'].isin(val_ids)]\n\n# Datasets and Dataloaders\ntrain_dataset = HistopathologyDataset(\n    data_dir='/kaggle/input/histopathologic-cancer-detection/train', \n    labels_df=train_df, \n    transform=data_transforms\n)\nval_dataset = HistopathologyDataset(\n    data_dir='/kaggle/input/histopathologic-cancer-detection/train', \n    labels_df=val_df, \n    transform=data_transforms\n)\n\n# Filtered missing labels in DataLoader\ndef collate_fn(batch):\n    # Filtering None values returned for images without labels\n    batch = list(filter(lambda x: x[0] is not None, batch))\n    if len(batch) == 0:\n        return None, None\n    return torch.utils.data.dataloader.default_collate(batch)\n\ntrain_loader = DataLoader(train_dataset, batch_size=32, shuffle=True, collate_fn=collate_fn)\nval_loader = DataLoader(val_dataset, batch_size=32, shuffle=False, collate_fn=collate_fn)\n\n# ResNet-18 model & modifying final layer for binary classification\nmodel = models.resnet18(pretrained=True)\nnum_features = model.fc.in_features\nmodel.fc = nn.Linear(num_features, 2)  # Binary classification: tumor or no tumor\n\n\ndevice = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\nmodel = model.to(device)\n\n# Loss function & Optimizer\ncriterion = nn.CrossEntropyLoss()\noptimizer = optim.Adam(model.parameters(), lr=0.001)\n\n# Training\ndef train_model(model, criterion, optimizer, num_epochs=5):\n    model.train()  # Set model to training mode\n    for epoch in range(num_epochs):\n        running_loss = 0.0\n        for inputs, labels in train_loader:\n            if inputs is None or labels is None:\n                continue  # Skipping batches with missing data\n\n            inputs, labels = inputs.to(device), labels.to(device)\n\n            optimizer.zero_grad()  # Zeroing parameter gradients\n            outputs = model(inputs)  # Forward pass\n            loss = criterion(outputs, labels)  # Compute loss\n            loss.backward()  # Backward pass\n            optimizer.step()  # Optimize model\n\n            running_loss += loss.item()\n\n        print(f'Epoch {epoch + 1}/{num_epochs}, Loss: {running_loss / len(train_loader)}')\n\n\ntrain_model(model, criterion, optimizer, num_epochs=5)\n","metadata":{"execution":{"iopub.status.busy":"2024-09-14T06:50:06.720719Z","iopub.execute_input":"2024-09-14T06:50:06.721171Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}