{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"pygments_lexer":"ipython3","nbconvert_exporter":"python","version":"3.6.4","file_extension":".py","codemirror_mode":{"name":"ipython","version":3},"name":"python","mimetype":"text/x-python"},"kaggle":{"accelerator":"nvidiaTeslaT4","dataSources":[{"sourceId":3649,"databundleVersionId":46718,"sourceType":"competition"}],"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"# CIFAR-10 Competition - Custom ResNet with Advanced Optimizer & Augmentation\n# Requirements: AdamW optimizer, Cosine Annealing with Warmup, CutMix augmentation\n\n# Cell 1: Install Required Packages and Import Libraries\nimport subprocess\nimport sys\n\n# Install py7zr if not available\ntry:\n    import py7zr\n    print(\"py7zr already available\")\nexcept ImportError:\n    print(\"Installing py7zr...\")\n    subprocess.check_call([sys.executable, '-m', 'pip', 'install', 'py7zr'])\n    import py7zr\n    print(\"py7zr installed successfully\")\n\n# Import other libraries\nimport torch\nimport torch.nn as nn\nimport torch.optim as optim\nimport torch.nn.functional as F\nimport torchvision.transforms as transforms\nfrom torch.utils.data import DataLoader, Dataset, random_split\nimport numpy as np\nimport matplotlib.pyplot as plt\nimport pandas as pd\nfrom tqdm.auto import tqdm\nimport os\nimport zipfile\nimport shutil\nfrom PIL import Image\nimport random\nimport warnings\nimport glob\nimport math\nwarnings.filterwarnings('ignore')\n\n# Set random seeds for reproducibility\ntorch.manual_seed(42)\nnp.random.seed(42)\nrandom.seed(42)\nif torch.cuda.is_available():\n    torch.cuda.manual_seed_all(42)\n\nprint(\"PyTorch version:\", torch.__version__)\nprint(\"CUDA available:\", torch.cuda.is_available())\n\n# Cell 2: Extract Competition Data\nprint(\"=== EXTRACTING COMPETITION DATA ===\")\n\ndef extract_7z_file(file_path, extract_path):\n    \"\"\"Extract .7z file to specified path\"\"\"\n    try:\n        with py7zr.SevenZipFile(file_path, mode='r') as archive:\n            archive.extractall(extract_path)\n        print(f\"Successfully extracted {file_path} to {extract_path}\")\n        return True\n    except Exception as e:\n        print(f\"Failed to extract {file_path}: {e}\")\n        return False\n\n# Create extraction directories\nos.makedirs('/kaggle/working/train_images', exist_ok=True)\nos.makedirs('/kaggle/working/test_images', exist_ok=True)\n\n# Extract training images\ntrain_7z_path = '/kaggle/input/cifar-10/train.7z'\nif os.path.exists(train_7z_path):\n    print(\"Extracting training images...\")\n    extract_7z_file(train_7z_path, '/kaggle/working/train_images')\n\n# Extract test images  \ntest_7z_path = '/kaggle/input/cifar-10/test.7z'\nif os.path.exists(test_7z_path):\n    print(\"Extracting test images...\")\n    extract_7z_file(test_7z_path, '/kaggle/working/test_images')\n\n# Load training labels\ntrain_labels_df = pd.read_csv('/kaggle/input/cifar-10/trainLabels.csv')\nprint(f\"Training labels shape: {train_labels_df.shape}\")\nprint(train_labels_df.head())\n\n# Check extracted data\ntrain_imgs = glob.glob('/kaggle/working/train_images/**/*.png', recursive=True)\ntest_imgs = glob.glob('/kaggle/working/test_images/**/*.png', recursive=True)\nprint(f\"Training images extracted: {len(train_imgs)}\")\nprint(f\"Test images extracted: {len(test_imgs)}\")\n\n# CIFAR-10 class mapping\nCLASSES = ['airplane', 'automobile', 'bird', 'cat', 'deer', \n           'dog', 'frog', 'horse', 'ship', 'truck']\nCLASS_TO_IDX = {cls: idx for idx, cls in enumerate(CLASSES)}\nIDX_TO_CLASS = {idx: cls for idx, cls in enumerate(CLASSES)}\n\n# Cell 3: CutMix Augmentation Implementation\ndef cutmix_data(inputs, targets, alpha=1.0):\n    \"\"\"Apply CutMix augmentation\"\"\"\n    batch_size = inputs.size(0)\n    \n    # Generate random indices for mixing\n    indices = torch.randperm(batch_size).to(inputs.device)\n    shuffled_inputs = inputs[indices]\n    shuffled_targets = targets[indices]\n    \n    # Generate lambda from beta distribution\n    lam = np.random.beta(alpha, alpha)\n    \n    # Generate random box coordinates\n    W = inputs.size(2)\n    H = inputs.size(3)\n    cut_rat = np.sqrt(1.0 - lam)\n    cut_w = int(W * cut_rat)\n    cut_h = int(H * cut_rat)\n    \n    # Uniform sampling of box center\n    cx = np.random.randint(W)\n    cy = np.random.randint(H)\n    \n    bbx1 = np.clip(cx - cut_w // 2, 0, W)\n    bby1 = np.clip(cy - cut_h // 2, 0, H)\n    bbx2 = np.clip(cx + cut_w // 2, 0, W)\n    bby2 = np.clip(cy + cut_h // 2, 0, H)\n    \n    # Apply CutMix\n    inputs[:, :, bbx1:bbx2, bby1:bby2] = shuffled_inputs[:, :, bbx1:bbx2, bby1:bby2]\n    \n    # Adjust lambda based on actual box size\n    lam = 1 - ((bbx2 - bbx1) * (bby2 - bby1) / (W * H))\n    \n    return inputs, targets, shuffled_targets, lam\n\n# Cell 4: Competition Dataset Classes with CutOut\nclass Cutout:\n    \"\"\"Cutout data augmentation\"\"\"\n    def __init__(self, n_holes=1, length=16):\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\n        for _ in range(self.n_holes):\n            y = np.random.randint(h)\n            x = np.random.randint(w)\n\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\n            mask[y1:y2, x1:x2] = 0.\n\n        mask = torch.from_numpy(mask)\n        mask = mask.expand_as(img)\n        img = img * mask\n\n        return img\n\nclass CompetitionCIFAR10Dataset(Dataset):\n    \"\"\"Dataset class for competition CIFAR-10 images\"\"\"\n    \n    def __init__(self, image_dir, labels_df=None, transform=None):\n        self.image_dir = image_dir\n        self.transform = transform\n        self.labels_df = labels_df\n        \n        # Get all image files\n        self.image_files = []\n        for root, dirs, files in os.walk(image_dir):\n            for file in files:\n                if file.lower().endswith('.png'):\n                    self.image_files.append(os.path.join(root, file))\n        \n        self.image_files = sorted(self.image_files)\n        \n        # Create filename to label mapping for training\n        if labels_df is not None:\n            self.filename_to_label = {}\n            for idx, row in labels_df.iterrows():\n                filename = f\"{row['id']}.png\"\n                label = row['label']\n                self.filename_to_label[filename] = CLASS_TO_IDX[label]\n        \n        print(f\"Dataset created with {len(self.image_files)} images\")\n        \n    def __len__(self):\n        return len(self.image_files)\n    \n    def __getitem__(self, idx):\n        img_path = self.image_files[idx]\n        \n        try:\n            # Load image\n            image = Image.open(img_path).convert('RGB')\n            \n            # Apply transforms\n            if self.transform:\n                image = self.transform(image)\n            \n            # Get label if available (training)\n            if self.labels_df is not None:\n                filename = os.path.basename(img_path)\n                if filename in self.filename_to_label:\n                    label = self.filename_to_label[filename]\n                else:\n                    label = 0  # Default label if not found\n                return image, label\n            else:\n                # Test set - return dummy label\n                return image, 0\n                \n        except Exception as e:\n            print(f\"Error loading image {img_path}: {e}\")\n            # Return a black image if loading fails\n            if self.transform:\n                dummy_image = self.transform(Image.new('RGB', (32, 32), color=(0, 0, 0)))\n            else:\n                dummy_image = Image.new('RGB', (32, 32), color=(0, 0, 0))\n            return dummy_image, 0\n\n# Cell 5: Enhanced Data Preprocessing with Advanced Augmentation\nMEAN = (0.485, 0.456, 0.406)\nSTD = (0.229, 0.224, 0.225)\n\n# Training transforms with ADVANCED augmentation including CutOut\ntrain_transform = transforms.Compose([\n    transforms.Resize((32, 32)),\n    transforms.RandomCrop(32, padding=4),\n    transforms.RandomHorizontalFlip(p=0.5),\n    transforms.RandomRotation(15),\n    transforms.ColorJitter(brightness=0.3, contrast=0.3, saturation=0.3, hue=0.1),\n    transforms.RandomGrayscale(p=0.05),\n    transforms.ToTensor(),\n    transforms.Normalize(MEAN, STD),\n    Cutout(n_holes=1, length=16),  # CutOut augmentation\n    transforms.RandomErasing(p=0.2, scale=(0.02, 0.15))\n])\n\n# Test transforms (no augmentation)\ntest_transform = transforms.Compose([\n    transforms.Resize((32, 32)),\n    transforms.ToTensor(),\n    transforms.Normalize(MEAN, STD)\n])\n\n# Cell 6: Create Datasets and Data Loaders\nprint(\"=== CREATING DATASETS ===\")\n\n# Create training dataset using competition images\ntrain_dataset = CompetitionCIFAR10Dataset(\n    image_dir='/kaggle/working/train_images',\n    labels_df=train_labels_df,\n    transform=train_transform\n)\n\n# Create train/validation split\ntrain_size = int(0.9 * len(train_dataset))\nval_size = len(train_dataset) - train_size\ntrain_subset, val_subset = random_split(train_dataset, [train_size, val_size])\n\n# Create separate validation dataset with test transforms\nval_dataset = CompetitionCIFAR10Dataset(\n    image_dir='/kaggle/working/train_images',\n    labels_df=train_labels_df,\n    transform=test_transform\n)\n\n# Create validation subset\nclass SubsetDataset(Dataset):\n    def __init__(self, dataset, indices):\n        self.dataset = dataset\n        self.indices = indices\n    \n    def __len__(self):\n        return len(self.indices)\n    \n    def __getitem__(self, idx):\n        return self.dataset[self.indices[idx]]\n\nval_dataset_subset = SubsetDataset(val_dataset, val_subset.indices)\n\n# Create test dataset\ntest_dataset = CompetitionCIFAR10Dataset(\n    image_dir='/kaggle/working/test_images',\n    labels_df=None,\n    transform=test_transform\n)\n\nprint(f\"Training samples: {len(train_subset)}\")\nprint(f\"Validation samples: {len(val_dataset_subset)}\")\nprint(f\"Test samples: {len(test_dataset)}\")\n\n# Create data loaders\nBATCH_SIZE = 128\ntrain_loader = DataLoader(train_subset, batch_size=BATCH_SIZE, shuffle=True, num_workers=0, pin_memory=True)\nval_loader = DataLoader(val_dataset_subset, batch_size=BATCH_SIZE, shuffle=False, num_workers=0, pin_memory=True)\ntest_loader = DataLoader(test_dataset, batch_size=BATCH_SIZE, shuffle=False, num_workers=0, pin_memory=True)\n\nprint(\"Data loaders created successfully!\")\n\n# Cell 7: Custom ResNet Architecture\nclass CustomResidualBlock(nn.Module):\n    \"\"\"Custom residual block with residual connections\"\"\"\n    def __init__(self, in_channels, out_channels, stride=1, downsample=None):\n        super(CustomResidualBlock, self).__init__()\n        \n        self.conv1 = nn.Conv2d(in_channels, out_channels, kernel_size=3, \n                              stride=stride, padding=1, bias=False)\n        self.bn1 = nn.BatchNorm2d(out_channels)\n        \n        self.conv2 = nn.Conv2d(out_channels, out_channels, kernel_size=3,\n                              stride=1, padding=1, bias=False)\n        self.bn2 = nn.BatchNorm2d(out_channels)\n        \n        self.downsample = downsample\n        \n    def forward(self, x):\n        identity = x\n        \n        out = self.conv1(x)\n        out = self.bn1(out)\n        out = F.relu(out)\n        \n        out = self.conv2(out)\n        out = self.bn2(out)\n        \n        if self.downsample is not None:\n            identity = self.downsample(x)\n        \n        out += identity  # Residual connection\n        out = F.relu(out)\n        \n        return out\n\nclass CustomResNet(nn.Module):\n    \"\"\"Custom ResNet architecture built from basic layers\"\"\"\n    def __init__(self, block_class, layers, num_classes=10):\n        super(CustomResNet, self).__init__()\n        self.in_channels = 64\n        \n        self.conv1 = nn.Conv2d(3, 64, kernel_size=3, stride=1, padding=1, bias=False)\n        self.bn1 = nn.BatchNorm2d(64)\n        \n        self.layer1 = self._make_layer(block_class, 64, layers[0], stride=1)\n        self.layer2 = self._make_layer(block_class, 128, layers[1], stride=2)\n        self.layer3 = self._make_layer(block_class, 256, layers[2], stride=2)\n        self.layer4 = self._make_layer(block_class, 512, layers[3], stride=2)\n        \n        self.avgpool = nn.AdaptiveAvgPool2d((1, 1))\n        self.fc = nn.Linear(512, num_classes)\n        \n        self._initialize_weights()\n        \n    def _make_layer(self, block_class, out_channels, num_blocks, stride=1):\n        downsample = None\n        \n        if stride != 1 or self.in_channels != out_channels:\n            downsample = nn.Sequential(\n                nn.Conv2d(self.in_channels, out_channels, kernel_size=1, \n                         stride=stride, bias=False),\n                nn.BatchNorm2d(out_channels)\n            )\n        \n        layers = []\n        layers.append(block_class(self.in_channels, out_channels, stride, downsample))\n        self.in_channels = out_channels\n        \n        for _ in range(1, num_blocks):\n            layers.append(block_class(self.in_channels, out_channels))\n        \n        return nn.Sequential(*layers)\n    \n    def _initialize_weights(self):\n        \"\"\"Random weight initialization\"\"\"\n        for m in self.modules():\n            if isinstance(m, nn.Conv2d):\n                nn.init.kaiming_normal_(m.weight, mode='fan_out', nonlinearity='relu')\n            elif isinstance(m, nn.BatchNorm2d):\n                nn.init.constant_(m.weight, 1)\n                nn.init.constant_(m.bias, 0)\n            elif isinstance(m, nn.Linear):\n                nn.init.normal_(m.weight, 0, 0.01)\n                nn.init.constant_(m.bias, 0)\n    \n    def forward(self, x):\n        out = F.relu(self.bn1(self.conv1(x)))\n        \n        out = self.layer1(out)\n        out = self.layer2(out)\n        out = self.layer3(out)\n        out = self.layer4(out)\n        \n        out = self.avgpool(out)\n        out = out.view(out.size(0), -1)\n        out = self.fc(out)\n        return out\n\ndef create_custom_resnet():\n    \"\"\"Create custom ResNet-50 architecture\"\"\"\n    return CustomResNet(CustomResidualBlock, [3, 4, 6, 3])\n\n# Cell 8: Model Initialization with AdamW Optimizer\ndevice = torch.device('cuda' if torch.cuda.is_available() else 'cpu')\nprint(f\"Using device: {device}\")\n\n# Create model\nmodel = create_custom_resnet().to(device)\n\ndef count_residual_blocks(model):\n    count = 0\n    for module in model.modules():\n        if isinstance(module, CustomResidualBlock):\n            count += 1\n    return count\n\ntotal_params = sum(p.numel() for p in model.parameters() if p.requires_grad)\nresidual_blocks = count_residual_blocks(model)\n\nprint(f\"Total trainable parameters: {total_params:,}\")\n\nprint(\"\\n=== NEW REQUIREMENTS VERIFICATION ===\")\nprint(\"✓ Random weight initialization (no pre-trained weights)\")\nprint(\"✓ Advanced optimizer: AdamW with weight decay\")\nprint(\"✓ Cosine annealing learning rate with warmup\")\nprint(\"✓ Advanced augmentation: CutOut + CutMix\")\nprint(f\"✓ Custom ResNet with {residual_blocks} residual blocks\")\n\n# Cell 9: Cosine Annealing with Warmup Scheduler\nclass CosineAnnealingWarmupRestarts:\n    \"\"\"Cosine annealing with linear warmup\"\"\"\n    def __init__(self, optimizer, warmup_epochs, max_epochs, eta_min=0):\n        self.optimizer = optimizer\n        self.warmup_epochs = warmup_epochs\n        self.max_epochs = max_epochs\n        self.eta_min = eta_min\n        self.base_lr = optimizer.param_groups[0]['lr']\n        \n    def step(self, epoch):\n        if epoch < self.warmup_epochs:\n            # Linear warmup\n            lr = self.base_lr * (epoch + 1) / self.warmup_epochs\n        else:\n            # Cosine annealing\n            progress = (epoch - self.warmup_epochs) / (self.max_epochs - self.warmup_epochs)\n            lr = self.eta_min + (self.base_lr - self.eta_min) * 0.5 * (1 + math.cos(math.pi * progress))\n        \n        for param_group in self.optimizer.param_groups:\n            param_group['lr'] = lr\n        \n        return lr\n\n# Setup optimizer and scheduler\ncriterion = nn.CrossEntropyLoss(label_smoothing=0.1)\n\n# ADVANCED OPTIMIZER: AdamW with weight decay\noptimizer = optim.AdamW(model.parameters(), lr=0.001, weight_decay=0.05, betas=(0.9, 0.999))\n\n# COSINE ANNEALING WITH WARMUP\nNUM_EPOCHS = 150\nWARMUP_EPOCHS = 10\nscheduler = CosineAnnealingWarmupRestarts(optimizer, warmup_epochs=WARMUP_EPOCHS, max_epochs=NUM_EPOCHS, eta_min=1e-6)\n\nprint(\"Training setup completed!\")\nprint(f\"Optimizer: AdamW (lr=0.001, weight_decay=0.05)\")\nprint(f\"Scheduler: Cosine Annealing with {WARMUP_EPOCHS}-epoch warmup\")\nprint(f\"Augmentation: CutOut + CutMix\")\n\n# Cell 10: Training Functions with CutMix\ndef train_epoch_with_cutmix(model, dataloader, criterion, optimizer, scheduler, epoch, device):\n    model.train()\n    running_loss = 0.0\n    correct = 0\n    total = 0\n    \n    progress_bar = tqdm(dataloader, desc=\"Training\", leave=False)\n    for batch_idx, (inputs, targets) in enumerate(progress_bar):\n        inputs, targets = inputs.to(device), targets.to(device)\n        \n        # Apply CutMix using the cutmix_data function\n        r = np.random.rand()\n        if r < 0.5:  # 50% chance to apply CutMix\n            inputs, targets_a, targets_b, lam = cutmix_data(inputs, targets, alpha=1.0)\n            \n            optimizer.zero_grad()\n            outputs = model(inputs)\n            loss = criterion(outputs, targets_a) * lam + criterion(outputs, targets_b) * (1 - lam)\n        else:\n            optimizer.zero_grad()\n            outputs = model(inputs)\n            loss = criterion(outputs, targets)\n        \n        loss.backward()\n        torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm=1.0)\n        optimizer.step()\n        \n        running_loss += loss.item()\n        _, predicted = outputs.max(1)\n        total += targets.size(0)\n        correct += predicted.eq(targets).sum().item()\n        \n        progress_bar.set_postfix({\n            'Loss': f'{running_loss/(batch_idx+1):.3f}',\n            'Acc': f'{100.*correct/total:.2f}%'\n        })\n    \n    return running_loss / len(dataloader), 100. * correct / total\n\ndef validate(model, dataloader, criterion, device):\n    model.eval()\n    running_loss = 0.0\n    correct = 0\n    total = 0\n    \n    with torch.no_grad():\n        progress_bar = tqdm(dataloader, desc=\"Validation\", leave=False)\n        for batch_idx, (inputs, targets) in enumerate(progress_bar):\n            inputs, targets = inputs.to(device), targets.to(device)\n            outputs = model(inputs)\n            loss = criterion(outputs, targets)\n            \n            running_loss += loss.item()\n            _, predicted = outputs.max(1)\n            total += targets.size(0)\n            correct += predicted.eq(targets).sum().item()\n            \n            progress_bar.set_postfix({\n                'Loss': f'{running_loss/(batch_idx+1):.3f}',\n                'Acc': f'{100.*correct/total:.2f}%'\n            })\n    \n    return running_loss / len(dataloader), 100. * correct / total\n\n# Cell 11: Main Training Loop\nbest_acc = 0\ntrain_losses, train_accs = [], []\nval_losses, val_accs = [], []\npatience_counter = 0\nPATIENCE = 25\n\nprint(\"\\n\" + \"=\"*70)\nprint(\"STARTING TRAINING WITH ADVANCED TECHNIQUES\")\nprint(\"=\"*70)\nprint(f\"Optimizer: AdamW\")\nprint(f\"LR Schedule: Cosine Annealing with Warmup\")\nprint(f\"Augmentation: CutOut + CutMix\")\nprint(f\"Total epochs: {NUM_EPOCHS}\")\n\nfor epoch in range(NUM_EPOCHS):\n    # Update learning rate with warmup\n    current_lr = scheduler.step(epoch)\n    \n    print(f'\\nEpoch {epoch+1}/{NUM_EPOCHS}')\n    print(f'Learning Rate: {current_lr:.6f}')\n    \n    # Train and validate\n    train_loss, train_acc = train_epoch_with_cutmix(model, train_loader, criterion, optimizer, scheduler, epoch, device)\n    val_loss, val_acc = validate(model, val_loader, criterion, device)\n    \n    # Save metrics\n    train_losses.append(train_loss)\n    train_accs.append(train_acc)\n    val_losses.append(val_loss)\n    val_accs.append(val_acc)\n    \n    # Save best model\n    if val_acc > best_acc:\n        best_acc = val_acc\n        patience_counter = 0\n        torch.save({\n            'epoch': epoch,\n            'model_state_dict': model.state_dict(),\n            'optimizer_state_dict': optimizer.state_dict(),\n            'best_acc': best_acc,\n        }, '/kaggle/working/best_model_advanced.pth')\n        print(f'✓ NEW BEST: {best_acc:.2f}% validation accuracy')\n    else:\n        patience_counter += 1\n    \n    print(f'Train: Loss={train_loss:.4f}, Acc={train_acc:.2f}%')\n    print(f'Val:   Loss={val_loss:.4f}, Acc={val_acc:.2f}%')\n    print(f'Best:  {best_acc:.2f}%')\n    \n    # Early stopping\n    if patience_counter >= PATIENCE:\n        print(f\"Early stopping triggered after {epoch+1} epochs\")\n        break\n    \n    # Target notification\n    if best_acc >= 94.2:\n        print(\"TARGET ACHIEVED! >=94.2% validation accuracy\")\n\nprint(f\"\\nTraining completed! Best validation accuracy: {best_acc:.2f}%\")\n\n# Cell 12: Generate Competition Submission\nprint(\"\\n=== GENERATING COMPETITION SUBMISSION ===\")\n\n# Load best model\ncheckpoint = torch.load('/kaggle/working/best_model_advanced.pth')\nmodel.load_state_dict(checkpoint['model_state_dict'])\n\nprint(f\"Making predictions on {len(test_dataset)} test images...\")\n\n# Generate predictions\nmodel.eval()\nall_predictions = []\nimage_ids = []\n\ntest_image_paths = test_dataset.image_files\nfor img_path in test_image_paths:\n    filename = os.path.basename(img_path)\n    img_id = int(filename.split('.')[0])\n    image_ids.append(img_id)\n\nwith torch.no_grad():\n    for i, (inputs, _) in enumerate(tqdm(test_loader, desc=\"Predicting\")):\n        inputs = inputs.to(device)\n        outputs = model(inputs)\n        _, predicted = outputs.max(1)\n        all_predictions.extend(predicted.cpu().numpy())\n\nassert len(all_predictions) == len(image_ids), f\"Mismatch: {len(all_predictions)} predictions vs {len(image_ids)} images\"\n\nprint(f\"Generated {len(all_predictions)} predictions\")\n\n# Create submission file\ntext_predictions = [CLASSES[pred] for pred in all_predictions]\nsubmission_data = list(zip(image_ids, text_predictions))\nsubmission_df = pd.DataFrame(submission_data, columns=['id', 'label'])\nsubmission_df = submission_df.sort_values('id').reset_index(drop=True)\n\nprint(f\"\\nSubmission shape: {submission_df.shape}\")\nprint(f\"ID range: {submission_df['id'].min()} to {submission_df['id'].max()}\")\nprint(\"\\nFirst 10 predictions:\")\nprint(submission_df.head(10))\n\n# Save submission\nsubmission_df.to_csv('/kaggle/working/submission.csv', index=False)\nprint(f\"\\n✅ SUBMISSION FILE SAVED: /kaggle/working/submission.csv\")\n\n# Cell 13: Final Summary\nprint(\"\\n\" + \"=\"*70)\nprint(\"FINAL REQUIREMENTS SUMMARY\")\nprint(\"=\"*70)\n\nprint(\"\\n✅ ALL NEW REQUIREMENTS MET:\")\nprint(\"   → Random weight initialization: ✓\")\nprint(\"   → Advanced optimizer (AdamW): ✓\")\nprint(\"   → Cosine annealing with warmup: ✓\")\nprint(\"   → Advanced augmentation (CutOut + CutMix): ✓\")\nprint(\"   → Custom neural network design: ✓\")\n\nprint(f\"\\n📊 PERFORMANCE:\")\nprint(f\"   → Best Validation Accuracy: {best_acc:.2f}%\")\nprint(f\"   → Target Score (>=94.2%): {'✓ ACHIEVED' if best_acc >= 94.2 else '✗ NOT YET'}\")\n\nprint(f\"\\n🔧 TECHNICAL DETAILS:\")\nprint(f\"   → Optimizer: AdamW (lr=0.001, weight_decay=0.05)\")\nprint(f\"   → LR Schedule: Cosine annealing with {WARMUP_EPOCHS}-epoch warmup\")\nprint(f\"   → Data Augmentation: CutOut + CutMix\")\nprint(f\"   → Architecture: Custom ResNet with {residual_blocks} residual blocks\")\nprint(f\"   → Total parameters: {total_params:,}\")\n\nprint(f\"\\n📁 OUTPUT FILES:\")\nprint(f\"   → best_model_advanced.pth\")\nprint(f\"   → submission.csv (300,000 predictions)\")\n\nprint(\"=\"*70)\nprint(\"Ready for Kaggle submission with advanced techniques!\")\nprint(\"=\"*70)","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}