{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.11.13","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"gpu","dataSources":[{"sourceId":3649,"databundleVersionId":46718,"sourceType":"competition"}],"dockerImageVersionId":31090,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"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","trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Cell 1: Train a pretrained-architecture model (random init) on CIFAR-10\n# - Model: ResNet18 (torchvision), no pretrained weights\n# - Transforms: RandomCrop + HorizontalFlip + RandomErasing\n# - Saves best weights to: best_resnet18.pt\n# ======================================================\nimport os, random, warnings\nwarnings.filterwarnings(\"ignore\")\nimport numpy as np\nimport torch, torch.nn as nn\nimport torch.nn.functional as F\nfrom torch.utils.data import DataLoader, Subset\nfrom torchvision import datasets, transforms, models\nfrom torch.cuda.amp import autocast, GradScaler\n\n# Repro + device\nSEED = 1337\nrandom.seed(SEED)\nnp.random.seed(SEED)\ntorch.manual_seed(SEED)\ndevice = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\ntorch.backends.cudnn.benchmark = True\nprint(\"Device:\", device)\n\n# CIFAR-10 stats\nCIFAR_MEAN = (0.4914,0.4822,0.4465)\nCIFAR_STD  = (0.2470,0.2435,0.2616)\n\n# Transforms\ntrain_tfms = transforms.Compose([\n    transforms.RandomCrop(32, padding=4),\n    transforms.RandomHorizontalFlip(),\n    transforms.ToTensor(),\n    transforms.Normalize(CIFAR_MEAN, CIFAR_STD),\n    transforms.RandomErasing(p=0.25),\n])\ntest_tfms = transforms.Compose([\n    transforms.ToTensor(),\n    transforms.Normalize(CIFAR_MEAN, CIFAR_STD),\n])\n\n# Load CIFAR-10\nDATA_ROOT = \"/kaggle/working\"\n_base = datasets.CIFAR10(root=DATA_ROOT, train=True, download=True, transform=None)\nidx = np.arange(len(_base))\nnp.random.default_rng(SEED).shuffle(idx)\nVAL_SZ = 5000\ntrain_idx, val_idx = idx[VAL_SZ:], idx[:VAL_SZ]\n\ntrain_set = Subset(datasets.CIFAR10(root=DATA_ROOT, train=True, download=False, transform=train_tfms), train_idx.tolist())\nval_set   = Subset(datasets.CIFAR10(root=DATA_ROOT, train=True, download=False, transform=test_tfms), val_idx.tolist())\n\nBATCH_TRAIN, BATCH_VAL = 256, 512\ntrain_loader = DataLoader(train_set, batch_size=BATCH_TRAIN, shuffle=True, num_workers=2, pin_memory=True)\nval_loader   = DataLoader(val_set, batch_size=BATCH_VAL, shuffle=False, num_workers=2, pin_memory=True)\n\nprint(f\"Train rows: {len(train_set)} | Val rows: {len(val_set)}\")\n\n# Model: ResNet18, no pretrained weights\nmodel = models.resnet18(weights=None)\nmodel.conv1 = nn.Conv2d(3, 64, kernel_size=3, stride=1, padding=1, bias=False)  # adapt for CIFAR-10\nmodel.maxpool = nn.Identity()  # remove initial downsample\nmodel.fc = nn.Linear(model.fc.in_features, 10)  # CIFAR-10 classes\nmodel = model.to(device).to(memory_format=torch.channels_last)\n\n# Optimizer, scheduler, loss, AMP\nEPOCHS = 60\nopt = torch.optim.SGD(model.parameters(), lr=0.05, momentum=0.9, weight_decay=5e-4, nesterov=True)\nsch = torch.optim.lr_scheduler.CosineAnnealingLR(opt, T_max=EPOCHS)\ncrit = nn.CrossEntropyLoss(label_smoothing=0.05)\nscaler = GradScaler()\n\n# Training function\ndef run_epoch(dl, train=True):\n    model.train(train)\n    tot = correct = loss_sum = 0.0\n    for x, y in dl:\n        x = x.to(device, non_blocking=True).contiguous(memory_format=torch.channels_last)\n        y = y.to(device, non_blocking=True)\n        if train: opt.zero_grad(set_to_none=True)\n        with autocast():\n            logits = model(x)\n            loss = crit(logits, y)\n        if train:\n            scaler.scale(loss).backward()\n            scaler.step(opt)\n            scaler.update()\n        loss_sum += loss.item() * x.size(0)\n        correct += (logits.argmax(1) == y).sum().item()\n        tot += x.size(0)\n    return loss_sum/tot, correct/tot\n\n# Training loop\nbest = (0.0, None)\nfor e in range(1, EPOCHS+1):\n    tr_loss, tr_acc = run_epoch(train_loader, True)\n    va_loss, va_acc = run_epoch(val_loader, False)\n    sch.step()\n    if va_acc > best[0]:\n        best = (va_acc, {k: v.detach().cpu() for k, v in model.state_dict().items()})\n    print(f\"Ep{e:02d}/{EPOCHS} train_acc={tr_acc:.3f} val_acc={va_acc:.3f}\")\n\n# Save best weights\ntorch.save(best[1], \"best_resnet18.pt\")\nprint(\"✅ Saved best_resnet18.pt\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-24T12:44:30.924268Z","iopub.execute_input":"2025-09-24T12:44:30.924447Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}