{"cells":[{"metadata":{},"cell_type":"markdown","source":"# Lavin version\nCopied from https://www.kaggle.com/wrrosa/hubmap-tf-with-tpu-efficientunet-512x512-subm by Wojtek Rosa.\n\nThe main difference in this version is the use of tiles that overlap on all four sides, as produced by https://www.kaggle.com/markalavin/hubmap-tile-images-w-overlap-and-build-tfrecords.  For example, I'm\ncurrently using tiles that are 512 x 512, plus 64 pixels of overlap on every side, laid out on a grid with\nrow and column strides of 512 and 512.  The advantage of this approach is that the prediction is done\nusing 640 x 640, and the inner 512 x 512 all \"see\" their correct neighborhoods by a \"radius\" of 64;\nafter the prediction, the 640 x 640 result is trimmed to 512 x 512 and inserted into the result tableau\nprior to run-length coding.  The downside of this approach is that it takes ~1.56 the processing time\nfor both prediction and training https://www.kaggle.com/markalavin/hubmap-tf-with-tpu-efficientunet-512x512-t-012036.  NOTE:  At the moment, the pnly part of the training that \"knows\" \nabout the overlapping layout is the ```dice_coeff``` function, which trims the borders of the predicted and\nground-truth mask images before calculating the Dice score.\n\nNotes:\n1.  Modify the training loss function to also do the trimming of the predicted and ground-truth images\n2.  I *think* it is possible to do both the inferencing **and** the run-length calculation tile-by-tile; the\ntotal runcode is the concatenation of each tile run code.  A problem with this is that the current code\ndoes prediction for all the tiles in the whole image, which causes a memory spike, washing out the benefit\nof the tile-at-a-time inference/runcoding.\n\nLavin modifications are enabled by setting variable LAVIN to True."},{"metadata":{"trusted":true},"cell_type":"code","source":"LAVIN = True","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Tensorflow HuBMAP - Hacking the Kidney competition starter kit:\n* https://www.kaggle.com/wrrosa/hubmap-tf-with-tpu-efficientunet-512x512-tfrecs (how to create training and inference tfrecords)\n* https://www.kaggle.com/wrrosa/hubmap-tf-with-tpu-efficientunet-512x512-train (training pipeline)\n* this notebook (inference with submission)\n\n# Versions\n* V1 (V7 train notebook) 4-CV efficientunetb0 512x512 (**LB .834**)\n* V2 (V8 train notebook) loss bce (LB .835)\n* V3 (V9 train notebook) efficientunetb1 (CV .871, LB .830)\n* V4 (V10 train notebook) efficientunetb4 (CV .874, **LB .839**)\n* V5 (V12 train notebook) efficientunetb7 (CV .858, LB .835)\n* V6 (V13 train notebook) efficientunetb4 (CV .877, LB .836)\n* V7 (V14 train notebook) efficientunetb4 with overlapped train data, summing preds in inference (CV .879, **LB .843**)\n* V8 (V14 train notebook) efficientunetb4  THRESHOLD=0.4, interpolation = cv2.INTER_AREA, rle_encode_less_memory (**LB .846**)\n* V9 (V14 train notebook) efficientunetb4, MIN_OVERLAP = 300 (**LB 0.848**)\n* V10 (V14 train notebook) efficientunetb4, checksum mask before modifications (1h 11m, no need to score)\n* V11 (V14 train notebook) efficientunetb4, SUBMISSION_MODE added (generate submission from public tfrec files, almost 20m = 3.5 times faster!)\n* V12 (V14 train notebook) efficientunetb4, CHECKSUM = False (...)"},{"metadata":{},"cell_type":"markdown","source":"# Refferences:\n* https://www.kaggle.com/joshi98kishan/hubmap-keras-pipeline-training-inference\n* https://www.kaggle.com/bguberfain/memory-aware-rle-encoding/\n* https://www.kaggle.com/leighplt/pytorch-fcn-resnet50"},{"metadata":{},"cell_type":"markdown","source":"# Parameters\nRead parameteres from notebook output, actually only **DIM** is used:"},{"metadata":{"trusted":true},"cell_type":"code","source":"if LAVIN:\n    mod_path = '/kaggle/input/hubmap-models/'\nelse:\n    mod_path = '/kaggle/input/hubmap-tf-with-tpu-efficientunet-512x512-train/'\n\nimport yaml\nimport pprint\nwith open(mod_path+'params.yaml') as file:\n    P = yaml.load(file, Loader=yaml.FullLoader)\n    pprint.pprint(P)\n    \nTHRESHOLD = 0.4 # preds > THRESHOLD\nWINDOW = 1024\nMIN_OVERLAP = 300\nNEW_SIZE = P['DIM']\n\nSUBMISSION_MODE = 'PUBLIC_TFREC' \n# 'PUBLIC_TFREC' = use created tfrecords for public test set with MIN_OVERLAP = 300 tiling 1024-512, ignore other (private test) data\n# 'FULL' do not use tfrecords, just full submission \n\nif LAVIN:\n    CHECKSUM = True # compute mask sum for each image\nelse:\n    CHECKSUM = False # compute mask sum for each image\n","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Metrics"},{"metadata":{"trusted":true},"cell_type":"code","source":"import json\n\nwith open(mod_path + 'metrics.json') as json_file:\n    M = json.load(json_file)\nprint('Model run datetime: '+M['datetime'])\nprint('OOF val_dice_coe: ' + str(M['oof_dice_coe']))","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Packages"},{"metadata":{"trusted":true},"cell_type":"code","source":"! pip install ../input/kerasapplications/keras-team-keras-applications-3b180cb -f ./ --no-index -q\n! pip install ../input/efficientnet/efficientnet-1.1.0/ -f ./ --no-index -q\nimport numpy as np\nimport pandas as pd\nimport os\nimport glob\nimport gc\nimport sys\nimport re\n\nimport matplotlib.pyplot as plt\n%matplotlib inline\n\nimport tifffile\nimport rasterio\nfrom rasterio.windows import Window\n\nimport pathlib\nfrom tqdm.notebook import tqdm\nimport cv2\n\nimport tensorflow as tf\nimport efficientnet as efn\nimport efficientnet.tfkeras","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def running_on_TPU():\n    try:\n        tpu = tf.distribute.cluster_resolver.TPUClusterResolver() # TPU detection\n        tf.config.experimental_connect_to_cluster(tpu)\n        tf.tpu.experimental.initialize_tpu_system(tpu)\n        strategy = tf.distribute.experimental.TPUStrategy(tpu)\n        return True\n    except:\n        return False\n    \nprint( \"running_on_TPU\", running_on_TPU(), file = sys.stderr )","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"markdown","source":"AUTO = tf.data.experimental.AUTOTUNE\nimage_feature = {\n    'image': tf.io.FixedLenFeature([], tf.string),\n}\ndef _parse_image(example_proto):\n    example = tf.io.parse_single_example(example_proto, image_feature, name = \"parse_example\")\n    dim_with_overlap = P[ 'DIM' ] + 2 * P[ 'PIXEL_OVERLAP' ]\n    image = tf.reshape( tf.io.decode_raw(example['image'],out_type=np.dtype('uint8')), \n                        (dim_with_overlap, dim_with_overlap, 3))\n    return image\n\n\ndataset = tf.data.TFRecordDataset( \"../input/blortzk-hubmap-test-overlapping-tiled-images/test/26dc41664-6068.tfrec\",\n                                   compression_type = \"GZIP\" )\ndataset = dataset.batch( 77 )\ndataset = dataset.prefetch(AUTO)\n# dataset = dataset.map(_parse_image)\n\niterator = iter( dataset )\nbatch = iterator.get_next()\nprint( \"type( batch )\", type( batch ), \"batch.shape\", batch.shape, \"dtype\", batch.dtype, file = sys.stderr )\nlist( map( _parse_image, batch ) )"},{"metadata":{},"cell_type":"markdown","source":"# Functions"},{"metadata":{"trusted":true},"cell_type":"code","source":"def rle_encode_less_memory(img):\n    pixels = img.T.flatten()\n    pixels[0] = 0\n    pixels[-1] = 0\n    runs = np.where(pixels[1:] != pixels[:-1])[0] + 2\n    runs[1::2] -= runs[::2]\n    return ' '.join(str(x) for x in runs)\n\ndef make_grid(shape, window=256, min_overlap=32):\n    \"\"\"\n        Return Array of size (N,4), where N - number of tiles,\n        2nd axis represente slices: x1,x2,y1,y2 \n    \"\"\"\n    x, y = shape\n    nx = x // (window - min_overlap) + 1\n    x1 = np.linspace(0, x, num=nx, endpoint=False, dtype=np.int64)\n    x1[-1] = x - window\n    x2 = (x1 + window).clip(0, x)\n    ny = y // (window - min_overlap) + 1\n    y1 = np.linspace(0, y, num=ny, endpoint=False, dtype=np.int64)\n    y1[-1] = y - window\n    y2 = (y1 + window).clip(0, y)\n    slices = np.zeros((nx,ny, 4), dtype=np.int64)\n    \n    for i in range(nx):\n        for j in range(ny):\n            slices[i,j] = x1[i], x2[i], y1[j], y2[j]    \n    return slices.reshape(nx*ny,4)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Models"},{"metadata":{"trusted":true},"cell_type":"code","source":"identity = rasterio.Affine(1, 0, 0, 0, 1, 0)\nfold_models = []\nfor fold_model_path in glob.glob(mod_path+'*.h5'):\n    fold_models.append(tf.keras.models.load_model(fold_model_path,compile = False))\nprint(len(fold_models))","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Tfrecords functions"},{"metadata":{"trusted":true},"cell_type":"code","source":"AUTO = tf.data.experimental.AUTOTUNE\nif LAVIN:\n    image_feature = {\n        'image': tf.io.FixedLenFeature([], tf.string),\n    }\nelse:\n    image_feature = {\n        'image': tf.io.FixedLenFeature([], tf.string),\n        'x1': tf.io.FixedLenFeature([], tf.int64),\n        'y1': tf.io.FixedLenFeature([], tf.int64)\n}\ndef _parse_image(example_proto):\n    example = tf.io.parse_single_example(example_proto, image_feature )\n    if LAVIN:\n        dim_with_overlap = P[ 'DIM' ] + 2 * P[ 'PIXEL_OVERLAP' ]\n        image = tf.reshape( tf.io.decode_raw(example['image'],out_type=np.dtype('uint8')), \n                           (dim_with_overlap, dim_with_overlap, 3))\n        return image, 24, 37   # Dummy x1 and y1 values\n    else:\n        image = tf.reshape( tf.io.decode_raw(example['image'],out_type=np.dtype('uint8')), (P['DIM'],P['DIM'], 3))\n        return image, example['x1'], example['y1']\n\ndef load_dataset(filenames, ordered=True):\n    ignore_order = tf.data.Options()\n    if not ordered:\n        ignore_order.experimental_deterministic = False\n    if LAVIN:\n        dataset = tf.data.TFRecordDataset(filenames, compression_type = \"GZIP\" )\n    else:\n        dataset = tf.data.TFRecordDataset(filenames)\n    dataset = dataset.with_options(ignore_order)\n    dataset = dataset.map(_parse_image)\n    return dataset\n\ndef get_dataset(FILENAME):\n    dataset = load_dataset(FILENAME)\n    dataset  = dataset.batch(64)\n    dataset = dataset.prefetch(AUTO)\n    return dataset.take( 10 )   # ### REMOVE \"take\"","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Results"},{"metadata":{"trusted":true},"cell_type":"markdown","source":"p = pathlib.Path('../input/hubmap-kidney-segmentation')\nsubm = {}\n\nfor i, filename in tqdm(enumerate(p.glob('test/*.tiff')), \n                        total = len(list(p.glob('test/*.tiff')))):\n    \n    print(f'{i+1} Predicting {filename.stem}')\n    \n    dataset = rasterio.open(filename.as_posix(), transform = identity)\n    if LAVIN:\n        image_pixel_rows, image_pixel_cols = dataset.shape\n    preds = np.zeros(dataset.shape, dtype=np.uint8)    \n    \n    if SUBMISSION_MODE == 'PUBLIC_TFREC' and MIN_OVERLAP == 300 and WINDOW == 1024 and NEW_SIZE == 512:\n        print('SUBMISSION_MODE: PUBLIC_TFREC')\n        if LAVIN:\n            fnames = glob.glob('/kaggle/input/blortzk-hubmap-test-overlapping-tiled-images/test/'+filename.stem+'*.tfrec')\n        else:\n            fnames = glob.glob('/kaggle/input/hubmap-tf-with-tpu-efficientunet-512x512-tfrecs/test/'+filename.stem+'*.tfrec')\n        \n        if len(fnames)>0: # PUBLIC TEST SET\n            for FILENAME in fnames:\n                pred = None\n                for fold_model in fold_models:\n                    tmp = fold_model.predict(get_dataset(FILENAME))/len(fold_models)\n                    if pred is None:\n                        pred = tmp\n                    else:\n                        pred += tmp\n                    del tmp\n                    gc.collect()\n\n                if LAVIN:\n                    # Threshold the prediction values and make them bools:\n                    pred = tf.cast( pred > THRESHOLD, tf.bool ).numpy().squeeze()\n                    print( \"after predict, pred.shape\", pred.shape, file = sys.stderr )\n                    pred_pixels = pred.shape[ 0 ] * pred.shape[ 1 ] * pred.shape[ 2 ]\n                    pred_ones = pred.sum();\n                    print( \"Total pixels\", pred_pixels, \"1-valued pixels\", pred_ones, file = sys.stderr )\n\n                else:\n                    pred = tf.cast((tf.image.resize(pred, (WINDOW,WINDOW)) > THRESHOLD),tf.bool).numpy().squeeze()\n\n                if LAVIN:\n                     \n                    DIM = P[ 'DIM' ]\n                    OVL = P[ 'PIXEL_OVERLAP' ]\n                   \n                    # Remember that we truncate the input to the largest number of whole DIMxDIM tiles\n                    end_pixel_rows = DIM * ( image_pixel_rows // DIM )\n                    end_pixel_cols = DIM * ( image_pixel_cols // DIM )\n                    \n                    print( \"preds.shape\", preds.shape, \"end_pixel_rows\", end_pixel_rows, \"end_pixel_cols\", end_pixel_cols, file = sys.stderr )\n\n                    idx = 0   # Index of tile in column-major order:\n\n                    for image_pixel_col in range( 0, end_pixel_cols, DIM ):\n                        for image_pixel_row in range( 0, end_pixel_rows, DIM ):\n                            if True:\n                                try:\n                                    trimmed_tile = pred[ idx, OVL : -OVL, OVL : -OVL ].squeeze()\n                                    '''\n                                    if ( trimmed_tile.sum() > 0 ):\n                                        plt.title( \"image_pixel_row \" + str( image_pixel_row ) + \" image_pixel_col \" + str( image_pixel_col ) )\n                                        plt.imshow( trimmed_tile )\n                                        plt.show()\n                                    '''\n                                except:\n                                    print( \"Exception: \", \"image_pixel_row \" + str( image_pixel_row ) + \" image_pixel_col \" + str( image_pixel_col ), file = sys.stderr )\n                                    if ( idx >= pred.shape[ 0 ] ):\n                                        break\n                                assert trimmed_tile.shape == ( DIM, DIM )\n                                preds[ image_pixel_row : image_pixel_row + DIM,\n                                       image_pixel_col : image_pixel_col + DIM ] =  trimmed_tile\n                            if False:\n                                print( \"image_pixel_row\", image_pixel_row, \"image_pixel_col\", image_pixel_col)\n                                print( \"image_pixel_row+P[DIM]\", image_pixel_row + P[ 'DIM' ], file = sys.stderr )\n                                print( \"image_pixel_col+P[DIM]\", image_pixel_col + P[ 'DIM' ], file = sys.stderr )\n                                \n                            idx += 1\n                        if ( idx >= pred.shape[ 0 ] ):\n                            break\n                        \n                                  \n                else:\n                    idx = 0\n                    for img, X1, Y1 in get_dataset(FILENAME):\n                        for fi in range(X1.shape[0]):\n                            x1 = X1[fi].numpy()\n                            y1 = Y1[fi].numpy()\n                            preds[x1:(x1+WINDOW),y1:(y1+WINDOW)] += pred[idx]\n                            idx += 1\n                pred = None\n                '''\n                fig, (ax1, ax2) = plt.subplots(1, 2, figsize = ( 3, 4 ) )\n                fig.suptitle( filename.stem )\n                ax1.imshow( preds )\n                rows = dataset.height\n                cols = dataset.width\n                image = dataset.read([1], window= ((0, rows), ( 0, 20000 ) ) ).squeeze()  # ### ((x1,x2),(y1,y2)))\n                plt.imshow( image )\n                plt.show()\n                image = None\n                gc.collect\n                '''\n                        \n        else: # IGNORE PRIVATE TEST SET (CREATE TFRECORDS IN FUTURE)\n            pass\n    else:\n        print('SUBMISSION_MODE: FULL')\n        slices = make_grid(dataset.shape, window=WINDOW, min_overlap=MIN_OVERLAP)\n\n\n        for (x1,x2,y1,y2) in slices:\n            image = dataset.read([1,2,3],\n                        window=Window.from_slices((x1,x2),(y1,y2)))\n            image = np.moveaxis(image, 0, -1)\n            image = cv2.resize(image, (NEW_SIZE, NEW_SIZE),interpolation = cv2.INTER_AREA)\n            image = cv2.cvtColor(image, cv2.COLOR_RGB2BGR)\n            image = np.expand_dims(image, 0)\n\n            pred = None\n\n            for fold_model in fold_models:\n                if pred is None:\n                    pred = np.squeeze(fold_model.predict(image))\n                else:\n                    pred += np.squeeze(fold_model.predict(image))\n\n            pred = pred/len(fold_models)\n\n            pred = cv2.resize(pred, (WINDOW, WINDOW))\n            preds[x1:x2,y1:y2] += (pred > THRESHOLD).astype(np.uint8)\n\n    preds = (preds > 0.5).astype(np.uint8)\n    \n    subm[i] = {'id':filename.stem, 'predicted': rle_encode_less_memory(preds)}\n    \n    if CHECKSUM:\n        print('Checksum: '+ str(np.sum(preds)))\n    \n    del preds\n    gc.collect();"},{"metadata":{},"cell_type":"markdown","source":"# Low-memory glom Prediction and Encoding\nThis version of the code above reduces the memory by doing model prediction and Run Length Encoding (RLE)\ncolumn by column rather than for the entire image."},{"metadata":{"trusted":true},"cell_type":"code","source":"def predict_and_encode_results( tiff_image_dirname, image_tile_dirname, trained_models, P, CSV_filename ):\n    '''\n    Does model-prediction using models in \"trained_model_dirnamefor all input images\n    represented by files in \"image_tile_dirname\", then run-length-encodes (RLE) the\n    predicted glom mask.\n    '''\n    print( \"tiff_image_dirname\", tiff_image_dirname, \"image_tile_dirname\", image_tile_dirname, file = sys.stderr )\n\n    # Retrieve the models, one per Training fold:\n    # trained_models = retrieve_trained_models( trained_model_dirname )\n\n    # Iterate over all the test images:\n    with open( CSV_filename, \"w\") as CSV:\n        CSV.write( \"id,predicted\\n\" )  # csv header\n        tiff_image_filenames = glob.glob( tiff_image_dirname + \"*.tiff\" )\n        for tiff_image_filename in tqdm( tiff_image_filenames ):  # ### FIX THIS!!!! ###\n            if \"26dc41664\" in tiff_image_filename:\n                print( \"tiff_image_filename\", tiff_image_filename, file = sys.stderr )\n                predict_and_encode_image( trained_models, tiff_image_filename, image_tile_dirname, CSV, P )\n            \n\ndef predict_and_encode_image( trained_models, tiff_image_filename, image_tile_dirname, CSV, P ):\n    print( \"\\ntiff_image_filename\", tiff_image_filename, \"image_tile_dirname\", image_tile_dirname, file = sys.stderr )\n    try:\n        image_id = re.compile( r\".*/([0-9a-fA-F]+)\\.tiff\" ).match( tiff_image_filename ).group( 1 )\n    except:\n        print( f\"ERROR: Could not find image_id in filename {tiff_image_filename}\")\n    with rasterio.open( tiff_image_filename, transform = None ) as dataset:  # Just to query shape\n        image_pixel_rows, image_pixel_cols = dataset.shape\n    image_tile_rows = image_pixel_rows // P[ 'DIM' ]   # e.g., 512 pixels / tile\n    image_tile_cols = image_pixel_cols // P[ 'DIM' ]\n        \n    # Iterate over all the tile columns in image:\n    tile_batch_iterator = open_tile_batch_iterator( image_id, image_tile_dirname, image_tile_rows )\n    RLE = ''\n    for image_tile_col in tqdm( range( image_tile_cols ) ):\n        RLE += \" \" + predict_and_encode_column( trained_models, image_id, image_tile_col, image_tile_rows, tile_batch_iterator, CSV, P )\n        print( \"Processed column\", image_tile_col, \"/\", image_tile_cols, \"for image_id\", image_id, file = sys.stderr )  # ### REMOVE!!! ###\n    \n\n    # Write out the result as one line in the CSV file\n    CSV.write( image_id + \",\" )\n    CSV.write( RLE )\n    CSV.write( \"\\n\" )\n    CSV.flush()\n    print( \"wrote one CSV record for image\", image_id, file = sys.stderr )\n                  \ndef predict_and_encode_column( trained_models, image_id, image_tile_col, image_tile_rows, tile_batch_iterator, CSV, P ):\n    '''\n    Returns string RLE for the tiles in column \"image_tile_col\"\n    '''\n    # Calculate the prediction for all tiles in \"image_tile_col\", averaging over one\n    # prediction for each model in \"trained_models\" and thresholding\n    tile_batch = tile_batch_iterator.get_next()\n    col_tiles = tf.map_fn( parse_tfrecs_to_column_tiles, tile_batch, dtype = \"uint8\" )\n    predicted_tiles = None\n    for trained_model in trained_models:\n        predicted_tile = trained_model.predict( col_tiles )\n        predicted_tiles = predicted_tile if predicted_tiles is None else predicted_tiles + predicted_tile\n    predicted_tiles /= len( trained_models )\n    predicted_tiles = tf.cast( predicted_tiles > THRESHOLD, tf.bool ).numpy().squeeze()\n    \n    # Trim the overlapping borders from each predicted output tile, then concatenate\n    # the column's tiles into a single 1-column-wide image\n    OVL = P[ 'PIXEL_OVERLAP' ]\n    trimmed_predicted_tiles = predicted_tiles[ :, OVL : - OVL, OVL : - OVL ]\n    column_tensor = tf.reshape( trimmed_predicted_tiles, ( ( P[ \"DIM\" ] * image_tile_rows , P[ \"DIM\" ] ) ) )\n\n    # Calculate the offset, in pixels, for the start of the current column\n    column_pixel_offset = P['DIM'] * P['DIM'] * image_tile_rows * image_tile_col\n    \n    # Calculate the string RLE, which will be concatenated with RLEs from other columns, to\n    # construct RLE for the entire image\n    RLE = encode_RLE( column_tensor.numpy(), column_pixel_offset )\n    return RLE\n\ndef open_tile_batch_iterator( image_id, image_tile_dirname, image_tile_rows ):\n    '''\n    Returns an iterator that iterates over batches in \"image_tile_dirname\"/\"image_id\"-nnn.tfrec\n    '''\n    image_tile_filename = glob.glob( image_tile_dirname + image_id + \"*.tfrec\" )\n    print( \"image_tile_filename\", image_tile_filename, file = sys.stderr)\n\n    dataset = tf.data.TFRecordDataset( image_tile_filename, compression_type = \"GZIP\" )\n    dataset = dataset.batch( image_tile_rows )\n    dataset = dataset.prefetch(AUTO)\n    # ### dataset = dataset.map(_parse_image)\n\n    iterator = iter( dataset )\n    return iterator\n\ndef parse_tfrecs_to_column_tiles(example_proto):\n    '''\n    Parse a batch of TFRecords in \"example_proto\" to extract an\n    array of image tiles comprising one tile column in the input.\n    '''\n    image_feature = {\n        'image': tf.io.FixedLenFeature([], tf.string),\n    }\n    example = tf.io.parse_single_example(example_proto, image_feature )\n    dim_with_overlap = P[ 'DIM' ] + 2 * P[ 'PIXEL_OVERLAP' ]\n    image = tf.reshape( tf.io.decode_raw(example['image'],out_type=np.dtype('uint8')), \n                        (dim_with_overlap, dim_with_overlap, 3))\n    return image\n\n# Based on https://www.kaggle.com/friedchips/fully-correct-hubmap-rle-encoding-and-decoding:\n# Given a predicted binary image tile column \"mask\" and a starting offset in\n# column-major ordered pixels, calculate and return the string RLE, which will be\n# concatenated with RLEs from other columns, to construct RLE for the entire image:\ndef encode_RLE( mask, column_pixel_offset = 0 ):\n    mask = mask.T.reshape(-1) # make 1D, column-first\n    mask = np.pad(mask, 1) # make sure that the 1d mask starts and ends with a 0\n    starts = np.nonzero((~mask[:-1]) & mask[1:])[0] + column_pixel_offset # start points\n    ends = np.nonzero(mask[:-1] & (~mask[1:]))[0] + column_pixel_offset # end points\n    rle = np.empty(2 * starts.size, dtype=int) # interlacing...\n    rle[0::2] = starts # ...starts...\n    rle[1::2] = ends - starts # ...and lengths\n    rle = ' '.join([ str(elem) for elem in rle ]) # turn into space-separated string\n    return rle\n\ndef mask2rle(mask, column_offset = 0):\n    ''' takes a 2d boolean numpy array and turns it into a space-delimited RLE string '''\n    \n    mask = mask.T.reshape(-1) # make 1D, column-first\n    mask = np.pad(mask, 1) # make sure that the 1d mask starts and ends with a 0\n    starts = np.nonzero((~mask[:-1]) & mask[1:])[0] + column_offset # start points\n    ends = np.nonzero(mask[:-1] & (~mask[1:]))[0] + column_offset # end points\n    rle = np.empty(2 * starts.size, dtype=int) # interlacing...\n    rle[0::2] = starts # ...starts...\n    rle[1::2] = ends - starts # ...and lengths\n    rle = ' '.join([ str(elem) for elem in rle ]) # turn into space-separated string\n    return rle\n\ndef rle2mask(rle, mask_shape):\n    ''' takes a space-delimited RLE string in column-first order\n    and turns it into a 2d boolean numpy array of shape mask_shape '''\n    \n    mask = np.zeros(np.prod(mask_shape), dtype=bool) # 1d mask array\n    rle = np.array(rle.split()).astype(int) # rle values to ints\n    starts = rle[::2]\n    lengths = rle[1::2]\n    for s, l in zip(starts, lengths):\n        mask[s:s+l] = True\n    return mask.reshape(np.flip(mask_shape)).T # flip because of column-first order\n\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"column_array = [ [ 0, 1, 1 ], [1, 1, 1 ], [ 1, 0, 0 ] ] \ncolumn_tensor = tf.convert_to_tensor( column_array )\nRLE = encode_RLE( column_tensor.numpy(), column_pixel_offset = 6 )\nprint( \"column_tensor\\n\", column_tensor, \"\\nRLE\", RLE, file = sys.stderr )\nrle2mask( RLE, ( 3, 5 ) )","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"!ls -al /kaggle/input/hubmap-kidney-segmentation/test/*.tiff","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"! touch /kaggle/working/submission.csv\ntiff_image_dirname = \"/kaggle/input/hubmap-kidney-segmentation/test/\"\nimage_tile_dirname = \"/kaggle/input/blortzk-hubmap-test-overlapping-tiled-images/test/\"\ntrained_models = fold_models\nCSV_filename = \"/kaggle/working/submission.csv\"\npredict_and_encode_results( tiff_image_dirname, image_tile_dirname, trained_models, P, CSV_filename )","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"'''\n! ls -al /kaggle/working/submission.csv\n! echo \"\" >/kaggle/working/submission.csv\n'''","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Making submission"},{"metadata":{"trusted":true},"cell_type":"code","source":"'''\nsubmission = pd.DataFrame.from_dict(subm, orient='index')\nsubmission.to_csv('submission.csv', index=False)\nsubmission.head()\n'''","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Visualizing results"},{"metadata":{"trusted":true},"cell_type":"code","source":"# From https://www.kaggle.com/friedchips/fully-correct-hubmap-rle-encoding-and-decoding\n\ndef visualize_mask_and_image( tiff_image_dirname, CSV_filename ): \n    image_RLEs = pd.read_csv( CSV_filename )\n    print( \"image_RLEs\", image_RLEs.head(), file = sys.stderr )\n\n    for tiff_image_filename in glob.glob( tiff_image_dirname + \"*.tiff\" ):\n        image_id = pathlib.Path( tiff_image_filename ).stem\n        RLE = image_RLEs.predicted[ image_RLEs.id == image_id ]\n        if ( len( RLE ) == 0 ):\n            print( \"For image_id\", image_id, \"no prediction\", file = sys.stderr )\n        else:\n            RLE = RLE.values[ 0 ]\n            print( \"image_id\", image_id, file = sys.stderr )\n            with rasterio.open( tiff_image_filename, transform = identity) as dataset:\n                # Round down the number of rows and columns to a multiple of the result tile size\n                image_pixel_rows, image_pixel_cols = dataset.shape\n                image_pixel_rows = image_pixel_rows // P[ 'DIM'] * P[ 'DIM' ]\n                image_pixel_cols = image_pixel_cols // P[ 'DIM'] * P[ 'DIM' ]\n            mask = rle2mask( RLE, ( image_pixel_rows, image_pixel_cols ) )\n            plt.imshow( mask )\n            plt.show()\n            plt.imshow( cv2.imread( tiff_image_filename ) )\n            plt.show()\n\n'''            \ntiff_image_dirname = \"/kaggle/input/hubmap-kidney-segmentation/test/\"\nCSV_filename = \"/kaggle/input/submission-four-out-of-five/submission.csv\" # ### \"/kaggle/working/submission.csv\"   \nvisualize_mask_and_image( tiff_image_dirname, CSV_filename )\n'''","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}