{"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":"# Help functions","metadata":{}},{"cell_type":"code","source":"import cv2\nimport numpy as np\nimport os\n\ndef load_data(base_path, batch_size=8):\n    # Iterate over the three train directories (train/1, train/2, train/3)\n    for fragment_id in range(1, 4):\n        fragment_path = os.path.join(base_path, str(fragment_id))\n        print(f\"Loading data from fragment: {fragment_id}\")\n\n        images, masks, inklabels = [], [], []\n        for i in range(65):  # Load surface_volume images (00.tif to 64.tif)\n            image_path = os.path.join(fragment_path, f'surface_volume/{i:02d}.tif')\n            image = cv2.imread(image_path, cv2.IMREAD_GRAYSCALE)\n            images.append(image)\n\n            # Load mask.png and inklabels.png only once per fragment\n            if i == 0:\n                mask = cv2.imread(os.path.join(fragment_path, 'mask.png'), cv2.IMREAD_GRAYSCALE)\n                inklabel = cv2.imread(os.path.join(fragment_path, 'inklabels.png'), cv2.IMREAD_GRAYSCALE)\n            \n            # Append the same mask and inklabel for each image slice\n            masks.append(mask)\n            inklabels.append(inklabel)\n\n            # Yield a batch of data\n            if len(images) == batch_size:\n                yield np.stack(images, axis=0), np.stack(masks, axis=0), np.stack(inklabels, axis=0)\n                images, masks, inklabels = [], [], []\n\n        # Yield any remaining data\n        if images:\n            yield np.stack(images, axis=0), np.stack(masks, axis=0), np.stack(inklabels, axis=0)\n\n    print(\"Data loading complete.\")\n\n# Usage example:\nbase_path = '/kaggle/input/vesuvius-challenge-ink-detection/train'\nfor images, masks, inklabels in load_data(base_path, batch_size=8):\n    # Process the batch of data\n    pass","metadata":{"execution":{"iopub.status.busy":"2023-05-10T22:02:10.035732Z","iopub.execute_input":"2023-05-10T22:02:10.036215Z","iopub.status.idle":"2023-05-10T22:11:23.984584Z","shell.execute_reply.started":"2023-05-10T22:02:10.036158Z","shell.execute_reply":"2023-05-10T22:11:23.982559Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Dataset","metadata":{}},{"cell_type":"code","source":"import torch\nfrom torch.utils.data import Dataset\nimport albumentations as A\nfrom albumentations.pytorch import ToTensorV2\nimport cv2\nimport numpy as np\nnp.__version__ = \"1.23.0\"\nimport os\nfrom torch.utils.data import Dataset\n\nclass VesuviusDataset(Dataset):\n    def __init__(self, base_path, transforms=None):\n        self.base_path = base_path\n        self.transforms = transforms\n        self.fragment_ids = [str(i) for i in range(1, 4)]\n        self.slice_ids = [f'{i:02d}' for i in range(65)]\n\n    def __len__(self):\n        return len(self.fragment_ids) * len(self.slice_ids)\n\n    def __getitem__(self, idx):\n        fragment_idx = idx // len(self.slice_ids)\n        slice_idx = idx % len(self.slice_ids)\n        fragment_id = self.fragment_ids[fragment_idx]\n        slice_id = self.slice_ids[slice_idx]\n\n        fragment_path = os.path.join(self.base_path, fragment_id)\n        image = cv2.imread(os.path.join(fragment_path, f'surface_volume/{slice_id}.tif'), cv2.IMREAD_GRAYSCALE)\n        mask = cv2.imread(os.path.join(fragment_path, 'mask.png'), cv2.IMREAD_GRAYSCALE)\n        inklabel = cv2.imread(os.path.join(fragment_path, 'inklabels.png'), cv2.IMREAD_GRAYSCALE)\n\n        if self.transforms:\n            augmented = self.transforms(image=image, mask=mask)\n            image = augmented['image']\n            mask = augmented['mask']\n\n        return image, mask, inklabel\n\ndef get_transforms():\n    # Define data augmentation and preprocessing transforms\n    return A.Compose([\n        A.HorizontalFlip(p=0.5),\n        A.VerticalFlip(p=0.5),\n        A.Normalize(mean=[0.485], std=[0.229]),  # Updated mean and std for grayscale images\n        ToTensorV2(),\n    ], p=1.0)\n\n# Usage example:\nbase_path = '/kaggle/input/vesuvius-challenge-ink-detection/train'\ntransforms = get_transforms()  # Define your data augmentation and preprocessing transforms\ndataset = VesuviusDataset(base_path, transforms=transforms)\n\n# Access data using indices\nimage, mask, inklabel = dataset[0]  # Get the first item from the dataset","metadata":{"execution":{"iopub.status.busy":"2023-05-10T22:15:19.191649Z","iopub.execute_input":"2023-05-10T22:15:19.192069Z","iopub.status.idle":"2023-05-10T22:15:20.580151Z","shell.execute_reply.started":"2023-05-10T22:15:19.192037Z","shell.execute_reply":"2023-05-10T22:15:20.578601Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Model","metadata":{}},{"cell_type":"code","source":"!pip install pretrainedmodels","metadata":{"execution":{"iopub.status.busy":"2023-05-10T22:17:00.422531Z","iopub.execute_input":"2023-05-10T22:17:00.423005Z","iopub.status.idle":"2023-05-10T22:17:19.722272Z","shell.execute_reply.started":"2023-05-10T22:17:00.422970Z","shell.execute_reply":"2023-05-10T22:17:19.720580Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"!pip install segmentation_models_pytorch","metadata":{"execution":{"iopub.status.busy":"2023-05-10T22:17:58.239944Z","iopub.execute_input":"2023-05-10T22:17:58.240390Z","iopub.status.idle":"2023-05-10T22:18:16.586089Z","shell.execute_reply.started":"2023-05-10T22:17:58.240356Z","shell.execute_reply":"2023-05-10T22:18:16.584845Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"!pip install efficientnet_pytorch","metadata":{"execution":{"iopub.status.busy":"2023-05-10T22:18:18.566587Z","iopub.execute_input":"2023-05-10T22:18:18.567062Z","iopub.status.idle":"2023-05-10T22:18:32.596399Z","shell.execute_reply.started":"2023-05-10T22:18:18.567022Z","shell.execute_reply":"2023-05-10T22:18:32.594558Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import torch.optim as optim\nfrom torch.cuda.amp import GradScaler, autocast\nfrom torch.utils.data import DataLoader\nfrom sklearn.model_selection import KFold\nimport sys\nsys.path.append('/kaggle/input/pretrainedmodels/pretrainedmodels-0.7.4/pretrainedmodels')\nsys.path.append('/kaggle/input/segmentation-models-pytorch/segmentation_models.pytorch-master')\nsys.path.append('/kaggle/input/efficientnet-pytorch/EfficientNet-PyTorch-master/efficientnet_pytorch')\n\nimport pretrainedmodels\nimport segmentation_models_pytorch as smp\nimport efficientnet_pytorch\n\n\nNUM_FOLDS = 5\nNUM_EPOCHS = 30\nBATCH_SIZE = 8\nDEVICE = 'cuda' if torch.cuda.is_available() else 'cpu'\nBACKBONE = 'efficientnet-b4'\nLEARNING_RATE = 1e-4\n\ndef get_model():\n    model = smp.DeepLabV3Plus(\n        encoder_name=BACKBONE,\n        encoder_weights='imagenet',\n        in_channels=1,\n        classes=1,\n    )\n    # Parallelize the model across multiple GPUs\n    if torch.cuda.device_count() > 1:\n        model = torch.nn.DataParallel(model)\n    return model.to(DEVICE)\n    \ndef train_one_fold(fold, train_loader, val_loader):\n    print(f\"Training fold {fold}\")\n    model = get_model().to(DEVICE)\n    criterion = nn.BCEWithLogitsLoss()\n    optimizer = optim.Adam(model.parameters(), lr=LEARNING_RATE)\n    scaler = GradScaler()  # For mixed precision training\n\n    for epoch in range(NUM_EPOCHS):\n        print(f\"Starting epoch {epoch}\")\n        # Training loop\n        model.train()\n        for batch in train_loader:\n            images, masks = batch\n            images, masks = images.to(DEVICE), masks.to(DEVICE)\n\n            optimizer.zero_grad()\n            with autocast():  # Mixed precision training\n                outputs = model(images)\n                loss = criterion(outputs, masks)\n            scaler.scale(loss).backward()\n            scaler.step(optimizer)\n            scaler.update()\n\n        # Validation loop\n        model.eval()\n        val_loss = 0\n        with torch.no_grad():\n            for batch in val_loader:\n                images, masks = batch\n                images, masks = images.to(DEVICE), masks.to(DEVICE)\n\n                outputs = model(images)\n                loss = criterion(outputs, masks)\n                val_loss += loss.item()\n\n        val_loss /= len(val_loader)\n        print(f\"Fold {fold}, Epoch {epoch}, Validation Loss: {val_loss}\")\n\n    return model\n\ndef kfold_cross_validation():\n    # Load and preprocess data\n    images, masks = load_data('/kaggle/input/vesuvius-challenge-ink-detection/train')  # Replace with the correct path to your data\n    \n    # Flatten the lists of fragments into a single list of image slices and masks\n    images = [img_slice for fragment in images for img_slice in fragment]\n    masks = [mask_slice for fragment_masks in masks for mask_slice in fragment_masks if fragment_masks is not None]\n    \n    dataset = VesuviusDataset(images, masks, transforms=get_transforms())\n    \n    kfold = KFold(n_splits=NUM_FOLDS, shuffle=True, random_state=42)\n    models = []\n    \n    for fold, (train_indices, val_indices) in enumerate(kfold.split(dataset)):\n        train_subset = torch.utils.data.Subset(dataset, train_indices)\n        val_subset = torch.utils.data.Subset(dataset, val_indices)\n        \n        train_loader = DataLoader(train_subset, batch_size=8, shuffle=True, num_workers=4)\n        val_loader = DataLoader(val_subset, batch_size=8, shuffle=False, num_workers=4)\n        \n        model = train_one_fold(fold, train_loader, val_loader)\n        models.append(model)\n    \n    return models\n\ndef ensemble_models(models):\n    print(\"Ensembling models\")\n    def ensemble(images):\n        with torch.no_grad():\n            preds = [model(images) for model in models]\n            avg_preds = sum(preds) / len(preds)\n        return avg_preds\n\n    return ensemble","metadata":{"execution":{"iopub.status.busy":"2023-05-10T22:18:52.564968Z","iopub.execute_input":"2023-05-10T22:18:52.565667Z","iopub.status.idle":"2023-05-10T22:18:52.590262Z","shell.execute_reply.started":"2023-05-10T22:18:52.565632Z","shell.execute_reply":"2023-05-10T22:18:52.588906Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Main","metadata":{}},{"cell_type":"code","source":"def kfold_cross_validation():\n    # Load and preprocess data\n    train_base_path = '/kaggle/input/vesuvius-challenge-ink-detection/train'\n    \n    # Create lists to store all images, masks, and inklabels\n    all_images, all_masks, all_inklabels = [], [], []\n    \n    # Iterate over the generator to get all batches of data\n    for images, masks, inklabels in load_data(train_base_path):\n        all_images.extend(images)\n        all_masks.extend(masks)\n        all_inklabels.extend(inklabels)\n    \n    # Convert lists to numpy arrays\n    all_images = np.stack(all_images, axis=0)\n    all_masks = np.stack(all_masks, axis=0)\n    all_inklabels = np.stack(all_inklabels, axis=0)\n    \n    dataset = VesuviusDataset(all_images, all_masks, transforms=get_transforms())\n    \n    kfold = KFold(n_splits=NUM_FOLDS, shuffle=True, random_state=42)\n    models = []\n    \n    for fold, (train_indices, val_indices) in enumerate(kfold.split(dataset)):\n        train_subset = torch.utils.data.Subset(dataset, train_indices)\n        val_subset = torch.utils.data.Subset(dataset, val_indices)\n        \n        train_loader = DataLoader(train_subset, batch_size=8, shuffle=True, num_workers=4)\n        val_loader = DataLoader(val_subset, batch_size=8, shuffle=False, num_workers=4)\n        \n        model = train_one_fold(fold, train_loader, val_loader)\n        models.append(model)\n    \n    return models\n\n# K-Fold Cross Validation and training\nmodels = kfold_cross_validation()\n\n# Ensembling models\nensemble_fn = ensemble_models(models)\n\n# Load test data\ntest_base_path = '/kaggle/input/vesuvius-challenge-ink-detection/test'\ntest_images = []\nfor fragment_id in range(1, 4):\n    fragment_path = os.path.join(test_base_path, str(fragment_id))\n    for i in range(65):\n        image_path = os.path.join(fragment_path, f'surface_volume/{i:02d}.tif')\n        image = cv2.imread(image_path, cv2.IMREAD_GRAYSCALE)\n        test_images.append(image)\n\ntest_data_loader = DataLoader(VesuviusDataset(test_images, None, get_transforms()), batch_size=BATCH_SIZE, shuffle=False)\n\n# Predict and create submission file\npredictions = predict(ensemble_fn, test_data_loader)\ncreate_submission_file(predictions)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Submission","metadata":{}},{"cell_type":"code","source":"import pandas as pd\n\ndef predict(ensemble_fn, test_data_loader):\n    predictions = []\n    with torch.no_grad():\n        for batch in test_data_loader:\n            images = batch\n            images = images.to(DEVICE)\n            outputs = ensemble_fn(images)\n            predictions.extend(outputs.cpu().numpy())\n    return predictions\n\ndef create_submission_file(predictions):\n    submission = pd.DataFrame(columns=['Id', 'Predicted'])\n    for i, pred in enumerate(predictions):\n        rle = rle_encoding(pred.squeeze())\n        submission = submission.append({'Id': str(i), 'Predicted': ' '.join(map(str, rle))}, ignore_index=True)\n    submission.to_csv('submission.csv', index=False)\n\n# Load and preprocess data\nimages, masks = load_data('train')  # Replace with the correct path to your data\n\n# K-Fold Cross Validation and training\nmodels = kfold_cross_validation()\n\n# Ensembling models\nensemble_fn = ensemble_models(models)\n\n# Load test data\ntest_images = [fragment for fragment_id in os.listdir('test') for fragment in load_data(os.path.join('test', fragment_id))[0]]  # Replace with the correct path to your test data\n\n# Flatten the list of test fragments into a single list of image slices\ntest_images = [img_slice for fragment in test_images for img_slice in fragment]\n\ntest_data_loader = DataLoader(VesuviusDataset(test_images, None, get_transforms()), batch_size=BATCH_SIZE, shuffle=False)\n\n# Predict and create submission file\npredictions = predict(ensemble_fn, test_data_loader)\ncreate_submission_file(predictions)","metadata":{},"execution_count":null,"outputs":[]}]}