{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.12.13","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":21755,"databundleVersionId":1475600}],"dockerImageVersionId":31401,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ============================================\n# БЫСТРЫЙ САБМИТ (2 ЭПОХИ, ~5 МИНУТ)\n# ============================================\nimport numpy as np\nfrom PIL import Image\nfrom pathlib import Path\nimport torch\nfrom torch.utils.data import Dataset, DataLoader, random_split\nfrom torchvision import transforms\nimport os\nimport shutil\n\n# Пути\nmonet_path = Path(\"/kaggle/input/competitions/gan-getting-started/monet_jpg\")\nphoto_path = Path(\"/kaggle/input/competitions/gan-getting-started/photo_jpg\")\nprint(f\"Моне: {len(list(monet_path.glob('**/*.jpg')))}, Фото: {len(list(photo_path.glob('**/*.jpg')))}\")\n\n# Датасет\nclass MonetPhoto(Dataset):\n    def __init__(self, monet_path, photo_path, transform=None):\n        self.monet_images = list(monet_path.glob(\"**/*.jpg\"))\n        self.photo_images = list(photo_path.glob(\"**/*.jpg\"))\n        self.transform = transform\n\n    def __len__(self):\n        return max(len(self.monet_images), len(self.photo_images))\n\n    def __getitem__(self, idx):\n        monet_image = Image.open(self.monet_images[idx % len(self.monet_images)])\n        photo_image = Image.open(self.photo_images[idx % len(self.photo_images)])\n        if self.transform:\n            monet_image = self.transform(monet_image)\n            photo_image = self.transform(photo_image)\n        return monet_image, photo_image\n\ndevice = \"cuda\" if torch.cuda.is_available() else \"cpu\"\nprint(f\"Device: {device}\")\n\n# Простые модели\nclass Generator(torch.nn.Module):\n    def __init__(self):\n        super().__init__()\n        self.model = torch.nn.Sequential(\n            torch.nn.Conv2d(3, 64, 4, 2, 1, padding_mode='reflect', bias=False, device=device),\n            torch.nn.BatchNorm2d(64, device=device), torch.nn.LeakyReLU(0.2),\n            torch.nn.Conv2d(64, 128, 4, 2, 1, padding_mode='reflect', bias=False, device=device),\n            torch.nn.BatchNorm2d(128, device=device), torch.nn.LeakyReLU(0.2),\n            torch.nn.ConvTranspose2d(128, 64, 4, 2, 1, bias=False, device=device),\n            torch.nn.BatchNorm2d(64, device=device), torch.nn.LeakyReLU(0.2),\n            torch.nn.ConvTranspose2d(64, 3, 4, 2, 1, bias=False, device=device),\n            torch.nn.Tanh()\n        )\n    def forward(self, x): return self.model(x)\n\nclass Discriminator(torch.nn.Module):\n    def __init__(self):\n        super().__init__()\n        self.model = torch.nn.Sequential(\n            torch.nn.Conv2d(3, 64, 4, 2, 1, bias=False, device=device),\n            torch.nn.LeakyReLU(0.2),\n            torch.nn.Conv2d(64, 128, 4, 2, 1, bias=False, device=device),\n            torch.nn.BatchNorm2d(128, device=device), torch.nn.LeakyReLU(0.2),\n            torch.nn.Conv2d(128, 1, 4, 2, 1, bias=False, device=device),\n            torch.nn.LeakyReLU(0.2), torch.nn.Flatten()\n        )\n    def forward(self, x): return self.model(x)\n\n# Данные\ndataset = MonetPhoto(monet_path, photo_path, transform=transforms.Compose([\n    transforms.Resize((128, 128)),\n    transforms.ToTensor(), \n    transforms.Normalize(0.5, 0.5)\n]))\n\ntrain_size = int(len(dataset) * 0.8)\ntraining_data, _ = random_split(dataset, [train_size, len(dataset) - train_size])\ntrain_loader = DataLoader(training_data, batch_size=8, shuffle=True, num_workers=0)\n\n# Модели\ngenerator = Generator()\ndiscriminator = Discriminator()\ng_opt = torch.optim.Adam(generator.parameters(), lr=2e-4, betas=(0.5, 0.999))\nd_opt = torch.optim.Adam(discriminator.parameters(), lr=2e-4, betas=(0.5, 0.999))\n\n# Обучение (2 эпохи)\nprint(\"Обучение 2 эпох...\")\nfor epoch in range(2):\n    for x, y in train_loader:\n        x, y = x.to(device), y.to(device)\n        \n        d_opt.zero_grad()\n        real = discriminator(y)\n        fake = discriminator(generator(x))\n        d_loss = torch.nn.functional.mse_loss(real, torch.ones_like(real)) + \\\n                 torch.nn.functional.mse_loss(fake, torch.zeros_like(fake))\n        d_loss.backward()\n        d_opt.step()\n        \n        g_opt.zero_grad()\n        fake = discriminator(generator(x))\n        g_loss = torch.nn.functional.mse_loss(fake, torch.ones_like(fake))\n        g_loss.backward()\n        g_opt.step()\n    print(f\"Эпоха {epoch+1}/2\")\n\n# Генерация сабмита\nprint(\"Генерация...\")\nos.makedirs('../images', exist_ok=True)\n\nwith torch.no_grad():\n    for i, (img, _) in enumerate(DataLoader(dataset, batch_size=1, shuffle=False)):\n        if i >= 7000: break\n        prediction = generator(img.to(device))[0].cpu().permute(1, 2, 0).numpy()\n        prediction = (prediction * 127.5 + 127.5).clip(0, 255).astype(np.uint8)\n        Image.fromarray(prediction).resize((256, 256)).save(f\"../images/{i}.jpg\")\n        if i % 1000 == 0: print(f\"{i}/7000\")\n\n# Архив\nshutil.make_archive(\"/kaggle/working/images\", 'zip', \"../images\")\nprint(f\"✅ Готово! {os.path.getsize('/kaggle/working/images.zip')/1024/1024:.0f}MB\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-28T12:59:42.655128Z","iopub.execute_input":"2026-05-28T12:59:42.655792Z","iopub.status.idle":"2026-05-28T13:02:08.051995Z","shell.execute_reply.started":"2026-05-28T12:59:42.655766Z","shell.execute_reply":"2026-05-28T13:02:08.051112Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}