{"cells":[{"metadata":{},"cell_type":"markdown","source":"<font color=\"navy\">I wrote this notebook to illustrate how to use tensorflow saved_model to make predictions.\nIt can be tricky to use the saved_model.\nMy submission for recursion cellular image classifiction score is</font>\n**<font color=\"red\" size=\"12\">0.129</font>**"},{"metadata":{},"cell_type":"markdown","source":""},{"metadata":{"trusted":true},"cell_type":"code","source":"from __future__ import absolute_import\nfrom __future__ import division\nfrom __future__ import print_function\n\nimport os\nimport time\n\nimport numpy as np\nfrom skimage.io import imread\nimport pandas as pd\n\nimport tensorflow as tf\n\nimport sys\nimport matplotlib.pyplot as plt\n\n%matplotlib inline","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#DEFAULT_BASE_PATH = 'https://storage.cloud.google.com/rxrx1-us-central1'\nDEFAULT_BASE_PATH = '../input'\nDEFAULT_METADATA_BASE_PATH = os.path.join(DEFAULT_BASE_PATH, 'recursion-cellular-image-classification')\nDEFAULT_TRAIN_BASE_PATH = os.path.join(DEFAULT_METADATA_BASE_PATH, 'train')\nDEFAULT_TEST_BASE_PATH = os.path.join(DEFAULT_METADATA_BASE_PATH, 'test')\nDEFAULT_CHANNELS = (1, 2, 3, 4, 5, 6)\nsaved_model_path= DEFAULT_BASE_PATH+\"/leighlin-recur-cell-saved-model/saved_model/saved_model\"","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"The saved_model comes from the [How to train a ResNet50 on RxRx1 using TPUs](https://github.com/recursionpharma/rxrx1-utils/blob/master/notebooks/training.ipynb)\nI have trained for 300 epochs and uploaded the saved_model zip file into my kaggal \"new dataset\". Kaggal automatically unzipped the zip files. I have just make the dataset public. Feel free to use it.\n[leighlin-recur-cell-saved-model](https://www.kaggle.com/leighlin0511/leighlin-recur-cell-saved-model)\n</br>\n\nThe directory structure should be like the following\n* saved_model\n* * --saved_model.pb\n* * --variables\n* * *   --variables.data-00000-of-00001\n* * *   --variables.index"},{"metadata":{"trusted":true},"cell_type":"code","source":"def image_path(experiment,\n               plate,\n               well,\n               site,\n               channel,\n               base_path=DEFAULT_TRAIN_BASE_PATH):\n    \n    \n    return os.path.join(base_path, experiment, \"Plate{}\".format(plate),\n                        \"{}_s{}_w{}.png\".format(well, site, channel))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#test/HEPG2-08/Plate1/B02_s1_w1.png\nimage_path01 = image_path(\"HUVEC-01\",\"1\",\"K17\",'1','3')\nprint(image_path01)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def load_image(image_path):\n    with tf.io.gfile.GFile(image_path, 'rb') as f:\n        return imread(f, format='png')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def load_images_as_matrix(image_paths, dtype=np.uint8):\n    n_channels = len(image_paths)\n\n    data = np.ndarray(shape=(512, 512, n_channels), dtype=dtype)\n\n    for ix, img_path in enumerate(image_paths):\n        data[:, :, ix] = load_image(img_path)\n\n    return data","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"The code is based on [Starter code for the CellSignal NeurIPS 2019 competition.](https://github.com/recursionpharma/rxrx1-utils)\n\nI have modified the code to return a matrix instead of tensor,"},{"metadata":{"trusted":true},"cell_type":"code","source":"def load_site(experiment,\n              plate,\n              well,\n              site,\n              channels=DEFAULT_CHANNELS,\n              base_path=DEFAULT_TRAIN_BASE_PATH):\n   \n    channel_paths = [\n        image_path(\n            experiment, plate, well, site, c, base_path=base_path)\n        for c in channels\n    ]\n    return load_images_as_matrix(channel_paths)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"image_shape = [512, 512, 6]\n# The mean and stds for each of the channels\nGLOBAL_PIXEL_STATS = (np.array([6.74696984, 14.74640167, 10.51260864,\n                                10.45369445,  5.49959796, 9.81545561]),\n                       np.array([7.95876312, 12.17305868, 5.86172946,\n                                 7.83451711, 4.701167, 5.43130431]))\ndef process_image(image, pixel_stats=GLOBAL_PIXEL_STATS):    \n    if pixel_stats is not None:\n        mean, std = pixel_stats\n        image = (image - mean) / std\n        \n    image = image[np.newaxis, :]\n    return image","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Load test metadata for predictions."},{"metadata":{"trusted":true},"cell_type":"code","source":"def _tf_read_csv(path):\n    with tf.io.gfile.GFile(path, 'rb') as f:\n        return pd.read_csv(f)\n\ndef _load_dataset(base_path, dataset, include_controls=True):\n    df = _tf_read_csv(os.path.join(base_path, dataset + '.csv'))\n    if include_controls:\n        controls = _tf_read_csv(\n            os.path.join(base_path, dataset + '_controls.csv'))\n        df['well_type'] = 'treatment'\n        df = pd.concat([controls, df], sort=True)\n    df['cell_type'] = df.experiment.str.split(\"-\").apply(lambda a: a[0])\n    df['dataset'] = dataset\n    return df\n\ndef load_test_metadata(base_path=DEFAULT_METADATA_BASE_PATH,\n                     include_controls=False):\n    df = _load_dataset(base_path, \"test\", include_controls=include_controls)\n    return df","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"metadata_test = load_test_metadata()\nmetadata_test.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def get_id_code(experiment,plate,well):\n    return \"{}_{}_{}\".format(experiment,plate,well)\n\n#HEPG2-08_1_B03\nprint(get_id_code(\"HEPG2-08\",\"1\",\"B03\"))","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"The prediction code. Make sure to <font color=\"red\">remove the breaking code</font> to make full test dataset predictions."},{"metadata":{"scrolled":false,"trusted":true},"cell_type":"code","source":"start_time = time.time()\n#df = pd.DataFrame(columns=('id_code','sirna','prob') )\ndf = pd.DataFrame(columns=('id_code','sirna') )\n\nwith tf.Session(graph=tf.Graph()) as sess:\n    signature_key = tf.saved_model.signature_constants.DEFAULT_SERVING_SIGNATURE_DEF_KEY\n    input_key = 'feature'\n    output_key_classes = 'classes'\n    output_key_p = 'probabilities'\n    meta_graph_def = tf.saved_model.loader.load(\n           sess,\n          [tf.saved_model.tag_constants.SERVING],\n          saved_model_path)\n    signature = meta_graph_def.signature_def\n    \n    x_tensor_name = signature[signature_key].inputs[input_key].name\n    print(signature[signature_key].outputs)\n    y_classes_tensor_name = signature[signature_key].outputs[output_key_classes].name\n    #y_p_tensor_name = signature[signature_key].outputs[output_key_p].name\n    \n    x = sess.graph.get_tensor_by_name(x_tensor_name)\n    y_classes = sess.graph.get_tensor_by_name(y_classes_tensor_name)    \n    #y_p = sess.graph.get_tensor_by_name(y_p_tensor_name)\n        \n    for index, row in metadata_test.iterrows():\n        #experiment  plate well cell_type\n        experiment = row[\"experiment\"]\n        plate = row[\"plate\"]\n        well = row[\"well\"]\n        cell_type = row[\"cell_type\"]\n        #I only test for site 1, you should include site 2 data as well\n        image_raw = load_site(experiment, plate, well, 1, base_path=DEFAULT_TEST_BASE_PATH)\n        \n        image = process_image(image_raw)\n        #y_out = sess.run([y_classes, y_p], {x: image})\n        y_out = sess.run(y_classes, {x: image})\n        #sirna = y_out[0][0]\n        sirna = y_out[0]\n        #prob = y_out[1][0,sirna]\n        \n        id_code = get_id_code(experiment,plate,well)\n        #df.loc[index] = [id_code, sirna, prob]\n        df.loc[index] = [id_code, sirna]\n        if index % 100 == 0:            \n            elapsed_time = time.time() - start_time\n            print(\"processed row {} with {} minutes\".format(index, (elapsed_time/60)))   \n        #Only test for first 200. Remove this code for the whole dataset\n        if index>20000:\n            break","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"submission = df\nsubmission.to_csv('submission.csv', index=False)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"There are many things that we can improve the score. Some possible ways are\n</br>TODO:\n* Add site 2 images for train and test dataset.\n* Add control data.\n\nPlease <font color=\"green\" size=\"5\">upvote</font> this kernel to help me motivated. :)"}],"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.7"}},"nbformat":4,"nbformat_minor":1}