{"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":65471,"databundleVersionId":7211464,"sourceType":"competition"},{"sourceId":5859,"sourceType":"modelInstanceVersion","isSourceIdPinned":true,"modelInstanceId":4632}],"dockerImageVersionId":30626,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import os\nimport pandas \nimport matplotlib.image as mpimg\nimport matplotlib.pyplot as plt\nfrom IPython.display import Image , display\nfrom sklearn.metrics import confusion_matrix, classification_report\nimport itertools\nimport shutil\nimport random\n%matplotlib inline\nimport numpy as np\nimport seaborn as sns\nimport cv2 \n","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2023-12-22T21:08:07.572147Z","iopub.execute_input":"2023-12-22T21:08:07.572422Z","iopub.status.idle":"2023-12-22T21:08:10.459497Z","shell.execute_reply.started":"2023-12-22T21:08:07.572397Z","shell.execute_reply":"2023-12-22T21:08:10.458454Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def get_labels_from_directory(root_directory, label_position=-3, label_kind=-2, extension='.png'):\n    directory_labels = {}\n    class_names = []\n\n\n    for subdir in os.listdir(root_directory):\n        subdir_path = os.path.join(root_directory, subdir)\n\n\n        if os.path.isdir(subdir_path):\n\n            for file_name in os.listdir(subdir_path):\n                file_path = os.path.join(subdir_path, file_name)\n\n\n                if os.path.isfile(file_path) and file_name.lower().endswith(extension):\n\n                    label = file_name.split('_')[label_position].split('.')[0]\n                    label_kind_name = file_name.split('_')[label_kind].split('.')[0]\n                    result_label = \" \".join([label, label_kind_name])\n\n\n                    directory_labels[result_label] = int(subdir)\n                    class_names.append(result_label)\n                    break\n\n    return directory_labels, sorted(class_names)\n\n\n\nroot_directory = '/kaggle/input/arabic-letters-classification/Final_Arabic_Alpha_dataset/Final_Arabic_Alpha_dataset/train'\nlabels, class_names = get_labels_from_directory(root_directory)\nprint(labels)\n","metadata":{"execution":{"iopub.status.busy":"2023-12-22T21:08:10.461028Z","iopub.execute_input":"2023-12-22T21:08:10.461449Z","iopub.status.idle":"2023-12-22T21:08:14.868949Z","shell.execute_reply.started":"2023-12-22T21:08:10.461421Z","shell.execute_reply":"2023-12-22T21:08:14.867951Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import torch\nfrom torchvision import  transforms\nfrom torch.utils.data import DataLoader\nfrom torch.utils.data import Dataset\nfrom PIL import Image\nimport random\nimport pathlib\nfrom glob import glob\n\nclass ImageFolderCustom(Dataset):\n\n\n    def __init__(self, targ_dir: str, split='train', transform=None, shuffle=True, seed=42):\n\n        self.root_dir = targ_dir\n        self.paths = list(pathlib.Path(targ_dir).glob(\"*/*.png\"))\n        self.cls_to_idx, self.classes = get_labels_from_directory(self.root_dir)\n        self.transform = transform\n        self.split = split\n        self.shuffle = shuffle\n\n        if self.shuffle:\n\n            if seed is not None:\n                random.seed(seed)\n\n            random.shuffle(self.paths)\n        if self.split == 'train':\n\n            train_size = int(0.9 * len(self.paths))\n            self.paths = self.paths[:train_size]\n        elif self.split == 'val':\n\n            val_size = len(self.paths) - int(0.9 * len(self.paths))\n            self.paths = self.paths[-val_size:]\n            \n    def __len__(self):\n        return len(self.paths)\n\n    def load_img(self, index):\n        image = Image.open(str(self.paths[index])).convert(\"RGB\")\n\n        return image\n\n    def __getitem__(self, index: int):\n        img = self.load_img(index)\n        label_name = str(self.paths[index]).split('_')[-3].split('.')[0]\n        label_kind = str(self.paths[index]).split('_')[-2].split('.')[0]\n        label_full_name = \" \".join([label_name, label_kind])\n        class_idx = self.cls_to_idx[label_full_name]\n        if self.transform:\n            return self.transform(img), class_idx\n        else:\n            return img, class_idx\n\n","metadata":{"execution":{"iopub.status.busy":"2023-12-22T21:08:19.703712Z","iopub.execute_input":"2023-12-22T21:08:19.704042Z","iopub.status.idle":"2023-12-22T21:08:25.168819Z","shell.execute_reply.started":"2023-12-22T21:08:19.704017Z","shell.execute_reply":"2023-12-22T21:08:25.167864Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class Threshold(object):\n    def __init__(self, threshold):\n        self.threshold = threshold\n\n    def __call__(self, img):\n        return (img > self.threshold).float()","metadata":{"execution":{"iopub.status.busy":"2023-12-22T21:08:26.722257Z","iopub.execute_input":"2023-12-22T21:08:26.723236Z","iopub.status.idle":"2023-12-22T21:08:26.727897Z","shell.execute_reply.started":"2023-12-22T21:08:26.723200Z","shell.execute_reply":"2023-12-22T21:08:26.726890Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_transform= transforms.Compose([\n    transforms.Resize((224, 224), antialias=True),\n    transforms.Grayscale(num_output_channels=3),\n    transforms.ToTensor(),\n    transforms.RandomApply([\n        transforms.GaussianBlur(kernel_size=3)\n    ], p=0.25),\n    Threshold(threshold=0.7),\n\n\n\n])\ntest_transform = transforms.Compose([\n    transforms.Resize((224, 224), antialias=True),\n    transforms.Grayscale(num_output_channels=3),\n    transforms.ToTensor(),\n    Threshold(threshold=0.7),\n\n\n\n])","metadata":{"execution":{"iopub.status.busy":"2023-12-22T21:08:29.120111Z","iopub.execute_input":"2023-12-22T21:08:29.121140Z","iopub.status.idle":"2023-12-22T21:08:29.127677Z","shell.execute_reply.started":"2023-12-22T21:08:29.121099Z","shell.execute_reply":"2023-12-22T21:08:29.126613Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"data_dir = '/kaggle/input/arabic-letters-classification/Final_Arabic_Alpha_dataset/Final_Arabic_Alpha_dataset/train'\ntrain_data_custom = ImageFolderCustom(targ_dir=data_dir, split='train', transform=train_transform, shuffle=True, seed=42)\nval_data_custom = ImageFolderCustom(targ_dir=data_dir, split='val', transform=test_transform, shuffle=False, seed=42)","metadata":{"execution":{"iopub.status.busy":"2023-12-22T21:08:34.829987Z","iopub.execute_input":"2023-12-22T21:08:34.830371Z","iopub.status.idle":"2023-12-22T21:08:35.836239Z","shell.execute_reply.started":"2023-12-22T21:08:34.830341Z","shell.execute_reply":"2023-12-22T21:08:35.835457Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_dataloader = DataLoader(\n      train_data_custom,\n      batch_size=64,\n      shuffle=True,\n      num_workers=2,\n      pin_memory=True,\n  )\nval_dataloader = DataLoader(\n      val_data_custom,\n      batch_size=64,\n      shuffle=False,\n      num_workers=2,\n      pin_memory=True,\n  )\nclass_names = train_data_custom.classes","metadata":{"execution":{"iopub.status.busy":"2023-12-22T21:08:40.326245Z","iopub.execute_input":"2023-12-22T21:08:40.327454Z","iopub.status.idle":"2023-12-22T21:08:40.332875Z","shell.execute_reply.started":"2023-12-22T21:08:40.327417Z","shell.execute_reply":"2023-12-22T21:08:40.331784Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import matplotlib.pyplot as plt\ndef plot_random_images(data_loader, num_images=10):\n    fig, axes = plt.subplots(1, num_images, figsize=(15, 3))\n\n    for i in range(num_images):\n        # Get a random batch from the DataLoader\n        batch = next(iter(data_loader))\n        images, labels = batch\n\n        index = torch.randint(0, images.size(0), (1,)).item()\n        image = images[index].squeeze().permute(1,2,0).numpy()\n        label = labels[index].item()\n\n\n\n        axes[i].imshow(image, cmap='gray')\n        axes[i].set_title(f\"Label: {label}\")\n        axes[i].axis('off')\n\n    plt.show()\n\n# Plot random images with labels\nplot_random_images(val_dataloader)","metadata":{"execution":{"iopub.status.busy":"2023-12-22T21:08:47.069577Z","iopub.execute_input":"2023-12-22T21:08:47.070516Z","iopub.status.idle":"2023-12-22T21:08:59.258450Z","shell.execute_reply.started":"2023-12-22T21:08:47.070454Z","shell.execute_reply":"2023-12-22T21:08:59.257450Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import torch\nfrom torch import nn\nfrom tqdm.auto import tqdm\ndef train_step(model: torch.nn.Module,\n               dataloader: torch.utils.data.DataLoader,\n               loss_fn: torch.nn.Module,\n               optimizer: torch.optim.Optimizer,\n               device: torch.device):\n\n    model.train()\n\n\n    train_loss, train_acc = 0, 0\n\n\n\n\n\n    for batch, (X, y) in tqdm(enumerate(dataloader), desc='training epoch'):\n\n\n        X, y = X.to(device), y.to(device)\n\n\n        y_pred = model(X)\n\n\n        loss = loss_fn(y_pred, y)\n        train_loss += loss.item()\n\n\n\n\n        optimizer.zero_grad()\n\n\n        loss.backward()\n\n\n        optimizer.step()\n\n\n        y_pred_class = torch.argmax(torch.softmax(y_pred, dim=1), dim=1)\n        train_acc += (y_pred_class == y).sum().item()/len(y_pred)\n\n\n\n\n\n    train_loss = train_loss / len(dataloader)\n    train_acc = train_acc / len(dataloader)\n    return train_loss, train_acc\n\ndef test_step(model: torch.nn.Module,\n              dataloader: torch.utils.data.DataLoader,\n              loss_fn: torch.nn.Module,\n              device: torch.device):\n\n    model.eval()\n\n\n    test_loss, test_acc = 0, 0\n\n\n\n\n    with torch.inference_mode():\n\n        for batch, (X, y) in enumerate(dataloader):\n\n            X, y = X.to(device), y.to(device)\n\n\n            test_pred_logits = model(X)\n\n\n            loss = loss_fn(test_pred_logits, y)\n            test_loss += loss.item()\n\n\n            test_pred_labels = test_pred_logits.argmax(dim=1)\n            test_acc += ((test_pred_labels == y).sum().item()/len(test_pred_labels))\n\n\n\n\n    test_loss = test_loss / len(dataloader)\n    test_acc = test_acc / len(dataloader)\n    return test_loss, test_acc\n\ndef train(model: torch.nn.Module,\n          train_dataloader: torch.utils.data.DataLoader,\n          test_dataloader: torch.utils.data.DataLoader,\n          optimizer: torch.optim.Optimizer,\n          loss_fn: torch.nn.Module,\n          starting_epochs: int,\n          epochs: int,\n          device: torch.device,\n          checkpoint_interval: int):\n\n    print(\"Training Data Size:\", len(train_dataloader.dataset))\n    print(\"Test Data Size:\", len(test_dataloader.dataset))\n\n    results = {\"train_loss\": [],\n        \"train_acc\": [],\n        \"test_loss\": [],\n        \"test_acc\": []\n    }\n\n    highest_train_accuracy = 0.0\n    highest_test_accuracy = 0.0\n    pbar = tqdm(total=epochs, initial=starting_epochs, dynamic_ncols=True, desc=\"Training\")\n\n    for epoch in range(starting_epochs, epochs):\n        train_loss, train_acc = train_step(model=model,\n                                           dataloader=train_dataloader,\n                                           loss_fn=loss_fn,\n                                           optimizer=optimizer,\n                                           device=device)\n        test_loss, test_acc = test_step(model=model,\n            dataloader=test_dataloader,\n            loss_fn=loss_fn,\n            device=device)\n\n\n        print(\n            f\"Epoch: {epoch+1} | \"\n            f\"train_loss: {train_loss:.4f} | \"\n            f\"train_acc: {train_acc:.4f} | \"\n            f\"test_loss: {test_loss:.4f} | \"\n            f\"test_acc: {test_acc:.4f}\"\n        )\n        if (epoch + 1) % checkpoint_interval == 0:\n            torch.save({\n                'epoch': epoch,\n                'model_state_dict': model.state_dict(),\n                'optimizer_state_dict': optimizer.state_dict(),\n                'train_loss': train_loss,\n                'train_acc': train_acc,\n                'test_loss': test_loss,\n                'test_acc': test_acc\n            }, f'checkpoint_epoch_last.pth')\n\n        if train_acc > highest_train_accuracy:\n            highest_train_accuracy = train_acc\n\n\n        if test_acc > highest_test_accuracy:\n            highest_test_accuracy = test_acc\n            torch.save(model, 'arabic_letters_classifier.pth')\n            torch.save(model.state_dict(), \"arabic_letters_classifier_param.pth\")\n\n        pbar.update(1)\n\n\n        results[\"train_loss\"].append(train_loss)\n        results[\"train_acc\"].append(train_acc)\n        results[\"test_loss\"].append(test_loss)\n        results[\"test_acc\"].append(test_acc)\n    print(\n        f\"Highest Train Accuracy: {highest_train_accuracy:.4f} | \"\n        f\"Highest Test Accuracy: {highest_test_accuracy:.4f}\"\n        )\n\n    return results","metadata":{"execution":{"iopub.status.busy":"2023-12-22T21:09:13.822693Z","iopub.execute_input":"2023-12-22T21:09:13.823030Z","iopub.status.idle":"2023-12-22T21:09:13.852074Z","shell.execute_reply.started":"2023-12-22T21:09:13.823003Z","shell.execute_reply":"2023-12-22T21:09:13.851151Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from torchvision import  models\ndevice = \"cuda\" if torch.cuda.is_available() else \"cpu\"\n\nmodel = models.resnet50(pretrained=True).to(device)\n\nnum_classes = 65\nclassifier = nn.Sequential(\n    nn.Linear(2048, 512),\n    nn.ReLU(),\n    nn.Dropout(0.5),\n    nn.Linear(512, num_classes),  ).to(device)\nmodel.fc = classifier","metadata":{"execution":{"iopub.status.busy":"2023-12-22T21:09:24.405985Z","iopub.execute_input":"2023-12-22T21:09:24.406767Z","iopub.status.idle":"2023-12-22T21:09:25.486899Z","shell.execute_reply.started":"2023-12-22T21:09:24.406735Z","shell.execute_reply":"2023-12-22T21:09:25.486113Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"criterion = nn.CrossEntropyLoss()\noptimizer = torch.optim.SGD(model.parameters(), lr=0.001, momentum=0.9)\nNUM_EPOCHS = 10\nstart_epoch = 0\nprint(f\"Starting from epoch: {start_epoch}\")\nmodel_result= train(model=model,\n             train_dataloader=train_dataloader,\n             test_dataloader=val_dataloader,\n             loss_fn=criterion,\n             optimizer=optimizer,\n             starting_epochs= start_epoch,\n             epochs=NUM_EPOCHS,\n             device=device,\n             checkpoint_interval=5)","metadata":{"execution":{"iopub.status.busy":"2023-12-22T21:09:29.614509Z","iopub.execute_input":"2023-12-22T21:09:29.614841Z","iopub.status.idle":"2023-12-22T22:09:19.838186Z","shell.execute_reply.started":"2023-12-22T21:09:29.614816Z","shell.execute_reply":"2023-12-22T22:09:19.837009Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import csv","metadata":{"execution":{"iopub.status.busy":"2023-12-22T22:55:16.613209Z","iopub.execute_input":"2023-12-22T22:55:16.613611Z","iopub.status.idle":"2023-12-22T22:55:16.618144Z","shell.execute_reply.started":"2023-12-22T22:55:16.613582Z","shell.execute_reply":"2023-12-22T22:55:16.617236Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"test_directory = '/kaggle/input/arabic-letters-classification/Final_Arabic_Alpha_dataset/Final_Arabic_Alpha_dataset/test'\ncsv_file_path = 'predictions.csv'\n\nwith open(csv_file_path, 'w', newline='') as csvfile:\n    csv_writer = csv.writer(csvfile)\n\n    csv_writer.writerow(['ID', 'Label'])\n\n    for file_name in os.listdir(test_directory):\n        if file_name.endswith(\".jpg\") or file_name.endswith(\".png\"):\n            image_path = os.path.join(test_directory, file_name)\n            image = Image.open(image_path).convert('RGB')\n            img_tensor = test_transform(image).unsqueeze(0)\n            img_tensor = img_tensor.cuda()\n            with torch.no_grad():\n                output = model(img_tensor)\n\n                predicted_class = torch.argmax(torch.softmax(output, dim=1), dim=1)\n\n                csv_writer.writerow([file_name, predicted_class.item()])","metadata":{"execution":{"iopub.status.busy":"2023-12-22T23:05:28.151402Z","iopub.execute_input":"2023-12-22T23:05:28.151755Z","iopub.status.idle":"2023-12-22T23:07:54.199355Z","shell.execute_reply.started":"2023-12-22T23:05:28.151728Z","shell.execute_reply":"2023-12-22T23:07:54.198305Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import pandas as pd\ndf = pd.read_csv('/kaggle/working/predictions.csv')\ndf.head(10)","metadata":{"execution":{"iopub.status.busy":"2023-12-22T23:10:10.652521Z","iopub.execute_input":"2023-12-22T23:10:10.653196Z","iopub.status.idle":"2023-12-22T23:10:10.670854Z","shell.execute_reply.started":"2023-12-22T23:10:10.653166Z","shell.execute_reply":"2023-12-22T23:10:10.669703Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}