{ "cells": [ { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "import boto3\n", "from IPython.display import display\n", "import json\n", "import matplotlib.pyplot as plt\n", "from multiprocessing import cpu_count, Pool\n", "import os\n", "import numpy as np\n", "import pickle\n", "from PIL import Image\n", "import random\n", "import sagemaker\n", "from sklearn.model_selection import train_test_split\n", "import ssl\n", "import tarfile\n", "import tensorflow as tf\n", "from tqdm import tqdm\n", "import urllib.request" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "## set s3 bucket\n", "sm_session = sagemaker.Session()\n", "bucket = sm_session.default_bucket()" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "CINIC-10.tar.gz: 688MB [25:46, 445kB/s] \n" ] } ], "source": [ "## download cinic 10 dataset\n", "# https://datashare.is.ed.ac.uk/handle/10283/3192\n", "\n", "# download progress bar\n", "class DownloadProgressBar(tqdm):\n", " def update_to(self, b=1, bsize=1, tsize=None):\n", " if tsize is not None:\n", " self.total = tsize\n", " self.update(b * bsize - self.n)\n", "\n", "def download_url(url, output_path):\n", " ssl._create_default_https_context = ssl._create_unverified_context\n", " with DownloadProgressBar(unit='B', unit_scale=True,\n", " miniters=1, desc=url.split('/')[-1]) as t:\n", " urllib.request.urlretrieve(url, filename=output_path, reporthook=t.update_to)\n", " \n", "\n", "# set up and start download\n", "cinic_filename = 'CINIC-10.tar.gz'\n", "cinic_download_url = 'https://datashare.is.ed.ac.uk/bitstream/handle/10283/3192/' + cinic_filename\n", "local_data_folder = '../data'\n", "cinic_extracted_folder = 'cinic-10'\n", "\n", "os.makedirs(local_data_folder, exist_ok=True)\n", "download_url(cinic_download_url, local_data_folder +'/'+ cinic_filename)" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [], "source": [ "## extract files\n", "extracted_path = local_data_folder + '/' + cinic_extracted_folder\n", "tarfile.open(os.path.join(local_data_folder, cinic_filename), 'r:gz').extractall(extracted_path)" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [], "source": [ "## train/validation/test split\n", "# load file names\n", "image_files = [os.path.join(r,file) for r,d,f in os.walk(extracted_path) for file in f if file.endswith('.png')]\n", "\n", "# shuffle and split\n", "train_filenames, validation_test_filenames = train_test_split(\n", " image_files, train_size=0.8, test_size=0.2, random_state=24601)\n", "validation_filenames, test_filenames = train_test_split(\n", " validation_test_filenames, train_size=0.5, test_size=0.5, random_state=24601)" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "data": { "image/png": "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\n", "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "## visualize CINIC-10 data\n", "\n", "# plot the first 5 samples in test\n", "fig, ax = plt.subplots(1,5, figsize=(15,5))\n", "for i in range(5):\n", " \n", " # parse label\n", " label = train_filenames[i].split('/')[-2]\n", "\n", " # load and plot image\n", " image = Image.open(train_filenames[i])\n", " image_np = np.asarray(image)\n", " ax[i].set_axis_off()\n", " ax[i].imshow(image_np)\n", " ax[i].set_title(label)" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "{0: 'airplane', 1: 'automobile', 2: 'bird', 3: 'cat', 4: 'deer', 5: 'dog', 6: 'frog', 7: 'horse', 8: 'ship', 9: 'truck'}\n" ] } ], "source": [ "## create label dictionary\n", "all_labels = [filename.split('/')[-2] for filename in image_files]\n", "all_labels = sorted(list(set(all_labels)))\n", "label_dictionary = {k:v for k,v in zip(all_labels, range(0,len(all_labels)))}\n", "inverted_label_dictionary = {v:k for k,v in label_dictionary.items()}\n", "\n", "label_dictionary_json = json.dumps(label_dictionary)\n", "with open(\"../data/label_dictionary.json\", \"w\") as f:\n", " f.write(label_dictionary_json)\n", " \n", "inverted_label_dictionary_json = json.dumps(inverted_label_dictionary)\n", "with open(\"../data/inverted_label_dictionary.json\", \"w\") as f:\n", " f.write(inverted_label_dictionary_json)\n", "\n", "print(inverted_label_dictionary)" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [], "source": [ "## helper functions to build the tfrecords protocol buffer\n", "# https://www.tensorflow.org/tutorials/load_data/tfrecord\n", "\n", "def _bytes_feature(value):\n", " \"\"\"Returns a bytes_list from a string / byte.\"\"\"\n", " return tf.train.Feature(bytes_list=tf.train.BytesList(value=[value]))\n", "\n", "def _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", " \n", "def _float_feature(value):\n", " \"\"\"Returns a float_list from a float / double.\"\"\"\n", " return tf.train.Feature(float_list=tf.train.FloatList(value=[value]))" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [], "source": [ "## functions to shard and convert to tfrecords\n", "\n", "# function to build the tfrecord file\n", "def create_tfrecords_in_shards(data_filenames, record_index, dataset_name):\n", " \n", " # set up paths\n", " output_path = '../data/sharded_tfrecords/{}'.format(dataset_name)\n", " output_file = '{}/{}_{:03d}.tfrecords'.format(output_path, dataset_name, record_index)\n", " os.makedirs(output_path, exist_ok=True)\n", " \n", " # set up tfrecord writer\n", " number_of_samples_written = 0\n", " with tf.io.TFRecordWriter(output_file) as record_writer:\n", "\n", " # write each entry to tfrecord\n", " num_entries_in_batch = len(data_filenames)\n", " for input_file in data_filenames:\n", " # load label and image\n", " label_str = input_file.split('/')[-2]\n", " label_int = label_dictionary[label_str]\n", " image = Image.open(input_file).convert('RGB')\n", " image_np = np.asarray(image)\n", " \n", " # encode and write to tfrecord\n", " example = tf.train.Example(features=tf.train.Features(\n", " feature={\n", " 'image': _bytes_feature(image_np.tobytes()),\n", " 'label': _int64_feature(label_int)\n", " }))\n", " record_writer.write(example.SerializeToString())\n", " number_of_samples_written += 1\n", "\n", " return number_of_samples_written, output_file\n", "\n", "\n", "# multiprocessing wrapper function\n", "def multi_create_tfrecords_in_shards(data_filenames, dataset_name, num_files_to_create, num_workers):\n", " \n", " # split up arguments to shard\n", " split_data_filenames = np.array_split(data_filenames, num_files_to_create)\n", " tfrecord_args = zip(split_data_filenames, range(0, num_files_to_create), [dataset_name]*num_files_to_create)\n", "\n", " # create the shards\n", " with Pool(processes=num_workers) as pool:\n", " tfrecords_func_output = pool.starmap(create_tfrecords_in_shards, tfrecord_args)\n", " sample_counts = [x[0] for x in tfrecords_func_output]\n", " output_files = [x[1] for x in tfrecords_func_output]\n", " \n", " return sum(sample_counts), output_files" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [], "source": [ "## create tfrecords for train, validation and test set\n", "\n", "num_files_to_create = 96 # some multiple of 8 as we will use 8 GPUs\n", "num_workers = cpu_count()-1\n", "\n", "num_train_samples, train_tfrecords = multi_create_tfrecords_in_shards(\n", " data_filenames=train_filenames,\n", " dataset_name='train',\n", " num_files_to_create=num_files_to_create,\n", " num_workers=num_workers,)\n", "\n", "num_validation_samples, validation_tfrecords = multi_create_tfrecords_in_shards(\n", " data_filenames=validation_filenames,\n", " dataset_name='validation',\n", " num_files_to_create=num_files_to_create,\n", " num_workers=num_workers,)\n", "\n", "num_test_samples, test_tfrecords = multi_create_tfrecords_in_shards(\n", " data_filenames=test_filenames,\n", " dataset_name='test',\n", " num_files_to_create=num_files_to_create,\n", " num_workers=num_workers,)" ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Wrote 216000 samples in the train set.\n", "Wrote 27000 samples in the validation set.\n", "Wrote 27000 samples in the test set.\n" ] } ], "source": [ "print(\"Wrote {} samples in the train set.\".format(num_train_samples))\n", "print(\"Wrote {} samples in the validation set.\".format(num_validation_samples))\n", "print(\"Wrote {} samples in the test set.\".format(num_test_samples))" ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [], "source": [ "## parse and confirm data in tfrecords\n", "\n", "# load and test the tf record files\n", "dataset = tf.data.TFRecordDataset(train_tfrecords)\n", "\n", "# Create a dictionary describing the features.\n", "sample_feature_description = {\n", " 'image': tf.io.FixedLenFeature([], tf.string),\n", " 'label': tf.io.FixedLenFeature([], tf.int64),\n", "}\n", "\n", "def _parse_sample_function(example_proto):\n", " return tf.io.parse_single_example(example_proto, sample_feature_description)\n", "\n", "parsed_sample_dataset = dataset.map(_parse_sample_function)\n", "\n", "for i, sample_features in enumerate(parsed_sample_dataset):\n", " image = tf.io.decode_raw(sample_features['image'], tf.uint8)\n", " image = tf.reshape(image, (32,32,3))\n", " \n", " label = sample_features['label']\n", " \n", " if i==1000: break" ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [ { "data": { "image/png": "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\n", "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "name": "stdout", "output_type": "stream", "text": [ "dog\n" ] } ], "source": [ "display(Image.fromarray(image.numpy()).resize((128,128)))\n", "print(inverted_label_dictionary[label.numpy()])" ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Counted 216000 samples in train set.\n", "Counted 27000 samples in validation set.\n", "Counted 27000 samples in test set.\n" ] } ], "source": [ "## count number of samples in tfrecords\n", "\n", "train_path = f'{local_data_folder}/sharded_tfrecords/train/'\n", "files = [os.path.join(r,file) for r,d,f in os.walk(train_path) for file in f]\n", "dataset = tf.data.TFRecordDataset(files)\n", "num_train_samples = sum(1 for _ in dataset)\n", "print(\"Counted {} samples in train set.\".format(num_train_samples))\n", "\n", "validation_path = f'{local_data_folder}/sharded_tfrecords/validation/'\n", "files = [os.path.join(r,file) for r,d,f in os.walk(validation_path) for file in f]\n", "dataset = tf.data.TFRecordDataset(files)\n", "num_validation_samples = sum(1 for _ in dataset)\n", "print(\"Counted {} samples in validation set.\".format(num_validation_samples))\n", "\n", "test_path = f'{local_data_folder}/sharded_tfrecords/test/'\n", "files = [os.path.join(r,file) for r,d,f in os.walk(test_path) for file in f]\n", "dataset = tf.data.TFRecordDataset(files)\n", "num_test_samples = sum(1 for _ in dataset)\n", "print(\"Counted {} samples in test set.\".format(num_test_samples))" ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [], "source": [ "## upload to s3\n", "for dataset in ['train', 'validation', 'test']:\n", " prefix = 'distributed_training_demo/data/' + dataset\n", " !aws s3 cp ../data/sharded_tfrecords/{dataset} s3://{bucket}/{prefix} --recursive --quiet" ] } ], "metadata": { "kernelspec": { "display_name": "conda_tensorflow2_p36", "language": "python", "name": "conda_tensorflow2_p36" }, "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.10" } }, "nbformat": 4, "nbformat_minor": 4 }