{"cells":[{"metadata":{},"cell_type":"markdown","source":"## Reading TFRecords for RSNA-STR Pulmonary Embolism Detection\n\nWe've provided a set of TFRecords for this competition. They contain all DICOM data, including the full DICOM pixel data. This notebook walks through the code for reading / using those TFRecords.\n\nNote: we have tried to create the most useful form of TFRecords for this competition - we'd love feedback about changes we could make the next time we have DICOM files in a competition."},{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":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\n\nimport tensorflow as tf\n\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\n\nimport matplotlib.pyplot as plt\n\n# Input data files are available in the read-only \"../input/\" directory\n# You can write up to 5GB to the current directory (/kaggle/working/) that gets preserved as output when you create a version using \"Save & Run All\" \n# You can also write temporary files to /kaggle/temp/, but they won't be saved outside of the current session","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"The format for unlabeled (test) data. Note that DICOM fields are all formatted as byte strings, and will require decoding / casting if using them in other ways.\n\nThe one exception here is \"image\", which contains the PixelData field, encoded as a byte string that will most likely be reconstructed into a numpy array before use. (Code below.)"},{"metadata":{"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","trusted":true},"cell_type":"code","source":"UNLABELED_TFRECORD_FORMAT = {'SpecificCharacterSet': tf.io.FixedLenFeature(shape=(), dtype=tf.string, default_value=None),\n 'ImageType': tf.io.FixedLenFeature(shape=(), dtype=tf.string, default_value=None),\n 'SOPClassUID': tf.io.FixedLenFeature(shape=(), dtype=tf.string, default_value=None),\n 'SOPInstanceUID': tf.io.FixedLenFeature(shape=(), dtype=tf.string, default_value=None),\n 'Modality': tf.io.FixedLenFeature(shape=(), dtype=tf.string, default_value=None),\n 'SliceThickness': tf.io.FixedLenFeature(shape=(), dtype=tf.string, default_value=None),\n 'KVP': tf.io.FixedLenFeature(shape=(), dtype=tf.string, default_value=None),\n 'GantryDetectorTilt': tf.io.FixedLenFeature(shape=(), dtype=tf.string, default_value=None),\n 'TableHeight': tf.io.FixedLenFeature(shape=(), dtype=tf.string, default_value=None),\n 'RotationDirection': tf.io.FixedLenFeature(shape=(), dtype=tf.string, default_value=None),\n 'XRayTubeCurrent': tf.io.FixedLenFeature(shape=(), dtype=tf.string, default_value=None),\n 'Exposure': tf.io.FixedLenFeature(shape=(), dtype=tf.string, default_value=None),\n 'ConvolutionKernel': tf.io.FixedLenFeature(shape=(), dtype=tf.string, default_value=None),\n 'PatientPosition': tf.io.FixedLenFeature(shape=(), dtype=tf.string, default_value=None),\n 'StudyInstanceUID': tf.io.FixedLenFeature(shape=(), dtype=tf.string, default_value=None),\n 'SeriesInstanceUID': tf.io.FixedLenFeature(shape=(), dtype=tf.string, default_value=None),\n 'SeriesNumber': tf.io.FixedLenFeature(shape=(), dtype=tf.string, default_value=None),\n 'InstanceNumber': tf.io.FixedLenFeature(shape=(), dtype=tf.string, default_value=None),\n 'ImagePositionPatient': tf.io.FixedLenFeature(shape=(), dtype=tf.string, default_value=None),\n 'ImageOrientationPatient': tf.io.FixedLenFeature(shape=(), dtype=tf.string, default_value=None),\n 'FrameOfReferenceUID': tf.io.FixedLenFeature(shape=(), dtype=tf.string, default_value=None),\n 'SamplesPerPixel': tf.io.FixedLenFeature(shape=(), dtype=tf.string, default_value=None),\n 'PhotometricInterpretation': tf.io.FixedLenFeature(shape=(), dtype=tf.string, default_value=None),\n 'Rows': tf.io.FixedLenFeature(shape=(), dtype=tf.string, default_value=None),\n 'Columns': tf.io.FixedLenFeature(shape=(), dtype=tf.string, default_value=None),\n 'PixelSpacing': tf.io.FixedLenFeature(shape=(), dtype=tf.string, default_value=None),\n 'BitsAllocated': tf.io.FixedLenFeature(shape=(), dtype=tf.string, default_value=None),\n 'BitsStored': tf.io.FixedLenFeature(shape=(), dtype=tf.string, default_value=None),\n 'HighBit': tf.io.FixedLenFeature(shape=(), dtype=tf.string, default_value=None),\n 'PixelRepresentation': tf.io.FixedLenFeature(shape=(), dtype=tf.string, default_value=None),\n 'WindowCenter': tf.io.FixedLenFeature(shape=(), dtype=tf.string, default_value=None),\n 'WindowWidth': tf.io.FixedLenFeature(shape=(), dtype=tf.string, default_value=None),\n 'RescaleIntercept': tf.io.FixedLenFeature(shape=(), dtype=tf.string, default_value=None),\n 'RescaleSlope': tf.io.FixedLenFeature(shape=(), dtype=tf.string, default_value=None),\n 'image': tf.io.FixedLenFeature(shape=(), dtype=tf.string, default_value=None)}","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"The format for labeled (train) data. This is identical to the test format, except for the labels themselves, which are stored as `int`."},{"metadata":{"trusted":true},"cell_type":"code","source":"LABELED_TFRECORD_FORMAT = {'SpecificCharacterSet': tf.io.FixedLenFeature(shape=(), dtype=tf.string, default_value=None),\n 'ImageType': tf.io.FixedLenFeature(shape=(), dtype=tf.string, default_value=None),\n 'SOPClassUID': tf.io.FixedLenFeature(shape=(), dtype=tf.string, default_value=None),\n 'SOPInstanceUID': tf.io.FixedLenFeature(shape=(), dtype=tf.string, default_value=None),\n 'Modality': tf.io.FixedLenFeature(shape=(), dtype=tf.string, default_value=None),\n 'SliceThickness': tf.io.FixedLenFeature(shape=(), dtype=tf.string, default_value=None),\n 'KVP': tf.io.FixedLenFeature(shape=(), dtype=tf.string, default_value=None),\n 'GantryDetectorTilt': tf.io.FixedLenFeature(shape=(), dtype=tf.string, default_value=None),\n 'TableHeight': tf.io.FixedLenFeature(shape=(), dtype=tf.string, default_value=None),\n 'RotationDirection': tf.io.FixedLenFeature(shape=(), dtype=tf.string, default_value=None),\n 'XRayTubeCurrent': tf.io.FixedLenFeature(shape=(), dtype=tf.string, default_value=None),\n 'Exposure': tf.io.FixedLenFeature(shape=(), dtype=tf.string, default_value=None),\n 'ConvolutionKernel': tf.io.FixedLenFeature(shape=(), dtype=tf.string, default_value=None),\n 'PatientPosition': tf.io.FixedLenFeature(shape=(), dtype=tf.string, default_value=None),\n 'StudyInstanceUID': tf.io.FixedLenFeature(shape=(), dtype=tf.string, default_value=None),\n 'SeriesInstanceUID': tf.io.FixedLenFeature(shape=(), dtype=tf.string, default_value=None),\n 'SeriesNumber': tf.io.FixedLenFeature(shape=(), dtype=tf.string, default_value=None),\n 'InstanceNumber': tf.io.FixedLenFeature(shape=(), dtype=tf.string, default_value=None),\n 'ImagePositionPatient': tf.io.FixedLenFeature(shape=(), dtype=tf.string, default_value=None),\n 'ImageOrientationPatient': tf.io.FixedLenFeature(shape=(), dtype=tf.string, default_value=None),\n 'FrameOfReferenceUID': tf.io.FixedLenFeature(shape=(), dtype=tf.string, default_value=None),\n 'SamplesPerPixel': tf.io.FixedLenFeature(shape=(), dtype=tf.string, default_value=None),\n 'PhotometricInterpretation': tf.io.FixedLenFeature(shape=(), dtype=tf.string, default_value=None),\n 'Rows': tf.io.FixedLenFeature(shape=(), dtype=tf.string, default_value=None),\n 'Columns': tf.io.FixedLenFeature(shape=(), dtype=tf.string, default_value=None),\n 'PixelSpacing': tf.io.FixedLenFeature(shape=(), dtype=tf.string, default_value=None),\n 'BitsAllocated': tf.io.FixedLenFeature(shape=(), dtype=tf.string, default_value=None),\n 'BitsStored': tf.io.FixedLenFeature(shape=(), dtype=tf.string, default_value=None),\n 'HighBit': tf.io.FixedLenFeature(shape=(), dtype=tf.string, default_value=None),\n 'PixelRepresentation': tf.io.FixedLenFeature(shape=(), dtype=tf.string, default_value=None),\n 'WindowCenter': tf.io.FixedLenFeature(shape=(), dtype=tf.string, default_value=None),\n 'WindowWidth': tf.io.FixedLenFeature(shape=(), dtype=tf.string, default_value=None),\n 'RescaleIntercept': tf.io.FixedLenFeature(shape=(), dtype=tf.string, default_value=None),\n 'RescaleSlope': tf.io.FixedLenFeature(shape=(), dtype=tf.string, default_value=None),\n 'negative_exam_for_pe': tf.io.FixedLenFeature(shape=(), dtype=tf.int64, default_value=None),\n 'qa_motion': tf.io.FixedLenFeature(shape=(), dtype=tf.int64, default_value=None),\n 'qa_contrast': tf.io.FixedLenFeature(shape=(), dtype=tf.int64, default_value=None),\n 'flow_artifact': tf.io.FixedLenFeature(shape=(), dtype=tf.int64, default_value=None),\n 'rv_lv_ratio_gte_1': tf.io.FixedLenFeature(shape=(), dtype=tf.int64, default_value=None),\n 'rv_lv_ratio_lt_1': tf.io.FixedLenFeature(shape=(), dtype=tf.int64, default_value=None),\n 'leftsided_pe': tf.io.FixedLenFeature(shape=(), dtype=tf.int64, default_value=None),\n 'chronic_pe': tf.io.FixedLenFeature(shape=(), dtype=tf.int64, default_value=None),\n 'true_filling_defect_not_pe': tf.io.FixedLenFeature(shape=(), dtype=tf.int64, default_value=None),\n 'rightsided_pe': tf.io.FixedLenFeature(shape=(), dtype=tf.int64, default_value=None),\n 'acute_and_chronic_pe': tf.io.FixedLenFeature(shape=(), dtype=tf.int64, default_value=None),\n 'central_pe': tf.io.FixedLenFeature(shape=(), dtype=tf.int64, default_value=None),\n 'indeterminate': tf.io.FixedLenFeature(shape=(), dtype=tf.int64, default_value=None),\n 'pe_present_on_image': tf.io.FixedLenFeature(shape=(), dtype=tf.int64, default_value=None),\n 'image': tf.io.FixedLenFeature(shape=(), dtype=tf.string, default_value=None)}","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Here, we cast our variables into their expected forms."},{"metadata":{"trusted":true},"cell_type":"code","source":"def read_labeled_tfrecord(example):\n    return read_tfrecord(example, LABELED_TFRECORD_FORMAT)\n\ndef read_unlabeled_tfrecord(example):\n    return read_tfrecord(example, UNLABELED_TFRECORD_FORMAT)\n\ndef read_tfrecord(example, record_format):\n    try:\n        example = tf.io.parse_single_example(example, record_format)\n    except:\n        print (example)\n        raise\n    \n    data = {k:tf.cast(example[k], record_format[k].dtype) for k in example}\n        \n    return data","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def load_dataset(filenames, labeled=True, ordered=False):\n    # Read from TFRecords. For optimal performance, reading from multiple files at once and\n    # disregarding data order. Order does not matter since we will be shuffling the data anyway.\n\n    ignore_order = tf.data.Options()\n    if not ordered:\n        ignore_order.experimental_deterministic = False # disable order, increase speed\n\n    dataset = tf.data.TFRecordDataset(filenames) # automatically interleaves reads from multiple files\n    dataset = dataset.with_options(ignore_order) # uses data as soon as it streams in, rather than in its original order\n    dataset = dataset.map(read_labeled_tfrecord if labeled else read_unlabeled_tfrecord)\n    # returns a dataset of (image, label) pairs if labeled=True or (image, id) pairs if labeled=False\n    return dataset","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Load the datasets from disk. These could also be loaded from GCS buckets using the `KaggleDatasets` library, shown further down."},{"metadata":{"trusted":true},"cell_type":"code","source":"train_dataset = load_dataset(tf.io.gfile.glob('/kaggle/input/rsna-pe-tfrecords-v2/train/*.tfrec'), labeled=True)\ntest_dataset = load_dataset(tf.io.gfile.glob('/kaggle/input/rsna-pe-tfrecords-v2/test/*.tfrec'), labeled=False)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# from kaggle_datasets import KaggleDatasets\n\n# GCS_DS_PATH = KaggleDatasets().get_gcs_path(\"rsna-pe-tfrecords-v2\") # you can list the bucket with \"!gsutil ls $GCS_DS_PATH\"\n\n# train_dataset = load_dataset(tf.io.gfile.glob(GCS_DATA_PATH + '/train/*.tfrec'), labeled=True)\n# test_dataset = load_dataset(tf.io.gfile.glob(GCS_DATA_PATH + '/test/*.tfrec'), labeled=False)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def plot_img(im):\n    plt.figure(figsize=(10,10))\n    ax = plt.subplot(1,2,1)\n    plt.imshow(im)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"In the next two loops, we'll show an example of decoding a byte-string DICOM field, and also of putting our DICOM image back into a numpy array."},{"metadata":{"trusted":true},"cell_type":"code","source":"train_fnames = []\n\nfor index, image_features in enumerate(train_dataset.as_numpy_iterator()):\n    ## decoding the byte string all DICOM fields are stored in:\n    image_name = image_features[\"SOPInstanceUID\"].decode(\"utf-8\")\n    train_fnames.append(image_name)\n    \n    ## decoding and checking our image data. Note that we're ONLY reading the first five entries.\n    if index < 5:\n        image = np.frombuffer(image_features[\"image\"], dtype=np.int16).reshape((512,512))\n        plot_img(image)\n    else:\n        break","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"test_fnames = []\n\nfor index, image_features in enumerate(test_dataset.as_numpy_iterator()):\n    ## decoding the byte string all DICOM fields are stored in:    \n    image_name = image_features[\"SOPInstanceUID\"].decode(\"utf-8\")\n    test_fnames.append(image_name)\n    \n    ## decoding and checking our image data. Note that we're ONLY reading the first five entries.\n    if index < 5:\n        image = np.frombuffer(image_features[\"image\"], dtype=np.int16).reshape((512,512))\n        plot_img(image)\n    else:\n        break","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"markdown","source":"And now we're ready to use the contents of these TFRecords with CPU, GPU or TPU!"},{"metadata":{"trusted":true},"cell_type":"code","source":"","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}