{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"pygments_lexer":"ipython3","nbconvert_exporter":"python","version":"3.6.4","file_extension":".py","codemirror_mode":{"name":"ipython","version":3},"name":"python","mimetype":"text/x-python"}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"# For the metric\nclass AverageMeter(object):\n    def __init__(self):\n        self.sum = 0\n        self.n = 0\n\n    def update(self, x, n=1):\n        self.sum += float(x)\n        self.n += n\n\n    def reset(self):\n        self.sum = 0\n        self.n = 0\n\n    def get_value(self):\n        if self.n:\n            return self.sum / self.n\n        return 0","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import torch\nimport torch.nn as nn\nimport torch.nn.functional as F\n# from DefineDataset import RandomOpt\n\ndef get_model_parameters(model):\n    total_parameters = 0\n    for layer in list(model.parameters()):\n        layer_parameter = 1\n        for l in list(layer.size()):\n            layer_parameter *= l\n        total_parameters += layer_parameter\n    return total_parameters\n\n\ndef _weights_init(m):\n    if isinstance(m, nn.Conv2d):\n        torch.nn.init.xavier_uniform_(m.weight)\n        if m.bias is not None:\n            torch.nn.init.zeros_(m.bias)\n    elif isinstance(m, nn.BatchNorm2d):\n        m.weight.data.fill_(1)\n        m.bias.data.zero_()\n    elif isinstance(m, nn.Linear):\n        n = m.weight.size(1)\n        m.weight.data.normal_(0, 0.01)\n        m.bias.data.zero_()\n\n\nclass h_sigmoid(nn.Module):\n    def __init__(self, inplace=True):\n        super(h_sigmoid, self).__init__()\n        self.inplace = inplace\n\n    def forward(self, x):\n        return F.relu6(x + 3., inplace=self.inplace) / 6.\n\n\nclass h_swish(nn.Module):\n    def __init__(self, inplace=True):\n        super(h_swish, self).__init__()\n        self.inplace = inplace\n\n    def forward(self, x):\n        out = F.relu6(x + 3., self.inplace) / 6.\n        return out * x\n\n\ndef _make_divisible(v, divisor=8, min_value=None):\n    if min_value is None:\n        min_value = divisor\n    new_v = max(min_value, int(v + divisor / 2) // divisor * divisor)\n    # Make sure that round down does not go down by more than 10%.\n    if new_v < 0.9 * v:\n        new_v += divisor\n    return new_v\n\n\nclass SqueezeBlock(nn.Module):\n    def __init__(self, exp_size, divide=4):\n        super(SqueezeBlock, self).__init__()\n        self.dense = nn.Sequential(\n            nn.Linear(exp_size, exp_size // divide),\n            nn.ReLU(inplace=True),\n            nn.Linear(exp_size // divide, exp_size),\n            h_sigmoid()\n        )\n\n    def forward(self, x):\n        batch, channels, height, width = x.size()\n        out = F.avg_pool2d(x, kernel_size=[height, width]).view(batch, -1)\n        out = self.dense(out)\n        out = out.view(batch, channels, 1, 1)\n        # out = hard_sigmoid(out)\n\n        return out * x\n\n\nclass MobileBlock(nn.Module):\n    def __init__(self, in_channels, out_channels, kernal_size, stride, nonLinear, SE, exp_size):\n        super(MobileBlock, self).__init__()\n        self.out_channels = out_channels\n        self.nonLinear = nonLinear\n        self.SE = SE\n        padding = (kernal_size - 1) // 2\n\n        self.use_connect = stride == 1 and in_channels == out_channels\n\n        if self.nonLinear == \"RE\":\n            activation = nn.ReLU\n        else:\n            activation = h_swish\n\n        self.conv = nn.Sequential(\n            nn.Conv2d(in_channels, exp_size, kernel_size=1, stride=1, padding=0, bias=False),\n            nn.BatchNorm2d(exp_size),\n            activation(inplace=True)\n        )\n        self.depth_conv = nn.Sequential(\n            nn.Conv2d(exp_size, exp_size, kernel_size=kernal_size, stride=stride, padding=padding, groups=exp_size),\n            nn.BatchNorm2d(exp_size),\n        )\n\n        if self.SE:\n            self.squeeze_block = SqueezeBlock(exp_size)\n\n        self.point_conv = nn.Sequential(\n            nn.Conv2d(exp_size, out_channels, kernel_size=1, stride=1, padding=0),\n            nn.BatchNorm2d(out_channels),\n            activation(inplace=True)\n        )\n\n    def forward(self, x):\n        # MobileNetV2\n        out = self.conv(x)\n        out = self.depth_conv(out)\n\n        # Squeeze and Excite\n        if self.SE:\n            out = self.squeeze_block(out)\n\n        # point-wise conv\n        out = self.point_conv(out)\n\n        # connection\n        if self.use_connect:\n            return x + out\n        else:\n            return out\n\n\nclass MobileNetV3(nn.Module):\n    def __init__(self, model_mode=\"LARGE\", num_classes=1000, multiplier=1.0, dropout_rate=0.0):\n        super(MobileNetV3, self).__init__()\n        self.num_classes = num_classes\n\n        if model_mode == \"LARGE\":\n            # layers = [\n            #     [16, 16, 3, 1, \"RE\", False, 16],\n            #     [16, 24, 3, 2, \"RE\", False, 64],\n            #     [24, 24, 3, 1, \"RE\", False, 72],\n            #     [24, 40, 5, 2, \"RE\", True, 72],\n            #     [40, 40, 5, 1, \"RE\", True, 120],\n            #\n            #     [40, 40, 5, 1, \"RE\", True, 120],\n            #     [40, 80, 3, 2, \"HS\", False, 240],\n            #     [80, 80, 3, 1, \"HS\", False, 200],\n            #     [80, 80, 3, 1, \"HS\", False, 184],\n            #     [80, 80, 3, 1, \"HS\", False, 184],\n            #\n            #     [80, 112, 3, 1, \"HS\", True, 480],\n            #     [112, 112, 3, 1, \"HS\", True, 672],\n            #     [112, 160, 5, 1, \"HS\", True, 672],\n            #     [160, 160, 5, 2, \"HS\", True, 672],\n            #     [160, 160, 5, 1, \"HS\", True, 960],\n            # ]\n\n            layers = [\n                [16, 16, 3, 1, \"RE\", False, 16],\n                [16, 24, 3, 1, \"RE\", False, 64],\n                [24, 24, 3, 1, \"RE\", False, 72],\n                [24, 40, 5, 1, \"RE\", True, 72],\n                [40, 40, 5, 1, \"RE\", True, 120],\n\n                [40, 40, 5, 1, \"RE\", True, 120],\n                [40, 80, 3, 1, \"HS\", False, 240],\n                [80, 80, 3, 1, \"HS\", False, 200],\n                [80, 80, 3, 1, \"HS\", False, 184],\n                [80, 80, 3, 1, \"HS\", False, 184],\n\n                [80, 112, 3, 1, \"HS\", True, 480],\n                [112, 112, 3, 1, \"HS\", True, 672],\n                [112, 160, 5, 1, \"HS\", True, 672],\n                [160, 160, 5, 1, \"HS\", True, 672],\n                [160, 160, 5, 1, \"HS\", True, 960],\n            ]\n            init_conv_out = _make_divisible(16 * multiplier)\n            print(f\"init_conv_out={init_conv_out}\")\n            self.init_conv = nn.Sequential(\n                nn.Conv2d(in_channels=RandomOpt().Z_DIM, out_channels=init_conv_out, kernel_size=3, stride=2, padding=1),\n                nn.BatchNorm2d(init_conv_out),\n                h_swish(inplace=True),\n            )\n\n            self.block = []\n            for in_channels, out_channels, kernal_size, stride, nonlinear, se, exp_size in layers:\n                in_channels = _make_divisible(in_channels * multiplier)\n                out_channels = _make_divisible(out_channels * multiplier)\n                exp_size = _make_divisible(exp_size * multiplier)\n                self.block.append(MobileBlock(in_channels, out_channels, kernal_size, stride, nonlinear, se, exp_size))\n            self.block = nn.Sequential(*self.block)\n\n            out_conv1_in = _make_divisible(160 * multiplier)\n            out_conv1_out = _make_divisible(960 * multiplier)\n            self.out_conv1 = nn.Sequential(\n                nn.Conv2d(out_conv1_in, out_conv1_out, kernel_size=1, stride=1),\n                nn.BatchNorm2d(out_conv1_out),\n                h_swish(inplace=True),\n            )\n\n            out_conv2_in = _make_divisible(960 * multiplier)\n            out_conv2_out = _make_divisible(1280 * multiplier)\n            self.out_conv2 = nn.Sequential(\n                nn.Conv2d(out_conv2_in, out_conv2_out, kernel_size=1, stride=1),\n                h_swish(inplace=True),\n                nn.Dropout(dropout_rate),\n                nn.Conv2d(out_conv2_out, self.num_classes, kernel_size=1, stride=1),\n            )\n\n        elif model_mode == \"SMALL\":\n            # layers = [\n            #     [16, 16, 3, 2, \"RE\", True, 16],\n            #     [16, 24, 3, 2, \"RE\", False, 72],\n            #     [24, 24, 3, 1, \"RE\", False, 88],\n            #     [24, 40, 5, 2, \"RE\", True, 96],\n            #     [40, 40, 5, 1, \"RE\", True, 240],\n            #     [40, 40, 5, 1, \"RE\", True, 240],\n            #     [40, 48, 5, 1, \"HS\", True, 120],\n            #     [48, 48, 5, 1, \"HS\", True, 144],\n            #     [48, 96, 5, 2, \"HS\", True, 288],\n            #     [96, 96, 5, 1, \"HS\", True, 576],\n            #     [96, 96, 5, 1, \"HS\", True, 576],\n            # ]\n\n            layers = [\n                [16, 16, 3, 1, \"RE\", True, 16],\n                [16, 24, 3, 1, \"RE\", False, 72],\n                [24, 24, 3, 1, \"RE\", False, 88],\n                [24, 40, 5, 1, \"RE\", True, 96],\n                [40, 40, 5, 1, \"RE\", True, 240],\n                [40, 40, 5, 1, \"RE\", True, 240],\n                [40, 48, 5, 1, \"HS\", True, 120],\n                [48, 48, 5, 1, \"HS\", True, 144],\n                [48, 96, 5, 1, \"HS\", True, 288],\n                [96, 96, 5, 1, \"HS\", True, 576],\n                [96, 96, 5, 1, \"HS\", True, 576],\n            ]\n\n            init_conv_out = _make_divisible(16 * multiplier)\n            self.init_conv = nn.Sequential(\n                nn.Conv2d(in_channels=RandomOpt().Z_DIM, out_channels=init_conv_out, kernel_size=3, stride=2, padding=1),\n                nn.BatchNorm2d(init_conv_out),\n                h_swish(inplace=True),\n            )\n\n            self.block = []\n            for in_channels, out_channels, kernal_size, stride, nonlinear, se, exp_size in layers:\n                in_channels = _make_divisible(in_channels * multiplier)\n                out_channels = _make_divisible(out_channels * multiplier)\n                exp_size = _make_divisible(exp_size * multiplier)\n                self.block.append(MobileBlock(in_channels, out_channels, kernal_size, stride, nonlinear, se, exp_size))\n            self.block = nn.Sequential(*self.block)\n\n            out_conv1_in = _make_divisible(96 * multiplier)\n            out_conv1_out = _make_divisible(576 * multiplier)\n            self.out_conv1 = nn.Sequential(\n                nn.Conv2d(out_conv1_in, out_conv1_out, kernel_size=1, stride=1),\n                SqueezeBlock(out_conv1_out),\n                nn.BatchNorm2d(out_conv1_out),\n                h_swish(inplace=True),\n            )\n\n            out_conv2_in = _make_divisible(576 * multiplier)\n            out_conv2_out = _make_divisible(1280 * multiplier)\n            self.out_conv2 = nn.Sequential(\n                nn.Conv2d(out_conv2_in, out_conv2_out, kernel_size=1, stride=1),\n                h_swish(inplace=True),\n                nn.Dropout(dropout_rate),\n                nn.Conv2d(out_conv2_out, self.num_classes, kernel_size=1, stride=1),\n            )\n\n\n        self.my_out_conv2 = nn.Sequential(\n            # out_size = (in_size - 1) * stride + Kernel - 2*padding + output_padding\n            # output_padding一般取stride-1，同时padding取 (kernel_size - 1)/2\n            # nn.ConvTranspose2d(out_conv2_in, self.num_classes, kernel_size=4, stride=2, padding=1, dilation=1)\n            nn.ConvTranspose2d(out_conv2_in, self.num_classes, kernel_size=3, stride=2, padding=1, dilation=1, output_padding=1)\n\n        )\n        self.apply(_weights_init)\n\n    def forward(self, x):\n        out = self.init_conv(x)\n        out = self.block(out)\n        out = self.out_conv1(out)\n        batch, channels, height, width = out.size()\n        # print(batch, channels, height, width)\n        # out = F.avg_pool2d(out, kernel_size=[height, width])\n        # out = self.out_conv2(out).view(batch, -1)\n        out = self.my_out_conv2(out)\n\n        return out\n\nimport argparse\n\ndef get_args():\n    # args = parser.parse_args()\n    # args = parser.parse_known_args()[0]\n\n\n    parser = argparse.ArgumentParser(\"parameters\")\n\n    parser.add_argument(\"--dataset-mode\", type=str, default=\"IMAGENET\", help=\"(example: CIFAR10, CIFAR100, IMAGENET), (default: IMAGENET)\")\n    parser.add_argument(\"--epochs\", type=int, default=100, help=\"number of epochs, (default: 100)\")\n    parser.add_argument(\"--batch-size\", type=int, default=512, help=\"number of batch size, (default, 512)\")\n    parser.add_argument(\"--learning-rate\", type=float, default=1e-1, help=\"learning_rate, (default: 1e-1)\")\n    parser.add_argument(\"--dropout\", type=float, default=0.8, help=\"dropout rate, not implemented yet, (default: 0.8)\")\n    parser.add_argument('--model-mode', type=str, default=\"LARGE\", help=\"(example: LARGE, SMALL), (default: LARGE)\")\n    parser.add_argument(\"--load-pretrained\", type=bool, default=False, help=\"(default: False)\")\n    parser.add_argument('--evaluate', type=bool, default=False, help=\"Testing time: True, (default: False)\")\n    parser.add_argument('--multiplier', type=float, default=1.0, help=\"(default: 1.0)\")\n    parser.add_argument('--print-interval', type=int, default=5, help=\"training information and evaluation information output frequency, (default: 5)\")\n    # parser.add_argument('--data', default='D:/ILSVRC/Data/CLS-LOC')\n    parser.add_argument('--workers', type=int, default=4)\n    parser.add_argument('--distributed', type=bool, default=False)\n\n\n    args = parser.parse_args(args=[])\n\n    return args","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import numpy as np\nimport torch.utils.data as data\nimport os\nimport PIL.Image as Image\nfrom tqdm import tqdm\nimport glob\nimport torch.nn as nn\nfrom torch import optim\nimport torch\n# from torch.utils.tensorboard import SummaryWriter\n\n\n\n\n# ================== random patch dataset ==============================\nclass RandomOpt():\n    def __init__(self):\n        self.SHARED_HEIGHT = 4096  # Height to resize all papyri RESIZE圖片高度 最後要提交的檔案要resize回來\n#         self.SHARED_HEIGHT = 9000  # Height to resize all papyri RESIZE圖片高度 最後要提交的檔案要resize回來\n        self.BUFFER = 64  # Half-size of papyrus patches we'll use as model inputs 圖片的X/2 Y/2 的值\n        self.Z_DIM = 24 # Number of slices in the z direction. Max value is 64 - Z_START\n        self.Z_START = 8  # Offset of slices in the z direction\n        # self.DATA_DIR = \"D:/work/vesuvius-challenge-ink-detection\"\n        self.DATA_DIR = \"/kaggle/input/vesuvius-challenge-ink-detection\"\n        self.device = torch.device('cuda:0' if torch.cuda.is_available() else 'cpu')\n        self.merge_img = True\n\n\ndef resize(img, SHARED_HEIGHT=RandomOpt().SHARED_HEIGHT):\n    current_width, current_height = img.size\n    aspect_ratio = current_width / current_height\n    new_width = int(SHARED_HEIGHT * aspect_ratio)\n    new_size = (new_width, SHARED_HEIGHT)\n    img = img.resize(new_size)\n    return img\n\n\ndef load_mask(split, index, DATA_DIR=RandomOpt().DATA_DIR):\n    img = Image.open(f\"{DATA_DIR}/{split}/{index}/mask.png\").convert('1')\n    img = resize(img)\n    return torch.from_numpy(np.array(img))\n\ndef load_labels(split, index, DATA_DIR=RandomOpt().DATA_DIR):\n    img = Image.open(f\"{DATA_DIR}/{split}/{index}/inklabels.png\")\n    img = resize(img)\n    return torch.from_numpy(np.array(img)).gt(0).float()\n\ndef load_volume(split, index, DATA_DIR=RandomOpt().DATA_DIR, Z_START=RandomOpt().Z_START, Z_DIM=RandomOpt().Z_DIM):\n    # Load the 3d x-ray scan, one slice at a time\n    z_slices = []\n\n    # 第一版\n    # z_slices_fnames = sorted(glob.glob(f\"{DATA_DIR}/{split}/{index}/surface_volume/*.tif\"))[Z_START:Z_START + Z_DIM]\n    #\n    # for z, filename in tqdm(enumerate(z_slices_fnames),desc='load_volume->'+f\"{DATA_DIR}/{split}/{index}/surface_volume\"):\n    #     img = Image.open(filename)\n    #     img = resize(img)\n    #     z_slice = np.array(img, dtype=\"float32\")\n    #     z_slices.append(torch.from_numpy(z_slice))\n    # tmp = torch.stack(z_slices, dim=0)\n    # 第一版\n\n#     #第2版\n#     images = [Image.open(filename) for filename in\n#         sorted(glob.glob(f\"{RandomOpt().DATA_DIR}/{split}/{index}/surface_volume/*.tif\"))[Z_START:Z_START + Z_DIM]]\n#     z_slices = np.stack([np.array(resize(img), dtype=\"float32\") for img in\n#                          tqdm(images,desc=f\"Loadind {split}/{index}/surface_volume\")],\n#                         axis=0)\n#     tmp = torch.from_numpy(z_slices)\n#     print(f\"finished load_volume shape=({tmp.shape})  from   {DATA_DIR}/{split}/{index}/surface_volume\")\n#     del z_slices,images\n#     gc.collect()\n#     #第2版\n    \n    #第3版\n    z_slices_fnames = sorted(glob.glob(f\"{DATA_DIR}/{split}/{index}/surface_volume/*.tif\"))[Z_START:Z_START + Z_DIM]\n\n    for z, filename in tqdm(enumerate(z_slices_fnames),desc='load_volume->'+f\"{DATA_DIR}/{split}/{index}/surface_volume\"):\n        img = Image.open(filename)\n        img = torch.from_numpy(np.array(resize(img), dtype=\"float32\"))\n        if z ==0:\n            z_slices =img\n        elif z==1:\n            z_slices = torch.stack((z_slices,img),dim=0)\n        else:\n            z_slices=torch.vstack((z_slices,torch.unsqueeze(img,0)))\n        del img\n        gc.collect()\n    return z_slices\n    #第3版\n\n    return tmp\n\n\n# Random choice of patches for training\ndef sample_random_location(shape, BUFFER=RandomOpt().BUFFER):\n    a=BUFFER\n    random_train_x = (shape[0] - BUFFER - 1 - a)*torch.rand(1)+a\n    random_train_y = (shape[1] - BUFFER - 1 - a)*torch.rand(1)+a\n    random_train_location = torch.stack([random_train_x, random_train_y])\n    return random_train_location\n\ndef is_in_masked_zone(location, mask):\n    return mask[location[0].long(), location[1].long()]\n\ndef is_in_val_zone(location, val_location, val_zone_size, BUFFER=RandomOpt().BUFFER):\n    x = location[0]\n    y = location[1]\n    x_match = val_location[0] - BUFFER <= x <= val_location[0] + val_zone_size[0] + BUFFER\n    y_match = val_location[1] - BUFFER <= y <= val_location[1] + val_zone_size[1] + BUFFER\n    return x_match and y_match\n\nclass RandomPatchLocDataset(data.Dataset):\n    def __init__(self, mask, val_location, val_zone_size):\n        self.mask = mask\n        self.val_location = val_location\n        self.val_zone_size = val_zone_size\n        self.sample_random_location_train = lambda x: sample_random_location(mask.shape)\n        self.is_in_mask_train = lambda x: is_in_masked_zone(x, mask)\n\n    def is_proper_train_location(self, location):\n        # 不在 VAL的範圍 在MASK的範圍\n        return not is_in_val_zone(location, self.val_location, self.val_zone_size) and self.is_in_mask_train(location)\n\n    def __len__(self):\n        return 1280\n\n    def __getitem__(self, index):\n        # Generate a random patch\n        # Ignore the index\n        loc = self.sample_random_location_train(0)\n        while not self.is_proper_train_location(loc):\n            #錯誤就換一個\n            loc = self.sample_random_location_train(0)\n        return loc.int().squeeze(1)","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# from DefineDataset import *\nimport matplotlib.pyplot as plt\nfrom skimage.transform import resize as resize_ski\nimport PIL.Image as Image\n# from MobileNet_v3 import *\n# from torchsummary import summary\nimport gc\n# import websockets\n# websockets.connect(uri, ping_timeout = 60)\n\n\n\n\n# ============= Model ==============\nclass ModelOpt:\n    def __init__(self):\n        self.GPU_ID = '0'\n        self.Z_DIM = RandomOpt().Z_DIM\n        self.BUFFER = RandomOpt().BUFFER\n        self.SEED = 0\n        self.BATCH_SIZE = 20 #每次輸入的立方體取樣個數  input data shape=  [self.BATCH_SIZE, self.Z_DIM ,self.BUFFER*2 , self.BUFFER*2]\n        self.LEARNING_RATE =1e-4\n        self.TRAINING_EPOCH = 30\n#         self.LOG_DIR = r'D:\\work\\vesuvius-challenge-ink-detection'\n        self.LOG_DIR = r'/kaggle/working/'\n        self.LOAD_VOLUME = [1,2,3,1,2,3] #讀取幾類樣本\n        # Val\n        self.VAL_LOC = (1300, 1000) # 取VAL圖片的起始點\n        self.VAL_SIZE = (300, 7000) # VAL圖片的大小  高:1300~1600, 寬:1000~8000\n        self.merge_img = True\n        self.LOAD_VOLUME = np.unique(self.LOAD_VOLUME) if self.merge_img else self.LOAD_VOLUME #要合併圖片的話 每種讀一次就好\n        print(f\"self.merge_img = {self.merge_img}  and self.LOAD_VOLUME={self.LOAD_VOLUME}\")\n\n\nclass RandomPatchModel():\n    def __init__(self,compute_predictions_map_flag=False,opt = ModelOpt()):\n        self.opt = opt\n        self._setup_all()\n        self.compute_predictions_map_flag=compute_predictions_map_flag\n        # self.net = UNet(in_ch=opt.Z_DIM).to(self.device)\n        self.net = MobileNetV3(model_mode=\"SMALL\", num_classes=1, multiplier=args.multiplier,\n                               dropout_rate=args.dropout).to(self.device)\n\n    def load_data(self,LOAD_VOLUME=ModelOpt().LOAD_VOLUME):\n        print(f'load_data with LOAD_VOLUME={LOAD_VOLUME}')\n        # 依照LOAD_VOLUME載入TrainDataset\n        # VAL_LOC重新定義\n        if not self.compute_predictions_map_flag:\n            self.volume_list = [load_volume('train', i) for i in LOAD_VOLUME]\n            print(f\"volume_list len={len(self.volume_list) } and shape of values = {self.volume_list[0].shape} \")\n            # Here volume: [Z_DIM, SHARED_HEIGHT, W_V1 + W_V2 + ...]\n            self.volume = torch.cat(self.volume_list, dim=2)\n            print(f\"Finial volume Shape = {self.volume.shape }\")\n            self.opt.VAL_LOC = (round(self.volume.shape[1] / 2), 0)  # 取VAL圖片的起始點\n            self.opt.VAL_SIZE = (300, round(self.volume.shape[2])-1)  # VAL圖片的大小  高:, 寬:\n            # Same for mask and label\n            self.mask_list = [load_mask('train', i) for i in LOAD_VOLUME]\n            print(f\"mask_list len={len(self.mask_list) } and shape of values = {self.mask_list[0].shape} \")\n            self.mask = torch.cat(self.mask_list, dim=1)\n            print(f\"mask Shape = {self.mask.shape}\")\n            self.labels_list = [load_labels('train', i) for i in LOAD_VOLUME]\n            print(f\"labels_list len={len(self.labels_list) } and shape of values = {self.labels_list[0].shape} \")\n            # [SHARED_HEIGHT, W_V1 + W_V2 + ...]\n            self.labels = torch.cat(self.labels_list, dim=1)\n            print(f\"labels Shape = {self.labels.shape }\")\n\n            # Dataset\n            self.loc_datast = RandomPatchLocDataset(self.mask, val_location= self.opt.VAL_LOC, val_zone_size= self.opt.VAL_SIZE)\n            self.loc_loader = data.DataLoader(self.loc_datast, batch_size= self.opt.BATCH_SIZE)\n            # Val\n            self.val_loc = []\n            for x in range( self.opt.VAL_LOC[0],  self.opt.VAL_LOC[0] +  self.opt.VAL_SIZE[0],  self.opt.BUFFER): # VAL圖片 每個圖片的中心點\n                for y in range( self.opt.VAL_LOC[1],  self.opt.VAL_LOC[1] +  self.opt.VAL_SIZE[1],  self.opt.BUFFER):\n                    if is_in_masked_zone([torch.tensor(x),torch.tensor(y)], self.mask): # VAL圖片是否在MASK之內\n                        self.val_loc.append([[x, y]])\n            print(f\"\\n======> Num of  Patches for Val: {len(self.val_loc)}\")\n\n\n    def _setup_all(self):\n        # random seed\n        np.random.seed(self.opt.SEED)\n        torch.manual_seed(self.opt.SEED)\n        torch.cuda.manual_seed_all(self.opt.SEED)\n        # torch\n        # os.environ['CUDA_VISIBLE_DEVICES'] = self.opt.GPU_ID\n        torch.backends.cudnn.enabled = True\n        torch.backends.cudnn.benchmark = True\n        self.device=torch.device('cuda:0' if torch.cuda.is_available() else 'cpu')\n        print(f\"self.device={self.device}\")\n        # Log\n        self.log_dir = self.opt.LOG_DIR\n        self.ckpt = os.path.join(self.log_dir)\n\n    def get_subvolume(self, batch_loc, volume, labels):\n        # batch_loc = [[X中心點,Y中心點],[X中心點,Y中心點],[X中心點,Y中心點]......]\n        # batch_loc : [batch_size, 2]\n        subvolume = []\n        label = []\n        for l in batch_loc:\n            x = l[0]\n            y = l[1]\n            sv = volume[:, x - self.opt.BUFFER:x + self.opt.BUFFER, y - self.opt.BUFFER:y + self.opt.BUFFER]\n            sv = sv / 65535.\n            subvolume.append(sv)\n            if labels is not None:\n                lb = labels[x - self.opt.BUFFER:x + self.opt.BUFFER, y - self.opt.BUFFER:y + self.opt.BUFFER]\n                lb = lb.unsqueeze(0)\n                label.append(lb)\n        # [batch, Z_DIM, BUFFER, BUFFER]\n        subvolume = torch.stack(subvolume)\n        # [batch, 1, BUFFER, BUFFER]\n        if labels is not None:\n            label = torch.stack(label)\n        return subvolume, label\n\n    def augment_train_data(self, subvolume, label):\n        # Add Data augmentation here\n        return subvolume, label\n    def train_loop(self,merge_img=ModelOpt().merge_img):\n        print(\"=====> Begin training\")\n        self.criterion = torch.nn.BCEWithLogitsLoss(reduction='mean')\n        self.optimizer = optim.Adam(self.net.parameters(), lr=self.opt.LEARNING_RATE)\n        self.net.train()\n\n        best_val_loss = 100\n        best_val_acc = 0\n        meter = AverageMeter()\n\n        if merge_img: #一次讀多種img合併\n            self.load_data()  # 重新定義資料集\n#             print(f\"Shape of Train data = {self.volume.shape}\")\n#             print(f\"Shape of Train label = {self.label.shape}\")\n            for epoch in range(self.opt.TRAINING_EPOCH):\n                bar = tqdm(enumerate(self.loc_loader), total=len(self.loc_datast) / self.opt.BATCH_SIZE)\n                bar.set_description_str(f\"Epoch: {epoch}\")\n                for i, loc in bar:\n                    # loc 是取樣本的起始點 [x,y]  = RandomPatchLocDataset的輸出\n                    subvolume, label = self.get_subvolume(loc, self.volume, self.labels)  # 取出樣本以及他的labels\n                    loss = self._train_step(subvolume.to(self.device), label)\n                    meter.update(loss)\n                    bar.set_postfix_str(f\"Avg loss: {np.round(meter.get_value(), 3)}\")\n\n                val_loss, val_acc = self.validataion_loop()\n                print(f\"======> Val Loss:{np.round(val_loss, 3)} | Val Acc:{np.round(val_acc, 3)} \")\n                if val_loss < best_val_loss and val_acc > best_val_acc:\n                    torch.save(self.net.state_dict(), os.path.join(self.ckpt, \"best.pt\"))\n                    print(\"======> Save best val model\")\n\n                    best_val_loss = val_loss\n                    best_val_acc = val_acc\n\n            del self.loc_datast\n            del self.loc_loader\n            del self.labels\n            del self.labels_list\n            del self.mask\n            del self.mask_list\n            del self.volume\n            del self.volume_list\n            del self.val_loc\n            gc.collect()\n        else:\n            #一次讀一種IMG\n            for dataset_count in self.opt.LOAD_VOLUME:\n                self.load_data(LOAD_VOLUME=[dataset_count]) # 重新定義資料集\n                # self.validataion_figplt()  #劃出Val區域\n                # 每個dataset跑TRAINING_EPOCH個跌代\n                for epoch in range(self.opt.TRAINING_EPOCH):\n                    bar = tqdm(enumerate(self.loc_loader), total=len(self.loc_datast) / self.opt.BATCH_SIZE)\n                    bar.set_description_str(f\"Epoch: {epoch}\")\n                    for i, loc in bar:\n                        # loc 是取樣本的起始點 [x,y]  = RandomPatchLocDataset的輸出\n                        subvolume, label = self.get_subvolume(loc, self.volume, self.labels) #取出樣本以及他的labels\n                        # print(subvolume.shape)\n                        # print(label.shape)\n                        loss = self._train_step(subvolume.to(self.device), label)\n                        meter.update(loss)\n                        bar.set_postfix_str(f\"Avg loss: {np.round(meter.get_value(),3)}\")\n\n                    val_loss, val_acc = self.validataion_loop()\n                    print(f\"======> Val Loss:{np.round(val_loss,3)} | Val Acc:{np.round(val_acc,3)} \")\n                    if val_loss < best_val_loss and val_acc > best_val_acc:\n                        torch.save(self.net.state_dict(), os.path.join(self.ckpt, \"best.pt\"))\n                        print(\"======> Save best val model\")\n\n                        best_val_loss = val_loss\n                        best_val_acc = val_acc\n\n                del self.loc_datast\n                del self.loc_loader\n                del self.labels\n                del self.labels_list\n                del self.mask\n                del self.mask_list\n                del self.volume\n                del self.volume_list\n                del self.val_loc\n                gc.collect()\n\n    def _train_step(self, subvolume, label):\n        self.optimizer.zero_grad()\n        # inputs: subvolume: [batch, Z_DIM, BUFFER, BUFFER]\n        #         label: [batch, 1, BUFFER, BUFFER]\n#         print(f\"subvolume={subvolume.shape}\")\n        outputs = self.net(subvolume)\n        # print(f\"Train outputs={outputs.shape}\")\n        # plt.imshow(outputs.detach().numpy()[0][0])\n        # plt.show()\n        loss = self.criterion(outputs, label.to(self.device))\n        loss.backward()\n        self.optimizer.step()\n        return loss\n\n    def validataion_loop(self,only_val=False):\n        meter_loss = AverageMeter()\n        meter_acc = AverageMeter()\n        self.net.eval()\n\n        if only_val:\n            print(f\"validataion_loop  only_val\")\n            self.load_data(LOAD_VOLUME=[1,2,3])\n#             self.validataion_figplt()  #劃出Val區域\n\n            for loc in self.val_loc:\n                subvolume, label = self.get_subvolume(loc, self.volume, self.labels)\n                outputs = self.net(subvolume.to(self.device))\n                loss = self.criterion(outputs, label.to(self.device))\n                meter_loss.update(loss)\n                pred = torch.sigmoid(outputs) > 0.5\n                meter_acc.update(\n                    (pred == label.to(self.device)).sum(),\n                    int(torch.prod(torch.tensor(label.shape)))\n                )\n\n            del self.loc_datast\n            del self.loc_loader\n            del self.labels\n            del self.labels_list\n            del self.mask\n            del self.mask_list\n            del self.volume\n            del self.volume_list\n            del self.val_loc\n            gc.collect()\n\n        else:\n            for loc in self.val_loc:\n                subvolume, label = self.get_subvolume(loc, self.volume, self.labels)\n                outputs = self.net(subvolume.to(self.device))\n                loss = self.criterion(outputs, label.to(self.device))\n                meter_loss.update(loss)\n                pred = torch.sigmoid(outputs) > 0.5\n                meter_acc.update(\n                    (pred == label.to(self.device)).sum(),\n                    int(torch.prod(torch.tensor(label.shape)))\n                )\n            self.net.train()\n            # Train那邊會釋放RAM\n        return meter_loss.get_value(), meter_acc.get_value()\n\n    def validataion_figplt(self):\n\n        fig = plt.figure()\n        ax = fig.add_subplot(1, 1, 1)\n        # rect = patches.Rectangle(upleft, width, height, linewidth=0.3, edgecolor='r',\n        #                          facecolor='none')  # facecolor：填充颜色\n\n        rect = plt.Rectangle((self.opt.VAL_LOC[1], self.opt.VAL_LOC[0]), self.opt.VAL_SIZE[1], self.opt.VAL_SIZE[0], fill=False, edgecolor='red', linewidth=1)\n        ax.add_patch(rect)\n        font = {'color': 'red',\n                'size': 20,\n                'family': 'Times New Roman'}\n        plt.text(0.1, 0.1, \"validataion Area\", fontdict=font)\n        plt.imshow(self.volume[0])\n        plt.show()\n\n    def load_best_ckpt(self,Test=False):\n        if Test:\n            self.net.load_state_dict(torch.load(\"/kaggle/input/load-best-test/best.pt\"))\n        else:\n            self.net.load_state_dict(torch.load(os.path.join(self.ckpt, \"best.pt\")))\n\n\n\ndef compute_predictions_map(split, index):\n    print(f\"======> Load data from {split}/{index}\")\n    test_volume = load_volume(split=split, index=index)\n    print(f\"======> load_mask from {split}/{index}\")\n    test_mask = load_mask(split=split, index=index)\n    print(f\"======> Volume shape: {test_volume.shape}\")\n    test_locations = []\n    BUFFER = model.opt.BUFFER\n    stride = BUFFER // 2\n\n    for x in range(BUFFER, test_volume.shape[1] - BUFFER, stride):\n        for y in range(BUFFER, test_volume.shape[2] - BUFFER, stride):\n            if is_in_masked_zone([torch.tensor(x),torch.tensor(y)], test_mask):\n                test_locations.append((x, y))\n    print(f\"======> {len(test_locations)} test locations (after filtering by mask)\")\n\n    predictions_map = torch.zeros((1, 1, test_volume.shape[1], test_volume.shape[2]))\n    predictions_map_counts = torch.zeros((1, 1, test_volume.shape[1], test_volume.shape[2]))\n    print(f\"======> Compute predictions\")\n\n    with torch.no_grad():\n        bar = tqdm(test_locations,desc='compute_predictions_map->'+f\"{DATA_DIR}/{split}/{index}:\")\n        for loc in bar:\n#             print(f\"test_volume = {test_volume.shape}\")\n            subvolume, label = model.get_subvolume([loc], test_volume, None)\n            outputs = model.net(subvolume.to(model.device))\n            pred = torch.sigmoid(outputs)\n            # print(f\"pred = {pred}\")\n            # print(loc, (pred > 0.5).sum())\n            # Here a single location may be with multiple result\n            # predictions_map 是4D 第一是BatchSize 第2維是通道 最後兩維可想成圖片\n            # 因為stride = BUFFER // 2 所以會有某些點做不只一次 predictions_map會相加 predictions_map_counts計算被加幾次來做平均\n            predictions_map[:, :, loc[0] - BUFFER : loc[0] + BUFFER, loc[1] - BUFFER : loc[1] + BUFFER] += pred.cpu()\n            predictions_map_counts[:, :, loc[0] - BUFFER : loc[0] + BUFFER, loc[1] - BUFFER : loc[1] + BUFFER] += 1\n#             print(f\"predictions_map = {predictions_map.shape}\")\n#             print(f\"predictions_map_counts = {predictions_map_counts.shape}\")\n            del subvolume\n            del outputs\n            del pred\n            gc.collect()\n\n\n    # print(predictions_map_b[:,:, 2500, 1000])\n    # print(predictions_map_counts[:,:, 2500, 1000])\n    predictions_map /= (predictions_map_counts + 1e-7)\n    return predictions_map\n\ndef rle(predictions_map, threshold):\n    flat_img = predictions_map.flatten()\n    flat_img = np.where(flat_img > threshold, 1, 0).astype(np.uint8)\n\n    starts = np.array((flat_img[:-1] == 0) & (flat_img[1:] == 1))\n    ends = np.array((flat_img[:-1] == 1) & (flat_img[1:] == 0))\n    starts_ix = np.where(starts)[0] + 2\n    ends_ix = np.where(ends)[0] + 2\n    lengths = ends_ix - starts_ix\n    return \" \".join(map(str, sum(zip(starts_ix, lengths), ())))\n\n\n\n\n\nif __name__ == '__main__':\n    #\n    Image.MAX_IMAGE_PIXELS = None\n    torch.cuda.empty_cache()\n    args = get_args()\n    DATA_DIR = RandomOpt().DATA_DIR\n    threshold_a = 0.10\n    threshold_b = 0.10\n    \n\n    \n    #Train\n    model = RandomPatchModel(compute_predictions_map_flag=False)\n# #     print(summary(model.net, (RandomOpt().Z_DIM, 128,128)))\n    model.train_loop()\n\n    # Validation\n#     Load the best model\n    model.load_best_ckpt()\n    model.net.eval()\n    model.criterion = torch.nn.BCEWithLogitsLoss(reduction='mean')\n    loss, acc = model.validataion_loop(only_val=True)\n    print(f\"Val loss: {np.round(loss, 3)} | Val acc: {np.round(acc, 3)}\")\n\n\n    predictions_map_a = compute_predictions_map(split=\"test\", index=\"a\")\n    plt.imshow(predictions_map_a.squeeze() > threshold_a, cmap='gray')\n    original_size_a = Image.open(DATA_DIR + \"/test/a/mask.png\").size\n    print(f\"original_size_a={original_size_a}\")\n    print(\"Do predictions_map_a\")\n    predictions_map_a = resize_ski(predictions_map_a.squeeze(), original_size_a).squeeze()\n    print(\"Do rle_a\")\n    rle_a = rle(predictions_map_a, threshold=threshold_a)\n    del predictions_map_a\n    del original_size_a\n    gc.collect()\n\n    predictions_map_b = compute_predictions_map(split=\"test\", index=\"b\")\n    plt.imshow(predictions_map_b.squeeze() > threshold_b, cmap='gray')\n    original_size_b = Image.open(DATA_DIR + \"/test/b/mask.png\").size\n    print(f\"original_size_b={original_size_b}\")\n    print(\"Do predictions_map_a\")\n    predictions_map_b = resize_ski(predictions_map_b.squeeze(), original_size_b).squeeze()\n    print(\"Do rle_b\")\n    rle_b = rle(predictions_map_b, threshold=threshold_b)\n    del predictions_map_b\n    del original_size_b\n    gc.collect()\n    \n    print(\"Id,Predicted\\na,\" + rle_a + \"\\nb,\" + rle_b, file=open('/kaggle/working/submission.csv', 'w'))\n# #     print(\"Id,Predicted\\na,\" + rle_a + \"\\nb,\" + rle_b, file=open(r'D:\\work\\vesuvius-challenge-ink-detection\\submission.csv', 'w'))","metadata":{},"execution_count":null,"outputs":[]}]}