
简介面向希望用CycleGAN训练自定义风格迁移模型的开发者与研究者压缩包中整合了完整可运行的PyTorch源码、原始论文与配套教程能够帮助用户绕开环境与数据准备的坑直接聚焦模型效果。素材涵盖数据加载、模型定义、训练测试等36个Python脚本14个Shell脚本用于数据集下载与环境配置另有Markdown说明、LaTeX论文源码和两个Jupyter演示示例共75个文件约41.87MB目录按options、datasets、models、scripts等模块组织便于按需查阅。CycleGAN通过双向循环一致性实现无配对图像的域迁移在画风转换、医学跨模态生成等场景均有应用相比传统风格迁移训练更稳定、测试速度更快。目前已有1256人学习下载适合毕业设计、深度学习入门或工程落地参考。附带教程博客提供了作者自己跑通数据集的实战经验能有效缩短调试时间快速产出可演示结果。 做风格变换做到一定阶段都会遇上一个绕不开的问题手上没有成对数据。之前我做过一阵子pix2pix效果是让人放心的但前提是你得拿到一一对应的训练对——白天和黑夜同一机位的照片、不同画风同一构图的油画这种数据在真实场景里根本凑不齐。CycleGAN 就是专门为这个场景设计的它不需要成对样本只用两个彼此独立的图像集合就能学出 A→B 的风格映射。我这次用 CycleGAN 跑自己的数据集从数据整理、代码配置到训练调参、Bug 排查完整走了一遍。现在把这段经验写下来给准备上手风格变换项目的朋友做一个可以直接参考的流程。1. 项目整体设计与思路拆解1.1 CycleGAN 解决的核心问题CycleGAN 的完整名字是 Unpaired Image-to-Image Translation using Cycle-Consistent Adversarial Networks2017 年提出的那篇论文。它的适用场景非常直接你手上有两个图像域 A 和 B但你没有“同一内容在 A 域和 B 域里分别长什么样”的成对样本你依然想让一张图从 A 域的风格转到 B 域。举个例子我手上的 A 域是手机拍的真实街景照片B 域是某位画家的风景油画两张图内容完全对不上但 CycleGAN 能从整体风格层面学到映射把一张新照片转成油画味道的结果。它为什么能做到这件事核心在于一个叫“循环一致性损失”的机制。简单说模型不仅学了一个 A→B 的生成器 G还学了一个 B→A 的生成器 F。把照片 x 从 A 转成 B 后再让 F 转回 A得到重建的图片 F(G(x))理想情况下它应该尽量接近原始的 x。这个循环让网络在没有成对标注的情况下仍然能约束生成内容的结构不跑偏。如果你想快速理解可以把它类比成一个翻译模型翻译成英文再翻回中文如果两次翻译后的内容和原文出入很大说明第一次翻译的质量是有问题的。CycleGAN 靠的就是这个“翻译回来检查”的思路。1.2 为什么直接选官方 PyTorch 实现CycleGAN 的官方仓库是 junyanz/pytorch-CycleGAN-and-pix2pix我在实际用下来之后觉得它有几个点很适合拿来自数据集训练。第一代码把数据加载、生成器、判别器、损失函数全部做了模块化封装你想改某一部分不用从头重写。第二官方实现里自带了 train.py 和 test.py 两个完整流程你在自己的数据集上只要把目录结构摆对命令几乎不用改。第三它的模型结构是 ResNet 生成器加 PatchGAN 判别器这套组合在今天依然是很多图像转换任务里能打底的标准结构。其实社区里也有一些第三方复现版本比如 TensorFlow 实现、Jittor 实现效果都不错。但如果你跑自己的数据集我建议先以官方 PyTorch 版为准因为遇到问题搜解决方案的时候能搜到的大量讨论都是基于这个仓库的。等你把官方流程跑通、确认参数怎么调再根据自己的需求去魔改也不迟。2. 数据集准备与处理2.1 数据集的收集与目录结构CycleGAN 对数据集的目录结构有默认约定。官方代码读取的根目录下必须包含 trainA、trainB、testA、testB 四个子目录。我这次做的实验是“真实照片到油画风格转换”所以 trainA 放的是真实风景照片trainB 放的是各类风格的油画作品。目录结构如下datasets/ └── mystyle/ ├── trainA/ # A 域训练图片比如照片 ├── trainB/ # B 域训练图片比如油画 ├── testA/ # A 域测试图片 └── testB/ # B 域测试图片关于数据规模我个人的经验是每个域至少准备 500 张以上最好能到 2000 张。CycleGAN 虽然用循环一致性约束了训练过程但本质还是对抗训练样本太少会让生成器很快记住训练集里的少数图案出现“不管输入什么图输出都长得差不多”的过拟合现象。我最早用每个域 300 张图试过一次效果确实不太行把数据补充到 1500 张左右后明显改善。收集数据时还需要注意清洗工作。重复图片要删掉模糊的、带水印的、有边框的图片我建议直接剔除因为这些噪声会让生成器学到“不该学的东西”。画作数据要尽量覆盖多种色调和构图照片数据也要尽量贴近真实应用场景。如果做的是专门领域的风格变换比如某种 X 光安检图像的风格增强实验那么训练数据就应该从对应场景里去采集不能用公开的通用数据集随便代替。2.2 数据预处理与增强方案官方代码在训练过程中会自动对图片做 resize 到 286×286再随机裁剪到 256×256同时在水平方向做随机翻转。这些操作能起到数据增强的作用让模型不那么容易过拟合。但输入图片本身最好先处理成长宽比例尽量接近 1:1 的格式否则训练时裁剪会丢掉大量边缘信息。我习惯先用脚本把图片统一转成 jpg并且把短边 resize 到 286 以上其他交给代码内部处理。如果需要更强的数据增强可以手动加入随机亮度扰动、饱和度抖动、小角度的旋转但要注意不能改变图片的语义内容。比如做照片到油画的转换你把照片旋转 90 度或大幅裁切生成器学到的内容可能会偏离真实场景。我的建议是第一步只保留官方默认的翻转和裁剪先观察基础效果确有必要再逐步增加增强方式否则出了问题不好定位。3. 代码配置与训练实操3.1 环境搭建与代码拉取代码环境方面我使用的是 Python 3.8 PyTorch 1.13这是官方仓库兼容性比较好的组合。PyTorch 2.x 我也试过训练脚本基本能跑但个别 ops 需要留意版本差异。完整的安装命令如下git clone https://github.com/junyanz/pytorch-CycleGAN-and-pix2pix.git cd pytorch-CycleGAN-and-pix2pix conda create -n cyclegan python3.8 conda activate cyclegan pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu118 pip install dominate pip install visdom其中 visdom 是用于训练过程可视化的工具如果不想额外启动一个 server也可以在训练命令里加上--display_id 0直接禁用可视化这也是我最常用的做法省心不少。3.2 核心训练参数与一键启动官方 train.py 的参数比较多我按实际使用频率整理了下面这个速查表参数默认值作用说明我的建议--dataroot无数据集根目录路径指向 datasets/mystyle--name无实验名称用于区分输出文件建议用项目名如 my_style--modelcycle_gan选择模型结构保持默认--gpu_ids0指定 GPU-1 表示 CPU单卡用 0--batch_size1批大小显存足够可调到 4 或 8--n_epochs100固定学习率的训练轮数默认 100--n_epochs_decay100学习率线性衰减的轮数默认 100--lr0.0002初始学习率保持默认一般不用改--lambda_A10.0循环一致性损失权重调整 cycle 强度的关键--lambda_B10.0反向循环一致性损失权重默认即可--lambda_identity0.0身份保持损失权重0.5~1.0 可改善颜色失真启动训练的命令非常简单python train.py --dataroot ./datasets/mystyle \ --name my_style \ --model cycle_gan \ --display_id 0训练开始后会在 checkpoints/my_style 目录下自动保存最新模型并在 loss_log.txt 里记录每一步的损失。有一点要提醒batch_size 官方默认是 1这是由 Instance Normalization 的特性决定的。如果你把 batch_size 调大效果不一定会变好反而可能让颜色的统计特性发生变化。我试过 batch_size 为 4生成结果有时会出现偏色后来还是用回默认值。3.3 训练过程监控与模型保存训练过程中最需要盯的是两个 loss生成器总损失和判别器损失。生成器总损失在 loss_log.txt 里会拆分成 G_A、G_B、cycle_A、cycle_B、idt 等几项。其中 cycle 损失下降得越明显说明循环一致性的约束在起作用。如果 cycle 损失下降很慢或者反复震荡通常说明学习率太大或者输入图片内容差异过大。模型默认每 5 轮保存一次同时 latest 版本一直会覆盖更新。我习惯在训练到 200 轮左右时把 latest_net_G_A.pth 复制出来做一次测试用肉眼看看效果再决定继续训练还是调整参数。千万不要只看 loss 数字判断好坏对抗训练本身就存在波动生成效果才是最终标准。4. 测试与结果评估4.1 单张图片与批量测试命令测试阶段和训练不同使用的是单独的命令脚本。官方会把 testA 目录里的图片全部读取并生成结果输出到 results/my_style 目录下python test.py --dataroot ./datasets/mystyle \ --name my_style \ --model cycle_gan如果你想测试自己的单张图片而不是目录里的全部图片可以单独建一个只有一张图的目录然后指定为 dataroot。测试脚本默认加载的是最新保存的 latest_net_G_A.pth。如果你想指定某个 epoch 的模型在命令后面加--epoch 200即可。这里容易踩的坑是test.py 读取的是 testA 目录如果目录为空命令虽然能跑但什么结果都不会输出。4.2 生成效果不好时的调整方向测试结果不理想时我通常按照以下顺序排查。生成图模糊先看是不是训练轮数不够CycleGAN 通常需要跑到 150 轮以上才会有清晰结果。如果内容结构严重变形说明循环一致性约束不够强可以把--lambda_A和--lambda_B从默认的 10 往上调。如果颜色发生了明显偏移比如照片转油画后整体发绿发蓝可以在训练时加上身份损失也就是把--lambda_identity设为 0.5 或 1.0。身份损失的原理不算复杂把一张 B 域的图输入给 A→B 的生成器理想情况下它的输出还是原图。加上这个约束之后生成器不会为了追求风格而把整体色调改得面目全非。我第一次用 CycleGAN 做作品风格迁移时就吃过亏不加身份损失生成的图很容易出现不自然的色偏。后来把 lambda_identity 调到 1.0颜色自然了很多。5. 论文配套阅读与参数调节心得5.1 论文核心内容与代码映射如果你想要把参数调明白我建议一定要读一读原论文重点看 3.1 节和 3.2 节。代码里的 loss_G 实际上由三部分组成第一部分是生成器对抗损失让生成图骗过判别器第二部分是循环一致性损失对应论文里的 cycle_loss第三部分是身份损失对应代码里的 idt_loss。三部分权重由 lambda_A、lambda_B 和 lambda_identity 三个参数控制。论文里的完整目标函数是 L(G, F, Dx, Dy) 的三项加和代码里的实现和论文完全对应。我在调参时会把 lambda_A 和 lambda_B 保持同步调整因为两个方向的循环一致性约束是对称的单独改一个会让 A→B 和 B→A 的训练节奏不一致。另外论文中提到生成器使用的是 ResNet 结构代码里用--netG resnet_9blocks指定如果图片内容比较复杂可以考虑改用resnet_6blocks网络更轻量训练速度会快一些但效果可能有细微变化。5.2 参数调节的实战经验不同数据集的“最优参数”差异很大但有几个方向性的经验可以直接套用。当你觉得生成结果内容保持得不错但风格转换得不够彻底可以考虑增大循环一致性损失权重同时把学习率稍微调低让训练更充分。当你觉得生成结果有太多原始输入的内容残留比如照片转油画后还能清楚看到噪点和相机纹理则需要减小循环一致性权重让生成器更大胆地改变局部区域。还要注意一个容易被忽略的点判别器的更新频率。官方代码里判别器和生成器每个 iteration 只更新一次整体比例是 1:1。如果你的训练出现生成器强、判别器弱也就是生成的图非常逼真但判别器 loss 已经趋近于 0 的情况可以尝试在每个 iteration 里额外更新一次判别器代码上只需改动少量逻辑。但这种情况在实际训练中不多见最常见的还是两者互相交替波动这属于正常现象不必太过担心。6. 典型问题排查与避坑记录6.1 常见报错与解决方案速查实际操作中新手遇到最多的几个报错和现象我整理成了速查表现象或报错可能原因解决方案报错找不到 visdom 相关模块没有正确安装或者没有启动 server安装 dominatevisdom或训练命令加 --display_id 0CUDA out of memory显存不够调小 batch_size或将生成器改为 resnet_6blocks训练 loss 一直很大且不下降学习率过大或数据有误把 lr 降到 0.0001检查 trainA 和 trainB 是否放反生成的全是纯色图生成器崩溃判别器太强调大网络容量减少训练轮数或降低判别器学习率测试时输出目录为空testA 里没有图片确认 testA 目录下确有测试图片图片颜色明显发灰输出值域和处理范围不匹配检查生成器最后的 Tanh 层到图片保存的映射是否正确6.2 实际操作中的关键提醒最后分享几个我在项目里踩过坑之后总结下来的经验。第一训练之前一定要确认 trainA 和 trainB 的图片不要互相混入。比如你的 A 域是照片B 域是油画但照片文件夹里不小心混了一百张油画模型就会非常困惑训练出来的映射会同时包含两套风格效果极其诡异。第二checkpoint 文件要定期备份。CycleGAN 训练动辄几十个小时我有一次在训练到一半时不小心把 checkpoints 目录清掉了前面所有进度全部丢失只能从头再来。现在我会每隔 20 轮把当前模型复制到另一个目录存放宁可多占一点磁盘也不能让训练进度白费。第三每跑一次实验把命令和关键参数记下来。不要以为你会记得当时用了什么 lambda 值现实是过了一个星期再来调模型你大概率会忘记上一次到底是怎么调的。我自己会在每个实验目录下放一个 config.txt把训练命令原样粘贴进去后续翻查的时候非常方便。这次做照片到油画风格变换的完整过程我自己最大的收获是理解了 CycleGAN 不是“一键出图”的黑魔法它是一套需要你根据数据特性反复调整的方案。数据质量、lambda 权重、训练轮数、身份损失每一个环节都会直接影响最终效果。如果你正准备拿自己的数据集跑 CycleGAN建议先拿一个小一点的子集做参数验证把流程走通了再上全量数据这样能省下大量折腾时间。等基础版本跑通之后你还可以试试 CUT、FastCUT 这些不需要循环一致性的新方法和 CycleGAN 做对比也许会有新的启发。本文还有配套的精品资源点击获取