{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.12.12","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"nvidiaTeslaT4","dataSources":[{"sourceType":"competition","sourceId":6799,"databundleVersionId":4225553},{"sourceType":"datasetVersion","sourceId":2409323,"datasetId":1457432,"databundleVersionId":2451409}],"dockerImageVersionId":31329,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"<div style=\"background-color:#fff; padding:40px; display:flex; justify-content:center; align-items:center; font-family:Arial, sans-serif;\">\n  <div style=\"background-color:#ffffff; padding:30px; border-radius:12px; max-width:600px; width:100%; text-align:center; box-shadow:0 10px 25px rgba(0,0,0,0.15);margin:0 auto;\">\n      <img src=\"https://holosen.net/public/src/img/logo/holosen-logo.png\" width=\"50\"/>\n    <p style=\"font-size:18px; font-weight:bold; color:#222222; line-height:1.8; margin-bottom:25px;text-align:justify\">\n     I prepared this code for the Holosen Artificial Intelligence 0-100 training course.\n        <br/>\n        For more detailed Persian training resources, you can visit:\n    </p>\n    <a href=\"https://holosen.net/artificial-intelligence/?src=kaggle\" target=\"_blank\" \n       style=\"display:inline-block; background-color:#525fe1; color:#ffffff; text-decoration:none; padding:14px 28px; border-radius:8px; font-size:16px; font-weight:bold;\">\n       Holosen Artificial Intelligence 0-100 Training Course\n    </a>\n  </div>\n</div>","metadata":{}},{"cell_type":"markdown","source":"> you can see `ImageNet - CNN` that created with `AlexNet` model from here:\n> \n> https://www.kaggle.com/code/hosseinbadrnezhad/imagenet-cnn-limited-edition","metadata":{}},{"cell_type":"code","source":"import os\nimport torch\nimport random\nimport torch.nn as nn\nimport torch.optim as optim\nfrom torchvision import models\nimport matplotlib.pyplot as plt\nfrom torchvision import transforms, datasets\nfrom torchvision.datasets import ImageFolder\nfrom torch.utils.data import random_split, DataLoader","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2026-03-23T20:06:06.779558Z","iopub.execute_input":"2026-03-23T20:06:06.780038Z","iopub.status.idle":"2026-03-23T20:06:16.259073Z","shell.execute_reply.started":"2026-03-23T20:06:06.780013Z","shell.execute_reply":"2026-03-23T20:06:16.258453Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Configuration","metadata":{}},{"cell_type":"code","source":"# DATA_PATH = '/kaggle/input/competitions/imagenet-object-localization-challenge/ILSVRC/Data/CLS-LOC/train'\nDATA_PATH = '/kaggle/input/datasets/arjunashok33/miniimagenet'","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-23T20:06:16.260503Z","iopub.execute_input":"2026-03-23T20:06:16.26083Z","iopub.status.idle":"2026-03-23T20:06:16.264384Z","shell.execute_reply.started":"2026-03-23T20:06:16.260805Z","shell.execute_reply":"2026-03-23T20:06:16.263621Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"BATCH_SIZE = 128\nEPOCHS = 10\nIMAGE_SIZE = 224\nWORKERS = 4","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-23T20:06:16.265386Z","iopub.execute_input":"2026-03-23T20:06:16.265714Z","iopub.status.idle":"2026-03-23T20:06:16.294174Z","shell.execute_reply.started":"2026-03-23T20:06:16.265674Z","shell.execute_reply":"2026-03-23T20:06:16.29343Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"NUM_CLASSESS_TO_USE = 10 # all => -1","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-23T20:06:16.295146Z","iopub.execute_input":"2026-03-23T20:06:16.295401Z","iopub.status.idle":"2026-03-23T20:06:16.304818Z","shell.execute_reply.started":"2026-03-23T20:06:16.295367Z","shell.execute_reply":"2026-03-23T20:06:16.30419Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')\ndevice","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-23T20:06:16.305788Z","iopub.execute_input":"2026-03-23T20:06:16.306369Z","iopub.status.idle":"2026-03-23T20:06:16.568003Z","shell.execute_reply.started":"2026-03-23T20:06:16.306345Z","shell.execute_reply":"2026-03-23T20:06:16.567294Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# ETL","metadata":{}},{"cell_type":"markdown","source":"## Tranform","metadata":{}},{"cell_type":"code","source":"train_transform = transforms.Compose([\n    transforms.Resize(256),\n    transforms.RandomCrop(IMAGE_SIZE),\n    transforms.RandomHorizontalFlip(),\n    transforms.ToTensor(),\n    transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])\n])\n\nval_transform = transforms.Compose([\n    transforms.Resize(256),\n    transforms.CenterCrop(IMAGE_SIZE),\n    transforms.ToTensor(),\n    transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])\n])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-23T20:06:16.568986Z","iopub.execute_input":"2026-03-23T20:06:16.569358Z","iopub.status.idle":"2026-03-23T20:06:16.579847Z","shell.execute_reply.started":"2026-03-23T20:06:16.569331Z","shell.execute_reply":"2026-03-23T20:06:16.579303Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Limited Edition Configuration","metadata":{}},{"cell_type":"code","source":"all_classes = sorted(os.listdir(DATA_PATH))\nprint(\"All classes count:\", len(all_classes))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-23T20:06:16.582126Z","iopub.execute_input":"2026-03-23T20:06:16.582353Z","iopub.status.idle":"2026-03-23T20:06:16.602088Z","shell.execute_reply.started":"2026-03-23T20:06:16.58233Z","shell.execute_reply":"2026-03-23T20:06:16.601518Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"if NUM_CLASSESS_TO_USE != -1:\n    selected_classes = random.sample(all_classes, NUM_CLASSESS_TO_USE)\nelse:\n    selected_classes = all_classes\n\nprint(\"selected classes count:\",len(selected_classes))\nselected_classes","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-23T20:06:16.602706Z","iopub.execute_input":"2026-03-23T20:06:16.60291Z","iopub.status.idle":"2026-03-23T20:06:16.608716Z","shell.execute_reply.started":"2026-03-23T20:06:16.602868Z","shell.execute_reply":"2026-03-23T20:06:16.608041Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"subset_path = '/kaggle/working/subset_data'\n\nif not os.path.exists(subset_path):\n    os.makedirs(subset_path)\n    \n    for cls in selected_classes:\n        src = os.path.join(DATA_PATH, cls)\n        dst = os.path.join(subset_path, cls)\n        os.symlink(src, dst)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-23T20:06:16.609928Z","iopub.execute_input":"2026-03-23T20:06:16.610206Z","iopub.status.idle":"2026-03-23T20:06:16.61885Z","shell.execute_reply.started":"2026-03-23T20:06:16.610175Z","shell.execute_reply":"2026-03-23T20:06:16.6182Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Dataset","metadata":{}},{"cell_type":"code","source":"dataset = datasets.ImageFolder(subset_path, transform=train_transform)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-23T20:06:16.619722Z","iopub.execute_input":"2026-03-23T20:06:16.620015Z","iopub.status.idle":"2026-03-23T20:06:37.246549Z","shell.execute_reply.started":"2026-03-23T20:06:16.619974Z","shell.execute_reply":"2026-03-23T20:06:37.245955Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"print(\"Count of classes:\",len(dataset.classes))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-23T20:06:37.247445Z","iopub.execute_input":"2026-03-23T20:06:37.247701Z","iopub.status.idle":"2026-03-23T20:06:37.251789Z","shell.execute_reply.started":"2026-03-23T20:06:37.247677Z","shell.execute_reply":"2026-03-23T20:06:37.251091Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Train / Validation","metadata":{}},{"cell_type":"code","source":"train_size = int(0.9 * len(dataset))\nval_size = len(dataset) - train_size\n\nprint(\"train size:\",train_size,\", validation size:\",val_size)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-23T20:06:37.252779Z","iopub.execute_input":"2026-03-23T20:06:37.253166Z","iopub.status.idle":"2026-03-23T20:06:37.265056Z","shell.execute_reply.started":"2026-03-23T20:06:37.253137Z","shell.execute_reply":"2026-03-23T20:06:37.264383Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train_data, val_data = random_split(dataset, [train_size, val_size])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-23T20:06:37.265816Z","iopub.execute_input":"2026-03-23T20:06:37.266104Z","iopub.status.idle":"2026-03-23T20:06:37.291379Z","shell.execute_reply.started":"2026-03-23T20:06:37.266077Z","shell.execute_reply":"2026-03-23T20:06:37.290784Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"val_data.dataset.transform = val_transform","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-23T20:06:37.292127Z","iopub.execute_input":"2026-03-23T20:06:37.292329Z","iopub.status.idle":"2026-03-23T20:06:37.295535Z","shell.execute_reply.started":"2026-03-23T20:06:37.292307Z","shell.execute_reply":"2026-03-23T20:06:37.294954Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Mini Batch","metadata":{}},{"cell_type":"code","source":"train_loader = DataLoader(\n    train_data,\n    batch_size=BATCH_SIZE,\n    shuffle=True,\n    num_workers=WORKERS,\n    pin_memory=True,\n    persistent_workers=True,\n    prefetch_factor=2\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-23T20:06:37.296448Z","iopub.execute_input":"2026-03-23T20:06:37.296706Z","iopub.status.idle":"2026-03-23T20:06:37.307464Z","shell.execute_reply.started":"2026-03-23T20:06:37.296683Z","shell.execute_reply":"2026-03-23T20:06:37.30686Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"val_loader = DataLoader(\n    val_data,\n    batch_size=BATCH_SIZE,\n    num_workers=WORKERS,\n    pin_memory=True,\n    persistent_workers=True,\n    prefetch_factor=2\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-23T20:06:37.308258Z","iopub.execute_input":"2026-03-23T20:06:37.308508Z","iopub.status.idle":"2026-03-23T20:06:37.320675Z","shell.execute_reply.started":"2026-03-23T20:06:37.308487Z","shell.execute_reply":"2026-03-23T20:06:37.320117Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Model (VGG16)","metadata":{}},{"cell_type":"code","source":"model = models.vgg16(weights='DEFAULT')\n\n# Lock all layers (prevent weights from changing during training)\nfor param in model.parameters():\n    param.requires_grad = False\n\n# Find the number of entries in the last layer (usually 4096)\nnum_features = model.classifier[6].in_features\n\n# Replace the last layer with a new layer set to 100 classes\n# This new layer automatically has requires_grad=True\nmodel.classifier[6] = nn.Linear(num_features, len(dataset.classes))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-23T20:06:37.321472Z","iopub.execute_input":"2026-03-23T20:06:37.321731Z","iopub.status.idle":"2026-03-23T20:06:39.102152Z","shell.execute_reply.started":"2026-03-23T20:06:37.321701Z","shell.execute_reply":"2026-03-23T20:06:39.101542Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## MultiGPU Support","metadata":{}},{"cell_type":"code","source":"if torch.cuda.device_count() > 1:\n    model = nn.DataParallel(model)\n\nmodel = model.to(device)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-23T20:06:39.102994Z","iopub.execute_input":"2026-03-23T20:06:39.103263Z","iopub.status.idle":"2026-03-23T20:06:39.549521Z","shell.execute_reply.started":"2026-03-23T20:06:39.103231Z","shell.execute_reply":"2026-03-23T20:06:39.548673Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Training Setup","metadata":{}},{"cell_type":"code","source":"criterion = nn.CrossEntropyLoss()\n\n# Only give the optimizer parameters that are not locked\noptimizer = torch.optim.Adam(filter(lambda p: p.requires_grad, model.parameters()), lr=0.001)\n\nscheduler = optim.lr_scheduler.StepLR(optimizer,step_size=10,gamma=0.1)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-23T20:06:39.550571Z","iopub.execute_input":"2026-03-23T20:06:39.550876Z","iopub.status.idle":"2026-03-23T20:06:39.555859Z","shell.execute_reply.started":"2026-03-23T20:06:39.550845Z","shell.execute_reply":"2026-03-23T20:06:39.555097Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Tracking","metadata":{}},{"cell_type":"code","source":"train_losses = []\nval_losses = []\nlrs = []","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-23T20:06:39.556637Z","iopub.execute_input":"2026-03-23T20:06:39.556871Z","iopub.status.idle":"2026-03-23T20:06:39.57021Z","shell.execute_reply.started":"2026-03-23T20:06:39.556842Z","shell.execute_reply":"2026-03-23T20:06:39.569582Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"for epoch in range(EPOCHS):\n\n    # Train\n    model.train()\n    train_loss = 0\n\n    for images, labels in train_loader:\n\n        images = images.to(device) # GPU/CPU\n        labels = labels.to(device) # GPU/CPU\n        \n        outputs = model(images)\n        loss = criterion(outputs, labels)\n\n        optimizer.zero_grad()\n        loss.backward()\n        optimizer.step()\n\n        train_loss += loss.item()\n\n    train_loss /= len(train_loader)\n\n    # Validation\n    model.eval()\n    val_loss = 0\n\n    with torch.no_grad():\n        for images, labels in val_loader:\n\n            images = images.to(device) # GPU/CPU\n            labels = labels.to(device) # GPU/CPU\n            \n            outputs = model(images)\n            loss = criterion(outputs, labels)\n\n            val_loss += loss.item()\n\n        val_loss /= len(val_loader)\n\n    current_lr = optimizer.param_groups[0]['lr']\n\n    # saving metrics\n    train_losses.append(train_loss)\n    val_losses.append(val_loss)\n    lrs.append(current_lr)\n    \n    print(f\"Epoch {epoch} => train loss = {train_loss:.4f}, val loss = {val_loss:.4f}, lr = {current_lr:.6f}\")\n\n    # Scheduler Step\n    scheduler.step()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-23T20:06:39.570962Z","iopub.execute_input":"2026-03-23T20:06:39.571223Z","execution_failed":"2026-03-23T20:07:52.025Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Plot\n## Learning Curve","metadata":{}},{"cell_type":"code","source":"plt.figure()\nplt.plot(train_losses, label=\"Train Loss\")\nplt.plot(val_losses, label = \"Validation Loss\")\nplt.xlabel(\"Epoch\")\nplt.ylabel(\"Loss\")\nplt.title(\"Learning Curve\")\nplt.legend()\nplt.grid()\nplt.show()","metadata":{"trusted":true,"execution":{"execution_failed":"2026-03-23T20:07:52.026Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Learning Rate","metadata":{}},{"cell_type":"code","source":"plt.figure()\nplt.plot(lrs, label=\"Learning Rate\")\nplt.xlabel(\"Epoch\")\nplt.ylabel(\"LR\")\nplt.title(\"Learning Schedule\")\nplt.legend()\nplt.grid()\nplt.show()","metadata":{"trusted":true,"execution":{"execution_failed":"2026-03-23T20:07:52.026Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Saving Model","metadata":{}},{"cell_type":"code","source":"torch.save(model.state_dict(),\"alex_net.pth\")\nprint(\"Model Saved\")","metadata":{"trusted":true,"execution":{"execution_failed":"2026-03-23T20:07:52.026Z"}},"outputs":[],"execution_count":null}]}