{ "cells": [ { "cell_type": "markdown", "id": "82a2f648", "metadata": {}, "source": [ "# 02 — CNN from Scratch\n", "\n", "Train a custom CNN with 5 convolutional blocks.\n", "- Conv2d → BN → ReLU → Conv2d → BN → ReLU → MaxPool (×5)\n", "- Global Average Pooling → FC classifier\n", "- Data augmentation: flip, rotation, jitter, crop\n", "\n", "### Expected Output\n", "- Best checkpoint → `ml/artifacts/checkpoints/cnn_best.pth`\n", "- Training curves, confusion matrix, per-class F1\n", "- Classification report and training summary JSON" ] }, { "cell_type": "code", "execution_count": 1, "id": "1fa1c4ac", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Project root: /Users/ajitkumarsingh/Desktop/desktop/cattle-breed-classifier-webapp\n" ] } ], "source": [ "import sys, os\n", "from pathlib import Path\n", "\n", "PROJECT_ROOT = Path(os.getcwd()).resolve()\n", "if 'notebooks' in str(PROJECT_ROOT):\n", " PROJECT_ROOT = PROJECT_ROOT.parent.parent\n", "sys.path.insert(0, str(PROJECT_ROOT))\n", "print(f'Project root: {PROJECT_ROOT}')" ] }, { "cell_type": "code", "execution_count": 2, "id": "01ca9c9d", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Using Apple MPS (Metal Performance Shaders)\n" ] } ], "source": [ "from ml.src.utils.seed import set_seed\n", "from ml.src.utils.device import get_device\n", "from ml.src.utils.io import load_config\n", "from ml.src.utils.manifests import create_dataloaders\n", "from ml.src.data.transforms import get_train_transforms, get_eval_transforms\n", "from ml.src.models.cnn import CattleCNN\n", "from ml.src.training.trainer import Trainer\n", "\n", "set_seed(42)\n", "device = get_device()" ] }, { "cell_type": "markdown", "id": "82cc219d", "metadata": {}, "source": [ "## 1. Load Config & Data" ] }, { "cell_type": "code", "execution_count": 3, "id": "50b507e8", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Image size: 224\n", "Batch size: 32\n", "Conv channels: [32, 64, 128, 256, 512]\n", "Epochs: 50\n" ] } ], "source": [ "config = load_config('cnn', PROJECT_ROOT / 'ml' / 'configs')\n", "config['num_classes'] = 26\n", "\n", "img_size = config['image']['size']\n", "batch_size = config['training']['batch_size']\n", "\n", "print(f'Image size: {img_size}')\n", "print(f'Batch size: {batch_size}')\n", "print(f'Conv channels: {config[\"model\"][\"architecture\"][\"conv_channels\"]}')\n", "print(f'Epochs: {config[\"training\"][\"num_epochs\"]}')" ] }, { "cell_type": "code", "execution_count": 4, "id": "fb5f07c2", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Classes: 26\n", "Train: 2139 | Val: 458 | Test: 459\n" ] } ], "source": [ "train_transforms = get_train_transforms(img_size=img_size)\n", "eval_transforms = get_eval_transforms(img_size=img_size)\n", "\n", "dataloaders = create_dataloaders(\n", " manifests_dir=PROJECT_ROOT / 'ml' / 'artifacts' / 'manifests',\n", " data_root=PROJECT_ROOT / 'Cattle_Resized',\n", " train_transform=train_transforms,\n", " eval_transform=eval_transforms,\n", " batch_size=batch_size,\n", " num_workers=config['data'].get('num_workers', 4),\n", ")\n", "\n", "class_names = dataloaders['train'].dataset.classes\n", "print(f'Classes: {len(class_names)}')\n", "print(f'Train: {len(dataloaders[\"train\"].dataset)} | Val: {len(dataloaders[\"val\"].dataset)} | Test: {len(dataloaders[\"test\"].dataset)}')" ] }, { "cell_type": "markdown", "id": "3d720152", "metadata": {}, "source": [ "## 2. Create Model" ] }, { "cell_type": "code", "execution_count": 5, "id": "eb04cdf6", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "CattleCNN(\n", " (features): Sequential(\n", " (0): ConvBlock(\n", " (block): Sequential(\n", " (0): Conv2d(3, 32, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))\n", " (1): BatchNorm2d(32, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n", " (2): ReLU(inplace=True)\n", " (3): Conv2d(32, 32, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))\n", " (4): BatchNorm2d(32, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n", " (5): ReLU(inplace=True)\n", " (6): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)\n", " )\n", " )\n", " (1): ConvBlock(\n", " (block): Sequential(\n", " (0): Conv2d(32, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))\n", " (1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n", " (2): ReLU(inplace=True)\n", " (3): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))\n", " (4): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n", " (5): ReLU(inplace=True)\n", " (6): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)\n", " )\n", " )\n", " (2): ConvBlock(\n", " (block): Sequential(\n", " (0): Conv2d(64, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))\n", " (1): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n", " (2): ReLU(inplace=True)\n", " (3): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))\n", " (4): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n", " (5): ReLU(inplace=True)\n", " (6): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)\n", " )\n", " )\n", " (3): ConvBlock(\n", " (block): Sequential(\n", " (0): Conv2d(128, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))\n", " (1): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n", " (2): ReLU(inplace=True)\n", " (3): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))\n", " (4): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n", " (5): ReLU(inplace=True)\n", " (6): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)\n", " )\n", " )\n", " (4): ConvBlock(\n", " (block): Sequential(\n", " (0): Conv2d(256, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))\n", " (1): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n", " (2): ReLU(inplace=True)\n", " (3): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))\n", " (4): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n", " (5): ReLU(inplace=True)\n", " (6): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)\n", " )\n", " )\n", " )\n", " (gap): AdaptiveAvgPool2d(output_size=1)\n", " (classifier): Sequential(\n", " (0): Dropout(p=0.4, inplace=False)\n", " (1): Linear(in_features=512, out_features=256, bias=True)\n", " (2): BatchNorm1d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n", " (3): ReLU(inplace=True)\n", " (4): Dropout(p=0.2, inplace=False)\n", " (5): Linear(in_features=256, out_features=26, bias=True)\n", " )\n", ")\n", "\n", "Total parameters: 4,854,714\n", "Model size: 18.5 MB (float32)\n" ] } ], "source": [ "model = CattleCNN.from_config(config)\n", "print(model)\n", "\n", "total_params = sum(p.numel() for p in model.parameters())\n", "print(f'\\nTotal parameters: {total_params:,}')\n", "print(f'Model size: {total_params * 4 / 1024 / 1024:.1f} MB (float32)')" ] }, { "cell_type": "markdown", "id": "d33e62b0", "metadata": {}, "source": [ "## 3. Train" ] }, { "cell_type": "code", "execution_count": 6, "id": "9d5de427", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n", "============================================================\n", "Training: cnn\n", "Device: mps\n", "Epochs: 50\n", "============================================================\n", "\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ "/Users/ajitkumarsingh/miniforge3/envs/cattle-classifier/lib/python3.12/site-packages/torch/utils/data/dataloader.py:1118: UserWarning: 'pin_memory' argument is set as true but not supported on MPS now, device pinned memory won't be used.\n", " super().__init__(loader)\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " Epoch 1 | Train Loss: 4.9079 | Train Acc: 0.0554 | Val Loss: 3.5658 | Val Acc: 0.0873 | LR: 0.001000\n", " Checkpoint saved: cnn_best.pth (value: 3.5658)\n", " Epoch 2 | Train Loss: 4.1389 | Train Acc: 0.0824 | Val Loss: 3.4800 | Val Acc: 0.0961 | LR: 0.000999\n", " Checkpoint saved: cnn_best.pth (value: 3.4800)\n", " Epoch 3 | Train Loss: 3.8920 | Train Acc: 0.0923 | Val Loss: 3.9241 | Val Acc: 0.1201 | LR: 0.000996\n", " EarlyStopping: 1/10\n", " Epoch 4 | Train Loss: 3.7722 | Train Acc: 0.0895 | Val Loss: 3.0622 | Val Acc: 0.1179 | LR: 0.000991\n", " Checkpoint saved: cnn_best.pth (value: 3.0622)\n", " Epoch 5 | Train Loss: 3.6928 | Train Acc: 0.1089 | Val Loss: 3.0745 | Val Acc: 0.1092 | LR: 0.000984\n", " EarlyStopping: 1/10\n", " Epoch 6 | Train Loss: 3.5790 | Train Acc: 0.1127 | Val Loss: 2.9818 | Val Acc: 0.1201 | LR: 0.000976\n", " Checkpoint saved: cnn_best.pth (value: 2.9818)\n", " Epoch 7 | Train Loss: 3.5056 | Train Acc: 0.1165 | Val Loss: 3.0962 | Val Acc: 0.1201 | LR: 0.000965\n", " EarlyStopping: 1/10\n", " Epoch 8 | Train Loss: 3.5763 | Train Acc: 0.1103 | Val Loss: 5.4329 | Val Acc: 0.0808 | LR: 0.000952\n", " EarlyStopping: 2/10\n", " Epoch 9 | Train Loss: 3.4984 | Train Acc: 0.1122 | Val Loss: 3.9391 | Val Acc: 0.1332 | LR: 0.000938\n", " EarlyStopping: 3/10\n", " Epoch 10 | Train Loss: 3.3699 | Train Acc: 0.1345 | Val Loss: 3.0901 | Val Acc: 0.1485 | LR: 0.000922\n", " EarlyStopping: 4/10\n", " Epoch 11 | Train Loss: 3.3655 | Train Acc: 0.1468 | Val Loss: 3.0115 | Val Acc: 0.1528 | LR: 0.000905\n", " EarlyStopping: 5/10\n", " Epoch 12 | Train Loss: 3.3982 | Train Acc: 0.1359 | Val Loss: 3.4726 | Val Acc: 0.1245 | LR: 0.000885\n", " EarlyStopping: 6/10\n", " Epoch 13 | Train Loss: 3.3166 | Train Acc: 0.1454 | Val Loss: 2.9135 | Val Acc: 0.1354 | LR: 0.000865\n", " Checkpoint saved: cnn_best.pth (value: 2.9135)\n", " Epoch 14 | Train Loss: 3.2789 | Train Acc: 0.1477 | Val Loss: 3.9513 | Val Acc: 0.1441 | LR: 0.000842\n", " EarlyStopping: 1/10\n", " Epoch 15 | Train Loss: 3.2337 | Train Acc: 0.1463 | Val Loss: 2.9434 | Val Acc: 0.1507 | LR: 0.000819\n", " EarlyStopping: 2/10\n", " Epoch 16 | Train Loss: 3.1519 | Train Acc: 0.1695 | Val Loss: 2.9700 | Val Acc: 0.1681 | LR: 0.000794\n", " EarlyStopping: 3/10\n", " Epoch 17 | Train Loss: 3.1828 | Train Acc: 0.1586 | Val Loss: 2.9203 | Val Acc: 0.1856 | LR: 0.000768\n", " EarlyStopping: 4/10\n", " Epoch 18 | Train Loss: 3.1499 | Train Acc: 0.1643 | Val Loss: 3.0137 | Val Acc: 0.1659 | LR: 0.000741\n", " EarlyStopping: 5/10\n", " Epoch 19 | Train Loss: 3.1063 | Train Acc: 0.1709 | Val Loss: 2.7784 | Val Acc: 0.1703 | LR: 0.000713\n", " Checkpoint saved: cnn_best.pth (value: 2.7784)\n", " Epoch 20 | Train Loss: 3.0587 | Train Acc: 0.1742 | Val Loss: 2.9675 | Val Acc: 0.2118 | LR: 0.000684\n", " EarlyStopping: 1/10\n", " Epoch 21 | Train Loss: 3.0843 | Train Acc: 0.1719 | Val Loss: 3.1986 | Val Acc: 0.1550 | LR: 0.000655\n", " EarlyStopping: 2/10\n", " Epoch 22 | Train Loss: 3.0464 | Train Acc: 0.1714 | Val Loss: 3.1444 | Val Acc: 0.1463 | LR: 0.000625\n", " EarlyStopping: 3/10\n", " Epoch 23 | Train Loss: 3.0281 | Train Acc: 0.1903 | Val Loss: 2.7497 | Val Acc: 0.1703 | LR: 0.000594\n", " Checkpoint saved: cnn_best.pth (value: 2.7497)\n", " Epoch 24 | Train Loss: 3.0194 | Train Acc: 0.1790 | Val Loss: 2.6915 | Val Acc: 0.1943 | LR: 0.000563\n", " Checkpoint saved: cnn_best.pth (value: 2.6915)\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ "python(85066) MallocStackLogging: can't turn off malloc stack logging because it was not enabled.\n", "python(85068) MallocStackLogging: can't turn off malloc stack logging because it was not enabled.\n", "python(85069) MallocStackLogging: can't turn off malloc stack logging because it was not enabled.\n", "python(85070) MallocStackLogging: can't turn off malloc stack logging because it was not enabled.\n", "Traceback (most recent call last):\n", "Traceback (most recent call last):\n", " File \"\", line 1, in \n", " File \"/Users/ajitkumarsingh/miniforge3/envs/cattle-classifier/lib/python3.12/multiprocessing/spawn.py\", line 122, in spawn_main\n", "Traceback (most recent call last):\n", " File \"\", line 1, in \n", " File \"/Users/ajitkumarsingh/miniforge3/envs/cattle-classifier/lib/python3.12/multiprocessing/spawn.py\", line 122, in spawn_main\n", " exitcode = _main(fd, parent_sentinel)\n", " ^^^^^^^^^^^^^^^^^^^^^^^^^^\n", " File \"/Users/ajitkumarsingh/miniforge3/envs/cattle-classifier/lib/python3.12/multiprocessing/spawn.py\", line 132, in _main\n", " exitcode = _main(fd, parent_sentinel)\n", " ^^^^ ^self = reduction.pickle.load(from_parent)^\n", "^^^^^^^^^^^^^^^^^^^^\n", " File \"/Users/ajitkumarsingh/miniforge3/envs/cattle-classifier/lib/python3.12/multiprocessing/spawn.py\", line 132, in _main\n", " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n", " File \"/Users/ajitkumarsingh/Desktop/desktop/cattle-breed-classifier-webapp/ml/src/utils/manifests.py\", line 12, in \n", " self = reduction.pickle.load(from_parent)\n", " ^^^^^^^^^^^^^^^^^ File \"\", line 1, in \n", "^^^^^^^^^^^^^ File \"/Users/ajitkumarsingh/miniforge3/envs/cattle-classifier/lib/python3.12/multiprocessing/spawn.py\", line 122, in spawn_main\n", "^^^^\n", " File \"/Users/ajitkumarsingh/Desktop/desktop/cattle-breed-classifier-webapp/ml/src/utils/manifests.py\", line 12, in \n", "Traceback (most recent call last):\n", " File \"\", line 1, in \n", " File \"/Users/ajitkumarsingh/miniforge3/envs/cattle-classifier/lib/python3.12/multiprocessing/spawn.py\", line 122, in spawn_main\n", " exitcode = _main(fd, parent_sentinel)\n", " ^^^^^^^^^^^^^^^^^^^^^^^^^^\n", " File \"/Users/ajitkumarsingh/miniforge3/envs/cattle-classifier/lib/python3.12/multiprocessing/spawn.py\", line 132, in _main\n", " exitcode = _main(fd, parent_sentinel)\n", " ^^^^^^^^^^^^^^^^^^^^^^^^^^\n", " File \"/Users/ajitkumarsingh/miniforge3/envs/cattle-classifier/lib/python3.12/multiprocessing/spawn.py\", line 132, in _main\n", " self = reduction.pickle.load(from_parent)\n", " ^^^^^^^^^^^^^^^^^^^^^^^^ ^self = reduction.pickle.load(from_parent)^\n", "^^^^^^^^\n", " File \"/Users/ajitkumarsingh/Desktop/desktop/cattle-breed-classifier-webapp/ml/src/utils/manifests.py\", line 12, in \n", " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n", " File \"/Users/ajitkumarsingh/Desktop/desktop/cattle-breed-classifier-webapp/ml/src/utils/manifests.py\", line 12, in \n", " from torchvision import transforms\n", " File \"/Users/ajitkumarsingh/miniforge3/envs/cattle-classifier/lib/python3.12/site-packages/torchvision/__init__.py\", line 8, in \n", " from torchvision import _meta_registrations, datasets, io, models, ops, transforms, utils # usort:skip\n", " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n", " File \"/Users/ajitkumarsingh/miniforge3/envs/cattle-classifier/lib/python3.12/site-packages/torchvision/models/__init__.py\", line 2, in \n", " from .convnext import *\n", " File \"/Users/ajitkumarsingh/miniforge3/envs/cattle-classifier/lib/python3.12/site-packages/torchvision/models/convnext.py\", line 9, in \n", " from ..ops.misc import Conv2dNormActivation, Permute\n", " File \"/Users/ajitkumarsingh/miniforge3/envs/cattle-classifier/lib/python3.12/site-packages/torchvision/ops/__init__.py\", line 23, in \n", " from .poolers import MultiScaleRoIAlign\n", " File \"/Users/ajitkumarsingh/miniforge3/envs/cattle-classifier/lib/python3.12/site-packages/torchvision/ops/poolers.py\", line 10, in \n", " from .roi_align import roi_align\n", " File \"/Users/ajitkumarsingh/miniforge3/envs/cattle-classifier/lib/python3.12/site-packages/torchvision/ops/roi_align.py\", line 7, in \n", " from torch._dynamo.utils import is_compile_supported\n", " File \"/Users/ajitkumarsingh/miniforge3/envs/cattle-classifier/lib/python3.12/site-packages/torch/_dynamo/__init__.py\", line 13, in \n", " from . import (\n", " File \"/Users/ajitkumarsingh/miniforge3/envs/cattle-classifier/lib/python3.12/site-packages/torch/_dynamo/aot_compile.py\", line 15, in \n", " from torch._dynamo.convert_frame import GraphRuntimeEnv\n", " File \"/Users/ajitkumarsingh/miniforge3/envs/cattle-classifier/lib/python3.12/site-packages/torch/_dynamo/convert_frame.py\", line 61, in \n", " from torch._dynamo.distributed import get_compile_pg\n", " File \"/Users/ajitkumarsingh/miniforge3/envs/cattle-classifier/lib/python3.12/site-packages/torch/_dynamo/distributed.py\", line 21, in \n", " from . import config\n", " File \"/Users/ajitkumarsingh/miniforge3/envs/cattle-classifier/lib/python3.12/site-packages/torch/_dynamo/config.py\", line 609, in \n", " debug_dir_root = default_debug_dir_root()\n", " ^^^^^^^^^^^^^^^^^^^^^^^^\n", " File \"/Users/ajitkumarsingh/miniforge3/envs/cattle-classifier/lib/python3.12/site-packages/torch/_dynamo/config.py\", line 605, in default_debug_dir_root\n", " return os.path.join(os.getcwd(), \"torch_compile_debug\")\n", " ^^^^^^^^^^^\n", "InterruptedError: [Errno 4] Interrupted system call\n", " from torchvision import transforms\n", " File \"/Users/ajitkumarsingh/miniforge3/envs/cattle-classifier/lib/python3.12/site-packages/torchvision/__init__.py\", line 8, in \n", " from torchvision import _meta_registrations, datasets, io, models, ops, transforms, utils # usort:skip\n", " from torchvision import transforms\n", " ^^^^^^^^^^^^^^^^^^^^^ File \"/Users/ajitkumarsingh/miniforge3/envs/cattle-classifier/lib/python3.12/site-packages/torchvision/__init__.py\", line 8, in \n", "^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^from torchvision import _meta_registrations, datasets, io, models, ops, transforms, utils # usort:skip^\n", "^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^ ^^from torchvision import transforms^^\n", "^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File \"/Users/ajitkumarsingh/miniforge3/envs/cattle-classifier/lib/python3.12/site-packages/torchvision/__init__.py\", line 8, in \n", "^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n", "\n", " File \"/Users/ajitkumarsingh/miniforge3/envs/cattle-classifier/lib/python3.12/site-packages/torchvision/models/__init__.py\", line 2, in \n", " from .convnext import *\n", " from torchvision import _meta_registrations, datasets, io, models, ops, transforms, utils # usort:skip\n", " File \"/Users/ajitkumarsingh/miniforge3/envs/cattle-classifier/lib/python3.12/site-packages/torchvision/models/convnext.py\", line 9, in \n", " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n", " File \"/Users/ajitkumarsingh/miniforge3/envs/cattle-classifier/lib/python3.12/site-packages/torchvision/models/__init__.py\", line 2, in \n", " from .convnext import *\n", " File \"/Users/ajitkumarsingh/miniforge3/envs/cattle-classifier/lib/python3.12/site-packages/torchvision/models/convnext.py\", line 9, in \n", " from ..ops.misc import Conv2dNormActivation, Permute\n", " File \"/Users/ajitkumarsingh/miniforge3/envs/cattle-classifier/lib/python3.12/site-packages/torchvision/ops/__init__.py\", line 23, in \n", " from ..ops.misc import Conv2dNormActivation, Permute\n", " from .poolers import MultiScaleRoIAlign\n", " File \"/Users/ajitkumarsingh/miniforge3/envs/cattle-classifier/lib/python3.12/site-packages/torchvision/ops/poolers.py\", line 10, in \n", " from .roi_align import roi_align\n", " File \"/Users/ajitkumarsingh/miniforge3/envs/cattle-classifier/lib/python3.12/site-packages/torchvision/ops/roi_align.py\", line 7, in \n", " File \"/Users/ajitkumarsingh/miniforge3/envs/cattle-classifier/lib/python3.12/site-packages/torchvision/ops/__init__.py\", line 23, in \n", " File \"/Users/ajitkumarsingh/miniforge3/envs/cattle-classifier/lib/python3.12/site-packages/torchvision/models/__init__.py\", line 2, in \n", " from torch._dynamo.utils import is_compile_supported\n", " File \"/Users/ajitkumarsingh/miniforge3/envs/cattle-classifier/lib/python3.12/site-packages/torch/_dynamo/__init__.py\", line 13, in \n", " from .convnext import *\n", " from . import (\n", " File \"/Users/ajitkumarsingh/miniforge3/envs/cattle-classifier/lib/python3.12/site-packages/torch/_dynamo/aot_compile.py\", line 15, in \n", " File \"/Users/ajitkumarsingh/miniforge3/envs/cattle-classifier/lib/python3.12/site-packages/torchvision/models/convnext.py\", line 9, in \n", " from torch._dynamo.convert_frame import GraphRuntimeEnv\n", " File \"/Users/ajitkumarsingh/miniforge3/envs/cattle-classifier/lib/python3.12/site-packages/torch/_dynamo/convert_frame.py\", line 61, in \n", " from ..ops.misc import Conv2dNormActivation, Permute\n", " File \"/Users/ajitkumarsingh/miniforge3/envs/cattle-classifier/lib/python3.12/site-packages/torchvision/ops/__init__.py\", line 23, in \n", " from torch._dynamo.distributed import get_compile_pg\n", " from .poolers import MultiScaleRoIAlign\n", " File \"/Users/ajitkumarsingh/miniforge3/envs/cattle-classifier/lib/python3.12/site-packages/torch/_dynamo/distributed.py\", line 21, in \n", " File \"/Users/ajitkumarsingh/miniforge3/envs/cattle-classifier/lib/python3.12/site-packages/torchvision/ops/poolers.py\", line 10, in \n", " from . import config\n", " File \"/Users/ajitkumarsingh/miniforge3/envs/cattle-classifier/lib/python3.12/site-packages/torch/_dynamo/config.py\", line 609, in \n", " debug_dir_root = default_debug_dir_root()\n", " ^^^^^^^^^^^^^^^^^^^^^^^^\n", " File \"/Users/ajitkumarsingh/miniforge3/envs/cattle-classifier/lib/python3.12/site-packages/torch/_dynamo/config.py\", line 605, in default_debug_dir_root\n", " return os.path.join(os.getcwd(), \"torch_compile_debug\")\n", " ^^^^^^^^^^^\n", "InterruptedError: [Errno 4] Interrupted system call\n", " from .poolers import MultiScaleRoIAlign\n", " File \"/Users/ajitkumarsingh/miniforge3/envs/cattle-classifier/lib/python3.12/site-packages/torchvision/ops/poolers.py\", line 10, in \n", " from .roi_align import roi_align\n", " File \"/Users/ajitkumarsingh/miniforge3/envs/cattle-classifier/lib/python3.12/site-packages/torchvision/ops/roi_align.py\", line 7, in \n", " from torch._dynamo.utils import is_compile_supported\n", " File \"/Users/ajitkumarsingh/miniforge3/envs/cattle-classifier/lib/python3.12/site-packages/torch/_dynamo/__init__.py\", line 13, in \n", " from . import (\n", " File \"/Users/ajitkumarsingh/miniforge3/envs/cattle-classifier/lib/python3.12/site-packages/torch/_dynamo/aot_compile.py\", line 15, in \n", " from torch._dynamo.convert_frame import GraphRuntimeEnv\n", " File \"/Users/ajitkumarsingh/miniforge3/envs/cattle-classifier/lib/python3.12/site-packages/torch/_dynamo/convert_frame.py\", line 61, in \n", " from torch._dynamo.distributed import get_compile_pg\n", " File \"/Users/ajitkumarsingh/miniforge3/envs/cattle-classifier/lib/python3.12/site-packages/torch/_dynamo/distributed.py\", line 21, in \n", " from . import config\n", " File \"/Users/ajitkumarsingh/miniforge3/envs/cattle-classifier/lib/python3.12/site-packages/torch/_dynamo/config.py\", line 609, in \n", " debug_dir_root = default_debug_dir_root()\n", " ^^^^^^^^^^^^^^^^^^^^^^^^\n", " File \"/Users/ajitkumarsingh/miniforge3/envs/cattle-classifier/lib/python3.12/site-packages/torch/_dynamo/config.py\", line 605, in default_debug_dir_root\n", " return os.path.join(os.getcwd(), \"torch_compile_debug\")\n", " ^^^^^^^^^^^\n", "InterruptedError: [Errno 4] Interrupted system call\n", " from .roi_align import roi_align\n", " File \"/Users/ajitkumarsingh/miniforge3/envs/cattle-classifier/lib/python3.12/site-packages/torchvision/ops/roi_align.py\", line 7, in \n", " from torch._dynamo.utils import is_compile_supported\n", " File \"/Users/ajitkumarsingh/miniforge3/envs/cattle-classifier/lib/python3.12/site-packages/torch/_dynamo/__init__.py\", line 13, in \n", " from . import (\n", " File \"/Users/ajitkumarsingh/miniforge3/envs/cattle-classifier/lib/python3.12/site-packages/torch/_dynamo/aot_compile.py\", line 15, in \n", " from torch._dynamo.convert_frame import GraphRuntimeEnv\n", " File \"/Users/ajitkumarsingh/miniforge3/envs/cattle-classifier/lib/python3.12/site-packages/torch/_dynamo/convert_frame.py\", line 61, in \n", " from torch._dynamo.distributed import get_compile_pg\n", " File \"/Users/ajitkumarsingh/miniforge3/envs/cattle-classifier/lib/python3.12/site-packages/torch/_dynamo/distributed.py\", line 21, in \n", " from . import config\n", " File \"/Users/ajitkumarsingh/miniforge3/envs/cattle-classifier/lib/python3.12/site-packages/torch/_dynamo/config.py\", line 609, in \n", " debug_dir_root = default_debug_dir_root()\n", " ^^^^^^^^^^^^^^^^^^^^^^^^\n", " File \"/Users/ajitkumarsingh/miniforge3/envs/cattle-classifier/lib/python3.12/site-packages/torch/_dynamo/config.py\", line 605, in default_debug_dir_root\n", " return os.path.join(os.getcwd(), \"torch_compile_debug\")\n", " ^^^^^^^^^^^\n", "InterruptedError: [Errno 4] Interrupted system call\n" ] }, { "ename": "RuntimeError", "evalue": "DataLoader worker (pid(s) 85066, 85069, 85070) exited unexpectedly", "output_type": "error", "traceback": [ "\u001b[31m---------------------------------------------------------------------------\u001b[39m", "\u001b[31mRuntimeError\u001b[39m Traceback (most recent call last)", "\u001b[36mFile \u001b[39m\u001b[32m~/miniforge3/envs/cattle-classifier/lib/python3.12/site-packages/torch/utils/data/dataloader.py:1310\u001b[39m, in \u001b[36m_MultiProcessingDataLoaderIter._try_get_data\u001b[39m\u001b[34m(self, timeout)\u001b[39m\n\u001b[32m 1309\u001b[39m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[32m-> \u001b[39m\u001b[32m1310\u001b[39m data = \u001b[38;5;28;43mself\u001b[39;49m\u001b[43m.\u001b[49m\u001b[43m_data_queue\u001b[49m\u001b[43m.\u001b[49m\u001b[43mget\u001b[49m\u001b[43m(\u001b[49m\u001b[43mtimeout\u001b[49m\u001b[43m=\u001b[49m\u001b[43mtimeout\u001b[49m\u001b[43m)\u001b[49m\n\u001b[32m 1311\u001b[39m \u001b[38;5;28;01mreturn\u001b[39;00m (\u001b[38;5;28;01mTrue\u001b[39;00m, data)\n", "\u001b[36mFile \u001b[39m\u001b[32m~/miniforge3/envs/cattle-classifier/lib/python3.12/multiprocessing/queues.py:113\u001b[39m, in \u001b[36mQueue.get\u001b[39m\u001b[34m(self, block, timeout)\u001b[39m\n\u001b[32m 112\u001b[39m timeout = deadline - time.monotonic()\n\u001b[32m--> \u001b[39m\u001b[32m113\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28;43mself\u001b[39;49m\u001b[43m.\u001b[49m\u001b[43m_poll\u001b[49m\u001b[43m(\u001b[49m\u001b[43mtimeout\u001b[49m\u001b[43m)\u001b[49m:\n\u001b[32m 114\u001b[39m \u001b[38;5;28;01mraise\u001b[39;00m Empty\n", "\u001b[36mFile \u001b[39m\u001b[32m~/miniforge3/envs/cattle-classifier/lib/python3.12/multiprocessing/connection.py:257\u001b[39m, in \u001b[36m_ConnectionBase.poll\u001b[39m\u001b[34m(self, timeout)\u001b[39m\n\u001b[32m 256\u001b[39m \u001b[38;5;28mself\u001b[39m._check_readable()\n\u001b[32m--> \u001b[39m\u001b[32m257\u001b[39m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;43mself\u001b[39;49m\u001b[43m.\u001b[49m\u001b[43m_poll\u001b[49m\u001b[43m(\u001b[49m\u001b[43mtimeout\u001b[49m\u001b[43m)\u001b[49m\n", "\u001b[36mFile \u001b[39m\u001b[32m~/miniforge3/envs/cattle-classifier/lib/python3.12/multiprocessing/connection.py:440\u001b[39m, in \u001b[36mConnection._poll\u001b[39m\u001b[34m(self, timeout)\u001b[39m\n\u001b[32m 439\u001b[39m \u001b[38;5;28;01mdef\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[34m_poll\u001b[39m(\u001b[38;5;28mself\u001b[39m, timeout):\n\u001b[32m--> \u001b[39m\u001b[32m440\u001b[39m r = \u001b[43mwait\u001b[49m\u001b[43m(\u001b[49m\u001b[43m[\u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[43m]\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mtimeout\u001b[49m\u001b[43m)\u001b[49m\n\u001b[32m 441\u001b[39m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28mbool\u001b[39m(r)\n", "\u001b[36mFile \u001b[39m\u001b[32m~/miniforge3/envs/cattle-classifier/lib/python3.12/multiprocessing/connection.py:1136\u001b[39m, in \u001b[36mwait\u001b[39m\u001b[34m(object_list, timeout)\u001b[39m\n\u001b[32m 1135\u001b[39m \u001b[38;5;28;01mwhile\u001b[39;00m \u001b[38;5;28;01mTrue\u001b[39;00m:\n\u001b[32m-> \u001b[39m\u001b[32m1136\u001b[39m ready = \u001b[43mselector\u001b[49m\u001b[43m.\u001b[49m\u001b[43mselect\u001b[49m\u001b[43m(\u001b[49m\u001b[43mtimeout\u001b[49m\u001b[43m)\u001b[49m\n\u001b[32m 1137\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m ready:\n", "\u001b[36mFile \u001b[39m\u001b[32m~/miniforge3/envs/cattle-classifier/lib/python3.12/selectors.py:415\u001b[39m, in \u001b[36m_PollLikeSelector.select\u001b[39m\u001b[34m(self, timeout)\u001b[39m\n\u001b[32m 414\u001b[39m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[32m--> \u001b[39m\u001b[32m415\u001b[39m fd_event_list = \u001b[38;5;28;43mself\u001b[39;49m\u001b[43m.\u001b[49m\u001b[43m_selector\u001b[49m\u001b[43m.\u001b[49m\u001b[43mpoll\u001b[49m\u001b[43m(\u001b[49m\u001b[43mtimeout\u001b[49m\u001b[43m)\u001b[49m\n\u001b[32m 416\u001b[39m \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[38;5;167;01mInterruptedError\u001b[39;00m:\n", "\u001b[36mFile \u001b[39m\u001b[32m~/miniforge3/envs/cattle-classifier/lib/python3.12/site-packages/torch/utils/data/_utils/signal_handling.py:73\u001b[39m, in \u001b[36m_set_SIGCHLD_handler..handler\u001b[39m\u001b[34m(signum, frame)\u001b[39m\n\u001b[32m 70\u001b[39m \u001b[38;5;28;01mdef\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[34mhandler\u001b[39m(signum, frame) -> \u001b[38;5;28;01mNone\u001b[39;00m:\n\u001b[32m 71\u001b[39m \u001b[38;5;66;03m# This following call uses `waitid` with WNOHANG from C side. Therefore,\u001b[39;00m\n\u001b[32m 72\u001b[39m \u001b[38;5;66;03m# Python can still get and update the process status successfully.\u001b[39;00m\n\u001b[32m---> \u001b[39m\u001b[32m73\u001b[39m \u001b[43m_error_if_any_worker_fails\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n\u001b[32m 74\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m previous_handler \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m:\n", "\u001b[31mRuntimeError\u001b[39m: DataLoader worker (pid 85066) exited unexpectedly with exit code 1. Details are lost due to multiprocessing. Rerunning with num_workers=0 may give better error trace.", "\nThe above exception was the direct cause of the following exception:\n", "\u001b[31mRuntimeError\u001b[39m Traceback (most recent call last)", "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[6]\u001b[39m\u001b[32m, line 10\u001b[39m\n\u001b[32m 6\u001b[39m device=device,\n\u001b[32m 7\u001b[39m model_name=\u001b[33m'cnn'\u001b[39m,\n\u001b[32m 8\u001b[39m )\n\u001b[32m 9\u001b[39m \n\u001b[32m---> \u001b[39m\u001b[32m10\u001b[39m training_summary = trainer.train()\n", "\u001b[36mFile \u001b[39m\u001b[32m~/Desktop/desktop/cattle-breed-classifier-webapp/ml/src/training/trainer.py:125\u001b[39m, in \u001b[36mTrainer.train\u001b[39m\u001b[34m(self)\u001b[39m\n\u001b[32m 121\u001b[39m set_seed(\u001b[38;5;28mself\u001b[39m.config.get(\u001b[33m'\u001b[39m\u001b[33mdata\u001b[39m\u001b[33m'\u001b[39m, {}).get(\u001b[33m'\u001b[39m\u001b[33mseed\u001b[39m\u001b[33m'\u001b[39m, \u001b[32m42\u001b[39m))\n\u001b[32m 123\u001b[39m \u001b[38;5;28;01mfor\u001b[39;00m epoch \u001b[38;5;129;01min\u001b[39;00m \u001b[38;5;28mrange\u001b[39m(\u001b[32m1\u001b[39m, \u001b[38;5;28mself\u001b[39m.num_epochs + \u001b[32m1\u001b[39m):\n\u001b[32m 124\u001b[39m \u001b[38;5;66;03m# Train\u001b[39;00m\n\u001b[32m--> \u001b[39m\u001b[32m125\u001b[39m train_metrics = \u001b[43mtrain_one_epoch\u001b[49m\u001b[43m(\u001b[49m\n\u001b[32m 126\u001b[39m \u001b[43m \u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[43m.\u001b[49m\u001b[43mmodel\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[43m.\u001b[49m\u001b[43mdataloaders\u001b[49m\u001b[43m[\u001b[49m\u001b[33;43m'\u001b[39;49m\u001b[33;43mtrain\u001b[39;49m\u001b[33;43m'\u001b[39;49m\u001b[43m]\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[43m.\u001b[49m\u001b[43mcriterion\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m 127\u001b[39m \u001b[43m \u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[43m.\u001b[49m\u001b[43moptimizer\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[43m.\u001b[49m\u001b[43mdevice\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[43m.\u001b[49m\u001b[43mgradient_clip\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m 128\u001b[39m \u001b[43m \u001b[49m\u001b[43m)\u001b[49m\n\u001b[32m 130\u001b[39m \u001b[38;5;66;03m# Validate\u001b[39;00m\n\u001b[32m 131\u001b[39m val_metrics = validate(\n\u001b[32m 132\u001b[39m \u001b[38;5;28mself\u001b[39m.model, \u001b[38;5;28mself\u001b[39m.dataloaders[\u001b[33m'\u001b[39m\u001b[33mval\u001b[39m\u001b[33m'\u001b[39m], \u001b[38;5;28mself\u001b[39m.criterion, \u001b[38;5;28mself\u001b[39m.device,\n\u001b[32m 133\u001b[39m )\n", "\u001b[36mFile \u001b[39m\u001b[32m~/Desktop/desktop/cattle-breed-classifier-webapp/ml/src/training/engine.py:32\u001b[39m, in \u001b[36mtrain_one_epoch\u001b[39m\u001b[34m(model, dataloader, criterion, optimizer, device, gradient_clip_max_norm)\u001b[39m\n\u001b[32m 29\u001b[39m total = \u001b[32m0\u001b[39m\n\u001b[32m 30\u001b[39m start_time = time.time()\n\u001b[32m---> \u001b[39m\u001b[32m32\u001b[39m \u001b[43m\u001b[49m\u001b[38;5;28;43;01mfor\u001b[39;49;00m\u001b[43m \u001b[49m\u001b[43mbatch_idx\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43m(\u001b[49m\u001b[43minputs\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mlabels\u001b[49m\u001b[43m)\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;129;43;01min\u001b[39;49;00m\u001b[43m \u001b[49m\u001b[38;5;28;43menumerate\u001b[39;49m\u001b[43m(\u001b[49m\u001b[43mdataloader\u001b[49m\u001b[43m)\u001b[49m\u001b[43m:\u001b[49m\n\u001b[32m 33\u001b[39m \u001b[43m \u001b[49m\u001b[43minputs\u001b[49m\u001b[43m \u001b[49m\u001b[43m=\u001b[49m\u001b[43m \u001b[49m\u001b[43minputs\u001b[49m\u001b[43m.\u001b[49m\u001b[43mto\u001b[49m\u001b[43m(\u001b[49m\u001b[43mdevice\u001b[49m\u001b[43m)\u001b[49m\n\u001b[32m 34\u001b[39m \u001b[43m \u001b[49m\u001b[43mlabels\u001b[49m\u001b[43m \u001b[49m\u001b[43m=\u001b[49m\u001b[43m \u001b[49m\u001b[43mlabels\u001b[49m\u001b[43m.\u001b[49m\u001b[43mto\u001b[49m\u001b[43m(\u001b[49m\u001b[43mdevice\u001b[49m\u001b[43m)\u001b[49m\n", "\u001b[36mFile \u001b[39m\u001b[32m~/miniforge3/envs/cattle-classifier/lib/python3.12/site-packages/torch/utils/data/dataloader.py:741\u001b[39m, in \u001b[36m_BaseDataLoaderIter.__next__\u001b[39m\u001b[34m(self)\u001b[39m\n\u001b[32m 738\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mself\u001b[39m._sampler_iter \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m:\n\u001b[32m 739\u001b[39m \u001b[38;5;66;03m# TODO(https://github.com/pytorch/pytorch/issues/76750)\u001b[39;00m\n\u001b[32m 740\u001b[39m \u001b[38;5;28mself\u001b[39m._reset() \u001b[38;5;66;03m# type: ignore[call-arg]\u001b[39;00m\n\u001b[32m--> \u001b[39m\u001b[32m741\u001b[39m data = \u001b[38;5;28;43mself\u001b[39;49m\u001b[43m.\u001b[49m\u001b[43m_next_data\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n\u001b[32m 742\u001b[39m \u001b[38;5;28mself\u001b[39m._num_yielded += \u001b[32m1\u001b[39m\n\u001b[32m 743\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m (\n\u001b[32m 744\u001b[39m \u001b[38;5;28mself\u001b[39m._dataset_kind == _DatasetKind.Iterable\n\u001b[32m 745\u001b[39m \u001b[38;5;129;01mand\u001b[39;00m \u001b[38;5;28mself\u001b[39m._IterableDataset_len_called \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m\n\u001b[32m 746\u001b[39m \u001b[38;5;129;01mand\u001b[39;00m \u001b[38;5;28mself\u001b[39m._num_yielded > \u001b[38;5;28mself\u001b[39m._IterableDataset_len_called\n\u001b[32m 747\u001b[39m ):\n", "\u001b[36mFile \u001b[39m\u001b[32m~/miniforge3/envs/cattle-classifier/lib/python3.12/site-packages/torch/utils/data/dataloader.py:1524\u001b[39m, in \u001b[36m_MultiProcessingDataLoaderIter._next_data\u001b[39m\u001b[34m(self)\u001b[39m\n\u001b[32m 1520\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mself\u001b[39m._shutdown \u001b[38;5;129;01mor\u001b[39;00m \u001b[38;5;28mself\u001b[39m._tasks_outstanding <= \u001b[32m0\u001b[39m:\n\u001b[32m 1521\u001b[39m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mAssertionError\u001b[39;00m(\n\u001b[32m 1522\u001b[39m \u001b[33m\"\u001b[39m\u001b[33mInvalid iterator state: shutdown or no outstanding tasks when fetching next data\u001b[39m\u001b[33m\"\u001b[39m\n\u001b[32m 1523\u001b[39m )\n\u001b[32m-> \u001b[39m\u001b[32m1524\u001b[39m idx, data = \u001b[38;5;28;43mself\u001b[39;49m\u001b[43m.\u001b[49m\u001b[43m_get_data\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n\u001b[32m 1525\u001b[39m \u001b[38;5;28mself\u001b[39m._tasks_outstanding -= \u001b[32m1\u001b[39m\n\u001b[32m 1526\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mself\u001b[39m._dataset_kind == _DatasetKind.Iterable:\n\u001b[32m 1527\u001b[39m \u001b[38;5;66;03m# Check for _IterableDatasetStopIteration\u001b[39;00m\n", "\u001b[36mFile \u001b[39m\u001b[32m~/miniforge3/envs/cattle-classifier/lib/python3.12/site-packages/torch/utils/data/dataloader.py:1483\u001b[39m, in \u001b[36m_MultiProcessingDataLoaderIter._get_data\u001b[39m\u001b[34m(self)\u001b[39m\n\u001b[32m 1479\u001b[39m \u001b[38;5;66;03m# In this case, `self._data_queue` is a `queue.Queue`,. But we don't\u001b[39;00m\n\u001b[32m 1480\u001b[39m \u001b[38;5;66;03m# need to call `.task_done()` because we don't use `.join()`.\u001b[39;00m\n\u001b[32m 1481\u001b[39m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[32m 1482\u001b[39m \u001b[38;5;28;01mwhile\u001b[39;00m \u001b[38;5;28;01mTrue\u001b[39;00m:\n\u001b[32m-> \u001b[39m\u001b[32m1483\u001b[39m success, data = \u001b[38;5;28;43mself\u001b[39;49m\u001b[43m.\u001b[49m\u001b[43m_try_get_data\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n\u001b[32m 1484\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m success:\n\u001b[32m 1485\u001b[39m \u001b[38;5;28;01mreturn\u001b[39;00m data\n", "\u001b[36mFile \u001b[39m\u001b[32m~/miniforge3/envs/cattle-classifier/lib/python3.12/site-packages/torch/utils/data/dataloader.py:1323\u001b[39m, in \u001b[36m_MultiProcessingDataLoaderIter._try_get_data\u001b[39m\u001b[34m(self, timeout)\u001b[39m\n\u001b[32m 1321\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mlen\u001b[39m(failed_workers) > \u001b[32m0\u001b[39m:\n\u001b[32m 1322\u001b[39m pids_str = \u001b[33m\"\u001b[39m\u001b[33m, \u001b[39m\u001b[33m\"\u001b[39m.join(\u001b[38;5;28mstr\u001b[39m(w.pid) \u001b[38;5;28;01mfor\u001b[39;00m w \u001b[38;5;129;01min\u001b[39;00m failed_workers)\n\u001b[32m-> \u001b[39m\u001b[32m1323\u001b[39m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mRuntimeError\u001b[39;00m(\n\u001b[32m 1324\u001b[39m \u001b[33mf\u001b[39m\u001b[33m\"\u001b[39m\u001b[33mDataLoader worker (pid(s) \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mpids_str\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m) exited unexpectedly\u001b[39m\u001b[33m\"\u001b[39m\n\u001b[32m 1325\u001b[39m ) \u001b[38;5;28;01mfrom\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[34;01me\u001b[39;00m\n\u001b[32m 1326\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28misinstance\u001b[39m(e, queue.Empty):\n\u001b[32m 1327\u001b[39m \u001b[38;5;28;01mreturn\u001b[39;00m (\u001b[38;5;28;01mFalse\u001b[39;00m, \u001b[38;5;28;01mNone\u001b[39;00m)\n", "\u001b[31mRuntimeError\u001b[39m: DataLoader worker (pid(s) 85066, 85069, 85070) exited unexpectedly" ] } ], "source": [ "trainer = Trainer(\n", " model=model,\n", " config=config,\n", " dataloaders=dataloaders,\n", " class_names=class_names,\n", " device=device,\n", " model_name='cnn',\n", ")\n", "\n", "training_summary = trainer.train()" ] }, { "cell_type": "markdown", "id": "a86a0967", "metadata": {}, "source": [ "## 4. Evaluate on Test Set" ] }, { "cell_type": "code", "execution_count": 7, "id": "200caebe", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n", "============================================================\n", "Evaluating: cnn on test\n", "============================================================\n", "\n", "Loaded best checkpoint from epoch 24\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ "python(96188) MallocStackLogging: can't turn off malloc stack logging because it was not enabled.\n", "python(96189) MallocStackLogging: can't turn off malloc stack logging because it was not enabled.\n", "python(96190) MallocStackLogging: can't turn off malloc stack logging because it was not enabled.\n", "python(96191) MallocStackLogging: can't turn off malloc stack logging because it was not enabled.\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\n", "TEST Results:\n", " Loss: 2.6294\n", " Accuracy: 0.2004\n", " Macro F1: 0.0875\n", " Macro Prec: 0.0788\n", " Macro Recall: 0.1186\n", " Avg Latency: 13.84 ms\n", " Model Size: 18.52 MB\n" ] } ], "source": [ "test_results = trainer.evaluate(split='test')" ] }, { "cell_type": "markdown", "id": "b0b84814", "metadata": {}, "source": [ "## 5. Save Artifacts" ] }, { "cell_type": "code", "execution_count": null, "id": "426248da", "metadata": {}, "outputs": [], "source": [ "trainer.save_artifacts()\n", "\n", "print('\\n=== CNN from Scratch Summary ===')\n", "print(f'Best Val Loss: {training_summary[\"best_val_loss\"]:.4f}')\n", "print(f'Best Val Acc: {training_summary[\"best_val_accuracy\"]:.4f}')\n", "print(f'Test Accuracy: {test_results[\"metrics\"][\"accuracy\"]:.4f}')\n", "print(f'Test Macro F1: {test_results[\"metrics\"][\"macro_f1\"]:.4f}')\n", "print(f'Latency: {test_results[\"latency\"][\"avg_ms\"]:.2f} ms')\n", "print(f'Model Size: {test_results[\"model_size_mb\"]:.2f} MB')" ] }, { "cell_type": "markdown", "id": "2d70745c", "metadata": {}, "source": [ "## 6. Classification Report" ] }, { "cell_type": "code", "execution_count": 8, "id": "efee8337", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ " precision recall f1-score support\n", "\n", " Alambadi Cow 0.08 0.07 0.08 14\n", " Amritmahal Cow 0.00 0.00 0.00 14\n", " Banni Buffalo 0.00 0.00 0.00 5\n", " Bargur Cow 0.00 0.00 0.00 9\n", " Dangi Cow 0.00 0.00 0.00 12\n", " Deoni Cow 0.00 0.00 0.00 16\n", " Gir Cow 0.25 0.50 0.33 38\n", " Hallikar Cow 0.16 0.29 0.20 28\n", "Jaffrabadi Buffalo 0.08 0.06 0.07 16\n", " Kangayam Cow 0.00 0.00 0.00 18\n", " Kankrej Cow 0.14 0.04 0.06 27\n", " Kasaragod Cow 0.00 0.00 0.00 14\n", " Kenkatha Cow 0.00 0.00 0.00 8\n", " Kherigarh Cow 0.00 0.00 0.00 5\n", " Malnad gidda Cow 0.27 0.25 0.26 16\n", " Mehsana Buffalo 0.14 0.20 0.17 15\n", " Nagori Cow 0.00 0.00 0.00 13\n", " Nagpuri Buffalo 0.18 0.30 0.23 33\n", " Nili ravi Buffalo 0.00 0.00 0.00 14\n", " Nimari Cow 0.00 0.00 0.00 13\n", " Pulikulam Cow 0.05 0.05 0.05 19\n", " Rathi Cow 0.17 0.09 0.12 22\n", " Sahiwal Cow 0.31 0.47 0.38 36\n", " Shurti Buffalo 0.00 0.00 0.00 9\n", " Tharparkar Cow 0.22 0.76 0.34 33\n", " Umblachery Cow 0.00 0.00 0.00 12\n", "\n", " accuracy 0.20 459\n", " macro avg 0.08 0.12 0.09 459\n", " weighted avg 0.12 0.20 0.14 459\n", "\n" ] } ], "source": [ "print(test_results['metrics']['classification_report'])" ] }, { "cell_type": "markdown", "id": "eb61adcd", "metadata": {}, "source": [ "---\n", "**✅ CNN from Scratch complete.** Proceed to `03_resnet_transfer_learning.ipynb`." ] } ], "metadata": { "kernelspec": { "display_name": "Cattle Classifier (Python 3.12)", "language": "python", "name": "cattle-classifier" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.12.13" } }, "nbformat": 4, "nbformat_minor": 5 }