{"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"},"kaggle":{"accelerator":"none","dataSources":[{"sourceId":7134568,"sourceType":"datasetVersion","datasetId":4116534}],"dockerImageVersionId":23648,"isInternetEnabled":false,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"# Intel Image Classification (CNN - Keras)\n\nThis notebook implements a CNN with Keras in order to classify images.\n1. Firstly, we'll import useful packages.\n1. Then, we'll load the data, before visualize and preprocess it.\n1. We'll try a simple CNN model and then we will evaluate its performances.\n1. We will then use pre trained model to address this challenge aswell.","metadata":{}},{"cell_type":"markdown","source":"# Import Packages","metadata":{}},{"cell_type":"code","source":"import numpy as np\nimport os\nfrom sklearn.metrics import confusion_matrix\nimport seaborn as sn; sn.set(font_scale=1.4)\nfrom sklearn.utils import shuffle           \nimport matplotlib.pyplot as plt             \nimport cv2                                 \nimport tensorflow as tf                \nfrom tqdm import tqdm","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2024-04-14T21:20:07.568324Z","iopub.execute_input":"2024-04-14T21:20:07.568978Z","iopub.status.idle":"2024-04-14T21:20:09.889300Z","shell.execute_reply.started":"2024-04-14T21:20:07.568863Z","shell.execute_reply":"2024-04-14T21:20:09.888239Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# I edited the class names\nclass_names = ['authentic', 'counterfeit']\nclass_names_label = {class_name:i for i, class_name in enumerate(class_names)}\n\nnb_classes = len(class_names)\n\nIMAGE_SIZE = (150, 150)","metadata":{"execution":{"iopub.status.busy":"2024-04-14T21:20:09.891814Z","iopub.execute_input":"2024-04-14T21:20:09.892503Z","iopub.status.idle":"2024-04-14T21:20:09.898571Z","shell.execute_reply.started":"2024-04-14T21:20:09.892433Z","shell.execute_reply":"2024-04-14T21:20:09.897788Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Loading the Data\nWe have to write a load_data function that load the images and the labels from the folder.","metadata":{}},{"cell_type":"code","source":"def load_data():\n    \"\"\"\n        Load the data:\n            - some images will be used to train the network.\n            - other images will be used to evaluate how accurately\n              the network learned to classify images.\n    \"\"\"\n    \n    # Add the dataset we curated\n    datasets = ['/kaggle/input/authentic-and-counterfeit-fashion/Data sources/seg_train/seg_train', '/kaggle/input/authentic-and-counterfeit-fashion/Data sources/seg_test/seg_test']\n    output = []\n    \n    # Iterate through training and test sets\n    for dataset in datasets:\n        \n        images = []\n        labels = []\n        \n        print(\"Loading {}\".format(dataset))\n        \n        # Iterate through each folder corresponding to a category\n        for folder in os.listdir(dataset):\n            label = class_names_label[folder]\n            \n            # Iterate through each image in our folder\n            for file in tqdm(os.listdir(os.path.join(dataset, folder))):\n                \n                # Get the path name of the image\n                img_path = os.path.join(os.path.join(dataset, folder), file)\n                # Open and resize the img\n                image = cv2.imread(img_path)\n                \n                # My edit: skip over images that weren't loaded in properly\n                if image is None:\n                    continue\n                    \n                image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)\n                image = cv2.resize(image, IMAGE_SIZE) \n                \n                # Append the image and its corresponding label to the output\n                images.append(image)\n                labels.append(label)\n                \n        images = np.array(images, dtype = 'float32')\n        labels = np.array(labels, dtype = 'int32')   \n        \n        output.append((images, labels))\n\n    return output","metadata":{"execution":{"iopub.status.busy":"2024-04-14T21:20:09.900293Z","iopub.execute_input":"2024-04-14T21:20:09.900557Z","iopub.status.idle":"2024-04-14T21:20:09.910788Z","shell.execute_reply.started":"2024-04-14T21:20:09.900510Z","shell.execute_reply":"2024-04-14T21:20:09.910041Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"(train_images, train_labels), (test_images, test_labels) = load_data()","metadata":{"execution":{"iopub.status.busy":"2024-04-14T21:20:09.912031Z","iopub.execute_input":"2024-04-14T21:20:09.912554Z","iopub.status.idle":"2024-04-14T21:20:11.208439Z","shell.execute_reply.started":"2024-04-14T21:20:09.912484Z","shell.execute_reply":"2024-04-14T21:20:11.207075Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_images, train_labels = shuffle(train_images, train_labels, random_state=25)","metadata":{"execution":{"iopub.status.busy":"2024-04-14T21:20:11.209658Z","iopub.execute_input":"2024-04-14T21:20:11.209928Z","iopub.status.idle":"2024-04-14T21:20:11.238094Z","shell.execute_reply.started":"2024-04-14T21:20:11.209868Z","shell.execute_reply":"2024-04-14T21:20:11.237209Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Let's explore the dataset\nWe can ask ourselves:\n* How many training and testing examples do we have ?\n* What is the size of the images ?\n* What is the proportion of each observed category ?","metadata":{}},{"cell_type":"code","source":"n_train = train_labels.shape[0]\nn_test = test_labels.shape[0]\n\nprint (\"Number of training examples: {}\".format(n_train))\nprint (\"Number of testing examples: {}\".format(n_test))\nprint (\"Each image is of size: {}\".format(IMAGE_SIZE))","metadata":{"execution":{"iopub.status.busy":"2024-04-14T21:20:11.239473Z","iopub.execute_input":"2024-04-14T21:20:11.239791Z","iopub.status.idle":"2024-04-14T21:20:11.245027Z","shell.execute_reply.started":"2024-04-14T21:20:11.239720Z","shell.execute_reply":"2024-04-14T21:20:11.244286Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import pandas as pd\n\n_, train_counts = np.unique(train_labels, return_counts=True)\n_, test_counts = np.unique(test_labels, return_counts=True)\npd.DataFrame({'train': train_counts,\n                    'test': test_counts}, \n             index=class_names\n            ).plot.bar()\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2024-04-14T21:20:11.246242Z","iopub.execute_input":"2024-04-14T21:20:11.246659Z","iopub.status.idle":"2024-04-14T21:20:11.530199Z","shell.execute_reply.started":"2024-04-14T21:20:11.246614Z","shell.execute_reply":"2024-04-14T21:20:11.529098Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Good practice: scale the data","metadata":{}},{"cell_type":"code","source":"train_images = train_images / 255.0 \ntest_images = test_images / 255.0","metadata":{"execution":{"iopub.status.busy":"2024-04-14T21:20:11.539291Z","iopub.execute_input":"2024-04-14T21:20:11.539889Z","iopub.status.idle":"2024-04-14T21:20:11.577662Z","shell.execute_reply.started":"2024-04-14T21:20:11.539822Z","shell.execute_reply":"2024-04-14T21:20:11.576318Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Visualize the data\nWe can display a random image from the training set.","metadata":{}},{"cell_type":"code","source":"def display_random_image(class_names, images, labels):\n    \"\"\"\n        Display a random image from the images array and its correspond label from the labels array.\n    \"\"\"\n    \n    index = np.random.randint(images.shape[0])\n    plt.figure()\n    plt.imshow(images[index])\n    plt.xticks([])\n    plt.yticks([])\n    plt.grid(False)\n    plt.title('Image #{} : '.format(index) + class_names[labels[index]])\n    plt.show()","metadata":{"execution":{"iopub.status.busy":"2024-04-14T21:20:11.579084Z","iopub.execute_input":"2024-04-14T21:20:11.579375Z","iopub.status.idle":"2024-04-14T21:20:11.584818Z","shell.execute_reply.started":"2024-04-14T21:20:11.579320Z","shell.execute_reply":"2024-04-14T21:20:11.583508Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"display_random_image(class_names, train_images, train_labels)","metadata":{"execution":{"iopub.status.busy":"2024-04-14T21:20:11.586093Z","iopub.execute_input":"2024-04-14T21:20:11.586431Z","iopub.status.idle":"2024-04-14T21:20:11.771020Z","shell.execute_reply.started":"2024-04-14T21:20:11.586370Z","shell.execute_reply":"2024-04-14T21:20:11.769940Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"We can also display the first 25 images from the training set directly with a loop to get a better view","metadata":{}},{"cell_type":"code","source":"def display_examples(class_names, images, labels):\n    \"\"\"\n        Display 25 images from the images array with its corresponding labels\n    \"\"\"\n    \n    fig = plt.figure(figsize=(10,10))\n    fig.suptitle(\"Some examples of images of the dataset\", fontsize=16)\n    for i in range(25):\n        try:\n            plt.subplot(5,5,i+1)\n            plt.xticks([])\n            plt.yticks([])\n            plt.grid(False)\n            plt.imshow(images[i], cmap=plt.cm.binary)\n            plt.xlabel(class_names[labels[i]])\n        except:\n            pass\n    plt.show()","metadata":{"execution":{"iopub.status.busy":"2024-04-14T21:20:11.772202Z","iopub.execute_input":"2024-04-14T21:20:11.772502Z","iopub.status.idle":"2024-04-14T21:20:11.779776Z","shell.execute_reply.started":"2024-04-14T21:20:11.772454Z","shell.execute_reply":"2024-04-14T21:20:11.778589Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"display_examples(class_names, train_images, train_labels)","metadata":{"execution":{"iopub.status.busy":"2024-04-14T21:20:11.781463Z","iopub.execute_input":"2024-04-14T21:20:11.782109Z","iopub.status.idle":"2024-04-14T21:20:13.105993Z","shell.execute_reply.started":"2024-04-14T21:20:11.782045Z","shell.execute_reply":"2024-04-14T21:20:13.104987Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Beginner: Simple Model Creation\n\nSteps are:\n1. Build the model,\n1. Compile the model,\n1. Train / fit the data to the model,\n1. Evaluate the model on the testing set,\n1. Carry out an error analysis of our model.\n\nWe can build an easy model composed of different layers such as:\n* Conv2D: (32 filters of size 3 by 3) The features will be \"extracted\" from the image.\n* MaxPooling2D: The images get half sized.\n* Flatten: Transforms the format of the images from a 2d-array to a 1d-array of 150 150 3 pixel values.\n* Relu  : given a value x, returns max(x, 0).\n* Softmax: 2 neurons, probability that the image belongs to one of the classes.","metadata":{}},{"cell_type":"code","source":"model = tf.keras.Sequential([\n    tf.keras.layers.Conv2D(32, (3, 3), activation = 'relu', input_shape = (150, 150, 3)), \n    tf.keras.layers.MaxPooling2D(2,2),\n    tf.keras.layers.Conv2D(32, (3, 3), activation = 'relu'),\n    tf.keras.layers.MaxPooling2D(2,2),\n    tf.keras.layers.Flatten(),\n    tf.keras.layers.Dense(128, activation=tf.nn.relu),\n    \n    # My edit: changed from 6 neurons to 2 because we have 2 classes\n    tf.keras.layers.Dense(2, activation=tf.nn.softmax) \n])","metadata":{"execution":{"iopub.status.busy":"2024-04-14T21:20:13.107339Z","iopub.execute_input":"2024-04-14T21:20:13.107633Z","iopub.status.idle":"2024-04-14T21:20:13.250175Z","shell.execute_reply.started":"2024-04-14T21:20:13.107577Z","shell.execute_reply":"2024-04-14T21:20:13.249146Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Then, we can compile it with some parameters such as:\n* **Optimizer**: adam = RMSProp + Momentum.\nWhat is Momentum and RMSProp ?\n* Momentum = takes into account past gradient to have a better update.\n* RMSProp = exponentially weighted average of the squares of past gradients.\n* **Loss function**: we use sparse categorical crossentropy for classification, each images belongs to one class only","metadata":{}},{"cell_type":"code","source":"model.compile(optimizer = 'adam', loss = 'sparse_categorical_crossentropy', metrics=['accuracy'])","metadata":{"execution":{"iopub.status.busy":"2024-04-14T21:20:13.251434Z","iopub.execute_input":"2024-04-14T21:20:13.251784Z","iopub.status.idle":"2024-04-14T21:20:13.385888Z","shell.execute_reply.started":"2024-04-14T21:20:13.251720Z","shell.execute_reply":"2024-04-14T21:20:13.384889Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"We fit the model to the data from the training set. The neural network will learn by itself the pattern in order to distinguish each category.","metadata":{}},{"cell_type":"code","source":"history = model.fit(train_images, train_labels, batch_size=128, epochs=20, validation_split = 0.2)","metadata":{"execution":{"iopub.status.busy":"2024-04-14T21:20:13.387464Z","iopub.execute_input":"2024-04-14T21:20:13.387828Z","iopub.status.idle":"2024-04-14T21:20:49.363648Z","shell.execute_reply.started":"2024-04-14T21:20:13.387750Z","shell.execute_reply":"2024-04-14T21:20:49.362548Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def plot_accuracy_loss(history):\n    \"\"\"\n        Plot the accuracy and the loss during the training of the nn.\n    \"\"\"\n    fig = plt.figure(figsize=(10,5))\n\n    # Plot accuracy\n    plt.subplot(221)\n    plt.plot(history.history['acc'],'bo--', label = \"acc\")\n    plt.plot(history.history['val_acc'], 'ro--', label = \"val_acc\")\n    plt.title(\"train_acc vs val_acc\")\n    plt.ylabel(\"accuracy\")\n    plt.xlabel(\"epochs\")\n    plt.legend()\n\n    # Plot loss function\n    plt.subplot(222)\n    plt.plot(history.history['loss'],'bo--', label = \"loss\")\n    plt.plot(history.history['val_loss'], 'ro--', label = \"val_loss\")\n    plt.title(\"train_loss vs val_loss\")\n    plt.ylabel(\"loss\")\n    plt.xlabel(\"epochs\")\n\n    plt.legend()\n    plt.show()","metadata":{"execution":{"iopub.status.busy":"2024-04-14T21:20:49.364814Z","iopub.execute_input":"2024-04-14T21:20:49.365194Z","iopub.status.idle":"2024-04-14T21:20:49.372928Z","shell.execute_reply.started":"2024-04-14T21:20:49.365052Z","shell.execute_reply":"2024-04-14T21:20:49.371864Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plot_accuracy_loss(history)","metadata":{"execution":{"iopub.status.busy":"2024-04-14T21:20:49.374598Z","iopub.execute_input":"2024-04-14T21:20:49.375021Z","iopub.status.idle":"2024-04-14T21:20:49.849265Z","shell.execute_reply.started":"2024-04-14T21:20:49.374942Z","shell.execute_reply":"2024-04-14T21:20:49.848353Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"We should evaluate the model performance on test set","metadata":{}},{"cell_type":"code","source":"test_loss = model.evaluate(test_images, test_labels)","metadata":{"execution":{"iopub.status.busy":"2024-04-14T21:20:49.850786Z","iopub.execute_input":"2024-04-14T21:20:49.851139Z","iopub.status.idle":"2024-04-14T21:20:50.180196Z","shell.execute_reply.started":"2024-04-14T21:20:49.851082Z","shell.execute_reply":"2024-04-14T21:20:50.179343Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"We see that we achieve high accuracy on the testing test.\n\nLet's see how the classifier is doing on random images.","metadata":{}},{"cell_type":"code","source":"predictions = model.predict(test_images)     # Vector of probabilities\npred_labels = np.argmax(predictions, axis = 1) # We take the highest probability\n\ndisplay_random_image(class_names, test_images, pred_labels)","metadata":{"execution":{"iopub.status.busy":"2024-04-14T21:20:50.181780Z","iopub.execute_input":"2024-04-14T21:20:50.182074Z","iopub.status.idle":"2024-04-14T21:20:50.626876Z","shell.execute_reply.started":"2024-04-14T21:20:50.182026Z","shell.execute_reply":"2024-04-14T21:20:50.625987Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Error analysis\n\nLet's try to understand which kinds of images the classifier has trouble with.","metadata":{}},{"cell_type":"code","source":"def print_mislabeled_images(class_names, test_images, test_labels, pred_labels):\n    \"\"\"\n        Print 25 examples of mislabeled images by the classifier, e.g when test_labels != pred_labels\n    \"\"\"\n    BOO = (test_labels == pred_labels)\n    mislabeled_indices = np.where(BOO == 0)\n    mislabeled_images = test_images[mislabeled_indices]\n    mislabeled_labels = pred_labels[mislabeled_indices]\n\n    title = \"Some examples of mislabeled images by the classifier:\"\n    display_examples(class_names,  mislabeled_images, mislabeled_labels)\n","metadata":{"execution":{"iopub.status.busy":"2024-04-14T21:20:50.628198Z","iopub.execute_input":"2024-04-14T21:20:50.628673Z","iopub.status.idle":"2024-04-14T21:20:50.635201Z","shell.execute_reply.started":"2024-04-14T21:20:50.628612Z","shell.execute_reply":"2024-04-14T21:20:50.634275Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print_mislabeled_images(class_names, test_images, test_labels, pred_labels)","metadata":{"execution":{"iopub.status.busy":"2024-04-14T21:20:50.636603Z","iopub.execute_input":"2024-04-14T21:20:50.637272Z","iopub.status.idle":"2024-04-14T21:20:51.542181Z","shell.execute_reply.started":"2024-04-14T21:20:50.636885Z","shell.execute_reply":"2024-04-14T21:20:51.541190Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"CM = confusion_matrix(test_labels, pred_labels)\nax = plt.axes()\nsn.heatmap(CM, annot=True, \n           annot_kws={\"size\": 10}, \n           xticklabels=class_names, \n           yticklabels=class_names, ax = ax)\nax.set_title('Confusion matrix')\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2024-04-14T21:20:51.543729Z","iopub.execute_input":"2024-04-14T21:20:51.544385Z","iopub.status.idle":"2024-04-14T21:20:51.925052Z","shell.execute_reply.started":"2024-04-14T21:20:51.544320Z","shell.execute_reply":"2024-04-14T21:20:51.923799Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Conclusion: The classifier has trouble with counterfeit images.\nIt's near 50/50 whether a counterfeit product is correctly classified or not.","metadata":{}}]}