{"cells":[{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"cell_type":"code","source":"import numpy as np, pandas as pd, os\nimport matplotlib.pyplot as plt\nimport glob\nimport datetime\nimport torch\nimport torchvision.transforms as transforms\nfrom torch import nn\nfrom torch.nn import functional as F\n\nimport pydicom\nimport vtk\nfrom vtk.util import numpy_support\n\nfrom pydicom import dcmread\nfrom tqdm import tqdm\nimport cv2\nimport gc\nimport pickle\n\nstartTime = datetime.datetime.now()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Codes from this cell are adopted from Quadcore/Richard Epstein public notebook\n# This notebook loads GDCM without Internet access.\n# GDCM is needed to read some DICOM compressed images.\n# Once you run a notebook and get the GDCM error, you must restart that Kernel to read the files, even if you load the GDCM software.\n# Note that you do not \"import GDCM\". You just \"import pydicom\".\n# The Dataset (gdcm-conda-install) was provided by Ronaldo S.A. Batista. Definitely deserves an upvote!\n\n!cp ../input/gdcm-conda-install/gdcm.tar .\n!tar -xvzf gdcm.tar\n!conda install --offline ./gdcm/gdcm-2.8.9-py37h71b2a6d_0.tar.bz2\n\nprint(\"GDCM installed.\")\n\nimport pydicom","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"dataDirPath = '../input/rsna-str-pulmonary-embolism-detection/'\nmodelDirPath = '../input/firstbaselinemodel/'\n\ntestDataDF = pd.read_csv(dataDirPath+'test.csv', dtype={'StudyInstanceUID':'string', 'SeriesInstanceUID':'string', 'SOPInstanceUID':'string'})\ntestDataDF = testDataDF.set_index('SOPInstanceUID')\nprint(testDataDF.head())\n\nDEBUG = (testDataDF.shape[0]==146853)\nDEBUG\nif DEBUG:\n    testDataDF = testDataDF.head(1000)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"listOfStudyID = testDataDF['StudyInstanceUID'].unique()\nprint(len(listOfStudyID))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Helper functions\n\ndef window(img, WL=50, WW=350):\n    upper, lower = WL+WW//2, WL-WW//2\n    X = np.clip(img.copy(), lower, upper)\n    X = X - np.min(X)\n    X = X / np.max(X)\n    X = (X*255.0).astype('uint8')\n    return X\n\ndata_transform = transforms.Compose([\n        transforms.ToTensor(),\n        transforms.Normalize(mean=[0.485, 0.456, 0.406],\n                             std=[0.229, 0.224, 0.225])\n    ])\n\n# Helper functions for inference\ndef dcmDataToImage(dcmData):\n    image = dcmData.pixel_array * int(dcmData.RescaleSlope) + int(dcmData.RescaleIntercept)\n    image = np.stack([window(image, WL=-600, WW=1500),\n                    window(image, WL=40, WW=400),\n                    window(image, WL=100, WW=700)], 2)\n    if image.shape[0] != 512 or image.shape[1] != 512:\n        image = cv2.resize(image, (512,512), interpolation = cv2.INTER_AREA)\n    #image = image.astype(np.float32)\n    return image\n\ndef getVolByVTK(PathDicom):\n    reader = vtk.vtkDICOMImageReader()\n    reader.SetDirectoryName(PathDicom)\n    reader.Update()\n\n    # Load dimensions using `GetDataExtent`\n    _extent = reader.GetDataExtent()\n    ConstPixelDims = [_extent[1]-_extent[0]+1, _extent[3]-_extent[2]+1, _extent[5]-_extent[4]+1]\n\n    # Load spacing values\n    ConstPixelSpacing = reader.GetPixelSpacing()\n\n    # Get the 'vtkImageData' object from the reader\n    imageData = reader.GetOutput()\n    # Get the 'vtkPointData' object from the 'vtkImageData' object\n    pointData = imageData.GetPointData()\n    # Ensure that only one array exists within the 'vtkPointData' object\n    assert (pointData.GetNumberOfArrays()==1)\n    # Get the `vtkArray` (or whatever derived type) which is needed for the `numpy_support.vtk_to_numpy` function\n    arrayData = pointData.GetArray(0)\n\n    # Convert the `vtkArray` to a NumPy array\n    ArrayDicom = numpy_support.vtk_to_numpy(arrayData)\n    # Reshape the NumPy array to 3D using 'ConstPixelDims' as a 'shape'\n    ArrayDicom = ArrayDicom.reshape(ConstPixelDims, order='F')\n    return ArrayDicom\n\n# Helper functions for inference\ndef VTKsliceToImage(VTKvol, index):\n    image = np.flipud(VTKvol[:,:,index].T.copy())\n    image = np.stack([window(image, WL=-600, WW=1500),\n                    window(image, WL=40, WW=400),\n                    window(image, WL=100, WW=700)], 2)\n    if image.shape[0] != 512 or image.shape[1] != 512:\n        image = cv2.resize(image, (512,512), interpolation = cv2.INTER_AREA)\n    #image = image.astype(np.float32)\n    return image\n\ndef chunks(lst, n):\n    \"\"\"Yield successive n-sized chunks from lst.\"\"\"\n    for i in range(0, len(lst), n):\n        yield lst[i:i + n]\n\ndef sortByImgPosHelper(dcmDataDict):\n    return dcmDataDict['img_pos']","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Helper functions to ensure label consistency\n\n#0 Negative for PE \n#1 Indeterminate \n#2 Chronic \n#3 Acute & Chronic \n#4 Central PE \n#5 Left PE \n#6 Right PE \n#7 RV/LV Ratio >= 1 \n#8 RV/LV Ratio < 1\n\n# Methods to ensure there is no logical inconsistency in the predicted labels\n# Supposed you have two numpy arrays, array A for image labels and array B for study lvl labels\n# Use modifyAll(A, B) to adjust the labels to be logically consistent as required for the competition rules\n\ndef negativeOrIndeterminate(imgLvlLabels, stdLvlLabels):\n    workingArray = stdLvlLabels[:2]\n    # Part 1 - only one of negative or indeterminate can be positive\n    # if both Neg and Indeterminate are >0.5, suppress the lower value to <0.49\n    if workingArray[0]>0.5 and workingArray[1]>0.5:\n        minInd = np.argmin(workingArray)\n        workingArray[minInd] = min(workingArray[minInd],0.49)\n    # Part 2 - if either negative or indeterminate is positive, then study is NOT positive, \n    # none of the image level labels can be positive\n    # if Neg or Indeterminate, supress all image level labels to <0.49    \n    if max(workingArray)>0.5:\n        imgLvlLabels[:] = np.minimum(imgLvlLabels,0.49)[:]\n    # Part 3 - if both negative and indeterminate is negative, then study is positive\n    # then at least one of the image has to be positive\n    if max(workingArray)<0.5 and max(imgLvlLabels)<0.5:\n        maxInd = np.argmax(imgLvlLabels)\n        imgLvlLabels[maxInd] = max(imgLvlLabels[maxInd],0.51)  \n    stdLvlLabels[:2] = workingArray\n    return\n\ndef rightLeftCentral(imgLvlLabels, stdLvlLabels):\n    workingArray = stdLvlLabels[4:7]\n    # Part 1 if at least one image level label is positive, one of these has to be positive\n    # if max(image level label) > 0.5, raise the highest level to >0.51\n    if max(imgLvlLabels)>0.5:\n        maxInd = np.argmax(workingArray)\n        workingArray[maxInd] = max(workingArray[maxInd],0.51)\n    else:\n        # Part 2 if all image level label are negative, right left central cannot be positive\n        # else suppress right left central to at most 0.49\n        workingArray[:] = np.minimum(workingArray,0.49)[:]\n    stdLvlLabels[4:7] = workingArray\n    return\n\ndef rv_lv_ratio(imgLvlLabels, stdLvlLabels):\n    workingArray = stdLvlLabels[7:9]\n    # Part 1 if at least one image level label is positive, one of these has to be positive\n    # if max(image level label) > 0.5, raise one of the rv_lv labels to >0.51\n    if max(imgLvlLabels)>0.5:\n        maxInd = np.argmax(workingArray)\n        workingArray[maxInd] = max(workingArray[maxInd],0.51)\n        stdLvlLabels[7:9] = workingArray\n    else:\n    # Part 2 if all image levels are negative, then neither rv_lv labels can be positive\n        workingArray[:] = np.minimum(workingArray,0.49)[:]\n    # Part 2 Both can't be simultaneously positive.only one of the two choices can be positive\n    # if smaller(min) of the two is >0.5, suppress it to 0.49\n    if min(workingArray)>0.5:\n        minInd = np.argmin(workingArray)\n        workingArray[minInd] = min(workingArray[minInd],0.49)\n    stdLvlLabels[7:9] = workingArray\n    return\n\ndef chronicOrAcuteChronic(imgLvlLabels, stdLvlLabels):\n    workingArray = stdLvlLabels[2:4]\n    # Both can't be simultaneously positive.only one of the two choices can be positive\n    if min(workingArray)>0.5:\n        minInd = np.argmin(workingArray)\n        workingArray[minInd] = min(workingArray[minInd],0.49)\n    stdLvlLabels[2:4] = workingArray\n    return\n\ndef modifyAll(imgLvlLabels, stdLvlLabels):\n    negativeOrIndeterminate(imgLvlLabels, stdLvlLabels)\n    rightLeftCentral(imgLvlLabels, stdLvlLabels)\n    rv_lv_ratio(imgLvlLabels, stdLvlLabels)\n    chronicOrAcuteChronic(imgLvlLabels, stdLvlLabels)\n    return","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"INPUT_SIZE = 64\nHIDDEN_SIZE = 32\nNUM_LAYERS = 1\nNUM_CLASSES = 1\n\nclass BiGRU(nn.Module):\n    def __init__(self, input_size, hidden_size, num_layers, num_classes):\n        super(BiGRU, self).__init__()\n        self.hidden_size = hidden_size\n        self.num_layers = num_layers\n        self.GRU = nn.GRU(\n            input_size, hidden_size, num_layers, batch_first=True, bidirectional=True\n        )\n        self.linear1 = nn.Linear(hidden_size*2, hidden_size)\n        self.linear2 = nn.Linear(hidden_size, num_classes)\n        self.linear3 = nn.Linear(hidden_size*2, hidden_size)\n        self.linear4 = nn.Linear(hidden_size, 9)\n\n    def forward(self, x):\n        imageLevelOutputs = []\n        h0 = torch.zeros(self.num_layers * 2, x.size(0), self.hidden_size).cuda()\n        #c0 = torch.zeros(self.num_layers * 2, x.size(0), self.hidden_size).cuda()\n\n        out, h_n = self.GRU(x, h0)\n        \n        for i, out_t in enumerate(out.chunk(out.size(1), dim=1)):\n            out_t = out_t.squeeze(1)\n            out_t = F.relu(self.linear1(out_t))\n            out_t = self.linear2(out_t)\n            imageLevelOutputs += [out_t]\n        imageLevelOutputs = torch.stack(imageLevelOutputs, 1).squeeze(2)\n        \n        h_n = h_n.view(1,-1)\n        studyLevelOutputs = F.relu(self.linear3(h_n))\n        studyLevelOutputs = self.linear4(studyLevelOutputs)\n        \n        return (imageLevelOutputs, studyLevelOutputs)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# List all models here\n\n# CV4\nCNNmodel1_Path = modelDirPath+'CNNmodel_01_epoch1_CV4_20201008_2252_embedder.pth' \nCNNembedderModel1 = torch.load(CNNmodel1_Path) \nCNNembedderModel1.eval();\n\nRNNmodel11_Path = modelDirPath+'CNNmodel_01_epoch1_CV4_20201008_2252_sequence4_20201010_1528.pth'\nRNNmodel11 = torch.load(RNNmodel11_Path) \nRNNmodel11.eval();\n\nRNNmodel12_Path = modelDirPath+'CNNmodel_01_epoch1_CV4_20201008_2252_sequence7_20201022_0539.pth'\nRNNmodel12 = torch.load(RNNmodel12_Path) \nRNNmodel12.eval();\n\nRNNmodel13_Path = modelDirPath+'CNNmodel_01_epoch1_CV4_20201008_2252_sequence5_20201022_0415.pth'\nRNNmodel13 = torch.load(RNNmodel13_Path) \nRNNmodel13.eval();\n\nRNNmodel14_Path = modelDirPath+'CNNmodel_01_epoch1_CV4_20201008_2252_sequence7_20201022_1749.pth'\nRNNmodel14 = torch.load(RNNmodel14_Path) \nRNNmodel14.eval();\n\n# CV0\nCNNmodel2_Path = modelDirPath+'CNNmodel_01_cv0_epoch1_20201014_0012_embedder.pth' \nCNNembedderModel2 = torch.load(CNNmodel2_Path) \nCNNembedderModel2.eval();\n\nRNNmodel21_Path = modelDirPath+'CNNmodel_01_cv0_epoch1_20201014_0012_sequence5_20201020_1653.pth'\nRNNmodel21 = torch.load(RNNmodel21_Path) \nRNNmodel21.eval();\n\nRNNmodel22_Path = modelDirPath+'CNNmodel_01_cv0_epoch1_20201014_0012_sequence8_20201020_2122.pth'\nRNNmodel22 = torch.load(RNNmodel22_Path) \nRNNmodel22.eval();\n\n# CV3\nCNNmodel3_Path = modelDirPath+'CNNmodel_01_cv3_epoch2_20201018_1153_embedder.pth' \nCNNembedderModel3 = torch.load(CNNmodel3_Path) \nCNNembedderModel3.eval();\n\nRNNmodel31_Path = modelDirPath+'CNNmodel_01_cv3_epoch2_20201018_1153_sequence2_20201019_0622.pth'\nRNNmodel31 = torch.load(RNNmodel31_Path) \nRNNmodel31.eval();\n\nRNNmodel32_Path = modelDirPath+'CNNmodel_01_cv3_epoch2_20201018_1153_sequence8_20201023_0529.pth'\nRNNmodel32 = torch.load(RNNmodel32_Path) \nRNNmodel32.eval();\n\n# log regression models\nlogRegModel_indeterminate = pickle.load(open('../input/firstbaselinemodel/logRegModel_indeterminate.sav', 'rb'))\nlogRegModel_chronic_pe = pickle.load(open('../input/firstbaselinemodel/logRegModel_chronic_pe.sav', 'rb'))\nlogRegModel_acute_and_chronic_pe = pickle.load(open('../input/firstbaselinemodel/logRegModel_acute_and_chronic_pe.sav', 'rb'))\nlogRegModel_rv_lv_ratio_gte_1 = pickle.load(open('../input/firstbaselinemodel/logRegModel_rv_lv_ratio_gte_1.sav', 'rb'))\nlogRegModel_rv_lv_ratio_lt_1 = pickle.load(open('../input/firstbaselinemodel/logRegModel_rv_lv_ratio_lt_1.sav', 'rb'))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Study level labels\nlistOfMetricLabels = ['negative_exam_for_pe', 'indeterminate',\n                        'chronic_pe', 'acute_and_chronic_pe',\n                        'central_pe', 'leftsided_pe', 'rightsided_pe',\n                        'rv_lv_ratio_gte_1', 'rv_lv_ratio_lt_1']\n\ndefaultScore = {'pe_present_on_image': 0.053915069524414806,\n                 'negative_exam_for_pe': 0.6763928618101033,\n                 'rv_lv_ratio_gte_1': 0.12875001256566257,\n                 'rv_lv_ratio_lt_1': 0.17437230326919448,\n                 'leftsided_pe': 0.21089872969528548,\n                 'chronic_pe': 0.040139752506710064,\n                 'rightsided_pe': 0.2575653665766779,\n                 'acute_and_chronic_pe': 0.019458347341720122,\n                 'central_pe': 0.054468517151291695,\n                 'indeterminate': 0.020484822355039723}\n\nq_weighted_means = [0.00326324, 0.05970682, 0.32645303, 0.67452216, 0.71344817, 0.4734337, 0.0740926, 0.00369781]\nsliceBins = [0/8, 1/8, 2/8, 3/8, 4/8, 5/8, 6/8, 7/8]\n\ndef getBinnedProb(sliceLoc):\n    thisProb = 0\n    for eachIndex, eachSlice in enumerate(sliceBins):\n        if sliceLoc>=eachSlice:\n            thisProb = q_weighted_means[eachIndex]\n    return(thisProb)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Helper functions\ndef RNNinferenceHelper(RNNmodel, embeddingVol):\n    imageLevelLabels, studyLevelLabels = RNNmodel(embeddingVol)\n    imageLevelLabels = torch.sigmoid(imageLevelLabels).squeeze(0).cpu().detach().numpy()\n    studyLevelLabels = torch.sigmoid(studyLevelLabels).squeeze(0).cpu().detach().numpy()\n    return imageLevelLabels,studyLevelLabels","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"numExceptions = 0\nsubmissionList = []\npred = 0.5","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def inferenceBlock(eachStudyID):\n    thisStudyDF = testDataDF[testDataDF['StudyInstanceUID']==eachStudyID]\n    listOfImageIDs = thisStudyDF.index\n    \n    listOfDcm_dataDict = []\n    for eachImageID in listOfImageIDs:\n        eachImagePath = dataDirPath+'/test/'+thisStudyDF.loc[eachImageID, 'StudyInstanceUID']+'/'+thisStudyDF.loc[eachImageID, 'SeriesInstanceUID']+'/'+eachImageID+'.dcm'\n        dcm_data = dcmread(eachImagePath)\n        img_pos = dcm_data[0x20, 0x32].value[2]\n        listOfDcm_dataDict.append({'imageID':eachImageID, 'dcm_data':dcm_data, 'img_pos':img_pos})\n\n    listOfDcm_dataDict.sort(key=sortByImgPosHelper, reverse=True)\n    tensorChunkIterator = chunks(listOfDcm_dataDict,48)\n\n    embeddingList1 = []\n    embeddingList2 = []\n    embeddingList3 = []\n    for eachChunk in tensorChunkIterator:\n        #torch.cuda.empty_cache()\n        images = [dcmDataToImage(eachImageID['dcm_data']) for eachImageID in eachChunk]\n        images = [eachImage.astype(np.float32) for eachImage in images]\n        listOfTensors = [data_transform(eachImage) for eachImage in images]\n        stackedImagesTensor = torch.stack(listOfTensors, dim=0, out=None)\n        stackedImagesTensor = stackedImagesTensor.cuda()\n        embedding1 = CNNembedderModel1(stackedImagesTensor).detach()\n        embeddingList1.append(embedding1)\n        embedding2 = CNNembedderModel2(stackedImagesTensor).detach()\n        embeddingList2.append(embedding2)\n        embedding3 = CNNembedderModel3(stackedImagesTensor).detach()\n        embeddingList3.append(embedding3)\n\n    embeddingVol1 = torch.cat(embeddingList1, dim=0)\n    embeddingVol1 = embeddingVol1.unsqueeze(0)\n    embeddingVol2 = torch.cat(embeddingList2, dim=0)\n    embeddingVol2 = embeddingVol2.unsqueeze(0)\n    embeddingVol3 = torch.cat(embeddingList3, dim=0)\n    embeddingVol3 = embeddingVol3.unsqueeze(0)\n\n    imageLevelLabels11, studyLevelLabels11 = RNNinferenceHelper(RNNmodel11, embeddingVol1)\n    imageLevelLabels12, studyLevelLabels12 = RNNinferenceHelper(RNNmodel12, embeddingVol1)\n    imageLevelLabels13, studyLevelLabels13 = RNNinferenceHelper(RNNmodel13, embeddingVol1)\n    imageLevelLabels14, studyLevelLabels14 = RNNinferenceHelper(RNNmodel14, embeddingVol1)\n    imageLevelLabels21, studyLevelLabels21 = RNNinferenceHelper(RNNmodel21, embeddingVol2)\n    imageLevelLabels22, studyLevelLabels22 = RNNinferenceHelper(RNNmodel22, embeddingVol2)\n    imageLevelLabels31, studyLevelLabels31 = RNNinferenceHelper(RNNmodel31, embeddingVol3)\n    imageLevelLabels32, studyLevelLabels32 = RNNinferenceHelper(RNNmodel32, embeddingVol3)\n\n    imageLevelLabels = 0.125*imageLevelLabels11 + 0.125*imageLevelLabels12 + 0.125*imageLevelLabels13 + 0.125*imageLevelLabels14 + 0.125*imageLevelLabels21 + 0.125*imageLevelLabels22 + 0.125*imageLevelLabels31 + 0.125*imageLevelLabels32\n    studyLevelLabels = 0.125*studyLevelLabels11 + 0.125*studyLevelLabels12 + 0.125*studyLevelLabels13 + 0.125*studyLevelLabels14 + 0.125*studyLevelLabels21 + 0.125*studyLevelLabels22 + 0.125*studyLevelLabels31 + 0.125*studyLevelLabels32\n    \n    studyLevelLabels_copy = np.copy(studyLevelLabels)\n    studyLevelLabels_copy = studyLevelLabels_copy[np.newaxis,:]\n    studyLevelLabels[1] = logRegModel_indeterminate.predict_proba(studyLevelLabels_copy)[0,1]\n    studyLevelLabels[2] = logRegModel_chronic_pe.predict_proba(studyLevelLabels_copy)[0,1]\n    studyLevelLabels[3] = logRegModel_acute_and_chronic_pe.predict_proba(studyLevelLabels_copy)[0,1]\n    studyLevelLabels[7] = logRegModel_rv_lv_ratio_gte_1.predict_proba(studyLevelLabels_copy)[0,1]\n    studyLevelLabels[8] = logRegModel_rv_lv_ratio_lt_1.predict_proba(studyLevelLabels_copy)[0,1]\n    \n    modifyAll(imageLevelLabels, studyLevelLabels)\n    \n    # imageLevelLabels\n    for eachIndex in range(len(listOfDcm_dataDict)):\n        submissionList.append([listOfDcm_dataDict[eachIndex]['imageID'], imageLevelLabels[eachIndex]])\n\n    # studyLevelLavels\n    for eachIndex, eachMetric in enumerate(listOfMetricLabels):\n        submissionList.append([eachStudyID+'_'+eachMetric, studyLevelLabels[eachIndex]])\n    return\n\ndef contingencyPlanB(eachStudyID):\n    # Contingency plan B\n    thisStudyDF = testDataDF[testDataDF['StudyInstanceUID']==eachStudyID]\n    listOfImageIDs = thisStudyDF.index\n\n    listOfDcm_dataDict = []\n    for eachImageID in listOfImageIDs:\n        eachImagePath = dataDirPath+'/test/'+thisStudyDF.loc[eachImageID, 'StudyInstanceUID']+'/'+thisStudyDF.loc[eachImageID, 'SeriesInstanceUID']+'/'+eachImageID+'.dcm'\n        dcm_data = dcmread(eachImagePath)\n        img_pos = dcm_data[0x20, 0x32].value[2]\n        listOfDcm_dataDict.append({'imageID':eachImageID, 'dcm_data':dcm_data, 'img_pos':img_pos})\n\n    listOfDcm_dataDict.sort(key=sortByImgPosHelper, reverse=True)\n\n    imageLevelLabels = np.full(len(listOfImageIDs), defaultScore['pe_present_on_image'])\n    studyLevelLabels = np.zeros(len(listOfMetricLabels))\n    for eachIndex in range(len(listOfDcm_dataDict)):\n        thisSliceLoc = eachIndex/(len(listOfDcm_dataDict)-1)\n        imageLevelLabels[eachIndex] = getBinnedProb(thisSliceLoc)\n    for eachIndex, eachMetric in enumerate(listOfMetricLabels):\n        studyLevelLabels[eachIndex] = defaultScore[eachMetric]\n    \n    modifyAll(imageLevelLabels, studyLevelLabels)\n    # imageLevelLabels\n    for eachIndex in range(len(listOfDcm_dataDict)):\n        submissionList.append([listOfDcm_dataDict[eachIndex]['imageID'], imageLevelLabels[eachIndex]])\n\n    # studyLevelLavels\n    for eachIndex, eachMetric in enumerate(listOfMetricLabels):\n        submissionList.append([eachStudyID+'_'+eachMetric, studyLevelLabels[eachIndex]])\n    return\n\ndef contingencyPlanC(eachStudyID):\n    global numExceptions\n    numExceptions += 1\n    # Contingency plan C\n    thisStudyDF = testDataDF[testDataDF['StudyInstanceUID']==eachStudyID]\n    listOfImageIDs = thisStudyDF.index\n    imageLevelLabels = np.full(len(listOfImageIDs), defaultScore['pe_present_on_image'])\n    studyLevelLabels = np.zeros(len(listOfMetricLabels))\n    for eachIndex, eachMetric in enumerate(listOfMetricLabels):\n        studyLevelLabels[eachIndex] = defaultScore[eachMetric]\n    \n    modifyAll(imageLevelLabels, studyLevelLabels)\n    # imageLevelLabels\n    for eachImageIDs in listOfImageIDs:\n        submissionList.append([eachImageIDs, imageLevelLabels[eachIndex]])\n\n    # studyLevelLavels\n    for eachIndex, eachMetric in enumerate(listOfMetricLabels):\n        submissionList.append([eachStudyID+'_'+eachMetric, studyLevelLabels[eachIndex]])\n    return\n\nwith torch.no_grad():\n    for eachStudyID in listOfStudyID:\n        gc.collect()\n        try:\n            try: \n                inferenceBlock(eachStudyID)\n            except:\n                contingencyPlanB(eachStudyID)\n        except:\n            contingencyPlanC(eachStudyID)\n        \nsubmissionDF = pd.DataFrame(submissionList, columns = ['id','label'])\nsubmissionDF.fillna(0.5)\nprint('finish')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"print(len(submissionDF))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def check_consistency(sub, test):\n    \n    '''\n    Checks label consistency and returns the errors\n    \n    Args:\n    sub   = submission dataframe (pandas)\n    test  = test.csv dataframe (pandas)\n    '''\n    \n    # EXAM LEVEL\n    for i in test['StudyInstanceUID'].unique():\n        df_tmp = sub.loc[sub.id.str.contains(i, regex = False)].reset_index(drop = True)\n        df_tmp['StudyInstanceUID'] = df_tmp['id'].str.split('_').str[0]\n        df_tmp['label_type']       = df_tmp['id'].str.split('_').str[1:].apply(lambda x: '_'.join(x))\n        del df_tmp['id']\n        if i == test['StudyInstanceUID'].unique()[0]:\n            df = df_tmp.copy()\n        else:\n            df = pd.concat([df, df_tmp], axis = 0)\n    df_exam = df.pivot(index = 'StudyInstanceUID', columns = 'label_type', values = 'label')\n    \n    # IMAGE LEVEL\n    df_image = sub.loc[sub.id.isin(test.SOPInstanceUID)].reset_index(drop = True)\n    df_image = df_image.merge(test, how = 'left', left_on = 'id', right_on = 'SOPInstanceUID')\n    df_image.rename(columns = {\"label\": \"pe_present_on_image\"}, inplace = True)\n    del df_image['id']\n    \n    # MERGER\n    df = df_exam.merge(df_image, how = 'left', on = 'StudyInstanceUID')\n    ids    = ['StudyInstanceUID', 'SeriesInstanceUID', 'SOPInstanceUID']\n    labels = [c for c in df.columns if c not in ids]\n    df = df[ids + labels]\n    \n    # SPLIT NEGATIVE AND POSITIVE EXAMS\n    df['positive_images_in_exam'] = df['StudyInstanceUID'].map(df.groupby(['StudyInstanceUID']).pe_present_on_image.max())\n    df_pos = df.loc[df.positive_images_in_exam >  0.5]\n    df_neg = df.loc[df.positive_images_in_exam <= 0.5]\n    \n    # CHECKING CONSISTENCY OF POSITIVE EXAM LABELS\n    rule1a = df_pos.loc[((df_pos.rv_lv_ratio_lt_1  >  0.5)  & \n                         (df_pos.rv_lv_ratio_gte_1 >  0.5)) | \n                        ((df_pos.rv_lv_ratio_lt_1  <= 0.5)  & \n                         (df_pos.rv_lv_ratio_gte_1 <= 0.5))].reset_index(drop = True)\n    rule1a['broken_rule'] = '1a'\n    rule1b = df_pos.loc[(df_pos.central_pe    <= 0.5) & \n                        (df_pos.rightsided_pe <= 0.5) & \n                        (df_pos.leftsided_pe  <= 0.5)].reset_index(drop = True)\n    rule1b['broken_rule'] = '1b'\n    rule1c = df_pos.loc[(df_pos.acute_and_chronic_pe > 0.5) & \n                        (df_pos.chronic_pe           > 0.5)].reset_index(drop = True)\n    rule1c['broken_rule'] = '1c'\n    rule1d = df_pos.loc[(df_pos.indeterminate        > 0.5) | \n                        (df_pos.negative_exam_for_pe > 0.5)].reset_index(drop = True)\n    rule1d['broken_rule'] = '1d'\n\n    # CHECKING CONSISTENCY OF NEGATIVE EXAM LABELS\n    rule2a = df_neg.loc[((df_neg.indeterminate        >  0.5)  & \n                         (df_neg.negative_exam_for_pe >  0.5)) | \n                        ((df_neg.indeterminate        <= 0.5)  & \n                         (df_neg.negative_exam_for_pe <= 0.5))].reset_index(drop = True)\n    rule2a['broken_rule'] = '2a'\n    rule2b = df_neg.loc[(df_neg.rv_lv_ratio_lt_1     > 0.5) | \n                        (df_neg.rv_lv_ratio_gte_1    > 0.5) |\n                        (df_neg.central_pe           > 0.5) | \n                        (df_neg.rightsided_pe        > 0.5) | \n                        (df_neg.leftsided_pe         > 0.5) |\n                        (df_neg.acute_and_chronic_pe > 0.5) | \n                        (df_neg.chronic_pe           > 0.5)].reset_index(drop = True)\n    rule2b['broken_rule'] = '2b'\n    \n    # MERGING INCONSISTENT PREDICTIONS\n    errors = pd.concat([rule1a, rule1b, rule1c, rule1d, rule2a, rule2b], axis = 0)\n    \n    # OUTPUT\n    print('Found', len(errors), 'inconsistent predictions')\n    return errors","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"print('numExceptions:', numExceptions)\n\ntest  = pd.read_csv(dataDirPath+'test.csv')\nconsistencyErrors = check_consistency(submissionDF, test)\n\n#if numExceptions < 50 and len(consistencyErrors) == 0: \nsubmissionDF.to_csv('submission.csv', index=False)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"endTime = datetime.datetime.now()\nprint(endTime-startTime)","execution_count":null,"outputs":[]}],"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":4,"nbformat_minor":4}