{"cells":[{"metadata":{},"cell_type":"markdown","source":"Instead of using `ImageDataGenerator`, this kernel experiments with preprocessing layers from `tf.keras.experimental.preprocessing` for image augmentation."},{"metadata":{"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","trusted":true},"cell_type":"code","source":"import pandas as pd\nimport tensorflow as tf\nfrom tensorflow import keras\n%matplotlib inline\nimport matplotlib.pyplot as plt\nfrom pathlib import Path\nfrom zipfile import ZipFile\nfrom functools import partial\n\nprint(list(Path(\"/kaggle/input/dogs-vs-cats\").iterdir()))","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Prepare datasets\n\n## Unzip files"},{"metadata":{"trusted":true},"cell_type":"code","source":"data_path = Path(\"/kaggle/input/dogs-vs-cats\")\n\nwith ZipFile(data_path / \"train.zip\",\"r\") as z:\n    z.extractall(\"/kaggle/temp/\")\n    \nwith ZipFile(data_path / \"test1.zip\",\"r\") as z:\n    z.extractall(\"/kaggle/temp/test\")","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Examine the data directories"},{"metadata":{"trusted":true},"cell_type":"code","source":"train_path = Path(\"/kaggle/temp/\") / \"train\"\ntest_path = Path(\"/kaggle/temp/\") / \"test\"\n\n# total number of files\nprint(len(list(train_path.iterdir())))\nprint(len(list((test_path / \"test1\").iterdir())))\n\n# samples\nprint(list(train_path.glob(\"*.jpg\"))[0])\nprint(list((test_path / \"test1\").glob(\"*.jpg\"))[0])","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Sort images"},{"metadata":{"trusted":true},"cell_type":"code","source":"try:\n    Path.mkdir(train_path / \"cat\")\n    Path.mkdir(train_path / \"dog\")\nexcept OSError:\n    pass\n\nfor file in train_path.glob(\"*.jpg\"):\n    if file.stem[:3]=='cat':\n        file.rename(train_path / \"cat\" / (file.stem + \".jpg\"))\n    elif file.stem[:3]=='dog':\n        file.rename(train_path / \"dog\" / (file.stem + \".jpg\"))","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Generate datasets"},{"metadata":{"trusted":true},"cell_type":"code","source":"img_height = 150\nimg_width = 150\nbatch_size = 128\n\ntrain_set = keras.preprocessing.image_dataset_from_directory(str(train_path),\n                                                             image_size=(img_height, img_width),\n                                                             batch_size=batch_size,\n                                                             validation_split=0.2,\n                                                             seed=123,\n                                                             subset=\"training\",\n                                                             color_mode='grayscale')\nvalidation_set = keras.preprocessing.image_dataset_from_directory(str(train_path),\n                                                                  image_size=(img_height, img_width),\n                                                                  batch_size=batch_size,\n                                                                  validation_split=0.2,\n                                                                  seed=123,\n                                                                  subset=\"validation\",\n                                                                  color_mode='grayscale')","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Cache and prefetch"},{"metadata":{"trusted":true},"cell_type":"code","source":"AUTOTUNE = tf.data.experimental.AUTOTUNE\n\ntrain_set = train_set.cache().shuffle(1000).prefetch(buffer_size=AUTOTUNE)\nvalidation_set = validation_set.cache().prefetch(buffer_size=AUTOTUNE)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Build and train model\n\n## Preprocessing layers for image augmentation"},{"metadata":{"trusted":true},"cell_type":"code","source":"data_augmentation = keras.models.Sequential([\n    keras.layers.experimental.preprocessing.Rescaling(1./255, input_shape=(img_height, img_width, 1)),\n    keras.layers.experimental.preprocessing.RandomFlip(\"horizontal\"),\n    keras.layers.experimental.preprocessing.RandomRotation(0.1),\n    keras.layers.experimental.preprocessing.RandomZoom(0.1)\n])","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Create a model"},{"metadata":{"trusted":true},"cell_type":"code","source":"conv2D_layer = partial(keras.layers.Conv2D,\n                       filters=16, kernel_size=3, padding='same', activation='relu')\n\nmodel = keras.models.Sequential([\n    data_augmentation,\n    conv2D_layer(),\n    keras.layers.MaxPooling2D(),\n    conv2D_layer(filters=32),\n    keras.layers.MaxPooling2D(),\n    conv2D_layer(filters=32),\n    keras.layers.MaxPooling2D(),\n    conv2D_layer(filters=64),\n    keras.layers.MaxPooling2D(),\n    conv2D_layer(filters=64),\n    keras.layers.MaxPooling2D(),\n    keras.layers.Dropout(0.1),\n    keras.layers.Flatten(),\n    keras.layers.Dense(256, activation='relu'),\n    keras.layers.Dropout(0.2),\n    keras.layers.Dense(1, activation='sigmoid')\n])\n\nmodel.summary()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Find an appropriate learning rate"},{"metadata":{"trusted":true},"cell_type":"code","source":"model.compile(optimizer=keras.optimizers.Adam(),\n              loss=tf.keras.losses.BinaryCrossentropy(),\n              metrics=['accuracy'])\nnum_epochs = 20\nlearning_rate_cb = keras.callbacks.LearningRateScheduler(lambda epoch: 1e-6 * 10**(epoch / num_epochs * 5))\n\nhistory = model.fit(train_set,epochs=num_epochs, callbacks=[learning_rate_cb])\n\nplt.semilogx(history.history[\"lr\"], history.history[\"loss\"])","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Train the model"},{"metadata":{"trusted":true},"cell_type":"code","source":"model = keras.models.Sequential([\n    data_augmentation,\n    conv2D_layer(),\n    keras.layers.MaxPooling2D(),\n    conv2D_layer(filters=32),\n    keras.layers.MaxPooling2D(),\n    conv2D_layer(filters=32),\n    keras.layers.MaxPooling2D(),\n    conv2D_layer(filters=64),\n    keras.layers.MaxPooling2D(),\n    conv2D_layer(filters=64),\n    keras.layers.MaxPooling2D(),\n    keras.layers.Dropout(0.1),\n    keras.layers.Flatten(),\n    keras.layers.Dense(256, activation='relu'),\n    keras.layers.Dropout(0.2),\n    keras.layers.Dense(1, activation='sigmoid')\n])\n\nmodel.compile(optimizer=keras.optimizers.Adam(lr=2e-3),\n              loss=tf.keras.losses.BinaryCrossentropy(),\n              metrics=['accuracy'])\nnum_epochs = 100\n\n# add callbacks\nhistory = model.fit(train_set,validation_data=validation_set, \n                    epochs=num_epochs,\n                    callbacks=[keras.callbacks.EarlyStopping(patience=10, restore_best_weights=True),\n                               keras.callbacks.ReduceLROnPlateau(patience=3, factor=0.5, min_lr=1e-4)])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def plot_graphs(history, metric):\n    plt.plot(history.history[metric])\n    plt.plot(history.history['val_'+metric], '')\n    plt.xlabel(\"Epochs\")\n    plt.ylabel(metric)\n    plt.legend([metric, 'val_'+metric])\n\nplt.figure(figsize=(16, 8))\nplt.subplot(1,2,1)\nplot_graphs(history, 'accuracy')\nplt.ylim(0.3, 1)\nplt.subplot(1,2,2)\nplot_graphs(history, 'loss')\nplt.ylim(0.1, 1)\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Test and submit"},{"metadata":{"trusted":true},"cell_type":"code","source":"test_set = keras.preprocessing.image_dataset_from_directory(str(test_path),\n                                                            image_size=(img_height, img_width),\n                                                            batch_size=batch_size,\n                                                            color_mode='grayscale')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"predictions = [int(round(p[0])) for p in model.predict(test_set)]\nids = [file.stem for file in (test_path / \"test1\").glob(\"*.jpg\")]\nsubmission_df = pd.DataFrame({'id':ids, 'label':predictions})\nsubmission_df.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"submission_df.to_csv(\"submission.csv\", index=False)","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}