{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "a1c8c29c",
   "metadata": {},
   "outputs": [],
   "source": [
    "import pickle \n",
    "import numpy as np \n",
    "import torch \n",
    "import torch.nn as nn \n",
    "import torch.optim as optim \n",
    "import torchvision \n",
    "import torchvision.transforms as transforms \n",
    "from torch.utils.data import DataLoader, Dataset \n",
    "from torchsummary import summary \n",
    "from tqdm import tqdm \n",
    "import os \n",
    "import matplotlib.pyplot as plt \n",
    "import cv2 \n",
    "import matplotlib.cm as cm \n",
    "from scipy import stats \n",
    "from scipy.stats import normaltest \n",
    "from scipy.stats import levene"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "87309000",
   "metadata": {},
   "outputs": [],
   "source": [
    "os.environ['CUDA_LAUNCH_BLOCKING'] = \"1\"\n",
    "os.environ[\"CUDA_VISIBLE_DEVICES\"] = \"0\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "bf78e7f1",
   "metadata": {},
   "outputs": [],
   "source": [
    "device = 'cuda' if torch.cuda.is_available() else 'cpu'"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "1dbdee7d",
   "metadata": {},
   "outputs": [],
   "source": [
    "torch.cuda.device_count()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "e179d3cc",
   "metadata": {},
   "outputs": [],
   "source": [
    "latent_dim = 8\n",
    "resize_pixel = 64 \n",
    "epochs = 100\n",
    "PATH = './VAE_Unet_checkpoint_220831.pt' \n",
    "loss_path = \"Loss_full_connection.tif\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "0a594871",
   "metadata": {},
   "outputs": [],
   "source": [
    "with open ('normal_dataset_n276_220727RCC_r64.pickle', 'rb') as f:\n",
    "    load_datasets4 = pickle.load(f)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "7e1ff53c",
   "metadata": {},
   "outputs": [],
   "source": [
    "train_set2 = []\n",
    "for dataset in load_datasets4:\n",
    "    images = np.array(dataset[0], dtype = np.float32)\n",
    "    train_set2.append([images, dataset[1]])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "7876c438",
   "metadata": {},
   "outputs": [],
   "source": [
    "with open ('validation_dataset_n58_220801RCC_r64.pickle', 'rb') as f:\n",
    "    load_datasets5 = pickle.load(f)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "8e93b8a2",
   "metadata": {},
   "outputs": [],
   "source": [
    "validation_set2 = []\n",
    "for dataset in load_datasets5:\n",
    "    images = np.array(dataset[0], dtype = np.float32)\n",
    "    validation_set2.append([images, dataset[1]])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "c13bc014",
   "metadata": {},
   "outputs": [],
   "source": [
    "with open ('abnormal_dataset_n96_220801RCC_TAO_r64.pickle', 'rb') as f:\n",
    "    datasets_abnormal2 = pickle.load(f)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "22039c9b",
   "metadata": {},
   "outputs": [],
   "source": [
    "abnormal_set2 = []\n",
    "for dataset in datasets_abnormal2:\n",
    "    images = np.array(dataset[0], dtype = np.float32)\n",
    "    abnormal_set2.append([images, dataset[1]])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "f11c47ea",
   "metadata": {},
   "outputs": [],
   "source": [
    "def remove_bone(dataset, value1 = 0.375, value2 = 0.71):#0.375  0.65 0.71\n",
    "    modified = []\n",
    "    dataset_c = dataset.copy()\n",
    "    for i in range(len(dataset_c)):\n",
    "        idx = (dataset_c[i][0] >= value2) | (dataset_c[i][0] <= value1)\n",
    "        dataset_c[i][0][idx] = 0#best 0.3\n",
    "        idx2 = (dataset_c[i][0] != 0)\n",
    "        dataset_c[i][0][idx2] = 0.69 # 0.65#0.68 #best 0.7\n",
    "        modified.append(dataset_c[i])\n",
    "        \n",
    "    return modified"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "500f8c9d",
   "metadata": {},
   "outputs": [],
   "source": [
    "train_set_rb = remove_bone(train_set2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "930ca598",
   "metadata": {},
   "outputs": [],
   "source": [
    "validation_set_rb = remove_bone(validation_set2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "0ade06fe",
   "metadata": {},
   "outputs": [],
   "source": [
    "abnormal_set_rb = remove_bone(abnormal_set2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "53d3058d",
   "metadata": {},
   "outputs": [],
   "source": [
    "class CustomDataset(Dataset):\n",
    "    def __init__(self, data1, data2, normal = True):\n",
    "        self.data1 = data1\n",
    "        self.data2 = data2\n",
    "        self.normal = normal\n",
    "        \n",
    "    def __len__(self):\n",
    "        return len(self.data1)\n",
    "    \n",
    "    def __getitem__(self, idx):\n",
    "        sample = self.data1[idx][0].reshape(1, resize_pixel, resize_pixel, resize_pixel)\n",
    "        sample = torch.tensor(sample)\n",
    "        sample2 = self.data2[idx][0].reshape(1, resize_pixel, resize_pixel, resize_pixel)\n",
    "        sample2 = torch.tensor(sample2)\n",
    "        label = self.data2[idx][1]\n",
    "            \n",
    "        return sample, sample2, label"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "6b640b78",
   "metadata": {},
   "outputs": [],
   "source": [
    "train_dataset = CustomDataset(train_set_rb, train_set_rb, normal = True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "4f93329c",
   "metadata": {},
   "outputs": [],
   "source": [
    "train_loader = DataLoader(train_dataset, batch_size = 32, shuffle = True) # maxpool로 메모리 과부하되어 size 줄임"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "d8a9e16f",
   "metadata": {},
   "outputs": [],
   "source": [
    "validation_dataset = CustomDataset(validation_set_rb, validation_set_rb, normal = True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "59847d8e",
   "metadata": {},
   "outputs": [],
   "source": [
    "validation_loader = DataLoader(validation_dataset, batch_size = 1, shuffle = False)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "1708c3a9",
   "metadata": {},
   "outputs": [],
   "source": [
    "abnormal_dataset = CustomDataset(abnormal_set_rb, abnormal_set_rb, normal = True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "28d5c05e",
   "metadata": {},
   "outputs": [],
   "source": [
    "abnormal_loader = DataLoader(abnormal_dataset, batch_size = 1, shuffle = False)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "eb1d8dd2",
   "metadata": {},
   "outputs": [],
   "source": [
    "class Unet(nn.Module):\n",
    "    def __init__(self, latent_dim):\n",
    "        super(Unet, self).__init__()\n",
    "        \n",
    "        self.layer_dn1 = nn.Sequential(\n",
    "            nn.Conv3d(1, 64, 3, stride = 1, padding = 1),\n",
    "            nn.BatchNorm3d(64),\n",
    "            nn.ReLU(),\n",
    "            nn.Dropout3d(p = 0.19),\n",
    "            nn.MaxPool3d(2, stride = 2)\n",
    "        )\n",
    "        \n",
    "        \n",
    "        self.layer_dn2 = nn.Sequential(\n",
    "            nn.Conv3d(64, 128, 3, stride = 1, padding = 1),\n",
    "            nn.BatchNorm3d(128),\n",
    "            nn.ReLU(),\n",
    "            nn.Dropout3d(p = 0.19),\n",
    "            nn.MaxPool3d(2, stride = 2)\n",
    "        )\n",
    "        \n",
    "        self.layer_dn3 = nn.Sequential(\n",
    "            nn.Conv3d(128, 256, 3, stride = 1, padding = 1),\n",
    "            nn.BatchNorm3d(256),\n",
    "            nn.ReLU(),\n",
    "            nn.Dropout3d(p = 0.20), \n",
    "            nn.MaxPool3d(2, stride = 2)\n",
    "        )    \n",
    "        \n",
    "\n",
    "        self.layer_dn4 = nn.Sequential(\n",
    "            nn.Conv3d(256, 512, 3, stride = 1), \n",
    "            nn.BatchNorm3d(512),\n",
    "            nn.ReLU(),\n",
    "            nn.Dropout3d(p = 0.23), \n",
    "            nn.MaxPool3d(2, stride = 2)\n",
    "        )\n",
    "    \n",
    "        \n",
    "        self.flatten = nn.Flatten(start_dim = 1)\n",
    "        \n",
    "        self.fc_layer_dn = nn.Sequential(\n",
    "            nn.Linear(512*3*3*3, 912), \n",
    "            nn.ReLU(),\n",
    "        )\n",
    "        \n",
    "        self.mean = nn.Linear(912, latent_dim)\n",
    "        self.var = nn.Linear(912, latent_dim)\n",
    "        \n",
    "        self.fc_layer_up = nn.Sequential(\n",
    "            nn.Linear(latent_dim, 912),\n",
    "            nn.ReLU(),\n",
    "            nn.Linear(912, 512*3*3*3) \n",
    "            )\n",
    "        \n",
    "        self.unflatten = nn.Unflatten(1, (512, 3, 3, 3)) #(1024, 2, 2, 2))\n",
    "        \n",
    "        self.layer_up2 = nn.Sequential(\n",
    "            nn.ConvTranspose3d(512, 256, 3, stride = 2, output_padding = 1),\n",
    "            nn.BatchNorm3d(256),\n",
    "            nn.LeakyReLU(0.6)\n",
    "            )\n",
    "        \n",
    "        self.layer_up3 = nn.Sequential(\n",
    "            nn.ConvTranspose3d(256, 128, 3, stride = 2, padding = 1, output_padding = 1),\n",
    "            nn.BatchNorm3d(128),\n",
    "            nn.LeakyReLU(0.6)\n",
    "            )\n",
    "\n",
    "        \n",
    "        self.layer_up4 = nn.Sequential(\n",
    "            nn.ConvTranspose3d(128, 64, 3, stride = 2, padding = 1, output_padding = 1),\n",
    "            nn.LeakyReLU(0.6)\n",
    "            )\n",
    "        \n",
    " \n",
    "        self.layer_up5 = nn.Sequential(\n",
    "            nn.ConvTranspose3d(64, 1, 3, stride = 1,padding = 1),\n",
    "            nn.Upsample(scale_factor = 2, mode = 'trilinear', align_corners=True)\n",
    "            )\n",
    "        \n",
    "\n",
    "        \n",
    "    def reparameterization(self, mean, var):\n",
    "        epsilon = torch.randn_like(var).to(device)\n",
    "        z = mean + var * epsilon\n",
    "        return z\n",
    "\n",
    "        \n",
    "    def forward(self, input):\n",
    "        conv_out = []\n",
    "        comp_out = []\n",
    "        latent_dim_out = []\n",
    "        out = self.layer_dn1(input)\n",
    "        conv_out.append(out) #0 \n",
    "        out = self.layer_dn2(out)\n",
    "        conv_out.append(out) #1\n",
    "        out = self.layer_dn3(out)\n",
    "        conv_out.append(out) #2\n",
    "        out = self.layer_dn4(out)\n",
    "        conv_out.append(out)#3\n",
    "        out = self.flatten(out)  \n",
    "        out = self.fc_layer_dn(out)\n",
    "        mean = self.mean(out)\n",
    "        log_var = self.var(out)\n",
    "        out = self.reparameterization(mean, torch.exp(0.5 * log_var + 1e-6))\n",
    "        latent_dim_out.append(out)\n",
    "        out = self.fc_layer_up(out)\n",
    "        out = self.unflatten(out)\n",
    "        out = self.layer_up2(out)\n",
    "        out = self.layer_up3(out)\n",
    "        out = self.layer_up4(out)\n",
    "        comp_out.append(out)\n",
    "        out = self.layer_up5(out)\n",
    "        out = torch.sigmoid(out)\n",
    "        \n",
    "        return out, comp_out, latent_dim_out, mean, log_var"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "17affe39",
   "metadata": {},
   "outputs": [],
   "source": [
    "unet = Unet(latent_dim)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "dce4181a",
   "metadata": {},
   "outputs": [],
   "source": [
    "unet = unet.to(device)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "255edf2b",
   "metadata": {
    "scrolled": false
   },
   "outputs": [],
   "source": [
    "summary(unet, input_size = (1, resize_pixel, resize_pixel, resize_pixel))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "a4a06445",
   "metadata": {},
   "outputs": [],
   "source": [
    "def loss_function(out, x, mean, log_var):\n",
    "    reproduction_loss = nn.functional.mse_loss(out, x, reduction = 'sum')\n",
    "    KLD = -0.5 * torch.sum(1 + log_var - torch.square(mean) - torch.exp(log_var+1e-6))\n",
    "    return reproduction_loss, KLD "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "b4c2e4e8",
   "metadata": {},
   "outputs": [],
   "source": [
    "optimizer = optim.Adam(unet.parameters(), lr = 1e-3)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "ea3cbe63",
   "metadata": {},
   "outputs": [],
   "source": [
    "class LRScheduler():\n",
    "    def __init__(self, optimizer, patience = 3, min_lr = 1e-5, factor = 0.3):\n",
    "        self.optimizer = optimizer\n",
    "        self.patience = patience\n",
    "        self.min_lr = min_lr\n",
    "        self.factor = factor\n",
    "        self.lr_scheduler = optim.lr_scheduler.ReduceLROnPlateau(\n",
    "                    self.optimizer, \n",
    "                    mode = 'min',\n",
    "                    patience = self.patience,\n",
    "                    factor = self.factor, \n",
    "                    min_lr = self.min_lr,\n",
    "                    verbose = True\n",
    "        )\n",
    "    \n",
    "    def __call__(self, loss):\n",
    "        self.lr_scheduler.step(loss)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "f4e3f7a2",
   "metadata": {},
   "outputs": [],
   "source": [
    "lr_scheduler = LRScheduler(optimizer)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "c0b96d64",
   "metadata": {},
   "outputs": [],
   "source": [
    "class EarlyStopping():\n",
    "    def __init__(self, patience = 5, verbose = True, delta = 0, path = PATH):\n",
    "        self.patience = patience\n",
    "        self.counter = 0\n",
    "        self.best_score = None\n",
    "        self.early_stop = False\n",
    "        self.val_loss_min = np.Inf\n",
    "        self.verbose = verbose\n",
    "        self.delta = delta\n",
    "        self.path = path\n",
    "        \n",
    "    def __call__(self, val_loss, model):\n",
    "        score = val_loss\n",
    "        if self.best_score is None:\n",
    "            self.best_score = score\n",
    "            self.save_checkpoint(val_loss, model)\n",
    "            \n",
    "        elif score > (self.best_score + self.delta):\n",
    "            self.counter += 1\n",
    "            print(f'EarlyStopping counter: {self.counter} out of {self.patience}')\n",
    "            if self.counter >= self.patience:\n",
    "                self.early_stop = True\n",
    "        \n",
    "        else:\n",
    "            self.best_score = score\n",
    "            self.save_checkpoint(val_loss, model)\n",
    "            self.counter = 0\n",
    "            \n",
    "    def save_checkpoint(self, val_loss, model):\n",
    "        if self.verbose:\n",
    "            print(f'Validation loss decreased ({self.val_loss_min:.6f} --> {val_loss:.6f}). Saving model ...')\n",
    "        torch.save(model.state_dict(), self.path)\n",
    "        self.val_loss_min = val_loss"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "d1c7953f",
   "metadata": {},
   "outputs": [],
   "source": [
    "early_stopping = EarlyStopping()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "536f90db",
   "metadata": {},
   "outputs": [],
   "source": [
    "def train(epoch, model, train_loader, optimizer):\n",
    "    model.train()\n",
    "    train_loss = 0.\n",
    "    reproduction_loss = 0.\n",
    "    KLD_loss = 0.\n",
    "    \n",
    "    for batch_idx, (x, y, _) in enumerate(train_loader):\n",
    "        torch.autograd.set_detect_anomaly(True)\n",
    "        x = x.to(device) \n",
    "        y = y.to(device)\n",
    "        \n",
    "        optimizer.zero_grad()\n",
    "        out, _, _, mean, log_var = model(x) \n",
    "        BCE, KLD = loss_function(out, y, mean, log_var) \n",
    "        reproduction_loss += BCE.item()\n",
    "        KLD_loss += KLD.item() \n",
    "        loss = BCE+KLD \n",
    "        train_loss += loss.item()\n",
    "        \n",
    "        loss.backward()\n",
    "        optimizer.step()\n",
    "        \n",
    "    print(\"======> Epoch: {} Average loss: {:.4f}\".format(\n",
    "        epoch, train_loss / len(train_loader.dataset)))\n",
    "    \n",
    "    return train_loss / len(train_loader.dataset), reproduction_loss / len(train_loader.dataset), KLD_loss / len(train_loader.dataset)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "1320c1db",
   "metadata": {},
   "outputs": [],
   "source": [
    "def test(model, test_loader):\n",
    "    model.eval()\n",
    "    test_loss = []\n",
    "    comp_outs = []\n",
    "    latent_dim_outs = []\n",
    "    output = []\n",
    "    reproduction_loss = []\n",
    "    KLD_loss = []\n",
    "    with torch.no_grad():\n",
    "        for batch_idx, (x, y, _) in enumerate(test_loader):\n",
    "            x = x.to(device)\n",
    "            y = y.to(device)\n",
    "        \n",
    "            optimizer.zero_grad()\n",
    "            out, comp_out, latent_dim_out, mean, log_var = model(x) \n",
    "            BCE, KLD = loss_function(out, y, mean, log_var)  \n",
    "            reproduction_loss.append(BCE.item())\n",
    "            KLD_loss.append(KLD.item()) \n",
    "            loss = BCE + KLD \n",
    "            test_loss.append(loss.item())\n",
    "            output.append(out.detach().cpu())\n",
    "            comp_outs.append(comp_out[0].detach().cpu())\n",
    "            latent_dim_outs.append(latent_dim_out[0].detach().cpu())\n",
    "\n",
    "    return test_loss, comp_outs, latent_dim_outs, output, reproduction_loss, KLD_loss #mean, log_var"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "d9d729fd",
   "metadata": {},
   "outputs": [],
   "source": [
    "train_dataset2 = CustomDataset(train_set_rb, train_set_rb, normal = True)\n",
    "train_loader2 = DataLoader(train_dataset2, batch_size = 1, shuffle = False)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "a963c83f",
   "metadata": {
    "scrolled": true
   },
   "outputs": [],
   "source": [
    "reproduction_losses = []\n",
    "KLD_losses = []\n",
    "total_losses = []\n",
    "\n",
    "validation_losses = []\n",
    "ab_losses = []\n",
    "\n",
    "\n",
    "for epoch in tqdm(range(0, epochs)):\n",
    "    train_loss, reproduction_loss, KLD_loss = train(epoch, unet, train_loader, optimizer)\n",
    "    reproduction_losses.append(reproduction_loss)\n",
    "    KLD_losses.append(KLD_loss)\n",
    "    total_losses.append(train_loss)\n",
    "    lr_scheduler(train_loss)\n",
    "    early_stopping(train_loss, unet)\n",
    "    \n",
    "    if (epoch+1)%1 == 0:\n",
    "        abnormal_loss, ab_comp_out, ab_latent_dim, _, abnormal_reproduction, abnormal_KLD = test(unet, abnormal_loader)\n",
    "        validation_loss, val_comp_out, val_latent_dim, _, validation_reproduction, validation_KLD = test(unet, validation_loader)\n",
    "        validation_losses.append(np.mean(np.array(validation_loss)))\n",
    "        ab_losses.append(np.mean(np.array(abnormal_loss)))\n",
    "\n",
    "        print(f'Epoch: {epoch+1}')\n",
    "        print(f'validation_loss: min {min(validation_loss)}, max {max(validation_loss)}')\n",
    "        print(f'abnormal_loss: min {min(abnormal_loss)}, max {max(abnormal_loss)}')\n",
    "        print(f'mean_validation_loss: {np.mean(np.array(validation_loss))}')\n",
    "        print(f'median_abnormal_loss: {np.median(np.array(abnormal_loss))}')\n",
    "        print(f'mean_abnormal_loss: {np.mean(np.array(abnormal_loss))}')\n",
    "\n",
    "    print('\\n')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "00812f86",
   "metadata": {},
   "outputs": [],
   "source": [
    "fig, ax = plt.subplots(1, 1, figsize = (16, 10))\n",
    "\n",
    "plt.ylim(10000, 50000)\n",
    "ax.plot(total_losses, color = 'b')\n",
    "ax.set_title('Total loss', size = 20)\n",
    "ax.plot(range(0, len(validation_losses)), validation_losses, color = 'g')\n",
    "ax.plot(range(0, len(ab_losses)), ab_losses, color = 'r')\n",
    "plt.legend([\"Train\", \"Validation - Normal\", \"Validation - Abnormal\"], fontsize = 14)\n",
    "plt.savefig(loss_path, dpi = 300)\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "68e56153",
   "metadata": {},
   "outputs": [],
   "source": [
    "def display_image_grid (images_filepaths, predicted_labels = (), cols = 8, cmap = cm.gray):\n",
    "    rows = (len(images_filepaths)-8) // cols\n",
    "    images_filepaths = images_filepaths.transpose(2, 0, 1, 3)\n",
    "    images_filepaths = images_filepaths[0:-8, :, :, :]\n",
    "    figure, ax = plt.subplots(nrows = rows, ncols = cols, figsize = (30, 30))\n",
    "    for i, image_filepath in enumerate(images_filepaths):\n",
    "        ax.ravel()[i].imshow(image_filepath, cmap = cmap)\n",
    "        ax.ravel()[i].set_title(i+1, color = 'black', fontsize = 20)\n",
    "        ax.ravel()[i].set_axis_off()\n",
    "    plt.tight_layout()\n",
    "    plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "11c7b9cc",
   "metadata": {},
   "outputs": [],
   "source": [
    "def display_image_grid2 (images_filepaths1, images_filepaths2, predicted_labels = (), cols = 8, cmap = cm.gray):\n",
    "    rows = (len(images_filepaths1)-8) // cols\n",
    "    images_filepaths1 = images_filepaths1.transpose(2, 0, 1, 3)\n",
    "    images_filepaths1 = images_filepaths1[0:-8, :, :, :]\n",
    "    images_filepaths2 = images_filepaths2.transpose(2, 0, 1, 3)\n",
    "    images_filepaths2 = images_filepaths2[0:-8, :, :, :]\n",
    "    images_filepaths = zip(images_filepaths1, images_filepaths2)\n",
    "    figure, ax = plt.subplots(nrows = rows, ncols = cols, figsize = (30, 30))\n",
    "    for i, image_filepath in enumerate(images_filepaths):\n",
    "        ax.ravel()[i].imshow(image_filepath[0], cmap = cmap)\n",
    "        ax.ravel()[i].imshow(image_filepath[1], cmap = cm.jet, alpha = 0.4)\n",
    "        ax.ravel()[i].set_title(i+1, color = 'black', fontsize = 20)\n",
    "        ax.ravel()[i].set_axis_off()\n",
    "    plt.tight_layout()\n",
    "    plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "f5e27efd",
   "metadata": {},
   "outputs": [],
   "source": [
    "display_image = abnormal_set_rb[0][0]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "fbcd0465",
   "metadata": {},
   "outputs": [],
   "source": [
    "display_image = display_image.reshape(1, 64, 64, 64)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "953ac384",
   "metadata": {},
   "outputs": [],
   "source": [
    "display_image = torch.tensor(display_image, dtype = torch.float32)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "05065fd6",
   "metadata": {},
   "outputs": [],
   "source": [
    "display_input = display_image.unsqueeze(0).to(device)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "d2cf5ee2",
   "metadata": {},
   "outputs": [],
   "source": [
    "out_image, _, _, mean, log_var = unet(display_input) "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "2537bbe3",
   "metadata": {},
   "outputs": [],
   "source": [
    "out_reshaped = out_image.detach().cpu().numpy().squeeze(0).transpose(1, 2, 3, 0)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "f6f395d2",
   "metadata": {},
   "outputs": [],
   "source": [
    "out_reshaped.shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "42e36fc5",
   "metadata": {},
   "outputs": [],
   "source": [
    "difference = np.power(display_input.detach().cpu().numpy().squeeze(0).transpose(1, 2, 3, 0) - out_reshaped, 2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "f3575df9",
   "metadata": {
    "scrolled": false
   },
   "outputs": [],
   "source": [
    "display_image_grid2(display_input.detach().cpu().numpy().squeeze(0).transpose(1, 2, 3, 0), difference)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "dd846366",
   "metadata": {
    "scrolled": false
   },
   "outputs": [],
   "source": [
    "display_image_grid(out_reshaped)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "93bb5172",
   "metadata": {
    "scrolled": false
   },
   "outputs": [],
   "source": [
    "display_image_grid(display_input.detach().cpu().numpy().squeeze(0).transpose(1, 2, 3, 0))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "3685617d",
   "metadata": {},
   "outputs": [],
   "source": [
    "train_loss, t_comp_out, t_latent_dim, train_out, _, _ = test(unet, train_loader2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "54838f0f",
   "metadata": {},
   "outputs": [],
   "source": [
    "validation_dataset2 = CustomDataset(validation_set_rb, validation_set_rb, normal = True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "61460ec6",
   "metadata": {},
   "outputs": [],
   "source": [
    "validation_loader2 = DataLoader(validation_dataset2, batch_size = 1, shuffle = False)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "37ed0b59",
   "metadata": {},
   "outputs": [],
   "source": [
    "validation_loss2, val_comp_out, val_latent_dim, validation_out, _, _ = test(unet, validation_loader2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "d53f3a5a",
   "metadata": {},
   "outputs": [],
   "source": [
    "abnormal_dataset2 = CustomDataset(abnormal_set_rb, abnormal_set_rb, normal = False)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "af07dd97",
   "metadata": {},
   "outputs": [],
   "source": [
    "abnormal_loader2 = DataLoader(abnormal_dataset2, batch_size = 1, shuffle = False)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "315c478b",
   "metadata": {},
   "outputs": [],
   "source": [
    "abnormal_loss2, ab_comp_out, ab_latent_dim, abnormal_out, _, _ = test(unet, abnormal_loader2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "d4bdff76",
   "metadata": {},
   "outputs": [],
   "source": [
    "def graphic_detection(output_made, color, margin = 1, alpha = 1):\n",
    "    plt.figure(figsize = (20, 6))\n",
    "    plt.ylim(-1, 1)\n",
    "    #plt.xlim(1800, 17000)\n",
    "    line = margin\n",
    "\n",
    "    \n",
    "    for i in range(len(output_made)):\n",
    "        diff = np.array(output_made[i]) #- np.array(output_real[i])\n",
    "        print(len(diff))\n",
    "        print(f'mean: {np.mean(diff)}')\n",
    "        print(f'std: {np.std(diff)}')\n",
    "    \n",
    "        for j in range(diff.shape[0]):\n",
    "            plt.plot(list(range(diff.shape[1])), diff[j])#, color = color[i], alpha = alpha[i])\n",
    "    \n",
    "    plt.axhline(0, color = 'black', linestyle = 'solid')\n",
    "    plt.axhline(margin, color = 'black', linestyle = 'dashed')\n",
    "    plt.axhline(-margin, color = 'black', linestyle = 'dashed')\n",
    "    #plt.ylim(-0.25, 0.25)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "9d3aa0ff",
   "metadata": {},
   "outputs": [],
   "source": [
    "with open('220831_output_set276_e100_8-DOl9191923-1best.pickle', 'wb') as s:\n",
    "    pickle.dump((train_out, validation_out, abnormal_out, train_set, validation_set, abnormal_set, train_loss, validation_loss2, abnormal_loss2), s)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "60035d71",
   "metadata": {},
   "outputs": [],
   "source": [
    "margin =21630\n",
    "\n",
    "print(np.where(np.array(abnormal_loss2) < margin))\n",
    "print(np.where(np.array(validation_loss2) > margin))\n",
    "print(np.where(np.array(train_loss) > margin))\n",
    "\n",
    "plt.figure(figsize = (20, 10))\n",
    "plt.scatter(list(range(0, len(validation_set))), validation_loss2, color = 'g')\n",
    "plt.scatter(list(range(0, len(abnormal_set))), abnormal_loss2, color = 'r')\n",
    "plt.scatter(list(range(0, len(train_set))), train_loss, color = 'b')\n",
    "plt.axhline(margin, color = 'k', linestyle = 'dotted')\n",
    "\n",
    "print(f'Epoch # of Minimal loss: {np.argmin(total_losses)}, Loss: {min(total_losses)}')\n",
    "print(f'Anomaly detection rate: {sum(np.array(abnormal_loss2) > margin)/len(abnormal_loader.dataset)}')\n",
    "print(f'Validation accuracy rate: {sum(np.array(validation_loss2) <= margin)/len(validation_loader.dataset)}')\n",
    "print(f'Train accuracy rate: {sum(np.array(train_loss) <= margin)/len(train_loader.dataset)}')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "4b0060ce",
   "metadata": {},
   "outputs": [],
   "source": [
    "#torch.save({\n",
    "#    'epoch': epoch,\n",
    "#    'model_state_dict': unet.state_dict(),\n",
    "#    'optimizer_state_dict': optimizer.state_dict(),\n",
    "#    'loss': train_loss\n",
    "#}, './220831_VAE_Maxpool276_100epochs_64_8-DOl9191923-3best_938873.pt')\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "0704983f",
   "metadata": {},
   "outputs": [],
   "source": [
    "#unet = Unet(latent_dim).to(device)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "5d7123f5",
   "metadata": {},
   "outputs": [],
   "source": [
    "#optimizer = optim.Adam(unet.parameters(), lr = 1e-3)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "204f2e9a",
   "metadata": {},
   "outputs": [],
   "source": [
    "#checkpoint = torch.load('./220831_VAE_Maxpool276_100epochs_64_8-DOl9191923-3best_938873.pt')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "1a6de3c5",
   "metadata": {},
   "outputs": [],
   "source": [
    "#unet.load_state_dict(checkpoint['model_state_dict'])\n",
    "#optimizer.load_state_dict(checkpoint['optimizer_state_dict'])\n",
    "#epoch = checkpoint['epoch']\n",
    "#total_losses = checkpoint['loss']"
   ]
  }
 ],
 "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.8.12"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
