{"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":21755,"databundleVersionId":1475600,"sourceType":"competition"}],"dockerImageVersionId":31193,"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,"execution":{"iopub.status.busy":"2025-12-08T01:12:37.035352Z","iopub.execute_input":"2025-12-08T01:12:37.035638Z","iopub.status.idle":"2025-12-08T01:12:50.020619Z","shell.execute_reply.started":"2025-12-08T01:12:37.03561Z","shell.execute_reply":"2025-12-08T01:12:50.019813Z"},"collapsed":true,"jupyter":{"outputs_hidden":true}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\nimport pandas as pd\nimport zipfile\nimport glob\nfrom PIL import Image\n%matplotlib inline\nimport matplotlib.pyplot as plt\nimport math\nimport numpy as np","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-08T01:12:50.02189Z","iopub.execute_input":"2025-12-08T01:12:50.022212Z","iopub.status.idle":"2025-12-08T01:12:50.026874Z","shell.execute_reply.started":"2025-12-08T01:12:50.022191Z","shell.execute_reply":"2025-12-08T01:12:50.026181Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"monet_path=os.path.join(r\"/kaggle/input/gan-getting-started\",\"monet_jpg\")\nphoto_path=os.path.join(r\"/kaggle/input/gan-getting-started\",\"photo_jpg\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-08T01:12:50.027614Z","iopub.execute_input":"2025-12-08T01:12:50.027874Z","iopub.status.idle":"2025-12-08T01:12:50.041683Z","shell.execute_reply.started":"2025-12-08T01:12:50.027851Z","shell.execute_reply":"2025-12-08T01:12:50.040906Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# 数据集搭建\nimport torch\nfrom torch import nn\nimport torchvision\nfrom torchvision import transforms\nfrom torch.utils.data import DataLoader,Dataset\nimport random\n\nclass MonetDataset(Dataset):\n    def __init__(self,monet_path,photo_path,size=(256,256)):\n        super().__init__()\n        random.seed(None)\n        self.monet_path=glob.glob(monet_path+\"/*\")\n        self.photo_path=glob.glob(photo_path+\"/*\")\n        random.shuffle(self.monet_path)\n        random.shuffle(self.photo_path)\n        self.transforms=transforms.Compose([\n            transforms.ToTensor(),\n            transforms.Resize(size),\n            transforms.Normalize([0.5,0.5,0.5],[0.5,0.5,0.5])\n        ])\n        random.seed(42)\n    def __len__(self):\n        return min(len(self.monet_path),len(self.photo_path))\n\n    def __getitem__(self,idx):\n        monet_img=self.transforms(Image.open(self.monet_path[idx]))\n        photo_img=self.transforms(Image.open(self.photo_path[idx]))\n        return monet_img,photo_img","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-08T01:12:50.043102Z","iopub.execute_input":"2025-12-08T01:12:50.043308Z","iopub.status.idle":"2025-12-08T01:12:56.275439Z","shell.execute_reply.started":"2025-12-08T01:12:50.043293Z","shell.execute_reply":"2025-12-08T01:12:56.274647Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def reverse_img(img,mean=[0.5]*3,std=[0.5]*3):\n    for img_channel,mean_channel,std_channel in zip(img,mean,std):\n        img_channel.mul_(std_channel).add_(mean_channel)\n    return img","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-08T01:12:56.276217Z","iopub.execute_input":"2025-12-08T01:12:56.276547Z","iopub.status.idle":"2025-12-08T01:12:56.280582Z","shell.execute_reply.started":"2025-12-08T01:12:56.276519Z","shell.execute_reply":"2025-12-08T01:12:56.279893Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class Upsample_block(nn.Module):\n    def __init__(self,in_ch,out_ch,dropout_ratio=0.5):\n        super().__init__()\n        self.upsample=nn.Upsample(scale_factor=2,mode=\"nearest\")\n        self.conv=nn.Conv2d(in_ch,out_ch,kernel_size=3,stride=1,padding=1)\n        self.norm=nn.InstanceNorm2d(out_ch)\n        self.dropout=nn.Dropout(dropout_ratio)\n        self.activation=nn.GELU()\n    def forward(self,X):\n        return self.activation(self.dropout(self.norm(self.conv(self.upsample(X)))))\n\nclass Conv_block(nn.Module):\n    def __init__(self,in_ch,out_ch,kernel_size=3,padding=1,stride=2):\n        super().__init__()\n        self.conv_layer=nn.Conv2d(in_ch,out_ch,kernel_size,stride=stride,padding=padding)\n        self.activation=nn.GELU()\n        self.norm=nn.InstanceNorm2d(out_ch)\n    def forward(self,X):\n        return self.activation(self.norm(self.conv_layer(X)))\n\nclass Res_Block(nn.Module):\n    def __init__(self,ch):\n        super().__init__()\n        self.pad=nn.ReflectionPad2d(1)\n        self.conv=nn.Conv2d(ch,ch,kernel_size=3,stride=1,padding=0)\n        self.norm=nn.InstanceNorm2d(ch)\n        self.activation=nn.GELU()\n        self.dropout=nn.Dropout(0.4)\n    def forward(self,X):\n        X1=self.dropout(self.activation(self.norm(self.conv(self.pad(X)))))\n        X2=self.dropout(self.activation(self.norm(self.conv(self.pad(X1)))))\n        return X2+X","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-08T01:12:56.281235Z","iopub.execute_input":"2025-12-08T01:12:56.281534Z","iopub.status.idle":"2025-12-08T01:12:56.299627Z","shell.execute_reply.started":"2025-12-08T01:12:56.281508Z","shell.execute_reply":"2025-12-08T01:12:56.298966Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class Generator(nn.Module):\n    def __init__(self,in_ch,out_ch,ResBlock_num=6):\n        super().__init__()\n        self.model=nn.Sequential(nn.ReflectionPad2d(3),\n                           Conv_block(in_ch,64,7,stride=1,padding=0),\n                           Conv_block(64,128,3,stride=2,padding=1),\n                           Conv_block(128,256,3,stride=2,padding=1),\n                            # 抽取特征\n                            *[Res_Block(256) for _ in range(ResBlock_num)],\n                            # 上采样\n                            Upsample_block(256,128),\n                            Upsample_block(128,64),\n                            #抽取全局特征\n                            nn.ReflectionPad2d(3),\n                            nn.Conv2d(64,out_ch,7,stride=1,padding=0),\n                            nn.Tanh()\n                           )\n    def forward(self,X):\n        return self.model(X)\n# PatchGAN\n\nclass Discriminator(nn.Module):\n    def __init__(self,in_ch,num_layers=3):\n        super().__init__()\n        model=nn.Sequential(\n            nn.Conv2d(in_ch,64,4,stride=2,padding=1),\n            nn.GELU(),\n        )\n        for i in range(1,num_layers+1):\n            in_ch=64*(2**(i-1))\n            out_ch=in_ch*2\n            if i ==num_layers:\n                model.append(Conv_block(in_ch,out_ch,4,2))\n            else :\n                model.append(Conv_block(in_ch,out_ch,4,1))\n        model.append(nn.Conv2d(2**(num_layers)*64,1,4,stride=1,padding=1))\n        self.model=model\n    def forward(self,X):\n        return self.model(X)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-08T01:12:56.300298Z","iopub.execute_input":"2025-12-08T01:12:56.300531Z","iopub.status.idle":"2025-12-08T01:12:56.3175Z","shell.execute_reply.started":"2025-12-08T01:12:56.300514Z","shell.execute_reply":"2025-12-08T01:12:56.316944Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def init_weight(m):\n    class_name=m.__class__.__name__\n    if class_name in [\"Conv2d\"]:\n        nn.init.kaiming_normal_(m.weight,mode=\"fan_out\",nonlinearity=\"relu\")\n        if m.bias is not None:\n            nn.init.zeros_(m.bias)\n    if class_name==\"Conv2d\" and m.out_channels==3:\n        nn.init.normal_(m.weight,std=0.02)\n        if m.bias is not None:\n            nn.init.zeros_(m.bias)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-08T01:12:56.318293Z","iopub.execute_input":"2025-12-08T01:12:56.318533Z","iopub.status.idle":"2025-12-08T01:12:56.334181Z","shell.execute_reply.started":"2025-12-08T01:12:56.318512Z","shell.execute_reply":"2025-12-08T01:12:56.333613Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class sample_fake(object):\n    def __init__(self, max_imgs=50):\n        self.max_imgs = max_imgs\n        self.imgs = []\n\n    def __call__(self, imgs):\n        # imgs: (batch, C, H, W)\n        ret = []\n        for img in imgs:\n            if len(self.imgs) < self.max_imgs:\n                self.imgs.append(img)\n                ret.append(img)\n            else:\n                if np.random.rand() > 0.5:\n                    idx = np.random.randint(0, self.max_imgs)\n                    ret.append(self.imgs[idx])\n                    self.imgs[idx] = img\n                else:\n                    ret.append(img)\n        # 返回 batch tensor，保证 shape 一致\n        return torch.stack(ret)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-08T01:12:56.334812Z","iopub.execute_input":"2025-12-08T01:12:56.334971Z","iopub.status.idle":"2025-12-08T01:12:56.347797Z","shell.execute_reply.started":"2025-12-08T01:12:56.334959Z","shell.execute_reply":"2025-12-08T01:12:56.347108Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class lr_sched():\n    def __init__(self, decay_epochs=100, total_epochs=200):\n        self.decay_epochs = decay_epochs\n        self.total_epochs = total_epochs\n\n    def step(self, epoch_num):\n        if epoch_num <= self.decay_epochs:\n            return 1.0\n        else:\n            fract = (epoch_num - self.decay_epochs)  / (self.total_epochs - self.decay_epochs)\n            return 1.0 - fract","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-08T01:12:56.350293Z","iopub.execute_input":"2025-12-08T01:12:56.350476Z","iopub.status.idle":"2025-12-08T01:12:56.364923Z","shell.execute_reply.started":"2025-12-08T01:12:56.350462Z","shell.execute_reply":"2025-12-08T01:12:56.364194Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class Accumulator:\n    def __init__(self,num):\n        self.metric=[0]*num\n    def __getitem__(self,idx):\n        return self.metric[idx]\n    def add(self,*args):\n        if args:\n            for i,arg in enumerate(args):\n                self.metric[i]+=arg\n\nclass Recorder:\n    def __init__(self,num):\n        self.metric=[[] for _ in range(num)]\n    def __getitem__(self,idx):\n        return self.metric[idx]\n    def __len__(self):\n        return len(self.metric)\n    def add(self,*args):\n        if args:\n            for i,arg in enumerate(args):\n                self.metric[i].append(arg)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-08T01:12:56.365719Z","iopub.execute_input":"2025-12-08T01:12:56.365969Z","iopub.status.idle":"2025-12-08T01:12:56.378493Z","shell.execute_reply.started":"2025-12-08T01:12:56.365948Z","shell.execute_reply":"2025-12-08T01:12:56.377843Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def Frozen(nets,training=True):\n    for net in nets:\n        for param in net.parameters():\n                param.requires_grad=training","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-08T01:12:56.379224Z","iopub.execute_input":"2025-12-08T01:12:56.379844Z","iopub.status.idle":"2025-12-08T01:12:56.392449Z","shell.execute_reply.started":"2025-12-08T01:12:56.379822Z","shell.execute_reply":"2025-12-08T01:12:56.391884Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# 采用混合精度训练\nfrom torch import amp\ntorch.backends.cudnn.benchmark=True\ntorch.backends.cuda.matmul.allow_tf32=True\ntorch.backends.cudnn.allow_tf32=True","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-08T01:12:56.393455Z","iopub.execute_input":"2025-12-08T01:12:56.393701Z","iopub.status.idle":"2025-12-08T01:12:56.405844Z","shell.execute_reply.started":"2025-12-08T01:12:56.39368Z","shell.execute_reply":"2025-12-08T01:12:56.405045Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import time\n\ndef show_img(transformed_imgs, true_imgs):\n    plt.figure(figsize=(8, 4))\n\n    plt.subplot(121)\n    plt.imshow(transformed_imgs[-1])\n    plt.axis(\"off\")\n    plt.title(\"Generated\")\n\n    plt.subplot(122)\n    plt.imshow(true_imgs[-1])\n    plt.axis(\"off\")\n    plt.title(\"True\")\n\n    plt.tight_layout()\n    plt.show()\n\n    time.sleep(2)\n    plt.close()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-08T01:12:56.406502Z","iopub.execute_input":"2025-12-08T01:12:56.407022Z","iopub.status.idle":"2025-12-08T01:12:56.424091Z","shell.execute_reply.started":"2025-12-08T01:12:56.407Z","shell.execute_reply":"2025-12-08T01:12:56.423355Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def show_chart(net):\n    series=np.arange(len(net.record_metric[0]))\n    plt.plot(series,net.record_metric[0],\"r-\",label=\"G_loss\")\n    plt.plot(series,net.record_metric[1],\"b-\",label=\"D_loss\")\n    plt.legend()\n    plt.yscale(\"log\")\n    plt.xscale(\"log\")\n    plt.xlabel(\"epochs\")\n    plt.ylabel(\"loss\")\n    plt.title(\"loss curve\")\n    plt.savefig(\".\\Storage\\loss_curve.png\")\n    plt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-08T01:12:56.424812Z","iopub.execute_input":"2025-12-08T01:12:56.425047Z","iopub.status.idle":"2025-12-08T01:12:56.445716Z","shell.execute_reply.started":"2025-12-08T01:12:56.425028Z","shell.execute_reply":"2025-12-08T01:12:56.445075Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\nimport torch\n\ndef save_generator_only(net, save_dir=\"./Storage\"):\n    os.makedirs(save_dir, exist_ok=True)                    \n    torch.save(net.G_Monet2Photo.state_dict(), \n               os.path.join(save_dir, \"G_Monet2Photo.pth\"))\n    \n    torch.save(net.G_Photo2Monet.state_dict(), \n               os.path.join(save_dir, \"G_Photo2Monet.pth\"))\n    \n    print(f\"生成器已成功保存到 {save_dir}/ 目录\")\n    print(\"  ├─ G_Monet2Photo.pth\")\n    print(\"  └─ G_Photo2Monet.pth\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-08T01:12:56.447132Z","iopub.execute_input":"2025-12-08T01:12:56.447459Z","iopub.status.idle":"2025-12-08T01:12:56.462093Z","shell.execute_reply.started":"2025-12-08T01:12:56.447438Z","shell.execute_reply":"2025-12-08T01:12:56.461407Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# 设置种子\nconfigue={\n    \"batch_size\":8,\n    \"seed\":42,\n    \"epochs\":200,\n    \"device\":\"cuda\" if torch.cuda.is_available() else \"cpu\",\n    \"start_lr\":2e-4,\n    \"temp\":10,\n    \"idt_coef\":0.5,\n    \"decay_epoch\":0\n}","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-08T01:12:56.462735Z","iopub.execute_input":"2025-12-08T01:12:56.463002Z","iopub.status.idle":"2025-12-08T01:12:56.525811Z","shell.execute_reply.started":"2025-12-08T01:12:56.46298Z","shell.execute_reply":"2025-12-08T01:12:56.525194Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# 转换接口\nos.makedirs(\".\\Image\",exist_ok=True)\n\nclass PhotoDataset(Dataset):\n    def __init__(self,photo_path,size=(256,256),configue=configue):\n        super().__init__()\n        random.seed(None)\n        self.photo_path=glob.glob(photo_path+\"/*\")\n        random.shuffle(self.photo_path)\n        self.transforms=transforms.Compose([\n            transforms.ToTensor(),\n            transforms.Resize(size),\n            transforms.Normalize([0.5,0.5,0.5],[0.5,0.5,0.5])\n        ])\n        random.seed(configue[\"seed\"])\n    def __len__(self):\n        return len(self.photo_path)\n\n    def __getitem__(self,idx):\n        photo_img=self.transforms(Image.open(self.photo_path[idx]))\n        return photo_img\n\nphoto_iter=DataLoader(PhotoDataset(photo_path),batch_size=1,shuffle=True,pin_memory=True)\n\n@torch.no_grad\ndef Transformer_image(net, data_iter, configue=configue, num=1):\n    net.G_Monet2Photo.eval()\n    net.G_Photo2Monet.eval()\n    net.D_Monet.eval()\n    net.D_Photo.eval()\n    true_imgs, transformed_imgs = [], []\n    for i, img in enumerate(data_iter):\n        if i == num:\n            break\n        device = configue[\"device\"]\n        img = img.to(device)\n        transformed_img = net.G_Photo2Monet(img)\n        transformed_img = reverse_img(transformed_img.cpu()[0])\n        transformed_img = transforms.ToPILImage()(transformed_img).convert(\"RGB\")\n        transformed_imgs.append(transformed_img)\n\n        img = reverse_img(img.cpu())\n        img = transforms.ToPILImage()(img[0]).convert(\"RGB\")\n        true_imgs.append(img)\n\n        transformed_img.save(f\".\\Image\\{i}.jpg\")\n    return transformed_imgs, true_imgs","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-08T01:12:56.526801Z","iopub.execute_input":"2025-12-08T01:12:56.527357Z","iopub.status.idle":"2025-12-08T01:12:56.555276Z","shell.execute_reply.started":"2025-12-08T01:12:56.527331Z","shell.execute_reply":"2025-12-08T01:12:56.55454Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class CycleGAN:\n    def __init__(self,in_ch,out_ch,configue):\n        self.configue=configue\n        self.epochs=configue[\"epochs\"]\n        self.start_lr=configue[\"start_lr\"]\n        self.temp=configue[\"temp\"]\n        self.decay_epoch=configue[\"decay_epoch\"] if configue[\"decay_epoch\"] else int(self.epochs/2)\n        self.idt_coef=configue[\"idt_coef\"]\n        self.device=configue[\"device\"]\n        self.G_Monet2Photo=Generator(in_ch,out_ch)\n        self.G_Photo2Monet=Generator(in_ch,out_ch)\n        self.D_Monet=Discriminator(in_ch)\n        self.D_Photo=Discriminator(in_ch)\n\n        self.mseloss=nn.MSELoss()\n        self.l1loss=nn.L1Loss()\n        self.G_adam=torch.optim.AdamW(itertools.chain(self.G_Monet2Photo.parameters(),self.G_Photo2Monet.parameters()),\n                                     lr=self.start_lr,betas=(0.5,0.999))\n        self.D_adam=torch.optim.AdamW(itertools.chain(self.D_Monet.parameters(),self.D_Photo.parameters()),\n                                     lr=self.start_lr,betas=(0.5,0.999))\n\n        self.sample_monet=sample_fake()\n        self.sample_photo=sample_fake()\n\n        G_lr=lr_sched(self.decay_epoch,self.epochs)\n        D_lr=lr_sched(self.decay_epoch,self.epochs)\n        self.G_sched=torch.optim.lr_scheduler.LambdaLR(self.G_adam,G_lr.step)\n        self.D_sched=torch.optim.lr_scheduler.LambdaLR(self.D_adam,D_lr.step)\n        self.record_metric=Recorder(2)\n\n        self.init()\n    def init(self):\n        self.G_Monet2Photo.apply(init_weight)\n        self.G_Photo2Monet.apply(init_weight)\n        self.D_Monet.apply(init_weight)\n        self.D_Photo.apply(init_weight)\n\n        self.G_Monet2Photo=self.G_Monet2Photo.to(self.device)\n        self.G_Photo2Monet=self.G_Photo2Monet.to(self.device)\n        self.D_Monet=self.D_Monet.to(self.device)\n        self.D_Photo=self.D_Photo.to(self.device)\n\n\n    def train(self,data_iter):\n        epochs=self.configue[\"epochs\"]\n        device=self.configue[\"device\"]\n        \n        record_metric=self.record_metric\n        scaler=amp.GradScaler(\"cuda\")\n        for epoch in range(epochs):\n            add_metric=Accumulator(3)\n            pbar=tqdm.tqdm(data_iter,total=len(data_iter),leave=False,desc=f\"{epoch+1}/{epochs}\")\n            for i,(monet_img,photo_img) in enumerate(pbar):\n                # ============================生成器============================\n                Frozen([self.D_Monet,self.D_Photo],False)\n                monet_img,photo_img=monet_img.to(device,non_blocking=True),photo_img.to(device,non_blocking=True)\n                self.G_adam.zero_grad()\n                #混合精度的前向传播\n                with amp.autocast(\"cuda\",enabled=True):\n                    fake_photo=self.G_Monet2Photo(monet_img)\n                    fake_monet=self.G_Photo2Monet(photo_img)\n                    cycle_monet=self.G_Photo2Monet(fake_monet)\n                    cycle_photo=self.G_Monet2Photo(fake_monet)\n                    id_monet=self.G_Photo2Monet(monet_img)\n                    id_photo=self.G_Monet2Photo(photo_img)\n    \n                    #身份损失---不能改变本来就是目标身份的图片\n                    id_monet_loss=self.l1loss(id_monet,monet_img)*self.temp*self.idt_coef\n                    id_photo_loss=self.l1loss(id_photo,photo_img)*self.temp*self.idt_coef\n                    # 循环损失---确保内容主体不改变，否则生成器只会骗判别器而全然不管内容主体，因此大权重\n                    cycle_monet_loss=self.l1loss(cycle_monet,monet_img)*self.temp\n                    cycle_photo_loss=self.l1loss(cycle_photo,photo_img)*self.temp\n                    # 对抗损失---判别器能否正确判断真假，这是我们严格要求的，所以加上 mseloss，即不允许容忍极端值\n                    monet_disc=self.D_Monet(fake_monet)\n                    photo_disc=self.D_Photo(fake_photo)\n                    # real=torch.ones(monet_disc.size()).to(device)\n                    real=torch.ones_like(monet_disc).to(device)\n                    monet_adv_loss=self.mseloss(monet_disc,real)\n                    photo_adv_loss=self.mseloss(photo_disc,real)\n                    # 总损失\n                    G_total_loss=id_monet_loss+id_photo_loss+cycle_monet_loss+\\\n                                    cycle_photo_loss+monet_adv_loss+photo_adv_loss\n                scaler.scale(G_total_loss).backward()\n                #因为上述损失与生成器目标一致，所以我们希望优化器同时兼顾这些损失\n                scaler.unscale_(self.G_adam)\n                scaler.step(self.G_adam)\n                scaler.update()\n                \n               # ============================判别器============================\n                Frozen([self.D_Monet,self.D_Photo],True)\n                self.D_adam.zero_grad()\n\n                with amp.autocast(\"cuda\",enabled=True):\n                    fake_monet = self.sample_monet(fake_monet.cpu().detach()).to(device)\n                    fake_photo = self.sample_photo(fake_photo.cpu().detach()).to(device)\n                    \n                    monet_real_disc=self.D_Monet(monet_img)\n                    monet_fake_disc=self.D_Monet(fake_monet)\n                    photo_real_disc=self.D_Photo(photo_img)\n                    photo_fake_disc=self.D_Photo(fake_photo)\n    \n                    # 通用的判别值\n                    # real_dsic=torch.ones(monet_real_disc.size(),device=device)\n                    # fake_disc=torch.zeros(monet_fake_disc.size(),device=device)\n                    real_dsic=torch.ones_like(monet_real_disc,device=device)\n                    fake_disc=torch.zeros_like(monet_fake_disc,device=device)\n                    # 真的判别为真，假的判别为假\n                    monet_real_loss=self.mseloss(monet_real_disc,real_dsic)\n                    monet_fake_loss=self.mseloss(monet_fake_disc,fake_disc)\n                    photo_real_loss=self.mseloss(photo_real_disc,real_dsic)\n                    photo_fake_loss=self.mseloss(photo_fake_disc,fake_disc)\n                    #总损失\n                    monet_disc_loss=(monet_real_loss+monet_fake_loss)/2\n                    photo_disc_loss=(photo_real_loss+photo_fake_loss)/2\n                    D_total_loss=monet_disc_loss+photo_disc_loss\n                scaler.scale(D_total_loss).backward()\n                scaler.unscale_(self.D_adam)\n                scaler.step(self.D_adam)\n                scaler.update()\n                \n                add_metric.add(G_total_loss.item(),D_total_loss.item(),len(monet_img))\n                #进度条更新\n                pbar.set_postfix(G_loss=G_total_loss.item(),D_loss=D_total_loss.item())\n            record_metric.add(add_metric[0]/add_metric[-1],add_metric[1]/add_metric[-1])\n            print(f\"<{epoch+1}/{epochs}>---<G_loss {add_metric[0]/add_metric[-1]}>---<M_loss  {add_metric[1]/add_metric[-1]}>\")\n            self.G_sched.step()\n            self.D_sched.step()\n            if (epoch+1)%20==0:\n                transformed_imgs, true_imgs=Transformer_image(net,photo_iter)\n                show_img(transformed_imgs, true_imgs)\n                save_generator_only(net)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-08T01:12:56.556684Z","iopub.execute_input":"2025-12-08T01:12:56.556935Z","iopub.status.idle":"2025-12-08T01:12:56.573731Z","shell.execute_reply.started":"2025-12-08T01:12:56.55692Z","shell.execute_reply":"2025-12-08T01:12:56.57301Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import itertools\nimport tqdm\n\ndef seed_(seed):\n    random.seed(42)\n    torch.manual_seed(42)\n    torch.cuda.manual_seed(42)\n    np.random.seed(42)\n        \nseed_(configue[\"seed\"])\nos.makedirs(\".\\Storage\",exist_ok=True)\nos.makedirs(\".\\Image\",exist_ok=True)\n\ndata_iter=DataLoader(MonetDataset(monet_path,photo_path),\n                     batch_size=configue[\"batch_size\"],\n                     shuffle=True,\n                     pin_memory=True,)\nnet=CycleGAN(3,3,configue)\nnet.train(data_iter)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-08T01:12:56.57433Z","iopub.execute_input":"2025-12-08T01:12:56.574489Z","iopub.status.idle":"2025-12-08T04:13:04.896952Z","shell.execute_reply.started":"2025-12-08T01:12:56.574476Z","shell.execute_reply":"2025-12-08T04:13:04.896245Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"show_chart(net)\nsave_generator_only(net)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-08T04:13:04.897946Z","iopub.execute_input":"2025-12-08T04:13:04.898136Z","iopub.status.idle":"2025-12-08T04:13:05.543992Z","shell.execute_reply.started":"2025-12-08T04:13:04.898117Z","shell.execute_reply":"2025-12-08T04:13:05.543245Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"transformed_imgs, true_imgs=Transformer_image(net,photo_iter)\nshow_img(transformed_imgs, true_imgs)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-08T04:19:15.741448Z","iopub.execute_input":"2025-12-08T04:19:15.742074Z","iopub.status.idle":"2025-12-08T04:19:18.040354Z","shell.execute_reply.started":"2025-12-08T04:19:15.742048Z","shell.execute_reply":"2025-12-08T04:19:18.039676Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import zipfile\n\ntest_paths = sorted(glob.glob(\"/kaggle/input/gan-getting-started/photo_jpg/*.jpg\"))\n\nwith torch.no_grad():\n    with zipfile.ZipFile(\"images.zip\", \"w\") as zf:\n        for i, path in enumerate(test_paths):\n            img = Image.open(path).convert(\"RGB\")\n            img = transforms.ToTensor()(img).unsqueeze(0).to(configue[\"device\"])\n            img = transforms.Normalize([0.5]*3, [0.5]*3)(img)\n            \n            fake = net.G_Photo2Monet(img)\n            fake = reverse_img(fake.squeeze(0).cpu()) \n            fake = transforms.ToPILImage()(fake).convert(\"RGB\")\n            fake.save(\"temp.jpg\")\n            zf.write(\"temp.jpg\", arcname=f\"{i+1}.jpg\")\n\nprint(\"images.zip 生成完毕，直接提交即可！\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-08T04:20:30.664623Z","iopub.execute_input":"2025-12-08T04:20:30.6653Z","iopub.status.idle":"2025-12-08T04:22:47.433956Z","shell.execute_reply.started":"2025-12-08T04:20:30.665279Z","shell.execute_reply":"2025-12-08T04:22:47.433161Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}