{"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":7170768,"sourceType":"datasetVersion","datasetId":4143074}],"dockerImageVersionId":30615,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"Notion Page for containing information on my model. The content will cover aspects such as the model's structure, layers, loss function, accuracy curve and loss curve. You can access the details through the following link: https://www.notion.so/mennahtullahmabrouk/NN-Arabic-Project-aebf1dce9cb74065b9af9465bf1cd194?pvs=4","metadata":{}},{"cell_type":"code","source":"import tensorflow as tf\nfrom tensorflow.keras import layers, models\nfrom tensorflow.keras.preprocessing.image import ImageDataGenerator\nimport plotly.subplots as sp\nimport plotly.graph_objects as go\nimport numpy as np","metadata":{"execution":{"iopub.status.busy":"2023-12-20T14:39:42.076617Z","iopub.execute_input":"2023-12-20T14:39:42.077017Z","iopub.status.idle":"2023-12-20T14:39:42.082079Z","shell.execute_reply.started":"2023-12-20T14:39:42.076985Z","shell.execute_reply":"2023-12-20T14:39:42.081242Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Set the path to your training data folder\ntrain_data_dir = '/kaggle/input/arabic-letters-classification/Final_Arabic_Alpha_dataset/Final_Arabic_Alpha_dataset/train'\n\n# Image dimensions and batch size\nimg_width, img_height = 64, 64\nbatch_size = 32\n\n# Create a data generator with data augmentation for training\ntrain_datagen = ImageDataGenerator(\n    rescale=1./255,\n    shear_range=0.2,\n    zoom_range=0.2,\n    horizontal_flip=True\n)\n\ntrain_generator = train_datagen.flow_from_directory(\n    train_data_dir,\n    target_size=(img_width, img_height),\n    batch_size=batch_size,\n    class_mode='categorical',\n    shuffle=False\n)\n\nlabels_dict = {class_name: label for label, class_name in train_generator.class_indices.items()}\nprint(labels_dict)","metadata":{"execution":{"iopub.status.busy":"2023-12-20T14:39:42.091802Z","iopub.execute_input":"2023-12-20T14:39:42.092146Z","iopub.status.idle":"2023-12-20T14:39:43.726764Z","shell.execute_reply.started":"2023-12-20T14:39:42.092122Z","shell.execute_reply":"2023-12-20T14:39:43.725839Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"num_images = 10\nnum_images_per_row = 5\nnum_rows = int(np.ceil(num_images / num_images_per_row))\nfig_images = sp.make_subplots(rows=num_rows, cols=num_images_per_row, subplot_titles=[f'Image {i+1}' for i in range(num_images)])\n\nfor i in range(num_images):\n    row_position = i // num_images_per_row + 1\n    col_position = i % num_images_per_row + 1\n\n    gray_image = np.dot(train_generator[i][0][0], [0.2989, 0.5870, 0.1140])\n    downsampled_image = gray_image[::-1, ::-1]\n    \n    fig_images.add_trace(\n        go.Heatmap(z=downsampled_image.T, colorscale='inferno', opacity=1, colorbar=dict(showticklabels=False)),\n        row=row_position,\n        col=col_position\n    )\n\nfig_images.update_layout(\n    title='Randomly Selected Images',\n    font=dict(color='white'),\n    paper_bgcolor='black',\n    plot_bgcolor='black',\n    showlegend=False,\n    width=1200,  \n    height=300 * num_rows,  \n)\n\nfig_images.show()","metadata":{"execution":{"iopub.status.busy":"2023-12-20T14:39:48.943025Z","iopub.execute_input":"2023-12-20T14:39:48.943778Z","iopub.status.idle":"2023-12-20T14:39:49.983867Z","shell.execute_reply.started":"2023-12-20T14:39:48.943744Z","shell.execute_reply":"2023-12-20T14:39:49.982868Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import os\nfrom torchvision import transforms, datasets\nfrom torch.utils.data import DataLoader\nimport matplotlib.pyplot as plt\nimport numpy as np\nimport plotly.graph_objects as go\nimport plotly.subplots as sp\n\ndef imshow(image, title=None):\n    plt.imshow(image)\n    plt.title(title)\n    plt.axis('off')\n    plt.show()\n\n# Set the path to your training data folder\ntrain_data_dir = '/kaggle/input/arabic-letters-classification/Final_Arabic_Alpha_dataset/Final_Arabic_Alpha_dataset/train'\n\n# Image dimensions and batch size\nimg_width, img_height = 64, 64\nbatch_size = 32\n\n# Define the transformation\ntransform = transforms.Compose([\n    transforms.Resize((img_height, img_width)),  \n    transforms.ToTensor(),\n])\n\n# Create the ImageFolder dataset\ndataset = datasets.ImageFolder(root=train_data_dir, transform=transform)\n\n# Create a DataLoader for batching and shuffling\ndataloader = DataLoader(dataset, batch_size=4, shuffle=True)\n\n# Display one batch of images and labels for demonstration purposes\nfor images, labels in dataloader:\n    num_images = len(images)\n    num_images_per_row = min(num_images, 5)\n    num_rows = int(np.ceil(num_images / num_images_per_row))\n    fig_images = sp.make_subplots(rows=num_rows, cols=num_images_per_row, subplot_titles=[f'Label: {dataset.classes[label]}' for label in labels])\n\n    for i in range(num_images):\n        row_position = i // num_images_per_row + 1\n        col_position = i % num_images_per_row + 1\n\n        gray_image = np.dot(images[i].numpy().transpose((1, 2, 0)), [0.2989, 0.5870, 0.1140])\n        downsampled_image = gray_image[::-1, ::-1]\n\n        fig_images.add_trace(\n            go.Heatmap(z=downsampled_image.T, colorscale='gray', showscale=False),\n            row=row_position,\n            col=col_position\n        )\n\n    fig_images.update_layout(\n        title='Randomly Selected Images',\n        font=dict(color='white'),\n        paper_bgcolor='black',\n        plot_bgcolor='black',\n        showlegend=False,\n        width=1200,\n        height=300 * num_rows,\n    )\n\n    fig_images.show()\n    break  \n","metadata":{"execution":{"iopub.status.busy":"2023-12-20T14:39:50.278903Z","iopub.execute_input":"2023-12-20T14:39:50.279525Z","iopub.status.idle":"2023-12-20T14:39:50.574952Z","shell.execute_reply.started":"2023-12-20T14:39:50.279494Z","shell.execute_reply":"2023-12-20T14:39:50.574121Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"\"\"\"\nimport torch\nimport torch.nn as nn\nimport torch.optim as optim\nfrom torchvision import transforms, datasets\nfrom torch.utils.data import DataLoader, random_split\nfrom tensorflow.keras.preprocessing.image import ImageDataGenerator\nimport torchvision.models as models\nfrom tqdm import tqdm\n\n\n# Define the number of classes\nnum_classes = 65\n\n# Define the model\nresnet50 = models.resnet50(pretrained=True)\nmodel = nn.Sequential(\n    nn.Conv2d(3, 64, kernel_size=(7, 7), stride=(2, 2), padding=(3, 3), bias=False),\n    nn.BatchNorm2d(64),\n    nn.ReLU(inplace=True),\n    nn.MaxPool2d(kernel_size=3, stride=2, padding=1),\n    resnet50.layer1,\n    resnet50.layer2,\n    resnet50.layer3,\n    resnet50.layer4,\n    nn.AdaptiveAvgPool2d((1, 1)),\n    nn.Flatten(),\n    nn.Linear(2048, num_classes)\n)\n\n# Move the entire model to GPU if available\nif torch.cuda.is_available():\n    model = model.cuda()\n\n# Define loss function and optimizer\ncriterion = nn.CrossEntropyLoss()\noptimizer = optim.SGD(model.parameters(), lr=0.001, momentum=0.9)\n\n# Assuming you have defined train_data_dir, img_width, img_height, batch_size\n# Create ImageDataGenerator for validation\nvalidation_datagen = ImageDataGenerator(rescale=1./255)  # You may need to adjust other parameters based on your requirements\n\n# Define the dataset and dataloader for training\ntrain_data_dir = '/kaggle/input/arabic-letters-classification/Final_Arabic_Alpha_dataset/Final_Arabic_Alpha_dataset/train'\nimg_width, img_height = 224, 224  # Adjust based on your image dimensions\nbatch_size = 32  # Adjust based on your preferences\n\nfull_dataset = datasets.ImageFolder(\n    root=train_data_dir,\n    transform=transforms.Compose([\n        transforms.Resize((img_width, img_height)),\n        transforms.ToTensor(),\n    ])\n)\n\n# Split the dataset into training and validation sets\nval_split = 0.2\nval_size = int(val_split * len(full_dataset))\ntrain_size = len(full_dataset) - val_size\n\ntrain_dataset, val_dataset = random_split(full_dataset, [train_size, val_size])\n\ntrain_dataloader = DataLoader(train_dataset, batch_size=batch_size, shuffle=True)\nval_dataloader = DataLoader(val_dataset, batch_size=batch_size, shuffle=False)\n\n# Validation loop\ndef validate(model, dataloader):\n    model.eval()\n    total_correct = 0\n    total_samples = 0\n\n    with torch.no_grad():\n        for inputs, labels in dataloader:\n            if torch.cuda.is_available():\n                inputs = inputs.cuda()\n                labels = labels.cuda()\n\n            model = model.to(inputs.device)\n\n            outputs = model(inputs)\n            _, predicted = torch.max(outputs.data, 1)\n            total_correct += (predicted == labels).sum().item()\n            total_samples += labels.size(0)\n\n    accuracy = total_correct / total_samples\n    return accuracy\n\nnum_epochs = 50\n\n# Training loop\nhistory = {'accuracy': [], 'loss': [], 'val_accuracy': [], 'val_loss': [], 'epoch': []}\n\nfor epoch in range(num_epochs):\n    history['epoch'].append(epoch + 1)  # Add the epoch information\n\n    # Training\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    # Create a tqdm progress bar\n    progress_bar = tqdm(enumerate(train_dataloader), total=total_batches, desc=f\"Epoch {epoch + 1}/{num_epochs}\")\n\n    for batch_idx, (inputs, labels) in progress_bar:\n        optimizer.zero_grad()\n\n        if torch.cuda.is_available():\n            inputs = inputs.cuda()\n            labels = labels.cuda()\n\n        model = model.to(inputs.device)\n\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        progress_bar.set_postfix({\"Loss\": loss.item(), \"Accuracy\": total_correct_train / total_train}, refresh=True)\n\n    train_accuracy = total_correct_train / total_train\n    avg_train_loss = running_loss / len(train_dataloader)\n\n    # Validation\n    val_accuracy = validate(model, val_dataloader)\n    val_loss = criterion(outputs, labels)\n\n    history['accuracy'].append(train_accuracy)\n    history['loss'].append(avg_train_loss)\n    history['val_accuracy'].append(val_accuracy)\n    history['val_loss'].append(val_loss.item())\n\n    print(f\"Epoch {epoch + 1}/{num_epochs} - Average Training Loss: {avg_train_loss:.4f} - Training Accuracy: {train_accuracy:.4f} - Validation Accuracy: {val_accuracy:.4f}\")\n\"\"\"","metadata":{"execution":{"iopub.status.busy":"2023-12-20T14:39:53.523485Z","iopub.execute_input":"2023-12-20T14:39:53.523869Z","iopub.status.idle":"2023-12-20T14:39:53.535596Z","shell.execute_reply.started":"2023-12-20T14:39:53.523838Z","shell.execute_reply":"2023-12-20T14:39:53.534541Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import torch\nimport torch.nn as nn\nimport torch.optim as optim\nfrom torchvision import transforms, datasets, models\nfrom torch.utils.data import DataLoader, random_split\nfrom tqdm import tqdm\n\n# Define the number of classes\nnum_classes = 65\n\n# Use the pre-trained ResNet-50 model\nresnet50 = models.resnet50(pretrained=True)\n\n# Modify the last fully connected layer for your specific number of classes\nresnet50.fc = nn.Linear(resnet50.fc.in_features, num_classes)\n\n# Move the entire model to GPU if available\nif torch.cuda.is_available():\n    resnet50 = resnet50.cuda()\n\n# Set the path to your training data folder\ntrain_data_dir = '/kaggle/input/arabic-letters-classification/Final_Arabic_Alpha_dataset/Final_Arabic_Alpha_dataset/train'\n\n# Image dimensions and batch size\nimg_width, img_height = 64, 64\nbatch_size = 60\n\n# Define the transformations, including data augmentation\ntransform = transforms.Compose([\n    transforms.RandomResizedCrop((img_height, img_width)),\n    transforms.RandomHorizontalFlip(),\n    transforms.RandomRotation(10),\n    transforms.ColorJitter(brightness=0.1, contrast=0.1, saturation=0.1, hue=0.1),\n    transforms.ToTensor(),\n])\n\n# Create the ImageFolder dataset with data augmentation\ndataset = datasets.ImageFolder(root=train_data_dir, transform=transform)\n\n# Split the dataset into training and validation sets\nval_split = 0.3\nval_size = int(val_split * len(dataset))\ntrain_size = len(dataset) - val_size\n\ntrain_dataset, val_dataset = random_split(dataset, [train_size, val_size])\n\n# Create a DataLoader for batching and shuffling\ntrain_dataloader = DataLoader(train_dataset, batch_size=batch_size, shuffle=True)\nval_dataloader = DataLoader(val_dataset, batch_size=batch_size, shuffle=False)\n\n\n# Define the optimizer\noptimizer = optim.SGD(resnet50.parameters(), lr=0.001, momentum=0.9)\n\n# Define the loss function\ncriterion = nn.CrossEntropyLoss()\n\n# Define the validate function\ndef validate(model, dataloader):\n    model.eval()\n    correct = 0\n    total = 0\n\n    with torch.no_grad():\n        for inputs, labels in dataloader:\n            if torch.cuda.is_available():\n                inputs = inputs.cuda()\n                labels = labels.cuda()\n\n            outputs = model(inputs)\n            _, predicted = torch.max(outputs.data, 1)\n            total += labels.size(0)\n            correct += (predicted == labels).sum().item()\n\n    model.train()\n    accuracy = correct / total\n    return accuracy\n\n# Training loop\nnum_epochs = 50\nhistory = {'accuracy': [], 'loss': [], 'val_accuracy': [], 'val_loss': [], 'epoch': []}\n\nfor epoch in range(num_epochs):\n    history['epoch'].append(epoch + 1)\n\n    # Training\n    resnet50.train()\n    running_loss = 0.0\n    total_correct_train = 0\n    total_train = 0\n    total_batches = len(train_dataloader)\n\n    progress_bar = tqdm(enumerate(train_dataloader), total=total_batches, desc=f\"Epoch {epoch + 1}/{num_epochs}\")\n\n    for batch_idx, (inputs, labels) in progress_bar:\n        optimizer.zero_grad()\n\n        if torch.cuda.is_available():\n            inputs = inputs.cuda()\n            labels = labels.cuda()\n\n        outputs = resnet50(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        progress_bar.set_postfix({\"Loss\": loss.item(), \"Accuracy\": total_correct_train / total_train}, refresh=True)\n\n    train_accuracy = total_correct_train / total_train\n    avg_train_loss = running_loss / len(train_dataloader)\n\n    # Validation\n    val_accuracy = validate(resnet50, val_dataloader)\n\n    val_loss = 0.0\n    for inputs, labels in val_dataloader:\n        if torch.cuda.is_available():\n            inputs = inputs.cuda()\n            labels = labels.cuda()\n\n        val_outputs = resnet50(inputs)\n        val_loss += criterion(val_outputs, labels).item()\n\n    val_loss /= len(val_dataloader)\n\n    history['accuracy'].append(train_accuracy)\n    history['loss'].append(avg_train_loss)\n    history['val_accuracy'].append(val_accuracy)\n    history['val_loss'].append(val_loss)\n\n    print(f\"Epoch {epoch + 1}/{num_epochs} - Average Training Loss: {avg_train_loss:.4f} - Training Accuracy: {train_accuracy:.4f} - Validation Accuracy: {val_accuracy:.4f}\")\n\n# Save the trained model\ntorch.save(resnet50.state_dict(), 'arabic_letters_model.pth')\n\n","metadata":{"execution":{"iopub.status.busy":"2023-12-20T16:42:13.238273Z","iopub.execute_input":"2023-12-20T16:42:13.238674Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import numpy as np\nimport plotly.graph_objects as go\nimport torch\nimport torch.nn as nn\nimport torchvision.models as models\n\ndevice = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\n\n# Assuming you have already modified resnet50\n# For example, by changing the number of classes to 65\nnum_classes = 65\nresnet50 = models.resnet50(pretrained=True)\nresnet50.fc = nn.Linear(resnet50.fc.in_features, num_classes)\n\ndef get_model_summary(model, input_tensor):\n    summary = []\n    for layer in model.children():\n        # Check if the layer is a convolutional layer\n        if isinstance(layer, nn.Conv2d):\n            # Create a dummy input with the correct size for convolutional layers\n            dummy_input = torch.zeros((1, 3, 224, 224)).to(device)\n        elif isinstance(layer, nn.Linear):\n            # Flatten the input for the linear layer\n            dummy_input = input_tensor.view(input_tensor.size(0), -1)\n        else:\n            # For other layers, use the provided input_tensor\n            dummy_input = input_tensor\n\n        try:\n            output = layer(dummy_input)\n        except Exception as e:\n            print(f\"Error in layer {layer.__class__.__name__}: {e}\")\n            output = None\n\n        if output is not None:\n            num_params = sum(p.numel() for p in layer.parameters())\n            output_shape = str(output.shape)\n            layer_type = str(layer.__class__.__name__)\n            summary.append((layer_type, output_shape, num_params))\n            input_tensor = output\n\n    return summary\n\n# Assuming modified input size\nmodified_input_size = resnet50.fc.in_features\ndummy_input = torch.zeros((1, modified_input_size)).to(device)\nmodel_summary = get_model_summary(resnet50.to(device), dummy_input)\n\ntable = go.Figure(data=[go.Table(\n    header=dict(values=['Layer (type)', 'Output Shape', 'Param #'],\n                fill_color='rgb(55, 55, 55)',\n                font=dict(color='white')),\n    cells=dict(values=[np.array(model_summary)[:, 0], np.array(model_summary)[:, 1], np.array(model_summary)[:, 2]],\n               fill_color='rgb(35, 35, 35)',\n               font=dict(color='white'))\n)])\n\nlayout = go.Layout(\n    title='Model Summary',\n    width=800,\n    height=400,\n    font=dict(color='white'),\n    paper_bgcolor='rgb(0, 0, 0)',\n    plot_bgcolor='rgb(0, 0, 0)'\n)\n\ntable.update_layout(layout)\ntable.show()\n","metadata":{"execution":{"iopub.status.busy":"2023-12-20T16:20:13.155578Z","iopub.execute_input":"2023-12-20T16:20:13.155876Z","iopub.status.idle":"2023-12-20T16:20:13.650249Z","shell.execute_reply.started":"2023-12-20T16:20:13.155849Z","shell.execute_reply":"2023-12-20T16:20:13.649298Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Plot training history\nfig = go.Figure()\nfig.add_trace(go.Scatter(y=history['accuracy'], mode='lines', name='Training Accuracy'))\nfig.add_trace(go.Scatter(y=history['loss'], mode='lines', name='Training Loss'))\nfig.add_trace(go.Scatter(y=history['val_accuracy'], mode='lines', name='Validation Accuracy'))\nfig.add_trace(go.Scatter(y=history['val_loss'], mode='lines', name='Validation Loss'))\nfig.update_layout(title='Training History', xaxis_title='Epoch', template='plotly_dark')\nfig.show()","metadata":{"execution":{"iopub.status.busy":"2023-12-20T16:20:13.651537Z","iopub.execute_input":"2023-12-20T16:20:13.652274Z","iopub.status.idle":"2023-12-20T16:20:13.690324Z","shell.execute_reply.started":"2023-12-20T16:20:13.652235Z","shell.execute_reply":"2023-12-20T16:20:13.689365Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import plotly.graph_objects as go\n\n# Plot training and validation accuracy separately\nfig = go.Figure()\nfig.add_trace(go.Scatter(x=history['epoch'], y=history['accuracy'], name='Training Accuracy'))\nfig.add_trace(go.Scatter(x=history['epoch'], y=history['val_accuracy'], name='Validation Accuracy'))\n\nfig.update_layout(\n    title='Training and Validation Accuracy',\n    xaxis_title='Epoch',\n    yaxis_title='Accuracy',\n    legend=dict(x=0.7, y=0.9),\n    width=800,\n    height=600,\n    plot_bgcolor='rgb(17,17,17)',\n    paper_bgcolor='rgb(17,17,17)',\n    font=dict(color='white')  \n)\n\nfig.show()\n","metadata":{"execution":{"iopub.status.busy":"2023-12-20T16:20:13.691587Z","iopub.execute_input":"2023-12-20T16:20:13.691890Z","iopub.status.idle":"2023-12-20T16:20:13.710733Z","shell.execute_reply.started":"2023-12-20T16:20:13.691867Z","shell.execute_reply":"2023-12-20T16:20:13.709772Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import os\nfrom torchvision import transforms, datasets\nfrom torch.utils.data import DataLoader\nimport torch.nn as nn\nimport torch.optim as optim\nfrom torchvision import transforms\nfrom torch.utils.data import DataLoader, Dataset\nfrom tqdm import tqdm\nfrom PIL import Image\nimport torch\nimport torchvision.models as models\n\nclass SingleLabelDataset(Dataset):\n    def __init__(self, data_folder, transform=None):\n        self.data_folder = data_folder\n        self.transform = transform\n        self.file_list = os.listdir(data_folder)\n\n    def __len__(self):\n        return len(self.file_list)\n\n    def __getitem__(self, idx):\n        img_name = os.path.join(self.data_folder, self.file_list[idx])\n        image = Image.open(img_name).convert(\"RGB\")\n\n        if self.transform:\n            image = self.transform(image)\n\n        # Assuming the label is derived from the filename or folder structure\n        filename_parts = self.file_list[idx].split(\"_\")\n        if len(filename_parts) >= 2:\n            label = int(filename_parts[1])\n        else:\n            # Handle the case where the filename doesn't have the expected structure\n            label = 0  # You can choose a default label or handle it differently\n\n        return image, label\n\n# Replace 'YourModel' with the actual name of your model class\nmodel = resnet50\n\n# Function for testing the model\ndef test(model, dataloader):\n    model.eval()\n    total_correct = 0\n    total_samples = 0\n\n    with torch.no_grad():\n        for inputs, labels in dataloader:\n            if torch.cuda.is_available():\n                inputs = inputs.cuda()\n                labels = labels.cuda()\n\n            # Move the model to the appropriate device (GPU or CPU)\n            model = model.to(inputs.device)\n\n            outputs = model(inputs)\n            _, predicted = torch.max(outputs.data, 1)\n            total_correct += (predicted == labels).sum().item()\n            total_samples += labels.size(0)\n\n    accuracy = total_correct / total_samples\n    return accuracy\n\n# Assuming you have defined the test data folder and image dimensions\ntest_data_folder = '/kaggle/input/arabic-letters-classification/Final_Arabic_Alpha_dataset/Final_Arabic_Alpha_dataset/test'\nimg_width, img_height = 64, 64  # Adjust based on your image dimensions used during training\nbatch_size = 32  # Adjust based on your preferences\n\n# Create the custom test dataset\ncustom_test_dataset = SingleLabelDataset(\n    data_folder=test_data_folder,\n    transform=transforms.Compose([\n        transforms.Resize((img_width, img_height)),\n        transforms.ToTensor(),\n    ])\n)\n\n# Create the custom test dataloader\ncustom_test_dataloader = DataLoader(custom_test_dataset, batch_size=batch_size, shuffle=False)\n\n# Test the model on the custom test dataset\ntest_accuracy = test(model, custom_test_dataloader)\nprint(f\"Test Accuracy: {test_accuracy:.4f}\")\n\n","metadata":{"execution":{"iopub.status.busy":"2023-12-20T16:20:13.713200Z","iopub.execute_input":"2023-12-20T16:20:13.713721Z","iopub.status.idle":"2023-12-20T16:20:46.720677Z","shell.execute_reply.started":"2023-12-20T16:20:13.713688Z","shell.execute_reply":"2023-12-20T16:20:46.719664Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import csv\nimport os\nimport torch\nfrom torchvision import transforms, datasets\nfrom torch.utils.data import DataLoader, Dataset\nfrom tqdm import tqdm\nfrom PIL import Image\nimport torch.nn.functional as F\nimport torchvision.models as models\n\ndef test_and_save_predictions(model, dataloader, csv_file_path):\n    model.eval()\n    predictions = []\n\n    with torch.no_grad():\n        for inputs, _ in tqdm(dataloader, desc=\"Generating Predictions\"):\n            if torch.cuda.is_available():\n                inputs = inputs.cuda()\n\n            model = model.to(inputs.device)\n\n            outputs = F.softmax(model(inputs), dim=1)\n            _, predicted_classes = torch.max(outputs, 1)\n\n            predictions.extend(predicted_classes.cpu().numpy())\n\n    # Create predictions.csv file\n    with open(csv_file_path, 'w', newline='') as csvfile:\n        csv_writer = csv.writer(csvfile)\n\n        csv_writer.writerow(['ID', 'Label'])\n\n        # Assuming the test dataset follows a specific naming convention (e.g., \"ID.jpg\")\n        file_ids = [int(filename.split('.')[0]) for filename in os.listdir('/kaggle/input/arabictest/test')]\n\n        for file_id, predicted_class in zip(file_ids, predictions):\n            csv_writer.writerow([file_id, predicted_class])\n\n    print(f\"Predictions saved to: {csv_file_path}\")\n\n# Assuming you have defined the test data folder and image dimensions\ntest_data_folder = '/kaggle/input/arabic-letters-classification/Final_Arabic_Alpha_dataset/Final_Arabic_Alpha_dataset/test'\nimg_width, img_height = 224, 224  # Adjust based on your image dimensions\nbatch_size = 32  # Adjust based on your preferences\n\n# Create the custom test dataset\ncustom_test_dataset = SingleLabelDataset(\n    data_folder=test_data_folder,\n    transform=transforms.Compose([\n        transforms.Resize((img_width, img_height)),\n        transforms.ToTensor(),\n    ])\n)\n\n# Create the custom test dataloader\ncustom_test_dataloader = DataLoader(custom_test_dataset, batch_size=batch_size, shuffle=False)\n\n# Specify the path for predictions.csv file\ncsv_file_path = 'predictions.csv'\n\n# Test the model on the custom test dataset and save predictions to CSV\ntest_and_save_predictions(model, custom_test_dataloader, csv_file_path)","metadata":{"execution":{"iopub.status.busy":"2023-12-20T16:20:46.721670Z","iopub.execute_input":"2023-12-20T16:20:46.721951Z","iopub.status.idle":"2023-12-20T16:21:41.207262Z","shell.execute_reply.started":"2023-12-20T16:20:46.721926Z","shell.execute_reply":"2023-12-20T16:21:41.206324Z"},"trusted":true},"execution_count":null,"outputs":[]}]}