{"metadata":{"kernelspec":{"name":"ir","display_name":"R","language":"R"},"language_info":{"name":"R","codemirror_mode":"r","pygments_lexer":"r","mimetype":"text/x-r-source","file_extension":".r","version":"4.0.5"},"kaggle":{"accelerator":"gpu","dataSources":[{"sourceId":5441,"databundleVersionId":38425,"sourceType":"competition"}],"dockerImageVersionId":30618,"isInternetEnabled":true,"language":"r","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"## TABLE OF CONTENT\n\n***\n\n#### [Section 1: Loading required libraries](#1)\n\n#### [Section 2: Data loading and preproccesing](#2)\n\n#### [Section 3: Creating splits and image loading](#3)\n\n#### [Section 4: Transfer learning with Xception model](#4)\n\n#### [Section 5: Visualizing results](#5)\n\n#### [Section 6: Evaluating the best epoch on the test split](#6)\n\n#### [Section 7: Loading submission images and making predictions](#7)","metadata":{"_uuid":"8c3a3a6e-19c5-4665-94ef-cc6ea8a4a8d0","_cell_guid":"f2656d0f-1265-4f79-baaa-f18a58967fac","trusted":true}},{"cell_type":"markdown","source":"# Loading required libraries <a class=\"anchor\" id=\"1\"></a>","metadata":{"_uuid":"4f1394c3-588f-4beb-b7c0-18dbb0a41a0d","_cell_guid":"fc1d95b4-b388-446e-a741-f7c38e634e26","trusted":true}},{"cell_type":"code","source":"suppressPackageStartupMessages({\n\n    library(keras)\n    library(tensorflow)\n    library(dplyr)\n    library(tidyr)\n    library(tidymodels)\n})","metadata":{"_uuid":"3fb86e9c-1295-4739-910e-c4c9083712c6","_cell_guid":"35adbf4e-b7c4-4733-af41-7584037576a4","collapsed":false,"jupyter":{"outputs_hidden":false},"execution":{"iopub.status.busy":"2024-06-21T11:29:47.315126Z","iopub.execute_input":"2024-06-21T11:29:47.349066Z","iopub.status.idle":"2024-06-21T11:29:49.962675Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Data loading <a class=\"anchor\" id=\"2\"></a>","metadata":{}},{"cell_type":"code","source":"setwd(\"/kaggle/input/dogs-vs-cats-redux-kernels-edition/\")\n\nfor (index in 2:length(dir())) {\n    file <- paste0(getwd(), sep = \"/\", dir()[index])\n    unzip(zipfile = file, exdir = \"/kaggle/working/\")\n}","metadata":{"_uuid":"6b3c1e1d-e04b-4e22-8dff-364eb88a6c05","_cell_guid":"05591338-c3b7-4f0b-9e32-9da314b3fedd","collapsed":false,"jupyter":{"outputs_hidden":false},"execution":{"iopub.status.busy":"2024-06-21T11:29:52.882329Z","iopub.execute_input":"2024-06-21T11:29:52.884217Z","iopub.status.idle":"2024-06-21T11:30:07.641758Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Data preproccesing\n\n#### Here I create a new dataframe with 3 columns, representing: `class`, `id` and `format`","metadata":{}},{"cell_type":"code","source":"setwd(\"/kaggle/working\")\n\ntrain_df <- dir(\"train\") %>%\n    as.data.frame()\n\n\ntrain_df <- separate_wider_delim(\n    data = train_df,\n    cols = .,\n    delim = \".\",\n    names = c(\"class\", \"id\", \"format\")\n)","metadata":{"_uuid":"662616d0-2900-4962-b0f5-8058b81b16ca","_cell_guid":"e0fd187b-5441-4c18-ba0d-123774f4d217","collapsed":false,"jupyter":{"outputs_hidden":false},"execution":{"iopub.status.busy":"2024-06-21T11:37:27.951185Z","iopub.execute_input":"2024-06-21T11:37:27.952674Z","iopub.status.idle":"2024-06-21T11:37:28.229086Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"#### Using dplyr convenient syntax, label each `class` object","metadata":{}},{"cell_type":"code","source":"train_df <- train_df %>%\n    mutate(id = paste(id, format, sep = \".\")) %>%\n    mutate(filename = paste(class, id, sep = \".\")) %>%\n    select(-format, -id) %>%\n    mutate(class = factor(\n        class,\n        levels = c(\"cat\", \"dog\"),\n        labels = c(\"0\", \"1\")\n    ))","metadata":{"_uuid":"8a701d9e-5b59-46e7-b04b-e5977d73cce2","_cell_guid":"a1894779-ff97-4d44-9357-6ede53d2d8ef","collapsed":false,"jupyter":{"outputs_hidden":false},"execution":{"iopub.status.busy":"2024-06-21T11:37:30.200537Z","iopub.execute_input":"2024-06-21T11:37:30.202078Z","iopub.status.idle":"2024-06-21T11:37:30.249784Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"#### As the result, We have two `classes` : 0 for cats and 1 for dogs, as well as paths for our images","metadata":{}},{"cell_type":"code","source":"head(train_df)","metadata":{"_uuid":"295735fc-d12b-42c5-8cfc-ab57b4dceefd","_cell_guid":"d3657671-7603-41b3-a678-074fe38759ff","collapsed":false,"jupyter":{"outputs_hidden":false},"execution":{"iopub.status.busy":"2024-06-21T11:37:32.695797Z","iopub.execute_input":"2024-06-21T11:37:32.697293Z","iopub.status.idle":"2024-06-21T11:37:32.723102Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Creating splits <a class=\"anchor\" id=\"3\"></a>\n\n#### Using `rsample` package from `tidymodels` framework, create a training, testing and validation splits","metadata":{}},{"cell_type":"code","source":"split <- initial_validation_split(\n    train_df,\n    prop = c(0.4, 0.1),\n    strata = \"class\"\n)\n\ntrain_split <- split %>% training()\ntest_split <- split %>% testing()\nval_split <- split %>% validation()","metadata":{"_uuid":"680de47e-81d4-455b-b7cb-d5ef2670f1df","_cell_guid":"d2f22133-f614-43f0-9efd-7546baf8e05d","collapsed":false,"jupyter":{"outputs_hidden":false},"execution":{"iopub.status.busy":"2024-06-21T11:37:35.845287Z","iopub.execute_input":"2024-06-21T11:37:35.846993Z","iopub.status.idle":"2024-06-21T11:37:35.925230Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Loading images from \"kaggle/working/train\" directory\n\n#### Note: You can adjust `batch_size` depending on the gpu load (more batches of data - higher gpu load)","metadata":{}},{"cell_type":"code","source":"batch_size <- 64\ntarget_size <- c(299, 299)","metadata":{"_uuid":"65885519-86c7-49e3-b4e9-309acc262504","_cell_guid":"05d1bdb0-2f36-4689-a8ce-b1c57eee4d14","collapsed":false,"jupyter":{"outputs_hidden":false},"execution":{"iopub.status.busy":"2024-06-21T11:39:26.528770Z","iopub.execute_input":"2024-06-21T11:39:26.530271Z","iopub.status.idle":"2024-06-21T11:39:26.542598Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"#### Note: I had a problem with default `class_mode = \"categorical\"` as it expects one-hot encoding, which is not our case","metadata":{}},{"cell_type":"code","source":"train_datagen <- flow_images_from_dataframe(\n    train_split,\n    \"train\",\n    x_col = \"filename\",\n    y_col = \"class\",\n    class_mode = \"binary\",\n    seed = 11,\n    batch_size = batch_size,\n    target_size = target_size\n)\n\ntable(train_datagen$classes)","metadata":{"_uuid":"9e203fb0-ad8d-49b1-99c6-4c8d50d7c4d8","_cell_guid":"02216cd7-a322-4f32-826c-3fbbb128204e","collapsed":false,"jupyter":{"outputs_hidden":false},"execution":{"iopub.status.busy":"2024-06-21T11:39:28.904010Z","iopub.execute_input":"2024-06-21T11:39:28.905452Z","iopub.status.idle":"2024-06-21T11:39:37.332773Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"val_datagen <- flow_images_from_dataframe(\n    val_split,\n    \"train\",\n    x_col = \"filename\",\n    y_col = \"class\",\n    class_mode = \"binary\",\n    seed = 11,\n    batch_size = batch_size,\n    target_size = target_size\n)\n\ntable(val_datagen$classes)","metadata":{"_uuid":"00b9227d-ef69-4d21-b4fc-ad832a09248f","_cell_guid":"1ce16878-01c2-43bd-91f1-193f11c674e3","collapsed":false,"jupyter":{"outputs_hidden":false},"execution":{"iopub.status.busy":"2024-06-21T11:39:42.635636Z","iopub.execute_input":"2024-06-21T11:39:42.637151Z","iopub.status.idle":"2024-06-21T11:39:42.696945Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Loading Xception model <a class=\"anchor\" id=\"4\"></a>\n\n#### Note #1 : I do not include top classification layers as we will define them later\n\n#### Note #2 : It is important to freeze weights as out dataset is different from imagenet","metadata":{}},{"cell_type":"code","source":"mod_base <- application_xception(\n    input_shape = c(target_size, 3),\n    include_top = FALSE,\n    weights = \"imagenet\"\n)\n\nfreeze_weights(mod_base)","metadata":{"_uuid":"a6a9b9f7-8f75-4308-8369-c4f9ea6d2e6b","_cell_guid":"6cefcc1b-20de-4322-a7f3-ab8ace1204d1","collapsed":false,"jupyter":{"outputs_hidden":false},"execution":{"iopub.status.busy":"2024-06-21T11:39:52.139304Z","iopub.execute_input":"2024-06-21T11:39:52.140838Z","iopub.status.idle":"2024-06-21T11:39:56.267184Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Adding new layers on top Xception model\n\n#### Note #1: It is vital to include `layer_rescaling` as Xception model expects input to be between [-1, 1]\n\n#### Note #2: The last layer activation must be sigmoid as we have two classes to predict: cats and dogs","metadata":{}},{"cell_type":"code","source":"input <- layer_input(shape = c(target_size, 3))\n\nmodel <- input %>%\n    layer_rescaling(scale = 1 / 127.5, offset = -1) %>%\n    mod_base(training = FALSE) %>%\n    layer_global_average_pooling_2d() %>%\n    layer_dense(512, activation = \"relu\") %>%\n    layer_dropout(0.5) %>%\n    layer_dense(1, activation = \"sigmoid\")\n\nmodel_build <- keras_model(inputs = input, outputs = model)","metadata":{"_uuid":"10a84e9a-0d60-49fb-b6b5-7e3f16143f64","_cell_guid":"46cd76c3-27aa-4983-8948-5db33dcad8fd","collapsed":false,"jupyter":{"outputs_hidden":false},"execution":{"iopub.status.busy":"2024-06-21T11:40:06.391567Z","iopub.execute_input":"2024-06-21T11:40:06.392993Z","iopub.status.idle":"2024-06-21T11:40:06.822307Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model_build %>%\n    compile(\n        loss = \"binary_crossentropy\",\n        optimizer = optimizer_rmsprop(learning_rate = 0.001),\n        metrics = \"accuracy\"\n    )","metadata":{"_uuid":"2f30fee3-fc9e-40bd-a848-281c31f22460","_cell_guid":"aff8c3fe-dd9d-47a1-9699-dc2fb68f3e61","collapsed":false,"jupyter":{"outputs_hidden":false},"execution":{"iopub.status.busy":"2024-06-21T11:40:09.609944Z","iopub.execute_input":"2024-06-21T11:40:09.611430Z","iopub.status.idle":"2024-06-21T11:40:09.639305Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"summary(model_build)","metadata":{"_uuid":"502fedac-2e92-42c8-8763-060f558a7953","_cell_guid":"7d11d669-7174-4b3c-8538-75a5e937fd59","collapsed":false,"_kg_hide-output":true,"jupyter":{"outputs_hidden":false},"execution":{"iopub.status.busy":"2024-06-21T11:40:11.828313Z","iopub.execute_input":"2024-06-21T11:40:11.829736Z","iopub.status.idle":"2024-06-21T11:40:11.909580Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Adding a list of callbacks for model monitoring\n\n#### Note: For convenient Tensorboard Web interface you can add `callback_tfboard`","metadata":{}},{"cell_type":"code","source":"early_stopping <- callback_early_stopping(\n    monitor = \"val_loss\",\n    min_delta = 1e-4,\n    patience = 5,\n    verbose = 1\n)\n\nreduce_lr <- callback_reduce_lr_on_plateau(\n    monitor = \"val_loss\",\n    factor = 0.5,\n    patience = 2,\n    verbose = 1\n)\n\ncallbacks_file <- callback_model_checkpoint(\n    \"best_at_{epoch}.keras\",\n    save_best_only = TRUE,\n    monitor = \"val_loss\",\n    mode = \"min\"\n)\n\n#callback_tfboard <- tf$keras$callbacks$TensorBoard(\"logs\")\n\n\ncallbacks <- list(\n    \n    early_stopping,\n    reduce_lr,\n    callbacks_file\n#    callback_tfboard\n\n)","metadata":{"_uuid":"b31dc290-04cd-46bf-a1e3-8ad3a49c0165","_cell_guid":"443bbeaf-5d20-4faf-9271-31d4d958762e","collapsed":false,"jupyter":{"outputs_hidden":false},"execution":{"iopub.status.busy":"2024-06-21T11:51:26.140988Z","iopub.execute_input":"2024-06-21T11:51:26.142499Z","iopub.status.idle":"2024-06-21T11:51:26.166491Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"history <- fit(\n    model_build,\n    train_datagen,\n    epochs = 5,\n    validation_data = val_datagen,\n    callbacks = callbacks\n)","metadata":{"_uuid":"01c96a2a-cac9-476f-8766-0a50a90a5a24","_cell_guid":"afd853ec-2fc9-49ba-8e67-d6845e6af2db","collapsed":false,"jupyter":{"outputs_hidden":false},"execution":{"iopub.status.busy":"2024-06-21T11:45:43.660466Z","iopub.execute_input":"2024-06-21T11:45:43.662126Z","iopub.status.idle":"2024-06-21T11:50:16.198354Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Visualizing results as well as minimum val_loss for validation <a class=\"anchor\" id=\"5\"></a>","metadata":{}},{"cell_type":"code","source":"min(history$metrics$val_loss)","metadata":{"_uuid":"751d2269-91b6-455c-abe6-04b97fa618bf","_cell_guid":"b9176701-3bc6-4f58-9717-f70345d13185","collapsed":false,"jupyter":{"outputs_hidden":false},"execution":{"iopub.status.busy":"2024-06-21T11:51:39.355068Z","iopub.execute_input":"2024-06-21T11:51:39.356559Z","iopub.status.idle":"2024-06-21T11:51:39.371334Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plot(history, type = \"b\")","metadata":{"_uuid":"b4597c9c-46e3-4ba3-a0be-d7c84c6d8c41","_cell_guid":"ed32c8aa-544e-4d21-b83d-72793b6420e9","collapsed":false,"jupyter":{"outputs_hidden":false},"execution":{"iopub.status.busy":"2024-06-21T11:51:43.128014Z","iopub.execute_input":"2024-06-21T11:51:43.129494Z","iopub.status.idle":"2024-06-21T11:51:43.721655Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Loading the test split images <a class=\"anchor\" id=\"6\"></a>","metadata":{}},{"cell_type":"code","source":"test_datagen <- flow_images_from_dataframe(\n    test_split,\n    \"train\",\n    x_col = \"filename\",\n    y_col = \"class\",\n    class_mode = \"binary\",\n    seed = 11,\n    batch_size = batch_size,\n    target_size = target_size\n)\n\ntable(test_datagen$classes)","metadata":{"_uuid":"c37ed171-c01f-4cc8-9584-c989459e39bd","_cell_guid":"f5b67885-8597-484f-8555-98f0d94265f7","collapsed":false,"jupyter":{"outputs_hidden":false},"execution":{"iopub.status.busy":"2024-06-21T12:00:17.781621Z","iopub.execute_input":"2024-06-21T12:00:17.783133Z","iopub.status.idle":"2024-06-21T12:00:17.953623Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Evaluating the model on test images","metadata":{}},{"cell_type":"code","source":"model_build %>%\n    evaluate(test_datagen)","metadata":{"_uuid":"c8d4dcd7-02d2-449d-9e50-70e98919af66","_cell_guid":"1720340b-8594-4ca6-910a-4a1e93de75d1","collapsed":false,"jupyter":{"outputs_hidden":false},"execution":{"iopub.status.busy":"2024-06-21T11:59:09.896473Z","iopub.execute_input":"2024-06-21T11:59:09.897943Z","iopub.status.idle":"2024-06-21T12:00:03.192497Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Loading submission images <a class=\"anchor\" id=\"7\"></a>\n\n#### Note: The same workflow as in previous loading steps","metadata":{}},{"cell_type":"code","source":"filenames <- dir(\"test\") %>%\n    as.data.frame()\n\n\nfilenames <- separate_wider_delim(\n    data = filenames,\n    cols = .,\n    delim = \".\",\n    names = c(\"id\", \"format\")\n)","metadata":{"_uuid":"4e6582cb-8c2e-48be-a591-0c8dcecbce7d","_cell_guid":"83e1cd58-96f2-4737-b870-bf2d7edcd642","collapsed":false,"jupyter":{"outputs_hidden":false},"execution":{"iopub.status.busy":"2024-06-21T12:08:04.537353Z","iopub.execute_input":"2024-06-21T12:08:04.539811Z","iopub.status.idle":"2024-06-21T12:08:04.656660Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"filenames <- filenames %>%\n    mutate(id = as.numeric(id)) %>%\n    arrange(id) %>%\n    mutate(id = paste(id, format, sep = \".\")) %>%\n    select(-format)\n\nhead(filenames)","metadata":{"_uuid":"e2aa69de-458b-488c-8e06-27cddddb8e2b","_cell_guid":"644bd304-b8fa-455d-9b98-1e54a772baca","collapsed":false,"jupyter":{"outputs_hidden":false},"execution":{"iopub.status.busy":"2024-06-21T12:08:06.616094Z","iopub.execute_input":"2024-06-21T12:08:06.617632Z","iopub.status.idle":"2024-06-21T12:08:06.673618Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"#### Note: It is very important to include `shuffle = FALSE`","metadata":{}},{"cell_type":"code","source":"real_datagen <- flow_images_from_dataframe(\n    filenames,\n    \"test\",\n    x_col = \"id\",\n    class_mode = NULL,\n    y_col = NULL,\n    target_size = target_size,\n    batch_size = batch_size,\n    shuffle = FALSE\n)","metadata":{"_uuid":"5d95fe4f-8135-4d69-8064-19ada7c33ff8","_cell_guid":"9eb918a1-0c67-4461-8d5d-cab5d853f6ba","collapsed":false,"jupyter":{"outputs_hidden":false},"execution":{"iopub.status.busy":"2024-06-21T12:10:02.685877Z","iopub.execute_input":"2024-06-21T12:10:02.687454Z","iopub.status.idle":"2024-06-21T12:10:02.822754Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Making predictions","metadata":{}},{"cell_type":"code","source":"score <- model_build %>% predict(real_datagen)","metadata":{"_uuid":"370274a0-136e-466d-8b56-31dbaf1e5a9b","_cell_guid":"e8294e3e-20f7-4942-a668-fcdbef925e2a","collapsed":false,"jupyter":{"outputs_hidden":false},"execution":{"iopub.status.busy":"2024-06-21T12:10:33.677983Z","iopub.execute_input":"2024-06-21T12:10:33.679560Z","iopub.status.idle":"2024-06-21T12:11:25.614257Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Customizing a dataframe in order to meet Kaggle requirements","metadata":{}},{"cell_type":"code","source":"score <- score %>% as.data.frame()\n\npredictions <- score %>%\n    mutate(id = seq(1, 12500, 1), label = V1) %>%\n    select(-V1)","metadata":{"_uuid":"5723ab38-1ee4-416e-b9cd-4897c843d261","_cell_guid":"a189cb29-34a2-46df-b68c-e2a4264e2a7d","collapsed":false,"jupyter":{"outputs_hidden":false},"execution":{"iopub.status.busy":"2024-06-21T12:11:50.968934Z","iopub.execute_input":"2024-06-21T12:11:50.970395Z","iopub.status.idle":"2024-06-21T12:11:50.988228Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"head(predictions)","metadata":{"_uuid":"799c4611-1450-4bcf-88f7-7215d1a26e20","_cell_guid":"cfcf5442-1175-490f-b01d-ea5ef165a97c","collapsed":false,"jupyter":{"outputs_hidden":false},"execution":{"iopub.status.busy":"2024-06-21T12:11:53.531403Z","iopub.execute_input":"2024-06-21T12:11:53.532919Z","iopub.status.idle":"2024-06-21T12:11:53.552796Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Uploading a csv file\n\n#### Note: `row.names = FALSE` ","metadata":{}},{"cell_type":"code","source":"write.csv(predictions, \"submission.csv\", row.names = FALSE)","metadata":{"_uuid":"d3303a4b-1ed1-4fdf-b5fa-45eba72bf822","_cell_guid":"e61ea41a-1744-4171-9b27-0c3d6b30a27b","collapsed":false,"jupyter":{"outputs_hidden":false},"execution":{"iopub.status.busy":"2024-06-21T12:14:02.000402Z","iopub.execute_input":"2024-06-21T12:14:02.001957Z","iopub.status.idle":"2024-06-21T12:14:02.047882Z"},"trusted":true},"execution_count":null,"outputs":[]}]}