{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.10.12","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"gpu","dataSources":[{"sourceId":45867,"databundleVersionId":6924515,"sourceType":"competition"},{"sourceId":7018227,"sourceType":"datasetVersion","datasetId":4035429}],"dockerImageVersionId":30580,"isInternetEnabled":false,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"# This Python 3 environment comes with many helpful analytics libraries installed\n# It is defined by the kaggle/python Docker image: https://github.com/kaggle/docker-python\n# For example, here's several helpful packages to load\n\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\n\n# Input data files are available in the read-only \"../input/\" directory\n# For example, running this (by clicking run or pressing Shift+Enter) will list all files under the input directory\ntest_df = pd.read_csv(\"/kaggle/input/UBC-OCEAN/test.csv\")\n# import os\n# for dirname, _, filenames in os.walk('/kaggle/input'):\n#     for filename in filenames:\n#         print(os.path.join(dirname, filename))\n\n# You can write up to 20GB to the current directory (/kaggle/working/) that gets preserved as output when you create a version using \"Save & Run All\" \n# You can also write temporary files to /kaggle/temp/, but they won't be saved outside of the current session","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2023-11-21T11:42:09.138011Z","iopub.execute_input":"2023-11-21T11:42:09.138275Z","iopub.status.idle":"2023-11-21T11:42:09.502763Z","shell.execute_reply.started":"2023-11-21T11:42:09.138249Z","shell.execute_reply":"2023-11-21T11:42:09.501841Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from glob import glob  \nimport os \nimport itertools\nimport numpy as np\nimport cv2 \nimport openslide\nimport pandas as pd\nimport time \nfrom openslide import ImageSlide, open_slide\nfrom openslide.deepzoom import DeepZoomGenerator\nfrom PIL import Image, ImageFilter, ImageStat\nfrom tqdm import tqdm \nfrom PIL import ImageFile\nImageFile.LOAD_TRUNCATED_IMAGES = True\nImage.MAX_IMAGE_PIXELS = None\nimport torch\n# import models_vit\nfrom collections import defaultdict\nimport torchvision.transforms as transforms\nimport torchvision.transforms.functional as VF\nfrom torch.utils.data import DataLoader\nimport argparse\nimport sys\nfrom timm.models.vision_transformer import VisionTransformer\n\n\n# The path can also be read from a config file, etc.\nOPENSLIDE_PATH = r\"D:\\UBC-OCSC\\openslide-win64-20220806\\bin\"\n\nimport os\nif hasattr(os, 'add_dll_directory'):\n    # Python >= 3.8 on Windows\n    with os.add_dll_directory(OPENSLIDE_PATH):\n        import openslide\nelse:\n    import openslide\n    \npatchs = []\nindexs = []\n\ndef color_filter(img):\n\n    img = cv2.cvtColor(np.asarray(img),cv2.COLOR_RGB2BGR)\n    hsv = cv2.cvtColor(img,cv2.COLOR_BGR2HSV)\n    lower = np.array([125,44,47],dtype='uint8')\n    upper = np.array([180,255,255],dtype='uint8')\n    mask = cv2.inRange(hsv,lower,upper)\n    # output = cv2.bitwise_and(img, img, mask = mask)\n\n    return np.sum(mask) > 50*255\n\ndef get_multiscale_coor(dz):\n    patchs_per_png = []\n    level = len(dz.level_tiles)-1\n    for col in range(2,dz.level_tiles[-1][0]-2):\n        for row in range(2, dz.level_tiles[-1][1]-2):\n                tile = dz.get_tile(level, (col,row))\n#                 print(type(tile))\n#                 edge = tile.filter(ImageFilter.FIND_EDGES)\n#                 edge = ImageStat.Stat(edge).sum\n#                 edge = np.mean(edge)/(224**2)\n#                 w, h = tile.size\n#                 if edge > 15:\n#                 tile.save(f'/kaggle/temp/test/patchs/{slide_idx}/20x_{col}_{row}.jpg')\n                patchs_per_png.append(np.array(tile))\n    return np.array(patchs_per_png)\n\n\ndef main(args):\n#     os.makedirs('/kaggle/temp/test/patch_pos',exist_ok=True)\n    target_dir = args.target_dir\n    PATCH_SIZE = 224\n    slides = []\n    model = vit_small(pretrained=True, progress=False, key=\"DINO_p16\", patch_size=16)\n    os.makedirs(target_dir, exist_ok=True)\n    model = model.cuda()\n    model.eval()\n    for slide_idx in test_df.image_id:\n#         slide_idx = slide_dir.split(os.sep)[-1].replace('.png', '')\n        slide_dir = os.path.join(r'/kaggle/input/UBC-OCEAN/test_images',str(slide_idx) + '.png')\n#         os.makedirs(f'/kaggle/temp/test/patchs/{slide_idx}',exist_ok=True)\n        slide = open_slide(slide_dir)\n        dz = DeepZoomGenerator(slide, PATCH_SIZE, overlap=0, limit_bounds=True)\n        patchs_per_png = get_multiscale_coor(dz)\n        compute_feats(args,patchs_per_png, slide_idx, model,target_dir)\n\n\nclass BagDataset():\n    def __init__(self, patchs_per_png, transform=None):\n        self.patchs_per_png = patchs_per_png\n        self.transform = transform\n\n    def __len__(self):\n        return len(self.patchs_per_png)\n\n    def __getitem__(self, idx):\n        temp_patchs = self.patchs_per_png[idx]\n        img = Image.fromarray(np.uint8(temp_patchs))\n        # sample = {'input': img}\n\n        if self.transform:\n            sample = self.transform(img)\n        return sample\n\n\ndef bag_dataset(args, patchs_per_png):\n    \n    transformed_dataset = BagDataset(patchs_per_png=patchs_per_png,\n                                     transform=transforms.Compose([\n                                         transforms.ToTensor(),\n                                         transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])])\n                                         )\n    dataloader = DataLoader(transformed_dataset, batch_size=args.batch_size,\n                            shuffle=False, num_workers=args.num_workers, drop_last=False)\n    return dataloader, len(transformed_dataset)\n\n\ndef compute_feats(args, patchs_per_png, slide_idx, model, save_path=None):\n#         slide_idx = bags_list[i].split(os.sep)[-1\n        feats_list = []\n#         if args.scale == 'multiscale':\n#             csv_file_path = glob(os.path.join(\n#                 bags_list[i], '*.jpg')) + glob(os.path.join(bags_list[i], '*.jpeg'))\n#         else:\n#             csv_file_path = glob(os.path.join(\n#                 bags_list[i], f'{args.scale}*.jpg')) + glob(os.path.join(bags_list[i], f'{args.scale}*.jpeg'))\n        dataloader, bag_size = bag_dataset(args, patchs_per_png)\n        with torch.no_grad():\n            for iteration, batch in enumerate(dataloader):\n                patches = batch.float().cuda()\n                # feats = model.forward_features(patches)\n                feats = model(patches)\n                # print(feats.shape)\n                feats = feats.cpu().numpy()\n                # print(feats.shape)\n                for feat in feats:\n                    feats_list.extend([feat])\n                # sys.stdout.write(\n                #     '\\r Computed: {}/{} -- {}/{}'.format(i+1, num_bags, iteration+1, len(dataloader)))\n        if len(feats_list) == 0:\n            print('No valid patch extracted from: ' + bags_list[i])\n        else:\n            df = pd.DataFrame(feats_list)\n            # print(len(feats_list))\n            # print(len(feats_list[0]))\n            # print(df.shape)\n            # os.makedirs(os.path.join(save_path, bags_list[i].split(\n            #     os.path.sep)[-2]), exist_ok=True)\n            df.to_csv(os.path.join(save_path, str(slide_idx) + '.csv'), index=False, float_format='%.8f',header=False)\n\n\n\n\n\ndef vit_small(pretrained, progress, key, **kwargs):\n    patch_size = kwargs.get(\"patch_size\", 16)\n    model = VisionTransformer(\n        img_size=224, patch_size=patch_size, embed_dim=384, num_heads=6, num_classes=0\n    )\n    if pretrained:\n        pretrained_path = r\"/kaggle/input/dsmil-ckpt2/dino_vit_small_patch16_ep200.torch\"\n        verbose = model.load_state_dict(\n            torch.load(pretrained_path)\n        )\n        print(verbose)\n    return model\n# def main(args):\n   \n#     # extraed features save path\n#     # exam : '../datasets/methods/'\n   \n   \n\ndef get_args_parser():\n    parser = argparse.ArgumentParser('UBC', add_help=False)\n    parser.add_argument('--root', default='/kaggle/temp/test/patchs', type=str,\n                        help='root directory of WSIs')\n    parser.add_argument('--batch_size', default=128, type=int,\n                        help='')\n    parser.add_argument('--num_workers', default=4, type=int,\n                        help='')\n    parser.add_argument('--scale', default='20x', type=str,\n                        help='(options) multiscale / 5x / 10x / 20x')    \n    parser.add_argument('--ckpt', default='../ckpt/mae/msc16_vb_e200/checkpoint199.pth', type=str,\n                        help='Batch size per GPU (effective batch size is batch_size * accum_iter * # gpus')\n    parser.add_argument('--model', default='vit_base_patch16', type=str, metavar='MODEL',\n                        help='Name of model to train')\n    parser.add_argument('--target_dir', default='/kaggle/temp/features', type=str, metavar='MODEL',\n                        help='Name of model to train')\n    parser.add_argument('--dino_module', default='teacher', type=str, metavar='MODEL',\n                        help='Name of model to train')\n    parser.add_argument('--global_pool', action='store_true',\n                        help='switch global pool')\n    return parser\n\n\nif __name__ == '__main__':\n    args = get_args_parser()\n    args = args.parse_args([])\n#     time1 = time.time()\n    main(args)\n#     time2 = time.time()\n#     print('Took %f second' % (time2 - time1))\n\n\n\n    # break\n# if __name__ == '__main__':\n#     time1 = time.time()\n#     main()\n#     time2 = time.time()\n#     print('Took %f second' % (time2 - time1))\n\n    ","metadata":{"execution":{"iopub.status.busy":"2023-11-21T11:42:09.504709Z","iopub.execute_input":"2023-11-21T11:42:09.504988Z","iopub.status.idle":"2023-11-21T11:42:19.833566Z","shell.execute_reply.started":"2023-11-21T11:42:09.504963Z","shell.execute_reply":"2023-11-21T11:42:19.831585Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import torch\nimport torch.nn as nn\nimport torch.nn.functional as F\nfrom torch.autograd import Variable\nimport csv\n\nclass FCLayer(nn.Module):\n    def __init__(self, in_size, out_size=1):\n        super(FCLayer, self).__init__()\n        self.fc = nn.Sequential(nn.Linear(in_size, out_size))\n    def forward(self, feats):\n        x = self.fc(feats)\n        return feats, x\n\nclass IClassifier(nn.Module):\n    def __init__(self, feature_extractor, feature_size, output_class):\n        super(IClassifier, self).__init__()\n        \n        self.feature_extractor = feature_extractor      \n        self.fc = nn.Linear(feature_size, output_class)\n        \n        \n    def forward(self, x):\n        device = x.device\n        feats = self.feature_extractor(x) # N x K\n        c = self.fc(feats.view(feats.shape[0], -1)) # N x C\n        return feats.view(feats.shape[0], -1), c\n\nclass BClassifier(nn.Module):\n    def __init__(self, input_size, output_class, dropout_v=0.0, nonlinear=True, passing_v=False): # K, L, N\n        super(BClassifier, self).__init__()\n        if nonlinear:\n            self.q = nn.Sequential(nn.Linear(input_size, 128), nn.ReLU(), nn.Linear(128, 128), nn.Tanh())\n        else:\n            self.q = nn.Linear(input_size, 128)\n        if passing_v:\n            self.v = nn.Sequential(\n                nn.Dropout(dropout_v),\n                nn.Linear(input_size, input_size),\n                nn.ReLU()\n            )\n        else:\n            self.v = nn.Identity()\n        \n        ### 1D convolutional layer that can handle multiple class (including binary)\n        self.fcc = nn.Conv1d(output_class, output_class, kernel_size=input_size)  \n        \n    def forward(self, feats, c): # N x K, N x C\n        device = feats.device\n        V = self.v(feats) # N x V, unsorted\n        Q = self.q(feats).view(feats.shape[0], -1) # N x Q, unsorted\n        \n        # handle multiple classes without for loop\n        _, m_indices = torch.sort(c, 0, descending=True) # sort class scores along the instance dimension, m_indices in shape N x C\n        m_feats = torch.index_select(feats, dim=0, index=m_indices[0, :]) # select critical instances, m_feats in shape C x K \n        q_max = self.q(m_feats) # compute queries of critical instances, q_max in shape C x Q\n        A = torch.mm(Q, q_max.transpose(0, 1)) # compute inner product of Q to each entry of q_max, A in shape N x C, each column contains unnormalized attention scores\n        A = F.softmax( A / torch.sqrt(torch.tensor(Q.shape[1], dtype=torch.float32, device=device)), 0) # normalize attention scores, A in shape N x C, \n        B = torch.mm(A.transpose(0, 1), V) # compute bag representation, B in shape C x V\n                \n        B = B.view(1, B.shape[0], B.shape[1]) # 1 x C x V\n        C = self.fcc(B) # 1 x C x 1\n        C = C.view(1, -1)\n        return C, A, B \n    \nclass MILNet(nn.Module):\n    def __init__(self, i_classifier, b_classifier):\n        super(MILNet, self).__init__()\n        self.i_classifier = i_classifier\n        self.b_classifier = b_classifier\n        \n    def forward(self, x):\n        feats, classes = self.i_classifier(x)\n        prediction_bag, A, B = self.b_classifier(feats, classes)\n        \n        return classes, prediction_bag, A, B\n        ","metadata":{"execution":{"iopub.status.busy":"2023-11-21T11:42:19.834879Z","iopub.status.idle":"2023-11-21T11:42:19.835248Z","shell.execute_reply.started":"2023-11-21T11:42:19.835072Z","shell.execute_reply":"2023-11-21T11:42:19.835089Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def save_csv_paths(folder_path, output_file):\n    csv_paths = []\n    for root, dirs, files in os.walk(folder_path):\n        for file in files:\n            if file.endswith(\".csv\"):\n                csv_paths.append(os.path.join(root, file).replace(\"\\\\\", \"/\"))\n\n\n    with open(output_file, mode='w', newline='') as f:\n        writer = csv.writer(f)\n        writer.writerow(['File Path'])\n        for path in csv_paths:\n            writer.writerow([path])\n\n# 指定文件夹路径和输出文件路径\nfolder_path = r'/kaggle/temp/features'  \noutput_file = r'/kaggle/temp/test_dfs.csv'  \n\n# 调用函数保存CSV文件路径\nsave_csv_paths(folder_path, output_file)","metadata":{"execution":{"iopub.status.busy":"2023-11-21T11:42:19.836221Z","iopub.status.idle":"2023-11-21T11:42:19.836582Z","shell.execute_reply.started":"2023-11-21T11:42:19.836394Z","shell.execute_reply":"2023-11-21T11:42:19.83641Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import torch\nimport torch.nn as nn\nfrom torch.utils.data import DataLoader, Dataset\nfrom torch.autograd import Variable\nimport torchvision.transforms.functional as VF\nfrom torchvision import transforms\n\nimport sys, argparse, os, copy, itertools, glob, datetime\nimport pandas as pd\nimport numpy as np\nfrom sklearn.utils import shuffle\nfrom sklearn.metrics import roc_curve, roc_auc_score, precision_recall_fscore_support\nfrom sklearn.datasets import load_svmlight_file\nfrom collections import OrderedDict\ndef get_bag_feats(csv_file_df):\n    \n    feats_csv_path = csv_file_df.iloc[0]\n    df = pd.read_csv(feats_csv_path)\n    feats = shuffle(df).reset_index(drop=True)\n    feats = feats.to_numpy()\n        \n    return feats\n\nos.environ['CUDA_VISIBLE_DEVICES']='0'\ni_classifier = FCLayer(in_size=384, out_size=5).cuda()\nb_classifier = BClassifier(input_size=384, output_class=5, dropout_v=0, nonlinear=1).cuda()\nmilnet = MILNet(i_classifier, b_classifier).cuda()\n\nstate_dict_weights = torch.load('/kaggle/input/dsmil-ckpt2/50.pth')\nmilnet.load_state_dict(state_dict_weights, strict=False)\n\n\ntest_feature_df = pd.read_csv('/kaggle/temp/test_dfs.csv')\n# print(test_df)\nmilnet.eval()\n\ntotal_loss = 0\ntest_labels = []\ntest_predictions = []\nTensor = torch.cuda.FloatTensor\n\n\n\n\nwith torch.no_grad():\n    for i in range(len(test_feature_df)):\n        feats = get_bag_feats(test_feature_df.iloc[i])\n        bag_feats = Variable(Tensor(np.array([feats])))\n        bag_feats = bag_feats.view(-1, 384)\n        ins_prediction, bag_prediction, _, _ = milnet(bag_feats)\n        max_prediction, _ = torch.max(ins_prediction, 0)  \n        test_predictions.extend([(0.5*torch.sigmoid(max_prediction)+0.5*torch.sigmoid(bag_prediction)).squeeze().cpu().numpy()])\ntest_predictions = np.array(test_predictions)\n\n\n    \n","metadata":{"execution":{"iopub.status.busy":"2023-11-21T11:42:19.838342Z","iopub.status.idle":"2023-11-21T11:42:19.838813Z","shell.execute_reply.started":"2023-11-21T11:42:19.838566Z","shell.execute_reply":"2023-11-21T11:42:19.838588Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"test_predictions[0]","metadata":{"execution":{"iopub.status.busy":"2023-11-21T11:42:19.84034Z","iopub.status.idle":"2023-11-21T11:42:19.840791Z","shell.execute_reply.started":"2023-11-21T11:42:19.840566Z","shell.execute_reply":"2023-11-21T11:42:19.840589Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"ctg_rvs = { '0':'CC',\n            '1':'EC',\n            '2': 'HGSC',\n            '3': 'LGSC',\n            '4':'MC'}\ntest_label_predictions = []\ntest_predictions_mv = np.max(test_predictions, axis=1)\ntest_predictions_mi = np.argmax(test_predictions, axis=1)\nfor i in range(len(test_predictions)):\n    if test_predictions_mv[i]<0.5:\n        test_label_predictions.append(\"Other\")\n    else: \n        test_label_predictions.append(ctg_rvs[str(test_predictions_mi[i])])\ntest_label_predictions","metadata":{"execution":{"iopub.status.busy":"2023-11-21T11:42:19.84206Z","iopub.status.idle":"2023-11-21T11:42:19.842487Z","shell.execute_reply.started":"2023-11-21T11:42:19.84227Z","shell.execute_reply":"2023-11-21T11:42:19.842291Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#生成最终的结果文件\noutput = pd.DataFrame({'image_id': test_df.image_id, 'label': test_label_predictions})\noutput.to_csv('/kaggle/working/submission.csv', index=False)\n","metadata":{"execution":{"iopub.status.busy":"2023-11-21T11:42:19.844141Z","iopub.status.idle":"2023-11-21T11:42:19.844483Z","shell.execute_reply.started":"2023-11-21T11:42:19.844316Z","shell.execute_reply":"2023-11-21T11:42:19.844333Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}