{"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"}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"!pip install facenet-pytorch","metadata":{"papermill":{"duration":0.008707,"end_time":"2023-08-28T21:29:20.317143","exception":false,"start_time":"2023-08-28T21:29:20.308436","status":"completed"},"tags":[],"_kg_hide-input":true,"execution":{"iopub.status.busy":"2023-08-31T09:15:20.351640Z","iopub.execute_input":"2023-08-31T09:15:20.352872Z","iopub.status.idle":"2023-08-31T09:15:37.460056Z","shell.execute_reply.started":"2023-08-31T09:15:20.352828Z","shell.execute_reply":"2023-08-31T09:15:37.458798Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## ⚙️ Install libs","metadata":{"papermill":{"duration":0.007617,"end_time":"2023-08-28T21:29:20.332797","exception":false,"start_time":"2023-08-28T21:29:20.325180","status":"completed"},"tags":[]}},{"cell_type":"code","source":"# work with data\nimport os\nimport shutil\nfrom sklearn.model_selection import train_test_split\nimport numpy as np\nimport pandas as pd\nfrom sklearn.manifold import TSNE\n\n# visualization \nfrom IPython.display import clear_output\nfrom tqdm import tqdm\nimport matplotlib.pyplot as plt\nimport matplotlib.image as mpimg\n\n# DL\nfrom sklearn import svm\nfrom sklearn.ensemble import RandomForestClassifier\nfrom sklearn.model_selection import GridSearchCV\n\nimport torch\nimport torchvision.transforms as transforms\nfrom PIL import Image\n\nfrom facenet_pytorch import MTCNN, InceptionResnetV1","metadata":{"papermill":{"duration":4.083792,"end_time":"2023-08-28T21:39:08.217857","exception":false,"start_time":"2023-08-28T21:39:04.134065","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2023-08-31T09:15:37.463410Z","iopub.execute_input":"2023-08-31T09:15:37.463923Z","iopub.status.idle":"2023-08-31T09:15:43.137333Z","shell.execute_reply.started":"2023-08-31T09:15:37.463877Z","shell.execute_reply":"2023-08-31T09:15:43.135906Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## 📊 Check dataset out","metadata":{"papermill":{"duration":0.007716,"end_time":"2023-08-28T21:39:08.233775","exception":false,"start_time":"2023-08-28T21:39:08.226059","status":"completed"},"tags":[]}},{"cell_type":"code","source":"source_dir = \"/kaggle/input/face-recognition-xt122/Train\"","metadata":{"papermill":{"duration":0.016594,"end_time":"2023-08-28T21:39:08.258484","exception":false,"start_time":"2023-08-28T21:39:08.241890","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2023-08-31T09:15:43.138837Z","iopub.execute_input":"2023-08-31T09:15:43.139485Z","iopub.status.idle":"2023-08-31T09:15:43.144999Z","shell.execute_reply.started":"2023-08-31T09:15:43.139449Z","shell.execute_reply":"2023-08-31T09:15:43.143898Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class_names = os.listdir(source_dir)\nclass_names","metadata":{"papermill":{"duration":0.026557,"end_time":"2023-08-28T21:39:08.293161","exception":false,"start_time":"2023-08-28T21:39:08.266604","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2023-08-31T09:15:43.147383Z","iopub.execute_input":"2023-08-31T09:15:43.147759Z","iopub.status.idle":"2023-08-31T09:15:43.171690Z","shell.execute_reply.started":"2023-08-31T09:15:43.147727Z","shell.execute_reply":"2023-08-31T09:15:43.170658Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def count(class_name):\n    path = os.path.join(source_dir, class_name)\n    file_names = os.listdir(path)\n    \n    return len(file_names)\n    \n\ncounts = [count(class_name) for class_name in class_names]\ncounts","metadata":{"papermill":{"duration":0.155799,"end_time":"2023-08-28T21:39:08.459942","exception":false,"start_time":"2023-08-28T21:39:08.304143","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2023-08-31T09:15:43.173045Z","iopub.execute_input":"2023-08-31T09:15:43.173591Z","iopub.status.idle":"2023-08-31T09:15:43.338235Z","shell.execute_reply.started":"2023-08-31T09:15:43.173558Z","shell.execute_reply":"2023-08-31T09:15:43.337372Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plt.bar(class_names, counts)\nplt.tight_layout()\nplt.show()","metadata":{"papermill":{"duration":0.409758,"end_time":"2023-08-28T21:39:08.879352","exception":false,"start_time":"2023-08-28T21:39:08.469594","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2023-08-31T09:15:43.339617Z","iopub.execute_input":"2023-08-31T09:15:43.340177Z","iopub.status.idle":"2023-08-31T09:15:43.689527Z","shell.execute_reply.started":"2023-08-31T09:15:43.340138Z","shell.execute_reply":"2023-08-31T09:15:43.688178Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"fig, axes = plt.subplots(1, len(class_names), figsize=(15, 5))\n\nfor i, class_name in enumerate(class_names):\n    class_dir = os.path.join(source_dir, class_name)\n    \n    # read first image\n    for file in os.listdir(class_dir):\n        image = mpimg.imread(os.path.join(class_dir, file))\n        break\n    \n    axes[i].imshow(image)\n    axes[i].set_title(class_name)\n    axes[i].axis('off')\n    \nplt.tight_layout()\nplt.show()","metadata":{"papermill":{"duration":1.549863,"end_time":"2023-08-28T21:39:10.438052","exception":false,"start_time":"2023-08-28T21:39:08.888189","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2023-08-31T09:15:43.691064Z","iopub.execute_input":"2023-08-31T09:15:43.691553Z","iopub.status.idle":"2023-08-31T09:15:45.530821Z","shell.execute_reply.started":"2023-08-31T09:15:43.691510Z","shell.execute_reply":"2023-08-31T09:15:45.529363Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## 🚀 Pipeline implentations\n\nWe are going to use Resnet to encode each picture, and after that, we will train an Random Forest for classifying the classes","metadata":{"papermill":{"duration":0.027152,"end_time":"2023-08-28T21:39:10.492192","exception":false,"start_time":"2023-08-28T21:39:10.465040","status":"completed"},"tags":[]}},{"cell_type":"code","source":"device = \"cuda\" if torch.cuda.is_available() else \"cpu\"","metadata":{"execution":{"iopub.status.busy":"2023-08-31T09:15:45.532405Z","iopub.execute_input":"2023-08-31T09:15:45.532779Z","iopub.status.idle":"2023-08-31T09:15:45.539600Z","shell.execute_reply.started":"2023-08-31T09:15:45.532747Z","shell.execute_reply":"2023-08-31T09:15:45.538381Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Although using GPU is inefficient without DataLoader","metadata":{}},{"cell_type":"code","source":"encodings = []\nencodings_classes = []\n\ndef image_iterator(base_dir):\n    \"\"\" The iterator that will go through entire dataset \"\"\"\n    \n    class_names = os.listdir(base_dir)\n    \n    for class_name in class_names:\n        pictures = os.listdir(os.path.join(base_dir, class_name))\n        \n        for picture in pictures:\n            yield { \n                \"class\": class_name, \n                \"path\": os.path.join(base_dir, class_name, picture)\n            }","metadata":{"papermill":{"duration":0.037611,"end_time":"2023-08-28T21:39:10.556621","exception":false,"start_time":"2023-08-28T21:39:10.519010","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2023-08-31T09:15:45.541449Z","iopub.execute_input":"2023-08-31T09:15:45.541793Z","iopub.status.idle":"2023-08-31T09:15:45.553580Z","shell.execute_reply.started":"2023-08-31T09:15:45.541765Z","shell.execute_reply":"2023-08-31T09:15:45.551978Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### 1️⃣ Face recognition model's encoder","metadata":{"papermill":{"duration":0.0267,"end_time":"2023-08-28T21:39:10.610568","exception":false,"start_time":"2023-08-28T21:39:10.583868","status":"completed"},"tags":[]}},{"cell_type":"code","source":"mtcnn = MTCNN(image_size=160, device=device)\nresnet = InceptionResnetV1(pretrained='vggface2').eval().to(device)","metadata":{"execution":{"iopub.status.busy":"2023-08-31T09:15:45.557933Z","iopub.execute_input":"2023-08-31T09:15:45.558339Z","iopub.status.idle":"2023-08-31T09:15:47.156147Z","shell.execute_reply.started":"2023-08-31T09:15:45.558309Z","shell.execute_reply":"2023-08-31T09:15:47.155134Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"fig, axes = plt.subplots(1, 2, figsize=(14, 7))\n\nfor picture in image_iterator(source_dir):\n    image = Image.open(picture[\"path\"])\n    \n    # Original image\n    axes[0].imshow(image)\n    axes[0].set_title(\"Original image\")\n    axes[0].axis('off')\n    \n    # Cropped image\n    axes[1].imshow(mtcnn(image).detach().numpy().transpose(1, 2, 0))\n    axes[1].set_title(\"Cropped and Normalized Image\")\n    axes[1].axis('off')\n    \n    break\n    \nplt.tight_layout()\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2023-08-31T09:15:47.157595Z","iopub.execute_input":"2023-08-31T09:15:47.158184Z","iopub.status.idle":"2023-08-31T09:15:49.128085Z","shell.execute_reply.started":"2023-08-31T09:15:47.158149Z","shell.execute_reply":"2023-08-31T09:15:49.126385Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def encode_pipeline(image: Image.Image) -> torch.Tensor:\n    image = mtcnn(image).to(device)\n    image_encodings = resnet(image.unsqueeze(0))\n    \n    return image_encodings","metadata":{"execution":{"iopub.status.busy":"2023-08-31T09:15:49.130026Z","iopub.execute_input":"2023-08-31T09:15:49.131066Z","iopub.status.idle":"2023-08-31T09:15:49.138770Z","shell.execute_reply.started":"2023-08-31T09:15:49.131016Z","shell.execute_reply":"2023-08-31T09:15:49.137454Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"for picture in tqdm(image_iterator(source_dir), total=sum(counts)):\n    image = Image.open(picture[\"path\"])\n    \n    try:\n        face_enc = encode_pipeline(image)\n\n        encodings.append(face_enc)\n        encodings_classes.append(picture[\"class\"])\n        \n    except AttributeError as error:\n        print(\"Couldn't recognize face: \", picture[\"class\"], picture[\"path\"])","metadata":{"papermill":{"duration":907.393506,"end_time":"2023-08-28T21:54:18.030800","exception":false,"start_time":"2023-08-28T21:39:10.637294","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2023-08-31T09:15:49.141085Z","iopub.execute_input":"2023-08-31T09:15:49.141687Z","iopub.status.idle":"2023-08-31T09:20:16.156222Z","shell.execute_reply.started":"2023-08-31T09:15:49.141637Z","shell.execute_reply":"2023-08-31T09:20:16.155079Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### 2️⃣ Sklearn Random Forest model train","metadata":{"papermill":{"duration":0.077205,"end_time":"2023-08-28T21:54:18.184636","exception":false,"start_time":"2023-08-28T21:54:18.107431","status":"completed"},"tags":[]}},{"cell_type":"code","source":"encodings = [e.squeeze().cpu().detach().numpy() for e in encodings]","metadata":{"execution":{"iopub.status.busy":"2023-08-31T09:20:16.158275Z","iopub.execute_input":"2023-08-31T09:20:16.159129Z","iopub.status.idle":"2023-08-31T09:20:16.948340Z","shell.execute_reply.started":"2023-08-31T09:20:16.159081Z","shell.execute_reply":"2023-08-31T09:20:16.946875Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"param_grid = {\n    'n_estimators': [250, 300, 350],\n    'min_samples_split': [2, 3],\n    'min_samples_leaf': [3, 4, 5],\n}\n\nclf = RandomForestClassifier()\ngrid_search = GridSearchCV(clf, param_grid, cv=5)\ngrid_search.fit(encodings, encodings_classes)","metadata":{"papermill":{"duration":0.581225,"end_time":"2023-08-28T21:54:18.842543","exception":false,"start_time":"2023-08-28T21:54:18.261318","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2023-08-31T09:20:16.951827Z","iopub.execute_input":"2023-08-31T09:20:16.952203Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Get the best parameters and best score\nbest_params = grid_search.best_params_\nbest_score = grid_search.best_score_\nclf = grid_search.best_estimator_\n\nprint(best_params, best_score)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## 🎲 Observing the Distribution of Classes","metadata":{"papermill":{"duration":0.079831,"end_time":"2023-08-28T21:54:19.000398","exception":false,"start_time":"2023-08-28T21:54:18.920567","status":"completed"},"tags":[]}},{"cell_type":"code","source":"encodings = np.array(encodings)\nencodings_classes = np.array(encodings_classes)","metadata":{"papermill":{"duration":0.095171,"end_time":"2023-08-28T21:54:19.176894","exception":false,"start_time":"2023-08-28T21:54:19.081723","status":"completed"},"tags":[],"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"tsne = TSNE(n_components=2)\ntsne_encodings = tsne.fit_transform(encodings)","metadata":{"papermill":{"duration":3.916371,"end_time":"2023-08-28T21:54:23.174032","exception":false,"start_time":"2023-08-28T21:54:19.257661","status":"completed"},"tags":[],"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plt.figure(figsize=(10, 7))\nfor i, class_name in enumerate(class_names):\n    idx = np.where(class_name == encodings_classes)\n    plt.scatter(tsne_encodings[idx, 0], tsne_encodings[idx, 1], label=class_name)\n    \nplt.title(\"t-SNE Visualization of Encodings\")\nplt.xlabel(\"t-SNE Component 1\")\nplt.ylabel(\"t-SNE Component 2\")\nplt.legend()\nplt.show()","metadata":{"papermill":{"duration":0.565248,"end_time":"2023-08-28T21:54:23.818183","exception":false,"start_time":"2023-08-28T21:54:23.252935","status":"completed"},"tags":[],"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## 🐍 Submit","metadata":{"papermill":{"duration":0.079722,"end_time":"2023-08-28T21:54:23.976927","exception":false,"start_time":"2023-08-28T21:54:23.897205","status":"completed"},"tags":[]}},{"cell_type":"code","source":"test_dir = \"/kaggle/input/face-recognition-xt122/Test\"\n\nclass_map = pd.read_csv(\"/kaggle/input/face-recognition-xt122/ClassMap.csv\")\nsample_submission = pd.read_csv(\"/kaggle/input/face-recognition-xt122/SampleSubmission.csv\")","metadata":{"papermill":{"duration":0.115819,"end_time":"2023-08-28T21:54:24.172649","exception":false,"start_time":"2023-08-28T21:54:24.056830","status":"completed"},"tags":[],"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def get_class_label(classe: str):\n    idx = class_map[class_map[\"classe_name\"] == classe][\"label_num\"]\n    return int(idx)\n\ndef get_path(image_name: str, ext: str = \".jpg\"):\n    return os.path.join(test_dir, image_name + ext)","metadata":{"papermill":{"duration":0.089742,"end_time":"2023-08-28T21:54:24.343578","exception":false,"start_time":"2023-08-28T21:54:24.253836","status":"completed"},"tags":[],"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"for idx, row in tqdm(sample_submission.iterrows(), total=len(sample_submission)):\n    # Face recognition encoder\n    image = Image.open(get_path(row[\"filename\"])) \n    try:\n        image_enc = encode_pipeline(image).squeeze().cpu().detach().numpy()\n        # Random Forest model\n        proba = clf.predict_proba([image_enc])\n        predicted_class = clf.classes_[np.argmax(proba)]\n    except AttributeError:\n        predicted_class = \"Others\"\n        \n    sample_submission.at[idx, \"label\"] = get_class_label(predicted_class)","metadata":{"papermill":{"duration":988.386666,"end_time":"2023-08-28T22:10:52.810033","exception":false,"start_time":"2023-08-28T21:54:24.423367","status":"completed"},"tags":[],"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"sample_submission.to_csv(\"submission.csv\", index=False)","metadata":{"papermill":{"duration":0.147925,"end_time":"2023-08-28T22:10:53.093231","exception":false,"start_time":"2023-08-28T22:10:52.945306","status":"completed"},"tags":[],"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{"papermill":{"duration":0.132508,"end_time":"2023-08-28T22:10:53.358595","exception":false,"start_time":"2023-08-28T22:10:53.226087","status":"completed"},"tags":[]},"execution_count":null,"outputs":[]}],"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"}}