{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.10.12","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"nvidiaTeslaT4","dataSources":[{"sourceId":5441,"databundleVersionId":38425,"sourceType":"competition"},{"sourceId":9900,"sourceType":"datasetVersion","datasetId":6209}],"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"# Import libraries","metadata":{}},{"cell_type":"code","source":"import os\nimport cv2\nfrom tqdm import tqdm\nimport zipfile\nimport random\nfrom random import shuffle\nimport warnings\nwarnings.filterwarnings('ignore')\n\nimport numpy as np \nimport pandas as pd\nimport seaborn as sns\nimport matplotlib.pyplot as plt\n%matplotlib inline \n\nfrom sklearn.model_selection import train_test_split\nfrom sklearn.metrics import classification_report\n\nimport tensorflow as tf\nfrom tensorflow.keras.models import Sequential\nfrom tensorflow.keras.layers import Conv2D, MaxPooling2D, Flatten, Dense, Dropout,GlobalAveragePooling2D\nfrom tensorflow.keras.utils import to_categorical\nfrom tensorflow.keras.applications import ResNet50","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Extract Data","metadata":{}},{"cell_type":"code","source":"train_dir_zip = \"/kaggle/input/dogs-vs-cats-redux-kernels-edition/train.zip\" \ntest_dir_zip =  \"/kaggle/input/dogs-vs-cats-redux-kernels-edition/test.zip\"\n\ntrain_dir = \"train_data\"\ntest_dir = \"test_data\"\n\nwith zipfile.ZipFile(train_dir_zip,'r') as zip_ref:\n    zip_ref.extractall(train_dir)\n    \nwith zipfile.ZipFile(test_dir_zip,'r') as zip_ref:\n    zip_ref.extractall(test_dir)","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### Set Parameters","metadata":{}},{"cell_type":"code","source":"train_path = os.listdir(\"/kaggle/working/train_data/train\")\ntest_path = os.listdir(\"/kaggle/working/test_data/test\")\nTRAIN_FOLDER = '/kaggle/working/train_data/train'\nTEST_FOLDER = '/kaggle/working/test_data/test'\nIMG_SIZE = 224\nTEST_SIZE = 0.3\nRANDOM_STATE = 2018\nBATCH_SIZE = 64\nNO_EPOCHS = 20\nNUM_CLASSES = 2\nRESNET_WEIGHTS_PATH = '/kaggle/input/resnet50/resnet50_weights_tf_dim_ordering_tf_kernels_notop.h5'","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"**Now, we can build another function to fully process the training images and their labels into arrays:**","metadata":{}},{"cell_type":"code","source":"def label_img_ohe(img):\n    # dog.93.png\n    labels = img.split(\".\")[-3]\n    if labels == \"cat\":\n        return [1,0]\n    elif labels == \"dog\":\n        return [0,1]\n\n\ndef process_data(data_image_list, DATA_FOLDER, isTrain=True):\n    data_df = []\n    for img in tqdm(data_image_list):\n        path = os.path.join(DATA_FOLDER,img)\n        if(isTrain):\n            label = label_img_ohe(img)\n        else:\n            label = img.split('.')[0]\n        img = cv2.imread(path,cv2.IMREAD_COLOR)\n        img = cv2.resize(img, (IMG_SIZE,IMG_SIZE))\n        data_df.append([np.array(img),np.array(label)])\n    shuffle(data_df)\n    return data_df","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Data exploration","metadata":{}},{"cell_type":"markdown","source":"### Class distribution","metadata":{}},{"cell_type":"markdown","source":"**Let's inspect the train data to check the cat/dog distribution. We show first the split in the reduced train data.**","metadata":{}},{"cell_type":"code","source":"def plot_image_list_count(data_image_list):\n    labels = []\n    for img in data_image_list:\n        labels.append(img.split('.')[-3])\n    sns.countplot(x=labels)\n    plt.title('Cats and Dogs')\n    \nplot_image_list_count(train_path)","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"**Let's show also the class distribution in the full train data set.**","metadata":{}},{"cell_type":"code","source":"plot_image_list_count(os.listdir(\"/kaggle/working/train_data/train\"))","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### Visualize Ssample of Images","metadata":{}},{"cell_type":"markdown","source":"**Let's represent some of the images. We start with a selection from the train set. We will show the first 25 images from the train set.**\n\n**First, we process the train data, reading the images and creating a table with images and labels. If the data is trom train set, the label is the one calculated with one hot encoding; if the data is from test set, the label will be the image number.**","metadata":{}},{"cell_type":"code","source":"train = process_data(train_path,TRAIN_FOLDER)","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"**Then, we plot the image selection.**","metadata":{}},{"cell_type":"code","source":"def show_images(data, isTest=False):\n    f, ax = plt.subplots(5,5, figsize=(15,15))\n    for i,data in enumerate(data[:25]):\n        img_num = data[1]\n        img_data = data[0]\n        label = np.argmax(img_num)\n        if label  == 1: \n            str_label='Dog'\n        elif label == 0: \n            str_label='Cat'\n        if(isTest):\n            str_label=\"None\"\n        ax[i//5, i%5].imshow(img_data)\n        ax[i//5, i%5].axis('off')\n        ax[i//5, i%5].set_title(\"{}\".format(str_label))\n    plt.show()\n\nshow_images(train)","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"**Let's also show a selection of the train set. We prepare the test set.**","metadata":{}},{"cell_type":"code","source":"test = process_data(test_path, TEST_FOLDER, False)","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"**Then, we show a selection of the test set.**","metadata":{}},{"cell_type":"code","source":"show_images(test,True)","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Model","metadata":{}},{"cell_type":"markdown","source":"#### Prepare the train data\n","metadata":{}},{"cell_type":"code","source":"X = np.array([i[0] for i in train]).reshape(-1,IMG_SIZE,IMG_SIZE,3)     # shape : (20000,224,224,3)\ny = np.array([i[1] for i in train])        # shape : (20000, 2)","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"#### Prepare the model","metadata":{}},{"cell_type":"markdown","source":"**We initialize the ResNet-50 model, adding an additional last layer of type Dense, with softmax activation function.**\n\n**We also set the first layer of the model to be not trainable, becaise ResNet-50 model was already trained.**","metadata":{}},{"cell_type":"code","source":"model = Sequential()\nmodel.add(ResNet50(include_top=False, pooling='max', weights='imagenet', input_shape=(224, 224, 3))) \nmodel.add(Dense(NUM_CLASSES, activation='softmax'))\n\nmodel.layers[0].trainable = True","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"model.summary()","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"#### Compile the model","metadata":{}},{"cell_type":"code","source":"model.compile(\n    optimizer='adam',\n    loss='categorical_crossentropy',\n    metrics=['accuracy'])","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"#### Split the train data in train and validation","metadata":{}},{"cell_type":"code","source":"X_train,X_val,y_train,y_val = train_test_split(X,y,test_size = TEST_SIZE,random_state = RANDOM_STATE)","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"#### Train the model","metadata":{}},{"cell_type":"code","source":"Train_history = model.fit(\n    X_train,y_train,\n    batch_size=BATCH_SIZE,\n    epochs = 10,\n    verbose = 1,\n    validation_data = (X_val,y_val),\n)","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"#### Validation accuracy and loss","metadata":{}},{"cell_type":"markdown","source":"**Let's show the train and validation accuracy on the same plot. As well, we will represent the train and validation loss on the same graph.**","metadata":{}},{"cell_type":"code","source":"def plot_accuracy_and_loss(train_model):\n    hist = Train_history.history\n    acc = hist['accuracy']\n    val_acc = hist['val_accuracy']\n    loss = hist['loss']\n    val_loss = hist['val_loss']\n    epochs = range(len(acc))\n    f, ax = plt.subplots(1,2, figsize=(14,6))\n    ax[0].plot(epochs, acc, 'g', label='Training accuracy')\n    ax[0].plot(epochs, val_acc, 'r', label='Validation accuracy')\n    ax[0].set_title('Training and validation accuracy')\n    ax[0].legend()\n    ax[1].plot(epochs, loss, 'g', label='Training loss')\n    ax[1].plot(epochs, val_loss, 'r', label='Validation loss')\n    ax[1].set_title('Training and validation loss')\n    ax[1].legend()\n    plt.show()\n    \nplot_accuracy_and_loss(Train_history)","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"**Let's also show the numeric validation accuracy and loss.**","metadata":{}},{"cell_type":"code","source":"score = model.evaluate(X_val, y_val, verbose=0)\nprint('Validation loss:', score[0])\nprint('Validation accuracy:', score[1])","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### Save Model","metadata":{}},{"cell_type":"code","source":"model.save('resnet_model_clf.h5')","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"#### Validation accuracy per class","metadata":{}},{"cell_type":"markdown","source":"**Let's show the validation accuracy per each class.**\n\n**We start by predicting the labels for the validation set.**","metadata":{}},{"cell_type":"code","source":"# get the predictions for the test data\npredicted_classes = model.predict(X_val)\npredicted_classes = np.argmax(predicted_classes, axis=1)\n\n# get the indices to be plotted\ny_true = np.argmax(y_val,axis=1)","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"print(classification_report(\n    y_true, predicted_classes, \n    target_names=[\"Cat [1]\",\"Dog [0]\"]\n))","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Prepare the submission","metadata":{}},{"cell_type":"markdown","source":"**Show test images with predicted class\nLet's show few of the test images with the predicted class. For this, we will have to predict the class.**","metadata":{}},{"cell_type":"code","source":"f, ax = plt.subplots(5,5, figsize=(15,15))\nfor i,data in enumerate(test[:25]):\n    img_num = data[1]\n    img_data = data[0]\n    orig = img_data\n    data = img_data.reshape(-1,IMG_SIZE,IMG_SIZE,3)\n    model_out = model.predict([data])[0]\n    \n    if np.argmax(model_out) == 1: \n        str_predicted='Dog'\n    else: \n        str_predicted='Cat'\n    ax[i//5, i%5].imshow(orig)\n    ax[i//5, i%5].axis('off')\n    ax[i//5, i%5].set_title(\"Predicted:{}\".format(str_predicted))    \nplt.show()","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### Test data prediction","metadata":{}},{"cell_type":"code","source":"pred_list = []\nimg_list = []\nfor img in tqdm(test):\n    img_data = img[0]\n    img_idx = img[1]\n    data = img_data.reshape(-1,IMG_SIZE,IMG_SIZE,3)\n    predicted = model.predict([data])[0]\n    img_list.append(img_idx)\n    pred_list.append(predicted[1])","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### Submission fileSubmission file","metadata":{}},{"cell_type":"code","source":"submission = pd.DataFrame({'id':img_list , 'label':pred_list})\nsubmission.head()\nsubmission.to_csv(\"submission.csv\", index=False)","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}