{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.10.14","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"none","dataSources":[],"dockerImageVersionId":30786,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"# This Python 3 environment comes with many helpful analytics libraries installed\n# It is defined by the kaggle/python Docker image: https://github.com/kaggle/docker-python\n# For example, here's several helpful packages to load\n\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\n\n# Input data files are available in the read-only \"../input/\" directory\n# For example, running this (by clicking run or pressing Shift+Enter) will list all files under the input directory\n\nimport os\nfor dirname, _, filenames in os.walk('/kaggle/input'):\n    for filename in filenames:\n        print(os.path.join(dirname, filename))\n\n# You can write up to 20GB to the current directory (/kaggle/working/) that gets preserved as output when you create a version using \"Save & Run All\" \n# You can also write temporary files to /kaggle/temp/, but they won't be saved outside of the current session","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2024-11-05T14:04:13.415049Z","iopub.execute_input":"2024-11-05T14:04:13.415779Z","iopub.status.idle":"2024-11-05T14:04:14.660402Z","shell.execute_reply.started":"2024-11-05T14:04:13.415710Z","shell.execute_reply":"2024-11-05T14:04:14.658902Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Let's import necessary packages\n\nimport torch\nfrom torchvision.datasets import MNIST\nimport matplotlib.pyplot as plt\nimport torchvision.transforms as transforms\nfrom torchvision.transforms import ToTensor\nfrom torch.nn.functional import one_hot","metadata":{"execution":{"iopub.status.busy":"2024-11-05T14:04:14.663023Z","iopub.execute_input":"2024-11-05T14:04:14.664662Z","iopub.status.idle":"2024-11-05T14:04:19.964031Z","shell.execute_reply.started":"2024-11-05T14:04:14.664611Z","shell.execute_reply":"2024-11-05T14:04:19.960783Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"torch.__version__","metadata":{"execution":{"iopub.status.busy":"2024-11-05T14:04:19.965962Z","iopub.execute_input":"2024-11-05T14:04:19.967044Z","iopub.status.idle":"2024-11-05T14:04:19.978013Z","shell.execute_reply.started":"2024-11-05T14:04:19.966988Z","shell.execute_reply":"2024-11-05T14:04:19.975785Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Let's get the MNIST dataset ","metadata":{"execution":{"iopub.status.busy":"2024-11-05T14:04:19.980624Z","iopub.execute_input":"2024-11-05T14:04:19.981075Z","iopub.status.idle":"2024-11-05T14:04:19.998744Z","shell.execute_reply.started":"2024-11-05T14:04:19.981032Z","shell.execute_reply":"2024-11-05T14:04:19.996837Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"\ntrain_data = MNIST(root=\"/kaggle/working/mnist-data\", train=True, download=True)\ntest_data = MNIST(root='/kaggle/working/mnist-data', train=False, download=True)\n\n\nprint(\"Training set size:\", len(train_data))\nprint(\"Test set size:\", len(test_data))","metadata":{"execution":{"iopub.status.busy":"2024-11-05T14:04:20.004892Z","iopub.execute_input":"2024-11-05T14:04:20.005788Z","iopub.status.idle":"2024-11-05T14:04:33.422951Z","shell.execute_reply.started":"2024-11-05T14:04:20.005729Z","shell.execute_reply":"2024-11-05T14:04:33.421650Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Let's check the type of the images in the dataset\n\ntype(train_data[0])","metadata":{"execution":{"iopub.status.busy":"2024-11-05T14:04:33.424390Z","iopub.execute_input":"2024-11-05T14:04:33.424769Z","iopub.status.idle":"2024-11-05T14:04:33.445870Z","shell.execute_reply.started":"2024-11-05T14:04:33.424729Z","shell.execute_reply":"2024-11-05T14:04:33.444647Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# So, the image and the target is stored in a tuple, Let's check the type of the image and the target\ntype(train_data[0][0]), type(train_data[0][1]) ","metadata":{"execution":{"iopub.status.busy":"2024-11-05T14:04:33.447496Z","iopub.execute_input":"2024-11-05T14:04:33.447998Z","iopub.status.idle":"2024-11-05T14:04:33.456837Z","shell.execute_reply.started":"2024-11-05T14:04:33.447954Z","shell.execute_reply":"2024-11-05T14:04:33.455436Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# OK, great let's look at some images in the dataset and their labels\n\nfor i in np.random.randint(0, 60000, 3):\n    image, label = train_data[i]\n\n    plt.imshow(image, cmap='gray')\n    plt.title(f'Label: {label}')\n    plt.axis('off')\n    plt.show()","metadata":{"execution":{"iopub.status.busy":"2024-11-05T14:04:33.458528Z","iopub.execute_input":"2024-11-05T14:04:33.459010Z","iopub.status.idle":"2024-11-05T14:04:33.964329Z","shell.execute_reply.started":"2024-11-05T14:04:33.458956Z","shell.execute_reply":"2024-11-05T14:04:33.963038Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Let's define a transform to convert images to tensors and normalize pixel values to [0, 1]\ntransform = transforms.Compose([\n    transforms.ToTensor()\n])","metadata":{"execution":{"iopub.status.busy":"2024-11-05T14:04:33.965778Z","iopub.execute_input":"2024-11-05T14:04:33.966249Z","iopub.status.idle":"2024-11-05T14:04:33.972720Z","shell.execute_reply.started":"2024-11-05T14:04:33.966199Z","shell.execute_reply":"2024-11-05T14:04:33.971315Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train_data = MNIST(root='/kaggle/working/mnist-data', train=True, transform=ToTensor(), download=False)\ntest_data = MNIST(root='/kaggle/working/mnist-data', train=False, transform=ToTensor(), download=False)","metadata":{"execution":{"iopub.status.busy":"2024-11-05T14:04:33.974462Z","iopub.execute_input":"2024-11-05T14:04:33.975051Z","iopub.status.idle":"2024-11-05T14:04:34.087687Z","shell.execute_reply.started":"2024-11-05T14:04:33.974999Z","shell.execute_reply":"2024-11-05T14:04:34.086721Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Now let's have a look at the the data\ntrain_data[0][0]","metadata":{"execution":{"iopub.status.busy":"2024-11-05T14:04:34.089196Z","iopub.execute_input":"2024-11-05T14:04:34.089670Z","iopub.status.idle":"2024-11-05T14:04:34.150857Z","shell.execute_reply.started":"2024-11-05T14:04:34.089621Z","shell.execute_reply":"2024-11-05T14:04:34.149555Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Great, this is a tensor, let's check it shape\ntrain_data[0][0].shape","metadata":{"execution":{"iopub.status.busy":"2024-11-05T14:04:34.152771Z","iopub.execute_input":"2024-11-05T14:04:34.153277Z","iopub.status.idle":"2024-11-05T14:04:34.163402Z","shell.execute_reply.started":"2024-11-05T14:04:34.153222Z","shell.execute_reply":"2024-11-05T14:04:34.161998Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Let's seperate the cross validation set aside\n\nfrom torch.utils.data import random_split\n\n\ncv_size = int(0.5 * len(test_data))  # 50% for CV\ntest_size = len(test_data) - cv_size  # Remaining 50% for Test\n\ncv_data, test_data = random_split(test_data, [cv_size, test_size])","metadata":{"execution":{"iopub.status.busy":"2024-11-05T14:04:34.164928Z","iopub.execute_input":"2024-11-05T14:04:34.165349Z","iopub.status.idle":"2024-11-05T14:04:34.182092Z","shell.execute_reply.started":"2024-11-05T14:04:34.165307Z","shell.execute_reply":"2024-11-05T14:04:34.180838Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### Now let's seperate the training instance and the target from the tuple and create a 2d tensor of shape (number of instances, 1\\*28\\*28) containing all the instances and a 2d tensor of shape (number of instances, number of classes) containing one hot encoded version of all the targets for both train and the test set.","metadata":{}},{"cell_type":"code","source":"def transform_shape(data_set):\n    \n    data_examples = torch.zeros(size=(len(data_set), 1*28*28))\n    targets = torch.zeros(size=(len(data_set), 1))\n    \n    for i,instance in enumerate(data_set):\n        data_examples[i] = instance[0].reshape(1*28*28) \n        targets[i] = instance[1]\n        \n    targets = one_hot(targets.long(), 10).squeeze()\n        \n    return data_examples, targets\n    ","metadata":{"execution":{"iopub.status.busy":"2024-11-05T14:04:34.187584Z","iopub.execute_input":"2024-11-05T14:04:34.187977Z","iopub.status.idle":"2024-11-05T14:04:34.195608Z","shell.execute_reply.started":"2024-11-05T14:04:34.187939Z","shell.execute_reply":"2024-11-05T14:04:34.194210Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"new_train_x, new_train_y = transform_shape(train_data)\nnew_test_x, new_test_y = transform_shape(test_data)\nnew_cv_x, new_cv_y = transform_shape(cv_data)","metadata":{"execution":{"iopub.status.busy":"2024-11-05T14:04:34.197113Z","iopub.execute_input":"2024-11-05T14:04:34.197627Z","iopub.status.idle":"2024-11-05T14:04:43.439338Z","shell.execute_reply.started":"2024-11-05T14:04:34.197567Z","shell.execute_reply":"2024-11-05T14:04:43.438061Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Let's check thier shape\nnew_train_x.shape, new_train_y.shape, new_test_x.shape, new_test_y.shape, new_cv_x.shape, new_cv_y.shape","metadata":{"execution":{"iopub.status.busy":"2024-11-05T14:04:43.440783Z","iopub.execute_input":"2024-11-05T14:04:43.441207Z","iopub.status.idle":"2024-11-05T14:04:43.449073Z","shell.execute_reply.started":"2024-11-05T14:04:43.441137Z","shell.execute_reply":"2024-11-05T14:04:43.447698Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Great, the data transformation was successful and the shapes look good, let's check one instance and its target\n\nnew_train_x[0]","metadata":{"execution":{"iopub.status.busy":"2024-11-05T14:04:43.451033Z","iopub.execute_input":"2024-11-05T14:04:43.451523Z","iopub.status.idle":"2024-11-05T14:04:43.463868Z","shell.execute_reply.started":"2024-11-05T14:04:43.451483Z","shell.execute_reply":"2024-11-05T14:04:43.462619Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"new_train_y[0]","metadata":{"execution":{"iopub.status.busy":"2024-11-05T14:04:43.465903Z","iopub.execute_input":"2024-11-05T14:04:43.466431Z","iopub.status.idle":"2024-11-05T14:04:43.475833Z","shell.execute_reply.started":"2024-11-05T14:04:43.466372Z","shell.execute_reply":"2024-11-05T14:04:43.474267Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# The data is ready, let's build a Neural Network 😊","metadata":{}},{"cell_type":"code","source":"# Let's import some other necessary modules\nfrom torch import nn\nfrom torch.nn import Sequential\nfrom torch.optim import Adam\nfrom torch.optim.lr_scheduler import LambdaLR","metadata":{"execution":{"iopub.status.busy":"2024-11-05T14:04:43.477569Z","iopub.execute_input":"2024-11-05T14:04:43.477971Z","iopub.status.idle":"2024-11-05T14:04:43.484711Z","shell.execute_reply.started":"2024-11-05T14:04:43.477931Z","shell.execute_reply":"2024-11-05T14:04:43.483257Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Make device agnostic code\ndevice = \"cuda\" if torch.cuda.is_available() else \"cpu\"\ndevice","metadata":{"execution":{"iopub.status.busy":"2024-11-05T14:04:43.488775Z","iopub.execute_input":"2024-11-05T14:04:43.489874Z","iopub.status.idle":"2024-11-05T14:04:43.499719Z","shell.execute_reply.started":"2024-11-05T14:04:43.489825Z","shell.execute_reply":"2024-11-05T14:04:43.498450Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"my_model = Sequential(\n    nn.Linear(new_train_x[0].shape[0],256),\n    nn.ReLU(),\n    nn.Linear(256,128),\n    nn.ReLU(),\n    nn.Linear(128,64),\n    nn.ReLU(),\n    nn.Linear(64,10),\n    nn.Softmax(dim=1)\n)","metadata":{"execution":{"iopub.status.busy":"2024-11-05T14:04:43.501130Z","iopub.execute_input":"2024-11-05T14:04:43.501676Z","iopub.status.idle":"2024-11-05T14:04:43.517213Z","shell.execute_reply.started":"2024-11-05T14:04:43.501565Z","shell.execute_reply":"2024-11-05T14:04:43.515980Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Let's looka at parameters of our model\n\nfor name, param in my_model.named_parameters():\n    print(f\"Parameter Name: {name}\")\n    print(f\"Shape: {param.shape}\")\n    print(param)\n    print(\"-\" * 50)","metadata":{"execution":{"iopub.status.busy":"2024-11-05T14:04:43.518679Z","iopub.execute_input":"2024-11-05T14:04:43.519079Z","iopub.status.idle":"2024-11-05T14:04:43.554192Z","shell.execute_reply.started":"2024-11-05T14:04:43.519039Z","shell.execute_reply":"2024-11-05T14:04:43.552375Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Now we've got a model, let's see what happens when we pass some data through it.\n\nuntrained_preds = my_model(new_cv_x.to(device))\nprint(f\"Length of predictions: {len(untrained_preds)}, Shape: {untrained_preds.shape}\")\nprint(f\"Length of test samples: {len(new_cv_y)}, Shape: {new_cv_y.shape}\")\nprint(f\"\\nFirst 10 predictions:\\n{untrained_preds[:10]}\")\nprint(f\"\\nFirst 10 test labels:\\n{new_cv_y[:10]}\")","metadata":{"execution":{"iopub.status.busy":"2024-11-05T14:04:43.555810Z","iopub.execute_input":"2024-11-05T14:04:43.556254Z","iopub.status.idle":"2024-11-05T14:04:43.627554Z","shell.execute_reply.started":"2024-11-05T14:04:43.556197Z","shell.execute_reply":"2024-11-05T14:04:43.626054Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Let's round the predictions and see again \n\nuntrained_preds = my_model(new_cv_x.to(device))\nprint(f\"Length of predictions: {len(untrained_preds)}, Shape: {untrained_preds.shape}\")\nprint(f\"Length of test samples: {len(new_cv_y)}, Shape: {new_cv_y.shape}\")\nprint(f\"\\nFirst 10 predictions:\\n{torch.round(untrained_preds[:10])}\")\nprint(f\"\\nFirst 10 test labels:\\n{new_cv_y[:10]}\")","metadata":{"execution":{"iopub.status.busy":"2024-11-05T14:04:43.629147Z","iopub.execute_input":"2024-11-05T14:04:43.629588Z","iopub.status.idle":"2024-11-05T14:04:43.681690Z","shell.execute_reply.started":"2024-11-05T14:04:43.629544Z","shell.execute_reply":"2024-11-05T14:04:43.679360Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Let's setup loss function and optimizer\n\n# We will use the crossentropyloss since we are performing softmax regression\n# And we will use the adams optimizer.\n\nloss = nn.CrossEntropyLoss()\noptimizer = Adam(params = my_model.parameters(), lr = 0.01)","metadata":{"execution":{"iopub.status.busy":"2024-11-05T14:04:43.683344Z","iopub.execute_input":"2024-11-05T14:04:43.683876Z","iopub.status.idle":"2024-11-05T14:04:43.692407Z","shell.execute_reply.started":"2024-11-05T14:04:43.683822Z","shell.execute_reply":"2024-11-05T14:04:43.690275Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Calculate accuracy (a classification metric)\ndef accuracy_fn(y_true, y_pred):\n    correct = torch.all(y_true == y_pred, dim=1).sum().item() # torch.eq() calculates where two tensors are equal\n    acc = (correct / len(y_pred)) * 100 \n    return acc","metadata":{"execution":{"iopub.status.busy":"2024-11-05T14:04:43.694782Z","iopub.execute_input":"2024-11-05T14:04:43.695253Z","iopub.status.idle":"2024-11-05T14:04:43.706995Z","shell.execute_reply.started":"2024-11-05T14:04:43.695202Z","shell.execute_reply":"2024-11-05T14:04:43.705017Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def train_model(model, epoch_nums, optimizer, loss, new_train_x, new_train_y, new_cv_x, new_cv_y):\n\n\n    # Set the number of epochs\n    epochs = epoch_nums\n\n    # Put data to target device\n    new_train_x, new_train_y = new_train_x.to(device), (new_train_y.type(torch.float)).to(device)\n    new_cv_x, new_cv_y = new_cv_x.to(device), (new_cv_y.type(torch.float)).to(device)\n\n    # Build training and evaluation loop\n    for epoch in range(epochs):\n        ### Training\n        my_model.train()\n\n        # 1. Forward pass (model outputs raw logits)\n        y_logits = my_model(new_train_x).squeeze() # squeeze to remove extra `1` dimensions, this won't work unless model and data are on same device \n        y_pred = torch.round(y_logits) # turn logits -> pred probs -> pred labls\n\n        # 2. Calculate loss/accuracy\n        # loss = loss_fn(torch.sigmoid(y_logits), # Using nn.BCELoss you need torch.sigmoid()\n        #                y_train) \n        train_loss = loss(y_logits, # Using nn.BCEWithLogitsLoss works with raw logits\n                       new_train_y) \n        acc = accuracy_fn(y_true=new_train_y, \n                          y_pred=y_pred) \n\n        # 3. Optimizer zero grad\n        optimizer.zero_grad()\n\n        # 4. Loss backwards\n        train_loss.backward()\n\n        # 5. Optimizer step\n        optimizer.step()\n\n        ### Testing\n        my_model.eval()\n        with torch.inference_mode():\n            # 1. Forward pass\n            cv_logits = my_model(new_cv_x).squeeze() \n            cv_pred = torch.round(cv_logits)\n            # 2. Caculate loss/accuracy\n            cv_loss = loss(cv_logits,\n                                new_cv_y)\n            cv_acc = accuracy_fn(y_true=new_cv_y,\n                                   y_pred=cv_pred)\n\n        # Print out what's happening every 10 epochs\n        if epoch % 100 == 0:\n            print(f\"Epoch: {epoch} | Loss: {train_loss:.5f}, Accuracy: {acc:.2f}% | CV loss: {cv_loss:.5f}, CV acc: {cv_acc:.2f}%\")","metadata":{"execution":{"iopub.status.busy":"2024-11-05T14:04:43.709636Z","iopub.execute_input":"2024-11-05T14:04:43.710092Z","iopub.status.idle":"2024-11-05T14:04:43.722857Z","shell.execute_reply.started":"2024-11-05T14:04:43.710047Z","shell.execute_reply":"2024-11-05T14:04:43.721270Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Let's go!!\n# Let's first train the model for first 500 epochs with a learning rate of 0.01 with the optimizer\ntrain_model(my_model, 500, optimizer, loss, new_train_x, new_train_y, new_cv_x, new_cv_y)","metadata":{"execution":{"iopub.status.busy":"2024-11-05T14:04:43.724427Z","iopub.execute_input":"2024-11-05T14:04:43.724855Z","iopub.status.idle":"2024-11-05T14:11:16.175363Z","shell.execute_reply.started":"2024-11-05T14:04:43.724814Z","shell.execute_reply":"2024-11-05T14:11:16.174391Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Awesome Let's check the final loss and accuracy on the cross validation set:\ncv_logits = my_model(new_cv_x).squeeze() \ncv_pred = torch.round(cv_logits)\n\ncv_loss = loss(cv_logits, (new_cv_y.type(torch.float)).to(device))\ncv_acc = accuracy_fn(y_true=new_cv_y, y_pred=cv_pred)\n\nprint(f\"The final loss on the CV set is: {cv_loss:.5f}\\n\\nThe final accuracy on the CV set is: {cv_acc:.2f}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-05T14:11:16.176846Z","iopub.execute_input":"2024-11-05T14:11:16.177482Z","iopub.status.idle":"2024-11-05T14:11:16.208083Z","shell.execute_reply.started":"2024-11-05T14:11:16.177432Z","shell.execute_reply":"2024-11-05T14:11:16.206885Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Great we achived an accurecy of 96.84% on the CV set","metadata":{}},{"cell_type":"code","source":"# Let's see how our model performs on the test set\n\ntest_logits = my_model(new_test_x).squeeze() \ntest_pred = torch.round(test_logits)\n\ntest_loss = loss(test_logits, (new_test_y.type(torch.float)).to(device))\ntest_acc = accuracy_fn(y_true=new_test_y, y_pred=test_pred)\n\nprint(f\"The final loss on the test set is: {test_loss:.5f}\\n\\nThe final accuracy on the test set is: {test_acc:.2f}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-05T14:11:16.209772Z","iopub.execute_input":"2024-11-05T14:11:16.210248Z","iopub.status.idle":"2024-11-05T14:11:16.240606Z","shell.execute_reply.started":"2024-11-05T14:11:16.210196Z","shell.execute_reply":"2024-11-05T14:11:16.239255Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Awesome we achived an accurecy of 97.26% on the test set","metadata":{}},{"cell_type":"code","source":"from sklearn.metrics import precision_score, recall_score\n\n\ntest_pred = torch.round(test_logits.detach()).cpu()\ntest_true = new_test_y.detach().cpu()  \n\n\ntest_pred_np = test_pred.numpy()\ntest_true_np = test_true.numpy()\n\n\nprecision = precision_score(test_true_np, test_pred_np, average='macro')\nrecall = recall_score(test_true_np, test_pred_np, average='macro')\n\nprint(f\"Precision: {precision:.5f}\\nRecall: {recall:.5f}\")\n\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-05T14:22:52.840629Z","iopub.execute_input":"2024-11-05T14:22:52.841177Z","iopub.status.idle":"2024-11-05T14:22:52.882169Z","shell.execute_reply.started":"2024-11-05T14:22:52.841104Z","shell.execute_reply":"2024-11-05T14:22:52.880755Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# We achived a precision of 97.28% and a recall of 97.24%","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-05T14:23:42.794267Z","iopub.execute_input":"2024-11-05T14:23:42.794720Z","iopub.status.idle":"2024-11-05T14:23:42.799973Z","shell.execute_reply.started":"2024-11-05T14:23:42.794650Z","shell.execute_reply":"2024-11-05T14:23:42.798710Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}