{"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":"## What are TPUs?\nThe Tensor Processing Unit (TPU) is a custom integrated chip, designed specifically to accelerate the process of training machine learning models. \n\n## TPUs for free at Kaggle\n**You can use up to 30 hours per week of TPUs and up to 9h at a time in a single session.**\n**For more info you can visit [here](https://www.kaggle.com/docs/tpu).**\n\n## Why do we need TFRecord format?\nThe TFRecord format is tensorflow's custom data format which is simple for storing a sequence of binary records. The advantages of using TFRecords are amazingly more efficient storage, fast I/O, self-contained files, etc. The main advantage of TPUs are faster I/O which results in faster model training.\n\nFor understanding the basics of TFRecords, please visit Ryan Holbrook notebook: [TFRecords Basics](https://www.kaggle.com/ryanholbrook/tfrecords-basics).\n\n### In this notebook you will learn how to convert image dataset into TFRecord format.\n\n## Useful resources which helped me:¶\n* https://www.tensorflow.org/tutorials/load_data/tfrecord\n* https://www.kaggle.com/mgornergoogle/five-flowers-with-keras-and-xception-on-tpu\n* https://towardsdatascience.com/a-practical-guide-to-tfrecords-584536bc786c\n* https://keras.io/examples/keras_recipes/creating_tfrecords/\n* https://www.kaggle.com/lqdisme/dog-breed-identification\n* https://cloud.google.com/blog/products/ai-machine-learning/what-makes-tpus-fine-tuned-for-deep-learning\n* https://pub.towardsai.net/writing-tfrecord-files-the-right-way-7c3cee3d7b12","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","_kg_hide-output":true,"execution":{"iopub.status.busy":"2021-09-21T12:38:18.803107Z","iopub.execute_input":"2021-09-21T12:38:18.803365Z","iopub.status.idle":"2021-09-21T12:38:26.434626Z","shell.execute_reply.started":"2021-09-21T12:38:18.803334Z","shell.execute_reply":"2021-09-21T12:38:26.433539Z"}}},{"cell_type":"markdown","source":"# Imports","metadata":{}},{"cell_type":"code","source":"import os\nimport numpy as np\nimport pandas as pd\nimport tensorflow as tf\nfrom PIL import Image\nfrom numpy import asarray\nfrom tensorflow.keras.preprocessing.image import img_to_array,load_img,ImageDataGenerator\nfrom tensorflow.keras.utils import to_categorical\nimport matplotlib.pyplot as plt\nimport warnings\nwarnings.filterwarnings(\"ignore\")","metadata":{"execution":{"iopub.status.busy":"2021-10-19T09:56:53.069105Z","iopub.execute_input":"2021-10-19T09:56:53.069477Z","iopub.status.idle":"2021-10-19T09:56:53.079473Z","shell.execute_reply.started":"2021-10-19T09:56:53.069445Z","shell.execute_reply":"2021-10-19T09:56:53.077143Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Loading datasets","metadata":{}},{"cell_type":"code","source":"TRAIN_DIR = '../input/dog-breed-identification/train'\nTEST_DIR = '../input/dog-breed-identification/test'\ndf = pd.read_csv('../input/dog-breed-identification/labels.csv')\nsubmission_df = pd.read_csv('../input/dog-breed-identification/sample_submission.csv')","metadata":{"execution":{"iopub.status.busy":"2021-10-11T07:46:02.408418Z","iopub.execute_input":"2021-10-11T07:46:02.409009Z","iopub.status.idle":"2021-10-11T07:46:03.125942Z","shell.execute_reply.started":"2021-10-11T07:46:02.40896Z","shell.execute_reply":"2021-10-11T07:46:03.12501Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Feature Engineering","metadata":{}},{"cell_type":"code","source":"dog_breeds = sorted(list(set(df['breed'])))\nnum_classes = len(dog_breeds)\nclass_to_num = dict(zip(dog_breeds, range(num_classes)))","metadata":{"execution":{"iopub.status.busy":"2021-10-11T07:46:03.127411Z","iopub.execute_input":"2021-10-11T07:46:03.127686Z","iopub.status.idle":"2021-10-11T07:46:03.14578Z","shell.execute_reply.started":"2021-10-11T07:46:03.127653Z","shell.execute_reply":"2021-10-11T07:46:03.14467Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from tqdm import tqdm\n\ndef load_image(TRAIN_DIR, df, image_size):\n    image_names = df['id']\n    labels = df['breed']\n    data_size = len(labels)\n    \n    X = np.empty([data_size, image_size[0], image_size[1], image_size[2]], dtype=np.uint8)\n    y = np.empty([data_size, 1], dtype=np.uint8)\n    \n    for i in tqdm(range(data_size)):\n        img_path = os.path.join(TRAIN_DIR, image_names[i]+'.jpg')\n        image = load_img(img_path, target_size=image_size)\n        X[i] = image\n        y[i] = class_to_num[labels[i]]\n    y = to_categorical(y)    \n    ind = np.random.permutation(data_size)\n    X = X[ind]\n    y = y[ind]\n    print(f\"X shape: {X.shape}\\ny shape: {y.shape}\")\n    return X,y\n\nimage_size = (331, 331, 3)\nX, y = load_image(TRAIN_DIR, df, image_size) ","metadata":{"execution":{"iopub.status.busy":"2021-10-11T07:46:03.147307Z","iopub.execute_input":"2021-10-11T07:46:03.147565Z","iopub.status.idle":"2021-10-11T07:48:16.748592Z","shell.execute_reply.started":"2021-10-11T07:46:03.147536Z","shell.execute_reply":"2021-10-11T07:48:16.747501Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def load_test_image(TEST_DIR, test_df, image_size):\n    image_names = test_df['id']\n    data_size = len(image_names)\n    X = np.empty([data_size, image_size[0], image_size[1], image_size[2]], dtype=np.uint8)\n\n    for i in tqdm(range(data_size)):\n        image_path = os.path.join(TEST_DIR, image_names[i]+'.jpg')\n        image = load_img(image_path, target_size=image_size)\n        X[i] = image\n    \n    print(f\"Test data shape: {X.shape}\")\n    return X\n\ntest = load_test_image(TEST_DIR, submission_df, image_size)","metadata":{"execution":{"iopub.status.busy":"2021-10-11T07:48:16.75066Z","iopub.execute_input":"2021-10-11T07:48:16.751046Z","iopub.status.idle":"2021-10-11T07:50:28.225465Z","shell.execute_reply.started":"2021-10-11T07:48:16.750987Z","shell.execute_reply":"2021-10-11T07:50:28.224441Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Funtions for feature creation\nThe following functions can be used to convert a value to a type compatible which takes a scalar input values and returns a tf.train.Feature.","metadata":{}},{"cell_type":"code","source":"def _bytes_feature(value):\n    if isinstance(value, type(tf.constant(0))): # if value ist tensor\n        value = value.numpy() # get value of tensor\n    return tf.train.Feature(bytes_list=tf.train.BytesList(value=[value]))\n\ndef _float_feature(value):\n    return tf.train.Feature(float_list=tf.train.FloatList(value=[value]))\n\ndef _int64_feature(value):\n    return tf.train.Feature(int64_list=tf.train.Int64List(value=[value]))\n\ndef serialize_array(array):\n    array = tf.io.serialize_tensor(array)\n    return array","metadata":{"execution":{"iopub.status.busy":"2021-10-11T07:50:28.227336Z","iopub.execute_input":"2021-10-11T07:50:28.227702Z","iopub.status.idle":"2021-10-11T07:50:28.239654Z","shell.execute_reply.started":"2021-10-11T07:50:28.227658Z","shell.execute_reply":"2021-10-11T07:50:28.238706Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def parse_single_image(image, label=None):\n    if label is None:\n        data = {\n                'height' : _int64_feature(image.shape[0]),\n                'width' : _int64_feature(image.shape[1]),\n                'depth' : _int64_feature(image.shape[2]),\n                'raw_image' : _bytes_feature(serialize_array(image)),\n        }\n    else:\n        data = {\n                'height' : _int64_feature(image.shape[0]),\n                'width' : _int64_feature(image.shape[1]),\n                'depth' : _int64_feature(image.shape[2]),\n                'raw_image' : _bytes_feature(serialize_array(image)),\n                'label' : _bytes_feature(serialize_array(label))\n        }\n    out = tf.train.Example(features=tf.train.Features(feature=data))\n    return out","metadata":{"execution":{"iopub.status.busy":"2021-10-11T07:50:28.242805Z","iopub.execute_input":"2021-10-11T07:50:28.243098Z","iopub.status.idle":"2021-10-11T07:50:28.252428Z","shell.execute_reply.started":"2021-10-11T07:50:28.243064Z","shell.execute_reply":"2021-10-11T07:50:28.251417Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Writing and Converting to TFRecord\n\nNow, we'll create a dictionary to store the actual image, height, width and depth of the image and the label where we first serialize the array and then convert it to a bytes_feature. All these key:value mappings make up the features for one Example.\n","metadata":{}},{"cell_type":"code","source":"import tqdm\ndef write_images_to_tfr(images, filename, labels=None):\n    max_files=800\n    out_dir=\"./\"\n    splits = (len(images)//max_files) + 1 #determine how many shards are needed\n    if len(images)%max_files == 0:\n        splits-=1\n    print(f\"\\nUsing {splits} shard(s) for {len(images)} files, with up to {max_files} samples per shard\")\n    \n    file_count = 0\n\n    for i in tqdm.tqdm(range(splits)):\n        current_shard_name = \"{}{}_{}{}.tfrecords\".format(out_dir, i+1, splits, filename)\n        writer = tf.io.TFRecordWriter(current_shard_name)\n\n        current_shard_count = 0\n        while current_shard_count < max_files: \n            index = i*max_files+current_shard_count\n            if index == len(images): \n                break\n            if labels is None:  \n                current_image = images[index]\n                out = parse_single_image(image=current_image)\n\n            else:\n                current_image = images[index]\n                current_label = labels[index]\n                out = parse_single_image(image=current_image, label=current_label)\n    \n            writer.write(out.SerializeToString())\n            current_shard_count+=1\n            file_count += 1\n\n        writer.close()\n    print(f\"\\nWrote {file_count} elements to TFRecord\")\n    return file_count","metadata":{"execution":{"iopub.status.busy":"2021-10-11T07:50:28.255654Z","iopub.execute_input":"2021-10-11T07:50:28.256012Z","iopub.status.idle":"2021-10-11T07:50:28.266444Z","shell.execute_reply.started":"2021-10-11T07:50:28.255975Z","shell.execute_reply":"2021-10-11T07:50:28.265557Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"write_images_to_tfr(X, \"train_images\", y)\nwrite_images_to_tfr(test, \"test_images\")\n","metadata":{"execution":{"iopub.status.busy":"2021-10-11T07:50:28.268054Z","iopub.execute_input":"2021-10-11T07:50:28.268377Z","iopub.status.idle":"2021-10-11T07:51:36.403069Z","shell.execute_reply.started":"2021-10-11T07:50:28.268336Z","shell.execute_reply":"2021-10-11T07:51:36.401494Z"},"trusted":true},"execution_count":null,"outputs":[]}]}