{"cells":[{"metadata":{},"cell_type":"markdown","source":"# Introduction\n\nSince the mask we have in the labels are mostly in the rectangles (or combination of rectangles) shapes. It is interesting to see that if we post-process the random-shape masks of a segmentation model to rectangle, we can get improved performance or not?\n\nIn this kernel, I show a simple way to post-process all masks to 4 choices of shapes : convex hull, approx. polygon, simple x-y rectangle and minimum-area rectangles. (credit : I took the starter code from bigsnarfdude : https://gist.github.com/bigsnarfdude/d811e31ee17495f82f10db12651ae82d )\n\nThe masks I will post-process came from my good friend Raman's great kernel : https://www.kaggle.com/samusram/cloud-classifier-for-post-processing (which is already post-process from other great kernel of Jan's https://www.kaggle.com/jpbremer/efficient-net-b4-unet-clouds :). \n\nThe convex-hull post-processing currently is the best of 4 choices (not yet test polygon), still having the same LB score as original predicted masks, but with more reasonable shapes. Since this kernel does not need GPU, whenever you are run out of GPU quota you can come here just to have fun. I myself prepared this kernel when I was run out of GPU quota also :)\n\n** UPDATE on V2 : ** Thanks to Ryan @ryches for his insightful suggestions. In V2, the mask touching the black stripe is removed. Additionally, this black-stripe removing process may cause some disconnect small triangle masks. Therefore, in V2, I also apply @artgor min_size remove post-processing. Now LB score improves from V1, but still not beat the original predicted masks (LB.655 vs. 650). Lastly, I add my own version of multi-color masks visualization just for fun.\n\n** UPDATE on V3 : ** Now support the minimum convex-hull that enclosing the predicting mask. This convex-hull performs better than minimum-area rectangle, and got equal score to the original masks.\n\n** UPDATE V5. ** Add approximate polygon post-processing using [Douglas-Peucker algorithm](http://en.wikipedia.org/wiki/Ramer-Douglas-Peucker_algorithm). "},{"metadata":{"_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","trusted":true,"_kg_hide-input":true},"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 in \nimport cv2\nimport os\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\nimport matplotlib.pyplot as plt\n%matplotlib inline\n\nfrom tqdm import tqdm_notebook as tqdm\n\nos.listdir('../input/')\n","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"We begin by reading Raman's output masks (0.655 LB) from his kernel. Or you can change to Jan's masks (0.653LB) if you want to try"},{"metadata":{"_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","trusted":true},"cell_type":"code","source":"sub = pd.read_csv('../input/cloud-classifier-for-post-processing/submission_segmentation_and_classifier.csv') # Raman's masks\n# sub = pd.read_csv('../input/efficient-net-b4-unet-clouds/submission.csv') # Jan's masks","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"We hide standard helper functions such as rle_decode/encode , etc."},{"metadata":{"trusted":true,"_kg_hide-input":true},"cell_type":"code","source":"# helper functions\n# credits: https://www.kaggle.com/artgor/segmentation-in-pytorch-using-convenient-tools\nclass_names = ['Fish', 'Flower', 'Sugar', 'Gravel']\ndef rle_decode(mask_rle: str = '', shape = (1400, 2100)):\n    '''\n    Decode rle encoded mask.\n    \n    :param mask_rle: run-length as string formatted (start length)\n    :param shape: (height, width) of array to return \n    Returns numpy array, 1 - mask, 0 - background\n    '''\n    s = mask_rle.split()\n    starts, lengths = [np.asarray(x, dtype=int) for x in (s[0:][::2], s[1:][::2])]\n    starts -= 1\n    ends = starts + lengths\n    img = np.zeros(shape[0] * shape[1], dtype=np.uint8)\n    for lo, hi in zip(starts, ends):\n        img[lo:hi] = 1\n    \n    return img.reshape(shape, order='F')\n\ndef mask2rle(img):\n    '''\n    Convert mask to rle.\n    img: numpy array, 1 - mask, 0 - background\n    Returns run length as string formated\n    '''\n    pixels= img.T.flatten()\n    pixels = np.concatenate([[0], pixels, [0]])\n    runs = np.where(pixels[1:] != pixels[:-1])[0] + 1\n    runs[1::2] -= runs[::2]\n    return ' '.join(str(x) for x in runs)\n\n\ndef make_mask(df, image_label, shape = (1400, 2100), cv_shape = (525, 350),debug=False):\n    \"\"\"\n    Create mask based on df, image name and shape.\n    \"\"\"\n    if debug:\n        print(shape,cv_shape)\n    df = df.set_index('Image_Label')\n    encoded_mask = df.loc[image_label, 'EncodedPixels']\n#     print('encode: ',encoded_mask[:10])\n    mask = np.zeros((shape[0], shape[1]), dtype=np.float32)\n    if encoded_mask is not np.nan:\n        mask = rle_decode(encoded_mask,shape=shape) # original size\n            \n    return cv2.resize(mask, cv_shape)\n\nmin_size = [10000 ,10000, 10000, 10000]\ndef post_process_minsize(mask, min_size):\n    \"\"\"\n    Post processing of each predicted mask, components with lesser number of pixels\n    than `min_size` are ignored\n    \"\"\"\n    \n    num_component, component = cv2.connectedComponents(mask.astype(np.uint8))\n    predictions = np.zeros(mask.shape)\n    num = 0\n    for c in range(1, num_component):\n        p = (component == c)\n        if p.sum() > min_size:\n            predictions[p] = 1\n            num += 1\n    return predictions #, num","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_kg_hide-input":true},"cell_type":"code","source":"def show_image(image,figsize=None,title=None):\n    \n    if figsize is not None:\n        fig = plt.figure(figsize=figsize)\n#     else: # crash!!\n#         fig = plt.figure()\n        \n    if image.ndim == 2:\n        plt.imshow(image,cmap='gray')\n    else:\n        plt.imshow(image)\n        \n    if title is not None:\n        plt.title(title)\n        \ndef show_Nimages(imgs,scale=1):\n\n    N=len(imgs)\n    fig = plt.figure(figsize=(25/scale, 16/scale))\n    for i, img in enumerate(imgs):\n        ax = fig.add_subplot(1, N, i + 1, xticks=[], yticks=[])\n        show_image(img)\n    plt.show()\n\ndef draw_masks(img2,img_mask_list):\n    \n    img = img2.copy()\n    for ii in range(4): # for each of the 4 masks\n        color_mask = np.zeros(img2.shape)\n        temp_mask = np.ones([img2.shape[0],img2.shape[1]])*127./255.\n        temp_mask[img_mask_list[ii] == 0] = 0\n        if ii < 3: # use different color for each mask\n            color_mask[:,:,ii] = temp_mask\n        else:\n            color_mask[:,:,0],color_mask[:,:,1],color_mask[:,:,2] = temp_mask,temp_mask,temp_mask # broadcasting to 3 channels\n    \n        img += color_mask\n        \n    return img","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"The following function is used to draw a convex-hull where you have four choices : \n\n* Convex Hull, (`mode = 'convex'`)\n* Simple xy-oriented rectangle, (`mode = 'rect'`)\n* Minimum-area rectangle and (`mode = 'min'`)\n* Approximate Polygon using [Douglas-Peucker algorithm](http://en.wikipedia.org/wiki/Ramer-Douglas-Peucker_algorithm) (`mode = 'approx'`)\n\nRef: https://opencv-python-tutroals.readthedocs.io/en/latest/py_tutorials/py_imgproc/py_contours/py_contour_features/py_contour_features.html"},{"metadata":{"trusted":true},"cell_type":"code","source":"def draw_convex_hull(mask, mode='convex'):\n    \n    img = np.zeros(mask.shape)\n    contours, hier = cv2.findContours(mask, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)\n    \n    for c in contours:\n        if mode=='rect': # simple rectangle\n            x, y, w, h = cv2.boundingRect(c)\n            cv2.rectangle(img, (x, y), (x+w, y+h), (255, 255, 255), -1)\n        elif mode=='convex': # minimum convex hull\n            hull = cv2.convexHull(c)\n            cv2.drawContours(img, [hull], 0, (255, 255, 255),-1)\n        elif mode=='approx':\n            epsilon = 0.02*cv2.arcLength(c,True)\n            approx = cv2.approxPolyDP(c,epsilon,True)\n            cv2.drawContours(img, [approx], 0, (255, 255, 255),-1)\n        else: # minimum area rectangle\n            rect = cv2.minAreaRect(c)\n            box = cv2.boxPoints(rect)\n            box = np.int0(box)\n            cv2.drawContours(img, [box], 0, (255, 255, 255),-1)\n    return img/255.","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Convex-Hull Shape\nTo speed up the process a bit, I use @ryches dataset that already preprocess images to 350x525. Below is an example of using the function."},{"metadata":{"trusted":true},"cell_type":"code","source":"mode='convex' # choose from 'rect', 'min', 'convex' and 'approx'\n\n\ntest_imgs_folder = '../input/understanding-clouds-resized/test_images_525/test_images_525'\nNN=5\nfolder_images=test_imgs_folder\nimages_list = ['e0cacb5.jpg', '05fcce5.jpg', 'e949e4b.jpg', 'ce8df6b.jpg', '41be432.jpg'] #os.listdir(folder_images)\ncurrent_batch = images_list[0: NN]\nprint(current_batch)\n\nfor i, image_name in enumerate(current_batch):\n    path = os.path.join(folder_images, image_name)\n    print(path)\n    img = cv2.imread(path).astype(np.float32) # use already-resized ryches' dataset\n    print(img.max(), img.min())\n    img = img/255.\n    \n    img2 = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)\n    img2 = np.stack([img2,img2,img2],axis=-1)\n         \n    img_mask=[]\n    img_mask_convex=[]\n    img_mask_convex_minsize=[]\n    \n    for class_id in range(4):\n        img_mask.append(make_mask(sub, image_name + '_' + class_names[class_id],shape=(350,525)))\n        print(img_mask[class_id].min(), img_mask[class_id].max())\n        img_mask_convex.append(draw_convex_hull(img_mask[class_id].astype(np.uint8), mode=mode))\n        img_mask_convex[class_id][img2[:,:,0]<=2/255.] = 0\n        img_mask_convex_minsize.append(post_process_minsize(img_mask_convex[class_id], min_size[class_id]) )\n    \n    img3 = draw_masks(img2,img_mask)\n    img4 = draw_masks(img2,img_mask_convex_minsize)\n    show_Nimages([img2,img3,img4])\n    show_Nimages(img_mask)\n#     show_Nimages([img2]+img_mask_convex)\n    show_Nimages(img_mask_convex_minsize)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Approximated Polygon Shape (Douglas-Peucker algorithm) "},{"metadata":{"trusted":true},"cell_type":"code","source":"mode='approx' # choose from 'rect', 'min', 'convex' and 'approx'\n\n\ntest_imgs_folder = '../input/understanding-clouds-resized/test_images_525/test_images_525'\nNN=5\nfolder_images=test_imgs_folder\nimages_list = ['e0cacb5.jpg', '05fcce5.jpg', 'e949e4b.jpg', 'ce8df6b.jpg', '41be432.jpg'] #os.listdir(folder_images)\ncurrent_batch = images_list[0: NN]\nprint(current_batch)\n\nfor i, image_name in enumerate(current_batch):\n    path = os.path.join(folder_images, image_name)\n    print(path)\n    img = cv2.imread(path).astype(np.float32) # use already-resized ryches' dataset\n    print(img.max(), img.min())\n    img = img/255.\n    \n    img2 = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)\n    img2 = np.stack([img2,img2,img2],axis=-1)\n         \n    img_mask=[]\n    img_mask_convex=[]\n    img_mask_convex_minsize=[]\n    \n    for class_id in range(4):\n        img_mask.append(make_mask(sub, image_name + '_' + class_names[class_id],shape=(350,525)))\n        print(img_mask[class_id].min(), img_mask[class_id].max())\n        img_mask_convex.append(draw_convex_hull(img_mask[class_id].astype(np.uint8), mode=mode))\n        img_mask_convex[class_id][img2[:,:,0]<=2/255.] = 0\n        img_mask_convex_minsize.append(post_process_minsize(img_mask_convex[class_id], min_size[class_id]) )\n    \n    img3 = draw_masks(img2,img_mask)\n    img4 = draw_masks(img2,img_mask_convex_minsize)\n    show_Nimages([img2,img3,img4])\n    show_Nimages(img_mask)\n#     show_Nimages([img2]+img_mask_convex)\n    show_Nimages(img_mask_convex_minsize)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Post-processing\n\nAfter preparing everything, we convert all masks to the selected-mode rectangle below."},{"metadata":{"trusted":true},"cell_type":"code","source":"model_class_names=['Fish', 'Flower', 'Gravel', 'Sugar']","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"mode='convex' # choose from 'rect', 'min', 'convex' and 'approx'\n\nimg_label_list = []\nenc_pixels_list = []\ntest_imgs = os.listdir(folder_images)\nfor test_img_i, test_img in enumerate(tqdm(test_imgs)):\n    for class_i, class_name in enumerate(model_class_names):\n        \n        path = os.path.join(folder_images, test_img)\n        img = cv2.imread(path).astype(np.float32) # use already-resized ryches' dataset\n        img = img/255.\n        img2 = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)\n        \n        img_label_list.append(f'{test_img}_{class_name}')\n        \n        mask = make_mask(sub, test_img + '_' + class_name,shape=(350,525))\n        if True:\n        #if class_name == 'Flower' or class_name =='Sugar': # you can decide to post-process for some certain classes \n            mask = draw_convex_hull(mask.astype(np.uint8), mode=mode)\n        mask[img2<=2/255.] = 0\n        mask = post_process_minsize(mask, min_size[class_i])\n        \n        if mask.sum() == 0:\n            enc_pixels_list.append(np.nan)\n        else:\n            mask = np.where(mask > 0.5, 1.0, 0.0)\n            enc_pixels_list.append(mask2rle(mask))\n            \nsubmission_df = pd.DataFrame({'Image_Label': img_label_list, 'EncodedPixels': enc_pixels_list})\nsubmission_df.to_csv('sub_convex.csv', index=None)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"sub_test=pd.read_csv('./sub_convex.csv')\nsub_test.head(10)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"'''Uncomment this cell if you want to check that everything works fine'''\n# NN=7\n\n# folder_images=test_imgs_folder\n# images_list = os.listdir(folder_images)\n# current_batch = images_list[0: NN]\n# print(current_batch)\n\n# for i, image_name in enumerate(current_batch):\n#     path = os.path.join(folder_images, image_name)\n#     print(path)\n#     img = cv2.imread(path).astype(np.float32) # use already-resized ryches' dataset\n#     print(img.max(), img.min())\n#     img = img/255.\n    \n#     img2 = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)\n#     img2 = np.stack([img2,img2,img2],axis=-1)\n         \n#     img_mask=[]\n#     img_mask_convex=[]\n#     for class_id in range(4):\n#         img_mask.append(make_mask(sub_test, image_name + '_' + class_names[class_id],shape=(350,525)))\n#         print(img_mask[class_id].min(), img_mask[class_id].max())\n#         img_mask_convex.append(draw_convex_hull(img_mask[class_id].astype(np.uint8)))\n#     show_Nimages([img2]+img_mask)\n#     show_Nimages([img2]+img_mask_convex)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"","execution_count":null,"outputs":[]}],"metadata":{"kernelspec":{"display_name":"Python 3","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.6.6"},"widgets":{"application/vnd.jupyter.widget-state+json":{"state":{"044e08a0cd98438887c34fcafcab0424":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"04f3849aa7be4de588ade37335e3db3a":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HBoxModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HBoxModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HBoxView","box_style":"","children":["IPY_MODEL_beca22b4e98844b2ac251f187706ea56","IPY_MODEL_b7522e6765f34041a228703e4b277889"],"layout":"IPY_MODEL_fc359586abfd495e9ec7fcdb945238c7"}},"072f5ad0f5a54076979db2be10a96b2e":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"09dfede38823413d829b3a604e6d813e":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"IntProgressModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"IntProgressModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"ProgressView","bar_style":"success","description":"","description_tooltip":null,"layout":"IPY_MODEL_b686750ad56d44009cf2c8c984eaf9c7","max":3698,"min":0,"orientation":"horizontal","style":"IPY_MODEL_82343347f18d405a9d99843f8e8cfc06","value":3698}},"417df8b3d7ef4e69947ea90b6601e028":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HTMLModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HTMLModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HTMLView","description":"","description_tooltip":null,"layout":"IPY_MODEL_e43e4cafb019406a858d1bf1ff6ea8c8","placeholder":"​","style":"IPY_MODEL_98fe0f2e755b45cab74b34e43cb04c40","value":"100% 3698/3698 [03:54&lt;00:00, 16.05it/s]"}},"46f79e3c2669493e9f33fad435f98974":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"4b87c123a6224d8aa84e5e8164a42691":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"5043d882529944cf83a54736ea7e5e36":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"5b086863288f40f4a447f3fb2cfe54ba":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"5c71423796ce4961860f9f926530abb5":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"62bb2689084b4eaeb96f3c6c11305044":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HBoxModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HBoxModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HBoxView","box_style":"","children":["IPY_MODEL_09dfede38823413d829b3a604e6d813e","IPY_MODEL_80336f10bfc54fe98909365e457ce322"],"layout":"IPY_MODEL_c5fd4b9ce6e74bb58603a249ac99dd8b"}},"6f45be7215a64837993d0df660f712f3":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"ProgressStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"ProgressStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","bar_color":null,"description_width":""}},"6ff65b2d47e54f03be17364ebc518562":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"73bff161658f45ae890c7e73c24f8911":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HBoxModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HBoxModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HBoxView","box_style":"","children":["IPY_MODEL_bc087e60dc1f4a83bf9b2aef890eba38","IPY_MODEL_c41e596ee4e8466c8577662becb1ba56"],"layout":"IPY_MODEL_bbd27da1dbd14747ad46bf16cda35e0a"}},"78403bbc4e19412f8faa357f1e564718":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HBoxModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HBoxModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HBoxView","box_style":"","children":["IPY_MODEL_c9d96d41728648b693470738b88ea08c","IPY_MODEL_417df8b3d7ef4e69947ea90b6601e028"],"layout":"IPY_MODEL_5c71423796ce4961860f9f926530abb5"}},"80336f10bfc54fe98909365e457ce322":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HTMLModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HTMLModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HTMLView","description":"","description_tooltip":null,"layout":"IPY_MODEL_044e08a0cd98438887c34fcafcab0424","placeholder":"​","style":"IPY_MODEL_a406a8c3e02c4fadaa42ae406f629fcc","value":"100% 3698/3698 [00:00&lt;00:00, 96284.91it/s]"}},"82343347f18d405a9d99843f8e8cfc06":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"ProgressStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"ProgressStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","bar_color":null,"description_width":""}},"98fe0f2e755b45cab74b34e43cb04c40":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"a07371bb985a4495883ad43bf3236b40":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"ProgressStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"ProgressStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","bar_color":null,"description_width":""}},"a406a8c3e02c4fadaa42ae406f629fcc":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"a42c6673b5114ca2a59d2decd1704f2c":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"ProgressStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"ProgressStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","bar_color":null,"description_width":""}},"b686750ad56d44009cf2c8c984eaf9c7":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"b7522e6765f34041a228703e4b277889":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HTMLModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HTMLModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HTMLView","description":"","description_tooltip":null,"layout":"IPY_MODEL_6ff65b2d47e54f03be17364ebc518562","placeholder":"​","style":"IPY_MODEL_4b87c123a6224d8aa84e5e8164a42691","value":"100% 4/4 [02:22&lt;00:00, 35.81s/it]"}},"bbd27da1dbd14747ad46bf16cda35e0a":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"bc087e60dc1f4a83bf9b2aef890eba38":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"IntProgressModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"IntProgressModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"ProgressView","bar_style":"success","description":"","description_tooltip":null,"layout":"IPY_MODEL_072f5ad0f5a54076979db2be10a96b2e","max":4,"min":0,"orientation":"horizontal","style":"IPY_MODEL_a42c6673b5114ca2a59d2decd1704f2c","value":4}},"beca22b4e98844b2ac251f187706ea56":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"IntProgressModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"IntProgressModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"ProgressView","bar_style":"success","description":"","description_tooltip":null,"layout":"IPY_MODEL_5b086863288f40f4a447f3fb2cfe54ba","max":4,"min":0,"orientation":"horizontal","style":"IPY_MODEL_a07371bb985a4495883ad43bf3236b40","value":4}},"c41e596ee4e8466c8577662becb1ba56":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HTMLModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HTMLModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HTMLView","description":"","description_tooltip":null,"layout":"IPY_MODEL_d52325e890384bfb8295ea265cdaacfa","placeholder":"​","style":"IPY_MODEL_5043d882529944cf83a54736ea7e5e36","value":"100% 4/4 [00:00&lt;00:00, 163.70it/s]"}},"c5fd4b9ce6e74bb58603a249ac99dd8b":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"c9d96d41728648b693470738b88ea08c":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"IntProgressModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"IntProgressModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"ProgressView","bar_style":"success","description":"","description_tooltip":null,"layout":"IPY_MODEL_46f79e3c2669493e9f33fad435f98974","max":3698,"min":0,"orientation":"horizontal","style":"IPY_MODEL_6f45be7215a64837993d0df660f712f3","value":3698}},"d52325e890384bfb8295ea265cdaacfa":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"e43e4cafb019406a858d1bf1ff6ea8c8":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"fc359586abfd495e9ec7fcdb945238c7":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}}},"version_major":2,"version_minor":0}}},"nbformat":4,"nbformat_minor":1}