{"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":31154,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"# =====================\n# Cell 0: Environment\n# =====================\n\nimport os, math, random, time, glob, json\nimport numpy as np\nfrom pathlib import Path\n\nimport torch\nimport torch.nn as nn\nimport torch.nn.functional as F\nfrom torch.utils.data import DataLoader\nfrom torch.optim import SGD\nfrom torch.optim.lr_scheduler import CosineAnnealingLR\nfrom torchvision import datasets, transforms, models\n\nfrom PIL import Image\n\nSEED = 123\nrandom.seed(SEED); np.random.seed(SEED); torch.manual_seed(SEED); torch.cuda.manual_seed_all(SEED)\n\nDEVICE = torch.device('cuda' if torch.cuda.is_available() else 'cpu')\nprint('Device:', DEVICE)","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2025-10-11T20:13:39.613534Z","iopub.execute_input":"2025-10-11T20:13:39.613784Z","iopub.status.idle":"2025-10-11T20:13:46.599485Z","shell.execute_reply.started":"2025-10-11T20:13:39.613766Z","shell.execute_reply":"2025-10-11T20:13:46.598733Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# =====================\n# Cell 1: Config\n# =====================\nclass CFG:\n    # Data & training\n    img_size = 32\n    epochs = 120            # Increase if you have more time (e.g., 200)\n    batch_size = 128\n    num_workers = 2\n\n    # Optimizer / LR\n    lr = 0.1\n    weight_decay = 5e-4\n    momentum = 0.9\n    warmup_epochs = 5\n\n    # Regularization\n    label_smoothing = 0.1\n    mixup_alpha = 0.2\n    cutmix_alpha = 1.0      # set to 0 to disable CutMix\n    mixup_prob = 0.7        # probability to apply Mixup/CutMix per batch\n\n    # EMA\n    use_ema = True\n    ema_decay = 0.999\n       \n    # Paths\n    work_dir = '.'\n    submission_path = os.path.join(work_dir, 'submission.csv')\n\n    # Classes for CIFAR-10 (match Kaggle label strings)\n    classes = ['airplane', 'automobile', 'bird', 'cat', 'deer',\n               'dog', 'frog', 'horse', 'ship', 'truck']\n\ncfg = CFG()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-11T20:14:43.399806Z","iopub.execute_input":"2025-10-11T20:14:43.400467Z","iopub.status.idle":"2025-10-11T20:14:43.405289Z","shell.execute_reply.started":"2025-10-11T20:14:43.400446Z","shell.execute_reply":"2025-10-11T20:14:43.404569Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# =====================\n# Cell 2: Advanced Data Augmentation for CIFAR-10\n# =====================\nimport torch\nfrom torchvision import transforms\nimport random\nimport numpy as np\nfrom PIL import Image\n\n# CIFAR-10 mean/std for normalization\nCIFAR10_MEAN = (0.4914, 0.4822, 0.4465)\nCIFAR10_STD  = (0.2023, 0.1994, 0.2010)\n\n# -----------------------\n# CutOut Implementation\n# -----------------------\nclass CutOut(object):\n    def __init__(self, n_holes=1, length=8):\n        self.n_holes = n_holes\n        self.length = length\n\n    def __call__(self, img):\n        h, w = img.size(1), img.size(2)\n        mask = np.ones((h, w), np.float32)\n        for n in range(self.n_holes):\n            y = np.random.randint(h)\n            x = np.random.randint(w)\n            y1 = np.clip(y - self.length // 2, 0, h)\n            y2 = np.clip(y + self.length // 2, 0, h)\n            x1 = np.clip(x - self.length // 2, 0, w)\n            x2 = np.clip(x + self.length // 2, 0, w)\n            mask[y1:y2, x1:x2] = 0.\n        mask = torch.from_numpy(mask)\n        mask = mask.expand_as(img)\n        img = img * mask\n        return img\n\n# -----------------------\n# Compose all augmentations\n# -----------------------\ntrain_transform = transforms.Compose([\n    transforms.RandomCrop(32, padding=4),\n    transforms.RandomHorizontalFlip(),\n    transforms.RandAugment(num_ops=3, magnitude=10),  # stronger than default\n    transforms.ToTensor(),\n    CutOut(n_holes=1, length=8),  # custom CutOut\n    transforms.Normalize(CIFAR10_MEAN, CIFAR10_STD)\n])\n\nvalid_transform = transforms.Compose([\n    transforms.ToTensor(),\n    transforms.Normalize(CIFAR10_MEAN, CIFAR10_STD)\n])\n\nprint(\"✅ Advanced augmentations (RandAugment + CutOut) enabled.\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-11T20:14:52.249599Z","iopub.execute_input":"2025-10-11T20:14:52.249853Z","iopub.status.idle":"2025-10-11T20:14:52.258864Z","shell.execute_reply.started":"2025-10-11T20:14:52.249836Z","shell.execute_reply":"2025-10-11T20:14:52.258112Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# =====================\n# Cell 3: Data\n# =====================\n\ndata_root = './data'\ntrain_set = datasets.CIFAR10(root=data_root, train=True,  download=True, transform=train_transform)\nvalid_set = datasets.CIFAR10(root=data_root, train=False, download=True, transform=valid_transform)\n\ntrain_loader = DataLoader(train_set, batch_size=cfg.batch_size, shuffle=True,\n                          num_workers=cfg.num_workers, pin_memory=True)\nvalid_loader = DataLoader(valid_set, batch_size=cfg.batch_size, shuffle=False,\n                          num_workers=cfg.num_workers, pin_memory=True)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-11T20:15:09.936299Z","iopub.execute_input":"2025-10-11T20:15:09.937026Z","iopub.status.idle":"2025-10-11T20:15:29.872696Z","shell.execute_reply.started":"2025-10-11T20:15:09.937004Z","shell.execute_reply":"2025-10-11T20:15:29.871943Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# =====================\n# Cell 4: Custom Residual Network (from scratch)\n# =====================\nimport torch\nimport torch.nn as nn\nimport torch.nn.functional as F\n\n# ---------------------\n# Residual Block\n# ---------------------\nclass ResidualBlock(nn.Module):\n    def __init__(self, in_channels, out_channels, stride=1):\n        super(ResidualBlock, self).__init__()\n        self.conv1 = nn.Conv2d(in_channels, out_channels, 3, stride, 1, bias=False)\n        self.bn1 = nn.BatchNorm2d(out_channels)\n        self.relu = nn.ReLU(inplace=True)\n        self.conv2 = nn.Conv2d(out_channels, out_channels, 3, 1, 1, bias=False)\n        self.bn2 = nn.BatchNorm2d(out_channels)\n\n        self.shortcut = nn.Sequential()\n        if stride != 1 or in_channels != out_channels:\n            self.shortcut = nn.Sequential(\n                nn.Conv2d(in_channels, out_channels, 1, stride, bias=False),\n                nn.BatchNorm2d(out_channels)\n            )\n\n    def forward(self, x):\n        identity = self.shortcut(x)\n        out = self.relu(self.bn1(self.conv1(x)))\n        out = self.bn2(self.conv2(out))\n        out += identity\n        out = self.relu(out)\n        return out\n\n# ---------------------\n# Custom ResNet-like Model\n# ---------------------\nclass CustomResNet(nn.Module):\n    def __init__(self, num_classes=10):\n        super(CustomResNet, self).__init__()\n        self.conv1 = nn.Conv2d(3, 64, kernel_size=3, stride=1, padding=1, bias=False)\n        self.bn1 = nn.BatchNorm2d(64)\n        self.relu = nn.ReLU(inplace=True)\n\n        self.layer1 = self._make_layer(64, 64, num_blocks=2, stride=1)\n        self.layer2 = self._make_layer(64, 128, num_blocks=2, stride=2)\n        self.layer3 = self._make_layer(128, 256, num_blocks=2, stride=2)\n        self.layer4 = self._make_layer(256, 512, num_blocks=2, stride=2)\n\n        self.avgpool = nn.AdaptiveAvgPool2d((1, 1))\n        self.fc = nn.Linear(512, num_classes)\n\n    def _make_layer(self, in_channels, out_channels, num_blocks, stride):\n        layers = [ResidualBlock(in_channels, out_channels, stride)]\n        for _ in range(1, num_blocks):\n            layers.append(ResidualBlock(out_channels, out_channels))\n        return nn.Sequential(*layers)\n\n    def forward(self, x):\n        x = self.relu(self.bn1(self.conv1(x)))\n        x = self.layer1(x)\n        x = self.layer2(x)\n        x = self.layer3(x)\n        x = self.layer4(x)\n        x = self.avgpool(x)\n        x = torch.flatten(x, 1)\n        x = self.fc(x)\n        return x\n\n# Initialize model\nmodel = CustomResNet(num_classes=10).to(DEVICE)\nprint(\"✅ Custom ResNet-like model built successfully.\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-11T20:15:52.614750Z","iopub.execute_input":"2025-10-11T20:15:52.615239Z","iopub.status.idle":"2025-10-11T20:15:52.867902Z","shell.execute_reply.started":"2025-10-11T20:15:52.615214Z","shell.execute_reply":"2025-10-11T20:15:52.867255Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# =====================\n# Cell 5: Losses (Label smoothing), MixUp/CutMix, EMA\n# =====================\nclass LabelSmoothingCE(nn.Module):\n    def __init__(self, smoothing=0.1):\n        super().__init__()\n        self.smoothing = smoothing\n    \n    \n    def forward(self, pred, target):\n        # pred: (B, C), logits; target: (B,) int\n        log_probs = F.log_softmax(pred, dim=-1)\n        n_classes = pred.size(-1)\n        with torch.no_grad():\n            true_dist = torch.zeros_like(pred)\n            true_dist.fill_(self.smoothing / (n_classes - 1))\n            true_dist.scatter_(1, target.unsqueeze(1), 1.0 - self.smoothing)\n        return torch.mean(torch.sum(-true_dist * log_probs, dim=-1))\n\n\ncriterion = LabelSmoothingCE(cfg.label_smoothing)\n\n\n# MixUp & CutMix utilities\n\n\ndef rand_bbox(W, H, lam):\n# for CutMix; returns bbox coords\n    cut_rat = math.sqrt(1.0 - lam)\n    cut_w, cut_h = int(W * cut_rat), int(H * cut_rat)\n    cx = np.random.randint(W)\n    cy = np.random.randint(H)\n    x1 = np.clip(cx - cut_w // 2, 0, W)\n    y1 = np.clip(cy - cut_h // 2, 0, H)\n    x2 = np.clip(cx + cut_w // 2, 0, W)\n    y2 = np.clip(cy + cut_h // 2, 0, H)\n    return x1, y1, x2, y2\n\n\n@torch.no_grad()\ndef update_ema(ema_model, model, decay):\n    msd = model.state_dict()\n    for k, v in ema_model.state_dict().items():\n        if k in msd:\n            ema_model.state_dict()[k].copy_(decay * v + (1 - decay) * msd[k])\n\n\nema_model = None\nif cfg.use_ema:\n    ema_model = CustomResNet(num_classes=10).to(DEVICE)\n    ema_model.load_state_dict(model.state_dict())\n    for p in ema_model.parameters():\n        p.requires_grad_(False)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-11T20:22:01.885103Z","iopub.execute_input":"2025-10-11T20:22:01.885374Z","iopub.status.idle":"2025-10-11T20:22:01.985643Z","shell.execute_reply.started":"2025-10-11T20:22:01.885351Z","shell.execute_reply":"2025-10-11T20:22:01.985013Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# =====================\n# Cell 6: Optimizer & Scheduler (Advanced)\n# =====================\nfrom torch.optim import AdamW\nfrom torch.optim.lr_scheduler import CosineAnnealingLR\n\noptimizer = AdamW(model.parameters(), lr=1e-3, weight_decay=1e-4)\nscheduler = CosineAnnealingLR(optimizer, T_max=cfg.epochs - cfg.warmup_epochs)\n\nscaler = torch.amp.GradScaler('cuda', enabled=(DEVICE.type == 'cuda'))\n\n# Warmup scheduler helper\nclass WarmupScheduler:\n    def __init__(self, optimizer, warmup_epochs, base_lr):\n        self.optimizer = optimizer\n        self.warmup_epochs = warmup_epochs\n        self.base_lr = base_lr\n\n    def set_epoch_lr(self, epoch):\n        if epoch < self.warmup_epochs:\n            lr = self.base_lr * (epoch + 1) / self.warmup_epochs\n            for pg in self.optimizer.param_groups:\n                pg['lr'] = lr\n\nwarmup = WarmupScheduler(optimizer, cfg.warmup_epochs, 1e-3)\nprint(\"✅ AdamW optimizer + cosine annealing with warmup initialized.\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-11T20:23:21.150380Z","iopub.execute_input":"2025-10-11T20:23:21.150953Z","iopub.status.idle":"2025-10-11T20:23:21.157717Z","shell.execute_reply.started":"2025-10-11T20:23:21.150929Z","shell.execute_reply":"2025-10-11T20:23:21.156907Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# =====================\n# Cell 7: Train & Validate loops\n# =====================\n\ndef train_one_epoch(epoch):\n    model.train()\n    running_loss, running_correct, total = 0.0, 0, 0\n\n    for images, targets in train_loader:\n        images, targets = images.to(DEVICE), targets.to(DEVICE)\n\n        # Decide on MixUp/CutMix\n        use_mix = random.random() < cfg.mixup_prob\n        if use_mix:\n            r = random.random()\n            if r < 0.5 and cfg.mixup_alpha > 0:  # MixUp\n                lam = np.random.beta(cfg.mixup_alpha, cfg.mixup_alpha)\n                idx = torch.randperm(images.size(0)).to(DEVICE)\n                mixed = lam * images + (1 - lam) * images[idx]\n                targets_a, targets_b = targets, targets[idx]\n                with torch.cuda.amp.autocast(enabled=(DEVICE.type=='cuda')):\n                    logits = model(mixed)\n                    loss = lam * criterion(logits, targets_a) + (1 - lam) * criterion(logits, targets_b)\n            elif cfg.cutmix_alpha > 0:            # CutMix\n                lam = np.random.beta(cfg.cutmix_alpha, cfg.cutmix_alpha)\n                idx = torch.randperm(images.size(0)).to(DEVICE)\n                x1, y1, x2, y2 = rand_bbox(images.size(3), images.size(2), lam)\n                images2 = images[idx].clone()\n                images[:, :, y1:y2, x1:x2] = images2[:, :, y1:y2, x1:x2]\n                lam = 1 - ((x2 - x1) * (y2 - y1) / (images.size(-1) * images.size(-2)))\n                targets_a, targets_b = targets, targets[idx]\n                with torch.cuda.amp.autocast(enabled=(DEVICE.type=='cuda')):\n                    logits = model(images)\n                    loss = lam * criterion(logits, targets_a) + (1 - lam) * criterion(logits, targets_b)\n            else:\n                with torch.cuda.amp.autocast(enabled=(DEVICE.type=='cuda')):\n                    logits = model(images)\n                    loss = criterion(logits, targets)\n        else:\n            with torch.cuda.amp.autocast(enabled=(DEVICE.type=='cuda')):\n                logits = model(images)\n                loss = criterion(logits, targets)\n\n        optimizer.zero_grad(set_to_none=True)\n        scaler.scale(loss).backward()\n        scaler.step(optimizer)\n        scaler.update()\n\n        if cfg.use_ema:\n            update_ema(ema_model, model, cfg.ema_decay)\n\n        # Metrics\n        with torch.no_grad():\n            preds = logits.argmax(1)\n            running_correct += (preds == targets).sum().item()\n            total += targets.size(0)\n            running_loss += loss.item() * targets.size(0)\n\n    # Scheduler step\n    if epoch < cfg.warmup_epochs:\n        warmup.set_epoch_lr(epoch)\n    else:\n        scheduler.step()\n\n    train_acc = running_correct / total\n    train_loss = running_loss / total\n    return train_loss, train_acc\n\n\n@torch.no_grad()\ndef evaluate(use_ema=True):\n    net = ema_model if (cfg.use_ema and use_ema) else model\n    net.eval()\n    total, correct, running_loss = 0, 0, 0.0\n\n    for images, targets in valid_loader:\n        images, targets = images.to(DEVICE), targets.to(DEVICE)\n        with torch.cuda.amp.autocast(enabled=(DEVICE.type=='cuda')):\n            logits = net(images)\n            loss = criterion(logits, targets)\n        preds = logits.argmax(1)\n        correct += (preds == targets).sum().item()\n        total += targets.size(0)\n        running_loss += loss.item() * targets.size(0)\n\n    return running_loss/total, correct/total","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-11T20:23:25.136150Z","iopub.execute_input":"2025-10-11T20:23:25.136634Z","iopub.status.idle":"2025-10-11T20:23:25.148452Z","shell.execute_reply.started":"2025-10-11T20:23:25.136611Z","shell.execute_reply":"2025-10-11T20:23:25.147794Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# =====================\n# Cell 8: Training loop\n# =====================\nbest_acc = 0.0\nbest_path = os.path.join(cfg.work_dir, 'best_model.pth')\n\nfor epoch in range(cfg.epochs):\n    t0 = time.time()\n    tr_loss, tr_acc = train_one_epoch(epoch)\n    val_loss, val_acc = evaluate(use_ema=True)\n    dt = time.time() - t0\n\n    if val_acc > best_acc:\n        best_acc = val_acc\n        torch.save((ema_model if cfg.use_ema else model).state_dict(), best_path)\n\n    # Print progress\n    current_lr = optimizer.param_groups[0]['lr']\n    print(f\"Epoch {epoch+1:03d}/{cfg.epochs} | lr {current_lr:.5f} | \"\n          f\"train_loss {tr_loss:.4f} acc {tr_acc:.4f} | val_loss {val_loss:.4f} acc {val_acc:.4f} | {dt:.1f}s\")\n\nprint('Best Val Acc:', best_acc)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-11T20:23:29.280366Z","iopub.execute_input":"2025-10-11T20:23:29.280865Z","iopub.status.idle":"2025-10-11T21:56:43.145147Z","shell.execute_reply.started":"2025-10-11T20:23:29.280843Z","shell.execute_reply":"2025-10-11T21:56:43.144213Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# =====================\n# Cell 9: Load best model and evaluate (final estimate of Kaggle score)\n# =====================\nif os.path.exists(best_path):\n    if cfg.use_ema:\n        ema_model.load_state_dict(torch.load(best_path, map_location='cpu'))\n    else:\n        model.load_state_dict(torch.load(best_path, map_location='cpu'))\n\nfinal_loss, final_acc = evaluate(use_ema=True)\nprint(f\"Final (official CIFAR-10 test) — Loss: {final_loss:.4f}, Acc: {final_acc:.4f}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-11T21:57:03.409937Z","iopub.execute_input":"2025-10-11T21:57:03.410658Z","iopub.status.idle":"2025-10-11T21:57:05.624790Z","shell.execute_reply.started":"2025-10-11T21:57:03.410630Z","shell.execute_reply":"2025-10-11T21:57:05.623842Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# =====================\n# Cell 10: Prepare Kaggle test set (from test.7z) — Decompression (Kaggle Only)\n# =====================\n\n!apt -y install libarchive-dev\n!pip install -q libarchive\nimport libarchive.public\ncnt = 0\nfor entry in libarchive.public.file_pour('/kaggle/input/cifar-10/test.7z'):\n     cnt += 1\n     if cnt % 1000 == 0:\n         print(cnt)\nimport glob\nprint('Num files in test/:', len(glob.glob('test/*')))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-11T22:01:37.534324Z","iopub.execute_input":"2025-10-11T22:01:37.535077Z","iopub.status.idle":"2025-10-11T22:02:47.964249Z","shell.execute_reply.started":"2025-10-11T22:01:37.535035Z","shell.execute_reply":"2025-10-11T22:02:47.963337Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# =====================\n# Cell 11: Kaggle test dataset & submission writer\n# =====================\nclass KaggleCIFAR10Test(torch.utils.data.Dataset):\n    def __init__(self, root='test', transform=None):\n        self.root = Path(root)\n        self.files = sorted(self.root.glob('*.png'), key=lambda p: int(p.stem))\n        self.transform = transform if transform is not None else valid_transform\n\n    def __len__(self):\n        return len(self.files)\n\n    def __getitem__(self, idx):\n        p = self.files[idx]\n        img = Image.open(p).convert('RGB')\n        if self.transform:\n            img = self.transform(img)\n        return img, int(p.stem)\n\n@torch.no_grad()\ndef predict_test_and_write_submission(model_to_use=None, out_csv='submission.csv'):\n    net = model_to_use if model_to_use is not None else (ema_model if cfg.use_ema else model)\n    net.eval()\n\n    test_ds = KaggleCIFAR10Test(root='test', transform=valid_transform)\n    test_loader = DataLoader(test_ds, batch_size=cfg.batch_size, shuffle=False,\n                             num_workers=cfg.num_workers, pin_memory=True)\n\n    ids = []\n    labels = []\n    for images, idnums in test_loader:\n        images = images.to(DEVICE)\n        with torch.cuda.amp.autocast(enabled=(DEVICE.type=='cuda')):\n            logits = net(images)\n            preds = logits.argmax(1).detach().cpu().numpy()\n        ids.extend(idnums.numpy().tolist())\n        labels.extend([cfg.classes[p] for p in preds])\n\n    # Write submission\n    import pandas as pd\n    df = pd.DataFrame({'id': ids, 'label': labels})\n    df = df.sort_values('id')\n    df.to_csv(out_csv, index=False)\n    print('Wrote:', out_csv, 'with shape', df.shape)\n\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-11T22:09:25.337845Z","iopub.execute_input":"2025-10-11T22:09:25.338189Z","iopub.status.idle":"2025-10-11T22:09:25.348494Z","shell.execute_reply.started":"2025-10-11T22:09:25.338165Z","shell.execute_reply":"2025-10-11T22:09:25.347699Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"predict_test_and_write_submission(out_csv=cfg.submission_path)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-11T22:09:50.320232Z","iopub.execute_input":"2025-10-11T22:09:50.320836Z","iopub.status.idle":"2025-10-11T22:11:08.481967Z","shell.execute_reply.started":"2025-10-11T22:09:50.320807Z","shell.execute_reply":"2025-10-11T22:11:08.480955Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"!ls -l submission.csv\n!head submission.csv","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-11T22:11:16.548185Z","iopub.execute_input":"2025-10-11T22:11:16.548975Z","iopub.status.idle":"2025-10-11T22:11:16.833823Z","shell.execute_reply.started":"2025-10-11T22:11:16.548949Z","shell.execute_reply":"2025-10-11T22:11:16.832993Z"}},"outputs":[],"execution_count":null}]}