From f1bbca0489f54938f36415a2f281c64a016d5193 Mon Sep 17 00:00:00 2001 From: Shreya Singh Date: Tue, 26 Oct 2021 15:20:05 -0400 Subject: [PATCH 01/29] pytorch benchmarking notebook --- experiments/pytorch_model/pytorch.ipynb | 1050 +++++++++++++++++++++++ 1 file changed, 1050 insertions(+) create mode 100644 experiments/pytorch_model/pytorch.ipynb diff --git a/experiments/pytorch_model/pytorch.ipynb b/experiments/pytorch_model/pytorch.ipynb new file mode 100644 index 000000000..74c031d58 --- /dev/null +++ b/experiments/pytorch_model/pytorch.ipynb @@ -0,0 +1,1050 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 40, + "id": "c114a9d9", + "metadata": {}, + "outputs": [], + "source": [ + "from skimage import io\n", + "import scipy.ndimage as ndi\n", + "import random\n", + "from tqdm import tqdm\n", + "import numpy as np\n", + "from sklearn.model_selection import KFold\n", + "from sklearn.neural_network import MLPClassifier\n", + "from sklearn.linear_model import LogisticRegression\n", + "from sklearn.metrics import roc_curve, auc, jaccard_score\n", + "import matplotlib.pyplot as plt\n", + "from scipy.spatial.distance import dice\n", + "\n", + "from pathlib import Path\n", + "import os" + ] + }, + { + "cell_type": "code", + "execution_count": 41, + "id": "9c3b7465", + "metadata": {}, + "outputs": [], + "source": [ + "import torch\n", + "from torch import nn\n", + "from torch.utils.data import DataLoader\n", + "from torchvision import datasets\n", + "from torchvision.transforms import ToTensor, Lambda, Compose\n", + "import matplotlib.pyplot as plt\n", + "from sklearn.metrics import accuracy_score, precision_score, recall_score, precision_recall_curve" + ] + }, + { + "cell_type": "code", + "execution_count": 42, + "id": "8809d925", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Downloading segments to /users/shrey2/Documents/NDD/brainlit/docs/notebooks/utils/data\n" + ] + } + ], + "source": [ + "data_dir = \"/users/shrey2/Documents/NDD/brainlit/docs/notebooks/utils/data\"\n", + "print(f\"Downloading segments to {data_dir}\")\n", + "if not os.path.exists(data_dir):\n", + " os.makedirs(data_dir)\n", + "\n", + "im_dir = Path(os.path.join(data_dir, \"sample-tif-location\"))\n", + "if not os.path.exists(im_dir):\n", + " os.makedirs(im_dir)\n", + "\n", + "swc_dir = os.path.join(data_dir, \"sample-swc-location\")\n", + "if not os.path.exists(swc_dir):\n", + " os.makedirs(swc_dir)\n", + "\n", + "mask_dir = Path(os.path.join(data_dir, \"mask-location\"))\n", + "\n", + "swc_base_path = Path(swc_dir) / \"Manual-GT\"\n", + "\n", + "gfp_files = list(im_dir.glob(\"**/*-gfp.tif\"))\n", + "\n", + "ms = \"\"" + ] + }, + { + "cell_type": "code", + "execution_count": 43, + "id": "0354dfe0", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "100%|███████████████████████████████████████████| 50/50 [00:10<00:00, 4.61it/s]\n" + ] + } + ], + "source": [ + "X_torch = []\n", + "y_torch = []\n", + "\n", + "for i, im_path in enumerate(tqdm(gfp_files)):\n", + "\n", + " f = im_path.parts[-1][:-8].split(\"_\")\n", + " image = f[0]\n", + " num = int(f[1])\n", + "\n", + " if (image == \"test\" and num in [9,10,24]) or (image == \"validation\" and num in [11]):\n", + " continue\n", + "\n", + " #getting image\n", + " im = io.imread(im_path, plugin=\"tifffile\")\n", + " im = (im - np.amin(im)) / (np.amax(im) - np.amin(im))\n", + " im = np.swapaxes(im,0,2)\n", + " im_padded = np.pad(im, ((4,4), (4,4), (3,3)) )\n", + " \n", + " #getting ground truth mask\n", + " file_name = str(im_path)[str(im_path).find(\"\\\\\", 80) + 1 : (str(im_path).find(\"sample\"))] + \"/mask-location/\"\n", + " file_num = file_name[file_name.find(\"_\")+1:]\n", + " if file_name[0] == 'v':\n", + " file_num = str(int(file_num)+25)\n", + " mask_path = Path(file_name + f[0] + \"_\" + f[1] + \"_mask.npy\")\n", + " mask = np.load(mask_path)\n", + " \n", + " X_torch.append(im)\n", + " y_torch.append(mask)" + ] + }, + { + "cell_type": "code", + "execution_count": 44, + "id": "b0873219", + "metadata": {}, + "outputs": [], + "source": [ + "X_torch_train = X_torch[0:30]\n", + "y_torch_train = y_torch[0:30]\n", + "x_torch_test = X_torch[31:45]\n", + "y_torch_test = y_torch[31:45]\n", + "\n", + "training_data = torch.tensor([X_torch_train, y_torch_train]).float()\n", + "test_data = torch.tensor([x_torch_test, y_torch_test]).float()\n", + "\n", + "batch_size = 2\n", + "\n", + "# Create data loaders.\n", + "train_dataloader = DataLoader(training_data, batch_size=batch_size)\n", + "test_dataloader = DataLoader(test_data, batch_size=batch_size)" + ] + }, + { + "cell_type": "code", + "execution_count": 45, + "id": "eff21f3b", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Feature batch shape: torch.Size([30, 330, 330, 100])\n", + "Labels batch shape: torch.Size([30, 330, 330, 100])\n", + "Using cpu device\n" + ] + } + ], + "source": [ + "train_features, train_labels = next(iter(train_dataloader))\n", + "print(f\"Feature batch shape: {train_features.size()}\")\n", + "print(f\"Labels batch shape: {train_labels.size()}\")\n", + "\n", + "device = 'cuda' if torch.cuda.is_available() else 'cpu'\n", + "print('Using {} device'.format(device))" + ] + }, + { + "cell_type": "markdown", + "id": "db730628", + "metadata": {}, + "source": [ + "### Manual Baseline Pytorch Model" + ] + }, + { + "cell_type": "code", + "execution_count": 47, + "id": "c1383a2d", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "NeuralNetwork(\n", + " (linear_relu_stack): Sequential(\n", + " (0): Conv2d(330, 660, kernel_size=(1, 1), stride=(1, 1))\n", + " (1): ReLU()\n", + " (2): Conv2d(660, 990, kernel_size=(1, 1), stride=(1, 1))\n", + " (3): ReLU()\n", + " (4): Conv2d(990, 10, kernel_size=(1, 1), stride=(1, 1))\n", + " (5): ReLU()\n", + " (6): Conv2d(10, 330, kernel_size=(1, 1), stride=(1, 1))\n", + " (7): ConvTranspose2d(330, 330, kernel_size=(1, 1), stride=(1, 1))\n", + " )\n", + ")\n" + ] + } + ], + "source": [ + "class NeuralNetwork(nn.Module):\n", + " def __init__(self):\n", + " super(NeuralNetwork, self).__init__()\n", + " #self.flatten = nn.Flatten()\n", + " self.linear_relu_stack = nn.Sequential(\n", + " #nn.Linear(10890000, 46),\n", + " #nn.ReLU(),\n", + " #nn.Linear(46, 46),\n", + " #nn.ReLU(),\n", + " #nn.Linear(46, 10),\n", + " nn.Conv2d(330, 660, 1, 1),\n", + " nn.ReLU(),\n", + " nn.Conv2d(660, 990, 1, 1),\n", + " nn.ReLU(),\n", + " nn.Conv2d(990, 10, 1, 1),\n", + " nn.ReLU(),\n", + " nn.Conv2d(10, 330, 1, 1),\n", + " \n", + " nn.ConvTranspose2d(330, 330, 1, 1),\n", + "\n", + " #nn.ConvTranspose2D(330, 330, 1, 1)\n", + " #nn.Conv2d(330, 330, 1, 1),\n", + " #nn.Conv2d(330, 330, 1, 1),\n", + "\n", + " #nn.Conv2d(660, 660, 1, 1),\n", + " #nn.Conv2d(660, 330, 1, 1),\n", + "\n", + " #nn.MaxPool2d(330),\n", + " #nn.Linear(1000, 330),\n", + "\n", + " #nn.Conv2d(100, 100, 1, 1),\n", + " #nn.Conv2d(100, 330, 1, 1),\n", + " #nn.Linear(330,330),\n", + " )\n", + "\n", + " def forward(self, x):\n", + " #x = self.flatten(x)\n", + " logits = self.linear_relu_stack(x)\n", + " #logits = self.linear(x)\n", + " #logits = nn.Softmax(dim=1)(logits)\n", + " self.Sigmoid = nn.Sigmoid()\n", + " logits = self.Sigmoid(logits)\n", + " #logits = torch.round(x).clone()\n", + " return logits\n", + " \n", + "model = NeuralNetwork().to(device)\n", + "print(model)" + ] + }, + { + "cell_type": "code", + "execution_count": 48, + "id": "3c16154b", + "metadata": {}, + "outputs": [], + "source": [ + "def train_loop(dataloader, model, loss_fn, optimizer):\n", + " size = len(dataloader.dataset)\n", + " #size = 330*330*100*14\n", + " y_true = []\n", + " y_pred = []\n", + " for batch, (X, y) in enumerate(dataloader):\n", + " #for (X, y) in enumerate(dataloader):\n", + " #print(X)\n", + " # Compute prediction and loss\n", + " #print(batch)\n", + " #print(X.shape)\n", + " #X = X.unsqueeze(3)\n", + " #print(X.shape)\n", + " optimizer.zero_grad()\n", + " pred = model(X)\n", + " pred = torch.squeeze(pred, 3).clone()\n", + " #pred = torch.squeeze(pred, 3)\n", + " #print(pred.shape)\n", + " #print(y.shape)\n", + "\n", + " loss = loss_fn(pred, y)\n", + "\n", + " # Backpropagation\n", + " #optimizer.zero_grad()\n", + " loss.backward()\n", + " optimizer.step()\n", + " \n", + " #getting accuracy\n", + " #pred_r = np.round(pred.detach().numpy())\n", + " #target = y.float()\n", + " #y_true.extend(target.tolist()) \n", + " #y_pred.extend(pred_r.reshape(-1).tolist())\n", + " #print(len(y_true))\n", + " #print(len(y_pred))\n", + " \n", + " if batch % 100 == 0:\n", + " loss, current = loss.item(), batch * len(X)\n", + " print(f\"loss: {loss:>7f} [{current:>5d}/{size:>5d}]\")\n", + " \n", + " #print(\"Accuracy on training set is\", accuracy_score(y_true,y_pred))\n", + "\n", + "\n", + "\n", + "def test_loop(dataloader, model, loss_fn):\n", + " #size = len(dataloader.dataset)\n", + " size = 330*330*100*14\n", + " print(\"Size: \", size)\n", + " num_batches = len(dataloader)\n", + " test_loss, correct = 0, 0\n", + " \n", + " y_true = []\n", + " y_pred = []\n", + "\n", + "\n", + " with torch.no_grad():\n", + " for X, y in dataloader:\n", + " #X = X.unsqueeze(3)\n", + " pred = model(X)\n", + " pred = torch.squeeze(pred, 3)\n", + " test_loss += loss_fn(pred, y).item()\n", + " #print(pred.shape)\n", + " #print(y.shape)\n", + " correct += (pred == y).type(torch.float).sum().item()\n", + " #correct += y.sum()\n", + " \n", + " #PREDICTIONS\n", + " #pred_r = np.round(pred)\n", + " #target = y.float()\n", + " #y_true.extend(target.tolist()) \n", + " #y_pred.extend(pred_r.reshape(-1).tolist())\n", + " \n", + " #print(\"Accuracy on test set is\" , accuracy_score(y_true,y_pred))\n", + " \n", + " test_loss /= num_batches\n", + " correct /= size\n", + " print(\"Correct: \", correct)\n", + " print(f\"Test Error: \\n Accuracy: {(100*correct):>0.1f}%, Avg loss: {test_loss:>8f} \\n\")\n", + " \n", + " return pred, test_loss" + ] + }, + { + "cell_type": "code", + "execution_count": 49, + "id": "03cb1ccb", + "metadata": {}, + "outputs": [], + "source": [ + "#pred, pred_list, loss_list = test_loop(test_dataloader, model, loss_fn)" + ] + }, + { + "cell_type": "code", + "execution_count": 50, + "id": "1a85b50f", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Epoch 1\n", + "-------------------------------\n", + "loss: 0.696159 [ 0/ 2]\n", + "Size: 152460000\n", + "Correct: 0.0\n", + "Test Error: \n", + " Accuracy: 0.0%, Avg loss: 0.688285 \n", + "\n", + "Epoch 2\n", + "-------------------------------\n", + "loss: 0.688274 [ 0/ 2]\n", + "Size: 152460000\n", + "Correct: 0.0\n", + "Test Error: \n", + " Accuracy: 0.0%, Avg loss: 0.680542 \n", + "\n", + "Epoch 3\n", + "-------------------------------\n", + "loss: 0.680528 [ 0/ 2]\n", + "Size: 152460000\n", + "Correct: 0.0\n", + "Test Error: \n", + " Accuracy: 0.0%, Avg loss: 0.672908 \n", + "\n", + "Done!\n" + ] + } + ], + "source": [ + "loss_fn = nn.BCELoss()\n", + "learning_rate = 0.8\n", + "optimizer = torch.optim.SGD(model.parameters(), lr=learning_rate)\n", + "epochs = 3\n", + "\n", + "pred_list = []\n", + "loss_list = []\n", + "\n", + "for t in range(epochs):\n", + " print(f\"Epoch {t+1}\\n-------------------------------\")\n", + " train_loop(train_dataloader, model, loss_fn, optimizer)\n", + " pred, loss = test_loop(test_dataloader, model, loss_fn)\n", + " pred_list.append(pred)\n", + " loss_list.append(loss)\n", + "print(\"Done!\")" + ] + }, + { + "cell_type": "code", + "execution_count": 51, + "id": "43045fd3", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Accuracy: 0.6448780532598715\n", + "Precision: 0.0013692552851777792\n", + "Recall: 0.31793854110289255\n", + "Nonzeros: 3861223\n", + "Nonzeros percent: 35.456593204775025\n" + ] + } + ], + "source": [ + "preds_0 = pred.numpy()[0].round().astype(int)\n", + "\n", + "print(\"Accuracy: \", accuracy_score(y_torch_test[0].astype(int).flatten(), preds_0.flatten()))\n", + "print(\"Precision: \", precision_score(y_torch_test[0].astype(int).flatten(), preds_0.flatten()))\n", + "print(\"Recall: \", recall_score(y_torch_test[0].astype(int).flatten(), preds_0.flatten()))\n", + "print(\"Nonzeros: \", np.count_nonzero(preds_0.flatten()))\n", + "print(\"Nonzeros percent: \", np.count_nonzero(preds_0.flatten()) / len(y_torch_test[0].astype(int).flatten()) * 100)" + ] + }, + { + "cell_type": "code", + "execution_count": 57, + "id": "b42ebefd", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "torch.Size([14, 330, 330, 100])" + ] + }, + "execution_count": 57, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "pred_list[0].shape" + ] + }, + { + "cell_type": "code", + "execution_count": 75, + "id": "ffd0a468", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "330\n", + "330\n", + "330\n" + ] + }, + { + "data": { + "text/plain": [ + "[]" + ] + }, + "execution_count": 75, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "import matplotlib.pyplot as plt\n", + "\n", + "acc_list = []\n", + "nonzero_list = []\n", + "for i in range(len(loss_list)):\n", + " pred = pred_list[0][i].numpy().round().astype(int)\n", + " print(len(pred))\n", + " acc = accuracy_score(y_torch_test[i].astype(int).flatten(), pred.flatten())\n", + " acc_list.append(acc)\n", + " \n", + " nonzero = np.count_nonzero(pred.flatten()) / len(y_torch_test[i].astype(int).flatten()) * 100\n", + " nonzero_list.append(nonzero)\n", + "\n", + "plt.figure()\n", + "plt.title(\"Accuracy over 3 epochs\")\n", + "plt.xlabel(\"epochs\")\n", + "plt.ylabel(\"accuracy\")\n", + "plt.plot(acc_list)\n", + "\n", + "plt.figure()\n", + "plt.title(\"% of nonzero predictions over 2 epochs\")\n", + "plt.xlabel(\"epochs\")\n", + "plt.ylabel(\"% nonzero preds\")\n", + "plt.plot(nonzero_list)" + ] + }, + { + "cell_type": "code", + "execution_count": 64, + "id": "e7f1674c", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[0.6882847547531128, 0.6805418133735657, 0.6729077696800232]" + ] + }, + "execution_count": 64, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "plt.figure()\n", + "plt.title(\"Loss over 3 epochs\")\n", + "plt.xlabel(\"epochs\")\n", + "plt.ylabel(\"Loss\")\n", + "plt.plot(loss_list)\n", + "\n", + "loss_list" + ] + }, + { + "cell_type": "code", + "execution_count": 73, + "id": "2c8fea0b", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(330, 330, 100)" + ] + }, + "execution_count": 73, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "pred_list[0][0].numpy().round().astype(int).shape" + ] + }, + { + "cell_type": "code", + "execution_count": 74, + "id": "eaa8e3ec", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/napari/_qt/qt_event_loop.py:256: FutureWarning: \n", + "The 'gui_qt()' context manager is deprecated.\n", + "If you are running napari from a script, please use 'napari.run()' as follows:\n", + "\n", + " import napari\n", + "\n", + " viewer = napari.Viewer() # no prior setup needed\n", + " # other code using the viewer...\n", + " napari.run()\n", + "\n", + "In IPython or Jupyter, 'napari.run()' is not necessary. napari will automatically\n", + "start an interactive event loop for you: \n", + "\n", + " import napari\n", + " viewer = napari.Viewer() # that's it!\n", + "\n", + " warn(\n" + ] + } + ], + "source": [ + "import napari\n", + "with napari.gui_qt():\n", + " viewer = napari.Viewer(ndisplay=3)\n", + " viewer.add_image((x_torch_test[0]))\n", + " viewer.add_labels((y_torch_test[0]).astype(int))\n", + " viewer.add_labels(pred_list[0][0].numpy().round().astype(int))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "189b418e", + "metadata": {}, + "outputs": [], + "source": [ + "precision, recall, thresholds = precision_recall_curve(y_torch_test[0].astype(int).flatten(), pred.numpy()[0].astype(int).flatten())\n", + "\n", + "plt.plot(precision, recall)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "10eb0c6c", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "id": "626fc9a5", + "metadata": {}, + "source": [ + "### AlexNet" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0a1fa990", + "metadata": {}, + "outputs": [], + "source": [ + "import torch\n", + "model = torch.hub.load('pytorch/vision:v0.10.0', 'alexnet', pretrained=True)\n", + "model.eval()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1a6a0cd8", + "metadata": {}, + "outputs": [], + "source": [ + "#model.features[0] = nn.Conv2d(330, 3, 1, 1),\n", + "#model.Conv2D = nn.Conv2D(330, 330, 1, 1)\n", + "model.features[0] = nn.Conv2d(330, 64, 1, 1)\n", + "#model.features[12] = nn.Conv2d(256, 9216, 1, 1)\n", + "\n", + "#model.fc = nn.Linear(4096, 330) \n", + "#model.classifier[1] = nn.Conv2d(9216, 4096, 1, 1)\n", + "#model.classifier[4] = nn.Conv2d(4096, 4096, 1, 1)\n", + "model.classifier[6] = nn.Conv2d(4096, 330, 1, 1)\n", + "\n", + "#model.classifier[6] = nn.ConvTranspose2d(4096, 330, 1, 1)\n", + "model.eval()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d37ade53", + "metadata": {}, + "outputs": [], + "source": [ + "correct = 0\n", + "with torch.no_grad():\n", + " for X, y in test_dataloader:\n", + " pred = model(X)\n", + " #pred = torch.squeeze(pred, 3)\n", + " #test_loss += loss_fn(pred, y).item()\n", + " \n", + " #correct += (pred == y).type(torch.float).sum().item()\n", + " \n", + "\n", + "#print(\"Correct: \", correct)\n", + "#print(f\"Test Error: \\n Accuracy: {(100*correct):>0.1f}%Avg loss: {test_loss:>8f} \\n\")\n", + " \n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "23850803", + "metadata": { + "scrolled": false + }, + "outputs": [], + "source": [ + "with torch.no_grad():\n", + " output = model(test_dataloader)\n", + "print(output[0])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f06b9541", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "id": "e0590064", + "metadata": {}, + "source": [ + "### uNet" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3a18c23b", + "metadata": {}, + "outputs": [], + "source": [ + "import torch\n", + "import torch.nn as nn\n", + "import torch.nn.functional as F\n", + "\n", + "\n", + "class DoubleConv(nn.Module):\n", + " \"\"\"(convolution => [BN] => ReLU) * 2\"\"\"\n", + "\n", + " def __init__(self, in_channels, out_channels, mid_channels=None):\n", + " super().__init__()\n", + " if not mid_channels:\n", + " mid_channels = out_channels\n", + " self.double_conv = nn.Sequential(\n", + " nn.Conv2d(in_channels, mid_channels, kernel_size=1, padding=1),\n", + " nn.BatchNorm2d(mid_channels),\n", + " nn.ReLU(inplace=True),\n", + " nn.Conv2d(mid_channels, out_channels, kernel_size=1, padding=1),\n", + " nn.BatchNorm2d(out_channels),\n", + " nn.ReLU(inplace=True)\n", + " )\n", + "\n", + " def forward(self, x):\n", + " return self.double_conv(x)\n", + "\n", + "\n", + "class Down(nn.Module):\n", + " \"\"\"Downscaling with maxpool then double conv\"\"\"\n", + "\n", + " def __init__(self, in_channels, out_channels):\n", + " super().__init__()\n", + " self.maxpool_conv = nn.Sequential(\n", + " nn.MaxPool2d(2),\n", + " DoubleConv(in_channels, out_channels)\n", + " )\n", + " \n", + "\n", + " def forward(self, x):\n", + " return self.maxpool_conv(x)\n", + "\n", + "\n", + "class Up(nn.Module):\n", + " \"\"\"Upscaling then double conv\"\"\"\n", + "\n", + " def __init__(self, in_channels, out_channels, bilinear=True):\n", + " super().__init__()\n", + "\n", + " # if bilinear, use the normal convolutions to reduce the number of channels\n", + " if bilinear:\n", + " self.up = nn.Upsample(scale_factor=2, mode='bilinear', align_corners=True)\n", + " self.conv = DoubleConv(in_channels, out_channels, in_channels // 2)\n", + " else:\n", + " self.up = nn.ConvTranspose2d(in_channels, in_channels // 2, kernel_size=1, stride=1)\n", + " self.conv = DoubleConv(in_channels, out_channels)\n", + "\n", + " def forward(self, x1, x2):\n", + " x1 = self.up(x1)\n", + " # input is CHW\n", + " diffY = x2.size()[2] - x1.size()[2]\n", + " diffX = x2.size()[3] - x1.size()[3]\n", + "\n", + " x1 = F.pad(x1, [diffX // 2, diffX - diffX // 2,\n", + " diffY // 2, diffY - diffY // 2])\n", + " # if you have padding issues, see\n", + " # https://github.com/HaiyongJiang/U-Net-Pytorch-Unstructured-Buggy/commit/0e854509c2cea854e247a9c615f175f76fbb2e3a\n", + " # https://github.com/xiaopeng-liao/Pytorch-UNet/commit/8ebac70e633bac59fc22bb5195e513d5832fb3bd\n", + " x = torch.cat([x2, x1], dim=1)\n", + " return self.conv(x)\n", + "\n", + "\n", + "class OutConv(nn.Module):\n", + " def __init__(self, in_channels, out_channels):\n", + " super(OutConv, self).__init__()\n", + " self.conv = nn.Conv2d(in_channels, out_channels, kernel_size=1)\n", + "\n", + " def forward(self, x):\n", + " return self.conv(x)\n", + " " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "be4f852a", + "metadata": {}, + "outputs": [], + "source": [ + "class UNet(nn.Module):\n", + " def __init__(self, n_channels, n_classes, bilinear=False):\n", + " super(UNet, self).__init__()\n", + " self.n_channels = n_channels\n", + " self.n_classes = n_classes\n", + " self.bilinear = bilinear\n", + "\n", + " self.inc = DoubleConv(n_channels, 330)\n", + " self.down1 = Down(330, 330)\n", + " self.down2 = Down(330, 330)\n", + " self.down3 = Down(330, 330)\n", + " factor = 2 if bilinear else 1\n", + " self.down4 = Down(330, 330 // factor)\n", + " self.up1 = Up(330, 330 // factor, bilinear)\n", + " self.up2 = Up(330, 330 // factor, bilinear)\n", + " self.up3 = Up(330, 330 // factor, bilinear)\n", + " self.up4 = Up(330, 330, bilinear)\n", + " self.outc = OutConv(330, n_classes)\n", + "\n", + " def forward(self, x):\n", + " x1 = self.inc(x)\n", + " x2 = self.down1(x1)\n", + " x3 = self.down2(x2)\n", + " x4 = self.down3(x3)\n", + " x5 = self.down4(x4)\n", + " x = self.up1(x5, x4)\n", + " x = self.up2(x, x3)\n", + " x = self.up3(x, x2)\n", + " x = self.up4(x, x1)\n", + " logits = self.outc(x)\n", + " return logits\n", + " \n", + "UNetModel = UNet(330, 330).to(device)\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "51ba0a57", + "metadata": { + "scrolled": true + }, + "outputs": [], + "source": [ + "#for X, y in test_dataloader:\n", + "# with torch.no_grad():\n", + "# output = UNetModel(X)\n", + "# # Tensor of shape 1000, with confidence scores over Imagenet's 1000 classes\n", + "# print(output[0].shape)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ab8bd0c0", + "metadata": {}, + "outputs": [], + "source": [ + "def train_loop(dataloader, model, loss_fn, optimizer):\n", + " size = len(dataloader.dataset)\n", + " #size = 330*330*100*14\n", + " y_true = []\n", + " y_pred = []\n", + " for batch, (X, y) in enumerate(dataloader):\n", + "\n", + " optimizer.zero_grad()\n", + " pred = model(X)\n", + " pred = torch.squeeze(pred, 3).clone()\n", + " #pred = torch.squeeze(pred, 3)\n", + " #print(pred.shape)\n", + " #print(y.shape)\n", + "\n", + " loss = loss_fn(pred, y)\n", + "\n", + " # Backpropagation\n", + " #optimizer.zero_grad()\n", + " loss.backward()\n", + " optimizer.step()\n", + " \n", + " #getting accuracy\n", + " #pred_r = np.round(pred.detach().numpy())\n", + " #target = y.float()\n", + " #y_true.extend(target.tolist()) \n", + " #y_pred.extend(pred_r.reshape(-1).tolist())\n", + " #print(len(y_true))\n", + " #print(len(y_pred))\n", + " \n", + " if batch % 100 == 0:\n", + " loss, current = loss.item(), batch * len(X)\n", + " print(f\"loss: {loss:>7f} [{current:>5d}/{size:>5d}]\")\n", + " \n", + " #print(\"Accuracy on training set is\", accuracy_score(y_true,y_pred))\n", + "\n", + "\n", + "def test_loop(dataloader, model, loss_fn):\n", + " #size = len(dataloader.dataset)\n", + " size = 330*330*100*14\n", + " print(\"Size: \", size)\n", + " num_batches = len(dataloader)\n", + " test_loss, correct = 0, 0\n", + " \n", + " y_true = []\n", + " y_pred = []\n", + "\n", + " with torch.no_grad():\n", + " for X, y in dataloader:\n", + " #X = X.unsqueeze(3)\n", + " pred = model(X)\n", + " #pred = torch.squeeze(pred, 3)\n", + " test_loss += loss_fn(pred, y).item()\n", + " #print(pred.shape)\n", + " #print(y.shape)\n", + " correct += (pred == y).type(torch.float).sum().item()\n", + " #correct += y.sum()\n", + " \n", + " #PREDICTIONS\n", + " #pred_r = np.round(pred)\n", + " #target = y.float()\n", + " #y_true.extend(target.tolist()) \n", + " #y_pred.extend(pred_r.reshape(-1).tolist())\n", + " \n", + " #print(\"Accuracy on test set is\" , accuracy_score(y_true,y_pred))\n", + " \n", + " test_loss /= num_batches\n", + " correct /= size\n", + " print(\"Correct: \", correct)\n", + " print(f\"Test Error: \\n Accuracy: {(100*correct):>0.1f}%, Avg loss: {test_loss:>8f} \\n\")\n", + " \n", + " return pred" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "54b501cb", + "metadata": { + "scrolled": true + }, + "outputs": [], + "source": [ + "loss_fn = nn.BCELoss()\n", + "learning_rate = 0.8\n", + "optimizer = torch.optim.SGD(UNetModel.parameters(), lr=learning_rate)\n", + "epochs = 5\n", + "\n", + "for t in range(epochs):\n", + " print(f\"Epoch {t+1}\\n-------------------------------\")\n", + " train_loop(train_dataloader, UNetModel, loss_fn, optimizer)\n", + " pred = test_loop(test_dataloader, UNetModel, loss_fn)\n", + "print(\"Done!\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f305f74e", + "metadata": {}, + "outputs": [], + "source": [ + "output_norm = output.numpy()\n", + "output_norm = abs(output_norm).astype(int)\n", + "print(\"nonzero num: \", np.count_nonzero(output_norm))\n", + "print(output_norm[0].shape)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "32789ee6", + "metadata": {}, + "outputs": [], + "source": [ + "preds_0 = output_norm[0]\n", + "\n", + "print(\"Accuracy: \", accuracy_score(y_torch_test[0].astype(int).flatten(), preds_0.flatten()))\n", + "print(\"Precision: \", precision_score(y_torch_test[0].astype(int).flatten(), preds_0.flatten()))\n", + "print(\"Recall: \", recall_score(y_torch_test[0].astype(int).flatten(), preds_0.flatten()))\n", + "print(\"Nonzeros: \", np.count_nonzero(preds_0.flatten()))\n", + "print(\"Nonzeros percent: \", np.count_nonzero(preds_0.flatten()) / len(y_torch_test[0].astype(int).flatten()) * 100)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1b42e5cc", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.7" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} From e585e548e5999d5f6bb76a3a682b00ccd6d96aa5 Mon Sep 17 00:00:00 2001 From: shreyasingh1 Date: Tue, 1 Mar 2022 18:38:44 -0500 Subject: [PATCH 02/29] cleaned pytorch notebook --- .../pytorch_model/pytorch - cleaned.ipynb | 2308 +++++++++++++++++ 1 file changed, 2308 insertions(+) create mode 100644 experiments/pytorch_model/pytorch - cleaned.ipynb diff --git a/experiments/pytorch_model/pytorch - cleaned.ipynb b/experiments/pytorch_model/pytorch - cleaned.ipynb new file mode 100644 index 000000000..8ae0bbe4a --- /dev/null +++ b/experiments/pytorch_model/pytorch - cleaned.ipynb @@ -0,0 +1,2308 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "id": "83bb4632", + "metadata": {}, + "outputs": [], + "source": [ + "from skimage import io\n", + "import scipy.ndimage as ndi\n", + "import random\n", + "from tqdm import tqdm\n", + "import numpy as np\n", + "from sklearn.model_selection import KFold\n", + "from sklearn.neural_network import MLPClassifier\n", + "from sklearn.linear_model import LogisticRegression\n", + "from sklearn.metrics import roc_curve, auc, jaccard_score\n", + "import matplotlib.pyplot as plt\n", + "from scipy.spatial.distance import dice\n", + "\n", + "from pathlib import Path\n", + "import os\n", + "\n", + "from tqdm.notebook import tqdm\n", + "\n", + "import warnings\n", + "warnings.filterwarnings('ignore')" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "74dc6f71", + "metadata": {}, + "outputs": [], + "source": [ + "import torch\n", + "from torch import nn\n", + "from torch.utils.data import DataLoader\n", + "from torchvision import datasets\n", + "from torchvision.transforms import ToTensor, Lambda, Compose\n", + "import matplotlib.pyplot as plt\n", + "from sklearn.metrics import accuracy_score, precision_score, recall_score, precision_recall_curve" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "32ea5eba", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Downloading segments to /users/shrey2/Documents/NDD/brainlit/docs/notebooks/utils/data\n" + ] + } + ], + "source": [ + "data_dir = \"/users/shrey2/Documents/NDD/brainlit/docs/notebooks/utils/data\"\n", + "print(f\"Downloading segments to {data_dir}\")\n", + "if not os.path.exists(data_dir):\n", + " os.makedirs(data_dir)\n", + "\n", + "im_dir = Path(os.path.join(data_dir, \"sample-tif-location\"))\n", + "if not os.path.exists(im_dir):\n", + " os.makedirs(im_dir)\n", + "\n", + "swc_dir = os.path.join(data_dir, \"sample-swc-location\")\n", + "if not os.path.exists(swc_dir):\n", + " os.makedirs(swc_dir)\n", + "\n", + "mask_dir = Path(os.path.join(data_dir, \"mask-location\"))\n", + "\n", + "swc_base_path = Path(swc_dir) / \"Manual-GT\"\n", + "\n", + "gfp_files = list(im_dir.glob(\"**/*-gfp.tif\"))\n", + "\n", + "ms = \"\"" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "8911c3c6", + "metadata": {}, + "outputs": [ + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "79fc0db9bc2942e587eaf4c4adb40812", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + " 0%| | 0/50 [00:00\n", + "Traceback (most recent call last):\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/events.py\", line 80, in _run\n", + " self._context.run(self._callback, *self._args)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/tornado/platform/asyncio.py\", line 189, in _handle_events\n", + " handler_func(fileobj, events)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 452, in _handle_events\n", + " self._handle_recv()\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 481, in _handle_recv\n", + " self._run_callback(callback, msg)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 431, in _run_callback\n", + " callback(*args, **kwargs)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/jupyter_client/threaded.py\", line 121, in _handle_recv\n", + " msg_list = self.ioloop._asyncio_event_loop.run_until_complete(get_msg(future_msg))\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 618, in run_until_complete\n", + " self._check_running()\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 580, in _check_running\n", + " raise RuntimeError(\n", + "RuntimeError: Cannot run the event loop while another loop is running\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Optimal Threshold for image 2: 0.48569155\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "ERROR:tornado.general:Uncaught exception in ZMQStream callback\n", + "Traceback (most recent call last):\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 431, in _run_callback\n", + " callback(*args, **kwargs)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/jupyter_client/threaded.py\", line 121, in _handle_recv\n", + " msg_list = self.ioloop._asyncio_event_loop.run_until_complete(get_msg(future_msg))\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 618, in run_until_complete\n", + " self._check_running()\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 580, in _check_running\n", + " raise RuntimeError(\n", + "RuntimeError: Cannot run the event loop while another loop is running\n", + "Exception in callback BaseAsyncIOLoop._handle_events(161, 1)\n", + "handle: \n", + "Traceback (most recent call last):\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/events.py\", line 80, in _run\n", + " self._context.run(self._callback, *self._args)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/tornado/platform/asyncio.py\", line 189, in _handle_events\n", + " handler_func(fileobj, events)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 452, in _handle_events\n", + " self._handle_recv()\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 481, in _handle_recv\n", + " self._run_callback(callback, msg)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 431, in _run_callback\n", + " callback(*args, **kwargs)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/jupyter_client/threaded.py\", line 121, in _handle_recv\n", + " msg_list = self.ioloop._asyncio_event_loop.run_until_complete(get_msg(future_msg))\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 618, in run_until_complete\n", + " self._check_running()\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 580, in _check_running\n", + " raise RuntimeError(\n", + "RuntimeError: Cannot run the event loop while another loop is running\n", + "ERROR:tornado.general:Uncaught exception in zmqstream callback\n", + "Traceback (most recent call last):\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 452, in _handle_events\n", + " self._handle_recv()\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 481, in _handle_recv\n", + " self._run_callback(callback, msg)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 431, in _run_callback\n", + " callback(*args, **kwargs)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/jupyter_client/threaded.py\", line 121, in _handle_recv\n", + " msg_list = self.ioloop._asyncio_event_loop.run_until_complete(get_msg(future_msg))\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 618, in run_until_complete\n", + " self._check_running()\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 580, in _check_running\n", + " raise RuntimeError(\n", + "RuntimeError: Cannot run the event loop while another loop is running\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Optimal Threshold for image 3: 0.48149103\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "ERROR:tornado.general:Uncaught exception in ZMQStream callback\n", + "Traceback (most recent call last):\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 431, in _run_callback\n", + " callback(*args, **kwargs)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/jupyter_client/threaded.py\", line 121, in _handle_recv\n", + " msg_list = self.ioloop._asyncio_event_loop.run_until_complete(get_msg(future_msg))\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 618, in run_until_complete\n", + " self._check_running()\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 580, in _check_running\n", + " raise RuntimeError(\n", + "RuntimeError: Cannot run the event loop while another loop is running\n", + "Exception in callback BaseAsyncIOLoop._handle_events(200, 1)\n", + "handle: \n", + "Traceback (most recent call last):\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/events.py\", line 80, in _run\n", + " self._context.run(self._callback, *self._args)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/tornado/platform/asyncio.py\", line 189, in _handle_events\n", + " handler_func(fileobj, events)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 452, in _handle_events\n", + " self._handle_recv()\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 481, in _handle_recv\n", + " self._run_callback(callback, msg)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 431, in _run_callback\n", + " callback(*args, **kwargs)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/jupyter_client/threaded.py\", line 121, in _handle_recv\n", + " msg_list = self.ioloop._asyncio_event_loop.run_until_complete(get_msg(future_msg))\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 618, in run_until_complete\n", + " self._check_running()\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 580, in _check_running\n", + " raise RuntimeError(\n", + "RuntimeError: Cannot run the event loop while another loop is running\n", + "ERROR:tornado.general:Uncaught exception in zmqstream callback\n", + "Traceback (most recent call last):\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 452, in _handle_events\n", + " self._handle_recv()\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 481, in _handle_recv\n", + " self._run_callback(callback, msg)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 431, in _run_callback\n", + " callback(*args, **kwargs)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/jupyter_client/threaded.py\", line 121, in _handle_recv\n", + " msg_list = self.ioloop._asyncio_event_loop.run_until_complete(get_msg(future_msg))\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 618, in run_until_complete\n", + " self._check_running()\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 580, in _check_running\n", + " raise RuntimeError(\n", + "RuntimeError: Cannot run the event loop while another loop is running\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Optimal Threshold for image 4: 0.48195323\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "ERROR:tornado.general:Uncaught exception in ZMQStream callback\n", + "Traceback (most recent call last):\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 431, in _run_callback\n", + " callback(*args, **kwargs)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/jupyter_client/threaded.py\", line 121, in _handle_recv\n", + " msg_list = self.ioloop._asyncio_event_loop.run_until_complete(get_msg(future_msg))\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 618, in run_until_complete\n", + " self._check_running()\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 580, in _check_running\n", + " raise RuntimeError(\n", + "RuntimeError: Cannot run the event loop while another loop is running\n", + "ERROR:tornado.general:Uncaught exception in zmqstream callback\n", + "Traceback (most recent call last):\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 452, in _handle_events\n", + " self._handle_recv()\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 481, in _handle_recv\n", + " self._run_callback(callback, msg)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 431, in _run_callback\n", + " callback(*args, **kwargs)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/jupyter_client/threaded.py\", line 121, in _handle_recv\n", + " msg_list = self.ioloop._asyncio_event_loop.run_until_complete(get_msg(future_msg))\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 618, in run_until_complete\n", + " self._check_running()\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 580, in _check_running\n", + " raise RuntimeError(\n", + "RuntimeError: Cannot run the event loop while another loop is running\n", + "Exception in callback BaseAsyncIOLoop._handle_events(239, 1)\n", + "handle: \n", + "Traceback (most recent call last):\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/events.py\", line 80, in _run\n", + " self._context.run(self._callback, *self._args)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/tornado/platform/asyncio.py\", line 189, in _handle_events\n", + " handler_func(fileobj, events)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 452, in _handle_events\n", + " self._handle_recv()\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 481, in _handle_recv\n", + " self._run_callback(callback, msg)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 431, in _run_callback\n", + " callback(*args, **kwargs)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/jupyter_client/threaded.py\", line 121, in _handle_recv\n", + " msg_list = self.ioloop._asyncio_event_loop.run_until_complete(get_msg(future_msg))\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 618, in run_until_complete\n", + " self._check_running()\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 580, in _check_running\n", + " raise RuntimeError(\n", + "RuntimeError: Cannot run the event loop while another loop is running\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Optimal Threshold for image 5: 0.4820033\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "ERROR:tornado.general:Uncaught exception in ZMQStream callback\n", + "Traceback (most recent call last):\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 431, in _run_callback\n", + " callback(*args, **kwargs)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/jupyter_client/threaded.py\", line 121, in _handle_recv\n", + " msg_list = self.ioloop._asyncio_event_loop.run_until_complete(get_msg(future_msg))\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 618, in run_until_complete\n", + " self._check_running()\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 580, in _check_running\n", + " raise RuntimeError(\n", + "RuntimeError: Cannot run the event loop while another loop is running\n", + "ERROR:tornado.general:Uncaught exception in zmqstream callback\n", + "Traceback (most recent call last):\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 452, in _handle_events\n", + " self._handle_recv()\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 481, in _handle_recv\n", + " self._run_callback(callback, msg)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 431, in _run_callback\n", + " callback(*args, **kwargs)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/jupyter_client/threaded.py\", line 121, in _handle_recv\n", + " msg_list = self.ioloop._asyncio_event_loop.run_until_complete(get_msg(future_msg))\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 618, in run_until_complete\n", + " self._check_running()\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 580, in _check_running\n", + " raise RuntimeError(\n", + "RuntimeError: Cannot run the event loop while another loop is running\n", + "Exception in callback BaseAsyncIOLoop._handle_events(278, 1)\n", + "handle: \n", + "Traceback (most recent call last):\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/events.py\", line 80, in _run\n", + " self._context.run(self._callback, *self._args)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/tornado/platform/asyncio.py\", line 189, in _handle_events\n", + " handler_func(fileobj, events)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 452, in _handle_events\n", + " self._handle_recv()\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 481, in _handle_recv\n", + " self._run_callback(callback, msg)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 431, in _run_callback\n", + " callback(*args, **kwargs)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/jupyter_client/threaded.py\", line 121, in _handle_recv\n", + " msg_list = self.ioloop._asyncio_event_loop.run_until_complete(get_msg(future_msg))\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 618, in run_until_complete\n", + " self._check_running()\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 580, in _check_running\n", + " raise RuntimeError(\n", + "RuntimeError: Cannot run the event loop while another loop is running\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Optimal Threshold for image 6: 0.48155692\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "ERROR:tornado.general:Uncaught exception in ZMQStream callback\n", + "Traceback (most recent call last):\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 431, in _run_callback\n", + " callback(*args, **kwargs)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/jupyter_client/threaded.py\", line 121, in _handle_recv\n", + " msg_list = self.ioloop._asyncio_event_loop.run_until_complete(get_msg(future_msg))\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 618, in run_until_complete\n", + " self._check_running()\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 580, in _check_running\n", + " raise RuntimeError(\n", + "RuntimeError: Cannot run the event loop while another loop is running\n", + "ERROR:tornado.general:Uncaught exception in zmqstream callback\n", + "Traceback (most recent call last):\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 452, in _handle_events\n", + " self._handle_recv()\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 481, in _handle_recv\n", + " self._run_callback(callback, msg)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 431, in _run_callback\n", + " callback(*args, **kwargs)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/jupyter_client/threaded.py\", line 121, in _handle_recv\n", + " msg_list = self.ioloop._asyncio_event_loop.run_until_complete(get_msg(future_msg))\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 618, in run_until_complete\n", + " self._check_running()\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 580, in _check_running\n", + " raise RuntimeError(\n", + "RuntimeError: Cannot run the event loop while another loop is running\n", + "Exception in callback BaseAsyncIOLoop._handle_events(317, 1)\n", + "handle: \n", + "Traceback (most recent call last):\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/events.py\", line 80, in _run\n", + " self._context.run(self._callback, *self._args)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/tornado/platform/asyncio.py\", line 189, in _handle_events\n", + " handler_func(fileobj, events)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 452, in _handle_events\n", + " self._handle_recv()\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 481, in _handle_recv\n", + " self._run_callback(callback, msg)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 431, in _run_callback\n", + " callback(*args, **kwargs)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/jupyter_client/threaded.py\", line 121, in _handle_recv\n", + " msg_list = self.ioloop._asyncio_event_loop.run_until_complete(get_msg(future_msg))\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 618, in run_until_complete\n", + " self._check_running()\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 580, in _check_running\n", + " raise RuntimeError(\n", + "RuntimeError: Cannot run the event loop while another loop is running\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Optimal Threshold for image 7: 0.48152474\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "ERROR:tornado.general:Uncaught exception in ZMQStream callback\n", + "Traceback (most recent call last):\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 431, in _run_callback\n", + " callback(*args, **kwargs)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/jupyter_client/threaded.py\", line 121, in _handle_recv\n", + " msg_list = self.ioloop._asyncio_event_loop.run_until_complete(get_msg(future_msg))\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 618, in run_until_complete\n", + " self._check_running()\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 580, in _check_running\n", + " raise RuntimeError(\n", + "RuntimeError: Cannot run the event loop while another loop is running\n", + "ERROR:tornado.general:Uncaught exception in zmqstream callback\n", + "Traceback (most recent call last):\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 452, in _handle_events\n", + " self._handle_recv()\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 481, in _handle_recv\n", + " self._run_callback(callback, msg)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 431, in _run_callback\n", + " callback(*args, **kwargs)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/jupyter_client/threaded.py\", line 121, in _handle_recv\n", + " msg_list = self.ioloop._asyncio_event_loop.run_until_complete(get_msg(future_msg))\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 618, in run_until_complete\n", + " self._check_running()\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_Exception in callback BaseAsyncIOLoop._handle_events(356, 1)\n", + "handle: \n", + "Traceback (most recent call last):\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/events.py\", line 80, in _run\n", + " self._context.run(self._callback, *self._args)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/tornado/platform/asyncio.py\", line 189, in _handle_events\n", + " handler_func(fileobj, events)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 452, in _handle_events\n", + " self._handle_recv()\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 481, in _handle_recv\n", + " self._run_callback(callback, msg)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 431, in _run_callback\n", + " callback(*args, **kwargs)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/jupyter_client/threaded.py\", line 121, in _handle_recv\n", + " msg_list = self.ioloop._asyncio_event_loop.run_until_complete(get_msg(future_msg))\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 618, in run_until_complete\n", + " self._check_running()\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 580, in _check_running\n", + " raise RuntimeError(\n", + "RuntimeError: Cannot run the event loop while another loop is running\n", + "events.py\", line 580, in _check_running\n", + " raise RuntimeError(\n", + "RuntimeError: Cannot run the event loop while another loop is running\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Optimal Threshold for image 8: 0.4880304\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "ERROR:tornado.general:Uncaught exception in ZMQStream callback\n", + "Traceback (most recent call last):\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 431, in _run_callback\n", + " callback(*args, **kwargs)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/jupyter_client/threaded.py\", line 121, in _handle_recv\n", + " msg_list = self.ioloop._asyncio_event_loop.run_until_complete(get_msg(future_msg))\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 618, in run_until_complete\n", + " self._check_running()\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 580, in _check_running\n", + " raise RuntimeError(\n", + "RuntimeError: Cannot run the event loop while another loop is running\n", + "ERROR:tornado.general:Uncaught exception in zmqstream callback\n", + "Traceback (most recent call last):\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 452, in _handle_events\n", + " self._handle_recv()\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 481, in _handle_recv\n", + " self._run_callback(callback, msg)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 431, in _run_callback\n", + " callback(*args, **kwargs)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/jupyter_client/threaded.py\", line 121, in _handle_recv\n", + " msg_list = self.ioloop._asyncio_event_loop.run_until_complete(get_msg(future_msg))\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 618, in run_until_complete\n", + " self._check_running()\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 580, in _check_running\n", + " raise RuntimeError(\n", + "RuntimeError: Cannot run the event loop while another loop is running\n", + "Exception in callback BaseAsyncIOLoop._handle_events(395, 1)\n", + "handle: \n", + "Traceback (most recent call last):\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/events.py\", line 80, in _run\n", + " self._context.run(self._callback, *self._args)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/tornado/platform/asyncio.py\", line 189, in _handle_events\n", + " handler_func(fileobj, events)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 452, in _handle_events\n", + " self._handle_recv()\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 481, in _handle_recv\n", + " self._run_callback(callback, msg)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 431, in _run_callback\n", + " callback(*args, **kwargs)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/jupyter_client/threaded.py\", line 121, in _handle_recv\n", + " msg_list = self.ioloop._asyncio_event_loop.run_until_complete(get_msg(future_msg))\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 618, in run_until_complete\n", + " self._check_running()\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 580, in _check_running\n", + " raise RuntimeError(\n", + "RuntimeError: Cannot run the event loop while another loop is running\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Optimal Threshold for image 9: 0.48267302\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "ERROR:tornado.general:Uncaught exception in ZMQStream callback\n", + "Traceback (most recent call last):\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 431, in _run_callback\n", + " callback(*args, **kwargs)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/jupyter_client/threaded.py\", line 121, in _handle_recv\n", + " msg_list = self.ioloop._asyncio_event_loop.run_until_complete(get_msg(future_msg))\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 618, in run_until_complete\n", + " self._check_running()\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 580, in _check_running\n", + " raise RuntimeError(\n", + "RuntimeError: Cannot run the event loop while another loop is running\n", + "ERROR:tornado.general:Uncaught exception in zmqstream callback\n", + "Traceback (most recent call last):\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 452, in _handle_events\n", + " self._handle_recv()\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 481, in _handle_recv\n", + " self._run_callback(callback, msg)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 431, in _run_callback\n", + " callback(*args, **kwargs)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/jupyter_client/threaded.py\", line 121, in _handle_recv\n", + " msg_list = self.ioloop._asyncio_event_loop.run_until_complete(get_msg(future_msg))\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 618, in run_until_complete\n", + " self._check_running()\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 580, in _check_running\n", + " raise RuntimeError(\n", + "RuntimeError: Cannot run the event loop while another loop is running\n", + "Exception in callback BaseAsyncIOLoop._handle_events(434, 1)\n", + "handle: \n", + "Traceback (most recent call last):\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/events.py\", line 80, in _run\n", + " self._context.run(self._callback, *self._args)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/tornado/platform/asyncio.py\", line 189, in _handle_events\n", + " handler_func(fileobj, events)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 452, in _handle_events\n", + " self._handle_recv()\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 481, in _handle_recv\n", + " self._run_callback(callback, msg)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 431, in _run_callback\n", + " callback(*args, **kwargs)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/jupyter_client/threaded.py\", line 121, in _handle_recv\n", + " msg_list = self.ioloop._asyncio_event_loop.run_until_complete(get_msg(future_msg))\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 618, in run_until_complete\n", + " self._check_running()\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 580, in _check_running\n", + " raise RuntimeError(\n", + "RuntimeError: Cannot run the event loop while another loop is running\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Optimal Threshold for image 10: 0.4855357\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "ERROR:tornado.general:Uncaught exception in ZMQStream callback\n", + "Traceback (most recent call last):\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 431, in _run_callback\n", + " callback(*args, **kwargs)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/jupyter_client/threaded.py\", line 121, in _handle_recv\n", + " msg_list = self.ioloop._asyncio_event_loop.run_until_complete(get_msg(future_msg))\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 618, in run_until_complete\n", + " self._check_running()\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 580, in _check_running\n", + " raise RuntimeError(\n", + "RuntimeError: Cannot run the event loop while another loop is running\n", + "ERROR:tornado.general:Uncaught exception in zmqstream callback\n", + "Traceback (most recent call last):\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 452, in _handle_events\n", + " self._handle_recv()\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 481, in _handle_recv\n", + " self._run_callback(callback, msg)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 431, in _run_callback\n", + " callback(*args, **kwargs)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/jupyter_client/threaded.py\", line 121, in _handle_recv\n", + " msg_list = self.ioloop._asyncio_event_loop.run_until_complete(get_msg(future_msg))\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 618, in run_until_complete\n", + " self._check_running()\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 580, in _check_running\n", + " raise RuntimeError(\n", + "RuntimeError: Cannot run the event loop while another loop is running\n", + "Exception in callback BaseAsyncIOLoop._handle_events(472, 1)\n", + "handle: \n", + "Traceback (most recent call last):\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/events.py\", line 80, in _run\n", + " self._context.run(self._callback, *self._args)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/tornado/platform/asyncio.py\", line 189, in _handle_events\n", + " handler_func(fileobj, events)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 452, in _handle_events\n", + " self._handle_recv()\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 481, in _handle_recv\n", + " self._run_callback(callback, msg)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 431, in _run_callback\n", + " callback(*args, **kwargs)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/jupyter_client/threaded.py\", line 121, in _handle_recv\n", + " msg_list = self.ioloop._asyncio_event_loop.run_until_complete(get_msg(future_msg))\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 618, in run_until_complete\n", + " self._check_running()\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 580, in _check_running\n", + " raise RuntimeError(\n", + "RuntimeError: Cannot run the event loop while another loop is running\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Optimal Threshold for image 11: 0.48116392\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "ERROR:tornado.general:Uncaught exception in ZMQStream callback\n", + "Traceback (most recent call last):\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 431, in _run_callback\n", + " callback(*args, **kwargs)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/jupyter_client/threaded.py\", line 121, in _handle_recv\n", + " msg_list = self.ioloop._asyncio_event_loop.run_until_complete(get_msg(future_msg))\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 618, in run_until_complete\n", + " self._check_running()\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 580, in _check_running\n", + " raise RuntimeError(\n", + "RuntimeError: Cannot run the event loop while another loop is running\n", + "Exception in callback BaseAsyncIOLoop._handle_events(512, 1)\n", + "handle: \n", + "Traceback (most recent call last):\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/events.py\", line 80, in _run\n", + " self._context.run(self._callback, *self._args)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/tornado/platform/asyncio.py\", line 189, in _handle_events\n", + " handler_func(fileobj, events)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 452, in _handle_events\n", + " self._handle_recv()\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 481, in _handle_recv\n", + " self._run_callback(callback, msg)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 431, in _run_callback\n", + " callback(*args, **kwargs)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/jupyter_client/threaded.py\", line 121, in _handle_recv\n", + " msg_list = self.ioloop._asyncio_event_loop.run_until_complete(get_msg(future_msg))\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 618, in run_until_complete\n", + " self._check_running()\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 580, in _check_running\n", + " raise RuntimeError(\n", + "RuntimeError: Cannot run the event loop while another loop is running\n", + "ERROR:tornado.general:Uncaught exception in zmqstream callback\n", + "Traceback (most recent call last):\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 452, in _handle_events\n", + " self._handle_recv()\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 481, in _handle_recv\n", + " self._run_callback(callback, msg)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 431, in _run_callback\n", + " callback(*args, **kwargs)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/jupyter_client/threaded.py\", line 121, in _handle_recv\n", + " msg_list = self.ioloop._asyncio_event_loop.run_until_complete(get_msg(future_msg))\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 618, in run_until_complete\n", + " self._check_running()\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 580, in _check_running\n", + " raise RuntimeError(\n", + "RuntimeError: Cannot run the event loop while another loop is running\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Optimal Threshold for image 12: 0.48119318\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "ERROR:tornado.general:Uncaught exception in ZMQStream callback\n", + "Traceback (most recent call last):\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 431, in _run_callback\n", + " callback(*args, **kwargs)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/jupyter_client/threaded.py\", line 121, in _handle_recv\n", + " msg_list = self.ioloop._asyncio_event_loop.run_until_complete(get_msg(future_msg))\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 618, in run_until_complete\n", + " self._check_running()\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 580, in _check_running\n", + " raise RuntimeError(\n", + "RuntimeError: Cannot run the event loop while another loop is running\n", + "Exception in callback BaseAsyncIOLoop._handle_events(551, 1)\n", + "handle: \n", + "Traceback (most recent call last):\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/events.py\", line 80, in _run\n", + " self._context.run(self._callback, *self._args)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/tornado/platform/asyncio.py\", line 189, in _handle_events\n", + " handler_func(fileobj, events)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 452, in _handle_events\n", + " self._handle_recv()\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 481, in _handle_recv\n", + " self._run_callback(callback, msg)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 431, in _run_callback\n", + " callback(*args, **kwargs)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/jupyter_client/threaded.py\", line 121, in _handle_recv\n", + " msg_list = self.ioloop._asyncio_event_loop.run_until_complete(get_msg(future_msg))\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 618, in run_until_complete\n", + " self._check_running()\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 580, in _check_running\n", + " raise RuntimeError(\n", + "RuntimeError: Cannot run the event loop while another loop is running\n", + "ERROR:tornado.general:Uncaught exception in zmqstream callback\n", + "Traceback (most recent call last):\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 452, in _handle_events\n", + " self._handle_recv()\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 481, in _handle_recv\n", + " self._run_callback(callback, msg)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 431, in _run_callback\n", + " callback(*args, **kwargs)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/jupyter_client/threaded.py\", line 121, in _handle_recv\n", + " msg_list = self.ioloop._asyncio_event_loop.run_until_complete(get_msg(future_msg))\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 618, in run_until_complete\n", + " self._check_running()\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 580, in _check_running\n", + " raise RuntimeError(\n", + "RuntimeError: Cannot run the event loop while another loop is running\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Optimal Threshold for image 13: 0.48149678\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "ERROR:tornado.general:Uncaught exception in ZMQStream callback\n", + "Traceback (most recent call last):\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 431, in _run_callback\n", + " callback(*args, **kwargs)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/jupyter_client/threaded.py\", line 121, in _handle_recv\n", + " msg_list = self.ioloop._asyncio_event_loop.run_until_complete(get_msg(future_msg))\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 618, in run_until_complete\n", + " self._check_running()\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 580, in _check_running\n", + " raise RuntimeError(\n", + "RuntimeError: Cannot run the event loop while another loop is running\n", + "ERROR:tornado.general:Uncaught exception in zmqstream callback\n", + "Traceback (most recent call last):\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 452, in _handle_events\n", + " self._handle_recv()\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 481, in _handle_recv\n", + " self._run_callback(callback, msg)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 431, in _run_callback\n", + " callback(*args, **kwargs)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/jupyter_client/threaded.py\", line 121, in _handle_recv\n", + " msg_list = self.ioloop._asyncio_event_loop.run_until_complete(get_msg(future_msg))\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 618, in run_until_complete\n", + " self._check_running()\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 580, in _check_running\n", + " raise RuntimeError(\n", + "RuntimeError: Cannot run the event loop while another loop is running\n", + "Exception in callback BaseAsyncIOLoop._handle_events(590, 1)\n", + "handle: \n", + "Traceback (most recent call last):\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/events.py\", line 80, in _run\n", + " self._context.run(self._callback, *self._args)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/tornado/platform/asyncio.py\", line 189, in _handle_events\n", + " handler_func(fileobj, events)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 452, in _handle_events\n", + " self._handle_recv()\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 481, in _handle_recv\n", + " self._run_callback(callback, msg)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 431, in _run_callback\n", + " callback(*args, **kwargs)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/jupyter_client/threaded.py\", line 121, in _handle_recv\n", + " msg_list = self.ioloop._asyncio_event_loop.run_until_complete(get_msg(future_msg))\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 618, in run_until_complete\n", + " self._check_running()\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 580, in _check_running\n", + " raise RuntimeError(\n", + "RuntimeError: Cannot run the event loop while another loop is running\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Optimal Threshold for image 14: 0.48900756\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "ERROR:tornado.general:Uncaught exception in ZMQStream callback\n", + "Traceback (most recent call last):\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 431, in _run_callback\n", + " callback(*args, **kwargs)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/jupyter_client/threaded.py\", line 121, in _handle_recv\n", + " msg_list = self.ioloop._asyncio_event_loop.run_until_complete(get_msg(future_msg))\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 618, in run_until_complete\n", + " self._check_running()\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 580, in _check_running\n", + " raise RuntimeError(\n", + "RuntimeError: Cannot run the event loop while another loop is running\n", + "ERROR:tornado.general:Uncaught exception in zmqstream callback\n", + "Traceback (most recent call last):\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 452, in _handle_events\n", + " self._handle_recv()\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 481, in _handle_recv\n", + " self._run_callback(callback, msg)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 431, in _run_callback\n", + " callback(*args, **kwargs)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/jupyter_client/threaded.py\", line 121, in _handle_recv\n", + " msg_list = self.ioloop._asyncio_event_loop.run_until_complete(get_msg(future_msg))\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 618, in run_until_complete\n", + " self._check_running()\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 580, in _check_running\n", + " raise RuntimeError(\n", + "RuntimeError: Cannot run the event loop while another loop is running\n", + "Exception in callback BaseAsyncIOLoop._handle_events(629, 1)\n", + "handle: \n", + "Traceback (most recent call last):\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/events.py\", line 80, in _run\n", + " self._context.run(self._callback, *self._args)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/tornado/platform/asyncio.py\", line 189, in _handle_events\n", + " handler_func(fileobj, events)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 452, in _handle_events\n", + " self._handle_recv()\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 481, in _handle_recv\n", + " self._run_callback(callback, msg)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 431, in _run_callback\n", + " callback(*args, **kwargs)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/jupyter_client/threaded.py\", line 121, in _handle_recv\n", + " msg_list = self.ioloop._asyncio_event_loop.run_until_complete(get_msg(future_msg))\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 618, in run_until_complete\n", + " self._check_running()\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 580, in _check_running\n", + " raise RuntimeError(\n", + "RuntimeError: Cannot run the event loop while another loop is running\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Optimal Threshold for image 15: 0.4819097\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "ERROR:tornado.general:Uncaught exception in ZMQStream callback\n", + "Traceback (most recent call last):\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 431, in _run_callback\n", + " callback(*args, **kwargs)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/jupyter_client/threaded.py\", line 121, in _handle_recv\n", + " msg_list = self.ioloop._asyncio_event_loop.run_until_complete(get_msg(future_msg))\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 618, in run_until_complete\n", + " self._check_running()\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 580, in _check_running\n", + " raise RuntimeError(\n", + "RuntimeError: Cannot run the event loop while another loop is running\n", + "Exception in callback BaseAsyncIOLoop._handle_events(668, 1)\n", + "handle: \n", + "Traceback (most recent call last):\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/events.py\", line 80, in _run\n", + " self._context.run(self._callback, *self._args)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/tornado/platform/asyncio.py\", line 189, in _handle_events\n", + " handler_func(fileobj, events)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 452, in _handle_events\n", + " self._handle_recv()\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 481, in _handle_recv\n", + " self._run_callback(callback, msg)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 431, in _run_callback\n", + " callback(*args, **kwargs)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/jupyter_client/threaded.py\", line 121, in _handle_recv\n", + " msg_list = self.ioloop._asyncio_event_loop.run_until_complete(get_msg(future_msg))\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 618, in run_until_complete\n", + " self._check_running()\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 580, in _check_running\n", + " raise RuntimeError(\n", + "RuntimeError: Cannot run the event loop while another loop is running\n", + "ERROR:tornado.general:Uncaught exception in zmqstream callback\n", + "Traceback (most recent call last):\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 452, in _handle_events\n", + " self._handle_recv()\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 481, in _handle_recv\n", + " self._run_callback(callback, msg)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 431, in _run_callback\n", + " callback(*args, **kwargs)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/jupyter_client/threaded.py\", line 121, in _handle_recv\n", + " msg_list = self.ioloop._asyncio_event_loop.run_until_complete(get_msg(future_msg))\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 618, in run_until_complete\n", + " self._check_running()\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 580, in _check_running\n", + " raise RuntimeError(\n", + "RuntimeError: Cannot run the event loop while another loop is running\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Optimal Threshold for image 16: 0.48162946\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "ERROR:tornado.general:Uncaught exception in ZMQStream callback\n", + "Traceback (most recent call last):\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 431, in _run_callback\n", + " callback(*args, **kwargs)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/jupyter_client/threaded.py\", line 121, in _handle_recv\n", + " msg_list = self.ioloop._asyncio_event_loop.run_until_complete(get_msg(future_msg))\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 618, in run_until_complete\n", + " self._check_running()\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 580, in _check_running\n", + " raise RuntimeError(\n", + "RuntimeError: Cannot run the event loop while another loop is running\n", + "ERROR:tornado.general:Uncaught exception in zmqstream callback\n", + "Traceback (most recent call last):\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 452, in _handle_events\n", + " self._handle_recv()\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 481, in _handle_recv\n", + " self._run_callback(callback, msg)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 431, in _run_callback\n", + " callback(*args, **kwargs)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/jupyter_client/threaded.py\", line 121, in _handle_recv\n", + " msg_list = self.ioloop._asyncio_event_loop.run_until_complete(get_msg(future_msg))\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 618, in run_until_complete\n", + " self._check_running()\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 580, in _check_running\n", + " raise RuntimeError(\n", + "RuntimeError: Cannot run the event loop while another loop is running\n", + "Exception in callback BaseAsyncIOLoop._handle_events(707, 1)\n", + "handle: \n", + "Traceback (most recent call last):\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/events.py\", line 80, in _run\n", + " self._context.run(self._callback, *self._args)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/tornado/platform/asyncio.py\", line 189, in _handle_events\n", + " handler_func(fileobj, events)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 452, in _handle_events\n", + " self._handle_recv()\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 481, in _handle_recv\n", + " self._run_callback(callback, msg)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 431, in _run_callback\n", + " callback(*args, **kwargs)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/jupyter_client/threaded.py\", line 121, in _handle_recv\n", + " msg_list = self.ioloop._asyncio_event_loop.run_until_complete(get_msg(future_msg))\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 618, in run_until_complete\n", + " self._check_running()\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 580, in _check_running\n", + " raise RuntimeError(\n", + "RuntimeError: Cannot run the event loop while another loop is running\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Optimal Threshold for image 17: 0.48406285\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "ERROR:tornado.general:Uncaught exception in ZMQStream callback\n", + "Traceback (most recent call last):\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 431, in _run_callback\n", + " callback(*args, **kwargs)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/jupyter_client/threaded.py\", line 121, in _handle_recv\n", + " msg_list = self.ioloop._asyncio_event_loop.run_until_complete(get_msg(future_msg))\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 618, in run_until_complete\n", + " self._check_running()\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 580, in _check_running\n", + " raise RuntimeError(\n", + "RuntimeError: Cannot run the event loop while another loop is running\n", + "ERROR:tornado.general:Uncaught exception in zmqstream callback\n", + "Traceback (most recent call last):\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 452, in _handle_events\n", + " self._handle_recv()\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 481, in _handle_recv\n", + " self._run_callback(callback, msg)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 431, in _run_callback\n", + " callback(*args, **kwargs)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/jupyter_client/threaded.py\", line 121, in _handle_recv\n", + " msg_list = self.ioloop._asyncio_event_loop.run_until_complete(get_msg(future_msg))\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 618, in run_until_complete\n", + " self._check_running()\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_Exception in callback BaseAsyncIOLoop._handle_events(746, 1)\n", + "handle: \n", + "Traceback (most recent call last):\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/events.py\", line 80, in _run\n", + " self._context.run(self._callback, *self._args)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/tornado/platform/asyncio.py\", line 189, in _handle_events\n", + " handler_func(fileobj, events)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 452, in _handle_events\n", + " self._handle_recv()\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 481, in _handle_recv\n", + " self._run_callback(callback, msg)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 431, in _run_callback\n", + " callback(*args, **kwargs)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/jupyter_client/threaded.py\", line 121, in _handle_recv\n", + " msg_list = self.ioloop._asyncio_event_loop.run_until_complete(get_msg(future_msg))\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 618, in run_until_complete\n", + " self._check_running()\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 580, in _check_running\n", + " raise RuntimeError(\n", + "RuntimeError: Cannot run the event loop while another loop is running\n", + "events.py\", line 580, in _check_running\n", + " raise RuntimeError(\n", + "RuntimeError: Cannot run the event loop while another loop is running\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Optimal Threshold for image 18: 0.48327488\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "ERROR:tornado.general:Uncaught exception in ZMQStream callback\n", + "Traceback (most recent call last):\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 431, in _run_callback\n", + " callback(*args, **kwargs)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/jupyter_client/threaded.py\", line 121, in _handle_recv\n", + " msg_list = self.ioloop._asyncio_event_loop.run_until_complete(get_msg(future_msg))\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 618, in run_until_complete\n", + " self._check_running()\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 580, in _check_running\n", + " raise RuntimeError(\n", + "RuntimeError: Cannot run the event loop while another loop is running\n", + "ERROR:tornado.general:Uncaught exception in zmqstream callback\n", + "Traceback (most recent call last):\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 452, in _handle_events\n", + " self._handle_recv()\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 481, in _handle_recv\n", + " self._run_callback(callback, msg)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 431, in _run_callback\n", + " callback(*args, **kwargs)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/jupyter_client/threaded.py\", line 121, in _handle_recv\n", + " msg_list = self.ioloop._asyncio_event_loop.run_until_complete(get_msg(future_msg))\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 618, in run_until_complete\n", + " self._check_running()\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 580, in _check_running\n", + " raise RuntimeError(\n", + "RuntimeError: Cannot run the event loop while another loop is running\n", + "Exception in callback BaseAsyncIOLoop._handle_events(785, 1)\n", + "handle: \n", + "Traceback (most recent call last):\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/events.py\", line 80, in _run\n", + " self._context.run(self._callback, *self._args)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/tornado/platform/asyncio.py\", line 189, in _handle_events\n", + " handler_func(fileobj, events)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 452, in _handle_events\n", + " self._handle_recv()\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 481, in _handle_recv\n", + " self._run_callback(callback, msg)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 431, in _run_callback\n", + " callback(*args, **kwargs)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/jupyter_client/threaded.py\", line 121, in _handle_recv\n", + " msg_list = self.ioloop._asyncio_event_loop.run_until_complete(get_msg(future_msg))\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 618, in run_until_complete\n", + " self._check_running()\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 580, in _check_running\n", + " raise RuntimeError(\n", + "RuntimeError: Cannot run the event loop while another loop is running\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Optimal Threshold for image 19: 0.4841251\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "ERROR:tornado.general:Uncaught exception in ZMQStream callback\n", + "Traceback (most recent call last):\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 431, in _run_callback\n", + " callback(*args, **kwargs)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/jupyter_client/threaded.py\", line 121, in _handle_recv\n", + " msg_list = self.ioloop._asyncio_event_loop.run_until_complete(get_msg(future_msg))\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 618, in run_until_complete\n", + " self._check_running()\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 580, in _check_running\n", + " raise RuntimeError(\n", + "RuntimeError: Cannot run the event loop while another loop is running\n", + "ERROR:tornado.general:Uncaught exception in zmqstream callback\n", + "Traceback (most recent call last):\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 452, in _handle_events\n", + " self._handle_recv()\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 481, in _handle_recv\n", + " self._run_callback(callback, msg)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 431, in _run_callback\n", + " callback(*args, **kwargs)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/jupyter_client/threaded.py\", line 121, in _handle_recv\n", + " msg_list = self.ioloop._asyncio_event_loop.run_until_complete(get_msg(future_msg))\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 618, in run_until_complete\n", + " self._check_running()\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 580, in _check_running\n", + " raise RuntimeError(\n", + "RuntimeError: Cannot run the event loop while another loop is running\n", + "Exception in callback BaseAsyncIOLoop._handle_events(822, 1)\n", + "handle: \n", + "Traceback (most recent call last):\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/events.py\", line 80, in _run\n", + " self._context.run(self._callback, *self._args)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/tornado/platform/asyncio.py\", line 189, in _handle_events\n", + " handler_func(fileobj, events)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 452, in _handle_events\n", + " self._handle_recv()\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 481, in _handle_recv\n", + " self._run_callback(callback, msg)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 431, in _run_callback\n", + " callback(*args, **kwargs)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/jupyter_client/threaded.py\", line 121, in _handle_recv\n", + " msg_list = self.ioloop._asyncio_event_loop.run_until_complete(get_msg(future_msg))\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 618, in run_until_complete\n", + " self._check_running()\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 580, in _check_running\n", + " raise RuntimeError(\n", + "RuntimeError: Cannot run the event loop while another loop is running\n", + "Context leak detected, msgtracer returned -1\n", + "ERROR:tornado.general:Uncaught exception in ZMQStream callback\n", + "Traceback (most recent call last):\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 431, in _run_callback\n", + " callback(*args, **kwargs)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/jupyter_client/threaded.py\", line 121, in _handle_recv\n", + " msg_list = self.ioloop._asyncio_event_loop.run_until_complete(get_msg(future_msg))\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 618, in run_until_complete\n", + " self._check_running()\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 580, in _check_running\n", + " raise RuntimeError(\n", + "RuntimeError: Cannot run the event loop while another loop is running\n", + "ERROR:tornado.general:Uncaught exception in zmqstream callback\n", + "Traceback (most recent call last):\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 452, in _handle_events\n", + " self._handle_recv()\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 481, in _handle_recv\n", + " self._run_callback(callback, msg)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 431, in _run_callback\n", + " callback(*args, **kwargs)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/jupyter_client/threaded.py\", line 121, in _handle_recv\n", + " msg_list = self.ioloop._asyncio_event_loop.run_until_complete(get_msg(future_msg))\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 618, in run_until_complete\n", + " self._check_running()\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 580, in _check_running\n", + " raise RuntimeError(\n", + "RuntimeError: Cannot run the event loop while another loop is running\n", + "Exception in callback BaseAsyncIOLoop._handle_events(862, 1)\n", + "handle: \n", + "Traceback (most recent call last):\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/events.py\", line 80, in _run\n", + " self._context.run(self._callback, *self._args)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/tornado/platform/asyncio.py\", line 189, in _handle_events\n", + " handler_func(fileobj, events)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 452, in _handle_events\n", + " self._handle_recv()\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 481, in _handle_recv\n", + " self._run_callback(callback, msg)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 431, in _run_callback\n", + " callback(*args, **kwargs)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/jupyter_client/threaded.py\", line 121, in _handle_recv\n", + " msg_list = self.ioloop._asyncio_event_loop.run_until_complete(get_msg(future_msg))\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 618, in run_until_complete\n", + " self._check_running()\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 580, in _check_running\n", + " raise RuntimeError(\n", + "RuntimeError: Cannot run the event loop while another loop is running\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Optimal Threshold for image 20: 0.48557067\n", + "Optimal Threshold for image 21: 0.48140803\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "ERROR:tornado.general:Uncaught exception in ZMQStream callback\n", + "Traceback (most recent call last):\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 431, in _run_callback\n", + " callback(*args, **kwargs)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/jupyter_client/threaded.py\", line 121, in _handle_recv\n", + " msg_list = self.ioloop._asyncio_event_loop.run_until_complete(get_msg(future_msg))\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 618, in run_until_complete\n", + " self._check_running()\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 580, in _check_running\n", + " raise RuntimeError(\n", + "RuntimeError: Cannot run the event loop while another loop is running\n", + "ERROR:tornado.general:Uncaught exception in zmqstream callback\n", + "Traceback (most recent call last):\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 452, in _handle_events\n", + " self._handle_recv()\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 481, in _handle_recv\n", + " self._run_callback(callback, msg)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 431, in _run_callback\n", + " callback(*args, **kwargs)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/jupyter_client/threaded.py\", line 121, in _handle_recv\n", + " msg_list = self.ioloop._asyncio_event_loop.run_until_complete(get_msg(future_msg))\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 618, in run_until_complete\n", + " self._check_running()\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 580, in _check_running\n", + " raise RuntimeError(\n", + "RuntimeError: Cannot run the event loop while another loop is running\n", + "Exception in callback BaseAsyncIOLoop._handle_events(902, 1)\n", + "handle: \n", + "Traceback (most recent call last):\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/events.py\", line 80, in _run\n", + " self._context.run(self._callback, *self._args)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/tornado/platform/asyncio.py\", line 189, in _handle_events\n", + " handler_func(fileobj, events)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 452, in _handle_events\n", + " self._handle_recv()\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 481, in _handle_recv\n", + " self._run_callback(callback, msg)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 431, in _run_callback\n", + " callback(*args, **kwargs)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/jupyter_client/threaded.py\", line 121, in _handle_recv\n", + " msg_list = self.ioloop._asyncio_event_loop.run_until_complete(get_msg(future_msg))\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 618, in run_until_complete\n", + " self._check_running()\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 580, in _check_running\n", + " raise RuntimeError(\n", + "RuntimeError: Cannot run the event loop while another loop is running\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Optimal Threshold for image 22: 0.48226443\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "ERROR:tornado.general:Uncaught exception in ZMQStream callback\n", + "Traceback (most recent call last):\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 431, in _run_callback\n", + " callback(*args, **kwargs)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/jupyter_client/threaded.py\", line 121, in _handle_recv\n", + " msg_list = self.ioloop._asyncio_event_loop.run_until_complete(get_msg(future_msg))\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 618, in run_until_complete\n", + " self._check_running()\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 580, in _check_running\n", + " raise RuntimeError(\n", + "RuntimeError: Cannot run the event loop while another loop is running\n", + "ERROR:tornado.general:Uncaught exception in zmqstream callback\n", + "Traceback (most recent call last):\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 452, in _handle_events\n", + " self._handle_recv()\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 481, in _handle_recv\n", + " self._run_callback(callback, msg)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 431, in _run_callback\n", + " callback(*args, **kwargs)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/jupyter_client/threaded.py\", line 121, in _handle_recv\n", + " msg_list = self.ioloop._asyncio_event_loop.run_until_complete(get_msg(future_msg))\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 618, in run_until_complete\n", + " self._check_running()\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 580, in _check_running\n", + " raise RuntimeError(\n", + "RuntimeError: Cannot run the event loop while another loop is running\n", + "Exception in callback BaseAsyncIOLoop._handle_events(940, 1)\n", + "handle: \n", + "Traceback (most recent call last):\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/events.py\", line 80, in _run\n", + " self._context.run(self._callback, *self._args)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/tornado/platform/asyncio.py\", line 189, in _handle_events\n", + " handler_func(fileobj, events)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 452, in _handle_events\n", + " self._handle_recv()\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 481, in _handle_recv\n", + " self._run_callback(callback, msg)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 431, in _run_callback\n", + " callback(*args, **kwargs)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/jupyter_client/threaded.py\", line 121, in _handle_recv\n", + " msg_list = self.ioloop._asyncio_event_loop.run_until_complete(get_msg(future_msg))\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 618, in run_until_complete\n", + " self._check_running()\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 580, in _check_running\n", + " raise RuntimeError(\n", + "RuntimeError: Cannot run the event loop while another loop is running\n", + "ERROR:tornado.general:Uncaught exception in ZMQStream callback\n", + "Traceback (most recent call last):\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 431, in _run_callback\n", + " callback(*args, **kwargs)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/jupyter_client/threaded.py\", line 121, in _handle_recv\n", + " msg_list = self.ioloop._asyncio_event_loop.run_until_complete(get_msg(future_msg))\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 618, in run_until_complete\n", + " self._check_running()\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 580, in _check_running\n", + " raise RuntimeError(\n", + "RuntimeError: Cannot run the event loop while another loop is running\n", + "Exception in callback BaseAsyncIOLoop._handle_events(980, 1)\n", + "handle: \n", + "Traceback (most recent call last):\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/events.py\", line 80, in _run\n", + " self._context.run(self._callback, *self._args)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/tornado/platform/asyncio.py\", line 189, in _handle_events\n", + " handler_func(fileobj, events)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 452, in _handle_events\n", + " self._handle_recv()\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 481, in _handle_recv\n", + " self._run_callback(callback, msg)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 431, in _run_callback\n", + " callback(*args, **kwargs)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/jupyter_client/threaded.py\", line 121, in _handle_recv\n", + " msg_list = self.ioloop._asyncio_event_loop.run_until_complete(get_msg(future_msg))\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 618, in run_until_complete\n", + " self._check_running()\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 580, in _check_running\n", + " raise RuntimeError(\n", + "RuntimeError: Cannot run the event loop while another loop is running\n", + "ERROR:tornado.general:Uncaught exception in zmqstream callback\n", + "Traceback (most recent call last):\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 452, in _handle_events\n", + " self._handle_recv()\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 481, in _handle_recv\n", + " self._run_callback(callback, msg)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 431, in _run_callback\n", + " callback(*args, **kwargs)\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/jupyter_client/threaded.py\", line 121, in _handle_recv\n", + " msg_list = self.ioloop._asyncio_event_loop.run_until_complete(get_msg(future_msg))\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 618, in run_until_complete\n", + " self._check_running()\n", + " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_" + ] + } + ], + "source": [ + "# Plot all images/predictions from last epoch\n", + "\n", + "from sklearn.metrics import roc_curve, precision_recall_curve, auc\n", + "\n", + "for i in range(len(y_list[len(y_list) - 1])):\n", + " x = x_list[i].clone()[:,0].numpy()\n", + " pred = pred_list[len(pred_list) - 1][i].clone()[:,0].numpy()\n", + " y = y_list[len(y_list) - 1][i].clone()[:,0].numpy()\n", + " \n", + " fpr, tpr, thresholds = roc_curve(y.flatten(), pred.flatten())\n", + " optimal_thresh = thresholds[np.argmax(tpr - fpr)]\n", + " print(\"Optimal Threshold for image \" + str(i) + \": \", optimal_thresh)\n", + " \n", + " pred_thresh = pred\n", + " \n", + " for i in range(1):\n", + " for a in range(330):\n", + " for b in range(330):\n", + " for c in range(100):\n", + " if pred[i][a][b][c] > optimal_thresh:\n", + " pred_thresh[i][a][b][c] = 1\n", + " else:\n", + " pred_thresh[i][a][b][c] = 0\n", + "\n", + "\n", + " import napari\n", + " with napari.gui_qt():\n", + " viewer = napari.Viewer(ndisplay=3)\n", + " viewer.add_image(x[0])\n", + " viewer.add_labels(y[0].astype(int))\n", + " viewer.add_labels(pred_thresh[0].astype(int), num_colors = 2)\n", + " \n", + " " + ] + }, + { + "cell_type": "code", + "execution_count": 69, + "id": "e2a9e603", + "metadata": {}, + "outputs": [], + "source": [ + "#metrics for one image\n", + "\n", + "#pred_0 = pred.clone().numpy()[:, 0].round().astype(int).flatten()\n", + "#target_0 = y_torch_test[:, 0].astype(int).flatten()\n", + "\n", + "#print(\"Accuracy: \", accuracy_score(target_0, pred_0) * 100)\n", + "#print(\"Precision: \", precision_score(target_0, pred_0) * 100)\n", + "#print(\"Recall: \", recall_score(target_0, pred_0) * 100)\n", + "#print(\"Nonzeros: \", np.count_nonzero(pred_0) * 100)\n", + "#print(\"Nonzeros percent: \", np.count_nonzero(pred_0) / len(target_0) * 100)" + ] + }, + { + "cell_type": "code", + "execution_count": 46, + "id": "50fa7478", + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Optimal Threshold: 0.53039104\n" + ] + }, + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 46, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "#PR and ROC Curves\n", + "\n", + "from sklearn.metrics import roc_curve, precision_recall_curve, auc\n", + "import matplotlib.pyplot as plt\n", + "\n", + "\n", + "last_pred = pred_list[len(pred_list)-1][len(pred_list[0])-1].clone()\n", + "#last_pred = pred_list[len(pred_list)-2].clone()\n", + "y_torch_test_0 = y_torch_test[:, 0]\n", + "\n", + "fpr, tpr, thresholds = roc_curve(y_torch_test_0.flatten(), last_pred.flatten())\n", + "roc_auc = auc(fpr, tpr)\n", + "\n", + "precision, recall, thresholds = precision_recall_curve(y_torch_test_0.flatten(), last_pred.flatten())\n", + "\n", + "#printing optimal ROC threshold\n", + "optimal_thresh = thresholds[np.argmax(tpr - fpr)]\n", + "print(\"Optimal Threshold: \", optimal_thresh)\n", + "\n", + "#plotting\n", + "plt.figure()\n", + "plt.title(\"ROC\")\n", + "plt.xlabel(\"fpr\")\n", + "plt.ylabel(\"tpr\")\n", + "plt.plot(fpr, tpr, label = 'AUC = %0.2f' % roc_auc)\n", + "plt.legend(loc = 'lower right')\n", + "\n", + "plt.figure()\n", + "plt.title(\"PR\")\n", + "plt.xlabel(\"recall\")\n", + "plt.ylabel(\"precision\")\n", + "plt.plot(recall, precision, label = \"AP = %0.2f\" % np.mean(precision))\n", + "plt.legend(loc = 'lower right')\n" + ] + }, + { + "cell_type": "code", + "execution_count": 47, + "id": "1d7d1464", + "metadata": {}, + "outputs": [], + "source": [ + "#thresholding for test image 0\n", + "\n", + "#pred2 = pred_list[len(pred_list)-2].clone().detach()\n", + "\n", + "#pred2 = pred.clone().detach()\n", + "#pred2_0 = pred2[:,0]\n", + "\n", + "pred2_0 = last_pred[:,0]\n", + "\n", + "predN0 = pred2_0.numpy()\n", + "#for i in range(predN.shape[0]):\n", + "for i in range(1):\n", + " for a in range(330):\n", + " for b in range(330):\n", + " for c in range(100):\n", + " if predN0[i][a][b][c] > optimal_thresh:\n", + " predN0[i][a][b][c] = 1\n", + " else:\n", + " predN0[i][a][b][c] = 0\n" + ] + }, + { + "cell_type": "code", + "execution_count": 49, + "id": "16bfc7cb", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/napari/_qt/qt_event_loop.py:256: FutureWarning: \n", + "The 'gui_qt()' context manager is deprecated.\n", + "If you are running napari from a script, please use 'napari.run()' as follows:\n", + "\n", + " import napari\n", + "\n", + " viewer = napari.Viewer() # no prior setup needed\n", + " # other code using the viewer...\n", + " napari.run()\n", + "\n", + "In IPython or Jupyter, 'napari.run()' is not necessary. napari will automatically\n", + "start an interactive event loop for you: \n", + "\n", + " import napari\n", + " viewer = napari.Viewer() # that's it!\n", + "\n", + " warn(\n" + ] + } + ], + "source": [ + "import napari\n", + "with napari.gui_qt():\n", + " viewer = napari.Viewer(ndisplay=3)\n", + " viewer.add_image((x_torch_test[0][22]))\n", + " viewer.add_labels((y_torch_test[0][22]).astype(int))\n", + " viewer.add_labels(predN0[0].astype(int), num_colors = 2)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b6852cea", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.7" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} From 368bec77757d4a03b4a789993eaea9eaf2b20774 Mon Sep 17 00:00:00 2001 From: shreyasingh1 Date: Tue, 1 Mar 2022 18:41:09 -0500 Subject: [PATCH 03/29] cleaned pytorch notebook output --- .../pytorch_model/pytorch - cleaned.ipynb | 109 ++++++------------ 1 file changed, 33 insertions(+), 76 deletions(-) diff --git a/experiments/pytorch_model/pytorch - cleaned.ipynb b/experiments/pytorch_model/pytorch - cleaned.ipynb index 8ae0bbe4a..f7c9a9789 100644 --- a/experiments/pytorch_model/pytorch - cleaned.ipynb +++ b/experiments/pytorch_model/pytorch - cleaned.ipynb @@ -697,18 +697,6 @@ "plt.plot(recall_list)" ] }, - { - "cell_type": "code", - "execution_count": null, - "id": "4155385a", - "metadata": { - "scrolled": true - }, - "outputs": [], - "source": [ - "acc_list_t" - ] - }, { "cell_type": "code", "execution_count": null, @@ -2124,57 +2112,26 @@ }, { "cell_type": "code", - "execution_count": 46, + "execution_count": 1, "id": "50fa7478", "metadata": { "scrolled": true }, "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Optimal Threshold: 0.53039104\n" - ] - }, { "data": { "text/plain": [ - "" + "'\\nfrom sklearn.metrics import roc_curve, precision_recall_curve, auc\\nimport matplotlib.pyplot as plt\\n\\n\\nlast_pred = pred_list[len(pred_list)-1][len(pred_list[0])-1].clone()\\n#last_pred = pred_list[len(pred_list)-2].clone()\\ny_torch_test_0 = y_torch_test[:, 0]\\n\\nfpr, tpr, thresholds = roc_curve(y_torch_test_0.flatten(), last_pred.flatten())\\nroc_auc = auc(fpr, tpr)\\n\\nprecision, recall, thresholds = precision_recall_curve(y_torch_test_0.flatten(), last_pred.flatten())\\n\\n#printing optimal ROC threshold\\noptimal_thresh = thresholds[np.argmax(tpr - fpr)]\\nprint(\"Optimal Threshold: \", optimal_thresh)\\n\\n#plotting\\nplt.figure()\\nplt.title(\"ROC\")\\nplt.xlabel(\"fpr\")\\nplt.ylabel(\"tpr\")\\nplt.plot(fpr, tpr, label = \\'AUC = %0.2f\\' % roc_auc)\\nplt.legend(loc = \\'lower right\\')\\n\\nplt.figure()\\nplt.title(\"PR\")\\nplt.xlabel(\"recall\")\\nplt.ylabel(\"precision\")\\nplt.plot(recall, precision, label = \"AP = %0.2f\" % np.mean(precision))\\nplt.legend(loc = \\'lower right\\')\\n'" ] }, - "execution_count": 46, + "execution_count": 1, "metadata": {}, "output_type": "execute_result" - }, - { - "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - }, - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAYIAAAEWCAYAAABrDZDcAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjQuMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/MnkTPAAAACXBIWXMAAAsTAAALEwEAmpwYAAAYXElEQVR4nO3dfZQddZ3n8ffXJBgQhEwSHU0nJpDAEgWD9BJ8QNmVwcAsiWcGTdhFYYYhKxoH8WFwj4wGRnd1QGdGxVFWUHAkCMwI7eHJw4OirmjCgjwE42lDkA6MJFFYMUCevvvHreDtTqe7Ot11L931fp3Th1u/+t263+ru8Omq+tWvIjORJNXXi9pdgCSpvQwCSao5g0CSas4gkKSaMwgkqeYMAkmqOYNAkmrOIJCGKCLWRcQzEfF0RPw6Ir4eEftGxPci4tmifWNE/FtEvKLd9UqDMQikPXNSZu4LvA7oBM4r2pcV7bOBfYGL2lSfVJpBIA1DZq4HbgJe06f9SeA6YF7Li5KGyCCQhiEipgMnAvf0aZ8M/BnQ3Y66pKEI5xqShiYi1gFTgG3AU8ANwIdoHBkcBWwFXgr8DFiYmb9qT6VSOR4RSHvm7Zl5QGa+KjPfm5nPFO1/nZn7A4cDk4CO9pUolWMQSBXIzPuBTwIXR0S0ux5pIAaBVJ3LgZcDC9tdiDQQg0CqSGZuAf4J+Nt21yINxIvFklRzHhFIUs0ZBJJUcwaBJNWcQSBJNTe+3QUM1ZQpU3LmzJntLkOSRpW77757Y2ZO7W/dqAuCmTNnsmrVqnaXIUmjSkQ8srt1nhqSpJozCCSp5gwCSao5g0CSas4gkKSaqywIIuKyiHgiIh7YzfqIiM9HRHdE3BcRr6uqFknS7lV5RPB1YMEA608A5hRfS4F/rrAWSdJuVBYEmXkn8JsBuiwCrsiGu4ADIuIVVdVz8wP/zvH/8H22bNtR1UdI0qjUzmsE04BHm5Z7irZdRMTSiFgVEas2bNiwRx/2nn+5m1/8+mk2Pv3cHr1fksaqUXGxODMvyczOzOycOrXfO6RL277D5y9IUrN2BsF6YHrTckfRJklqoXYGQRfw7mL00NHAU5n5eBvrkaRaqmzSuYhYARwLTImIHuATwASAzPwycCNwItANbAb+oqpaJEm7V1kQZOYpg6xP4H1Vfb4kqZxRcbFYklSd2gVBOmhIknqpXRBIknozCCSp5gwCSao5g0CSas4gkKSaMwgkqeZqFwSJ40clqVntgkCS1JtBIEk1ZxBIUs0ZBJJUcwaBJNWcQSBJNWcQSFLN1S4InIZaknqrXRBIknozCCSp5gwCSao5g0CSas4gkKSaMwgkqeZqFwSOHpWk3moXBJKk3gwCSao5g0CSas4gkKSaMwgkqeYMAkmqudoFQTr9qCT1UmkQRMSCiFgTEd0R8dF+1s+IiDsi4p6IuC8iTqyyHknSrioLgogYB1wMnADMBU6JiLl9up0HXJ2ZRwBLgC9VVY8kqX9VHhEcBXRn5trM3AJcBSzq0yeBlxav9wceq7AeSVI/qgyCacCjTcs9RVuz5cCpEdED3Ai8v78NRcTSiFgVEas2bNhQRa2SVFvtvlh8CvD1zOwATgS+ERG71JSZl2RmZ2Z2Tp06teVFStJYVmUQrAemNy13FG3NzgCuBsjMHwMTgSkV1iRJ6qPKIFgJzImIWRGxF42LwV19+vwKeCtARBxKIwgqPffj4FFJ6q2yIMjMbcAy4BbgIRqjgx6MiAsiYmHR7UPAmRHxM2AFcHo60F+SWmp8lRvPzBtpXARubvt40+vVwBurrEGSNLB2XyyWJLWZQSBJNWcQSFLNGQSSVHMGgSTVXO2CwMGpktRb7YJAktSbQSBJNWcQSFLNGQSSVHMGgSTVnEEgSTVXwyBw/KgkNathEEiSmhkEklRzBoEk1ZxBIEk1ZxBIUs0ZBJJUc7ULAmcflaTeahcEkqTeDAJJqjmDQJJqziCQpJozCCSp5gwCSaq52gWBo0clqbfaBYEkqTeDQJJqziCQpJqrNAgiYkFErImI7oj46G76vDMiVkfEgxFxZZX1SJJ2Nb6qDUfEOOBi4E+AHmBlRHRl5uqmPnOA/wG8MTN/GxEvq6oeSVL/qjwiOArozsy1mbkFuApY1KfPmcDFmflbgMx8osJ6JEn9KH1EEBHTgFc1vycz7xzgLdOAR5uWe4D5ffocXGz7R8A4YHlm3tzPZy8FlgLMmDGjbMmSpBJKBUFEfAZYDKwGthfNCQwUBGU/fw5wLNAB3BkRh2Xmk82dMvMS4BKAzs7OYd0K4DTUktRb2SOCtwOHZOZzQ9j2emB603JH0dasB/hJZm4FHo6IX9AIhpVD+BxJ0jCUvUawFpgwxG2vBOZExKyI2AtYAnT16XMdjaMBImIKjVNFa4f4OZKkYSh7RLAZuDcibgOePyrIzL/e3Rsyc1tELANuoXH+/7LMfDAiLgBWZWZXse74iNh5yukjmblpD/dFkrQHygZBF7v+NT+ozLwRuLFP28ebXifwweJLktQGpYIgMy8vTu8cXDStKc7rS5JGubKjho4FLgfWAQFMj4jTBhk+KkkaBcqeGvoscHxmrgGIiIOBFcCRVRVWlXQiaknqpeyooQk7QwAgM3/B0EcRSZJegMoeEayKiK8C/1Is/zdgVTUlSZJaqWwQnAW8D9g5XPQHwJcqqUiS1FJlRw09B3yu+JIkjSEDBkFEXJ2Z74yI++nncb+ZeXhllUmSWmKwI4Kzi//+l6oLkSS1x4CjhjLz8eLlRuDRzHwEeDHwWuCximurhLOPSlJvZYeP3glMLJ5J8F3gXcDXqypKktQ6ZYMgMnMz8GfAlzLzHcCrqytLktQqpYMgIl5P4/6BG4q2cdWUJElqpbJB8AEaD5n/djGV9IHAHZVVJUlqmbL3EXwf+H7T8lr+cHOZJGkUG+w+gn/MzA9ExHfo/z6ChZVVJklqicGOCL5R/PeiqgtpFYePSlJvAwZBZt5dvFwFPJOZOwAiYhyN+wkkSaNc2YvFtwH7NC3vDdw68uVIklqtbBBMzMyndy4Ur/cZoL8kaZQoGwS/j4jX7VyIiCOBZ6opSZLUSmWfR/AB4JqIeIzGM4v/GFhcVVGSpNYpex/Byoj4D8AhRdOazNxaXVmSpFYpdWooIvYBzgXOzswHgJkR4dTUkjQGlL1G8DVgC/D6Ynk98MlKKqpY7npfnCTVWtkgOCgz/x7YClDMRBqVVSVJapmyQbAlIvammGYiIg4CnqusKklSy5QdNfQJ4GZgekR8E3gjcHpVRUmSWmfQIIiIFwGTaDyU5mgap4TOzsyNFdcmSWqBQYMgM3dExN9k5tX84aE0kqQxouw1glsj4sMRMT0i/mjnV6WVSZJaomwQLAbeS+PhNKuavgYUEQsiYk1EdEfERwfo9+cRkRHRWbKePeY01JLUW9kgmAtcDPwMuBf4AoM8vL6Yqvpi4ITi/adExNx++u0HnA38pHTVkqQRUzYILgcOBT5PIwTmFm0DOQrozsy1mbkFuApY1E+/vwM+AzxbshZJ0ggqO3z0NZnZ/Nf8HRGxepD3TAMebVruAeY3dyhmNJ2emTdExEd2t6GIWAosBZgxY0bJkiVJZZQ9Ivi/EXH0zoWImE+JawQDKYalfg740GB9M/OSzOzMzM6pU6cO52MlSX2UPSI4Evg/EfGrYnkGsCYi7gcyMw/v5z3rgelNyx1F2077Aa8BvhcR0JjauisiFmbmsEJGklRe2SBYsAfbXgnMiYhZNAJgCfBfd67MzKeAKTuXI+J7wIcNAUlqrbLPI3hkqBvOzG0RsQy4BRgHXJaZD0bEBcCqzOwa6jYlSSOv7BHBHsnMG4Eb+7R9fDd9j62yFklS/8peLJYkjVEGgSTVnEEgSTVnEEhSzRkEklRztQsCZx+VpN5qFwSSpN4MAkmqOYNAkmrOIJCkmjMIJKnmDAJJqjmDQJJqrnZBkHgjgSQ1q10QSJJ6MwgkqeYMAkmqOYNAkmrOIJCkmjMIJKnmahcETkMtSb3VLggkSb0ZBJJUcwaBJNWcQSBJNWcQSFLNGQSSVHO1CwJHj0pSb7ULAklSbwaBJNVcpUEQEQsiYk1EdEfER/tZ/8GIWB0R90XEbRHxqirrkSTtqrIgiIhxwMXACcBc4JSImNun2z1AZ2YeDlwL/H1V9UiS+lflEcFRQHdmrs3MLcBVwKLmDpl5R2ZuLhbvAjoqrEeS1I8qg2Aa8GjTck/RtjtnADf1tyIilkbEqohYtWHDhhEsUZL0grhYHBGnAp3Ahf2tz8xLMrMzMzunTp06rM9Kpx+VpF7GV7jt9cD0puWOoq2XiDgO+Bjwlsx8rsJ6JEn9qPKIYCUwJyJmRcRewBKgq7lDRBwBfAVYmJlPVFiLJGk3KguCzNwGLANuAR4Crs7MByPigohYWHS7ENgXuCYi7o2Irt1sTpJUkSpPDZGZNwI39mn7eNPr46r8fEnS4F4QF4slSe1jEEhSzRkEklRztQsC7yKQpN5qFwSSpN4MAkmqOYNAkmrOIJCkmjMIJKnmDAJJqrnaBYGzUEtSb7ULAklSbwaBJNWcQSBJNWcQSFLNGQSSVHMGgSTVXA2DwPGjktSshkEgSWpmEEhSzRkEklRz49tdgKT62rp1Kz09PTz77LPtLmXMmDhxIh0dHUyYMKH0ewwCSW3T09PDfvvtx8yZM4mIdpcz6mUmmzZtoqenh1mzZpV+n6eGJLXNs88+y+TJkw2BERIRTJ48echHWAaBpLYyBEbWnnw/axcETkMtSb3VLggkqa/rrruOiODnP//5823r1q1j7733Zt68ecydO5f3vOc97NixY1if89xzz7F48WJmz57N/PnzWbduXb/9br75Zg455BBmz57Npz/96efbH374YebPn8/s2bNZvHgxW7ZsGVY9OxkEkmpvxYoVvOlNb2LFihW92g866CDuvfde7rvvPlavXs111103rM+59NJLmTRpEt3d3Zxzzjmce+65u/TZvn0773vf+7jppptYvXo1K1asYPXq1QCce+65nHPOOXR3dzNp0iQuvfTSYdWzk6OGJL0gnP+dB1n92P8b0W3OfeVL+cRJrx6wz9NPP80Pf/hD7rjjDk466STOP//8XfqMHz+eN7zhDXR3dw+rnuuvv57ly5cDcPLJJ7Ns2TIys9d5/Z/+9KfMnj2bAw88EIAlS5Zw/fXXc+ihh3L77bdz5ZVXAnDaaaexfPlyzjrrrGHVBB4RSKq566+/ngULFnDwwQczefJk7r777l36bN68mdtuu43DDjtsl3XHHHMM8+bN2+Xr1ltv3aXv+vXrmT59OtAIl/33359Nmzbttg9AR0cH69evZ9OmTRxwwAGMHz++V/tI8IhA0gvCYH+5V2XFihWcffbZQOOv7xUrVnDkkUcC8Mtf/pJ58+YRESxatIgTTjhhl/f/4Ac/aGm9Vag0CCJiAfBPwDjgq5n56T7rXwxcARwJbAIWZ+a6Kmv62o/WMXHCOCa9ZC9euf9Eh65JNfab3/yG22+/nfvvv5+IYPv27UQEF154IfCHawQDOeaYY/jd7363S/tFF13Ecccd16tt2rRpPProo3R0dLBt2zaeeuopJk+e3G+fnXp6epg2bRqTJ0/mySefZNu2bYwfP/759pFQWRBExDjgYuBPgB5gZUR0Zebqpm5nAL/NzNkRsQT4DLC4qpoAbrj/cW64//F+171kr3G88oC9eezJZzhixqRe6wbLi76B0l/3vtvo26e/UNq1z8A9+quzbNSVzcQYZItZ0VTfVQz9rWo0cXXDlEd+w1XVWmazf/nqCazb+PsR325ZK674Jm9/xxI+9dkvPN+2ZOHbuPo73+WVHdPZun0HDw9S3xXfvnm36/q+9w3/+W184Stf5Y/nHM53vn0N89/4ZtZt2tyrz5RZc3lozS+48+4HefkrXskV37ySf/zyZazbtJk3vfktXHvttSxZsoTLL7+cRYsW7cFe76rKI4KjgO7MXAsQEVcBi4DmIFgELC9eXwt8MSIic+R/NQ/YZwJPbt7aq+3AKS9h4oRxrH68cYFq6n4vZu3G3/Pajv15Zuv25/v1LadvcX2r7bf4IW6j0ScH7FPmc0f6W1l2c6PpQKuqo8KqvgVVlFvVz2uwPxq27xjP1u17MCRzhOrt+tdrOPP9H2BbMSw0gOP/dCHX/9s1LF32ATJh+7CGjPYu9ORT3s2Hl53Jsf/xcA44YBL/8JWvsX1H8ut/f5yPfXAZX73yX4kXjePj//MiTnvnIrZv38HJp7yLgw4+lO07kvM/+SnOPP3dnHfeeRxxxBGcccYZw6itqcoK/p/b2HDEycCCzPyrYvldwPzMXNbU54GiT0+x/Muiz8Y+21oKLAWYMWPGkY888siQ6/nemid4/5X3cP/5b9vTXZI0wh566CEOPfTQdpcx5vT3fY2IuzOzs7/+o2LUUGZekpmdmdk5derUPdrGsYe8zBCQpH5UGQTrgelNyx1FW799ImI8sD+Ni8aSpBapMghWAnMiYlZE7AUsAbr69OkCTitenwzcXsX1AUkvXP6TH1l78v2sLAgycxuwDLgFeAi4OjMfjIgLImJh0e1SYHJEdAMfBD5aVT2SXngmTpzIpk2bDIMRsvN5BBMnThzS+yq7WFyVzs7OXLVqVbvLkDQCfELZyNvdE8oGuljsncWS2mbChAlDepKWqjEqRg1JkqpjEEhSzRkEklRzo+5icURsAIZ+a3HDFGDjoL3GFve5HtznehjOPr8qM/u9I3fUBcFwRMSq3V01H6vc53pwn+uhqn321JAk1ZxBIEk1V7cguKTdBbSB+1wP7nM9VLLPtbpGIEnaVd2OCCRJfRgEklRzYzIIImJBRKyJiO6I2GVG04h4cUR8q1j/k4iY2YYyR1SJff5gRKyOiPsi4raIeFU76hxJg+1zU78/j4iMiFE/1LDMPkfEO4uf9YMRcWWraxxpJX63Z0TEHRFxT/H7fWI76hwpEXFZRDxRPMGxv/UREZ8vvh/3RcTrhv2hmTmmvoBxwC+BA4G9gJ8Bc/v0eS/w5eL1EuBb7a67Bfv8n4B9itdn1WGfi377AXcCdwGd7a67BT/nOcA9wKRi+WXtrrsF+3wJcFbxei6wrt11D3Of3wy8DnhgN+tPBG6i8UDko4GfDPczx+IRwVFAd2auzcwtwFXAoj59FgGXF6+vBd4aVT3BvDUG3efMvCMzNxeLd9F4YtxoVubnDPB3wGeAsTDPcZl9PhO4ODN/C5CZT7S4xpFWZp8TeGnxen/gsRbWN+Iy807gNwN0WQRckQ13AQdExCuG85ljMQimAY82LfcUbf32ycYDdJ4CJrekumqU2edmZ9D4i2I0G3Sfi0Pm6Zl5QysLq1CZn/PBwMER8aOIuCsiFrSsumqU2eflwKkR0QPcCLy/NaW1zVD/vQ/K5xHUTEScCnQCb2l3LVWKiBcBnwNOb3MprTaexumhY2kc9d0ZEYdl5pPtLKpipwBfz8zPRsTrgW9ExGsyc0e7CxstxuIRwXpgetNyR9HWb5+IGE/jcHJTS6qrRpl9JiKOAz4GLMzM51pUW1UG2+f9gNcA34uIdTTOpXaN8gvGZX7OPUBXZm7NzIeBX9AIhtGqzD6fAVwNkJk/BibSmJxtrCr1730oxmIQrATmRMSsiNiLxsXgrj59uoDTitcnA7dncRVmlBp0nyPiCOArNEJgtJ83hkH2OTOfyswpmTkzM2fSuC6yMDNH83NOy/xuX0fjaICImELjVNHaFtY40srs86+AtwJExKE0gmBDS6tsrS7g3cXooaOBpzLz8eFscMydGsrMbRGxDLiFxoiDyzLzwYi4AFiVmV3ApTQOH7tpXJRZ0r6Kh6/kPl8I7AtcU1wX/1VmLmxb0cNUcp/HlJL7fAtwfESsBrYDH8nMUXu0W3KfPwT874g4h8aF49NH8x92EbGCRphPKa57fAKYAJCZX6ZxHeREoBvYDPzFsD9zFH+/JEkjYCyeGpIkDYFBIEk1ZxBIUs0ZBJJUcwaBJNWcQSC1UEScHhFfLF4vj4gPt7smySCQSihu3vHfi8Ykf7Gl3YiImcU8+FcADwB/GxErizngz2/q9+6i7WcR8Y2i7aTiWRf3RMStEfHydu2HNJgxd2exNMLm0JiO5KU0piM5isY88F0R8WYac1SdB7whMzdGxB8V7/shcHRmZkT8FfA3NO6AlV5wDAJpYI9k5l0RcRFwPI2HvkBjuo45wGuBazJzI0Bm7pxHvgP4VjFP/F7Aw60tWyrPU0PSwH5f/DeA/5WZ84qv2Zl56QDv+wLwxcw8DPjvNCZCk16QDAKpnFuAv4yIfQEiYlpEvAy4HXhHREwu2neeGtqfP0wNfFrfjUkvJJ4akkrIzO8WUxz/uJi99Wng1GImzE8B34+I7TROHZ1O46lZ10TEb2mExay2FC6V4OyjklRznhqSpJozCCSp5gwCSao5g0CSas4gkKSaMwgkqeYMAkmquf8P4Fgg1yv2Z9UAAAAASUVORK5CYII=\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" } ], "source": [ "#PR and ROC Curves\n", - "\n", + "'''\n", "from sklearn.metrics import roc_curve, precision_recall_curve, auc\n", "import matplotlib.pyplot as plt\n", "\n", @@ -2205,15 +2162,27 @@ "plt.xlabel(\"recall\")\n", "plt.ylabel(\"precision\")\n", "plt.plot(recall, precision, label = \"AP = %0.2f\" % np.mean(precision))\n", - "plt.legend(loc = 'lower right')\n" + "plt.legend(loc = 'lower right')\n", + "'''" ] }, { "cell_type": "code", - "execution_count": 47, + "execution_count": 3, "id": "1d7d1464", "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "'\\npred2_0 = last_pred[:,0]\\n\\npredN0 = pred2_0.numpy()\\n#for i in range(predN.shape[0]):\\nfor i in range(1):\\n for a in range(330):\\n for b in range(330):\\n for c in range(100):\\n if predN0[i][a][b][c] > optimal_thresh:\\n predN0[i][a][b][c] = 1\\n else:\\n predN0[i][a][b][c] = 0\\n'" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "#thresholding for test image 0\n", "\n", @@ -2221,7 +2190,7 @@ "\n", "#pred2 = pred.clone().detach()\n", "#pred2_0 = pred2[:,0]\n", - "\n", + "'''\n", "pred2_0 = last_pred[:,0]\n", "\n", "predN0 = pred2_0.numpy()\n", @@ -2233,46 +2202,34 @@ " if predN0[i][a][b][c] > optimal_thresh:\n", " predN0[i][a][b][c] = 1\n", " else:\n", - " predN0[i][a][b][c] = 0\n" + " predN0[i][a][b][c] = 0\n", + "'''" ] }, { "cell_type": "code", - "execution_count": 49, + "execution_count": 2, "id": "16bfc7cb", "metadata": {}, "outputs": [ { - "name": "stderr", - "output_type": "stream", - "text": [ - "/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/napari/_qt/qt_event_loop.py:256: FutureWarning: \n", - "The 'gui_qt()' context manager is deprecated.\n", - "If you are running napari from a script, please use 'napari.run()' as follows:\n", - "\n", - " import napari\n", - "\n", - " viewer = napari.Viewer() # no prior setup needed\n", - " # other code using the viewer...\n", - " napari.run()\n", - "\n", - "In IPython or Jupyter, 'napari.run()' is not necessary. napari will automatically\n", - "start an interactive event loop for you: \n", - "\n", - " import napari\n", - " viewer = napari.Viewer() # that's it!\n", - "\n", - " warn(\n" - ] + "data": { + "text/plain": [ + "'import napari\\nwith napari.gui_qt():\\n viewer = napari.Viewer(ndisplay=3)\\n viewer.add_image((x_torch_test[0][22]))\\n viewer.add_labels((y_torch_test[0][22]).astype(int))\\n viewer.add_labels(predN0[0].astype(int), num_colors = 2)'" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" } ], "source": [ - "import napari\n", + "'''import napari\n", "with napari.gui_qt():\n", " viewer = napari.Viewer(ndisplay=3)\n", " viewer.add_image((x_torch_test[0][22]))\n", " viewer.add_labels((y_torch_test[0][22]).astype(int))\n", - " viewer.add_labels(predN0[0].astype(int), num_colors = 2)" + " viewer.add_labels(predN0[0].astype(int), num_colors = 2)'''" ] }, { From b0f6126505cee9058d27ea7acf427f48e9f16710 Mon Sep 17 00:00:00 2001 From: shreyasingh1 Date: Tue, 1 Mar 2022 18:43:16 -0500 Subject: [PATCH 04/29] cleaned output --- .../pytorch_model/pytorch - cleaned.ipynb | 1337 +---------------- 1 file changed, 2 insertions(+), 1335 deletions(-) diff --git a/experiments/pytorch_model/pytorch - cleaned.ipynb b/experiments/pytorch_model/pytorch - cleaned.ipynb index f7c9a9789..cd976f8bc 100644 --- a/experiments/pytorch_model/pytorch - cleaned.ipynb +++ b/experiments/pytorch_model/pytorch - cleaned.ipynb @@ -716,1345 +716,12 @@ }, { "cell_type": "code", - "execution_count": 13, + "execution_count": null, "id": "8b6386ad", "metadata": { "scrolled": true }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Optimal Threshold for image 0: 0.4813292\n", - "Optimal Threshold for image 1: 0.48879603\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "ERROR:tornado.general:Uncaught exception in ZMQStream callback\n", - "Traceback (most recent call last):\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 431, in _run_callback\n", - " callback(*args, **kwargs)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/jupyter_client/threaded.py\", line 121, in _handle_recv\n", - " msg_list = self.ioloop._asyncio_event_loop.run_until_complete(get_msg(future_msg))\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 618, in run_until_complete\n", - " self._check_running()\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 580, in _check_running\n", - " raise RuntimeError(\n", - "RuntimeError: Cannot run the event loop while another loop is running\n", - "ERROR:tornado.general:Uncaught exception in zmqstream callback\n", - "Traceback (most recent call last):\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 452, in _handle_events\n", - " self._handle_recv()\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 481, in _handle_recv\n", - " self._run_callback(callback, msg)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 431, in _run_callback\n", - " callback(*args, **kwargs)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/jupyter_client/threaded.py\", line 121, in _handle_recv\n", - " msg_list = self.ioloop._asyncio_event_loop.run_until_complete(get_msg(future_msg))\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 618, in run_until_complete\n", - " self._check_running()\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 580, in _check_running\n", - " raise RuntimeError(\n", - "RuntimeError: Cannot run the event loop while another loop is running\n", - "Exception in callback BaseAsyncIOLoop._handle_events(120, 1)\n", - "handle: \n", - "Traceback (most recent call last):\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/events.py\", line 80, in _run\n", - " self._context.run(self._callback, *self._args)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/tornado/platform/asyncio.py\", line 189, in _handle_events\n", - " handler_func(fileobj, events)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 452, in _handle_events\n", - " self._handle_recv()\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 481, in _handle_recv\n", - " self._run_callback(callback, msg)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 431, in _run_callback\n", - " callback(*args, **kwargs)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/jupyter_client/threaded.py\", line 121, in _handle_recv\n", - " msg_list = self.ioloop._asyncio_event_loop.run_until_complete(get_msg(future_msg))\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 618, in run_until_complete\n", - " self._check_running()\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 580, in _check_running\n", - " raise RuntimeError(\n", - "RuntimeError: Cannot run the event loop while another loop is running\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Optimal Threshold for image 2: 0.48569155\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "ERROR:tornado.general:Uncaught exception in ZMQStream callback\n", - "Traceback (most recent call last):\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 431, in _run_callback\n", - " callback(*args, **kwargs)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/jupyter_client/threaded.py\", line 121, in _handle_recv\n", - " msg_list = self.ioloop._asyncio_event_loop.run_until_complete(get_msg(future_msg))\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 618, in run_until_complete\n", - " self._check_running()\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 580, in _check_running\n", - " raise RuntimeError(\n", - "RuntimeError: Cannot run the event loop while another loop is running\n", - "Exception in callback BaseAsyncIOLoop._handle_events(161, 1)\n", - "handle: \n", - "Traceback (most recent call last):\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/events.py\", line 80, in _run\n", - " self._context.run(self._callback, *self._args)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/tornado/platform/asyncio.py\", line 189, in _handle_events\n", - " handler_func(fileobj, events)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 452, in _handle_events\n", - " self._handle_recv()\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 481, in _handle_recv\n", - " self._run_callback(callback, msg)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 431, in _run_callback\n", - " callback(*args, **kwargs)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/jupyter_client/threaded.py\", line 121, in _handle_recv\n", - " msg_list = self.ioloop._asyncio_event_loop.run_until_complete(get_msg(future_msg))\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 618, in run_until_complete\n", - " self._check_running()\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 580, in _check_running\n", - " raise RuntimeError(\n", - "RuntimeError: Cannot run the event loop while another loop is running\n", - "ERROR:tornado.general:Uncaught exception in zmqstream callback\n", - "Traceback (most recent call last):\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 452, in _handle_events\n", - " self._handle_recv()\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 481, in _handle_recv\n", - " self._run_callback(callback, msg)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 431, in _run_callback\n", - " callback(*args, **kwargs)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/jupyter_client/threaded.py\", line 121, in _handle_recv\n", - " msg_list = self.ioloop._asyncio_event_loop.run_until_complete(get_msg(future_msg))\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 618, in run_until_complete\n", - " self._check_running()\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 580, in _check_running\n", - " raise RuntimeError(\n", - "RuntimeError: Cannot run the event loop while another loop is running\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Optimal Threshold for image 3: 0.48149103\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "ERROR:tornado.general:Uncaught exception in ZMQStream callback\n", - "Traceback (most recent call last):\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 431, in _run_callback\n", - " callback(*args, **kwargs)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/jupyter_client/threaded.py\", line 121, in _handle_recv\n", - " msg_list = self.ioloop._asyncio_event_loop.run_until_complete(get_msg(future_msg))\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 618, in run_until_complete\n", - " self._check_running()\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 580, in _check_running\n", - " raise RuntimeError(\n", - "RuntimeError: Cannot run the event loop while another loop is running\n", - "Exception in callback BaseAsyncIOLoop._handle_events(200, 1)\n", - "handle: \n", - "Traceback (most recent call last):\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/events.py\", line 80, in _run\n", - " self._context.run(self._callback, *self._args)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/tornado/platform/asyncio.py\", line 189, in _handle_events\n", - " handler_func(fileobj, events)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 452, in _handle_events\n", - " self._handle_recv()\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 481, in _handle_recv\n", - " self._run_callback(callback, msg)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 431, in _run_callback\n", - " callback(*args, **kwargs)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/jupyter_client/threaded.py\", line 121, in _handle_recv\n", - " msg_list = self.ioloop._asyncio_event_loop.run_until_complete(get_msg(future_msg))\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 618, in run_until_complete\n", - " self._check_running()\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 580, in _check_running\n", - " raise RuntimeError(\n", - "RuntimeError: Cannot run the event loop while another loop is running\n", - "ERROR:tornado.general:Uncaught exception in zmqstream callback\n", - "Traceback (most recent call last):\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 452, in _handle_events\n", - " self._handle_recv()\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 481, in _handle_recv\n", - " self._run_callback(callback, msg)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 431, in _run_callback\n", - " callback(*args, **kwargs)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/jupyter_client/threaded.py\", line 121, in _handle_recv\n", - " msg_list = self.ioloop._asyncio_event_loop.run_until_complete(get_msg(future_msg))\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 618, in run_until_complete\n", - " self._check_running()\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 580, in _check_running\n", - " raise RuntimeError(\n", - "RuntimeError: Cannot run the event loop while another loop is running\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Optimal Threshold for image 4: 0.48195323\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "ERROR:tornado.general:Uncaught exception in ZMQStream callback\n", - "Traceback (most recent call last):\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 431, in _run_callback\n", - " callback(*args, **kwargs)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/jupyter_client/threaded.py\", line 121, in _handle_recv\n", - " msg_list = self.ioloop._asyncio_event_loop.run_until_complete(get_msg(future_msg))\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 618, in run_until_complete\n", - " self._check_running()\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 580, in _check_running\n", - " raise RuntimeError(\n", - "RuntimeError: Cannot run the event loop while another loop is running\n", - "ERROR:tornado.general:Uncaught exception in zmqstream callback\n", - "Traceback (most recent call last):\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 452, in _handle_events\n", - " self._handle_recv()\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 481, in _handle_recv\n", - " self._run_callback(callback, msg)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 431, in _run_callback\n", - " callback(*args, **kwargs)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/jupyter_client/threaded.py\", line 121, in _handle_recv\n", - " msg_list = self.ioloop._asyncio_event_loop.run_until_complete(get_msg(future_msg))\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 618, in run_until_complete\n", - " self._check_running()\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 580, in _check_running\n", - " raise RuntimeError(\n", - "RuntimeError: Cannot run the event loop while another loop is running\n", - "Exception in callback BaseAsyncIOLoop._handle_events(239, 1)\n", - "handle: \n", - "Traceback (most recent call last):\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/events.py\", line 80, in _run\n", - " self._context.run(self._callback, *self._args)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/tornado/platform/asyncio.py\", line 189, in _handle_events\n", - " handler_func(fileobj, events)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 452, in _handle_events\n", - " self._handle_recv()\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 481, in _handle_recv\n", - " self._run_callback(callback, msg)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 431, in _run_callback\n", - " callback(*args, **kwargs)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/jupyter_client/threaded.py\", line 121, in _handle_recv\n", - " msg_list = self.ioloop._asyncio_event_loop.run_until_complete(get_msg(future_msg))\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 618, in run_until_complete\n", - " self._check_running()\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 580, in _check_running\n", - " raise RuntimeError(\n", - "RuntimeError: Cannot run the event loop while another loop is running\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Optimal Threshold for image 5: 0.4820033\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "ERROR:tornado.general:Uncaught exception in ZMQStream callback\n", - "Traceback (most recent call last):\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 431, in _run_callback\n", - " callback(*args, **kwargs)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/jupyter_client/threaded.py\", line 121, in _handle_recv\n", - " msg_list = self.ioloop._asyncio_event_loop.run_until_complete(get_msg(future_msg))\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 618, in run_until_complete\n", - " self._check_running()\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 580, in _check_running\n", - " raise RuntimeError(\n", - "RuntimeError: Cannot run the event loop while another loop is running\n", - "ERROR:tornado.general:Uncaught exception in zmqstream callback\n", - "Traceback (most recent call last):\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 452, in _handle_events\n", - " self._handle_recv()\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 481, in _handle_recv\n", - " self._run_callback(callback, msg)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 431, in _run_callback\n", - " callback(*args, **kwargs)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/jupyter_client/threaded.py\", line 121, in _handle_recv\n", - " msg_list = self.ioloop._asyncio_event_loop.run_until_complete(get_msg(future_msg))\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 618, in run_until_complete\n", - " self._check_running()\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 580, in _check_running\n", - " raise RuntimeError(\n", - "RuntimeError: Cannot run the event loop while another loop is running\n", - "Exception in callback BaseAsyncIOLoop._handle_events(278, 1)\n", - "handle: \n", - "Traceback (most recent call last):\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/events.py\", line 80, in _run\n", - " self._context.run(self._callback, *self._args)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/tornado/platform/asyncio.py\", line 189, in _handle_events\n", - " handler_func(fileobj, events)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 452, in _handle_events\n", - " self._handle_recv()\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 481, in _handle_recv\n", - " self._run_callback(callback, msg)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 431, in _run_callback\n", - " callback(*args, **kwargs)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/jupyter_client/threaded.py\", line 121, in _handle_recv\n", - " msg_list = self.ioloop._asyncio_event_loop.run_until_complete(get_msg(future_msg))\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 618, in run_until_complete\n", - " self._check_running()\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 580, in _check_running\n", - " raise RuntimeError(\n", - "RuntimeError: Cannot run the event loop while another loop is running\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Optimal Threshold for image 6: 0.48155692\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "ERROR:tornado.general:Uncaught exception in ZMQStream callback\n", - "Traceback (most recent call last):\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 431, in _run_callback\n", - " callback(*args, **kwargs)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/jupyter_client/threaded.py\", line 121, in _handle_recv\n", - " msg_list = self.ioloop._asyncio_event_loop.run_until_complete(get_msg(future_msg))\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 618, in run_until_complete\n", - " self._check_running()\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 580, in _check_running\n", - " raise RuntimeError(\n", - "RuntimeError: Cannot run the event loop while another loop is running\n", - "ERROR:tornado.general:Uncaught exception in zmqstream callback\n", - "Traceback (most recent call last):\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 452, in _handle_events\n", - " self._handle_recv()\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 481, in _handle_recv\n", - " self._run_callback(callback, msg)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 431, in _run_callback\n", - " callback(*args, **kwargs)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/jupyter_client/threaded.py\", line 121, in _handle_recv\n", - " msg_list = self.ioloop._asyncio_event_loop.run_until_complete(get_msg(future_msg))\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 618, in run_until_complete\n", - " self._check_running()\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 580, in _check_running\n", - " raise RuntimeError(\n", - "RuntimeError: Cannot run the event loop while another loop is running\n", - "Exception in callback BaseAsyncIOLoop._handle_events(317, 1)\n", - "handle: \n", - "Traceback (most recent call last):\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/events.py\", line 80, in _run\n", - " self._context.run(self._callback, *self._args)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/tornado/platform/asyncio.py\", line 189, in _handle_events\n", - " handler_func(fileobj, events)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 452, in _handle_events\n", - " self._handle_recv()\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 481, in _handle_recv\n", - " self._run_callback(callback, msg)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 431, in _run_callback\n", - " callback(*args, **kwargs)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/jupyter_client/threaded.py\", line 121, in _handle_recv\n", - " msg_list = self.ioloop._asyncio_event_loop.run_until_complete(get_msg(future_msg))\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 618, in run_until_complete\n", - " self._check_running()\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 580, in _check_running\n", - " raise RuntimeError(\n", - "RuntimeError: Cannot run the event loop while another loop is running\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Optimal Threshold for image 7: 0.48152474\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "ERROR:tornado.general:Uncaught exception in ZMQStream callback\n", - "Traceback (most recent call last):\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 431, in _run_callback\n", - " callback(*args, **kwargs)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/jupyter_client/threaded.py\", line 121, in _handle_recv\n", - " msg_list = self.ioloop._asyncio_event_loop.run_until_complete(get_msg(future_msg))\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 618, in run_until_complete\n", - " self._check_running()\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 580, in _check_running\n", - " raise RuntimeError(\n", - "RuntimeError: Cannot run the event loop while another loop is running\n", - "ERROR:tornado.general:Uncaught exception in zmqstream callback\n", - "Traceback (most recent call last):\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 452, in _handle_events\n", - " self._handle_recv()\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 481, in _handle_recv\n", - " self._run_callback(callback, msg)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 431, in _run_callback\n", - " callback(*args, **kwargs)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/jupyter_client/threaded.py\", line 121, in _handle_recv\n", - " msg_list = self.ioloop._asyncio_event_loop.run_until_complete(get_msg(future_msg))\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 618, in run_until_complete\n", - " self._check_running()\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_Exception in callback BaseAsyncIOLoop._handle_events(356, 1)\n", - "handle: \n", - "Traceback (most recent call last):\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/events.py\", line 80, in _run\n", - " self._context.run(self._callback, *self._args)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/tornado/platform/asyncio.py\", line 189, in _handle_events\n", - " handler_func(fileobj, events)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 452, in _handle_events\n", - " self._handle_recv()\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 481, in _handle_recv\n", - " self._run_callback(callback, msg)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 431, in _run_callback\n", - " callback(*args, **kwargs)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/jupyter_client/threaded.py\", line 121, in _handle_recv\n", - " msg_list = self.ioloop._asyncio_event_loop.run_until_complete(get_msg(future_msg))\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 618, in run_until_complete\n", - " self._check_running()\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 580, in _check_running\n", - " raise RuntimeError(\n", - "RuntimeError: Cannot run the event loop while another loop is running\n", - "events.py\", line 580, in _check_running\n", - " raise RuntimeError(\n", - "RuntimeError: Cannot run the event loop while another loop is running\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Optimal Threshold for image 8: 0.4880304\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "ERROR:tornado.general:Uncaught exception in ZMQStream callback\n", - "Traceback (most recent call last):\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 431, in _run_callback\n", - " callback(*args, **kwargs)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/jupyter_client/threaded.py\", line 121, in _handle_recv\n", - " msg_list = self.ioloop._asyncio_event_loop.run_until_complete(get_msg(future_msg))\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 618, in run_until_complete\n", - " self._check_running()\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 580, in _check_running\n", - " raise RuntimeError(\n", - "RuntimeError: Cannot run the event loop while another loop is running\n", - "ERROR:tornado.general:Uncaught exception in zmqstream callback\n", - "Traceback (most recent call last):\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 452, in _handle_events\n", - " self._handle_recv()\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 481, in _handle_recv\n", - " self._run_callback(callback, msg)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 431, in _run_callback\n", - " callback(*args, **kwargs)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/jupyter_client/threaded.py\", line 121, in _handle_recv\n", - " msg_list = self.ioloop._asyncio_event_loop.run_until_complete(get_msg(future_msg))\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 618, in run_until_complete\n", - " self._check_running()\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 580, in _check_running\n", - " raise RuntimeError(\n", - "RuntimeError: Cannot run the event loop while another loop is running\n", - "Exception in callback BaseAsyncIOLoop._handle_events(395, 1)\n", - "handle: \n", - "Traceback (most recent call last):\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/events.py\", line 80, in _run\n", - " self._context.run(self._callback, *self._args)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/tornado/platform/asyncio.py\", line 189, in _handle_events\n", - " handler_func(fileobj, events)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 452, in _handle_events\n", - " self._handle_recv()\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 481, in _handle_recv\n", - " self._run_callback(callback, msg)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 431, in _run_callback\n", - " callback(*args, **kwargs)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/jupyter_client/threaded.py\", line 121, in _handle_recv\n", - " msg_list = self.ioloop._asyncio_event_loop.run_until_complete(get_msg(future_msg))\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 618, in run_until_complete\n", - " self._check_running()\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 580, in _check_running\n", - " raise RuntimeError(\n", - "RuntimeError: Cannot run the event loop while another loop is running\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Optimal Threshold for image 9: 0.48267302\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "ERROR:tornado.general:Uncaught exception in ZMQStream callback\n", - "Traceback (most recent call last):\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 431, in _run_callback\n", - " callback(*args, **kwargs)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/jupyter_client/threaded.py\", line 121, in _handle_recv\n", - " msg_list = self.ioloop._asyncio_event_loop.run_until_complete(get_msg(future_msg))\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 618, in run_until_complete\n", - " self._check_running()\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 580, in _check_running\n", - " raise RuntimeError(\n", - "RuntimeError: Cannot run the event loop while another loop is running\n", - "ERROR:tornado.general:Uncaught exception in zmqstream callback\n", - "Traceback (most recent call last):\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 452, in _handle_events\n", - " self._handle_recv()\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 481, in _handle_recv\n", - " self._run_callback(callback, msg)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 431, in _run_callback\n", - " callback(*args, **kwargs)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/jupyter_client/threaded.py\", line 121, in _handle_recv\n", - " msg_list = self.ioloop._asyncio_event_loop.run_until_complete(get_msg(future_msg))\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 618, in run_until_complete\n", - " self._check_running()\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 580, in _check_running\n", - " raise RuntimeError(\n", - "RuntimeError: Cannot run the event loop while another loop is running\n", - "Exception in callback BaseAsyncIOLoop._handle_events(434, 1)\n", - "handle: \n", - "Traceback (most recent call last):\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/events.py\", line 80, in _run\n", - " self._context.run(self._callback, *self._args)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/tornado/platform/asyncio.py\", line 189, in _handle_events\n", - " handler_func(fileobj, events)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 452, in _handle_events\n", - " self._handle_recv()\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 481, in _handle_recv\n", - " self._run_callback(callback, msg)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 431, in _run_callback\n", - " callback(*args, **kwargs)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/jupyter_client/threaded.py\", line 121, in _handle_recv\n", - " msg_list = self.ioloop._asyncio_event_loop.run_until_complete(get_msg(future_msg))\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 618, in run_until_complete\n", - " self._check_running()\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 580, in _check_running\n", - " raise RuntimeError(\n", - "RuntimeError: Cannot run the event loop while another loop is running\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Optimal Threshold for image 10: 0.4855357\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "ERROR:tornado.general:Uncaught exception in ZMQStream callback\n", - "Traceback (most recent call last):\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 431, in _run_callback\n", - " callback(*args, **kwargs)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/jupyter_client/threaded.py\", line 121, in _handle_recv\n", - " msg_list = self.ioloop._asyncio_event_loop.run_until_complete(get_msg(future_msg))\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 618, in run_until_complete\n", - " self._check_running()\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 580, in _check_running\n", - " raise RuntimeError(\n", - "RuntimeError: Cannot run the event loop while another loop is running\n", - "ERROR:tornado.general:Uncaught exception in zmqstream callback\n", - "Traceback (most recent call last):\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 452, in _handle_events\n", - " self._handle_recv()\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 481, in _handle_recv\n", - " self._run_callback(callback, msg)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 431, in _run_callback\n", - " callback(*args, **kwargs)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/jupyter_client/threaded.py\", line 121, in _handle_recv\n", - " msg_list = self.ioloop._asyncio_event_loop.run_until_complete(get_msg(future_msg))\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 618, in run_until_complete\n", - " self._check_running()\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 580, in _check_running\n", - " raise RuntimeError(\n", - "RuntimeError: Cannot run the event loop while another loop is running\n", - "Exception in callback BaseAsyncIOLoop._handle_events(472, 1)\n", - "handle: \n", - "Traceback (most recent call last):\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/events.py\", line 80, in _run\n", - " self._context.run(self._callback, *self._args)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/tornado/platform/asyncio.py\", line 189, in _handle_events\n", - " handler_func(fileobj, events)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 452, in _handle_events\n", - " self._handle_recv()\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 481, in _handle_recv\n", - " self._run_callback(callback, msg)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 431, in _run_callback\n", - " callback(*args, **kwargs)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/jupyter_client/threaded.py\", line 121, in _handle_recv\n", - " msg_list = self.ioloop._asyncio_event_loop.run_until_complete(get_msg(future_msg))\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 618, in run_until_complete\n", - " self._check_running()\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 580, in _check_running\n", - " raise RuntimeError(\n", - "RuntimeError: Cannot run the event loop while another loop is running\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Optimal Threshold for image 11: 0.48116392\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "ERROR:tornado.general:Uncaught exception in ZMQStream callback\n", - "Traceback (most recent call last):\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 431, in _run_callback\n", - " callback(*args, **kwargs)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/jupyter_client/threaded.py\", line 121, in _handle_recv\n", - " msg_list = self.ioloop._asyncio_event_loop.run_until_complete(get_msg(future_msg))\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 618, in run_until_complete\n", - " self._check_running()\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 580, in _check_running\n", - " raise RuntimeError(\n", - "RuntimeError: Cannot run the event loop while another loop is running\n", - "Exception in callback BaseAsyncIOLoop._handle_events(512, 1)\n", - "handle: \n", - "Traceback (most recent call last):\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/events.py\", line 80, in _run\n", - " self._context.run(self._callback, *self._args)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/tornado/platform/asyncio.py\", line 189, in _handle_events\n", - " handler_func(fileobj, events)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 452, in _handle_events\n", - " self._handle_recv()\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 481, in _handle_recv\n", - " self._run_callback(callback, msg)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 431, in _run_callback\n", - " callback(*args, **kwargs)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/jupyter_client/threaded.py\", line 121, in _handle_recv\n", - " msg_list = self.ioloop._asyncio_event_loop.run_until_complete(get_msg(future_msg))\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 618, in run_until_complete\n", - " self._check_running()\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 580, in _check_running\n", - " raise RuntimeError(\n", - "RuntimeError: Cannot run the event loop while another loop is running\n", - "ERROR:tornado.general:Uncaught exception in zmqstream callback\n", - "Traceback (most recent call last):\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 452, in _handle_events\n", - " self._handle_recv()\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 481, in _handle_recv\n", - " self._run_callback(callback, msg)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 431, in _run_callback\n", - " callback(*args, **kwargs)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/jupyter_client/threaded.py\", line 121, in _handle_recv\n", - " msg_list = self.ioloop._asyncio_event_loop.run_until_complete(get_msg(future_msg))\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 618, in run_until_complete\n", - " self._check_running()\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 580, in _check_running\n", - " raise RuntimeError(\n", - "RuntimeError: Cannot run the event loop while another loop is running\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Optimal Threshold for image 12: 0.48119318\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "ERROR:tornado.general:Uncaught exception in ZMQStream callback\n", - "Traceback (most recent call last):\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 431, in _run_callback\n", - " callback(*args, **kwargs)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/jupyter_client/threaded.py\", line 121, in _handle_recv\n", - " msg_list = self.ioloop._asyncio_event_loop.run_until_complete(get_msg(future_msg))\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 618, in run_until_complete\n", - " self._check_running()\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 580, in _check_running\n", - " raise RuntimeError(\n", - "RuntimeError: Cannot run the event loop while another loop is running\n", - "Exception in callback BaseAsyncIOLoop._handle_events(551, 1)\n", - "handle: \n", - "Traceback (most recent call last):\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/events.py\", line 80, in _run\n", - " self._context.run(self._callback, *self._args)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/tornado/platform/asyncio.py\", line 189, in _handle_events\n", - " handler_func(fileobj, events)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 452, in _handle_events\n", - " self._handle_recv()\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 481, in _handle_recv\n", - " self._run_callback(callback, msg)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 431, in _run_callback\n", - " callback(*args, **kwargs)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/jupyter_client/threaded.py\", line 121, in _handle_recv\n", - " msg_list = self.ioloop._asyncio_event_loop.run_until_complete(get_msg(future_msg))\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 618, in run_until_complete\n", - " self._check_running()\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 580, in _check_running\n", - " raise RuntimeError(\n", - "RuntimeError: Cannot run the event loop while another loop is running\n", - "ERROR:tornado.general:Uncaught exception in zmqstream callback\n", - "Traceback (most recent call last):\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 452, in _handle_events\n", - " self._handle_recv()\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 481, in _handle_recv\n", - " self._run_callback(callback, msg)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 431, in _run_callback\n", - " callback(*args, **kwargs)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/jupyter_client/threaded.py\", line 121, in _handle_recv\n", - " msg_list = self.ioloop._asyncio_event_loop.run_until_complete(get_msg(future_msg))\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 618, in run_until_complete\n", - " self._check_running()\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 580, in _check_running\n", - " raise RuntimeError(\n", - "RuntimeError: Cannot run the event loop while another loop is running\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Optimal Threshold for image 13: 0.48149678\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "ERROR:tornado.general:Uncaught exception in ZMQStream callback\n", - "Traceback (most recent call last):\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 431, in _run_callback\n", - " callback(*args, **kwargs)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/jupyter_client/threaded.py\", line 121, in _handle_recv\n", - " msg_list = self.ioloop._asyncio_event_loop.run_until_complete(get_msg(future_msg))\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 618, in run_until_complete\n", - " self._check_running()\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 580, in _check_running\n", - " raise RuntimeError(\n", - "RuntimeError: Cannot run the event loop while another loop is running\n", - "ERROR:tornado.general:Uncaught exception in zmqstream callback\n", - "Traceback (most recent call last):\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 452, in _handle_events\n", - " self._handle_recv()\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 481, in _handle_recv\n", - " self._run_callback(callback, msg)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 431, in _run_callback\n", - " callback(*args, **kwargs)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/jupyter_client/threaded.py\", line 121, in _handle_recv\n", - " msg_list = self.ioloop._asyncio_event_loop.run_until_complete(get_msg(future_msg))\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 618, in run_until_complete\n", - " self._check_running()\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 580, in _check_running\n", - " raise RuntimeError(\n", - "RuntimeError: Cannot run the event loop while another loop is running\n", - "Exception in callback BaseAsyncIOLoop._handle_events(590, 1)\n", - "handle: \n", - "Traceback (most recent call last):\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/events.py\", line 80, in _run\n", - " self._context.run(self._callback, *self._args)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/tornado/platform/asyncio.py\", line 189, in _handle_events\n", - " handler_func(fileobj, events)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 452, in _handle_events\n", - " self._handle_recv()\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 481, in _handle_recv\n", - " self._run_callback(callback, msg)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 431, in _run_callback\n", - " callback(*args, **kwargs)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/jupyter_client/threaded.py\", line 121, in _handle_recv\n", - " msg_list = self.ioloop._asyncio_event_loop.run_until_complete(get_msg(future_msg))\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 618, in run_until_complete\n", - " self._check_running()\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 580, in _check_running\n", - " raise RuntimeError(\n", - "RuntimeError: Cannot run the event loop while another loop is running\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Optimal Threshold for image 14: 0.48900756\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "ERROR:tornado.general:Uncaught exception in ZMQStream callback\n", - "Traceback (most recent call last):\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 431, in _run_callback\n", - " callback(*args, **kwargs)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/jupyter_client/threaded.py\", line 121, in _handle_recv\n", - " msg_list = self.ioloop._asyncio_event_loop.run_until_complete(get_msg(future_msg))\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 618, in run_until_complete\n", - " self._check_running()\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 580, in _check_running\n", - " raise RuntimeError(\n", - "RuntimeError: Cannot run the event loop while another loop is running\n", - "ERROR:tornado.general:Uncaught exception in zmqstream callback\n", - "Traceback (most recent call last):\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 452, in _handle_events\n", - " self._handle_recv()\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 481, in _handle_recv\n", - " self._run_callback(callback, msg)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 431, in _run_callback\n", - " callback(*args, **kwargs)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/jupyter_client/threaded.py\", line 121, in _handle_recv\n", - " msg_list = self.ioloop._asyncio_event_loop.run_until_complete(get_msg(future_msg))\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 618, in run_until_complete\n", - " self._check_running()\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 580, in _check_running\n", - " raise RuntimeError(\n", - "RuntimeError: Cannot run the event loop while another loop is running\n", - "Exception in callback BaseAsyncIOLoop._handle_events(629, 1)\n", - "handle: \n", - "Traceback (most recent call last):\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/events.py\", line 80, in _run\n", - " self._context.run(self._callback, *self._args)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/tornado/platform/asyncio.py\", line 189, in _handle_events\n", - " handler_func(fileobj, events)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 452, in _handle_events\n", - " self._handle_recv()\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 481, in _handle_recv\n", - " self._run_callback(callback, msg)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 431, in _run_callback\n", - " callback(*args, **kwargs)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/jupyter_client/threaded.py\", line 121, in _handle_recv\n", - " msg_list = self.ioloop._asyncio_event_loop.run_until_complete(get_msg(future_msg))\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 618, in run_until_complete\n", - " self._check_running()\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 580, in _check_running\n", - " raise RuntimeError(\n", - "RuntimeError: Cannot run the event loop while another loop is running\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Optimal Threshold for image 15: 0.4819097\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "ERROR:tornado.general:Uncaught exception in ZMQStream callback\n", - "Traceback (most recent call last):\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 431, in _run_callback\n", - " callback(*args, **kwargs)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/jupyter_client/threaded.py\", line 121, in _handle_recv\n", - " msg_list = self.ioloop._asyncio_event_loop.run_until_complete(get_msg(future_msg))\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 618, in run_until_complete\n", - " self._check_running()\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 580, in _check_running\n", - " raise RuntimeError(\n", - "RuntimeError: Cannot run the event loop while another loop is running\n", - "Exception in callback BaseAsyncIOLoop._handle_events(668, 1)\n", - "handle: \n", - "Traceback (most recent call last):\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/events.py\", line 80, in _run\n", - " self._context.run(self._callback, *self._args)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/tornado/platform/asyncio.py\", line 189, in _handle_events\n", - " handler_func(fileobj, events)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 452, in _handle_events\n", - " self._handle_recv()\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 481, in _handle_recv\n", - " self._run_callback(callback, msg)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 431, in _run_callback\n", - " callback(*args, **kwargs)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/jupyter_client/threaded.py\", line 121, in _handle_recv\n", - " msg_list = self.ioloop._asyncio_event_loop.run_until_complete(get_msg(future_msg))\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 618, in run_until_complete\n", - " self._check_running()\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 580, in _check_running\n", - " raise RuntimeError(\n", - "RuntimeError: Cannot run the event loop while another loop is running\n", - "ERROR:tornado.general:Uncaught exception in zmqstream callback\n", - "Traceback (most recent call last):\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 452, in _handle_events\n", - " self._handle_recv()\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 481, in _handle_recv\n", - " self._run_callback(callback, msg)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 431, in _run_callback\n", - " callback(*args, **kwargs)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/jupyter_client/threaded.py\", line 121, in _handle_recv\n", - " msg_list = self.ioloop._asyncio_event_loop.run_until_complete(get_msg(future_msg))\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 618, in run_until_complete\n", - " self._check_running()\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 580, in _check_running\n", - " raise RuntimeError(\n", - "RuntimeError: Cannot run the event loop while another loop is running\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Optimal Threshold for image 16: 0.48162946\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "ERROR:tornado.general:Uncaught exception in ZMQStream callback\n", - "Traceback (most recent call last):\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 431, in _run_callback\n", - " callback(*args, **kwargs)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/jupyter_client/threaded.py\", line 121, in _handle_recv\n", - " msg_list = self.ioloop._asyncio_event_loop.run_until_complete(get_msg(future_msg))\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 618, in run_until_complete\n", - " self._check_running()\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 580, in _check_running\n", - " raise RuntimeError(\n", - "RuntimeError: Cannot run the event loop while another loop is running\n", - "ERROR:tornado.general:Uncaught exception in zmqstream callback\n", - "Traceback (most recent call last):\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 452, in _handle_events\n", - " self._handle_recv()\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 481, in _handle_recv\n", - " self._run_callback(callback, msg)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 431, in _run_callback\n", - " callback(*args, **kwargs)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/jupyter_client/threaded.py\", line 121, in _handle_recv\n", - " msg_list = self.ioloop._asyncio_event_loop.run_until_complete(get_msg(future_msg))\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 618, in run_until_complete\n", - " self._check_running()\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 580, in _check_running\n", - " raise RuntimeError(\n", - "RuntimeError: Cannot run the event loop while another loop is running\n", - "Exception in callback BaseAsyncIOLoop._handle_events(707, 1)\n", - "handle: \n", - "Traceback (most recent call last):\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/events.py\", line 80, in _run\n", - " self._context.run(self._callback, *self._args)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/tornado/platform/asyncio.py\", line 189, in _handle_events\n", - " handler_func(fileobj, events)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 452, in _handle_events\n", - " self._handle_recv()\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 481, in _handle_recv\n", - " self._run_callback(callback, msg)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 431, in _run_callback\n", - " callback(*args, **kwargs)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/jupyter_client/threaded.py\", line 121, in _handle_recv\n", - " msg_list = self.ioloop._asyncio_event_loop.run_until_complete(get_msg(future_msg))\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 618, in run_until_complete\n", - " self._check_running()\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 580, in _check_running\n", - " raise RuntimeError(\n", - "RuntimeError: Cannot run the event loop while another loop is running\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Optimal Threshold for image 17: 0.48406285\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "ERROR:tornado.general:Uncaught exception in ZMQStream callback\n", - "Traceback (most recent call last):\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 431, in _run_callback\n", - " callback(*args, **kwargs)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/jupyter_client/threaded.py\", line 121, in _handle_recv\n", - " msg_list = self.ioloop._asyncio_event_loop.run_until_complete(get_msg(future_msg))\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 618, in run_until_complete\n", - " self._check_running()\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 580, in _check_running\n", - " raise RuntimeError(\n", - "RuntimeError: Cannot run the event loop while another loop is running\n", - "ERROR:tornado.general:Uncaught exception in zmqstream callback\n", - "Traceback (most recent call last):\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 452, in _handle_events\n", - " self._handle_recv()\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 481, in _handle_recv\n", - " self._run_callback(callback, msg)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 431, in _run_callback\n", - " callback(*args, **kwargs)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/jupyter_client/threaded.py\", line 121, in _handle_recv\n", - " msg_list = self.ioloop._asyncio_event_loop.run_until_complete(get_msg(future_msg))\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 618, in run_until_complete\n", - " self._check_running()\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_Exception in callback BaseAsyncIOLoop._handle_events(746, 1)\n", - "handle: \n", - "Traceback (most recent call last):\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/events.py\", line 80, in _run\n", - " self._context.run(self._callback, *self._args)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/tornado/platform/asyncio.py\", line 189, in _handle_events\n", - " handler_func(fileobj, events)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 452, in _handle_events\n", - " self._handle_recv()\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 481, in _handle_recv\n", - " self._run_callback(callback, msg)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 431, in _run_callback\n", - " callback(*args, **kwargs)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/jupyter_client/threaded.py\", line 121, in _handle_recv\n", - " msg_list = self.ioloop._asyncio_event_loop.run_until_complete(get_msg(future_msg))\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 618, in run_until_complete\n", - " self._check_running()\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 580, in _check_running\n", - " raise RuntimeError(\n", - "RuntimeError: Cannot run the event loop while another loop is running\n", - "events.py\", line 580, in _check_running\n", - " raise RuntimeError(\n", - "RuntimeError: Cannot run the event loop while another loop is running\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Optimal Threshold for image 18: 0.48327488\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "ERROR:tornado.general:Uncaught exception in ZMQStream callback\n", - "Traceback (most recent call last):\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 431, in _run_callback\n", - " callback(*args, **kwargs)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/jupyter_client/threaded.py\", line 121, in _handle_recv\n", - " msg_list = self.ioloop._asyncio_event_loop.run_until_complete(get_msg(future_msg))\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 618, in run_until_complete\n", - " self._check_running()\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 580, in _check_running\n", - " raise RuntimeError(\n", - "RuntimeError: Cannot run the event loop while another loop is running\n", - "ERROR:tornado.general:Uncaught exception in zmqstream callback\n", - "Traceback (most recent call last):\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 452, in _handle_events\n", - " self._handle_recv()\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 481, in _handle_recv\n", - " self._run_callback(callback, msg)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 431, in _run_callback\n", - " callback(*args, **kwargs)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/jupyter_client/threaded.py\", line 121, in _handle_recv\n", - " msg_list = self.ioloop._asyncio_event_loop.run_until_complete(get_msg(future_msg))\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 618, in run_until_complete\n", - " self._check_running()\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 580, in _check_running\n", - " raise RuntimeError(\n", - "RuntimeError: Cannot run the event loop while another loop is running\n", - "Exception in callback BaseAsyncIOLoop._handle_events(785, 1)\n", - "handle: \n", - "Traceback (most recent call last):\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/events.py\", line 80, in _run\n", - " self._context.run(self._callback, *self._args)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/tornado/platform/asyncio.py\", line 189, in _handle_events\n", - " handler_func(fileobj, events)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 452, in _handle_events\n", - " self._handle_recv()\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 481, in _handle_recv\n", - " self._run_callback(callback, msg)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 431, in _run_callback\n", - " callback(*args, **kwargs)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/jupyter_client/threaded.py\", line 121, in _handle_recv\n", - " msg_list = self.ioloop._asyncio_event_loop.run_until_complete(get_msg(future_msg))\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 618, in run_until_complete\n", - " self._check_running()\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 580, in _check_running\n", - " raise RuntimeError(\n", - "RuntimeError: Cannot run the event loop while another loop is running\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Optimal Threshold for image 19: 0.4841251\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "ERROR:tornado.general:Uncaught exception in ZMQStream callback\n", - "Traceback (most recent call last):\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 431, in _run_callback\n", - " callback(*args, **kwargs)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/jupyter_client/threaded.py\", line 121, in _handle_recv\n", - " msg_list = self.ioloop._asyncio_event_loop.run_until_complete(get_msg(future_msg))\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 618, in run_until_complete\n", - " self._check_running()\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 580, in _check_running\n", - " raise RuntimeError(\n", - "RuntimeError: Cannot run the event loop while another loop is running\n", - "ERROR:tornado.general:Uncaught exception in zmqstream callback\n", - "Traceback (most recent call last):\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 452, in _handle_events\n", - " self._handle_recv()\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 481, in _handle_recv\n", - " self._run_callback(callback, msg)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 431, in _run_callback\n", - " callback(*args, **kwargs)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/jupyter_client/threaded.py\", line 121, in _handle_recv\n", - " msg_list = self.ioloop._asyncio_event_loop.run_until_complete(get_msg(future_msg))\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 618, in run_until_complete\n", - " self._check_running()\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 580, in _check_running\n", - " raise RuntimeError(\n", - "RuntimeError: Cannot run the event loop while another loop is running\n", - "Exception in callback BaseAsyncIOLoop._handle_events(822, 1)\n", - "handle: \n", - "Traceback (most recent call last):\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/events.py\", line 80, in _run\n", - " self._context.run(self._callback, *self._args)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/tornado/platform/asyncio.py\", line 189, in _handle_events\n", - " handler_func(fileobj, events)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 452, in _handle_events\n", - " self._handle_recv()\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 481, in _handle_recv\n", - " self._run_callback(callback, msg)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 431, in _run_callback\n", - " callback(*args, **kwargs)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/jupyter_client/threaded.py\", line 121, in _handle_recv\n", - " msg_list = self.ioloop._asyncio_event_loop.run_until_complete(get_msg(future_msg))\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 618, in run_until_complete\n", - " self._check_running()\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 580, in _check_running\n", - " raise RuntimeError(\n", - "RuntimeError: Cannot run the event loop while another loop is running\n", - "Context leak detected, msgtracer returned -1\n", - "ERROR:tornado.general:Uncaught exception in ZMQStream callback\n", - "Traceback (most recent call last):\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 431, in _run_callback\n", - " callback(*args, **kwargs)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/jupyter_client/threaded.py\", line 121, in _handle_recv\n", - " msg_list = self.ioloop._asyncio_event_loop.run_until_complete(get_msg(future_msg))\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 618, in run_until_complete\n", - " self._check_running()\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 580, in _check_running\n", - " raise RuntimeError(\n", - "RuntimeError: Cannot run the event loop while another loop is running\n", - "ERROR:tornado.general:Uncaught exception in zmqstream callback\n", - "Traceback (most recent call last):\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 452, in _handle_events\n", - " self._handle_recv()\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 481, in _handle_recv\n", - " self._run_callback(callback, msg)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 431, in _run_callback\n", - " callback(*args, **kwargs)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/jupyter_client/threaded.py\", line 121, in _handle_recv\n", - " msg_list = self.ioloop._asyncio_event_loop.run_until_complete(get_msg(future_msg))\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 618, in run_until_complete\n", - " self._check_running()\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 580, in _check_running\n", - " raise RuntimeError(\n", - "RuntimeError: Cannot run the event loop while another loop is running\n", - "Exception in callback BaseAsyncIOLoop._handle_events(862, 1)\n", - "handle: \n", - "Traceback (most recent call last):\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/events.py\", line 80, in _run\n", - " self._context.run(self._callback, *self._args)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/tornado/platform/asyncio.py\", line 189, in _handle_events\n", - " handler_func(fileobj, events)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 452, in _handle_events\n", - " self._handle_recv()\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 481, in _handle_recv\n", - " self._run_callback(callback, msg)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 431, in _run_callback\n", - " callback(*args, **kwargs)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/jupyter_client/threaded.py\", line 121, in _handle_recv\n", - " msg_list = self.ioloop._asyncio_event_loop.run_until_complete(get_msg(future_msg))\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 618, in run_until_complete\n", - " self._check_running()\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 580, in _check_running\n", - " raise RuntimeError(\n", - "RuntimeError: Cannot run the event loop while another loop is running\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Optimal Threshold for image 20: 0.48557067\n", - "Optimal Threshold for image 21: 0.48140803\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "ERROR:tornado.general:Uncaught exception in ZMQStream callback\n", - "Traceback (most recent call last):\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 431, in _run_callback\n", - " callback(*args, **kwargs)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/jupyter_client/threaded.py\", line 121, in _handle_recv\n", - " msg_list = self.ioloop._asyncio_event_loop.run_until_complete(get_msg(future_msg))\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 618, in run_until_complete\n", - " self._check_running()\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 580, in _check_running\n", - " raise RuntimeError(\n", - "RuntimeError: Cannot run the event loop while another loop is running\n", - "ERROR:tornado.general:Uncaught exception in zmqstream callback\n", - "Traceback (most recent call last):\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 452, in _handle_events\n", - " self._handle_recv()\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 481, in _handle_recv\n", - " self._run_callback(callback, msg)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 431, in _run_callback\n", - " callback(*args, **kwargs)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/jupyter_client/threaded.py\", line 121, in _handle_recv\n", - " msg_list = self.ioloop._asyncio_event_loop.run_until_complete(get_msg(future_msg))\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 618, in run_until_complete\n", - " self._check_running()\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 580, in _check_running\n", - " raise RuntimeError(\n", - "RuntimeError: Cannot run the event loop while another loop is running\n", - "Exception in callback BaseAsyncIOLoop._handle_events(902, 1)\n", - "handle: \n", - "Traceback (most recent call last):\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/events.py\", line 80, in _run\n", - " self._context.run(self._callback, *self._args)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/tornado/platform/asyncio.py\", line 189, in _handle_events\n", - " handler_func(fileobj, events)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 452, in _handle_events\n", - " self._handle_recv()\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 481, in _handle_recv\n", - " self._run_callback(callback, msg)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 431, in _run_callback\n", - " callback(*args, **kwargs)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/jupyter_client/threaded.py\", line 121, in _handle_recv\n", - " msg_list = self.ioloop._asyncio_event_loop.run_until_complete(get_msg(future_msg))\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 618, in run_until_complete\n", - " self._check_running()\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 580, in _check_running\n", - " raise RuntimeError(\n", - "RuntimeError: Cannot run the event loop while another loop is running\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Optimal Threshold for image 22: 0.48226443\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "ERROR:tornado.general:Uncaught exception in ZMQStream callback\n", - "Traceback (most recent call last):\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 431, in _run_callback\n", - " callback(*args, **kwargs)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/jupyter_client/threaded.py\", line 121, in _handle_recv\n", - " msg_list = self.ioloop._asyncio_event_loop.run_until_complete(get_msg(future_msg))\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 618, in run_until_complete\n", - " self._check_running()\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 580, in _check_running\n", - " raise RuntimeError(\n", - "RuntimeError: Cannot run the event loop while another loop is running\n", - "ERROR:tornado.general:Uncaught exception in zmqstream callback\n", - "Traceback (most recent call last):\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 452, in _handle_events\n", - " self._handle_recv()\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 481, in _handle_recv\n", - " self._run_callback(callback, msg)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 431, in _run_callback\n", - " callback(*args, **kwargs)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/jupyter_client/threaded.py\", line 121, in _handle_recv\n", - " msg_list = self.ioloop._asyncio_event_loop.run_until_complete(get_msg(future_msg))\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 618, in run_until_complete\n", - " self._check_running()\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 580, in _check_running\n", - " raise RuntimeError(\n", - "RuntimeError: Cannot run the event loop while another loop is running\n", - "Exception in callback BaseAsyncIOLoop._handle_events(940, 1)\n", - "handle: \n", - "Traceback (most recent call last):\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/events.py\", line 80, in _run\n", - " self._context.run(self._callback, *self._args)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/tornado/platform/asyncio.py\", line 189, in _handle_events\n", - " handler_func(fileobj, events)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 452, in _handle_events\n", - " self._handle_recv()\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 481, in _handle_recv\n", - " self._run_callback(callback, msg)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 431, in _run_callback\n", - " callback(*args, **kwargs)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/jupyter_client/threaded.py\", line 121, in _handle_recv\n", - " msg_list = self.ioloop._asyncio_event_loop.run_until_complete(get_msg(future_msg))\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 618, in run_until_complete\n", - " self._check_running()\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 580, in _check_running\n", - " raise RuntimeError(\n", - "RuntimeError: Cannot run the event loop while another loop is running\n", - "ERROR:tornado.general:Uncaught exception in ZMQStream callback\n", - "Traceback (most recent call last):\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 431, in _run_callback\n", - " callback(*args, **kwargs)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/jupyter_client/threaded.py\", line 121, in _handle_recv\n", - " msg_list = self.ioloop._asyncio_event_loop.run_until_complete(get_msg(future_msg))\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 618, in run_until_complete\n", - " self._check_running()\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 580, in _check_running\n", - " raise RuntimeError(\n", - "RuntimeError: Cannot run the event loop while another loop is running\n", - "Exception in callback BaseAsyncIOLoop._handle_events(980, 1)\n", - "handle: \n", - "Traceback (most recent call last):\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/events.py\", line 80, in _run\n", - " self._context.run(self._callback, *self._args)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/tornado/platform/asyncio.py\", line 189, in _handle_events\n", - " handler_func(fileobj, events)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 452, in _handle_events\n", - " self._handle_recv()\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 481, in _handle_recv\n", - " self._run_callback(callback, msg)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 431, in _run_callback\n", - " callback(*args, **kwargs)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/jupyter_client/threaded.py\", line 121, in _handle_recv\n", - " msg_list = self.ioloop._asyncio_event_loop.run_until_complete(get_msg(future_msg))\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 618, in run_until_complete\n", - " self._check_running()\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 580, in _check_running\n", - " raise RuntimeError(\n", - "RuntimeError: Cannot run the event loop while another loop is running\n", - "ERROR:tornado.general:Uncaught exception in zmqstream callback\n", - "Traceback (most recent call last):\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 452, in _handle_events\n", - " self._handle_recv()\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 481, in _handle_recv\n", - " self._run_callback(callback, msg)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/zmq/eventloop/zmqstream.py\", line 431, in _run_callback\n", - " callback(*args, **kwargs)\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/jupyter_client/threaded.py\", line 121, in _handle_recv\n", - " msg_list = self.ioloop._asyncio_event_loop.run_until_complete(get_msg(future_msg))\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_events.py\", line 618, in run_until_complete\n", - " self._check_running()\n", - " File \"/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/asyncio/base_" - ] - } - ], + "outputs": [], "source": [ "# Plot all images/predictions from last epoch\n", "\n", From 31ce0e6645e866239955102039a2f09b81fc7746 Mon Sep 17 00:00:00 2001 From: shreyasingh1 <40285923+shreyasingh1@users.noreply.github.com> Date: Tue, 26 Apr 2022 14:51:52 -0400 Subject: [PATCH 05/29] Update utils.rst adding cnn segmentation docs v1 --- docs/reference/utils.rst | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/docs/reference/utils.rst b/docs/reference/utils.rst index 7506fb75b..c6ac7f732 100644 --- a/docs/reference/utils.rst +++ b/docs/reference/utils.rst @@ -11,6 +11,8 @@ Data Helper Methods .. autoapiclass:: NeuronTrace :members: + +.. autoapifunction:: make_masks .. currentmodule:: brainlit.utils.upload_to_neuroglancer @@ -24,3 +26,11 @@ S3 Helper Methods .. autoapifunction:: upload_chunks .. autoapifunction:: get_file_paths .. autoapifunction:: main + +.. currentmodule:: brainlit.utils.cnn_segmentation + +CNN Segmentation +------------------- + +.. autoapifunction:: preprocess +.. autoapifunction:: performance From a4cf5a99381fd642780cb3d4420da8ab1f5f81db Mon Sep 17 00:00:00 2001 From: shreyasingh1 Date: Tue, 26 Apr 2022 15:07:27 -0400 Subject: [PATCH 06/29] Pytorch Segmentation example notebook and helper files (brainlit.utils) --- brainlit/utils/__init__.py | 3 + brainlit/utils/cnn_segmentation/__init__.py | 6 + .../utils/cnn_segmentation/performance.py | 248 ++++ brainlit/utils/cnn_segmentation/preprocess.py | 161 +++ brainlit/utils/make_masks.py | 101 ++ .../pytorch_model/Pytorch Segmentation.ipynb | 608 ++++++++++ .../pytorch_model/pytorch - cleaned.ipynb | 932 --------------- experiments/pytorch_model/pytorch.ipynb | 1050 ----------------- 8 files changed, 1127 insertions(+), 1982 deletions(-) create mode 100644 brainlit/utils/cnn_segmentation/__init__.py create mode 100644 brainlit/utils/cnn_segmentation/performance.py create mode 100644 brainlit/utils/cnn_segmentation/preprocess.py create mode 100644 brainlit/utils/make_masks.py create mode 100644 experiments/pytorch_model/Pytorch Segmentation.ipynb delete mode 100644 experiments/pytorch_model/pytorch - cleaned.ipynb delete mode 100644 experiments/pytorch_model/pytorch.ipynb diff --git a/brainlit/utils/__init__.py b/brainlit/utils/__init__.py index 67986bac0..da0d0e3eb 100644 --- a/brainlit/utils/__init__.py +++ b/brainlit/utils/__init__.py @@ -2,3 +2,6 @@ from brainlit.utils.upload import * from brainlit.utils.Neuron_trace import * from brainlit.utils.benchmarking_params import * +from brainlit.utils.make_masks import * + +import brainlit.utils.cnn_segmentation \ No newline at end of file diff --git a/brainlit/utils/cnn_segmentation/__init__.py b/brainlit/utils/cnn_segmentation/__init__.py new file mode 100644 index 000000000..6ea708b21 --- /dev/null +++ b/brainlit/utils/cnn_segmentation/__init__.py @@ -0,0 +1,6 @@ +import brainlit.utils.cnn_segmentation + +from brainlit.utils.cnn_segmentation import * + +from brainlit.utils.cnn_segmentation.preprocess import * +from brainlit.utils.cnn_segmentation.performance import * diff --git a/brainlit/utils/cnn_segmentation/performance.py b/brainlit/utils/cnn_segmentation/performance.py new file mode 100644 index 000000000..6a0f0786f --- /dev/null +++ b/brainlit/utils/cnn_segmentation/performance.py @@ -0,0 +1,248 @@ + +# functions for model training and performance evaluation + +import numpy as np +from sklearn.metrics import roc_curve, auc, jaccard_score +from tqdm.notebook import tqdm +import torch +from torch import nn +import matplotlib.pyplot as plt +from sklearn.metrics import accuracy_score, precision_score, recall_score, precision_recall_curve + +# INPUT +# train_dataloader +# NN model defined locally +# loss fn class +# name of optimizer +def train_loop(dataloader, model, loss_fn, optimizer): + + for batch, (X_all, y_all) in enumerate(dataloader): + + loss_list = [] + + for image in range(X_all.shape[1]): + X = np.reshape(X_all[0][image], (1, 1, 66, 66, 20)) + y = np.reshape(y_all[0][image], (1, 1, 66, 66, 20)) + + # Compute prediction and loss + optimizer.zero_grad() + pred = model(X) + pred = torch.squeeze(pred, 3).clone() + loss = loss_fn(pred, y) + + # Backpropagation + loss.backward() + optimizer.step() + loss, current = loss.item(), batch * len(X) + loss_list.append(loss) + +# INPUT +# test_dataloader +# model defined locally +# loss_fn +def test_loop(dataloader, model, loss_fn): + for batch, (X_all, y_all) in enumerate(dataloader): + + loss_list = [] + y_pred = [] + y_list = [] + x_list = [] + + with torch.no_grad(): + for image in range(X_all.shape[1]): + + X = np.reshape(X_all[0][image], (1, 1, 330, 330, 100)) + y = np.reshape(y_all[0][image], (1, 1, 330, 330, 100)) + pred = model(X) + pred = torch.squeeze(pred, 3) + + x_list.append(X) + y_list.append(y) + y_pred.append(pred) + + loss_list.append(loss_fn(pred, y).item()) + + avg_loss = np.average(loss_list) + print("Avg test loss:", avg_loss) + + return x_list, y_pred, y_list, avg_loss + + +# Dice loss class +class DiceLoss(nn.Module): + def __init__(self, weight=None, size_average=True): + super(DiceLoss, self).__init__() + + def forward(self, inputs, targets, smooth=1): + inputs = inputs.view(-1) + targets = targets.view(-1) + + intersection = (inputs * targets).sum() + dice = (2. * intersection + smooth) / (inputs.sum() + targets.sum() + smooth) + + return 1 - dice + + +# getting accuracy, precision, recall at each epoch +# INPUT +# pred_list, list of predictions for every image at every epoch +# y_list, list of true y masks +# OUTPUT +# lists for avg accuracy, precision, recall, and percent_nonzero at each epoch +def get_metrics(pred_list, y_list): + acc_list = [] + precision_list = [] + recall_list = [] + percent_nonzero = [] + + for i in tqdm(range(len(pred_list))): + acc_list_t = [] + precision_list_t = [] + recall_list_t = [] + percent_nonzero_t = [] + + for j in tqdm(range(len(pred_list[0]))): + pred = pred_list[i][j].clone().numpy()[:, 0].round().astype(int).flatten() + target = y_list[i][j][:, 0].clone().numpy().astype(int).flatten() + + acc = accuracy_score(target, pred) * 100 + acc_list_t.append(acc) + + pr = precision_score(target, pred) * 100 + precision_list_t.append(pr) + + rc = recall_score(target, pred) * 100 + recall_list_t.append(rc) + + nz = (np.count_nonzero(pred) / len(target)) * 100 + percent_nonzero_t.append(nz) + + mean_acc = np.mean(acc_list_t) + mean_pr = np.mean(precision_list_t) + mean_rc = np.mean(recall_list_t) + mean_nz = np.mean(percent_nonzero_t) + + acc_list.append(mean_acc) + precision_list.append(mean_pr) + recall_list.append(mean_rc) + percent_nonzero.append(mean_nz) + + return acc_list, precision_list, recall_list, percent_nonzero + + +# Quick test stats +# INPUT +# stat = "all" for all stats +# acc_list, precision_list, recall_list, and percent_nonzero from get_metrics function +# OUTPUT +# printed metrics for specified epoch +def quick_stats(stat, epoch, acc_list, precision_list, recall_list, percent_nonzero): + if stat == "accuracy": + print("Accuracy at epoch " + str(epoch) + " is " + str(acc_list[epoch - 1])) + if stat == "all": + print("Accuracy at epoch " + str(epoch) + " is " + str(acc_list[epoch - 1])) + print("Precision at epoch " + str(epoch) + " is " + str(precision_list[epoch - 1])) + print("Recall at epoch " + str(epoch) + " is " + str(recall_list[epoch - 1])) + print("Percent nonzero at epoch " + str(epoch) + " is " + str(percent_nonzero[epoch - 1])) + +# INPUT +# loss list, list of test loss/any loss at each epoch +# acc_list, precision_list, recall_list, and percent_nonzero from get_metrics function +# OUTPUT +# plotted figures +def plot_metrics_over_epoch(loss_list, acc_list, precision_list, recall_list, percent_nonzero): + plt.figure() + plt.title("Test loss over epoch") + plt.xlabel("Epoch") + plt.ylabel("Test loss") + plt.plot(loss_list) + + plt.figure() + plt.title("Accuracy over epoch") + plt.xlabel("Epoch") + plt.ylabel("Avg accuracy (%)") + plt.plot(acc_list) + + plt.figure() + plt.title("Precision over epoch") + plt.xlabel("Epoch") + plt.ylabel("Avg precision (%)") + plt.plot(precision_list) + + plt.figure() + plt.title("Recall over epoch") + plt.xlabel("Epoch") + plt.ylabel("Avg recall (%)") + plt.plot(recall_list) + + plt.figure() + plt.title("Percent_nonzero over epoch") + plt.xlabel("Epoch") + plt.ylabel("Nonzeros (%)") + plt.plot(percent_nonzero) + +# INPUT +# pred_list, y_list +# OUPTUT +# precision and recall plots for all images at last epoch +def plot_pr_histograms(pred_list, y_list): + + i = len(pred_list) - 1 + precision_list_t = [] + recall_list_t = [] + + for j in tqdm(range(len(pred_list[0]))): + pred = pred_list[i][j].clone().numpy()[:, 0].round().astype(int).flatten() + target = y_list[i][j][:, 0].clone().numpy().astype(int).flatten() + + pr = precision_score(target, pred) * 100 + precision_list_t.append(pr) + + rc = recall_score(target, pred) * 100 + recall_list_t.append(rc) + + # Precision histogram on last epoch + plt.figure() + plt.title("Precision histogram for individual 11 images on last epoch") + plt.ylabel("Individual Precision") + plt.hist(precision_list_t, bins=20) + + # Recall histogram on last epoch + plt.figure() + plt.title("Recall histogram for individual 11 images on last epoch") + plt.ylabel("Individual Recall") + plt.hist(recall_list_t, bins=20) + +# INPUT +# x_list, list of all x images from testing loop +# pred_list, list of testing predictions +# y_list, list of testing y values +# OUTPUT +# visualizations in napari +def plot_with_napari(x_list, pred_list, y_list): + for i in range(len(y_list[len(y_list) - 1])): + x = x_list[i].clone()[:, 0].numpy() + pred = pred_list[len(pred_list) - 1][i].clone()[:, 0].numpy() + y = y_list[len(y_list) - 1][i].clone()[:, 0].numpy() + + fpr, tpr, thresholds = roc_curve(y.flatten(), pred.flatten()) + optimal_thresh = thresholds[np.argmax(tpr - fpr)] + #print("Optimal Threshold for image " + str(i) + ": ", optimal_thresh) + + pred_thresh = pred + + for i in range(1): + for a in range(330): + for b in range(330): + for c in range(100): + if pred[i][a][b][c] > optimal_thresh: + pred_thresh[i][a][b][c] = 1 + else: + pred_thresh[i][a][b][c] = 0 + + import napari + with napari.gui_qt(): + viewer = napari.Viewer(ndisplay=3) + viewer.add_image(x[0]) + viewer.add_labels(y[0].astype(int)) + viewer.add_labels(pred_thresh[0].astype(int), num_colors=2) diff --git a/brainlit/utils/cnn_segmentation/preprocess.py b/brainlit/utils/cnn_segmentation/preprocess.py new file mode 100644 index 000000000..c7dd1d59b --- /dev/null +++ b/brainlit/utils/cnn_segmentation/preprocess.py @@ -0,0 +1,161 @@ + +# preprocessing data from tifs to tensors for evaluation + +from skimage import io +import numpy as np +from pathlib import Path +import os +from tqdm.notebook import tqdm +import torch +from torch.utils.data import DataLoader + + +# INPUT +# data_dir = str, path to tif and mask files +# OUTPUT +# X_img = list of 3d np array images +# y_mask = list of 3d np array masks +def get_img_and_mask(data_dir): + im_dir = Path(os.path.join(data_dir, "sample-tif-location")) + gfp_files = list(im_dir.glob("**/*-gfp.tif")) + X_img = [] + y_mask = [] + + for i, im_path in enumerate(tqdm(gfp_files)): + + f = im_path.parts[-1][:-8].split("_") + image = f[0] + num = int(f[1]) + + if (image == "test" and num in [9, 10, 24]) or (image == "validation" and num in [11]): + continue + + # getting image + im = io.imread(im_path, plugin="tifffile") + im = (im - np.amin(im)) / (np.amax(im) - np.amin(im)) + im = np.swapaxes(im, 0, 2) + im_padded = np.pad(im, ((4, 4), (4, 4), (3, 3))) + + # getting ground truth mask + file_name = str(im_path)[str(im_path).find("\\", 80) + 1: (str(im_path).find("sample"))] + "/mask-location/" + file_num = file_name[file_name.find("_") + 1:] + if file_name[0] == 'v': + file_num = str(int(file_num) + 25) + mask_path = Path(file_name + f[0] + "_" + f[1] + "_mask.npy") + mask = np.load(mask_path) + + X_img.append(im) + y_mask.append(mask) + + return X_img, y_mask + +# Train/test/split +# INPUT +# X_img = list of 3d np array images +# y_mask = list of 3d np array masks +# test_percent = % of data in test set, default = 0.25 +# OUTPUT +# X_train, y_train, X_test, y_test = lists of specified +# training and testing size +def train_test_split(X_img, y_mask, test_percent = 0.25): + num_images = len(X_img) + test_images = num_images * test_percent + train_images = int(num_images - test_images) + + X_train = X_img[0:train_images] + y_train = y_mask[0:train_images] + + X_test = X_img[train_images:num_images] + y_test = y_mask[train_images:num_images] + + return X_train, y_train, X_test, y_test + +# get subvolumes for training set +# INPUT +# X_train, y_train from train_test_split function +# x_dim, int, x_dim of subvolume, must be divisible by image shape +# y_dim, int, y_dim of subvolume, must be divisible by image shape +# z_dim, int, z_dim of subvolume, must be divisible by image shape +# OUTPUT +# X_train_subvolume, y_train_subvolume, lists of subvolumes for training +def get_subvolumes(X_train, y_train, x_dim, y_dim, z_dim): + X_train_subvolumes = [] + y_train_subvolumes = [] + + # check to see if x_dim, y_dim, and z_dim are even units of input image + if X_train[0].shape[0] % x_dim != 0: + print("note: inputted x_dim is not evenly divisible by image") + if X_train[0].shape[1] % y_dim != 0: + print("note: inputted y_dim is not evenly divisible by image") + if X_train[0].shape[2] % z_dim != 0: + print("note: inputted z_dim is not evenly divisible by image") + + # getting subvolumes + for image in X_train: + i = 0 + while i < image.shape[0]: + j = 0 + while j < image.shape[1]: + k = 0 + while k < image.shape[2]: + subvol = image[i:i + x_dim, j:j + y_dim, k:k + z_dim] + X_train_subvolumes.append(subvol) + k += z_dim + j += y_dim + i += x_dim + + for mask in y_train: + i = 0 + while i < mask.shape[0]: + j = 0 + while j < mask.shape[1]: + k = 0 + while k < mask.shape[2]: + subvol = mask[i:i + x_dim, j:j + y_dim, k:k + z_dim] + y_train_subvolumes.append(subvol) + k += z_dim + j += y_dim + i += x_dim + + return X_train_subvolumes, y_train_subvolumes + +# INPUT +# X_train_subvolumes, y_train_subvolumes, X_test, y_test +# OUTPUT +# train_dataloader, torch object +# test_dataloader, torch object +def getting_torch_objects(X_train_subvolumes, y_train_subvolumes, X_test, y_test): + x_dim = X_train_subvolumes[0].shape[0] + y_dim = X_train_subvolumes[0].shape[1] + z_dim = X_train_subvolumes[0].shape[2] + length = len(X_train_subvolumes) + + img_x_dim = X_test[0].shape[0] + img_y_dim = X_test[0].shape[1] + img_z_dim = X_test[0].shape[2] + + X_torch_train = np.reshape(X_train_subvolumes, (1, length, x_dim, y_dim, z_dim)) + y_torch_train = np.reshape(y_train_subvolumes, (1, length, x_dim, y_dim, z_dim)) + + X_torch_test = np.reshape(X_test, (1, len(X_test), img_x_dim, img_y_dim, img_z_dim)) + y_torch_test = np.reshape(y_test, (1, len(y_test), img_x_dim, img_y_dim, img_z_dim)) + + training_data = torch.tensor([X_torch_train, y_torch_train]).float() + test_data = torch.tensor([X_torch_test, y_torch_test]).float() + + batch_size = 2 + # Create data loaders. + train_dataloader = DataLoader(training_data, batch_size=batch_size) + test_dataloader = DataLoader(test_data, batch_size=batch_size) + + # printing dataloader dimensions + train_features, train_labels = next(iter(train_dataloader)) + print(f"Training features shape: {train_features.size()}") + test_features, test_labels = next(iter(test_dataloader)) + print(f"Testing features shape: {test_features.size()}") + + # printing device torch is using (cuda or cpu) + device = 'cuda' if torch.cuda.is_available() else 'cpu' + print('Using {} device'.format(device)) + + return train_dataloader, test_dataloader diff --git a/brainlit/utils/make_masks.py b/brainlit/utils/make_masks.py new file mode 100644 index 000000000..5dd0683e2 --- /dev/null +++ b/brainlit/utils/make_masks.py @@ -0,0 +1,101 @@ +from brainlit.utils.Neuron_trace import NeuronTrace +import numpy as np +from skimage import io +import os +from scipy.ndimage.morphology import distance_transform_edt +from pathlib import Path +from brainlit.viz.swc2voxel import Bresenham3D +from brainlit.utils.benchmarking_params import ( + brain_offsets, + vol_offsets, + scales, + type_to_date, +) + +def make_masks(data_dir): + im_dir = Path(os.path.join(data_dir, "sample-tif-location")) + swc_dir = Path(os.path.join(data_dir, "sample-swc-location")) + mask_dir = os.path.join(data_dir, "mask-location") + if not os.path.exists(mask_dir): + os.makedirs(mask_dir) + + # loading all the benchmarking images from local paths + + # mask_dir = data_dir / "benchmarking_masks" + gfp_files = list(im_dir.glob("**/*.tif")) + # swc_base_path = data_dir / "Manual-GT" + save = True + + for im_num, im_path in enumerate(gfp_files): + # loading one gfp image + im = io.imread(im_path, plugin="tifffile") + im = np.swapaxes(im, 0, 2) + + file_name = im_path.parts[-1][:-8] + + f = im_path.parts[-1][:-8].split("_") + image = f[0] + date = type_to_date[image] + num = int(f[1]) + + scale = scales[date] + brain_offset = brain_offsets[date] + vol_offset = vol_offsets[date][num] + im_offset = np.add(brain_offset, vol_offset) + + # loading all the .swc files corresponding to the image + # all the paths of .swc files are saved in variable swc_files + lower = int(np.floor((num - 1) / 5) * 5 + 1) + upper = int(np.floor((num - 1) / 5) * 5 + 5) + dir1 = date + "_" + image + "_" + str(lower) + "-" + str(upper) + dir2 = date + "_" + image + "_" + str(num) + swc_path = swc_dir / "Manual-GT" / dir1 / dir2 + swc_files = list(swc_path.glob("**/*.swc")) + + paths_total = [] + labels_total = np.zeros(im.shape) + + # generate paths and save them into paths_total + for swc_num, swc in enumerate(swc_files): + if "cube" in swc.parts[-1]: + # skip the bounding box swc + continue + swc = str(swc) + swc_trace = NeuronTrace(path=swc) + paths = swc_trace.get_paths() + swc_offset, _, _, _ = swc_trace.get_df_arguments() + offset_diff = np.subtract(swc_offset, im_offset) + + # for every path in that swc + for path_num, p in enumerate(paths): + pvox = (p + offset_diff) / (scale) * 1000 + paths_total.append(pvox) + + # generate labels by using paths + for path_voxel in paths_total: + for voxel_num, voxel in enumerate(path_voxel): + if voxel_num == 0: + continue + voxel_prev = path_voxel[voxel_num - 1, :] + xs, ys, zs = Bresenham3D( + int(voxel_prev[0]), + int(voxel_prev[1]), + int(voxel_prev[2]), + int(voxel[0]), + int(voxel[1]), + int(voxel[2]), + ) + for x, y, z in zip(xs, ys, zs): + vox = np.array((x, y, z)) + if (vox >= 0).all() and (vox < im.shape).all(): + labels_total[x, y, z] = 1 + + label_flipped = labels_total * 0 + label_flipped[labels_total == 0] = 1 + dists = distance_transform_edt(label_flipped, sampling=scale) + labels_total[dists <= 1000] = 1 + + if save: + im_file_name = file_name + "_mask.npy" + out_file = mask_dir + "/" + im_file_name + np.save(out_file, labels_total) \ No newline at end of file diff --git a/experiments/pytorch_model/Pytorch Segmentation.ipynb b/experiments/pytorch_model/Pytorch Segmentation.ipynb new file mode 100644 index 000000000..82a358316 --- /dev/null +++ b/experiments/pytorch_model/Pytorch Segmentation.ipynb @@ -0,0 +1,608 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "id": "cd35537c", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/nilearn/datasets/__init__.py:93: FutureWarning: Fetchers from the nilearn.datasets module will be updated in version 0.9 to return python strings instead of bytes and Pandas dataframes instead of Numpy arrays.\n", + " warn(\"Fetchers from the nilearn.datasets module will be \"\n" + ] + } + ], + "source": [ + "from brainlit.utils.cnn_segmentation import *\n", + "from brainlit.utils import make_masks\n", + "\n", + "import warnings\n", + "warnings.filterwarnings('ignore')" + ] + }, + { + "cell_type": "markdown", + "id": "892b6c02", + "metadata": {}, + "source": [ + "### Downloading Benchmarking Data" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "f089bd1a", + "metadata": {}, + "outputs": [], + "source": [ + "import boto3\n", + "from botocore import UNSIGNED\n", + "from botocore.client import Config\n", + "import os\n", + "from pathlib import Path\n", + "import numpy as np\n", + "from skimage import io\n", + "from tqdm import tqdm" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "ec1b7beb", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Downloading segments to /Users/shrey2/Documents/NDD/brainlit/experiments/pytorch_model/data\n" + ] + } + ], + "source": [ + "cwd = Path(os.path.abspath(''))\n", + "data_dir = os.path.join(cwd, \"data\")\n", + "print(f\"Downloading segments to {data_dir}\")\n", + "if not os.path.exists(data_dir):\n", + " os.makedirs(data_dir)\n", + "\n", + "im_dir = Path(os.path.join(data_dir, \"sample-tif-location\"))\n", + "if not os.path.exists(im_dir):\n", + " os.makedirs(im_dir)\n", + "\n", + "swc_dir = Path(os.path.join(data_dir, \"sample-swc-location\"))\n", + "if not os.path.exists(swc_dir):\n", + " os.makedirs(swc_dir)" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "bb987499", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "52it [11:33, 13.34s/it]\n" + ] + } + ], + "source": [ + "s3 = boto3.resource(\"s3\", config=Config(signature_version=UNSIGNED))\n", + "bucket = s3.Bucket(\"open-neurodata\")\n", + "prefix = \"brainlit/benchmarking_data/tif-files\" #use this for windows\n", + "# prefix = os.path.join(\"brainlit\", \"benchmarking_data\", \"tif-files\") #use this for mac/linux\n", + "im_count = 0\n", + "for _ in bucket.objects.filter(Prefix=prefix):\n", + " im_count += 1\n", + "for i, im_obj in enumerate(tqdm(bucket.objects.filter(Prefix=prefix))):\n", + " if im_obj.key[-4:] == '.tif':\n", + " im_name = os.path.basename(im_obj.key)\n", + " im_path = os.path.join(im_dir, im_name)\n", + " bucket.download_file(im_obj.key, im_path)" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "1203860b", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "601it [00:53, 11.24it/s]\n" + ] + } + ], + "source": [ + "s3 = boto3.resource(\"s3\", config=Config(signature_version=UNSIGNED))\n", + "bucket = s3.Bucket(\"open-neurodata\")\n", + "prefix = \"brainlit/benchmarking_data/Manual-GT\" #use this for windows\n", + "# prefix = os.path.join(\"brainlit\", \"benchmarking_data\", \"Manual-GT\") #use this for mac/linux\n", + "swc_count = 0\n", + "for _ in bucket.objects.filter(Prefix=prefix):\n", + " swc_count += 1\n", + "for i, swc_obj in enumerate(tqdm(bucket.objects.filter(Prefix=prefix))):\n", + " if swc_obj.key[-4:] == '.swc':\n", + " idx = swc_obj.key.find('Manual-GT')\n", + " swc_name = swc_obj.key[idx:]\n", + " swc_path = os.path.join(swc_dir, swc_name)\n", + " dir = os.path.dirname(swc_path)\n", + " if not os.path.exists(dir):\n", + " os.makedirs(dir)\n", + " bucket.download_file(swc_obj.key, swc_path)" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "374d960c", + "metadata": {}, + "outputs": [], + "source": [ + "# creating image masks\n", + "make_masks(data_dir)" + ] + }, + { + "cell_type": "markdown", + "id": "dbd22cc6", + "metadata": {}, + "source": [ + "### Preprocessing data (preprocess.py)" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "436c14f6", + "metadata": {}, + "outputs": [ + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "50cc88076eb74b669a933068d2eaf18a", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + " 0%| | 0/50 [00:00" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "# getting performance metrics over all epochs\n", + "acc_list, precision_list, recall_list, percent_nonzero = get_metrics(pred_list, y_list)\n", + "\n", + "# printing performance metrics from specific epoch\n", + "quick_stats(\"all\", 2, acc_list, precision_list, recall_list, percent_nonzero)\n", + "\n", + "# plotting metrics\n", + "plot_metrics_over_epoch(loss_list, acc_list, precision_list, recall_list, percent_nonzero)\n", + "\n", + "# plotting precision/recall histograms\n", + "plot_pr_histograms(pred_list, y_list)" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "id": "1835b0b7", + "metadata": {}, + "outputs": [], + "source": [ + "# plotting with napari\n", + "plot_with_napari(x_list, pred_list, y_list)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "08f8e790", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.7" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/experiments/pytorch_model/pytorch - cleaned.ipynb b/experiments/pytorch_model/pytorch - cleaned.ipynb deleted file mode 100644 index cd976f8bc..000000000 --- a/experiments/pytorch_model/pytorch - cleaned.ipynb +++ /dev/null @@ -1,932 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 1, - "id": "83bb4632", - "metadata": {}, - "outputs": [], - "source": [ - "from skimage import io\n", - "import scipy.ndimage as ndi\n", - "import random\n", - "from tqdm import tqdm\n", - "import numpy as np\n", - "from sklearn.model_selection import KFold\n", - "from sklearn.neural_network import MLPClassifier\n", - "from sklearn.linear_model import LogisticRegression\n", - "from sklearn.metrics import roc_curve, auc, jaccard_score\n", - "import matplotlib.pyplot as plt\n", - "from scipy.spatial.distance import dice\n", - "\n", - "from pathlib import Path\n", - "import os\n", - "\n", - "from tqdm.notebook import tqdm\n", - "\n", - "import warnings\n", - "warnings.filterwarnings('ignore')" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "id": "74dc6f71", - "metadata": {}, - "outputs": [], - "source": [ - "import torch\n", - "from torch import nn\n", - "from torch.utils.data import DataLoader\n", - "from torchvision import datasets\n", - "from torchvision.transforms import ToTensor, Lambda, Compose\n", - "import matplotlib.pyplot as plt\n", - "from sklearn.metrics import accuracy_score, precision_score, recall_score, precision_recall_curve" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "id": "32ea5eba", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Downloading segments to /users/shrey2/Documents/NDD/brainlit/docs/notebooks/utils/data\n" - ] - } - ], - "source": [ - "data_dir = \"/users/shrey2/Documents/NDD/brainlit/docs/notebooks/utils/data\"\n", - "print(f\"Downloading segments to {data_dir}\")\n", - "if not os.path.exists(data_dir):\n", - " os.makedirs(data_dir)\n", - "\n", - "im_dir = Path(os.path.join(data_dir, \"sample-tif-location\"))\n", - "if not os.path.exists(im_dir):\n", - " os.makedirs(im_dir)\n", - "\n", - "swc_dir = os.path.join(data_dir, \"sample-swc-location\")\n", - "if not os.path.exists(swc_dir):\n", - " os.makedirs(swc_dir)\n", - "\n", - "mask_dir = Path(os.path.join(data_dir, \"mask-location\"))\n", - "\n", - "swc_base_path = Path(swc_dir) / \"Manual-GT\"\n", - "\n", - "gfp_files = list(im_dir.glob(\"**/*-gfp.tif\"))\n", - "\n", - "ms = \"\"" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "id": "8911c3c6", - "metadata": {}, - "outputs": [ - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "79fc0db9bc2942e587eaf4c4adb40812", - "version_major": 2, - "version_minor": 0 - }, - "text/plain": [ - " 0%| | 0/50 [00:00 optimal_thresh:\n", - " pred_thresh[i][a][b][c] = 1\n", - " else:\n", - " pred_thresh[i][a][b][c] = 0\n", - "\n", - "\n", - " import napari\n", - " with napari.gui_qt():\n", - " viewer = napari.Viewer(ndisplay=3)\n", - " viewer.add_image(x[0])\n", - " viewer.add_labels(y[0].astype(int))\n", - " viewer.add_labels(pred_thresh[0].astype(int), num_colors = 2)\n", - " \n", - " " - ] - }, - { - "cell_type": "code", - "execution_count": 69, - "id": "e2a9e603", - "metadata": {}, - "outputs": [], - "source": [ - "#metrics for one image\n", - "\n", - "#pred_0 = pred.clone().numpy()[:, 0].round().astype(int).flatten()\n", - "#target_0 = y_torch_test[:, 0].astype(int).flatten()\n", - "\n", - "#print(\"Accuracy: \", accuracy_score(target_0, pred_0) * 100)\n", - "#print(\"Precision: \", precision_score(target_0, pred_0) * 100)\n", - "#print(\"Recall: \", recall_score(target_0, pred_0) * 100)\n", - "#print(\"Nonzeros: \", np.count_nonzero(pred_0) * 100)\n", - "#print(\"Nonzeros percent: \", np.count_nonzero(pred_0) / len(target_0) * 100)" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "id": "50fa7478", - "metadata": { - "scrolled": true - }, - "outputs": [ - { - "data": { - "text/plain": [ - "'\\nfrom sklearn.metrics import roc_curve, precision_recall_curve, auc\\nimport matplotlib.pyplot as plt\\n\\n\\nlast_pred = pred_list[len(pred_list)-1][len(pred_list[0])-1].clone()\\n#last_pred = pred_list[len(pred_list)-2].clone()\\ny_torch_test_0 = y_torch_test[:, 0]\\n\\nfpr, tpr, thresholds = roc_curve(y_torch_test_0.flatten(), last_pred.flatten())\\nroc_auc = auc(fpr, tpr)\\n\\nprecision, recall, thresholds = precision_recall_curve(y_torch_test_0.flatten(), last_pred.flatten())\\n\\n#printing optimal ROC threshold\\noptimal_thresh = thresholds[np.argmax(tpr - fpr)]\\nprint(\"Optimal Threshold: \", optimal_thresh)\\n\\n#plotting\\nplt.figure()\\nplt.title(\"ROC\")\\nplt.xlabel(\"fpr\")\\nplt.ylabel(\"tpr\")\\nplt.plot(fpr, tpr, label = \\'AUC = %0.2f\\' % roc_auc)\\nplt.legend(loc = \\'lower right\\')\\n\\nplt.figure()\\nplt.title(\"PR\")\\nplt.xlabel(\"recall\")\\nplt.ylabel(\"precision\")\\nplt.plot(recall, precision, label = \"AP = %0.2f\" % np.mean(precision))\\nplt.legend(loc = \\'lower right\\')\\n'" - ] - }, - "execution_count": 1, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "#PR and ROC Curves\n", - "'''\n", - "from sklearn.metrics import roc_curve, precision_recall_curve, auc\n", - "import matplotlib.pyplot as plt\n", - "\n", - "\n", - "last_pred = pred_list[len(pred_list)-1][len(pred_list[0])-1].clone()\n", - "#last_pred = pred_list[len(pred_list)-2].clone()\n", - "y_torch_test_0 = y_torch_test[:, 0]\n", - "\n", - "fpr, tpr, thresholds = roc_curve(y_torch_test_0.flatten(), last_pred.flatten())\n", - "roc_auc = auc(fpr, tpr)\n", - "\n", - "precision, recall, thresholds = precision_recall_curve(y_torch_test_0.flatten(), last_pred.flatten())\n", - "\n", - "#printing optimal ROC threshold\n", - "optimal_thresh = thresholds[np.argmax(tpr - fpr)]\n", - "print(\"Optimal Threshold: \", optimal_thresh)\n", - "\n", - "#plotting\n", - "plt.figure()\n", - "plt.title(\"ROC\")\n", - "plt.xlabel(\"fpr\")\n", - "plt.ylabel(\"tpr\")\n", - "plt.plot(fpr, tpr, label = 'AUC = %0.2f' % roc_auc)\n", - "plt.legend(loc = 'lower right')\n", - "\n", - "plt.figure()\n", - "plt.title(\"PR\")\n", - "plt.xlabel(\"recall\")\n", - "plt.ylabel(\"precision\")\n", - "plt.plot(recall, precision, label = \"AP = %0.2f\" % np.mean(precision))\n", - "plt.legend(loc = 'lower right')\n", - "'''" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "id": "1d7d1464", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "'\\npred2_0 = last_pred[:,0]\\n\\npredN0 = pred2_0.numpy()\\n#for i in range(predN.shape[0]):\\nfor i in range(1):\\n for a in range(330):\\n for b in range(330):\\n for c in range(100):\\n if predN0[i][a][b][c] > optimal_thresh:\\n predN0[i][a][b][c] = 1\\n else:\\n predN0[i][a][b][c] = 0\\n'" - ] - }, - "execution_count": 3, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "#thresholding for test image 0\n", - "\n", - "#pred2 = pred_list[len(pred_list)-2].clone().detach()\n", - "\n", - "#pred2 = pred.clone().detach()\n", - "#pred2_0 = pred2[:,0]\n", - "'''\n", - "pred2_0 = last_pred[:,0]\n", - "\n", - "predN0 = pred2_0.numpy()\n", - "#for i in range(predN.shape[0]):\n", - "for i in range(1):\n", - " for a in range(330):\n", - " for b in range(330):\n", - " for c in range(100):\n", - " if predN0[i][a][b][c] > optimal_thresh:\n", - " predN0[i][a][b][c] = 1\n", - " else:\n", - " predN0[i][a][b][c] = 0\n", - "'''" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "id": "16bfc7cb", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "'import napari\\nwith napari.gui_qt():\\n viewer = napari.Viewer(ndisplay=3)\\n viewer.add_image((x_torch_test[0][22]))\\n viewer.add_labels((y_torch_test[0][22]).astype(int))\\n viewer.add_labels(predN0[0].astype(int), num_colors = 2)'" - ] - }, - "execution_count": 2, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "'''import napari\n", - "with napari.gui_qt():\n", - " viewer = napari.Viewer(ndisplay=3)\n", - " viewer.add_image((x_torch_test[0][22]))\n", - " viewer.add_labels((y_torch_test[0][22]).astype(int))\n", - " viewer.add_labels(predN0[0].astype(int), num_colors = 2)'''" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "b6852cea", - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.9.7" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/experiments/pytorch_model/pytorch.ipynb b/experiments/pytorch_model/pytorch.ipynb deleted file mode 100644 index 74c031d58..000000000 --- a/experiments/pytorch_model/pytorch.ipynb +++ /dev/null @@ -1,1050 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 40, - "id": "c114a9d9", - "metadata": {}, - "outputs": [], - "source": [ - "from skimage import io\n", - "import scipy.ndimage as ndi\n", - "import random\n", - "from tqdm import tqdm\n", - "import numpy as np\n", - "from sklearn.model_selection import KFold\n", - "from sklearn.neural_network import MLPClassifier\n", - "from sklearn.linear_model import LogisticRegression\n", - "from sklearn.metrics import roc_curve, auc, jaccard_score\n", - "import matplotlib.pyplot as plt\n", - "from scipy.spatial.distance import dice\n", - "\n", - "from pathlib import Path\n", - "import os" - ] - }, - { - "cell_type": "code", - "execution_count": 41, - "id": "9c3b7465", - "metadata": {}, - "outputs": [], - "source": [ - "import torch\n", - "from torch import nn\n", - "from torch.utils.data import DataLoader\n", - "from torchvision import datasets\n", - "from torchvision.transforms import ToTensor, Lambda, Compose\n", - "import matplotlib.pyplot as plt\n", - "from sklearn.metrics import accuracy_score, precision_score, recall_score, precision_recall_curve" - ] - }, - { - "cell_type": "code", - "execution_count": 42, - "id": "8809d925", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Downloading segments to /users/shrey2/Documents/NDD/brainlit/docs/notebooks/utils/data\n" - ] - } - ], - "source": [ - "data_dir = \"/users/shrey2/Documents/NDD/brainlit/docs/notebooks/utils/data\"\n", - "print(f\"Downloading segments to {data_dir}\")\n", - "if not os.path.exists(data_dir):\n", - " os.makedirs(data_dir)\n", - "\n", - "im_dir = Path(os.path.join(data_dir, \"sample-tif-location\"))\n", - "if not os.path.exists(im_dir):\n", - " os.makedirs(im_dir)\n", - "\n", - "swc_dir = os.path.join(data_dir, \"sample-swc-location\")\n", - "if not os.path.exists(swc_dir):\n", - " os.makedirs(swc_dir)\n", - "\n", - "mask_dir = Path(os.path.join(data_dir, \"mask-location\"))\n", - "\n", - "swc_base_path = Path(swc_dir) / \"Manual-GT\"\n", - "\n", - "gfp_files = list(im_dir.glob(\"**/*-gfp.tif\"))\n", - "\n", - "ms = \"\"" - ] - }, - { - "cell_type": "code", - "execution_count": 43, - "id": "0354dfe0", - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "100%|███████████████████████████████████████████| 50/50 [00:10<00:00, 4.61it/s]\n" - ] - } - ], - "source": [ - "X_torch = []\n", - "y_torch = []\n", - "\n", - "for i, im_path in enumerate(tqdm(gfp_files)):\n", - "\n", - " f = im_path.parts[-1][:-8].split(\"_\")\n", - " image = f[0]\n", - " num = int(f[1])\n", - "\n", - " if (image == \"test\" and num in [9,10,24]) or (image == \"validation\" and num in [11]):\n", - " continue\n", - "\n", - " #getting image\n", - " im = io.imread(im_path, plugin=\"tifffile\")\n", - " im = (im - np.amin(im)) / (np.amax(im) - np.amin(im))\n", - " im = np.swapaxes(im,0,2)\n", - " im_padded = np.pad(im, ((4,4), (4,4), (3,3)) )\n", - " \n", - " #getting ground truth mask\n", - " file_name = str(im_path)[str(im_path).find(\"\\\\\", 80) + 1 : (str(im_path).find(\"sample\"))] + \"/mask-location/\"\n", - " file_num = file_name[file_name.find(\"_\")+1:]\n", - " if file_name[0] == 'v':\n", - " file_num = str(int(file_num)+25)\n", - " mask_path = Path(file_name + f[0] + \"_\" + f[1] + \"_mask.npy\")\n", - " mask = np.load(mask_path)\n", - " \n", - " X_torch.append(im)\n", - " y_torch.append(mask)" - ] - }, - { - "cell_type": "code", - "execution_count": 44, - "id": "b0873219", - "metadata": {}, - "outputs": [], - "source": [ - "X_torch_train = X_torch[0:30]\n", - "y_torch_train = y_torch[0:30]\n", - "x_torch_test = X_torch[31:45]\n", - "y_torch_test = y_torch[31:45]\n", - "\n", - "training_data = torch.tensor([X_torch_train, y_torch_train]).float()\n", - "test_data = torch.tensor([x_torch_test, y_torch_test]).float()\n", - "\n", - "batch_size = 2\n", - "\n", - "# Create data loaders.\n", - "train_dataloader = DataLoader(training_data, batch_size=batch_size)\n", - "test_dataloader = DataLoader(test_data, batch_size=batch_size)" - ] - }, - { - "cell_type": "code", - "execution_count": 45, - "id": "eff21f3b", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Feature batch shape: torch.Size([30, 330, 330, 100])\n", - "Labels batch shape: torch.Size([30, 330, 330, 100])\n", - "Using cpu device\n" - ] - } - ], - "source": [ - "train_features, train_labels = next(iter(train_dataloader))\n", - "print(f\"Feature batch shape: {train_features.size()}\")\n", - "print(f\"Labels batch shape: {train_labels.size()}\")\n", - "\n", - "device = 'cuda' if torch.cuda.is_available() else 'cpu'\n", - "print('Using {} device'.format(device))" - ] - }, - { - "cell_type": "markdown", - "id": "db730628", - "metadata": {}, - "source": [ - "### Manual Baseline Pytorch Model" - ] - }, - { - "cell_type": "code", - "execution_count": 47, - "id": "c1383a2d", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "NeuralNetwork(\n", - " (linear_relu_stack): Sequential(\n", - " (0): Conv2d(330, 660, kernel_size=(1, 1), stride=(1, 1))\n", - " (1): ReLU()\n", - " (2): Conv2d(660, 990, kernel_size=(1, 1), stride=(1, 1))\n", - " (3): ReLU()\n", - " (4): Conv2d(990, 10, kernel_size=(1, 1), stride=(1, 1))\n", - " (5): ReLU()\n", - " (6): Conv2d(10, 330, kernel_size=(1, 1), stride=(1, 1))\n", - " (7): ConvTranspose2d(330, 330, kernel_size=(1, 1), stride=(1, 1))\n", - " )\n", - ")\n" - ] - } - ], - "source": [ - "class NeuralNetwork(nn.Module):\n", - " def __init__(self):\n", - " super(NeuralNetwork, self).__init__()\n", - " #self.flatten = nn.Flatten()\n", - " self.linear_relu_stack = nn.Sequential(\n", - " #nn.Linear(10890000, 46),\n", - " #nn.ReLU(),\n", - " #nn.Linear(46, 46),\n", - " #nn.ReLU(),\n", - " #nn.Linear(46, 10),\n", - " nn.Conv2d(330, 660, 1, 1),\n", - " nn.ReLU(),\n", - " nn.Conv2d(660, 990, 1, 1),\n", - " nn.ReLU(),\n", - " nn.Conv2d(990, 10, 1, 1),\n", - " nn.ReLU(),\n", - " nn.Conv2d(10, 330, 1, 1),\n", - " \n", - " nn.ConvTranspose2d(330, 330, 1, 1),\n", - "\n", - " #nn.ConvTranspose2D(330, 330, 1, 1)\n", - " #nn.Conv2d(330, 330, 1, 1),\n", - " #nn.Conv2d(330, 330, 1, 1),\n", - "\n", - " #nn.Conv2d(660, 660, 1, 1),\n", - " #nn.Conv2d(660, 330, 1, 1),\n", - "\n", - " #nn.MaxPool2d(330),\n", - " #nn.Linear(1000, 330),\n", - "\n", - " #nn.Conv2d(100, 100, 1, 1),\n", - " #nn.Conv2d(100, 330, 1, 1),\n", - " #nn.Linear(330,330),\n", - " )\n", - "\n", - " def forward(self, x):\n", - " #x = self.flatten(x)\n", - " logits = self.linear_relu_stack(x)\n", - " #logits = self.linear(x)\n", - " #logits = nn.Softmax(dim=1)(logits)\n", - " self.Sigmoid = nn.Sigmoid()\n", - " logits = self.Sigmoid(logits)\n", - " #logits = torch.round(x).clone()\n", - " return logits\n", - " \n", - "model = NeuralNetwork().to(device)\n", - "print(model)" - ] - }, - { - "cell_type": "code", - "execution_count": 48, - "id": "3c16154b", - "metadata": {}, - "outputs": [], - "source": [ - "def train_loop(dataloader, model, loss_fn, optimizer):\n", - " size = len(dataloader.dataset)\n", - " #size = 330*330*100*14\n", - " y_true = []\n", - " y_pred = []\n", - " for batch, (X, y) in enumerate(dataloader):\n", - " #for (X, y) in enumerate(dataloader):\n", - " #print(X)\n", - " # Compute prediction and loss\n", - " #print(batch)\n", - " #print(X.shape)\n", - " #X = X.unsqueeze(3)\n", - " #print(X.shape)\n", - " optimizer.zero_grad()\n", - " pred = model(X)\n", - " pred = torch.squeeze(pred, 3).clone()\n", - " #pred = torch.squeeze(pred, 3)\n", - " #print(pred.shape)\n", - " #print(y.shape)\n", - "\n", - " loss = loss_fn(pred, y)\n", - "\n", - " # Backpropagation\n", - " #optimizer.zero_grad()\n", - " loss.backward()\n", - " optimizer.step()\n", - " \n", - " #getting accuracy\n", - " #pred_r = np.round(pred.detach().numpy())\n", - " #target = y.float()\n", - " #y_true.extend(target.tolist()) \n", - " #y_pred.extend(pred_r.reshape(-1).tolist())\n", - " #print(len(y_true))\n", - " #print(len(y_pred))\n", - " \n", - " if batch % 100 == 0:\n", - " loss, current = loss.item(), batch * len(X)\n", - " print(f\"loss: {loss:>7f} [{current:>5d}/{size:>5d}]\")\n", - " \n", - " #print(\"Accuracy on training set is\", accuracy_score(y_true,y_pred))\n", - "\n", - "\n", - "\n", - "def test_loop(dataloader, model, loss_fn):\n", - " #size = len(dataloader.dataset)\n", - " size = 330*330*100*14\n", - " print(\"Size: \", size)\n", - " num_batches = len(dataloader)\n", - " test_loss, correct = 0, 0\n", - " \n", - " y_true = []\n", - " y_pred = []\n", - "\n", - "\n", - " with torch.no_grad():\n", - " for X, y in dataloader:\n", - " #X = X.unsqueeze(3)\n", - " pred = model(X)\n", - " pred = torch.squeeze(pred, 3)\n", - " test_loss += loss_fn(pred, y).item()\n", - " #print(pred.shape)\n", - " #print(y.shape)\n", - " correct += (pred == y).type(torch.float).sum().item()\n", - " #correct += y.sum()\n", - " \n", - " #PREDICTIONS\n", - " #pred_r = np.round(pred)\n", - " #target = y.float()\n", - " #y_true.extend(target.tolist()) \n", - " #y_pred.extend(pred_r.reshape(-1).tolist())\n", - " \n", - " #print(\"Accuracy on test set is\" , accuracy_score(y_true,y_pred))\n", - " \n", - " test_loss /= num_batches\n", - " correct /= size\n", - " print(\"Correct: \", correct)\n", - " print(f\"Test Error: \\n Accuracy: {(100*correct):>0.1f}%, Avg loss: {test_loss:>8f} \\n\")\n", - " \n", - " return pred, test_loss" - ] - }, - { - "cell_type": "code", - "execution_count": 49, - "id": "03cb1ccb", - "metadata": {}, - "outputs": [], - "source": [ - "#pred, pred_list, loss_list = test_loop(test_dataloader, model, loss_fn)" - ] - }, - { - "cell_type": "code", - "execution_count": 50, - "id": "1a85b50f", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Epoch 1\n", - "-------------------------------\n", - "loss: 0.696159 [ 0/ 2]\n", - "Size: 152460000\n", - "Correct: 0.0\n", - "Test Error: \n", - " Accuracy: 0.0%, Avg loss: 0.688285 \n", - "\n", - "Epoch 2\n", - "-------------------------------\n", - "loss: 0.688274 [ 0/ 2]\n", - "Size: 152460000\n", - "Correct: 0.0\n", - "Test Error: \n", - " Accuracy: 0.0%, Avg loss: 0.680542 \n", - "\n", - "Epoch 3\n", - "-------------------------------\n", - "loss: 0.680528 [ 0/ 2]\n", - "Size: 152460000\n", - "Correct: 0.0\n", - "Test Error: \n", - " Accuracy: 0.0%, Avg loss: 0.672908 \n", - "\n", - "Done!\n" - ] - } - ], - "source": [ - "loss_fn = nn.BCELoss()\n", - "learning_rate = 0.8\n", - "optimizer = torch.optim.SGD(model.parameters(), lr=learning_rate)\n", - "epochs = 3\n", - "\n", - "pred_list = []\n", - "loss_list = []\n", - "\n", - "for t in range(epochs):\n", - " print(f\"Epoch {t+1}\\n-------------------------------\")\n", - " train_loop(train_dataloader, model, loss_fn, optimizer)\n", - " pred, loss = test_loop(test_dataloader, model, loss_fn)\n", - " pred_list.append(pred)\n", - " loss_list.append(loss)\n", - "print(\"Done!\")" - ] - }, - { - "cell_type": "code", - "execution_count": 51, - "id": "43045fd3", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Accuracy: 0.6448780532598715\n", - "Precision: 0.0013692552851777792\n", - "Recall: 0.31793854110289255\n", - "Nonzeros: 3861223\n", - "Nonzeros percent: 35.456593204775025\n" - ] - } - ], - "source": [ - "preds_0 = pred.numpy()[0].round().astype(int)\n", - "\n", - "print(\"Accuracy: \", accuracy_score(y_torch_test[0].astype(int).flatten(), preds_0.flatten()))\n", - "print(\"Precision: \", precision_score(y_torch_test[0].astype(int).flatten(), preds_0.flatten()))\n", - "print(\"Recall: \", recall_score(y_torch_test[0].astype(int).flatten(), preds_0.flatten()))\n", - "print(\"Nonzeros: \", np.count_nonzero(preds_0.flatten()))\n", - "print(\"Nonzeros percent: \", np.count_nonzero(preds_0.flatten()) / len(y_torch_test[0].astype(int).flatten()) * 100)" - ] - }, - { - "cell_type": "code", - "execution_count": 57, - "id": "b42ebefd", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "torch.Size([14, 330, 330, 100])" - ] - }, - "execution_count": 57, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "pred_list[0].shape" - ] - }, - { - "cell_type": "code", - "execution_count": 75, - "id": "ffd0a468", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "330\n", - "330\n", - "330\n" - ] - }, - { - "data": { - "text/plain": [ - "[]" - ] - }, - "execution_count": 75, - "metadata": {}, - "output_type": "execute_result" - }, - { - "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - }, - { - "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": [ - "import matplotlib.pyplot as plt\n", - "\n", - "acc_list = []\n", - "nonzero_list = []\n", - "for i in range(len(loss_list)):\n", - " pred = pred_list[0][i].numpy().round().astype(int)\n", - " print(len(pred))\n", - " acc = accuracy_score(y_torch_test[i].astype(int).flatten(), pred.flatten())\n", - " acc_list.append(acc)\n", - " \n", - " nonzero = np.count_nonzero(pred.flatten()) / len(y_torch_test[i].astype(int).flatten()) * 100\n", - " nonzero_list.append(nonzero)\n", - "\n", - "plt.figure()\n", - "plt.title(\"Accuracy over 3 epochs\")\n", - "plt.xlabel(\"epochs\")\n", - "plt.ylabel(\"accuracy\")\n", - "plt.plot(acc_list)\n", - "\n", - "plt.figure()\n", - "plt.title(\"% of nonzero predictions over 2 epochs\")\n", - "plt.xlabel(\"epochs\")\n", - "plt.ylabel(\"% nonzero preds\")\n", - "plt.plot(nonzero_list)" - ] - }, - { - "cell_type": "code", - "execution_count": 64, - "id": "e7f1674c", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "[0.6882847547531128, 0.6805418133735657, 0.6729077696800232]" - ] - }, - "execution_count": 64, - "metadata": {}, - "output_type": "execute_result" - }, - { - "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": [ - "plt.figure()\n", - "plt.title(\"Loss over 3 epochs\")\n", - "plt.xlabel(\"epochs\")\n", - "plt.ylabel(\"Loss\")\n", - "plt.plot(loss_list)\n", - "\n", - "loss_list" - ] - }, - { - "cell_type": "code", - "execution_count": 73, - "id": "2c8fea0b", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "(330, 330, 100)" - ] - }, - "execution_count": 73, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "pred_list[0][0].numpy().round().astype(int).shape" - ] - }, - { - "cell_type": "code", - "execution_count": 74, - "id": "eaa8e3ec", - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/napari/_qt/qt_event_loop.py:256: FutureWarning: \n", - "The 'gui_qt()' context manager is deprecated.\n", - "If you are running napari from a script, please use 'napari.run()' as follows:\n", - "\n", - " import napari\n", - "\n", - " viewer = napari.Viewer() # no prior setup needed\n", - " # other code using the viewer...\n", - " napari.run()\n", - "\n", - "In IPython or Jupyter, 'napari.run()' is not necessary. napari will automatically\n", - "start an interactive event loop for you: \n", - "\n", - " import napari\n", - " viewer = napari.Viewer() # that's it!\n", - "\n", - " warn(\n" - ] - } - ], - "source": [ - "import napari\n", - "with napari.gui_qt():\n", - " viewer = napari.Viewer(ndisplay=3)\n", - " viewer.add_image((x_torch_test[0]))\n", - " viewer.add_labels((y_torch_test[0]).astype(int))\n", - " viewer.add_labels(pred_list[0][0].numpy().round().astype(int))" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "189b418e", - "metadata": {}, - "outputs": [], - "source": [ - "precision, recall, thresholds = precision_recall_curve(y_torch_test[0].astype(int).flatten(), pred.numpy()[0].astype(int).flatten())\n", - "\n", - "plt.plot(precision, recall)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "10eb0c6c", - "metadata": {}, - "outputs": [], - "source": [] - }, - { - "cell_type": "markdown", - "id": "626fc9a5", - "metadata": {}, - "source": [ - "### AlexNet" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "0a1fa990", - "metadata": {}, - "outputs": [], - "source": [ - "import torch\n", - "model = torch.hub.load('pytorch/vision:v0.10.0', 'alexnet', pretrained=True)\n", - "model.eval()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "1a6a0cd8", - "metadata": {}, - "outputs": [], - "source": [ - "#model.features[0] = nn.Conv2d(330, 3, 1, 1),\n", - "#model.Conv2D = nn.Conv2D(330, 330, 1, 1)\n", - "model.features[0] = nn.Conv2d(330, 64, 1, 1)\n", - "#model.features[12] = nn.Conv2d(256, 9216, 1, 1)\n", - "\n", - "#model.fc = nn.Linear(4096, 330) \n", - "#model.classifier[1] = nn.Conv2d(9216, 4096, 1, 1)\n", - "#model.classifier[4] = nn.Conv2d(4096, 4096, 1, 1)\n", - "model.classifier[6] = nn.Conv2d(4096, 330, 1, 1)\n", - "\n", - "#model.classifier[6] = nn.ConvTranspose2d(4096, 330, 1, 1)\n", - "model.eval()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "d37ade53", - "metadata": {}, - "outputs": [], - "source": [ - "correct = 0\n", - "with torch.no_grad():\n", - " for X, y in test_dataloader:\n", - " pred = model(X)\n", - " #pred = torch.squeeze(pred, 3)\n", - " #test_loss += loss_fn(pred, y).item()\n", - " \n", - " #correct += (pred == y).type(torch.float).sum().item()\n", - " \n", - "\n", - "#print(\"Correct: \", correct)\n", - "#print(f\"Test Error: \\n Accuracy: {(100*correct):>0.1f}%Avg loss: {test_loss:>8f} \\n\")\n", - " \n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "23850803", - "metadata": { - "scrolled": false - }, - "outputs": [], - "source": [ - "with torch.no_grad():\n", - " output = model(test_dataloader)\n", - "print(output[0])" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "f06b9541", - "metadata": {}, - "outputs": [], - "source": [] - }, - { - "cell_type": "markdown", - "id": "e0590064", - "metadata": {}, - "source": [ - "### uNet" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "3a18c23b", - "metadata": {}, - "outputs": [], - "source": [ - "import torch\n", - "import torch.nn as nn\n", - "import torch.nn.functional as F\n", - "\n", - "\n", - "class DoubleConv(nn.Module):\n", - " \"\"\"(convolution => [BN] => ReLU) * 2\"\"\"\n", - "\n", - " def __init__(self, in_channels, out_channels, mid_channels=None):\n", - " super().__init__()\n", - " if not mid_channels:\n", - " mid_channels = out_channels\n", - " self.double_conv = nn.Sequential(\n", - " nn.Conv2d(in_channels, mid_channels, kernel_size=1, padding=1),\n", - " nn.BatchNorm2d(mid_channels),\n", - " nn.ReLU(inplace=True),\n", - " nn.Conv2d(mid_channels, out_channels, kernel_size=1, padding=1),\n", - " nn.BatchNorm2d(out_channels),\n", - " nn.ReLU(inplace=True)\n", - " )\n", - "\n", - " def forward(self, x):\n", - " return self.double_conv(x)\n", - "\n", - "\n", - "class Down(nn.Module):\n", - " \"\"\"Downscaling with maxpool then double conv\"\"\"\n", - "\n", - " def __init__(self, in_channels, out_channels):\n", - " super().__init__()\n", - " self.maxpool_conv = nn.Sequential(\n", - " nn.MaxPool2d(2),\n", - " DoubleConv(in_channels, out_channels)\n", - " )\n", - " \n", - "\n", - " def forward(self, x):\n", - " return self.maxpool_conv(x)\n", - "\n", - "\n", - "class Up(nn.Module):\n", - " \"\"\"Upscaling then double conv\"\"\"\n", - "\n", - " def __init__(self, in_channels, out_channels, bilinear=True):\n", - " super().__init__()\n", - "\n", - " # if bilinear, use the normal convolutions to reduce the number of channels\n", - " if bilinear:\n", - " self.up = nn.Upsample(scale_factor=2, mode='bilinear', align_corners=True)\n", - " self.conv = DoubleConv(in_channels, out_channels, in_channels // 2)\n", - " else:\n", - " self.up = nn.ConvTranspose2d(in_channels, in_channels // 2, kernel_size=1, stride=1)\n", - " self.conv = DoubleConv(in_channels, out_channels)\n", - "\n", - " def forward(self, x1, x2):\n", - " x1 = self.up(x1)\n", - " # input is CHW\n", - " diffY = x2.size()[2] - x1.size()[2]\n", - " diffX = x2.size()[3] - x1.size()[3]\n", - "\n", - " x1 = F.pad(x1, [diffX // 2, diffX - diffX // 2,\n", - " diffY // 2, diffY - diffY // 2])\n", - " # if you have padding issues, see\n", - " # https://github.com/HaiyongJiang/U-Net-Pytorch-Unstructured-Buggy/commit/0e854509c2cea854e247a9c615f175f76fbb2e3a\n", - " # https://github.com/xiaopeng-liao/Pytorch-UNet/commit/8ebac70e633bac59fc22bb5195e513d5832fb3bd\n", - " x = torch.cat([x2, x1], dim=1)\n", - " return self.conv(x)\n", - "\n", - "\n", - "class OutConv(nn.Module):\n", - " def __init__(self, in_channels, out_channels):\n", - " super(OutConv, self).__init__()\n", - " self.conv = nn.Conv2d(in_channels, out_channels, kernel_size=1)\n", - "\n", - " def forward(self, x):\n", - " return self.conv(x)\n", - " " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "be4f852a", - "metadata": {}, - "outputs": [], - "source": [ - "class UNet(nn.Module):\n", - " def __init__(self, n_channels, n_classes, bilinear=False):\n", - " super(UNet, self).__init__()\n", - " self.n_channels = n_channels\n", - " self.n_classes = n_classes\n", - " self.bilinear = bilinear\n", - "\n", - " self.inc = DoubleConv(n_channels, 330)\n", - " self.down1 = Down(330, 330)\n", - " self.down2 = Down(330, 330)\n", - " self.down3 = Down(330, 330)\n", - " factor = 2 if bilinear else 1\n", - " self.down4 = Down(330, 330 // factor)\n", - " self.up1 = Up(330, 330 // factor, bilinear)\n", - " self.up2 = Up(330, 330 // factor, bilinear)\n", - " self.up3 = Up(330, 330 // factor, bilinear)\n", - " self.up4 = Up(330, 330, bilinear)\n", - " self.outc = OutConv(330, n_classes)\n", - "\n", - " def forward(self, x):\n", - " x1 = self.inc(x)\n", - " x2 = self.down1(x1)\n", - " x3 = self.down2(x2)\n", - " x4 = self.down3(x3)\n", - " x5 = self.down4(x4)\n", - " x = self.up1(x5, x4)\n", - " x = self.up2(x, x3)\n", - " x = self.up3(x, x2)\n", - " x = self.up4(x, x1)\n", - " logits = self.outc(x)\n", - " return logits\n", - " \n", - "UNetModel = UNet(330, 330).to(device)\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "51ba0a57", - "metadata": { - "scrolled": true - }, - "outputs": [], - "source": [ - "#for X, y in test_dataloader:\n", - "# with torch.no_grad():\n", - "# output = UNetModel(X)\n", - "# # Tensor of shape 1000, with confidence scores over Imagenet's 1000 classes\n", - "# print(output[0].shape)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "ab8bd0c0", - "metadata": {}, - "outputs": [], - "source": [ - "def train_loop(dataloader, model, loss_fn, optimizer):\n", - " size = len(dataloader.dataset)\n", - " #size = 330*330*100*14\n", - " y_true = []\n", - " y_pred = []\n", - " for batch, (X, y) in enumerate(dataloader):\n", - "\n", - " optimizer.zero_grad()\n", - " pred = model(X)\n", - " pred = torch.squeeze(pred, 3).clone()\n", - " #pred = torch.squeeze(pred, 3)\n", - " #print(pred.shape)\n", - " #print(y.shape)\n", - "\n", - " loss = loss_fn(pred, y)\n", - "\n", - " # Backpropagation\n", - " #optimizer.zero_grad()\n", - " loss.backward()\n", - " optimizer.step()\n", - " \n", - " #getting accuracy\n", - " #pred_r = np.round(pred.detach().numpy())\n", - " #target = y.float()\n", - " #y_true.extend(target.tolist()) \n", - " #y_pred.extend(pred_r.reshape(-1).tolist())\n", - " #print(len(y_true))\n", - " #print(len(y_pred))\n", - " \n", - " if batch % 100 == 0:\n", - " loss, current = loss.item(), batch * len(X)\n", - " print(f\"loss: {loss:>7f} [{current:>5d}/{size:>5d}]\")\n", - " \n", - " #print(\"Accuracy on training set is\", accuracy_score(y_true,y_pred))\n", - "\n", - "\n", - "def test_loop(dataloader, model, loss_fn):\n", - " #size = len(dataloader.dataset)\n", - " size = 330*330*100*14\n", - " print(\"Size: \", size)\n", - " num_batches = len(dataloader)\n", - " test_loss, correct = 0, 0\n", - " \n", - " y_true = []\n", - " y_pred = []\n", - "\n", - " with torch.no_grad():\n", - " for X, y in dataloader:\n", - " #X = X.unsqueeze(3)\n", - " pred = model(X)\n", - " #pred = torch.squeeze(pred, 3)\n", - " test_loss += loss_fn(pred, y).item()\n", - " #print(pred.shape)\n", - " #print(y.shape)\n", - " correct += (pred == y).type(torch.float).sum().item()\n", - " #correct += y.sum()\n", - " \n", - " #PREDICTIONS\n", - " #pred_r = np.round(pred)\n", - " #target = y.float()\n", - " #y_true.extend(target.tolist()) \n", - " #y_pred.extend(pred_r.reshape(-1).tolist())\n", - " \n", - " #print(\"Accuracy on test set is\" , accuracy_score(y_true,y_pred))\n", - " \n", - " test_loss /= num_batches\n", - " correct /= size\n", - " print(\"Correct: \", correct)\n", - " print(f\"Test Error: \\n Accuracy: {(100*correct):>0.1f}%, Avg loss: {test_loss:>8f} \\n\")\n", - " \n", - " return pred" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "54b501cb", - "metadata": { - "scrolled": true - }, - "outputs": [], - "source": [ - "loss_fn = nn.BCELoss()\n", - "learning_rate = 0.8\n", - "optimizer = torch.optim.SGD(UNetModel.parameters(), lr=learning_rate)\n", - "epochs = 5\n", - "\n", - "for t in range(epochs):\n", - " print(f\"Epoch {t+1}\\n-------------------------------\")\n", - " train_loop(train_dataloader, UNetModel, loss_fn, optimizer)\n", - " pred = test_loop(test_dataloader, UNetModel, loss_fn)\n", - "print(\"Done!\")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "f305f74e", - "metadata": {}, - "outputs": [], - "source": [ - "output_norm = output.numpy()\n", - "output_norm = abs(output_norm).astype(int)\n", - "print(\"nonzero num: \", np.count_nonzero(output_norm))\n", - "print(output_norm[0].shape)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "32789ee6", - "metadata": {}, - "outputs": [], - "source": [ - "preds_0 = output_norm[0]\n", - "\n", - "print(\"Accuracy: \", accuracy_score(y_torch_test[0].astype(int).flatten(), preds_0.flatten()))\n", - "print(\"Precision: \", precision_score(y_torch_test[0].astype(int).flatten(), preds_0.flatten()))\n", - "print(\"Recall: \", recall_score(y_torch_test[0].astype(int).flatten(), preds_0.flatten()))\n", - "print(\"Nonzeros: \", np.count_nonzero(preds_0.flatten()))\n", - "print(\"Nonzeros percent: \", np.count_nonzero(preds_0.flatten()) / len(y_torch_test[0].astype(int).flatten()) * 100)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "1b42e5cc", - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.9.7" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} From 00f374446281a2d58ac0c47c0250cdc92f0d720a Mon Sep 17 00:00:00 2001 From: shreyasingh1 Date: Tue, 26 Apr 2022 15:21:24 -0400 Subject: [PATCH 07/29] formatting files with black --- brainlit/utils/__init__.py | 2 +- .../utils/cnn_segmentation/performance.py | 32 +++++++++++++++---- brainlit/utils/cnn_segmentation/preprocess.py | 29 +++++++++++------ brainlit/utils/make_masks.py | 3 +- 4 files changed, 47 insertions(+), 19 deletions(-) diff --git a/brainlit/utils/__init__.py b/brainlit/utils/__init__.py index da0d0e3eb..2358e878a 100644 --- a/brainlit/utils/__init__.py +++ b/brainlit/utils/__init__.py @@ -4,4 +4,4 @@ from brainlit.utils.benchmarking_params import * from brainlit.utils.make_masks import * -import brainlit.utils.cnn_segmentation \ No newline at end of file +import brainlit.utils.cnn_segmentation diff --git a/brainlit/utils/cnn_segmentation/performance.py b/brainlit/utils/cnn_segmentation/performance.py index 6a0f0786f..85a56e45a 100644 --- a/brainlit/utils/cnn_segmentation/performance.py +++ b/brainlit/utils/cnn_segmentation/performance.py @@ -1,4 +1,3 @@ - # functions for model training and performance evaluation import numpy as np @@ -7,7 +6,12 @@ import torch from torch import nn import matplotlib.pyplot as plt -from sklearn.metrics import accuracy_score, precision_score, recall_score, precision_recall_curve +from sklearn.metrics import ( + accuracy_score, + precision_score, + recall_score, + precision_recall_curve, +) # INPUT # train_dataloader @@ -36,6 +40,7 @@ def train_loop(dataloader, model, loss_fn, optimizer): loss, current = loss.item(), batch * len(X) loss_list.append(loss) + # INPUT # test_dataloader # model defined locally @@ -78,7 +83,7 @@ def forward(self, inputs, targets, smooth=1): targets = targets.view(-1) intersection = (inputs * targets).sum() - dice = (2. * intersection + smooth) / (inputs.sum() + targets.sum() + smooth) + dice = (2.0 * intersection + smooth) / (inputs.sum() + targets.sum() + smooth) return 1 - dice @@ -141,16 +146,26 @@ def quick_stats(stat, epoch, acc_list, precision_list, recall_list, percent_nonz print("Accuracy at epoch " + str(epoch) + " is " + str(acc_list[epoch - 1])) if stat == "all": print("Accuracy at epoch " + str(epoch) + " is " + str(acc_list[epoch - 1])) - print("Precision at epoch " + str(epoch) + " is " + str(precision_list[epoch - 1])) + print( + "Precision at epoch " + str(epoch) + " is " + str(precision_list[epoch - 1]) + ) print("Recall at epoch " + str(epoch) + " is " + str(recall_list[epoch - 1])) - print("Percent nonzero at epoch " + str(epoch) + " is " + str(percent_nonzero[epoch - 1])) + print( + "Percent nonzero at epoch " + + str(epoch) + + " is " + + str(percent_nonzero[epoch - 1]) + ) + # INPUT # loss list, list of test loss/any loss at each epoch # acc_list, precision_list, recall_list, and percent_nonzero from get_metrics function # OUTPUT # plotted figures -def plot_metrics_over_epoch(loss_list, acc_list, precision_list, recall_list, percent_nonzero): +def plot_metrics_over_epoch( + loss_list, acc_list, precision_list, recall_list, percent_nonzero +): plt.figure() plt.title("Test loss over epoch") plt.xlabel("Epoch") @@ -181,6 +196,7 @@ def plot_metrics_over_epoch(loss_list, acc_list, precision_list, recall_list, pe plt.ylabel("Nonzeros (%)") plt.plot(percent_nonzero) + # INPUT # pred_list, y_list # OUPTUT @@ -213,6 +229,7 @@ def plot_pr_histograms(pred_list, y_list): plt.ylabel("Individual Recall") plt.hist(recall_list_t, bins=20) + # INPUT # x_list, list of all x images from testing loop # pred_list, list of testing predictions @@ -227,7 +244,7 @@ def plot_with_napari(x_list, pred_list, y_list): fpr, tpr, thresholds = roc_curve(y.flatten(), pred.flatten()) optimal_thresh = thresholds[np.argmax(tpr - fpr)] - #print("Optimal Threshold for image " + str(i) + ": ", optimal_thresh) + # print("Optimal Threshold for image " + str(i) + ": ", optimal_thresh) pred_thresh = pred @@ -241,6 +258,7 @@ def plot_with_napari(x_list, pred_list, y_list): pred_thresh[i][a][b][c] = 0 import napari + with napari.gui_qt(): viewer = napari.Viewer(ndisplay=3) viewer.add_image(x[0]) diff --git a/brainlit/utils/cnn_segmentation/preprocess.py b/brainlit/utils/cnn_segmentation/preprocess.py index c7dd1d59b..9e49397fa 100644 --- a/brainlit/utils/cnn_segmentation/preprocess.py +++ b/brainlit/utils/cnn_segmentation/preprocess.py @@ -1,4 +1,3 @@ - # preprocessing data from tifs to tensors for evaluation from skimage import io @@ -27,7 +26,9 @@ def get_img_and_mask(data_dir): image = f[0] num = int(f[1]) - if (image == "test" and num in [9, 10, 24]) or (image == "validation" and num in [11]): + if (image == "test" and num in [9, 10, 24]) or ( + image == "validation" and num in [11] + ): continue # getting image @@ -37,9 +38,14 @@ def get_img_and_mask(data_dir): im_padded = np.pad(im, ((4, 4), (4, 4), (3, 3))) # getting ground truth mask - file_name = str(im_path)[str(im_path).find("\\", 80) + 1: (str(im_path).find("sample"))] + "/mask-location/" - file_num = file_name[file_name.find("_") + 1:] - if file_name[0] == 'v': + file_name = ( + str(im_path)[ + str(im_path).find("\\", 80) + 1 : (str(im_path).find("sample")) + ] + + "/mask-location/" + ) + file_num = file_name[file_name.find("_") + 1 :] + if file_name[0] == "v": file_num = str(int(file_num) + 25) mask_path = Path(file_name + f[0] + "_" + f[1] + "_mask.npy") mask = np.load(mask_path) @@ -49,6 +55,7 @@ def get_img_and_mask(data_dir): return X_img, y_mask + # Train/test/split # INPUT # X_img = list of 3d np array images @@ -57,7 +64,7 @@ def get_img_and_mask(data_dir): # OUTPUT # X_train, y_train, X_test, y_test = lists of specified # training and testing size -def train_test_split(X_img, y_mask, test_percent = 0.25): +def train_test_split(X_img, y_mask, test_percent=0.25): num_images = len(X_img) test_images = num_images * test_percent train_images = int(num_images - test_images) @@ -70,6 +77,7 @@ def train_test_split(X_img, y_mask, test_percent = 0.25): return X_train, y_train, X_test, y_test + # get subvolumes for training set # INPUT # X_train, y_train from train_test_split function @@ -98,7 +106,7 @@ def get_subvolumes(X_train, y_train, x_dim, y_dim, z_dim): while j < image.shape[1]: k = 0 while k < image.shape[2]: - subvol = image[i:i + x_dim, j:j + y_dim, k:k + z_dim] + subvol = image[i : i + x_dim, j : j + y_dim, k : k + z_dim] X_train_subvolumes.append(subvol) k += z_dim j += y_dim @@ -111,7 +119,7 @@ def get_subvolumes(X_train, y_train, x_dim, y_dim, z_dim): while j < mask.shape[1]: k = 0 while k < mask.shape[2]: - subvol = mask[i:i + x_dim, j:j + y_dim, k:k + z_dim] + subvol = mask[i : i + x_dim, j : j + y_dim, k : k + z_dim] y_train_subvolumes.append(subvol) k += z_dim j += y_dim @@ -119,6 +127,7 @@ def get_subvolumes(X_train, y_train, x_dim, y_dim, z_dim): return X_train_subvolumes, y_train_subvolumes + # INPUT # X_train_subvolumes, y_train_subvolumes, X_test, y_test # OUTPUT @@ -155,7 +164,7 @@ def getting_torch_objects(X_train_subvolumes, y_train_subvolumes, X_test, y_test print(f"Testing features shape: {test_features.size()}") # printing device torch is using (cuda or cpu) - device = 'cuda' if torch.cuda.is_available() else 'cpu' - print('Using {} device'.format(device)) + device = "cuda" if torch.cuda.is_available() else "cpu" + print("Using {} device".format(device)) return train_dataloader, test_dataloader diff --git a/brainlit/utils/make_masks.py b/brainlit/utils/make_masks.py index 5dd0683e2..b7fa3e74a 100644 --- a/brainlit/utils/make_masks.py +++ b/brainlit/utils/make_masks.py @@ -12,6 +12,7 @@ type_to_date, ) + def make_masks(data_dir): im_dir = Path(os.path.join(data_dir, "sample-tif-location")) swc_dir = Path(os.path.join(data_dir, "sample-swc-location")) @@ -98,4 +99,4 @@ def make_masks(data_dir): if save: im_file_name = file_name + "_mask.npy" out_file = mask_dir + "/" + im_file_name - np.save(out_file, labels_total) \ No newline at end of file + np.save(out_file, labels_total) From 621c4ba3240ee76527531af6ed2b21f74ee0f618 Mon Sep 17 00:00:00 2001 From: shreyasingh1 Date: Tue, 26 Apr 2022 15:47:00 -0400 Subject: [PATCH 08/29] black formatting Pytorch Segmentation notebook --- .../pytorch_model/Pytorch Segmentation.ipynb | 41 +++++++++++-------- 1 file changed, 25 insertions(+), 16 deletions(-) diff --git a/experiments/pytorch_model/Pytorch Segmentation.ipynb b/experiments/pytorch_model/Pytorch Segmentation.ipynb index 82a358316..b6c84d45c 100644 --- a/experiments/pytorch_model/Pytorch Segmentation.ipynb +++ b/experiments/pytorch_model/Pytorch Segmentation.ipynb @@ -20,7 +20,8 @@ "from brainlit.utils import make_masks\n", "\n", "import warnings\n", - "warnings.filterwarnings('ignore')" + "\n", + "warnings.filterwarnings(\"ignore\")" ] }, { @@ -63,7 +64,7 @@ } ], "source": [ - "cwd = Path(os.path.abspath(''))\n", + "cwd = Path(os.path.abspath(\"\"))\n", "data_dir = os.path.join(cwd, \"data\")\n", "print(f\"Downloading segments to {data_dir}\")\n", "if not os.path.exists(data_dir):\n", @@ -95,13 +96,13 @@ "source": [ "s3 = boto3.resource(\"s3\", config=Config(signature_version=UNSIGNED))\n", "bucket = s3.Bucket(\"open-neurodata\")\n", - "prefix = \"brainlit/benchmarking_data/tif-files\" #use this for windows\n", + "prefix = \"brainlit/benchmarking_data/tif-files\" # use this for windows\n", "# prefix = os.path.join(\"brainlit\", \"benchmarking_data\", \"tif-files\") #use this for mac/linux\n", "im_count = 0\n", "for _ in bucket.objects.filter(Prefix=prefix):\n", " im_count += 1\n", "for i, im_obj in enumerate(tqdm(bucket.objects.filter(Prefix=prefix))):\n", - " if im_obj.key[-4:] == '.tif':\n", + " if im_obj.key[-4:] == \".tif\":\n", " im_name = os.path.basename(im_obj.key)\n", " im_path = os.path.join(im_dir, im_name)\n", " bucket.download_file(im_obj.key, im_path)" @@ -124,14 +125,14 @@ "source": [ "s3 = boto3.resource(\"s3\", config=Config(signature_version=UNSIGNED))\n", "bucket = s3.Bucket(\"open-neurodata\")\n", - "prefix = \"brainlit/benchmarking_data/Manual-GT\" #use this for windows\n", + "prefix = \"brainlit/benchmarking_data/Manual-GT\" # use this for windows\n", "# prefix = os.path.join(\"brainlit\", \"benchmarking_data\", \"Manual-GT\") #use this for mac/linux\n", "swc_count = 0\n", "for _ in bucket.objects.filter(Prefix=prefix):\n", " swc_count += 1\n", "for i, swc_obj in enumerate(tqdm(bucket.objects.filter(Prefix=prefix))):\n", - " if swc_obj.key[-4:] == '.swc':\n", - " idx = swc_obj.key.find('Manual-GT')\n", + " if swc_obj.key[-4:] == \".swc\":\n", + " idx = swc_obj.key.find(\"Manual-GT\")\n", " swc_name = swc_obj.key[idx:]\n", " swc_path = os.path.join(swc_dir, swc_name)\n", " dir = os.path.dirname(swc_path)\n", @@ -193,7 +194,7 @@ "outputs": [], "source": [ "# train/test split of specified test size\n", - "X_train, y_train, X_test, y_test = train_test_split(X_img, y_mask, test_percent = 0.25)" + "X_train, y_train, X_test, y_test = train_test_split(X_img, y_mask, test_percent=0.25)" ] }, { @@ -204,7 +205,9 @@ "outputs": [], "source": [ "# getting training subvolumes <- can skip if you do want to train on whole image\n", - "X_train_subvolumes, y_train_subvolumes = get_subvolumes(X_train, y_train, x_dim = 66, y_dim = 66, z_dim = 20)" + "X_train_subvolumes, y_train_subvolumes = get_subvolumes(\n", + " X_train, y_train, x_dim=66, y_dim=66, z_dim=20\n", + ")" ] }, { @@ -225,7 +228,9 @@ ], "source": [ "# getting torch objects\n", - "train_dataloader, test_dataloader = getting_torch_objects(X_train_subvolumes, y_train_subvolumes, X_test, y_test)" + "train_dataloader, test_dataloader = getting_torch_objects(\n", + " X_train_subvolumes, y_train_subvolumes, X_test, y_test\n", + ")" ] }, { @@ -257,11 +262,12 @@ "source": [ "# Define your own neural network architecture here\n", "\n", + "\n", "class NeuralNetwork(nn.Module):\n", " def __init__(self):\n", " super(NeuralNetwork, self).__init__()\n", " self.linear_relu_stack = nn.Sequential(\n", - " nn.Conv3d(1, 1, kernel_size = 3, stride = 1, padding = 1),\n", + " nn.Conv3d(1, 1, kernel_size=3, stride=1, padding=1),\n", " )\n", "\n", " def forward(self, x):\n", @@ -270,7 +276,8 @@ " logits = self.Sigmoid(logits)\n", " return logits\n", "\n", - "device = 'cuda' if torch.cuda.is_available() else 'cpu'\n", + "\n", + "device = \"cuda\" if torch.cuda.is_available() else \"cpu\"\n", "model = NeuralNetwork().to(device)\n", "print(model)" ] @@ -355,7 +362,7 @@ } ], "source": [ - "#loss_fn = nn.BCELoss()\n", + "# loss_fn = nn.BCELoss()\n", "loss_fn = DiceLoss()\n", "learning_rate = 0.09\n", "optimizer = torch.optim.SGD(model.parameters(), lr=learning_rate)\n", @@ -369,11 +376,11 @@ " print(f\"Epoch {t+1}\\n-------------------------------\")\n", " train_loop(train_dataloader, model, loss_fn, optimizer)\n", " x_list, y_pred, y, loss = test_loop(test_dataloader, model, loss_fn)\n", - " \n", + "\n", " pred_list.append(y_pred)\n", " y_list.append(y)\n", " loss_list.append(loss)\n", - " \n", + "\n", "print(\"Done!\")" ] }, @@ -558,7 +565,9 @@ "quick_stats(\"all\", 2, acc_list, precision_list, recall_list, percent_nonzero)\n", "\n", "# plotting metrics\n", - "plot_metrics_over_epoch(loss_list, acc_list, precision_list, recall_list, percent_nonzero)\n", + "plot_metrics_over_epoch(\n", + " loss_list, acc_list, precision_list, recall_list, percent_nonzero\n", + ")\n", "\n", "# plotting precision/recall histograms\n", "plot_pr_histograms(pred_list, y_list)" From 771c3f96aa1d22cebd9279211a68062fb8f9356c Mon Sep 17 00:00:00 2001 From: shreyasingh1 Date: Mon, 2 May 2022 23:34:35 -0400 Subject: [PATCH 09/29] commenting out napari, adding torch to requirements file --- .../pytorch_model/Pytorch Segmentation.ipynb | 26 ++++++++++++------- setup.py | 3 ++- 2 files changed, 18 insertions(+), 11 deletions(-) diff --git a/experiments/pytorch_model/Pytorch Segmentation.ipynb b/experiments/pytorch_model/Pytorch Segmentation.ipynb index b6c84d45c..eeebb4131 100644 --- a/experiments/pytorch_model/Pytorch Segmentation.ipynb +++ b/experiments/pytorch_model/Pytorch Segmentation.ipynb @@ -2,16 +2,23 @@ "cells": [ { "cell_type": "code", - "execution_count": 1, + "execution_count": 3, "id": "cd35537c", "metadata": {}, "outputs": [ { - "name": "stderr", - "output_type": "stream", - "text": [ - "/Users/shrey2/opt/anaconda3/envs/nd/lib/python3.9/site-packages/nilearn/datasets/__init__.py:93: FutureWarning: Fetchers from the nilearn.datasets module will be updated in version 0.9 to return python strings instead of bytes and Pandas dataframes instead of Numpy arrays.\n", - " warn(\"Fetchers from the nilearn.datasets module will be \"\n" + "ename": "ModuleNotFoundError", + "evalue": "No module named 'zarr'", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mModuleNotFoundError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0;32mfrom\u001b[0m \u001b[0mbrainlit\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mutils\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mcnn_segmentation\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0;34m*\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 2\u001b[0m \u001b[0;32mfrom\u001b[0m \u001b[0mbrainlit\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mutils\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mmake_masks\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 3\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 4\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mwarnings\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 5\u001b[0m \u001b[0mwarnings\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mfilterwarnings\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"ignore\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m~/Documents/NDD/brainlit/brainlit/__init__.py\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mwarnings\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 2\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 3\u001b[0;31m \u001b[0;32mimport\u001b[0m \u001b[0mbrainlit\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0malgorithms\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 4\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mbrainlit\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mcloudreg\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 5\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mbrainlit\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mfeature_extraction\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m~/Documents/NDD/brainlit/brainlit/algorithms/__init__.py\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0;32mfrom\u001b[0m \u001b[0mbrainlit\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0malgorithms\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mgenerate_fragments\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 2\u001b[0m \u001b[0;32mfrom\u001b[0m \u001b[0mbrainlit\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0malgorithms\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mgenerate_fragments\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0;34m*\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 3\u001b[0m \u001b[0;32mfrom\u001b[0m \u001b[0mbrainlit\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0malgorithms\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mconnect_fragments\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 4\u001b[0m \u001b[0;32mfrom\u001b[0m \u001b[0mbrainlit\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0malgorithms\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mconnect_fragments\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0;34m*\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 5\u001b[0m \u001b[0;32mfrom\u001b[0m \u001b[0mbrainlit\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0malgorithms\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mtrace_analysis\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m~/Documents/NDD/brainlit/brainlit/algorithms/generate_fragments/__init__.py\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[0;32mfrom\u001b[0m \u001b[0mbrainlit\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0malgorithms\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mgenerate_fragments\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mtube_seg\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0;34m*\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 2\u001b[0m \u001b[0;32mfrom\u001b[0m \u001b[0mbrainlit\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0malgorithms\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mgenerate_fragments\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0madaptive_thresh\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0;34m*\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 3\u001b[0;31m \u001b[0;32mfrom\u001b[0m \u001b[0mbrainlit\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0malgorithms\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mgenerate_fragments\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mstate_generation\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0;34m*\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 4\u001b[0m \u001b[0;32mfrom\u001b[0m \u001b[0mbrainlit\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0malgorithms\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mgenerate_fragments\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mpcurve\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0;34m*\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m~/Documents/NDD/brainlit/brainlit/algorithms/generate_fragments/state_generation.py\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0;32mimport\u001b[0m \u001b[0mzarr\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 2\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mnumpy\u001b[0m \u001b[0;32mas\u001b[0m \u001b[0mnp\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 3\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mh5py\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 4\u001b[0m \u001b[0;32mfrom\u001b[0m \u001b[0mjoblib\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mParallel\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mdelayed\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 5\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mos\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;31mModuleNotFoundError\u001b[0m: No module named 'zarr'" ] } ], @@ -20,7 +27,6 @@ "from brainlit.utils import make_masks\n", "\n", "import warnings\n", - "\n", "warnings.filterwarnings(\"ignore\")" ] }, @@ -575,13 +581,13 @@ }, { "cell_type": "code", - "execution_count": 14, + "execution_count": 2, "id": "1835b0b7", "metadata": {}, "outputs": [], "source": [ "# plotting with napari\n", - "plot_with_napari(x_list, pred_list, y_list)" + "# plot_with_napari(x_list, pred_list, y_list)" ] }, { @@ -595,7 +601,7 @@ ], "metadata": { "kernelspec": { - "display_name": "Python 3 (ipykernel)", + "display_name": "Python 3", "language": "python", "name": "python3" }, diff --git a/setup.py b/setup.py index 58ea9bebb..ac718c8df 100644 --- a/setup.py +++ b/setup.py @@ -28,7 +28,8 @@ "nibabel>=2.4.1", "nilearn>=0.5.2", "zarr>=2.10.2", -"h5py>=3.3.0" +"h5py>=3.3.0", +"torch>=1.9.1 ] From 43c335b41975674ab3bc310cee043f95da3eeb46 Mon Sep 17 00:00:00 2001 From: shreyasingh1 Date: Mon, 2 May 2022 23:37:26 -0400 Subject: [PATCH 10/29] bug in setup.py --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index ac718c8df..287c3c07d 100644 --- a/setup.py +++ b/setup.py @@ -29,7 +29,7 @@ "nilearn>=0.5.2", "zarr>=2.10.2", "h5py>=3.3.0", -"torch>=1.9.1 +"torch>=1.9.1" ] From 20d4e536fcc403f3bf200fb624e19c8ba1d09c76 Mon Sep 17 00:00:00 2001 From: shreyasingh1 Date: Tue, 3 May 2022 15:32:16 -0400 Subject: [PATCH 11/29] black --- .../pytorch_model/Pytorch Segmentation.ipynb | 21 +++---------------- 1 file changed, 3 insertions(+), 18 deletions(-) diff --git a/experiments/pytorch_model/Pytorch Segmentation.ipynb b/experiments/pytorch_model/Pytorch Segmentation.ipynb index eeebb4131..230aacace 100644 --- a/experiments/pytorch_model/Pytorch Segmentation.ipynb +++ b/experiments/pytorch_model/Pytorch Segmentation.ipynb @@ -2,31 +2,16 @@ "cells": [ { "cell_type": "code", - "execution_count": 3, + "execution_count": 4, "id": "cd35537c", "metadata": {}, - "outputs": [ - { - "ename": "ModuleNotFoundError", - "evalue": "No module named 'zarr'", - "output_type": "error", - "traceback": [ - "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[0;31mModuleNotFoundError\u001b[0m Traceback (most recent call last)", - "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0;32mfrom\u001b[0m \u001b[0mbrainlit\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mutils\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mcnn_segmentation\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0;34m*\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 2\u001b[0m \u001b[0;32mfrom\u001b[0m \u001b[0mbrainlit\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mutils\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mmake_masks\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 3\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 4\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mwarnings\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 5\u001b[0m \u001b[0mwarnings\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mfilterwarnings\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"ignore\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;32m~/Documents/NDD/brainlit/brainlit/__init__.py\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mwarnings\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 2\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 3\u001b[0;31m \u001b[0;32mimport\u001b[0m \u001b[0mbrainlit\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0malgorithms\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 4\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mbrainlit\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mcloudreg\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 5\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mbrainlit\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mfeature_extraction\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;32m~/Documents/NDD/brainlit/brainlit/algorithms/__init__.py\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0;32mfrom\u001b[0m \u001b[0mbrainlit\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0malgorithms\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mgenerate_fragments\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 2\u001b[0m \u001b[0;32mfrom\u001b[0m \u001b[0mbrainlit\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0malgorithms\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mgenerate_fragments\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0;34m*\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 3\u001b[0m \u001b[0;32mfrom\u001b[0m \u001b[0mbrainlit\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0malgorithms\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mconnect_fragments\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 4\u001b[0m \u001b[0;32mfrom\u001b[0m \u001b[0mbrainlit\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0malgorithms\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mconnect_fragments\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0;34m*\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 5\u001b[0m \u001b[0;32mfrom\u001b[0m \u001b[0mbrainlit\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0malgorithms\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mtrace_analysis\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;32m~/Documents/NDD/brainlit/brainlit/algorithms/generate_fragments/__init__.py\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[0;32mfrom\u001b[0m \u001b[0mbrainlit\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0malgorithms\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mgenerate_fragments\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mtube_seg\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0;34m*\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 2\u001b[0m \u001b[0;32mfrom\u001b[0m \u001b[0mbrainlit\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0malgorithms\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mgenerate_fragments\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0madaptive_thresh\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0;34m*\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 3\u001b[0;31m \u001b[0;32mfrom\u001b[0m \u001b[0mbrainlit\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0malgorithms\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mgenerate_fragments\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mstate_generation\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0;34m*\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 4\u001b[0m \u001b[0;32mfrom\u001b[0m \u001b[0mbrainlit\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0malgorithms\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mgenerate_fragments\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mpcurve\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0;34m*\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;32m~/Documents/NDD/brainlit/brainlit/algorithms/generate_fragments/state_generation.py\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0;32mimport\u001b[0m \u001b[0mzarr\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 2\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mnumpy\u001b[0m \u001b[0;32mas\u001b[0m \u001b[0mnp\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 3\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mh5py\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 4\u001b[0m \u001b[0;32mfrom\u001b[0m \u001b[0mjoblib\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mParallel\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mdelayed\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 5\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mos\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;31mModuleNotFoundError\u001b[0m: No module named 'zarr'" - ] - } - ], + "outputs": [], "source": [ "from brainlit.utils.cnn_segmentation import *\n", "from brainlit.utils import make_masks\n", "\n", "import warnings\n", + "\n", "warnings.filterwarnings(\"ignore\")" ] }, From a5fe493545e7b7da278265b45497b61238ffa877 Mon Sep 17 00:00:00 2001 From: shreyasingh1 Date: Tue, 10 May 2022 03:20:13 -0400 Subject: [PATCH 12/29] add tests for preprocess.py and performance.py --- brainlit/utils/cnn_segmentation/__init__.py | 2 - .../utils/cnn_segmentation/performance.py | 102 +++++++++++------- brainlit/utils/cnn_segmentation/preprocess.py | 69 ++++++------ .../tests/test_performance.py | 34 ++++++ .../cnn_segmentation/tests/test_preprocess.py | 72 +++++++++++++ brainlit/utils/make_masks.py | 7 ++ 6 files changed, 211 insertions(+), 75 deletions(-) create mode 100644 brainlit/utils/cnn_segmentation/tests/test_performance.py create mode 100644 brainlit/utils/cnn_segmentation/tests/test_preprocess.py diff --git a/brainlit/utils/cnn_segmentation/__init__.py b/brainlit/utils/cnn_segmentation/__init__.py index 6ea708b21..10f095d1e 100644 --- a/brainlit/utils/cnn_segmentation/__init__.py +++ b/brainlit/utils/cnn_segmentation/__init__.py @@ -1,6 +1,4 @@ import brainlit.utils.cnn_segmentation -from brainlit.utils.cnn_segmentation import * - from brainlit.utils.cnn_segmentation.preprocess import * from brainlit.utils.cnn_segmentation.performance import * diff --git a/brainlit/utils/cnn_segmentation/performance.py b/brainlit/utils/cnn_segmentation/performance.py index 85a56e45a..a783d65ac 100644 --- a/brainlit/utils/cnn_segmentation/performance.py +++ b/brainlit/utils/cnn_segmentation/performance.py @@ -13,13 +13,14 @@ precision_recall_curve, ) -# INPUT -# train_dataloader -# NN model defined locally -# loss fn class -# name of optimizer def train_loop(dataloader, model, loss_fn, optimizer): - + """Pytorch model training loop + Args: + train_dataloader: torch object from getting_torch_objects function in preprocess.py + model: pytorch model, defined locally + loss_fn: loss_fn class name, ex: BCELoss, Dice + optimizer: name of optimizer, ex. Adam, SGD, etc. + """ for batch, (X_all, y_all) in enumerate(dataloader): loss_list = [] @@ -41,11 +42,18 @@ def train_loop(dataloader, model, loss_fn, optimizer): loss_list.append(loss) -# INPUT -# test_dataloader -# model defined locally -# loss_fn def test_loop(dataloader, model, loss_fn): + """Pytorch model testing loop + Args: + test_dataloader: torch object from getting_torch_objects function in preprocess.py + model: pytorch model, defined locally + loss_fn: loss_fn class name, ex: BCELoss, Dice + Returns: + x_list: list, true images + y_pred: nested list, model predictions for each image at each epoch + y_list: nested list, true masks for each image at each epoch + avg_loss: list, average loss at each epoch + """ for batch, (X_all, y_all) in enumerate(dataloader): loss_list = [] @@ -88,13 +96,17 @@ def forward(self, inputs, targets, smooth=1): return 1 - dice -# getting accuracy, precision, recall at each epoch -# INPUT -# pred_list, list of predictions for every image at every epoch -# y_list, list of true y masks -# OUTPUT -# lists for avg accuracy, precision, recall, and percent_nonzero at each epoch def get_metrics(pred_list, y_list): + """Getting accuracy, precision, and recall at each epoch + Args: + pred_list: list of predictions for every image at every epoch, output of testing loop + y_list: list of true y masks, output of testing loop + Returns: + acc_list: list of average accuracy for each epoch + precision_list: list of average precision for each epoch + recall_list: list of average recall for each epoch + percent_nonzero: list of percent of nonzero predictions at each epoch + """ acc_list = [] precision_list = [] recall_list = [] @@ -135,13 +147,17 @@ def get_metrics(pred_list, y_list): return acc_list, precision_list, recall_list, percent_nonzero -# Quick test stats -# INPUT -# stat = "all" for all stats -# acc_list, precision_list, recall_list, and percent_nonzero from get_metrics function -# OUTPUT -# printed metrics for specified epoch def quick_stats(stat, epoch, acc_list, precision_list, recall_list, percent_nonzero): + """Printing quick test stats at specified epoch + Args: + stat: str, "all" if you want to print all metrics (accuracy, precision, reacll, % nonzero) + acc_list: list of average accuracy for each epoch, from get_metrics function + precision_list: list of average precision for each epoch, from get_metrics function + recall_list: list of average recall for each epoch, from get_metrics function + percent_nonzero: list of percent of nonzero predictions at each epoch, from get_metrics function + Returns: + Printed metrics for specified epoch + """ if stat == "accuracy": print("Accuracy at epoch " + str(epoch) + " is " + str(acc_list[epoch - 1])) if stat == "all": @@ -157,15 +173,19 @@ def quick_stats(stat, epoch, acc_list, precision_list, recall_list, percent_nonz + str(percent_nonzero[epoch - 1]) ) - -# INPUT -# loss list, list of test loss/any loss at each epoch -# acc_list, precision_list, recall_list, and percent_nonzero from get_metrics function -# OUTPUT -# plotted figures def plot_metrics_over_epoch( loss_list, acc_list, precision_list, recall_list, percent_nonzero ): + """Plotting all metrics over epoch + Args: + loss_list: list of test loss over epoch + acc_list: list of average accuracy for each epoch, from get_metrics function + precision_list: list of average precision for each epoch, from get_metrics function + recall_list: list of average recall for each epoch, from get_metrics function + percent_nonzero: list of percent of nonzero predictions at each epoch, from get_metrics function + Returns: + Plotted figures for accuracy, precision, recall, % nonzero, and loss over epoch + """ plt.figure() plt.title("Test loss over epoch") plt.xlabel("Epoch") @@ -197,12 +217,14 @@ def plot_metrics_over_epoch( plt.plot(percent_nonzero) -# INPUT -# pred_list, y_list -# OUPTUT -# precision and recall plots for all images at last epoch def plot_pr_histograms(pred_list, y_list): - + """Plotting histograms for precision and recall at final epoch + Args: + pred_list: list of predictions for all images at last epoch + y_list: lost of true y masks for all images at last epoch + Returns: + Precision and recall plots for all images at last epoch + """ i = len(pred_list) - 1 precision_list_t = [] recall_list_t = [] @@ -230,13 +252,15 @@ def plot_pr_histograms(pred_list, y_list): plt.hist(recall_list_t, bins=20) -# INPUT -# x_list, list of all x images from testing loop -# pred_list, list of testing predictions -# y_list, list of testing y values -# OUTPUT -# visualizations in napari def plot_with_napari(x_list, pred_list, y_list): + """Plotting all test images at an epoch in napari + Args: + x_list: list of all x images from testing loop + pred_list: list of all testing predictions at an epoch + y_list: list of true ground truth masks at that same epoch + Returns: + Visualizations of napari image, ground truth mask, and thresholded prediction mask + """ for i in range(len(y_list[len(y_list) - 1])): x = x_list[i].clone()[:, 0].numpy() pred = pred_list[len(pred_list) - 1][i].clone()[:, 0].numpy() diff --git a/brainlit/utils/cnn_segmentation/preprocess.py b/brainlit/utils/cnn_segmentation/preprocess.py index 9e49397fa..467e7fe2d 100644 --- a/brainlit/utils/cnn_segmentation/preprocess.py +++ b/brainlit/utils/cnn_segmentation/preprocess.py @@ -9,12 +9,14 @@ from torch.utils.data import DataLoader -# INPUT -# data_dir = str, path to tif and mask files -# OUTPUT -# X_img = list of 3d np array images -# y_mask = list of 3d np array masks def get_img_and_mask(data_dir): + """Get lists of tif images and associated ground truth masks + Args: + data_dir: str, path to tif and mask files + Returns: + X_img: list of 3d np array images + y_mask: list of 3d np array masks + """ im_dir = Path(os.path.join(data_dir, "sample-tif-location")) gfp_files = list(im_dir.glob("**/*-gfp.tif")) X_img = [] @@ -56,15 +58,14 @@ def get_img_and_mask(data_dir): return X_img, y_mask -# Train/test/split -# INPUT -# X_img = list of 3d np array images -# y_mask = list of 3d np array masks -# test_percent = % of data in test set, default = 0.25 -# OUTPUT -# X_train, y_train, X_test, y_test = lists of specified -# training and testing size def train_test_split(X_img, y_mask, test_percent=0.25): + """Get train/test/split of images and masks + Args: + X_img: list of 3d np array images + y_mask: list of 3d np array masks + Returns: + X_train, y_train, X_test, y_test: lists of specifie training and testing size + """ num_images = len(X_img) test_images = num_images * test_percent train_images = int(num_images - test_images) @@ -78,26 +79,21 @@ def train_test_split(X_img, y_mask, test_percent=0.25): return X_train, y_train, X_test, y_test -# get subvolumes for training set -# INPUT -# X_train, y_train from train_test_split function -# x_dim, int, x_dim of subvolume, must be divisible by image shape -# y_dim, int, y_dim of subvolume, must be divisible by image shape -# z_dim, int, z_dim of subvolume, must be divisible by image shape -# OUTPUT -# X_train_subvolume, y_train_subvolume, lists of subvolumes for training def get_subvolumes(X_train, y_train, x_dim, y_dim, z_dim): + """Get subvolumes of specified site for training dataset + Args: + X_train: list of imgs, from train_test_split function + y_train: list of masks, from train_test_split function + x_dim: int, x_dim of subvolume, must be divisible by image shape + y_dim: int, y_dim of subvolume, must be divisible by image shape + z_dim: int, z_dim of subvolume, must be divisible by image shape + Returns: + X_train_subvolume: list of image subvolumes for training + y_train_subvolume: list of associated mask subvolumes for training + """ X_train_subvolumes = [] y_train_subvolumes = [] - # check to see if x_dim, y_dim, and z_dim are even units of input image - if X_train[0].shape[0] % x_dim != 0: - print("note: inputted x_dim is not evenly divisible by image") - if X_train[0].shape[1] % y_dim != 0: - print("note: inputted y_dim is not evenly divisible by image") - if X_train[0].shape[2] % z_dim != 0: - print("note: inputted z_dim is not evenly divisible by image") - # getting subvolumes for image in X_train: i = 0 @@ -128,12 +124,17 @@ def get_subvolumes(X_train, y_train, x_dim, y_dim, z_dim): return X_train_subvolumes, y_train_subvolumes -# INPUT -# X_train_subvolumes, y_train_subvolumes, X_test, y_test -# OUTPUT -# train_dataloader, torch object -# test_dataloader, torch object def getting_torch_objects(X_train_subvolumes, y_train_subvolumes, X_test, y_test): + """Get training data in torch object format + Args: + X_train_subvolumes: list, training images (or subvolumes) from get_subvolumes function + y_train_subvolumes: list, trianing masks (or subvolumes) from get_subvolumes function + X_test: list, testing images from train_test_split function + y_test: list, testing masks from train_test_split function + Returns: + X_train_subvolume: list of image subvolumes for training + y_train_subvolume: list of associated mask subvolumes for training + """ x_dim = X_train_subvolumes[0].shape[0] y_dim = X_train_subvolumes[0].shape[1] z_dim = X_train_subvolumes[0].shape[2] diff --git a/brainlit/utils/cnn_segmentation/tests/test_performance.py b/brainlit/utils/cnn_segmentation/tests/test_performance.py new file mode 100644 index 000000000..7d9140a2a --- /dev/null +++ b/brainlit/utils/cnn_segmentation/tests/test_performance.py @@ -0,0 +1,34 @@ + +import pytest + +import numpy as np +import torch + +from brainlit.utils.cnn_segmentation import performance +from numpy.testing import ( + assert_array_equal, +) + +############################ +### functionality checks ### +############################ + +def test_get_metrics(): + pred_list = [torch.from_numpy(np.zeros(shape=(4, 4, 4))), torch.from_numpy(np.ones(shape=(4, 4, 4)))] + y_list = [torch.from_numpy(np.ones(shape=(4, 4, 4))), torch.from_numpy(np.ones(shape=(4, 4, 4)))] + + acc_list, precision_list, recall_list, percent_nonzero = performance.get_metrics(pred_list, y_list) + + acc_true = [0.0, 100.0] + precision_true = [0.0, 100.0] + recall_true = [0.0, 100.0] + percent_nonzero_true = [0.0, 100.0] + + assert_array_equal(acc_list, acc_true) + assert_array_equal(precision_list, precision_true) + assert_array_equal(recall_list, recall_true) + assert_array_equal(percent_nonzero, percent_nonzero_true) + + + + diff --git a/brainlit/utils/cnn_segmentation/tests/test_preprocess.py b/brainlit/utils/cnn_segmentation/tests/test_preprocess.py new file mode 100644 index 000000000..d683190d0 --- /dev/null +++ b/brainlit/utils/cnn_segmentation/tests/test_preprocess.py @@ -0,0 +1,72 @@ +import pytest + +import numpy as np +from brainlit.utils.cnn_segmentation import preprocess +from numpy.testing import ( + assert_array_equal, +) + +############################ +### functionality checks ### +############################ + +def test_train_test_split(): + X_img = [0, 1, 2, 3] + y_mask = [0.0, 1.1, 2.2, 3.3] + + + X_train, y_train, X_test, y_test = preprocess.train_test_split(X_img, y_mask) + + X_train_true = [0, 1, 2] + y_train_true = [0.0, 1.1, 2.2] + X_test_true = [3] + y_test_true = [3.3] + + assert_array_equal(X_train, X_train_true) + assert_array_equal(y_train, y_train_true) + assert_array_equal(X_test, X_test_true) + assert_array_equal(y_test, y_test_true) + + +def test_get_subvolumes(): + X_train = [np.zeros(shape=(4, 4, 4))] + y_train = [np.ones(shape=(4, 4, 4))] + + x_dim = 2 + y_dim = 2 + z_dim = 2 + + X_train_subvolumes, y_train_subvolumes = preprocess.get_subvolumes(X_train, y_train, x_dim, y_dim, z_dim) + + X_train_subvolumes_true = [np.zeros(shape=(2, 2, 2)), np.zeros(shape=(2, 2, 2)), np.zeros(shape=(2, 2, 2)), + np.zeros(shape=(2, 2, 2)), np.zeros(shape=(2, 2, 2)), np.zeros(shape=(2, 2, 2)), + np.zeros(shape=(2, 2, 2)), np.zeros(shape=(2, 2, 2))] + + y_train_subvolumes_true = [np.ones(shape=(2, 2, 2)), np.ones(shape=(2, 2, 2)), np.ones(shape=(2, 2, 2)), + np.ones(shape=(2, 2, 2)), np.ones(shape=(2, 2, 2)), np.ones(shape=(2, 2, 2)), + np.ones(shape=(2, 2, 2)), np.ones(shape=(2, 2, 2))] + + assert_array_equal(X_train_subvolumes[0], X_train_subvolumes_true[0]) + assert_array_equal(y_train_subvolumes[0], y_train_subvolumes_true[0]) + + +def test_getting_torch_objects(): + X_train = [np.zeros(shape=(4, 4, 4))] + y_train = [np.ones(shape=(4, 4, 4))] + X_test = [np.zeros(shape=(4, 4, 4))] + y_test = [np.ones(shape=(4, 4, 4))] + + train_dataloader, test_dataloader = preprocess.getting_torch_objects(X_train, y_train, X_test, y_test) + + train_dataloader_size = [2, 1, 1, 4, 4, 4] + test_dataloader_size = [2, 1, 1, 4, 4, 4] + + assert_array_equal(list(next(iter(train_dataloader)).size()), train_dataloader_size) + assert_array_equal(list(next(iter(test_dataloader)).size()), test_dataloader_size) + + + + + + + diff --git a/brainlit/utils/make_masks.py b/brainlit/utils/make_masks.py index b7fa3e74a..c6bfb7b82 100644 --- a/brainlit/utils/make_masks.py +++ b/brainlit/utils/make_masks.py @@ -14,6 +14,13 @@ def make_masks(data_dir): + """Swc to numpy mask + Args: + data_dir: direction to base data folder that download_benchmarking points to. + Should contain sample-tif-location and sample-swc-location + Returns: + Saved numpy masks in data-dir/mask-location for each image in sample-tif-location + """ im_dir = Path(os.path.join(data_dir, "sample-tif-location")) swc_dir = Path(os.path.join(data_dir, "sample-swc-location")) mask_dir = os.path.join(data_dir, "mask-location") From 8d1ea9bf3ba40557d5bfdc3e9ba039d81bea2ce9 Mon Sep 17 00:00:00 2001 From: shreyasingh1 Date: Tue, 10 May 2022 03:28:11 -0400 Subject: [PATCH 13/29] black --- .../utils/cnn_segmentation/performance.py | 100 +++++++++--------- brainlit/utils/cnn_segmentation/preprocess.py | 54 +++++----- .../tests/test_performance.py | 24 +++-- .../cnn_segmentation/tests/test_preprocess.py | 51 +++++---- brainlit/utils/make_masks.py | 10 +- 5 files changed, 128 insertions(+), 111 deletions(-) diff --git a/brainlit/utils/cnn_segmentation/performance.py b/brainlit/utils/cnn_segmentation/performance.py index a783d65ac..03713cf6c 100644 --- a/brainlit/utils/cnn_segmentation/performance.py +++ b/brainlit/utils/cnn_segmentation/performance.py @@ -13,13 +13,14 @@ precision_recall_curve, ) + def train_loop(dataloader, model, loss_fn, optimizer): """Pytorch model training loop - Args: - train_dataloader: torch object from getting_torch_objects function in preprocess.py - model: pytorch model, defined locally - loss_fn: loss_fn class name, ex: BCELoss, Dice - optimizer: name of optimizer, ex. Adam, SGD, etc. + Args: + train_dataloader: torch object from getting_torch_objects function in preprocess.py + model: pytorch model, defined locally + loss_fn: loss_fn class name, ex: BCELoss, Dice + optimizer: name of optimizer, ex. Adam, SGD, etc. """ for batch, (X_all, y_all) in enumerate(dataloader): @@ -44,15 +45,15 @@ def train_loop(dataloader, model, loss_fn, optimizer): def test_loop(dataloader, model, loss_fn): """Pytorch model testing loop - Args: - test_dataloader: torch object from getting_torch_objects function in preprocess.py - model: pytorch model, defined locally - loss_fn: loss_fn class name, ex: BCELoss, Dice - Returns: - x_list: list, true images - y_pred: nested list, model predictions for each image at each epoch - y_list: nested list, true masks for each image at each epoch - avg_loss: list, average loss at each epoch + Args: + test_dataloader: torch object from getting_torch_objects function in preprocess.py + model: pytorch model, defined locally + loss_fn: loss_fn class name, ex: BCELoss, Dice + Returns: + x_list: list, true images + y_pred: nested list, model predictions for each image at each epoch + y_list: nested list, true masks for each image at each epoch + avg_loss: list, average loss at each epoch """ for batch, (X_all, y_all) in enumerate(dataloader): @@ -98,14 +99,14 @@ def forward(self, inputs, targets, smooth=1): def get_metrics(pred_list, y_list): """Getting accuracy, precision, and recall at each epoch - Args: - pred_list: list of predictions for every image at every epoch, output of testing loop - y_list: list of true y masks, output of testing loop - Returns: - acc_list: list of average accuracy for each epoch - precision_list: list of average precision for each epoch - recall_list: list of average recall for each epoch - percent_nonzero: list of percent of nonzero predictions at each epoch + Args: + pred_list: list of predictions for every image at every epoch, output of testing loop + y_list: list of true y masks, output of testing loop + Returns: + acc_list: list of average accuracy for each epoch + precision_list: list of average precision for each epoch + recall_list: list of average recall for each epoch + percent_nonzero: list of percent of nonzero predictions at each epoch """ acc_list = [] precision_list = [] @@ -149,14 +150,14 @@ def get_metrics(pred_list, y_list): def quick_stats(stat, epoch, acc_list, precision_list, recall_list, percent_nonzero): """Printing quick test stats at specified epoch - Args: - stat: str, "all" if you want to print all metrics (accuracy, precision, reacll, % nonzero) - acc_list: list of average accuracy for each epoch, from get_metrics function - precision_list: list of average precision for each epoch, from get_metrics function - recall_list: list of average recall for each epoch, from get_metrics function - percent_nonzero: list of percent of nonzero predictions at each epoch, from get_metrics function - Returns: - Printed metrics for specified epoch + Args: + stat: str, "all" if you want to print all metrics (accuracy, precision, reacll, % nonzero) + acc_list: list of average accuracy for each epoch, from get_metrics function + precision_list: list of average precision for each epoch, from get_metrics function + recall_list: list of average recall for each epoch, from get_metrics function + percent_nonzero: list of percent of nonzero predictions at each epoch, from get_metrics function + Returns: + Printed metrics for specified epoch """ if stat == "accuracy": print("Accuracy at epoch " + str(epoch) + " is " + str(acc_list[epoch - 1])) @@ -173,18 +174,19 @@ def quick_stats(stat, epoch, acc_list, precision_list, recall_list, percent_nonz + str(percent_nonzero[epoch - 1]) ) + def plot_metrics_over_epoch( loss_list, acc_list, precision_list, recall_list, percent_nonzero ): """Plotting all metrics over epoch - Args: - loss_list: list of test loss over epoch - acc_list: list of average accuracy for each epoch, from get_metrics function - precision_list: list of average precision for each epoch, from get_metrics function - recall_list: list of average recall for each epoch, from get_metrics function - percent_nonzero: list of percent of nonzero predictions at each epoch, from get_metrics function - Returns: - Plotted figures for accuracy, precision, recall, % nonzero, and loss over epoch + Args: + loss_list: list of test loss over epoch + acc_list: list of average accuracy for each epoch, from get_metrics function + precision_list: list of average precision for each epoch, from get_metrics function + recall_list: list of average recall for each epoch, from get_metrics function + percent_nonzero: list of percent of nonzero predictions at each epoch, from get_metrics function + Returns: + Plotted figures for accuracy, precision, recall, % nonzero, and loss over epoch """ plt.figure() plt.title("Test loss over epoch") @@ -219,11 +221,11 @@ def plot_metrics_over_epoch( def plot_pr_histograms(pred_list, y_list): """Plotting histograms for precision and recall at final epoch - Args: - pred_list: list of predictions for all images at last epoch - y_list: lost of true y masks for all images at last epoch - Returns: - Precision and recall plots for all images at last epoch + Args: + pred_list: list of predictions for all images at last epoch + y_list: lost of true y masks for all images at last epoch + Returns: + Precision and recall plots for all images at last epoch """ i = len(pred_list) - 1 precision_list_t = [] @@ -254,12 +256,12 @@ def plot_pr_histograms(pred_list, y_list): def plot_with_napari(x_list, pred_list, y_list): """Plotting all test images at an epoch in napari - Args: - x_list: list of all x images from testing loop - pred_list: list of all testing predictions at an epoch - y_list: list of true ground truth masks at that same epoch - Returns: - Visualizations of napari image, ground truth mask, and thresholded prediction mask + Args: + x_list: list of all x images from testing loop + pred_list: list of all testing predictions at an epoch + y_list: list of true ground truth masks at that same epoch + Returns: + Visualizations of napari image, ground truth mask, and thresholded prediction mask """ for i in range(len(y_list[len(y_list) - 1])): x = x_list[i].clone()[:, 0].numpy() diff --git a/brainlit/utils/cnn_segmentation/preprocess.py b/brainlit/utils/cnn_segmentation/preprocess.py index 467e7fe2d..12b642699 100644 --- a/brainlit/utils/cnn_segmentation/preprocess.py +++ b/brainlit/utils/cnn_segmentation/preprocess.py @@ -11,11 +11,11 @@ def get_img_and_mask(data_dir): """Get lists of tif images and associated ground truth masks - Args: - data_dir: str, path to tif and mask files - Returns: - X_img: list of 3d np array images - y_mask: list of 3d np array masks + Args: + data_dir: str, path to tif and mask files + Returns: + X_img: list of 3d np array images + y_mask: list of 3d np array masks """ im_dir = Path(os.path.join(data_dir, "sample-tif-location")) gfp_files = list(im_dir.glob("**/*-gfp.tif")) @@ -60,11 +60,11 @@ def get_img_and_mask(data_dir): def train_test_split(X_img, y_mask, test_percent=0.25): """Get train/test/split of images and masks - Args: - X_img: list of 3d np array images - y_mask: list of 3d np array masks - Returns: - X_train, y_train, X_test, y_test: lists of specifie training and testing size + Args: + X_img: list of 3d np array images + y_mask: list of 3d np array masks + Returns: + X_train, y_train, X_test, y_test: lists of specifie training and testing size """ num_images = len(X_img) test_images = num_images * test_percent @@ -81,15 +81,15 @@ def train_test_split(X_img, y_mask, test_percent=0.25): def get_subvolumes(X_train, y_train, x_dim, y_dim, z_dim): """Get subvolumes of specified site for training dataset - Args: - X_train: list of imgs, from train_test_split function - y_train: list of masks, from train_test_split function - x_dim: int, x_dim of subvolume, must be divisible by image shape - y_dim: int, y_dim of subvolume, must be divisible by image shape - z_dim: int, z_dim of subvolume, must be divisible by image shape - Returns: - X_train_subvolume: list of image subvolumes for training - y_train_subvolume: list of associated mask subvolumes for training + Args: + X_train: list of imgs, from train_test_split function + y_train: list of masks, from train_test_split function + x_dim: int, x_dim of subvolume, must be divisible by image shape + y_dim: int, y_dim of subvolume, must be divisible by image shape + z_dim: int, z_dim of subvolume, must be divisible by image shape + Returns: + X_train_subvolume: list of image subvolumes for training + y_train_subvolume: list of associated mask subvolumes for training """ X_train_subvolumes = [] y_train_subvolumes = [] @@ -126,14 +126,14 @@ def get_subvolumes(X_train, y_train, x_dim, y_dim, z_dim): def getting_torch_objects(X_train_subvolumes, y_train_subvolumes, X_test, y_test): """Get training data in torch object format - Args: - X_train_subvolumes: list, training images (or subvolumes) from get_subvolumes function - y_train_subvolumes: list, trianing masks (or subvolumes) from get_subvolumes function - X_test: list, testing images from train_test_split function - y_test: list, testing masks from train_test_split function - Returns: - X_train_subvolume: list of image subvolumes for training - y_train_subvolume: list of associated mask subvolumes for training + Args: + X_train_subvolumes: list, training images (or subvolumes) from get_subvolumes function + y_train_subvolumes: list, trianing masks (or subvolumes) from get_subvolumes function + X_test: list, testing images from train_test_split function + y_test: list, testing masks from train_test_split function + Returns: + X_train_subvolume: list of image subvolumes for training + y_train_subvolume: list of associated mask subvolumes for training """ x_dim = X_train_subvolumes[0].shape[0] y_dim = X_train_subvolumes[0].shape[1] diff --git a/brainlit/utils/cnn_segmentation/tests/test_performance.py b/brainlit/utils/cnn_segmentation/tests/test_performance.py index 7d9140a2a..cfbe3c805 100644 --- a/brainlit/utils/cnn_segmentation/tests/test_performance.py +++ b/brainlit/utils/cnn_segmentation/tests/test_performance.py @@ -1,4 +1,3 @@ - import pytest import numpy as np @@ -13,22 +12,27 @@ ### functionality checks ### ############################ + def test_get_metrics(): - pred_list = [torch.from_numpy(np.zeros(shape=(4, 4, 4))), torch.from_numpy(np.ones(shape=(4, 4, 4)))] - y_list = [torch.from_numpy(np.ones(shape=(4, 4, 4))), torch.from_numpy(np.ones(shape=(4, 4, 4)))] + pred_list = [ + torch.from_numpy(np.zeros(shape=(4, 4, 4))), + torch.from_numpy(np.ones(shape=(4, 4, 4))), + ] + y_list = [ + torch.from_numpy(np.ones(shape=(4, 4, 4))), + torch.from_numpy(np.ones(shape=(4, 4, 4))), + ] + + acc_list, precision_list, recall_list, percent_nonzero = performance.get_metrics( + pred_list, y_list + ) - acc_list, precision_list, recall_list, percent_nonzero = performance.get_metrics(pred_list, y_list) - acc_true = [0.0, 100.0] precision_true = [0.0, 100.0] recall_true = [0.0, 100.0] percent_nonzero_true = [0.0, 100.0] - + assert_array_equal(acc_list, acc_true) assert_array_equal(precision_list, precision_true) assert_array_equal(recall_list, recall_true) assert_array_equal(percent_nonzero, percent_nonzero_true) - - - - diff --git a/brainlit/utils/cnn_segmentation/tests/test_preprocess.py b/brainlit/utils/cnn_segmentation/tests/test_preprocess.py index d683190d0..f0f2c8a38 100644 --- a/brainlit/utils/cnn_segmentation/tests/test_preprocess.py +++ b/brainlit/utils/cnn_segmentation/tests/test_preprocess.py @@ -10,11 +10,11 @@ ### functionality checks ### ############################ + def test_train_test_split(): X_img = [0, 1, 2, 3] y_mask = [0.0, 1.1, 2.2, 3.3] - X_train, y_train, X_test, y_test = preprocess.train_test_split(X_img, y_mask) X_train_true = [0, 1, 2] @@ -36,37 +36,48 @@ def test_get_subvolumes(): y_dim = 2 z_dim = 2 - X_train_subvolumes, y_train_subvolumes = preprocess.get_subvolumes(X_train, y_train, x_dim, y_dim, z_dim) - - X_train_subvolumes_true = [np.zeros(shape=(2, 2, 2)), np.zeros(shape=(2, 2, 2)), np.zeros(shape=(2, 2, 2)), - np.zeros(shape=(2, 2, 2)), np.zeros(shape=(2, 2, 2)), np.zeros(shape=(2, 2, 2)), - np.zeros(shape=(2, 2, 2)), np.zeros(shape=(2, 2, 2))] - - y_train_subvolumes_true = [np.ones(shape=(2, 2, 2)), np.ones(shape=(2, 2, 2)), np.ones(shape=(2, 2, 2)), - np.ones(shape=(2, 2, 2)), np.ones(shape=(2, 2, 2)), np.ones(shape=(2, 2, 2)), - np.ones(shape=(2, 2, 2)), np.ones(shape=(2, 2, 2))] + X_train_subvolumes, y_train_subvolumes = preprocess.get_subvolumes( + X_train, y_train, x_dim, y_dim, z_dim + ) + + X_train_subvolumes_true = [ + np.zeros(shape=(2, 2, 2)), + np.zeros(shape=(2, 2, 2)), + np.zeros(shape=(2, 2, 2)), + np.zeros(shape=(2, 2, 2)), + np.zeros(shape=(2, 2, 2)), + np.zeros(shape=(2, 2, 2)), + np.zeros(shape=(2, 2, 2)), + np.zeros(shape=(2, 2, 2)), + ] + + y_train_subvolumes_true = [ + np.ones(shape=(2, 2, 2)), + np.ones(shape=(2, 2, 2)), + np.ones(shape=(2, 2, 2)), + np.ones(shape=(2, 2, 2)), + np.ones(shape=(2, 2, 2)), + np.ones(shape=(2, 2, 2)), + np.ones(shape=(2, 2, 2)), + np.ones(shape=(2, 2, 2)), + ] assert_array_equal(X_train_subvolumes[0], X_train_subvolumes_true[0]) assert_array_equal(y_train_subvolumes[0], y_train_subvolumes_true[0]) - - + + def test_getting_torch_objects(): X_train = [np.zeros(shape=(4, 4, 4))] y_train = [np.ones(shape=(4, 4, 4))] X_test = [np.zeros(shape=(4, 4, 4))] y_test = [np.ones(shape=(4, 4, 4))] - train_dataloader, test_dataloader = preprocess.getting_torch_objects(X_train, y_train, X_test, y_test) + train_dataloader, test_dataloader = preprocess.getting_torch_objects( + X_train, y_train, X_test, y_test + ) train_dataloader_size = [2, 1, 1, 4, 4, 4] test_dataloader_size = [2, 1, 1, 4, 4, 4] assert_array_equal(list(next(iter(train_dataloader)).size()), train_dataloader_size) assert_array_equal(list(next(iter(test_dataloader)).size()), test_dataloader_size) - - - - - - - diff --git a/brainlit/utils/make_masks.py b/brainlit/utils/make_masks.py index c6bfb7b82..839a63cf7 100644 --- a/brainlit/utils/make_masks.py +++ b/brainlit/utils/make_masks.py @@ -15,11 +15,11 @@ def make_masks(data_dir): """Swc to numpy mask - Args: - data_dir: direction to base data folder that download_benchmarking points to. - Should contain sample-tif-location and sample-swc-location - Returns: - Saved numpy masks in data-dir/mask-location for each image in sample-tif-location + Args: + data_dir: direction to base data folder that download_benchmarking points to. + Should contain sample-tif-location and sample-swc-location + Returns: + Saved numpy masks in data-dir/mask-location for each image in sample-tif-location """ im_dir = Path(os.path.join(data_dir, "sample-tif-location")) swc_dir = Path(os.path.join(data_dir, "sample-swc-location")) From f6d522e344cdf2b591c038fb37e274c9dd142575 Mon Sep 17 00:00:00 2001 From: shreyasingh1 <40285923+shreyasingh1@users.noreply.github.com> Date: Tue, 10 May 2022 03:28:35 -0400 Subject: [PATCH 14/29] commenting out utils.rst changes --- docs/reference/utils.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/reference/utils.rst b/docs/reference/utils.rst index c6ac7f732..fc1a5e8b2 100644 --- a/docs/reference/utils.rst +++ b/docs/reference/utils.rst @@ -12,7 +12,7 @@ Data Helper Methods .. autoapiclass:: NeuronTrace :members: -.. autoapifunction:: make_masks +#.. autoapifunction:: make_masks .. currentmodule:: brainlit.utils.upload_to_neuroglancer @@ -32,5 +32,5 @@ S3 Helper Methods CNN Segmentation ------------------- -.. autoapifunction:: preprocess -.. autoapifunction:: performance +#.. autoapifunction:: preprocess +#.. autoapifunction:: performance From 20b4bc56d9f548b6e5fe8a9f09f82daf7d9aee19 Mon Sep 17 00:00:00 2001 From: shreyasingh1 Date: Tue, 10 May 2022 03:37:18 -0400 Subject: [PATCH 15/29] renaming test file --- .../cnn_segmentation/{performance.py => performance_cnn.py} | 0 .../tests/{test_performance.py => test_performance_cnn.py} | 0 brainlit/utils/cnn_segmentation/tests/test_preprocess.py | 2 +- 3 files changed, 1 insertion(+), 1 deletion(-) rename brainlit/utils/cnn_segmentation/{performance.py => performance_cnn.py} (100%) rename brainlit/utils/cnn_segmentation/tests/{test_performance.py => test_performance_cnn.py} (100%) diff --git a/brainlit/utils/cnn_segmentation/performance.py b/brainlit/utils/cnn_segmentation/performance_cnn.py similarity index 100% rename from brainlit/utils/cnn_segmentation/performance.py rename to brainlit/utils/cnn_segmentation/performance_cnn.py diff --git a/brainlit/utils/cnn_segmentation/tests/test_performance.py b/brainlit/utils/cnn_segmentation/tests/test_performance_cnn.py similarity index 100% rename from brainlit/utils/cnn_segmentation/tests/test_performance.py rename to brainlit/utils/cnn_segmentation/tests/test_performance_cnn.py diff --git a/brainlit/utils/cnn_segmentation/tests/test_preprocess.py b/brainlit/utils/cnn_segmentation/tests/test_preprocess.py index f0f2c8a38..d8227c8c8 100644 --- a/brainlit/utils/cnn_segmentation/tests/test_preprocess.py +++ b/brainlit/utils/cnn_segmentation/tests/test_preprocess.py @@ -1,7 +1,7 @@ import pytest import numpy as np -from brainlit.utils.cnn_segmentation import preprocess +from brainlit.utils.cnn_segmentation import preprocess_cnn from numpy.testing import ( assert_array_equal, ) From 3d30f5949857fdf5c21ad58c89abd22beb7cfc40 Mon Sep 17 00:00:00 2001 From: shreyasingh1 Date: Tue, 10 May 2022 03:45:55 -0400 Subject: [PATCH 16/29] fixing last bugs so it builds --- brainlit/utils/cnn_segmentation/tests/test_performance_cnn.py | 2 +- brainlit/utils/cnn_segmentation/tests/test_preprocess.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/brainlit/utils/cnn_segmentation/tests/test_performance_cnn.py b/brainlit/utils/cnn_segmentation/tests/test_performance_cnn.py index cfbe3c805..dc91c1f3f 100644 --- a/brainlit/utils/cnn_segmentation/tests/test_performance_cnn.py +++ b/brainlit/utils/cnn_segmentation/tests/test_performance_cnn.py @@ -3,7 +3,7 @@ import numpy as np import torch -from brainlit.utils.cnn_segmentation import performance +from brainlit.utils.cnn_segmentation import performance_cnn from numpy.testing import ( assert_array_equal, ) diff --git a/brainlit/utils/cnn_segmentation/tests/test_preprocess.py b/brainlit/utils/cnn_segmentation/tests/test_preprocess.py index d8227c8c8..f0f2c8a38 100644 --- a/brainlit/utils/cnn_segmentation/tests/test_preprocess.py +++ b/brainlit/utils/cnn_segmentation/tests/test_preprocess.py @@ -1,7 +1,7 @@ import pytest import numpy as np -from brainlit.utils.cnn_segmentation import preprocess_cnn +from brainlit.utils.cnn_segmentation import preprocess from numpy.testing import ( assert_array_equal, ) From 0ac085709e3901602b320a678fe084da268ba881 Mon Sep 17 00:00:00 2001 From: shreyasingh1 Date: Tue, 10 May 2022 03:50:51 -0400 Subject: [PATCH 17/29] labeling bug --- brainlit/utils/cnn_segmentation/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/brainlit/utils/cnn_segmentation/__init__.py b/brainlit/utils/cnn_segmentation/__init__.py index 10f095d1e..3e1d7e78e 100644 --- a/brainlit/utils/cnn_segmentation/__init__.py +++ b/brainlit/utils/cnn_segmentation/__init__.py @@ -1,4 +1,4 @@ import brainlit.utils.cnn_segmentation from brainlit.utils.cnn_segmentation.preprocess import * -from brainlit.utils.cnn_segmentation.performance import * +from brainlit.utils.cnn_segmentation.performance_cnn import * From d576a9d89d3acc66e22e69ea6559f66de52acac9 Mon Sep 17 00:00:00 2001 From: shreyasingh1 Date: Tue, 10 May 2022 03:58:53 -0400 Subject: [PATCH 18/29] relabeling so it builds - building locally now --- brainlit/utils/cnn_segmentation/__init__.py | 2 +- .../utils/cnn_segmentation/{preprocess.py => preprocess_cnn.py} | 0 .../tests/{test_preprocess.py => test_preprocess_cnn.py} | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) rename brainlit/utils/cnn_segmentation/{preprocess.py => preprocess_cnn.py} (100%) rename brainlit/utils/cnn_segmentation/tests/{test_preprocess.py => test_preprocess_cnn.py} (97%) diff --git a/brainlit/utils/cnn_segmentation/__init__.py b/brainlit/utils/cnn_segmentation/__init__.py index 3e1d7e78e..e14f78e9f 100644 --- a/brainlit/utils/cnn_segmentation/__init__.py +++ b/brainlit/utils/cnn_segmentation/__init__.py @@ -1,4 +1,4 @@ import brainlit.utils.cnn_segmentation -from brainlit.utils.cnn_segmentation.preprocess import * +from brainlit.utils.cnn_segmentation.preprocess_cnn import * from brainlit.utils.cnn_segmentation.performance_cnn import * diff --git a/brainlit/utils/cnn_segmentation/preprocess.py b/brainlit/utils/cnn_segmentation/preprocess_cnn.py similarity index 100% rename from brainlit/utils/cnn_segmentation/preprocess.py rename to brainlit/utils/cnn_segmentation/preprocess_cnn.py diff --git a/brainlit/utils/cnn_segmentation/tests/test_preprocess.py b/brainlit/utils/cnn_segmentation/tests/test_preprocess_cnn.py similarity index 97% rename from brainlit/utils/cnn_segmentation/tests/test_preprocess.py rename to brainlit/utils/cnn_segmentation/tests/test_preprocess_cnn.py index f0f2c8a38..d8227c8c8 100644 --- a/brainlit/utils/cnn_segmentation/tests/test_preprocess.py +++ b/brainlit/utils/cnn_segmentation/tests/test_preprocess_cnn.py @@ -1,7 +1,7 @@ import pytest import numpy as np -from brainlit.utils.cnn_segmentation import preprocess +from brainlit.utils.cnn_segmentation import preprocess_cnn from numpy.testing import ( assert_array_equal, ) From a5d455a43a6a055c0dd7d9be60a35c3a82d2a5e9 Mon Sep 17 00:00:00 2001 From: shreyasingh1 Date: Tue, 10 May 2022 04:12:14 -0400 Subject: [PATCH 19/29] more renaming --- .../utils/cnn_segmentation/tests/test_performance_cnn.py | 2 +- .../utils/cnn_segmentation/tests/test_preprocess_cnn.py | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/brainlit/utils/cnn_segmentation/tests/test_performance_cnn.py b/brainlit/utils/cnn_segmentation/tests/test_performance_cnn.py index dc91c1f3f..1708028d3 100644 --- a/brainlit/utils/cnn_segmentation/tests/test_performance_cnn.py +++ b/brainlit/utils/cnn_segmentation/tests/test_performance_cnn.py @@ -23,7 +23,7 @@ def test_get_metrics(): torch.from_numpy(np.ones(shape=(4, 4, 4))), ] - acc_list, precision_list, recall_list, percent_nonzero = performance.get_metrics( + acc_list, precision_list, recall_list, percent_nonzero = performance_cnn.get_metrics( pred_list, y_list ) diff --git a/brainlit/utils/cnn_segmentation/tests/test_preprocess_cnn.py b/brainlit/utils/cnn_segmentation/tests/test_preprocess_cnn.py index d8227c8c8..115510c39 100644 --- a/brainlit/utils/cnn_segmentation/tests/test_preprocess_cnn.py +++ b/brainlit/utils/cnn_segmentation/tests/test_preprocess_cnn.py @@ -15,7 +15,7 @@ def test_train_test_split(): X_img = [0, 1, 2, 3] y_mask = [0.0, 1.1, 2.2, 3.3] - X_train, y_train, X_test, y_test = preprocess.train_test_split(X_img, y_mask) + X_train, y_train, X_test, y_test = preprocess_cnn.train_test_split(X_img, y_mask) X_train_true = [0, 1, 2] y_train_true = [0.0, 1.1, 2.2] @@ -36,7 +36,7 @@ def test_get_subvolumes(): y_dim = 2 z_dim = 2 - X_train_subvolumes, y_train_subvolumes = preprocess.get_subvolumes( + X_train_subvolumes, y_train_subvolumes = preprocess_cnn.get_subvolumes( X_train, y_train, x_dim, y_dim, z_dim ) @@ -72,7 +72,7 @@ def test_getting_torch_objects(): X_test = [np.zeros(shape=(4, 4, 4))] y_test = [np.ones(shape=(4, 4, 4))] - train_dataloader, test_dataloader = preprocess.getting_torch_objects( + train_dataloader, test_dataloader = preprocess_cnn.getting_torch_objects( X_train, y_train, X_test, y_test ) From f5111674b2d5b12ebd873ff25acf55aa0da451bd Mon Sep 17 00:00:00 2001 From: shreyasingh1 Date: Tue, 10 May 2022 04:25:21 -0400 Subject: [PATCH 20/29] black --- .../utils/cnn_segmentation/tests/test_performance_cnn.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/brainlit/utils/cnn_segmentation/tests/test_performance_cnn.py b/brainlit/utils/cnn_segmentation/tests/test_performance_cnn.py index 1708028d3..67d0543c5 100644 --- a/brainlit/utils/cnn_segmentation/tests/test_performance_cnn.py +++ b/brainlit/utils/cnn_segmentation/tests/test_performance_cnn.py @@ -23,9 +23,12 @@ def test_get_metrics(): torch.from_numpy(np.ones(shape=(4, 4, 4))), ] - acc_list, precision_list, recall_list, percent_nonzero = performance_cnn.get_metrics( - pred_list, y_list - ) + ( + acc_list, + precision_list, + recall_list, + percent_nonzero, + ) = performance_cnn.get_metrics(pred_list, y_list) acc_true = [0.0, 100.0] precision_true = [0.0, 100.0] From de3e3db80622981c7227e000f140f691f2a7d0f0 Mon Sep 17 00:00:00 2001 From: shreyasingh1 Date: Tue, 10 May 2022 04:37:19 -0400 Subject: [PATCH 21/29] removing tdqm from file --- brainlit/utils/cnn_segmentation/performance_cnn.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/brainlit/utils/cnn_segmentation/performance_cnn.py b/brainlit/utils/cnn_segmentation/performance_cnn.py index 03713cf6c..93501c6f4 100644 --- a/brainlit/utils/cnn_segmentation/performance_cnn.py +++ b/brainlit/utils/cnn_segmentation/performance_cnn.py @@ -2,7 +2,6 @@ import numpy as np from sklearn.metrics import roc_curve, auc, jaccard_score -from tqdm.notebook import tqdm import torch from torch import nn import matplotlib.pyplot as plt @@ -113,13 +112,13 @@ def get_metrics(pred_list, y_list): recall_list = [] percent_nonzero = [] - for i in tqdm(range(len(pred_list))): + for i in range(len(pred_list)): acc_list_t = [] precision_list_t = [] recall_list_t = [] percent_nonzero_t = [] - for j in tqdm(range(len(pred_list[0]))): + for j in range(len(pred_list[0])): pred = pred_list[i][j].clone().numpy()[:, 0].round().astype(int).flatten() target = y_list[i][j][:, 0].clone().numpy().astype(int).flatten() From d10fe39a93059f696ada35ea947d49e930195722 Mon Sep 17 00:00:00 2001 From: shreyasingh1 <40285923+shreyasingh1@users.noreply.github.com> Date: Tue, 10 May 2022 15:12:09 -0400 Subject: [PATCH 22/29] [skip ci] test update utils.rst file --- docs/reference/utils.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/reference/utils.rst b/docs/reference/utils.rst index fc1a5e8b2..03164d9d2 100644 --- a/docs/reference/utils.rst +++ b/docs/reference/utils.rst @@ -32,5 +32,5 @@ S3 Helper Methods CNN Segmentation ------------------- -#.. autoapifunction:: preprocess -#.. autoapifunction:: performance +.. autoapifunction:: preprocess_cnn +.. autoapifunction:: performance_cnn From ea35e0c5ae9dad448c0a567702fff58b2e1f1aca Mon Sep 17 00:00:00 2001 From: shreyasingh1 <40285923+shreyasingh1@users.noreply.github.com> Date: Tue, 10 May 2022 15:26:56 -0400 Subject: [PATCH 23/29] [skip ci] trying with only preprocess_cnn --- docs/reference/utils.rst | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/docs/reference/utils.rst b/docs/reference/utils.rst index 03164d9d2..34efb012a 100644 --- a/docs/reference/utils.rst +++ b/docs/reference/utils.rst @@ -27,10 +27,13 @@ S3 Helper Methods .. autoapifunction:: get_file_paths .. autoapifunction:: main -.. currentmodule:: brainlit.utils.cnn_segmentation CNN Segmentation ------------------- -.. autoapifunction:: preprocess_cnn -.. autoapifunction:: performance_cnn +.. currentmodule:: brainlit.utils.cnn_segmentation.preprocess_cnn + +.. autoapifunction:: get_subvolumes +.. autoapifunction:: getting_torch_objects + +#.. autoapifunction:: performance_cnn From c7eea1169ddd804d2cf47d7eaf15798a92d40c7c Mon Sep 17 00:00:00 2001 From: shreyasingh1 Date: Tue, 10 May 2022 15:43:04 -0400 Subject: [PATCH 24/29] [skip ci] letting docstrings render properly - test --- .../utils/cnn_segmentation/performance_cnn.py | 21 ++++++++++++------- .../utils/cnn_segmentation/preprocess_cnn.py | 13 +++++++----- 2 files changed, 22 insertions(+), 12 deletions(-) diff --git a/brainlit/utils/cnn_segmentation/performance_cnn.py b/brainlit/utils/cnn_segmentation/performance_cnn.py index 93501c6f4..56442473a 100644 --- a/brainlit/utils/cnn_segmentation/performance_cnn.py +++ b/brainlit/utils/cnn_segmentation/performance_cnn.py @@ -15,7 +15,8 @@ def train_loop(dataloader, model, loss_fn, optimizer): """Pytorch model training loop - Args: + + Arguments: train_dataloader: torch object from getting_torch_objects function in preprocess.py model: pytorch model, defined locally loss_fn: loss_fn class name, ex: BCELoss, Dice @@ -44,7 +45,8 @@ def train_loop(dataloader, model, loss_fn, optimizer): def test_loop(dataloader, model, loss_fn): """Pytorch model testing loop - Args: + + Arguments: test_dataloader: torch object from getting_torch_objects function in preprocess.py model: pytorch model, defined locally loss_fn: loss_fn class name, ex: BCELoss, Dice @@ -98,7 +100,8 @@ def forward(self, inputs, targets, smooth=1): def get_metrics(pred_list, y_list): """Getting accuracy, precision, and recall at each epoch - Args: + + Arguments: pred_list: list of predictions for every image at every epoch, output of testing loop y_list: list of true y masks, output of testing loop Returns: @@ -149,7 +152,8 @@ def get_metrics(pred_list, y_list): def quick_stats(stat, epoch, acc_list, precision_list, recall_list, percent_nonzero): """Printing quick test stats at specified epoch - Args: + + Arguments: stat: str, "all" if you want to print all metrics (accuracy, precision, reacll, % nonzero) acc_list: list of average accuracy for each epoch, from get_metrics function precision_list: list of average precision for each epoch, from get_metrics function @@ -178,7 +182,8 @@ def plot_metrics_over_epoch( loss_list, acc_list, precision_list, recall_list, percent_nonzero ): """Plotting all metrics over epoch - Args: + + Arguments: loss_list: list of test loss over epoch acc_list: list of average accuracy for each epoch, from get_metrics function precision_list: list of average precision for each epoch, from get_metrics function @@ -220,7 +225,8 @@ def plot_metrics_over_epoch( def plot_pr_histograms(pred_list, y_list): """Plotting histograms for precision and recall at final epoch - Args: + + Arguments: pred_list: list of predictions for all images at last epoch y_list: lost of true y masks for all images at last epoch Returns: @@ -255,7 +261,8 @@ def plot_pr_histograms(pred_list, y_list): def plot_with_napari(x_list, pred_list, y_list): """Plotting all test images at an epoch in napari - Args: + + Arguments: x_list: list of all x images from testing loop pred_list: list of all testing predictions at an epoch y_list: list of true ground truth masks at that same epoch diff --git a/brainlit/utils/cnn_segmentation/preprocess_cnn.py b/brainlit/utils/cnn_segmentation/preprocess_cnn.py index 12b642699..02b9d1a80 100644 --- a/brainlit/utils/cnn_segmentation/preprocess_cnn.py +++ b/brainlit/utils/cnn_segmentation/preprocess_cnn.py @@ -11,7 +11,8 @@ def get_img_and_mask(data_dir): """Get lists of tif images and associated ground truth masks - Args: + + Arguments: data_dir: str, path to tif and mask files Returns: X_img: list of 3d np array images @@ -81,15 +82,16 @@ def train_test_split(X_img, y_mask, test_percent=0.25): def get_subvolumes(X_train, y_train, x_dim, y_dim, z_dim): """Get subvolumes of specified site for training dataset - Args: + + Arguments: X_train: list of imgs, from train_test_split function y_train: list of masks, from train_test_split function x_dim: int, x_dim of subvolume, must be divisible by image shape y_dim: int, y_dim of subvolume, must be divisible by image shape z_dim: int, z_dim of subvolume, must be divisible by image shape Returns: - X_train_subvolume: list of image subvolumes for training - y_train_subvolume: list of associated mask subvolumes for training + X_train_subvolume: List of image subvolumes, for training + y_train_subvolume: List of associated mask subvolumes, for training """ X_train_subvolumes = [] y_train_subvolumes = [] @@ -126,7 +128,8 @@ def get_subvolumes(X_train, y_train, x_dim, y_dim, z_dim): def getting_torch_objects(X_train_subvolumes, y_train_subvolumes, X_test, y_test): """Get training data in torch object format - Args: + + Arguments: X_train_subvolumes: list, training images (or subvolumes) from get_subvolumes function y_train_subvolumes: list, trianing masks (or subvolumes) from get_subvolumes function X_test: list, testing images from train_test_split function From 966f0c94738a24ec3fcf17d631b09fc248a8de99 Mon Sep 17 00:00:00 2001 From: shreyasingh1 Date: Tue, 10 May 2022 17:39:22 -0400 Subject: [PATCH 25/29] [skip ci] --- brainlit/utils/cnn_segmentation/performance_cnn.py | 6 ++++++ brainlit/utils/cnn_segmentation/preprocess_cnn.py | 4 ++++ 2 files changed, 10 insertions(+) diff --git a/brainlit/utils/cnn_segmentation/performance_cnn.py b/brainlit/utils/cnn_segmentation/performance_cnn.py index 56442473a..a133650e0 100644 --- a/brainlit/utils/cnn_segmentation/performance_cnn.py +++ b/brainlit/utils/cnn_segmentation/performance_cnn.py @@ -50,6 +50,7 @@ def test_loop(dataloader, model, loss_fn): test_dataloader: torch object from getting_torch_objects function in preprocess.py model: pytorch model, defined locally loss_fn: loss_fn class name, ex: BCELoss, Dice + Returns: x_list: list, true images y_pred: nested list, model predictions for each image at each epoch @@ -104,6 +105,7 @@ def get_metrics(pred_list, y_list): Arguments: pred_list: list of predictions for every image at every epoch, output of testing loop y_list: list of true y masks, output of testing loop + Returns: acc_list: list of average accuracy for each epoch precision_list: list of average precision for each epoch @@ -159,6 +161,7 @@ def quick_stats(stat, epoch, acc_list, precision_list, recall_list, percent_nonz precision_list: list of average precision for each epoch, from get_metrics function recall_list: list of average recall for each epoch, from get_metrics function percent_nonzero: list of percent of nonzero predictions at each epoch, from get_metrics function + Returns: Printed metrics for specified epoch """ @@ -189,6 +192,7 @@ def plot_metrics_over_epoch( precision_list: list of average precision for each epoch, from get_metrics function recall_list: list of average recall for each epoch, from get_metrics function percent_nonzero: list of percent of nonzero predictions at each epoch, from get_metrics function + Returns: Plotted figures for accuracy, precision, recall, % nonzero, and loss over epoch """ @@ -229,6 +233,7 @@ def plot_pr_histograms(pred_list, y_list): Arguments: pred_list: list of predictions for all images at last epoch y_list: lost of true y masks for all images at last epoch + Returns: Precision and recall plots for all images at last epoch """ @@ -266,6 +271,7 @@ def plot_with_napari(x_list, pred_list, y_list): x_list: list of all x images from testing loop pred_list: list of all testing predictions at an epoch y_list: list of true ground truth masks at that same epoch + Returns: Visualizations of napari image, ground truth mask, and thresholded prediction mask """ diff --git a/brainlit/utils/cnn_segmentation/preprocess_cnn.py b/brainlit/utils/cnn_segmentation/preprocess_cnn.py index 02b9d1a80..33def1fc9 100644 --- a/brainlit/utils/cnn_segmentation/preprocess_cnn.py +++ b/brainlit/utils/cnn_segmentation/preprocess_cnn.py @@ -14,6 +14,7 @@ def get_img_and_mask(data_dir): Arguments: data_dir: str, path to tif and mask files + Returns: X_img: list of 3d np array images y_mask: list of 3d np array masks @@ -64,6 +65,7 @@ def train_test_split(X_img, y_mask, test_percent=0.25): Args: X_img: list of 3d np array images y_mask: list of 3d np array masks + Returns: X_train, y_train, X_test, y_test: lists of specifie training and testing size """ @@ -89,6 +91,7 @@ def get_subvolumes(X_train, y_train, x_dim, y_dim, z_dim): x_dim: int, x_dim of subvolume, must be divisible by image shape y_dim: int, y_dim of subvolume, must be divisible by image shape z_dim: int, z_dim of subvolume, must be divisible by image shape + Returns: X_train_subvolume: List of image subvolumes, for training y_train_subvolume: List of associated mask subvolumes, for training @@ -134,6 +137,7 @@ def getting_torch_objects(X_train_subvolumes, y_train_subvolumes, X_test, y_test y_train_subvolumes: list, trianing masks (or subvolumes) from get_subvolumes function X_test: list, testing images from train_test_split function y_test: list, testing masks from train_test_split function + Returns: X_train_subvolume: list of image subvolumes for training y_train_subvolume: list of associated mask subvolumes for training From e4e476c51deb7103b5149d111dbae773cbf91613 Mon Sep 17 00:00:00 2001 From: shreyasingh1 <40285923+shreyasingh1@users.noreply.github.com> Date: Tue, 10 May 2022 17:40:57 -0400 Subject: [PATCH 26/29] [skip ci] update utils.rst --- docs/reference/utils.rst | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/docs/reference/utils.rst b/docs/reference/utils.rst index 34efb012a..5334ced2f 100644 --- a/docs/reference/utils.rst +++ b/docs/reference/utils.rst @@ -36,4 +36,10 @@ CNN Segmentation .. autoapifunction:: get_subvolumes .. autoapifunction:: getting_torch_objects -#.. autoapifunction:: performance_cnn +.. currentmodule:: brainlit.utils.cnn_segmentation.performance_cnn + +.. autoapifunction:: train_loop +.. autoapifunction:: test_loop +.. autoapifunction:: get_metrics + + From 1f4827b9582fa11211d3d3f44d8856252e4554a1 Mon Sep 17 00:00:00 2001 From: shreyasingh1 Date: Tue, 10 May 2022 17:43:09 -0400 Subject: [PATCH 27/29] adding in make_masks.py --- brainlit/utils/make_masks.py | 118 ++++++++++++++++++++++------------- 1 file changed, 75 insertions(+), 43 deletions(-) diff --git a/brainlit/utils/make_masks.py b/brainlit/utils/make_masks.py index 839a63cf7..af2780731 100644 --- a/brainlit/utils/make_masks.py +++ b/brainlit/utils/make_masks.py @@ -27,12 +27,7 @@ def make_masks(data_dir): if not os.path.exists(mask_dir): os.makedirs(mask_dir) - # loading all the benchmarking images from local paths - - # mask_dir = data_dir / "benchmarking_masks" gfp_files = list(im_dir.glob("**/*.tif")) - # swc_base_path = data_dir / "Manual-GT" - save = True for im_num, im_path in enumerate(gfp_files): # loading one gfp image @@ -41,27 +36,12 @@ def make_masks(data_dir): file_name = im_path.parts[-1][:-8] - f = im_path.parts[-1][:-8].split("_") - image = f[0] - date = type_to_date[image] - num = int(f[1]) - - scale = scales[date] - brain_offset = brain_offsets[date] - vol_offset = vol_offsets[date][num] - im_offset = np.add(brain_offset, vol_offset) - - # loading all the .swc files corresponding to the image - # all the paths of .swc files are saved in variable swc_files - lower = int(np.floor((num - 1) / 5) * 5 + 1) - upper = int(np.floor((num - 1) / 5) * 5 + 5) - dir1 = date + "_" + image + "_" + str(lower) + "-" + str(upper) - dir2 = date + "_" + image + "_" + str(num) + scale, brain_offset, vol_offset, im_offset, dir1, dir2 = get_scales(im_path) + swc_path = swc_dir / "Manual-GT" / dir1 / dir2 swc_files = list(swc_path.glob("**/*.swc")) paths_total = [] - labels_total = np.zeros(im.shape) # generate paths and save them into paths_total for swc_num, swc in enumerate(swc_files): @@ -80,30 +60,82 @@ def make_masks(data_dir): paths_total.append(pvox) # generate labels by using paths - for path_voxel in paths_total: - for voxel_num, voxel in enumerate(path_voxel): - if voxel_num == 0: - continue - voxel_prev = path_voxel[voxel_num - 1, :] - xs, ys, zs = Bresenham3D( - int(voxel_prev[0]), - int(voxel_prev[1]), - int(voxel_prev[2]), - int(voxel[0]), - int(voxel[1]), - int(voxel[2]), - ) - for x, y, z in zip(xs, ys, zs): - vox = np.array((x, y, z)) - if (vox >= 0).all() and (vox < im.shape).all(): - labels_total[x, y, z] = 1 + labels_total = paths_to_Bresenham(im, paths_total, dilate_dist=1000) label_flipped = labels_total * 0 label_flipped[labels_total == 0] = 1 dists = distance_transform_edt(label_flipped, sampling=scale) labels_total[dists <= 1000] = 1 - if save: - im_file_name = file_name + "_mask.npy" - out_file = mask_dir + "/" + im_file_name - np.save(out_file, labels_total) + im_file_name = file_name + "_mask.npy" + out_file = mask_dir + "/" + im_file_name + np.save(out_file, labels_total) + + +def get_scales(im_path): + """Get image and swc scaling factors + Args: + im_path: path to image + Returns: + scale: scaling image factor from benchmarking_params + brain_offset: brain_offset image factor from benchmarking_params + vol_offset: vol_offset image factor from benchmarking_params + im_offset: image offset factor from benchmarking_params + dir1: swc dir 1 to find swc file + dir2: swc dir 2 to find swc file + """ + f = im_path.parts[-1][:-8].split("_") + image = f[0] + date = type_to_date[image] + num = int(f[1]) + + scale = scales[date] + brain_offset = brain_offsets[date] + vol_offset = vol_offsets[date][num] + im_offset = np.add(brain_offset, vol_offset) + + # loading all the .swc files corresponding to the image + # all the paths of .swc files are saved in variable swc_files + lower = int(np.floor((num - 1) / 5) * 5 + 1) + upper = int(np.floor((num - 1) / 5) * 5 + 5) + dir1 = date + "_" + image + "_" + str(lower) + "-" + str(upper) + dir2 = date + "_" + image + "_" + str(num) + + return scale, brain_offset, vol_offset, im_offset, dir1, dir2 + + +def paths_to_Bresenham(im, paths_total, dilate_dist=1000): + """generate Dilated Mask using paths + Args: + im: image corresponding to mask + paths_total: list of all paths from swc files + dilate_dist: amount in microns to dilate mask by, default = 1000 + Returns: + labels_total: dilated mask from path + """ + labels_total = np.zeros(im.shape) + + for path_voxel in paths_total: + for voxel_num, voxel in enumerate(path_voxel): + if voxel_num == 0: + continue + voxel_prev = path_voxel[voxel_num - 1, :] + xs, ys, zs = Bresenham3D( + int(voxel_prev[0]), + int(voxel_prev[1]), + int(voxel_prev[2]), + int(voxel[0]), + int(voxel[1]), + int(voxel[2]), + ) + for x, y, z in zip(xs, ys, zs): + vox = np.array((x, y, z)) + if (vox >= 0).all() and (vox < im.shape).all(): + labels_total[x, y, z] = 1 + + label_flipped = labels_total * 0 + label_flipped[labels_total == 0] = 1 + dists = distance_transform_edt(label_flipped, sampling=scale) + labels_total[dists <= dilate_dist] = 1 + + return labels_total From bd76a71b0171660a0e3a013e40d6e3082935803d Mon Sep 17 00:00:00 2001 From: shreyasingh1 <40285923+shreyasingh1@users.noreply.github.com> Date: Tue, 10 May 2022 17:46:50 -0400 Subject: [PATCH 28/29] [skip ci] adding make_masks to rst file --- docs/reference/utils.rst | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/reference/utils.rst b/docs/reference/utils.rst index 5334ced2f..924942bb1 100644 --- a/docs/reference/utils.rst +++ b/docs/reference/utils.rst @@ -12,7 +12,9 @@ Data Helper Methods .. autoapiclass:: NeuronTrace :members: -#.. autoapifunction:: make_masks +.. currentmodule:: brainlit.utils.make_masks + +.. autoapifunction:: make_masks .. currentmodule:: brainlit.utils.upload_to_neuroglancer From ffc246dfbbc749bffdae625bd8373a9e17a6d0f4 Mon Sep 17 00:00:00 2001 From: shreyasingh1 Date: Tue, 10 May 2022 18:05:18 -0400 Subject: [PATCH 29/29] final push to test circleCI and nettlify build --- .../utils/cnn_segmentation/performance_cnn.py | 16 ++++++++-------- .../utils/cnn_segmentation/preprocess_cnn.py | 10 +++++----- brainlit/utils/make_masks.py | 11 ++++++++--- 3 files changed, 21 insertions(+), 16 deletions(-) diff --git a/brainlit/utils/cnn_segmentation/performance_cnn.py b/brainlit/utils/cnn_segmentation/performance_cnn.py index a133650e0..cfe3cb760 100644 --- a/brainlit/utils/cnn_segmentation/performance_cnn.py +++ b/brainlit/utils/cnn_segmentation/performance_cnn.py @@ -52,10 +52,10 @@ def test_loop(dataloader, model, loss_fn): loss_fn: loss_fn class name, ex: BCELoss, Dice Returns: - x_list: list, true images - y_pred: nested list, model predictions for each image at each epoch - y_list: nested list, true masks for each image at each epoch - avg_loss: list, average loss at each epoch + List, true images: x_list + Nested list, model predictions for each image at each epoch: y_pred + Nested list, true masks for each image at each epoch: y_list + List, average loss at each epoch: avg_loss """ for batch, (X_all, y_all) in enumerate(dataloader): @@ -107,10 +107,10 @@ def get_metrics(pred_list, y_list): y_list: list of true y masks, output of testing loop Returns: - acc_list: list of average accuracy for each epoch - precision_list: list of average precision for each epoch - recall_list: list of average recall for each epoch - percent_nonzero: list of percent of nonzero predictions at each epoch + List of average accuracy for each epoch: acc_list + List of average precision for each epoch: precision_list + List of average recall for each epoch: recall_list + List of percent of nonzero predictions at each epoch: percent_nonzero """ acc_list = [] precision_list = [] diff --git a/brainlit/utils/cnn_segmentation/preprocess_cnn.py b/brainlit/utils/cnn_segmentation/preprocess_cnn.py index 33def1fc9..01645223f 100644 --- a/brainlit/utils/cnn_segmentation/preprocess_cnn.py +++ b/brainlit/utils/cnn_segmentation/preprocess_cnn.py @@ -16,8 +16,8 @@ def get_img_and_mask(data_dir): data_dir: str, path to tif and mask files Returns: - X_img: list of 3d np array images - y_mask: list of 3d np array masks + List of 3d np array images: X_img + List of 3d np array masks: y_img """ im_dir = Path(os.path.join(data_dir, "sample-tif-location")) gfp_files = list(im_dir.glob("**/*-gfp.tif")) @@ -67,7 +67,7 @@ def train_test_split(X_img, y_mask, test_percent=0.25): y_mask: list of 3d np array masks Returns: - X_train, y_train, X_test, y_test: lists of specifie training and testing size + Lists of specifie training and testing size: X_train, y_train, X_test, y_test: l """ num_images = len(X_img) test_images = num_images * test_percent @@ -139,8 +139,8 @@ def getting_torch_objects(X_train_subvolumes, y_train_subvolumes, X_test, y_test y_test: list, testing masks from train_test_split function Returns: - X_train_subvolume: list of image subvolumes for training - y_train_subvolume: list of associated mask subvolumes for training + List of image subvolumes for training: X_train_subvolume + List of associated mask subvolumes for training: y_train_subvolumes """ x_dim = X_train_subvolumes[0].shape[0] y_dim = X_train_subvolumes[0].shape[1] diff --git a/brainlit/utils/make_masks.py b/brainlit/utils/make_masks.py index af2780731..294bfdf8d 100644 --- a/brainlit/utils/make_masks.py +++ b/brainlit/utils/make_masks.py @@ -15,9 +15,11 @@ def make_masks(data_dir): """Swc to numpy mask - Args: + + Arguments: data_dir: direction to base data folder that download_benchmarking points to. Should contain sample-tif-location and sample-swc-location + Returns: Saved numpy masks in data-dir/mask-location for each image in sample-tif-location """ @@ -74,8 +76,10 @@ def make_masks(data_dir): def get_scales(im_path): """Get image and swc scaling factors - Args: + + Arguments: im_path: path to image + Returns: scale: scaling image factor from benchmarking_params brain_offset: brain_offset image factor from benchmarking_params @@ -106,7 +110,8 @@ def get_scales(im_path): def paths_to_Bresenham(im, paths_total, dilate_dist=1000): """generate Dilated Mask using paths - Args: + + Arguments: im: image corresponding to mask paths_total: list of all paths from swc files dilate_dist: amount in microns to dilate mask by, default = 1000