{"cells":[{"metadata":{"_uuid":"b4f095b8a01be0e980f57c6a217611527c12c9e5"},"cell_type":"markdown","source":"# Keras Densenet model with tf.data version"},{"metadata":{"_uuid":"95a71da0f11be327f2705cf8079397ad28b7e996"},"cell_type":"markdown","source":"Make the model with `keras.application` model and use `tf.data` to load large size images in kaggle kernel.\n\nIf you have other ways to load large images, please leave a comment!"},{"metadata":{"_uuid":"5fab99716858608a81f88912da735aedad9e088a"},"cell_type":"markdown","source":"## References\n\n* https://www.tensorflow.org/guide/keras#input_tfdata_datasets\n* https://www.kaggle.com/pestipeti/keras-cnn-starter\n* https://www.kaggle.com/satian/keras-mobilenet-starter\n* [imple and efficient data augmentations using the Tensorfow tf.Data and Dataset API](https://www.wouterbulten.nl/blog/tech/data-augmentation-using-tensorflow-data-dataset/)\n\n\n### After..\n* Used 'Martin Piotte' bounding box model [link](https://www.kaggle.com/martinpiotte/whale-recognition-model-with-score-0-78563/notebook)\n* And Phan Huy Hoang's kernel [link](https://www.kaggle.com/phhasian0710/create-bounding-box-images-whale-recognition/notebook)"},{"metadata":{"_uuid":"02c7c5ff83c2823e3f7cc7a05506de479c14a15c"},"cell_type":"markdown","source":"## Set up\n\n* If don't write `tensorflow.`, error may occur."},{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"cell_type":"code","source":"import os\nimport time\nimport math\n\nimport numpy as np\nimport matplotlib.pyplot as plt\nimport pandas as pd\n\nfrom sklearn.preprocessing import LabelEncoder\nfrom sklearn.preprocessing import OneHotEncoder\n\nimport tensorflow as tf\n#tf.enable_eager_execution()\nfrom tensorflow.keras.models import load_model\nfrom tensorflow.keras.preprocessing import image\nfrom tensorflow.keras.applications.densenet import preprocess_input\n\nfrom tensorflow.keras.optimizers import Adam\nfrom tensorflow.keras.metrics import categorical_accuracy, top_k_categorical_accuracy, categorical_crossentropy","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"4880a7160104a7b80842038a17bf14b48da73258"},"cell_type":"markdown","source":"# Load the train.csv file"},{"metadata":{"_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","trusted":true},"cell_type":"code","source":"df = pd.read_csv('../input/humpback-whale-identification/train.csv')\ndf.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"f37e74dde07a5a9a8aad0b41e5454a5741983bcb"},"cell_type":"code","source":"df.count()","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"cc7f8f9084bde807d902ebabaca0fe58fc2e1f09"},"cell_type":"markdown","source":"## Make label one-hot vector"},{"metadata":{"trusted":true,"_uuid":"d7c4c2966044c9b0ef9fe1952292791389a05c2c"},"cell_type":"code","source":"def prepare_labels(y):\n    values = np.array(y)\n    label_encoder = LabelEncoder()\n    integer_encoded = label_encoder.fit_transform(values)\n    # print(integer_encoded)\n\n    onehot_encoder = OneHotEncoder(sparse=False)\n    integer_encoded = integer_encoded.reshape(len(integer_encoded), 1)\n    onehot_encoded = onehot_encoder.fit_transform(integer_encoded)\n    # print(onehot_encoded)\n\n    y = onehot_encoded\n    print(y.shape)\n    return y, label_encoder","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"80927e577654ee031383315f96112e884b1db0c6"},"cell_type":"code","source":"y, label_encoder = prepare_labels(df['Id'])","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"ff9bf037cc5671b6273f46216b308d68e6f342f2"},"cell_type":"markdown","source":"## Copy the images \n\nclass per image is lower than 4 images, copy the images."},{"metadata":{"trusted":true,"_uuid":"72323705770c53f1fbccb9d37f96a37ff9e7b675"},"cell_type":"code","source":"labels_count = df.Id.value_counts()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"99e9af65f8f6426395b8c6b4b1e0fc9387830308"},"cell_type":"code","source":"new_train = pd.DataFrame(columns=['Image', 'Id'])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"923eea1ef903a3b45d95168538cd2fd345051d48"},"cell_type":"code","source":"train_names = df.index.values\n\ndup = []\nfor idx,row in df.iterrows():\n    if labels_count[row['Id']] < 4:\n        dup.extend([idx]*math.ceil((4 - labels_count[row['Id']])/labels_count[row['Id']]))\n    if idx == 25360:\n        print('last class')\n        \ntrain_names = np.concatenate([train_names, dup])\ntrain_names = train_names[np.random.RandomState(seed=42).permutation(train_names.shape[0])]\nlen(train_names)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"1d8268d1e5b24f1f92b7aa6c6c349c9e7feca100"},"cell_type":"code","source":"count = 0\nfor i in range(len(train_names)):\n    new_train = new_train.append(df.loc[[train_names[i]]])\n    count +=1\nprint(new_train.count())","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"25f8ef84bebe2cfb54ceddeef664223b34c9e908"},"cell_type":"markdown","source":"make one-hot vector in new_train."},{"metadata":{"trusted":true,"_uuid":"2c92c6bbf1e8495bcf8af2c02be0b4590ab8c810"},"cell_type":"code","source":"del df\ndel y, label_encoder\ndel train_names","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"b7ae1b66c00ff3cffda387f29773d8e459e9bdb7"},"cell_type":"code","source":"new_y, label_encoder = prepare_labels(new_train['Id'])","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"ae8396e91d87360baa3ad52a4283cfad1f7fe0f1"},"cell_type":"markdown","source":"### Save the new_train dataFrame to csv file"},{"metadata":{"trusted":true,"_uuid":"f30066d6f5aed6253289eaa01c05e42ba5a8099b"},"cell_type":"code","source":"new_train.to_csv('new_train.csv')","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"45a6a398cc18985d6bc84b43dc44818db882e931"},"cell_type":"markdown","source":"## Load the csv file."},{"metadata":{"trusted":true,"_uuid":"1abcb468ccbc8a006820eed9a022af55caadac39"},"cell_type":"code","source":"#new_train = pd.read_csv('../input/kernelbe655f6ff1/new_train.csv')\n#new_train.head()\n#tr_y, tr_label_encoder = prepare_labels(new_train['Id'])","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"5965dba27951b874df757feec4cfac70fa18b547"},"cell_type":"markdown","source":"## Make `tf.data`"},{"metadata":{"_uuid":"f6f9dc68913dca1c50eacc3052f67bcc234c3e1c"},"cell_type":"markdown","source":"### Define load_image function\n\nFirst, define `load_image` function.\n\nIn last line in function, we can set image size. In this, set image size [224, 224]."},{"metadata":{"trusted":true,"_uuid":"a5393d33b5c397bfcb3c51679b3908d98e8ab38e"},"cell_type":"code","source":"def load_image(path):\n    path='../input/humpback-whale-identification/train/' + path\n    image_string = tf.read_file(path)\n\n    # Don't use tf.image.decode_image, or the output shape will be undefined\n    image = tf.image.decode_jpeg(image_string, channels=3)\n\n    # This will convert to float values in [0, 1]\n    image = tf.image.convert_image_dtype(image, tf.float32)\n\n    image = tf.image.resize_images(image, [224, 224])\n    return image","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"4fbb206a5435dec014ade5f83259f8a31a10e507"},"cell_type":"markdown","source":"### Define `tf.data` augmentation function\n\nUsed the augmentation function in [imple and efficient data augmentations using the Tensorfow tf.Data and Dataset API](https://www.wouterbulten.nl/blog/tech/data-augmentation-using-tensorflow-data-dataset/).<br>\nAnd apply just filp, rot90 and zoom."},{"metadata":{"trusted":true,"_uuid":"2acbeb6aa2b534f673bef87dfae507a3b976c3ff"},"cell_type":"code","source":"def flip(x: tf.Tensor) -> tf.Tensor:\n    \"\"\"Flip augmentation\n\n    Args:\n        x: Image to flip\n\n    Returns:\n        Augmented image\n    \"\"\"\n    x = tf.image.random_flip_left_right(x)\n    #x = tf.image.random_flip_up_down(x)\n\n    return x\n\ndef color(x: tf.Tensor) -> tf.Tensor:\n    \"\"\"Color augmentation\n\n    Args:\n        x: Image\n\n    Returns:\n        Augmented image\n    \"\"\"\n    x = tf.image.random_hue(x, 0.08)\n    x = tf.image.random_saturation(x, 0.6, 1.6)\n    x = tf.image.random_brightness(x, 0.05)\n    x = tf.image.random_contrast(x, 0.7, 1.3)\n    return x\n\ndef rotate(x: tf.Tensor) -> tf.Tensor:\n    \"\"\"Rotation augmentation\n\n    Args:\n        x: Image\n\n    Returns:\n        Augmented image\n    \"\"\"\n\n    return tf.image.rot90(x, tf.random_uniform(shape=[], minval=-1, maxval=1, dtype=tf.int32))\n\ndef zoom(x: tf.Tensor) -> tf.Tensor:\n    \"\"\"Zoom augmentation\n\n    Args:\n        x: Image\n\n    Returns:\n        Augmented image\n    \"\"\"\n\n    # Generate 20 crop settings, ranging from a 1% to 20% crop.\n    scales = list(np.arange(0.8, 1.0, 0.01))\n    boxes = np.zeros((len(scales), 4))\n\n    for i, scale in enumerate(scales):\n        x1 = y1 = 0.5 - (0.5 * scale)\n        x2 = y2 = 0.5 + (0.5 * scale)\n        boxes[i] = [x1, y1, x2, y2]\n\n    def random_crop(img):\n        # Create different crops for an image\n        crops = tf.image.crop_and_resize([img], boxes=boxes, box_ind=np.zeros(len(scales)), crop_size=(224,224))\n        # Return a random crop\n        return crops[tf.random_uniform(shape=[], minval=0, maxval=len(scales), dtype=tf.int32)]\n\n\n    choice = tf.random_uniform(shape=[], minval=0., maxval=1., dtype=tf.float32)\n\n    # Only apply cropping 50% of the time\n    return tf.cond(choice < 0.5, lambda: x, lambda: random_crop(x))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"57c681ef6a670bc8407070fd5c244657652090ff"},"cell_type":"code","source":"train_data = tf.data.Dataset.from_tensor_slices((new_train.Image, new_y))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"f5728afb101ed62c4d47783c4fd7146f3c71bbd6"},"cell_type":"code","source":"train_data = train_data.map(lambda x,y: (load_image(x),y))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"85850b02954019c1afa4e6343a1ce77749f2327f"},"cell_type":"code","source":"# sample x_2 data\naugmentations = [flip, zoom, rotate]\n\nfor f in augmentations:\n    train_data = train_data.map(lambda x,y: (tf.cond(tf.random_uniform([], 0, 1) > 0.75, lambda: f(x), lambda: x), y))\ntrain_data = train_data.map(lambda x,y : (tf.clip_by_value(x, 0, 1), y))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"2957a28076ff4855e54936c740296fe8c9bd40b9"},"cell_type":"code","source":"train_data = train_data.batch(32).repeat()\ntrain_data = train_data.prefetch(1)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"1d5870546bdf745df441a627b36c00f53b4903b3"},"cell_type":"markdown","source":"## Define Keras Densenet model\n\nLoad the model with keras.application. I chose 'DenseNet' model. \n\nAbout other keras model, refer to [keras document](https://keras.io/search.html?q=application)\n\n"},{"metadata":{"trusted":true,"_uuid":"1341be62850dc9fc984b034b26a3f0867d38002d"},"cell_type":"code","source":"from tensorflow.keras.applications.densenet import DenseNet121","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"366bc36d58cdafdded6af86f503199232208d064"},"cell_type":"code","source":"#load the base densenet model\nmodel = DenseNet121(include_top=True, weights=None, input_shape=(224,224,3), classes=5005)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"f66fe840d730dda870724d61ef76b8ccde6ba4f8"},"cell_type":"code","source":"#Add the metrics\n'''\ndef top_5_accuracy(y_true, y_pred):\n    return top_k_categorical_accuracy(y_true, y_pred, k=5)\n'''","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"8ee50962b347e1ee9150b269918448a34ddc519b"},"cell_type":"code","source":"model.compile(optimizer=Adam(lr=3e-4), loss='categorical_crossentropy',\n              metrics=[categorical_crossentropy, categorical_accuracy])\nprint(model.summary())","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"11d5ac3860fb7ff4a96f2d928dc0760f1496a24c","scrolled":true},"cell_type":"code","source":"start = time.time()\nhistory = model.fit(train_data, steps_per_epoch=len(new_train)//32, epochs=5, verbose=1)\n\nprint(\"Finish Training : {}\".format(time.time()-start))","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"8f85b1cf030bab80d692fe42a3935ec34ad62558"},"cell_type":"markdown","source":"## Test the model"},{"metadata":{"trusted":true,"_uuid":"ee1bbf02acb9be5c9773a9265c67a43603ad477d"},"cell_type":"code","source":"test = os.listdir(\"../input/humpback-whale-identification/test/\")\nprint(len(test))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"6df976760b4a4ef28f31cc328d2a4488afb898e6"},"cell_type":"code","source":"col = ['Image']\ntest_df = pd.DataFrame(test, columns=col)\ntest_df['Id'] = ''","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"141fabf83089e3ee0a1985e6b3f3360ba6a30775"},"cell_type":"code","source":"#For prediction\ndumy_y = np.zeros([7960,5005])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"1acbb0870b5488f5600193a75fd973018a00d1d6"},"cell_type":"code","source":"def test_load_image(path):\n    path='../input/humpback-whale-identification/test/' + path\n    image_string = tf.read_file(path)\n\n    # Don't use tf.image.decode_image, or the output shape will be undefined\n    image = tf.image.decode_jpeg(image_string, channels=3)\n\n    # This will convert to float values in [0, 1]\n    image = tf.image.convert_image_dtype(image, tf.float32)\n\n    image = tf.image.resize_images(image, [224, 224])\n    return image","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"872e78b4297591cc47b068e8ac83ad0172944a68"},"cell_type":"code","source":"test_data = tf.data.Dataset.from_tensor_slices((test_df.Image, dumy_y))\ntest_data = test_data.map(lambda x,y : (test_load_image(x),y))\ntest_data = test_data.batch(32).repeat()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"scrolled":true,"_uuid":"c4346ff95144816374d495b43516b54ee21ef4fb"},"cell_type":"code","source":"predictions = model.predict(test_data, steps=7960//32, verbose=1)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"1036e43bd396d97a8d81d56b268c9e845815fb2e"},"cell_type":"code","source":"for i, pred in enumerate(predictions):\n    test_df.loc[i, 'Id'] = ' '.join(label_encoder.inverse_transform(pred.argsort()[-5:][::-1]))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"8ff86b243a31e82c1c5bf1b0f982c97085e50a03"},"cell_type":"code","source":"test_df.head(10)\ntest_df.to_csv('submission.csv', index=False)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"cb72298d2961767cf07efdd66fd2e8c93894014e"},"cell_type":"code","source":"","execution_count":null,"outputs":[]}],"metadata":{"kernelspec":{"display_name":"Python 3","language":"python","name":"python3"},"language_info":{"name":"python","version":"3.6.6","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"}},"nbformat":4,"nbformat_minor":1}