{"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"}],"dockerImageVersionId":30587,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import os\nimport torch\nimport torch.nn.functional as F\nimport torch.nn as nn\nimport torch.optim as optim\nfrom torchvision import transforms\nfrom torchvision.models import resnet50\nfrom torch.utils.data import Dataset, DataLoader, random_split\nfrom PIL import Image\nimport csv\n\n%matplotlib inline\n%config InlineBackend.figure_format = 'retina'\nimport matplotlib.pyplot as plt","metadata":{"execution":{"iopub.status.busy":"2023-12-07T07:12:41.404653Z","iopub.execute_input":"2023-12-07T07:12:41.405001Z","iopub.status.idle":"2023-12-07T07:12:44.573696Z","shell.execute_reply.started":"2023-12-07T07:12:41.404971Z","shell.execute_reply":"2023-12-07T07:12:44.572836Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def nameToLabel(name):\n  return \"_\".join(name.replace('.', '_').split('_')[1:3])\n\ndef imshow(image, ax=None, title=None, normalize=True):\n    if ax is None:\n        fig, ax = plt.subplots()\n    image = image.numpy().transpose((1, 2, 0))\n\n    if normalize:\n        mean = np.array([0.485, 0.456, 0.406])\n        std = np.array([0.229, 0.224, 0.225])\n        image = std * image + mean\n        image = np.clip(image, 0, 1)\n\n    ax.imshow(image)\n    ax.spines['top'].set_visible(False)\n    ax.spines['right'].set_visible(False)\n    ax.spines['left'].set_visible(False)\n    ax.spines['bottom'].set_visible(False)\n    ax.set_title(title)\n    ax.tick_params(axis='both', length=0)\n    ax.set_xticklabels('')\n    ax.set_yticklabels('')\n\n    return ax","metadata":{"execution":{"iopub.status.busy":"2023-12-07T07:12:44.575180Z","iopub.execute_input":"2023-12-07T07:12:44.575581Z","iopub.status.idle":"2023-12-07T07:12:44.585029Z","shell.execute_reply.started":"2023-12-07T07:12:44.575554Z","shell.execute_reply":"2023-12-07T07:12:44.584068Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"base_folder = \"/kaggle/input/arabic-letters-classification/Final_Arabic_Alpha_dataset/Final_Arabic_Alpha_dataset/train/\"\nlabels_dict = {}\n\nfor category in sorted(os.listdir(base_folder), key=lambda x: int(x)):\n    for picture in os.listdir(base_folder + category):\n      labels_dict[category] = nameToLabel(picture)\n      break\nlabels_dict","metadata":{"execution":{"iopub.status.busy":"2023-12-07T07:12:44.586359Z","iopub.execute_input":"2023-12-07T07:12:44.586867Z","iopub.status.idle":"2023-12-07T07:12:58.820752Z","shell.execute_reply.started":"2023-12-07T07:12:44.586821Z","shell.execute_reply":"2023-12-07T07:12:58.819797Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class CustomDataset(Dataset):\n    def __init__(self, root_folder, transform=None):\n        self.root_folder = root_folder\n        self.transform = transform\n        self.classes = sorted(os.listdir(root_folder), key=lambda x: int(x))\n        self.class_to_idx = {cls: i for i, cls in enumerate(self.classes)}\n        self.images = self.make_dataset()\n\n    def make_dataset(self):\n        images = []\n        for label in self.classes:\n            label_folder = os.path.join(self.root_folder, label)\n            for image_name in os.listdir(label_folder):\n                image_path = os.path.join(label_folder, image_name)\n                item = (image_path, self.class_to_idx[label])\n                images.append(item)\n        return images\n\n    def __len__(self):\n        return len(self.images)\n\n    def __getitem__(self, index):\n        image_path, label = self.images[index]\n        image = Image.open(image_path).convert(\"RGB\")\n\n        if self.transform:\n            image = self.transform(image)\n\n        return image, label","metadata":{"execution":{"iopub.status.busy":"2023-12-07T07:12:58.823348Z","iopub.execute_input":"2023-12-07T07:12:58.823718Z","iopub.status.idle":"2023-12-07T07:12:58.833053Z","shell.execute_reply.started":"2023-12-07T07:12:58.823683Z","shell.execute_reply":"2023-12-07T07:12:58.832020Z"},"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()\n\nclass Dilate(object):\n    def __init__(self, radius=3):\n        self.radius = radius\n\n    def __call__(self, img):\n        kernel = torch.ones(1, 1, self.radius * 2 + 1, self.radius * 2 + 1).to(img.device)\n        return F.conv2d(img.unsqueeze(0), kernel, padding=self.radius).squeeze(0)\n","metadata":{"execution":{"iopub.status.busy":"2023-12-07T07:12:58.834407Z","iopub.execute_input":"2023-12-07T07:12:58.834760Z","iopub.status.idle":"2023-12-07T07:12:58.844583Z","shell.execute_reply.started":"2023-12-07T07:12:58.834727Z","shell.execute_reply":"2023-12-07T07:12:58.843694Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"transform = transforms.Compose([\n    transforms.Resize((100, 100)),\n    transforms.Grayscale(num_output_channels=1),\n    transforms.ToTensor(),\n    Threshold(threshold=0.9),\n    Dilate(radius=1),\n])\n\ndataset = CustomDataset(base_folder, transform=transform)\n\ntrain_size = int(0.8 * len(dataset))\nval_size = int(0.1 * len(dataset))\ntest_size = len(dataset) - train_size - val_size\ntrain_dataset, val_dataset, test_dataset = random_split(dataset, [train_size, val_size, test_size])","metadata":{"execution":{"iopub.status.busy":"2023-12-07T07:12:58.845836Z","iopub.execute_input":"2023-12-07T07:12:58.846435Z","iopub.status.idle":"2023-12-07T07:12:59.034546Z","shell.execute_reply.started":"2023-12-07T07:12:58.846404Z","shell.execute_reply":"2023-12-07T07:12:59.033649Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"batch_size = 512\ntrain_dataloader = DataLoader(train_dataset, batch_size=batch_size, shuffle=True)\nval_dataloader = DataLoader(val_dataset, batch_size=batch_size, shuffle=False)\ntest_dataloader = DataLoader(test_dataset, batch_size=batch_size, shuffle=False)","metadata":{"execution":{"iopub.status.busy":"2023-12-07T07:12:59.035839Z","iopub.execute_input":"2023-12-07T07:12:59.036335Z","iopub.status.idle":"2023-12-07T07:12:59.041182Z","shell.execute_reply.started":"2023-12-07T07:12:59.036306Z","shell.execute_reply":"2023-12-07T07:12:59.040432Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"for batch_idx, (images, labels) in enumerate(train_dataloader):\n    if batch_idx == 0:\n        for i in range(min(2, batch_size)):\n            imshow(images[i], title=labels_dict[str(labels[i].item())], normalize=False)\n            print(f\"Label: {labels[i]}\")\n            print(images[i].shape)\n        break","metadata":{"execution":{"iopub.status.busy":"2023-12-07T07:12:59.042416Z","iopub.execute_input":"2023-12-07T07:12:59.042743Z","iopub.status.idle":"2023-12-07T07:13:03.375119Z","shell.execute_reply.started":"2023-12-07T07:12:59.042717Z","shell.execute_reply":"2023-12-07T07:13:03.374157Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"for batch_idx, (images, labels) in enumerate(test_dataloader):\n    if batch_idx == 0:\n        for i in range(min(2, batch_size)):\n            imshow(images[i], title=labels_dict[str(labels[i].item())], normalize=False)\n            print(f\"Label: {labels[i]}\")\n            print(images[i].shape)\n        break","metadata":{"execution":{"iopub.status.busy":"2023-12-07T07:13:03.376468Z","iopub.execute_input":"2023-12-07T07:13:03.376790Z","iopub.status.idle":"2023-12-07T07:13:07.312330Z","shell.execute_reply.started":"2023-12-07T07:13:03.376761Z","shell.execute_reply":"2023-12-07T07:13:07.311405Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"for batch_idx, (images, labels) in enumerate(val_dataloader):\n    if batch_idx == 0:\n        for i in range(min(2, batch_size)):\n            imshow(images[i], title=labels_dict[str(labels[i].item())], normalize=False)\n            print(f\"Label: {labels[i]}\")\n            print(images[i].shape)\n        break","metadata":{"execution":{"iopub.status.busy":"2023-12-07T07:13:07.315117Z","iopub.execute_input":"2023-12-07T07:13:07.315421Z","iopub.status.idle":"2023-12-07T07:13:11.421149Z","shell.execute_reply.started":"2023-12-07T07:13:07.315394Z","shell.execute_reply":"2023-12-07T07:13:11.420163Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model = resnet50(pretrained=True)\nnum_classes = len(dataset.classes)\nmodel.fc = nn.Linear(model.fc.in_features, num_classes)\nmodel.conv1 = nn.Conv2d(1, 64, kernel_size=(7, 7), stride=(2, 2), padding=(3, 3), bias=False)\nif(torch.cuda.is_available()):\n    model = model.cuda()\ncriterion = nn.CrossEntropyLoss()\noptimizer = optim.SGD(model.parameters(), lr=0.001, momentum=0.9)\nprint_interval = 10\nnum_epochs = 50","metadata":{"execution":{"iopub.status.busy":"2023-12-07T07:13:11.422567Z","iopub.execute_input":"2023-12-07T07:13:11.423242Z","iopub.status.idle":"2023-12-07T07:13:15.200900Z","shell.execute_reply.started":"2023-12-07T07:13:11.423202Z","shell.execute_reply":"2023-12-07T07:13:15.200070Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"for epoch in range(num_epochs):\n    model.train()\n    running_loss = 0.0\n    total_correct_train = 0\n    total_train = 0\n    total_batches = len(train_dataloader)\n\n    for batch_idx, (inputs, labels) in enumerate(train_dataloader):\n        if torch.cuda.is_available():\n            inputs = inputs.cuda()\n            labels = labels.cuda()\n\n        optimizer.zero_grad()\n        outputs = model(inputs)\n        loss = criterion(outputs, labels)\n        loss.backward()\n        optimizer.step()\n        torch.cuda.empty_cache()\n        running_loss += loss.item()\n\n        _, predicted_train = torch.max(outputs.data, 1)\n        total_correct_train += (predicted_train == labels).sum().item()\n        total_train += labels.size(0)\n\n        if (batch_idx + 1) % print_interval == 0 or (batch_idx + 1) == total_batches:\n            print(f\"Epoch {epoch + 1}/{num_epochs}, Batch {batch_idx + 1}/{total_batches}, Loss: {loss.item()}\")\n\n    train_accuracy = total_correct_train / total_train\n\n    model.eval()\n    val_loss = 0.0\n    correct = 0\n    total = 0\n\n    with torch.no_grad():\n        for batch_idx, (val_inputs, val_labels) in enumerate(val_dataloader):\n            if torch.cuda.is_available():\n                val_inputs = val_inputs.cuda()\n                val_labels = val_labels.cuda()\n\n            val_outputs = model(val_inputs)\n            val_loss += criterion(val_outputs, val_labels).item()\n\n            _, predicted = torch.max(val_outputs.data, 1)\n            total += val_labels.size(0)\n            correct += (predicted == val_labels).sum().item()\n            torch.cuda.empty_cache()\n\n            if (batch_idx + 1) % print_interval == 0 or (batch_idx + 1) == len(val_dataloader):\n                avg_val_loss = val_loss / (batch_idx + 1)\n                val_accuracy = correct / total\n                print(f\"Validation Batch {batch_idx + 1}/{len(val_dataloader)}, Validation Loss: {avg_val_loss}, Validation Accuracy: {val_accuracy}\")\n\n    avg_train_loss = running_loss / len(train_dataloader)\n    avg_val_loss = val_loss / len(val_dataloader)\n    val_accuracy = correct / total\n\n    print(f\"Epoch {epoch + 1}/{num_epochs}, Average Training Loss: {avg_train_loss}, Average Validation Loss: {avg_val_loss}, Training Accuracy: {train_accuracy}, Validation Accuracy: {val_accuracy}\")\n","metadata":{"execution":{"iopub.status.busy":"2023-12-07T07:13:15.202077Z","iopub.execute_input":"2023-12-07T07:13:15.202374Z","iopub.status.idle":"2023-12-07T09:30:35.999793Z","shell.execute_reply.started":"2023-12-07T07:13:15.202348Z","shell.execute_reply":"2023-12-07T09:30:35.998753Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model.eval()\ncorrect = 0\ntotal = 0\nwith torch.no_grad():\n    for test_inputs, test_labels in test_dataloader:\n        if torch.cuda.is_available():\n            test_inputs = test_inputs.cuda()\n            test_labels = test_labels.cuda()\n        test_outputs = model(test_inputs)\n        _, predicted = torch.max(test_outputs.data, 1)\n        total += test_labels.size(0)\n        correct += (predicted == test_labels).sum().item()\n\ntest_accuracy = correct / total\nprint(f\"Test Accuracy: {test_accuracy}\")","metadata":{"execution":{"iopub.status.busy":"2023-12-07T09:30:36.001048Z","iopub.execute_input":"2023-12-07T09:30:36.001348Z","iopub.status.idle":"2023-12-07T09:31:09.548839Z","shell.execute_reply.started":"2023-12-07T09:30:36.001318Z","shell.execute_reply":"2023-12-07T09:31:09.547885Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"save_path = 'trained_model.pth'\ntorch.save(model.state_dict(), save_path)\nprint(f\"Model saved at: {save_path}\")","metadata":{"execution":{"iopub.status.busy":"2023-12-07T09:31:09.550088Z","iopub.execute_input":"2023-12-07T09:31:09.550404Z","iopub.status.idle":"2023-12-07T09:31:09.702066Z","shell.execute_reply.started":"2023-12-07T09:31:09.550376Z","shell.execute_reply":"2023-12-07T09:31:09.701131Z"},"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 filename in sorted(os.listdir(test_directory), key=lambda x: int(x.split('.')[0])):\n        if filename.endswith(\".jpg\") or filename.endswith(\".png\"):\n            image_path = os.path.join(test_directory, filename)\n\n            input_image = Image.open(image_path).convert('L')\n            input_tensor = transform(input_image).unsqueeze(0)\n            input_tensor = input_tensor.cuda()\n            \n\n            with torch.no_grad():\n                output = model(input_tensor)\n\n            _, predicted_class = torch.max(output, 1)\n\n            csv_writer.writerow([int(filename.split('.')[0]), predicted_class.item()])\n\nprint(f\"Predictions saved to: {csv_file_path}\")","metadata":{"execution":{"iopub.status.busy":"2023-12-07T09:31:28.096266Z","iopub.execute_input":"2023-12-07T09:31:28.096657Z","iopub.status.idle":"2023-12-07T09:34:23.702957Z","shell.execute_reply.started":"2023-12-07T09:31:28.096627Z","shell.execute_reply":"2023-12-07T09:34:23.701722Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}