{"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":"code","source":"# This Python 3 environment comes with many helpful analytics libraries installed\n# It is defined by the kaggle/python Docker image: https://github.com/kaggle/docker-python\n# For example, here's several helpful packages to load\n\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\n\n# Input data files are available in the read-only \"../input/\" directory\n# For example, running this (by clicking run or pressing Shift+Enter) will list all files under the input directory\n\nimport os\nfor dirname, _, filenames in os.walk('/kaggle/input'):\n    for filename in filenames:\n        print(os.path.join(dirname, filename))\n\n# You can write up to 20GB to the current directory (/kaggle/working/) that gets preserved as output when you create a version using \"Save & Run All\" \n# You can also write temporary files to /kaggle/temp/, but they won't be saved outside of the current session","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2023-03-31T23:56:41.325676Z","iopub.execute_input":"2023-03-31T23:56:41.326679Z","iopub.status.idle":"2023-03-31T23:56:41.416803Z","shell.execute_reply.started":"2023-03-31T23:56:41.326613Z","shell.execute_reply":"2023-03-31T23:56:41.415684Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#Loading and testing image recongnition\n#importing Libraries\nimport torch\nimport torch.nn as nn\nimport torch.optim as optim\nimport numpy as np\nimport glob\nimport PIL.Image as Image\nimport torch.utils.data as data\nimport matplotlib.pyplot as plt\nimport matplotlib.patches as patches\nfrom tqdm import tqdm\nfrom ipywidgets import interact, fixed\n\nPREFIX = '/kaggle/input/vesuvius-challenge-ink-detection/train/1/'\nBUFFER = 30 #Buffer Size in x and y direction\nZ_START = 27 #First slice in the z direction to use\nZ_DIM = 10 #Number of slices in the z direction\nTRAINING_STEPS = 30000\nLEARNING_RATE = 0.03\nBATCH_SIZE = 32\nDEVICE = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\n\nplt.imshow(Image.open(PREFIX+\"ir.png\"), cmap=\"gray\")","metadata":{"execution":{"iopub.status.busy":"2023-03-31T23:56:55.048127Z","iopub.execute_input":"2023-03-31T23:56:55.048539Z","iopub.status.idle":"2023-03-31T23:57:00.877058Z","shell.execute_reply.started":"2023-03-31T23:56:55.048502Z","shell.execute_reply":"2023-03-31T23:57:00.876011Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Now we need to load the Binary Images\n* mask.png: a mask of which pixels contain data and which pixels we should ignore\n* inklabels.png: out label data: whether a pixel contains ink or no ink (which has been labeled based on the infrared photo)","metadata":{}},{"cell_type":"code","source":"mask = np.array(Image.open(PREFIX+\"mask.png\").convert('1'))\nlabel = torch.from_numpy(np.array(Image.open(PREFIX+\"inklabels.png\"))).gt(0).float().to(DEVICE)\nfig, (ax1, ax2) = plt.subplots(1,2)\nax1.set_title(\"mask.png\")\nax1.imshow(mask, cmap='gray')\nax2.set_title(\"inklabels.png\")\nax2.imshow(label.cpu(), cmap='gray')\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2023-03-31T23:57:00.878584Z","iopub.execute_input":"2023-03-31T23:57:00.880010Z","iopub.status.idle":"2023-03-31T23:57:06.870495Z","shell.execute_reply.started":"2023-03-31T23:57:00.879967Z","shell.execute_reply":"2023-03-31T23:57:06.869287Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#Load the 3d x-ray scan on slice at the time\nimages = [np.array(Image.open(filename), dtype=np.float32)/65535.0 for filename in tqdm(sorted(glob.glob(PREFIX+\"surface_volume/*.tif\"))[Z_START:Z_START+Z_DIM])]\nimage_stack = torch.stack([torch.from_numpy(image) for image in images], dim=0).to(DEVICE)\n\nfig, axes = plt.subplots(1, len(images), figsize=(15,3))\nfor image, ax in zip(images, axes):\n    ax.imshow(np.array(Image.fromarray(image).resize((image.shape[1]//20, image.shape[0]//20)), dtype=np.float32), cmap='gray')\n    ax.set_xticks([]); ax.set_yticks([])\nfig.tight_layout()\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2023-03-31T23:57:06.872832Z","iopub.execute_input":"2023-03-31T23:57:06.873221Z","iopub.status.idle":"2023-03-31T23:57:27.349594Z","shell.execute_reply.started":"2023-03-31T23:57:06.873182Z","shell.execute_reply":"2023-03-31T23:57:27.348511Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"rect = (1100, 3500, 700, 950)\nfig, ax = plt.subplots()\nax.imshow(label.cpu())\npatch = patches.Rectangle((rect[0], rect[1]), rect[2], rect[3], linewidth=2, edgecolor='r', facecolor='none')\nax.add_patch(patch)\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2023-03-31T23:57:27.351752Z","iopub.execute_input":"2023-03-31T23:57:27.352243Z","iopub.status.idle":"2023-03-31T23:57:29.191462Z","shell.execute_reply.started":"2023-03-31T23:57:27.352201Z","shell.execute_reply":"2023-03-31T23:57:29.190267Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Define a PyTorch Dataset and a simple sample model","metadata":{}},{"cell_type":"code","source":"class SubvolumeDataset(data.Dataset):\n    def __init__(self, image_stack, label, pixels):\n        self.image_stack = image_stack\n        self.label = label\n        self.pixels = pixels\n    def __len__(self):\n        return len(self.pixels)\n    def __getitem__(self, index):\n        y, x = self.pixels[index]\n        subvolume = self.image_stack[:, y-BUFFER:y+BUFFER+1, x-BUFFER:x+BUFFER+1].view(1, Z_DIM, BUFFER*2+1, BUFFER*2+1)\n        inklabel = self.label[y, x].view(1)\n        return subvolume, inklabel\n\nmodel = nn.Sequential(\n    nn.Conv3d(1, 16, 3, 1, 1), nn.MaxPool3d(2, 2),\n    nn.Conv3d(16, 32, 3, 1, 1), nn.MaxPool3d(2, 2),\n    nn.Conv3d(32, 64, 3, 1, 1), nn.MaxPool3d(2, 2),\n    nn.Flatten(start_dim=1),\n    nn.LazyLinear(128), nn.ReLU(),\n    nn.LazyLinear(1), nn.Sigmoid()\n).to(DEVICE)","metadata":{"execution":{"iopub.status.busy":"2023-03-31T23:57:29.193076Z","iopub.execute_input":"2023-03-31T23:57:29.193744Z","iopub.status.idle":"2023-03-31T23:57:29.217128Z","shell.execute_reply.started":"2023-03-31T23:57:29.193702Z","shell.execute_reply":"2023-03-31T23:57:29.215956Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print(\"Generating pixel lists...\")\n# Split our dataset into train and val. The pixels inside the rect are the \n# val set, and the pixels outside the rect are the train set.\npixels_inside_rect = []\npixels_outside_rect = []\nfor pixel in zip(*np.where(mask == 1)):\n    if pixel[1] < BUFFER or pixel[1] >= mask.shape[1]-BUFFER or pixel[0] < BUFFER or pixel[0] >= mask.shape[0]-BUFFER:\n        continue # Too close to the edge\n    if pixel[1] >= rect[0] and pixel[1] <= rect[0]+rect[2] and pixel[0] >= rect[1] and pixel[0] <= rect[1]+rect[3]:\n        pixels_inside_rect.append(pixel)\n    else:\n        pixels_outside_rect.append(pixel)\n\nprint(\"Training...\")\ntrain_dataset = SubvolumeDataset(image_stack, label, pixels_outside_rect)\ntrain_loader = data.DataLoader(train_dataset, batch_size=BATCH_SIZE, shuffle=True)\ncriterion = nn.BCELoss()\noptimizer = optim.SGD(model.parameters(), lr=LEARNING_RATE)\nscheduler = torch.optim.lr_scheduler.OneCycleLR(optimizer, max_lr=LEARNING_RATE, total_steps=TRAINING_STEPS)\nmodel.train()\n# running_loss = 0.0\nfor i, (subvolumes, inklabels) in tqdm(enumerate(train_loader), total=TRAINING_STEPS):\n    if i >= TRAINING_STEPS:\n        break\n    optimizer.zero_grad()\n    outputs = model(subvolumes.to(DEVICE))\n    loss = criterion(outputs, inklabels.to(DEVICE))\n    loss.backward()\n    optimizer.step()\n    scheduler.step()\n#     running_loss += loss.item()\n#     if i % 3000 == 3000-1:\n#         print(\"Loss:\", running_loss / 3000)\n#         running_loss = 0.0","metadata":{"execution":{"iopub.status.busy":"2023-03-31T23:57:29.219772Z","iopub.execute_input":"2023-03-31T23:57:29.220178Z","iopub.status.idle":"2023-04-01T00:06:48.215844Z","shell.execute_reply.started":"2023-03-31T23:57:29.220138Z","shell.execute_reply":"2023-04-01T00:06:48.214487Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"eval_dataset = SubvolumeDataset(image_stack, label, pixels_inside_rect)\neval_loader = data.DataLoader(eval_dataset, batch_size=BATCH_SIZE, shuffle=False)\noutput = torch.zeros_like(label).float()\nmodel.eval()\nwith torch.no_grad():\n    for i, (subvolumes, _) in enumerate(tqdm(eval_loader)):\n        for j, value in enumerate(model(subvolumes.to(DEVICE))):\n            output[pixels_inside_rect[i*BATCH_SIZE+j]] = value\n            \nfig, (ax1, ax2) = plt.subplots(1, 2)\nax1.imshow(output.cpu(), cmap='gray')\nax2.imshow(output.cpu(), cmap='gray')\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2023-04-01T00:06:48.217597Z","iopub.execute_input":"2023-04-01T00:06:48.218105Z","iopub.status.idle":"2023-04-01T00:08:15.618718Z","shell.execute_reply.started":"2023-04-01T00:06:48.218061Z","shell.execute_reply":"2023-04-01T00:08:15.617515Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"THRESHOLD = 0.4\nfig, (ax1, ax2) = plt.subplots(1,2)\nax1.imshow(output.gt(THRESHOLD).cpu(), cmap='gray')\nax2.imshow(label.cpu(), cmap='gray')\nplt.show","metadata":{"execution":{"iopub.status.busy":"2023-04-01T00:19:44.151149Z","iopub.execute_input":"2023-04-01T00:19:44.152106Z","iopub.status.idle":"2023-04-01T00:19:47.914018Z","shell.execute_reply.started":"2023-04-01T00:19:44.152056Z","shell.execute_reply":"2023-04-01T00:19:47.912792Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#Old Code, keeping it for Backup\n#def rle(output):\n    #flat_img = np.where(output.flatten().cpu() > THRESHOLD, 1,0).astype(np.uint8)\n    #starts = np.array((flat_img[:-1] == 0) & (flat_img[1:] ==1))\n    #ends = np.array((flat_img[:-1] == 1) & (flat_img[1:] == 0))\n    #starts_ix = np.where(starts)[0] + 2\n    #ends_ix = np.where(ends)[0] + 2\n    #lenghts = ends_ix - starts_ix\n    #return \" \".join(map(str, sum(zip(starts_ix, lenghts),())))\n#rle_output = rle(output)\n# This doesn't make too much sense, but let's just output in the required format\n# so notebook works as a submission\n#print(\"Id,Predicted\\na,\" + rle_output + \"\\nb,\" + rle_output, file=open('submission.csv', 'w'))","metadata":{"execution":{"iopub.status.busy":"2023-03-31T23:50:43.008962Z","iopub.status.idle":"2023-03-31T23:50:43.009464Z","shell.execute_reply.started":"2023-03-31T23:50:43.009200Z","shell.execute_reply":"2023-03-31T23:50:43.009225Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Modify the rle function to accept a threshold as a parameter\ndef rle(output, THRESHOLD=0.4):\n    flat_img = np.where(output.flatten().cpu() > THRESHOLD, 1, 0).astype(np.uint8)\n    starts = np.array((flat_img[:-1] == 0) & (flat_img[1:] == 1))\n    ends = np.array((flat_img[:-1] == 1) & (flat_img[1:] == 0))\n    starts_ix = np.where(starts)[0] + 2\n    ends_ix = np.where(ends)[0] + 2\n    lengths = ends_ix - starts_ix\n    return \" \".join(map(str, sum(zip(starts_ix, lengths), ())))","metadata":{"execution":{"iopub.status.busy":"2023-04-01T00:19:52.514110Z","iopub.execute_input":"2023-04-01T00:19:52.514515Z","iopub.status.idle":"2023-04-01T00:19:52.522782Z","shell.execute_reply.started":"2023-04-01T00:19:52.514480Z","shell.execute_reply":"2023-04-01T00:19:52.521380Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Update the save_csv function to accept two different rle_outputs\ndef save_csv(rle_output_a, rle_output_b, filename='submission.csv'):\n    df = pd.DataFrame({'Id': ['a', 'b'], 'Predicted': [rle_output_a, rle_output_b]})\n    df.to_csv(filename, index=False)\n\ndef read_and_print_csv(filename='submission.csv'):\n    df = pd.read_csv(filename)\n    print(df)","metadata":{"execution":{"iopub.status.busy":"2023-04-01T00:19:56.945472Z","iopub.execute_input":"2023-04-01T00:19:56.946120Z","iopub.status.idle":"2023-04-01T00:19:56.953568Z","shell.execute_reply.started":"2023-04-01T00:19:56.946075Z","shell.execute_reply":"2023-04-01T00:19:56.952361Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Generate two different rle_outputs using different threshold values\nrle_output_a = rle(output, THRESHOLD=0.4)\nrle_output_b = rle(output, THRESHOLD=0.5)\n\n# Save the rle_outputs to the CSV file\nsave_csv(rle_output_a, rle_output_b)\n\n# Read and print the contents of the CSV file\nread_and_print_csv()","metadata":{"execution":{"iopub.status.busy":"2023-04-01T00:19:58.814024Z","iopub.execute_input":"2023-04-01T00:19:58.815214Z","iopub.status.idle":"2023-04-01T00:20:00.391731Z","shell.execute_reply.started":"2023-04-01T00:19:58.815152Z","shell.execute_reply":"2023-04-01T00:20:00.390565Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#Old Code\n#def save_csv(rle_output, filename='submission.csv'):\n    #df = pd.DataFrame({'Id': ['a', 'b'], 'Predicted': [rle_output, rle_output]})\n    #df.to_csv(filename, index=False)\n\n#def read_and_print_csv(filename='submission.csv'):\n    #df = pd.read_csv(filename)\n    #print(df)\n\n#rle_output = rle(output)\n#save_csv(rle_output)\n\n# Read and print the contents of the CSV file\n#read_and_print_csv()","metadata":{"execution":{"iopub.status.busy":"2023-03-30T23:28:58.855136Z","iopub.execute_input":"2023-03-30T23:28:58.855522Z","iopub.status.idle":"2023-03-30T23:28:59.737105Z","shell.execute_reply.started":"2023-03-30T23:28:58.855489Z","shell.execute_reply":"2023-03-30T23:28:59.735948Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{"execution":{"iopub.status.busy":"2023-03-30T23:26:23.271010Z","iopub.execute_input":"2023-03-30T23:26:23.272029Z","iopub.status.idle":"2023-03-30T23:26:23.283176Z","shell.execute_reply.started":"2023-03-30T23:26:23.271991Z","shell.execute_reply":"2023-03-30T23:26:23.282098Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}