文章目录
- 一、风格迁移模型🎨
- 二、论文简读
-
- [(1)FastStyleTransfer(快速风格迁移,Johnson et al., 2016)](#(1)FastStyleTransfer(快速风格迁移,Johnson et al., 2016))
- [(2)AdaIN(自适应实例规范化,Huang & Belongie, 2017)](#(2)AdaIN(自适应实例规范化,Huang & Belongie, 2017))
- [(3)CycleGAN:基于循环一致性的无配对图像风格迁移方法(Zhu et al., 2017)](#(3)CycleGAN:基于循环一致性的无配对图像风格迁移方法(Zhu et al., 2017))
- 三、CycleGAN:项目实战
-
- 1、环境配置
- 2、使用CPU模式而非GPU(默认强制使用,有GPU跳过该步骤)
- 3、文件配置
- [4、代码测试(Test a CycleGAN model)](#4、代码测试(Test a CycleGAN model))
- [备注1:CycleGAN 本质上无法保证 " 主体不变、仅变风格 "](#备注1:CycleGAN 本质上无法保证 " 主体不变、仅变风格 ")
- [备注2:白 / 黑背景将使得模型失去迁移方向](#备注2:白 / 黑背景将使得模型失去迁移方向)
一、风格迁移模型🎨
1、发展时间线
年份 | 模型/方法 | 发布者/会议 | 技术关键词 | 关键贡献或备注 |
---|---|---|---|---|
2015 | NeuralStyleTransfer | Gatys等(CVPR) | Gram矩阵、VGG特征、优化迭代 | 开创性风格迁移方法,掀起研究热潮 |
2016 | FastStyleTransfer | Johnson等(ECCV) | 感知损失、快速前向网络 | 实现实时风格迁移,提升实用性 |
2017 | AdaIN | Huang等(NeurIPS) | 自适应实例归一化 | 任意风格迁移新范式,灵活性强 |
2017 | WCT | Li等(CVPR) | 白化与着色变换(WCT) | 无需训练,基于特征统计 |
2017 | Pix2Pix | Isola等(CVPR) | 条件GAN、成对图像翻译 | 开创成对图像翻译标准方法 |
2017 | CycleGAN | Zhu等(ICCV) | 循环一致性、无监督图像翻译 | 打破成对限制,支持任意风格迁移 |
2018 | MUNIT | Huang等(ECCV) | 多模态风格迁移、潜变量解耦 | 实现多风格切换 |
2019 | UGATIT | Kim等(ICLR) | 注意力机制、可控无监督迁移 | 强化结构保持,适用于面部、插画等 |
2020 | CUT | Park等(ECCV) | 对比学习、PatchNCE损失 | 改进CycleGAN,提升图像结构保持能力 |
2022 | StableDiffusion | CompVis等 | 文图扩散模型、文本控制 | 图文创作与艺术风格迁移 |
2023 | DALL·E2 | OpenAI | CLIP引导图文生成、多模态优化 | 多样化风格图生成利器,适合设计类应用 |
2、分类与优缺点
类别 | 代表模型 | 特点描述 | 优点 | 局限性 |
---|---|---|---|---|
统计特征匹配类 | NeuralStyleTransfer、AdaIN、WCT | 特征层统计参数(均值/方差)匹配 | 快速、无需训练、可实时应用 | 风格粒度不可控,结构保持差 |
成对监督类 | Pix2Pix | 条件GAN训练,有明确输入输出成对 | 精确控制、结构保持好 | 需成对样本,任务限制大 |
无监督图像翻译类 | CycleGAN、DualGAN、CUT | 循环一致性、对比学习等实现非配对迁移 | 无需配对,适用于多风格切换 | 训练稳定性差,细节模糊,存在模式崩溃风险 |
结构保持增强类 | UGATIT、MUNIT、DRIT | 引入注意力或语义模块,增强结构和可控性 | 支持局部显著风格、结构更完整 | 推理慢,训练复杂,对参数敏感 |
跨模态生成类 | StableDiffusion、DALL·E、ControlNet | 文本控制图像风格,生成类大模型 | 控制力强、创意表达能力强 | 结构不可控、不适用于精确图像风格迁移 |
3、选择建议
使用需求 | 推荐模型 | 是否需训练 | 推理速度 | 结构保持 | 风格质量 | 适用建议 |
---|---|---|---|---|---|---|
快速预览风格效果 | AdaIN、WCT | 否 | ★★★★★ | ★★ | ★★★★ | 适合滤镜类APP、快速尝试多种风格 |
批量生成某一固定风格 | FastStyleTransfer | 是 | ★★★★ | ★★★★ | ★★★★ | 一次训练后多图高效渲染 |
精确图↔图风格转换 | Pix2Pix | 是 | ★★★ | ★★★★★ | ★★★★ | 数据成对充分时优选 |
任意图像风格迁移 | CycleGAN、CUT | 是 | ★★★ | ★★★★ | ★★★★ | 适合插画↔实拍等风格转换 |
多风格自由切换 | MUNIT、DRIT、StyleGAN | 是 | ★★ | ★★★★ | ★★★★ | 风格交互应用场景,如头像生成、社交内容等 |
文本描述控制图像风格 | StableDiffusion、DALL·E | 否 | ★★ | ★★ | ★★★★★ | 创意类内容创作,如封面设计、艺术生成等 |
4、HuggingFace Demo(instruct-pix2pix) ------ 在线测试
https://huggingface.co/spaces/timbrooks/instruct-pix2pix
- 输入:任意照片 + 文字指令(如 "Turn it into a cyberpunk style")
- 特点:无需风格图,直接通过文本描述控制风格。
- 超参数:
- Text CFG:7.5(默认)
- Image CFG:1.5(默认)
- 备注:权重越大,越倾向于哪一方!
- 输入图像的一般要求
- 格式:常见的图片格式(如 .jpg, .png, .webp)。
- 分辨率:建议 512x512 ~ 1024x1024 像素(太高可能被自动压缩)。
- 内容清晰:避免过度模糊、噪点或强压缩伪影。
- 主体明确:风格迁移对主体(如人像、建筑、风景)效果更好。
二、论文简读
(1)FastStyleTransfer(快速风格迁移,Johnson et al., 2016)
快速神经风格:将一张图片的内容与另一张图片的风格进行混合
- https://github.com/pytorch/examples/tree/main/fast_neural_style
- https://github.com/jcjohnson/fast-neural-style
1、原理概述
FastStyleTransfer 是一种利用感知损失(Perceptual Loss)实现的快速图像风格迁移方法。其基本结构为一个前馈神经网络,在训练阶段学习将任意图像转换为特定风格的图像。训练完成后,该网络在推理阶段可实现毫秒级图像风格转换。
网络结构
- 输入:内容图像(如渲染图);
- 输出:风格化图像;
- 损失函数基于 VGG 特征提取器:
- 内容损失:保持原始图像的语义结构;
- 风格损失:匹配目标风格图的Gram矩阵特征;
- 总变差损失(TV loss):增强图像平滑性。
2、特点与优势
优势点 | 说明 |
---|---|
✅ 推理速度快 | 一次前向传播即可完成风格迁移,0.05~0.2秒/张,适合实时应用。 |
✅ 不改变图像结构 | 网络学习内容保留与风格分离,结果结构清晰。 |
✅ 工程部署简单 | 可导出为TorchScript或ONNX,部署于边缘设备或网页端。 |
3、 局限性
局限点 | 描述 |
---|---|
❌ 每种风格需单独训练一个模型 | 若需支持多种风格,需为每种风格图单独训练一次,增加存储与训练成本。 |
❌ 风格灵活性较低 | 风格结果相对固定,无法在推理阶段动态调整风格程度或更换风格图像。 |
(2)AdaIN(自适应实例规范化,Huang & Belongie, 2017)
AdaIN:通过自适应实例规范化,实现实时任意风格转换
1、原理概述
AdaIN 是一种任意风格图像迁移方法,通过在推理阶段动态注入风格图像特征统计信息,实现任意风格的实时转换。核心思想是:将内容图像的特征归一化后,重新赋予目标风格图的均值与方差,从而在不改变内容结构的前提下完成风格映射。
关键模块:Adaptive Instance Normalization
设内容特征为 fc,风格特征为 fs,则:
AdaIN ( f c , f s ) = σ ( f s ) ⋅ ( f c − μ ( f c ) σ ( f c ) ) + μ ( f s ) \text{AdaIN}(f_c, f_s) = \sigma(f_s) \cdot \left( \frac{f_c - \mu(f_c)}{\sigma(f_c)} \right) + \mu(f_s) AdaIN(fc,fs)=σ(fs)⋅(σ(fc)fc−μ(fc))+μ(fs)其中:
μ:均值
σ:标准差
2、特点与优势
局限点 | 描述 |
---|---|
❌ 风格仅体现颜色与纹理分布 | 不适合高度结构化或抽象风格(如某些插画或2.5D卡通),表现不如GAN类方法。 |
❌ 对抗性质量不及GAN | 相比CycleGAN等对抗训练方法,输出真实感稍弱,细节较平滑。 |
3、局限性
局限点 | 描述 |
---|---|
❌ 风格仅体现颜色与纹理分布 | 不适合高度结构化或抽象风格(如某些插画或2.5D卡通),表现不如GAN类方法。 |
❌ 对抗性质量不及GAN | 相比CycleGAN等对抗训练方法,输出真实感稍弱,细节较平滑。 |
(3)CycleGAN:基于循环一致性的无配对图像风格迁移方法(Zhu et al., 2017)
- 论文地址:https://junyanz.github.io/CycleGAN/
- 开源地址:https://github.com/junyanz/pytorch-CycleGAN-and-pix2pix
1、原理概述
CycleGAN是一种用于图像到图像转换(Image-to-Image Translation)任务的生成对抗网络(GAN)框架,具有无需成对训练样本,学习两个域之间的映射关系,实现跨领域图像转换。其核心思想是通过循环一致性损失(Cycle Consistency Loss) 约束风格迁移的可逆性,从而在保留图像结构的同时实现风格映射。
基本架构 :CycleGAN包括两个生成器(GA→B 和 GB→A)与两个判别器(DA 和 DB)
其中:
GA→B:将A域图像(如照片)转换为B域图像(如油画);例如:照片 → 油画、夏天 → 冬天、马 → 斑马
GB→A:实现B→A的反向转换;例如:照片 → 油画、夏天 → 冬天、马 → 斑马(反着)
DA 与 DB:分别判别生成图像是否属于对应域的真实样本。
循环一致性损失(Cycle Loss):A → B → A ≈ A
B → A → B ≈ B
这种结构使得即使两个领域之间没有一一对应的图像对,模型也能学到结构稳定的风格映射。
2、特点与优势
优势点 | 说明 |
---|---|
✅ 无需配对训练样本 | 相较于Pix2Pix等方法,CycleGAN仅依赖两个领域的非配对图像,降低了数据准备难度。 |
✅ 结构保持能力强 | 通过循环损失保持图像内容结构不变,适合结构稳定但风格差异大的任务(如风景↔油画)。 |
✅ 具备双向映射能力 | 同时学习A→B和B→A转换路径,提升模型鲁棒性与泛化能力。 |
✅ 可生成较高质量图像 | 相比简单风格迁移模型,CycleGAN在图像真实感、边缘保留等方面表现更优。 |
3、局限性
局限点 | 描述 |
---|---|
❌ 需大量非配对数据 | 虽不要求成对图像,但仍需大量覆盖多样风格的两域图像(例如上千张A域图像+上千张B域图像)才能训练有效模型。 |
❌ 单图像训练效果差 | 如果仅提供一张风格图像,模型难以提取稳定风格特征,易过拟合或风格失真。 |
❌ 推理依赖训练域 | 测试时输入图像必须来自训练时分布相近的领域,否则模型输出不可控、泛化能力弱。 |
❌ 训练耗时且资源密集 | 通常需数小时至数天GPU训练时间,不适合快速测试或小样本部署。 |
4、适用与非适用场景
✅ 适用场景
- 领域之间存在明显风格差异,但结构内容一致(如:实拍照片↔渲染图、风景↔油画)。
- 具备大规模非配对训练数据,可以覆盖目标领域的主要特征分布。
- 需要高质量风格映射效果,用于研究、艺术生成等精度要求较高任务。
❌ 非适用场景
- 仅有1~5张风格参考图像,无法支撑有效训练。
- 风格域差异较抽象或领域跨度过大(如素描↔动漫、照片↔2.5D手绘)时,CycleGAN输出容易失控。
- 对训练时长、部署资源有限制,如实时应用、比赛时间紧张等场合。
5、实战建议
在如 " 渲染图↔2.5D插画风格 " 的图像风格互换场景中,若仅有少量参考图或时间限制较大,建议优先采用无需训练的通用风格迁移方法(如AdaIN或FastStyleTransfer)。而CycleGAN更适用于训练资源充足、可离线生成高质量双向风格映射的情况。
三、CycleGAN:项目实战
1、环境配置
python
conda create -n CycleGAN38 python=3.8 -y
conda activate CycleGAN38
pip install requirements.txt
2、使用CPU模式而非GPU(默认强制使用,有GPU跳过该步骤)
(模型强制使用GPU)如果你没有 GPU 或者 CUDA 配置不正确,可以修改代码以强制使用 CPU:
(1)在 base_options.py 文件中
python
torch.cuda.set_device(opt.gpu_ids[0])
######################################################
(1)将其修改为:
######################################################
# 如果没有 GPU,可直接强制使用 CPU
if torch.cuda.is_available() and len(opt.gpu_ids) > 0:
torch.cuda.set_device(opt.gpu_ids[0])
else:
device = torch.device("cpu") # 强制使用 CPU
print("No GPU detected, using CPU instead.")
# state_dict = torch.load(load_path, map_location=str(self.device))
######################################################
(2)将其修改为:
######################################################
if self.device.type == 'cpu':
state_dict = torch.load(load_path, map_location=lambda storage, loc: storage)
else:
state_dict = torch.load(load_path, map_location=self.device)
(2)在 base_options.py 文件中
python
self.device = torch.device('cuda:{}'.format(self.gpu_ids[0])) if self.gpu_ids else torch.device('cpu') # get device name: CPU or GPU
######################################################
将其修改为:
######################################################
# self.device = torch.device('cuda:{}'.format(self.gpu_ids[0])) if self.gpu_ids and self.gpu_ids[0] != -1 else torch.device('cpu')
if self.gpu_ids and self.gpu_ids[0] != -1 and torch.cuda.is_available(): # 增加了 torch.cuda.is_available() 的检查
self.device = torch.device('cuda:{}'.format(self.gpu_ids[0]))
else: # 如果没有指定有效 GPU 或 CUDA 不可用,则强制使用 CPU
self.device = torch.device('cpu')
(3)在 networks.py 文件中
python
def init_net(net, init_type='normal', init_gain=0.02, gpu_ids=[]):
# if len(gpu_ids) > 0:
# assert(torch.cuda.is_available())
# net.to(gpu_ids[0])
# net = torch.nn.DataParallel(net, gpu_ids) # multi-GPUs
# init_weights(net, init_type, init_gain=init_gain)
# return net
######################################################
将其修改为:
######################################################
# Determine the device
if len(gpu_ids) > 0 and gpu_ids[0] != -1 and torch.cuda.is_available(): # 修改了这里的条件判断
device = torch.device('cuda:{}'.format(gpu_ids[0]))
net.to(device)
if len(gpu_ids) > 1: # Only use DataParallel if multiple GPUs are specified
net = torch.nn.DataParallel(net, gpu_ids) # multi-GPUs
else: # 增加了 else 分支来处理 CPU 情况
device = torch.device('cpu')
net.to(device)
init_weights(net, init_type, init_gain=init_gain)
return net
3、文件配置
(1)数据集下载
cyclegan地址:http://efrosgans.eecs.berkeley.edu/cyclegan/datasets/
(2)模型下载
cyclegan地址:http://efrosgans.eecs.berkeley.edu/cyclegan/pretrained_models/
4、代码测试(Test a CycleGAN model)
以下是两条test.py命令的参数逐项详细解析(详细请看test.py说明),用于在复现CycleGAN模型时正确理解和自定义测试流程:
python
✅ 命令1:双向测试 CycleGAN(A→B和B→A)
python test.py --dataroot ./datasets/maps --name maps_cyclegan --model cycle_gan
参数 含义
--dataroot ./datasets/maps 指定数据集根目录,CycleGAN会自动寻找testA/和testB/两个子目录,分别代表两个方向的测试数据
--name maps_cyclegan 模型名称,对应于checkpoints/maps_cyclegan路径下保存的训练模型参数(G_A、G_B等)
--model cycle_gan 指定模型类型为cycle_gan,表示使用CycleGAN的生成器G_A(A→B)和G_B(B→A)做双向翻译测试
✅ 命令2:仅单向测试(如horse→zebra)
python test.py --dataroot datasets/horse2zebra/testA --name horse2zebra_pretrained --model test --no_dropout
参数 含义
--dataroot datasets/horse2zebra/testA 测试集只提供testA/(源域图像),不需要testB/,只做单向A→B映射
--name horse2zebra_pretrained 指定模型名为horse2zebra_pretrained,将从checkpoints/horse2zebra_pretrained中加载训练好的G_A模型
--model test 指定测试模式为单向测试,默认只使用G_A(源域→目标域),不会进行Cycle Consistency或B→A映射
--no_dropout 禁用Dropout(测试阶段通常不使用Dropout,结果更加稳定)
📁 输出文件默认保存路径:./results/horse2zebra_pretrained/test_latest/images/
备注1:CycleGAN 本质上无法保证 " 主体不变、仅变风格 "
CycleGAN 所使用的是无监督图像到图像转换框架,其本质是:在不使用成对图像监督的前提下,学习两个域之间的整体映射关系,而不是单独控制前景或背景。
备注2:白 / 黑背景将使得模型失去迁移方向
原因如下:
CycleGAN不具备语义理解能力
它依靠像素分布的统计特征进行映射;
全白/黑背景的统计特征过于简单,模型难以提取有用信息;
如果背景占图像面积过大,模型会将背景视作主体的一部分。背景过于"干净",扰乱迁移逻辑
模型的迁移逻辑通常依赖局部纹理;
纯背景导致输入特征"太干净",而输出风格域中的背景往往存在纹理或渐变,模型会"强行添加内容";目标结构稀疏,易丢失原图语义
CycleGAN 的生成器为全卷积结构,弱语义感知;
当前景小、背景大时,模型会偏向"迁移背景",导致主题模糊。
对于CycleGAN:白/黑背景不是"无内容",而是"全是背景内容";
如果风格图中的背景有丰富纹理或颜色变化,模型会认为"纯白纯黑背景是待转换的区域";
最终结果:模型在尝试改变背景的过程中,牺牲了前景稳定性,迁移效果不佳。