{"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_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"## Creating TFRecords\n- https://keras.io/examples/keras_recipes/creating_tfrecords/#define-tfrecords-helper-functions","metadata":{}},{"cell_type":"code","source":"import glob\nimport random\nimport os\nimport math\n\nimport pandas as pd\nimport numpy as np\nimport matplotlib.pylab as plt\nfrom tqdm.notebook import tqdm\nimport tensorflow as tf\nfrom tensorflow.data import AUTOTUNE\nimport tensorflow_addons as tfa\nimport tensorflow_datasets as tfds\nfrom sklearn.model_selection import train_test_split, GroupShuffleSplit\nfrom kaggle_datasets import KaggleDatasets\n\nplt.style.use('ggplot')\nplt.rcParams['figure.figsize'] = (12, 10)","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2022-02-06T00:11:15.161932Z","iopub.execute_input":"2022-02-06T00:11:15.162360Z","iopub.status.idle":"2022-02-06T00:11:25.352664Z","shell.execute_reply.started":"2022-02-06T00:11:15.162247Z","shell.execute_reply":"2022-02-06T00:11:25.351731Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"!ls ../input/happy-whale-and-dolphin","metadata":{"execution":{"iopub.status.busy":"2022-02-06T00:11:25.354478Z","iopub.execute_input":"2022-02-06T00:11:25.354837Z","iopub.status.idle":"2022-02-06T00:11:26.150624Z","shell.execute_reply.started":"2022-02-06T00:11:25.354800Z","shell.execute_reply":"2022-02-06T00:11:26.149432Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_paths = glob.glob('../input/happy-whale-and-dolphin/train_images/*')\ntest_paths = glob.glob('../input/happy-whale-and-dolphin/test_images/*')   \ntest_labels = np.repeat(-1, len(test_paths))\nprint('Number of train images:', len(train_paths))\nprint('Number of test images:', len(test_paths))","metadata":{"execution":{"iopub.status.busy":"2022-02-06T00:11:26.152481Z","iopub.execute_input":"2022-02-06T00:11:26.152777Z","iopub.status.idle":"2022-02-06T00:11:27.696758Z","shell.execute_reply.started":"2022-02-06T00:11:26.152745Z","shell.execute_reply":"2022-02-06T00:11:27.695861Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train = pd.read_csv('../input/happy-whale-and-dolphin/train.csv')\nind2label = {x: i for i, x in enumerate(train['individual_id'].unique())}\nlabel2ind = {x[1]: x[0] for x in ind2label.items()}\ntrain['label'] = train['individual_id'].map(ind2label)\n\n# thanks to https://www.kaggle.com/c/happy-whale-and-dolphin/discussion/305574\ntrain['species'] = train['species'].replace({\n    \"globis\": \"short_finned_pilot_whale\",\n    \"pilot_whale\": \"short_finned_pilot_whale\",\n    \"kiler_whale\": \"killer_whale\",\n    \"bottlenose_dolpin\": \"bottlenose_dolphin\"\n})","metadata":{"execution":{"iopub.status.busy":"2022-02-06T00:11:27.699055Z","iopub.execute_input":"2022-02-06T00:11:27.699995Z","iopub.status.idle":"2022-02-06T00:11:27.917474Z","shell.execute_reply.started":"2022-02-06T00:11:27.699942Z","shell.execute_reply":"2022-02-06T00:11:27.916138Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print('Number of unique species:', train['species'].unique().shape[0])","metadata":{"execution":{"iopub.status.busy":"2022-02-06T00:11:27.919196Z","iopub.execute_input":"2022-02-06T00:11:27.920152Z","iopub.status.idle":"2022-02-06T00:11:27.933323Z","shell.execute_reply.started":"2022-02-06T00:11:27.920102Z","shell.execute_reply":"2022-02-06T00:11:27.932167Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"ax = train['species'].value_counts(ascending=True).plot.barh()\nax.bar_label(ax.containers[0]);","metadata":{"execution":{"iopub.status.busy":"2022-02-06T00:11:27.934979Z","iopub.execute_input":"2022-02-06T00:11:27.935304Z","iopub.status.idle":"2022-02-06T00:11:28.743966Z","shell.execute_reply.started":"2022-02-06T00:11:27.935259Z","shell.execute_reply":"2022-02-06T00:11:28.742935Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"ax = train['species'].value_counts(ascending=True, normalize=True).plot.barh()\nax.bar_label(ax.containers[0]);","metadata":{"execution":{"iopub.status.busy":"2022-02-06T00:11:28.745398Z","iopub.execute_input":"2022-02-06T00:11:28.745667Z","iopub.status.idle":"2022-02-06T00:11:29.465301Z","shell.execute_reply.started":"2022-02-06T00:11:28.745629Z","shell.execute_reply":"2022-02-06T00:11:29.464298Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Splitting","metadata":{}},{"cell_type":"code","source":"class CFG:\n    seed = 42\n    val_size = 0.25\n    img_height = 128\n    img_width = 128","metadata":{"execution":{"iopub.status.busy":"2022-02-06T00:11:29.466795Z","iopub.execute_input":"2022-02-06T00:11:29.467018Z","iopub.status.idle":"2022-02-06T00:11:29.471518Z","shell.execute_reply.started":"2022-02-06T00:11:29.466992Z","shell.execute_reply":"2022-02-06T00:11:29.470573Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_imgs, val_imgs, train_labels, val_labels = train_test_split(\n    train['image'],\n    train['label'],\n    test_size=CFG.val_size,\n    random_state=CFG.seed,\n    stratify=train['species']\n)\n\n# https://stackoverflow.com/questions/54797508/how-to-generate-a-train-test-split-based-on-a-group-id\n# tr, val = next(\n#     GroupShuffleSplit(\n#         n_splits=2,\n#         test_size=Config.val_size,\n#         random_state=Config.seed\n#     ).split(train['image'], groups=train['label'])\n# )\n# train_imgs, val_imgs = train['image'].iloc[tr], train['image'].iloc[val]\n# train_labels, val_labels = train['label'].iloc[tr], train['label'].iloc[val]\n\ntrain_imgs = ('../input/happy-whale-and-dolphin/train_images/' + train_imgs).values\nval_imgs = ('../input/happy-whale-and-dolphin/train_images/' + val_imgs).values\ntrain_labels = train_labels.values\nval_labels = val_labels.values\n\ntrain_imgs.shape, val_imgs.shape, train_labels.shape, val_labels.shape","metadata":{"execution":{"iopub.status.busy":"2022-02-06T00:11:29.472858Z","iopub.execute_input":"2022-02-06T00:11:29.473123Z","iopub.status.idle":"2022-02-06T00:11:29.589313Z","shell.execute_reply.started":"2022-02-06T00:11:29.473095Z","shell.execute_reply":"2022-02-06T00:11:29.588433Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print(len(np.unique(train_labels)))\nprint(len(np.unique(val_labels)))","metadata":{"execution":{"iopub.status.busy":"2022-02-06T00:11:29.591710Z","iopub.execute_input":"2022-02-06T00:11:29.592226Z","iopub.status.idle":"2022-02-06T00:11:29.601893Z","shell.execute_reply.started":"2022-02-06T00:11:29.592183Z","shell.execute_reply":"2022-02-06T00:11:29.600873Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"len(set(train_labels) & set(val_labels))","metadata":{"execution":{"iopub.status.busy":"2022-02-06T00:11:29.603132Z","iopub.execute_input":"2022-02-06T00:11:29.603373Z","iopub.status.idle":"2022-02-06T00:11:29.625987Z","shell.execute_reply.started":"2022-02-06T00:11:29.603346Z","shell.execute_reply":"2022-02-06T00:11:29.624966Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Defining TFRecords helper functions","metadata":{}},{"cell_type":"code","source":"num_samples = 4096\n\ndef calculate_num_tf_records(paths):\n    num_tfrecords = len(paths) // num_samples\n    if len(paths) % num_samples:\n        num_tfrecords += 1  # add one record if there are any remaining samples\n    return num_tfrecords\n\ndef image_feature(value):\n    \"\"\"Returns a bytes_list from a string / byte.\"\"\"\n    return tf.train.Feature(\n        bytes_list=tf.train.BytesList(value=[tf.io.encode_jpeg(value).numpy()])\n    )\n\ndef bytes_feature(value):\n    \"\"\"Returns a bytes_list from a string / byte.\"\"\"\n    return tf.train.Feature(bytes_list=tf.train.BytesList(value=[value.encode()]))\n\ndef float_feature(value):\n    \"\"\"Returns a float_list from a float / double.\"\"\"\n    return tf.train.Feature(float_list=tf.train.FloatList(value=[value]))\n\ndef int64_feature(value):\n    \"\"\"Returns an int64_list from a bool / enum / int / uint.\"\"\"\n    return tf.train.Feature(int64_list=tf.train.Int64List(value=[value]))\n\ndef float_feature_list(value):\n    \"\"\"Returns a list of float_list from a float / double.\"\"\"\n    return tf.train.Feature(float_list=tf.train.FloatList(value=value))\n\ndef create_example(image, label, path):\n    feature = {\n        \"image\": image_feature(image),\n        \"label\": int64_feature(label),\n        \"path\": bytes_feature(path)\n    }\n    return tf.train.Example(features=tf.train.Features(feature=feature))","metadata":{"execution":{"iopub.status.busy":"2022-02-06T00:11:29.627321Z","iopub.execute_input":"2022-02-06T00:11:29.627575Z","iopub.status.idle":"2022-02-06T00:11:29.641974Z","shell.execute_reply.started":"2022-02-06T00:11:29.627544Z","shell.execute_reply":"2022-02-06T00:11:29.641005Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_len_records = calculate_num_tf_records(train_imgs)\nval_len_records = calculate_num_tf_records(val_imgs)\ntest_len_records = calculate_num_tf_records(test_paths)\nprint(train_len_records, val_len_records, test_len_records)","metadata":{"execution":{"iopub.status.busy":"2022-02-06T00:11:29.643195Z","iopub.execute_input":"2022-02-06T00:11:29.643490Z","iopub.status.idle":"2022-02-06T00:11:29.659938Z","shell.execute_reply.started":"2022-02-06T00:11:29.643458Z","shell.execute_reply":"2022-02-06T00:11:29.659066Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Writing TFRecords","metadata":{}},{"cell_type":"code","source":"def write_to_tfrecords(labels, paths, len_records: int, prefix: str):\n    for tfrec_num in range(len_records):\n        start, end = (tfrec_num * num_samples), ((tfrec_num + 1) * num_samples)\n        sample_labels = labels[start:end]\n        sample_paths = paths[start:end]\n        filename = prefix + \"-file_%.2i-%i.tfrec\" % (tfrec_num, len(sample_paths))\n        with tf.io.TFRecordWriter(filename) as writer:\n            for sample_label, sample_path in zip(sample_labels, sample_paths):\n                image = tf.io.decode_jpeg(tf.io.read_file(sample_path))\n                image = tf.cast(image, tf.float32)\n                image = tf.image.resize(image, size=(CFG.img_height, CFG.img_width))\n                image = tf.cast(image, tf.uint8)\n                example = create_example(image, sample_label, sample_path)\n                writer.write(example.SerializeToString())\n        print('Wrote', filename)","metadata":{"execution":{"iopub.status.busy":"2022-02-06T00:11:29.661070Z","iopub.execute_input":"2022-02-06T00:11:29.661576Z","iopub.status.idle":"2022-02-06T00:11:29.671822Z","shell.execute_reply.started":"2022-02-06T00:11:29.661545Z","shell.execute_reply":"2022-02-06T00:11:29.670916Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"%%time\n\nwrite_to_tfrecords(\n    labels=train_labels,\n    paths=train_imgs,\n    len_records=train_len_records,\n    prefix='train'\n)","metadata":{"execution":{"iopub.status.busy":"2022-02-06T00:11:29.672891Z","iopub.execute_input":"2022-02-06T00:11:29.673119Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"%%time\n\nwrite_to_tfrecords(\n    labels=val_labels,\n    paths=val_imgs,\n    len_records=val_len_records,\n    prefix='val'\n)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"%%time\n\nwrite_to_tfrecords(\n    labels=test_labels,\n    paths=test_paths,\n    len_records=test_len_records,\n    prefix='test'\n)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Reading TFRecords","metadata":{}},{"cell_type":"code","source":"def read_tfrecord(example):\n    features = {\n        'image': tf.io.FixedLenFeature([], tf.string),\n        'label': tf.io.FixedLenFeature([], tf.int64),  \n        'path': tf.io.FixedLenFeature([], tf.string)\n    }\n    example = tf.io.parse_single_example(example, features)\n    image = tf.io.decode_jpeg(example['image'], channels=3)\n    label = example['label']\n    path = example['path']\n    return image, label, path","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"filenames = tf.io.gfile.glob('./train*.tfrec')\nds = tf.data.TFRecordDataset(filenames, num_parallel_reads=AUTOTUNE)\nds = ds.map(read_tfrecord, num_parallel_calls=AUTOTUNE)\nds = ds.shuffle(300, seed=1)\nprint(ds)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# fast read!\nfor image, label, path in ds.take(3):\n    image = image.numpy()\n    label = label.numpy()\n    path = path.numpy()\n    \n    plt.imshow(image)\n    plt.title(f'label: {label}\\npath: {path.decode().split(\"/\")[-1]}')\n    plt.show();","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}