ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

使用 PyTorch 实现神经风格迁移:VGGNet 特征重建与 Gram 矩阵损失全解析

2026/9/30 6:42:50 拓冰建站 浏览量
使用 PyTorch 实现神经风格迁移:VGGNet 特征重建与 Gram 矩阵损失全解析 示例工程【免费下载链接】pytorch-tutorialPyTorch Tutorial for Deep Learning Researchers项目地址https://gitcode.com/gh_mirrors/py/pytorch-tutorial点击查看免费下载神经风格迁移Neural Style Transfer是深度学习图像生成领域最经典的算法之一它用 CNN 将一张照片的内容与一幅画作的风格融合生成全新的艺术化图像。本文以 pytorch-tutorial 仓库中 tutorials/03-advanced/neural_style_transfer 的完整实现为骨架深入讲解内容损失Content Loss与风格损失Style Loss的数学原理、VGGNet 特征提取的源码细节以及完整的命令行运行与参数调优方案。读完本文你将掌握从零复现神经风格迁移的能力并能熟练调整风格权重、优化步数与采样频率等关键参数。算法总览一张照片 一幅画 一张新图像神经风格迁移的核心目标非常直观给定内容图像如一张人物照片与风格图像如一幅波普艺术画作生成一张目标图像使它在内容上与内容图像尽可能接近、在风格上与风格图像尽可能接近。算法不是训练一个生成网络而是在预训练好的 VGGNet 上做逐像素优化把目标图像当作可学习参数通过反向传播不断更新它。原版算法由 Gatys 等人于 2015 年提出论文《A Neural Algorithm of Artistic Style》核心思想是利用预训练 CNN 不同卷积层的特征图来解耦内容与风格深层的卷积特征保留图像的高层语义内容而浅层特征之间的相关性则刻画纹理风格。该教程仓库中的 main.py 以不到 130 行代码完整实现了这一算法非常适合作为理解风格迁移原理的入门范本。算法流程可概括为四步将内容图像与风格图像分别前向传播到预训练 VGGNet提取多层卷积特征图将目标图像初始化为内容图像的克隆同样前向传播提取特征分别计算内容损失与风格损失加权求和得到总损失用 Adam 优化器对目标图像的像素做梯度更新迭代多步后得到风格化结果。核心原理内容损失与风格损失内容损失Content Loss约束高层语义特征要最小化目标图像与内容图像的内容差异做法是让两者在 VGGNet 多个卷积层上的特征图尽可能一致。具体地把内容图像与目标图像分别前向传播到预训练 VGGNet提取多个卷积层的特征图然后计算二者特征图之间的均方误差Mean-Squared Error, MSE。对应到源码 main.pyfor f1, f2, f3 in zip(target_features, content_features, style_features): # Compute content loss with target and content images content_loss torch.mean((f1 - f2)**2)其中f1是目标图像的特征图f2是内容图像的特征图。content_loss累加 5 个选定卷积层的 MSE 之和。由于特征图是多通道的MSE 会对所有通道、所有空间位置求均值因此它度量的是整体像素级特征的接近程度——当内容损失趋近于 0 时目标图像在 VGGNet 眼中的高层语义就与内容图像几乎一致。风格损失Style Loss用 Gram 矩阵约束纹理相关性内容损失约束的是特征图本身的数值而风格损失约束的是特征图通道之间的相关性。思路是把每个卷积层的特征图展平为(C, H×W)的矩阵再与其转置相乘得到C×C的 Gram 矩阵。Gram 矩阵的每个元素G_ij度量了第i个通道与第j个通道特征之间的相关性这种统计相关性正是纹理风格的本质表征——它丢弃了空间位置信息只保留哪些纹理模式倾向同时出现。源码中 Gram 矩阵与风格损失的计算位于 main.py# Reshape convolutional feature maps _, c, h, w f1.size() f1 f1.view(c, h * w) f3 f3.view(c, h * w) # Compute gram matrix f1 torch.mm(f1, f1.t()) f3 torch.mm(f3, f3.t()) # Compute style loss with target and style images style_loss torch.mean((f1 - f3)**2) / (c * h * w)这里f1是目标图像的特征图f3是风格图像的特征图。二者展平后各自计算 Gram 矩阵再求 MSE并除以c * h * w做归一化避免不同层特征图尺寸差异导致损失量级失衡。风格损失越小目标图像的通道间相关性统计就越接近风格图像从而在纹理上趋同于风格画作。总损失与权重平衡总损失为内容损失与风格损失的加权和见 main.pyloss content_loss config.style_weight * style_loss默认style_weight 100见 参数定义即风格损失被放大 100 倍。这一权重直接控制最终效果偏向保留内容还是强化风格权重过小结果接近原照片权重过大内容结构会被风格纹理淹没甚至完全失真。这是本教程中最重要的可调参数。源码级实现剖析环境依赖该示例的依赖极少见 requirements.txttorch/torchvision模型与预训练权重来源Pillow图像 I/Oargparse命令行参数解析仓库根目录 README.md 声明整体教程依赖 Python 2.7 或 3.5、PyTorch 0.4.0。考虑到models.vgg19(pretrainedTrue)会下载 VGG19 的 ImageNet 预训练权重建议在联网环境中运行。设备配置与图像加载main.py 首先自动选择运行设备device torch.device(cuda if torch.cuda.is_available() else cpu)load_image函数main.py负责读入图像并转成张量支持两种缩放策略def load_image(image_path, transformNone, max_sizeNone, shapeNone): image Image.open(image_path) if max_size: scale max_size / max(image.size) size np.array(image.size) * scale image image.resize(size.astype(int), Image.ANTIALIAS) if shape: image image.resize(shape, Image.LANCZOS) if transform: image transform(image).unsqueeze(0) return image.to(device)max_size按比例缩放使图像最长边不超过指定像素数默认 400用于控制计算量shape强制缩放到指定尺寸(H, W)用于把风格图像拉伸到与内容图像一致。在main中main.pycontent load_image(config.content, transform, max_sizeconfig.max_size) style load_image(config.style, transform, shape[content.size(2), content.size(3)])风格图像被强制 resize 成内容图像的尺寸这样两路特征图的空间大小一致Gram 矩阵可以直接做减法。图像归一化与反归一化VGGNet 在 ImageNet 上训练时输入图像被归一化到均值为mean[0.485, 0.456, 0.406]、标准差为std[0.229, 0.224, 0.225]因此风格迁移也必须使用同样的统计量做标准化main.pytransform transforms.Compose([ transforms.ToTensor(), transforms.Normalize(mean(0.485, 0.456, 0.406), std(0.229, 0.224, 0.225))])保存结果前需要做逆变换反归一化源码中的反归一化参数main.pydenorm transforms.Normalize((-2.12, -2.04, -1.80), (4.37, 4.46, 4.44))其中-2.12 ≈ -0.485 / 0.229、4.37 ≈ 1 / 0.229等正是前面均值和标准差的逆运算(x - mean) / std的逆为x * std mean展开即(x mean_neg) * std_scale形式之后用clamp_(0, 1)把像素裁剪回合法区间。VGGNet 特征提取网络风格迁移使用 VGGNet 作为特征提取器。本实现直接复用torchvision.models.vgg19(pretrainedTrue).features并只保留其中 5 个卷积层输出见 main.pyclass VGGNet(nn.Module): def __init__(self): Select conv1_1 ~ conv5_1 activation maps. super(VGGNet, self).__init__() self.select [0, 5, 10, 19, 28] self.vgg models.vgg19(pretrainedTrue).features def forward(self, x): Extract multiple convolutional feature maps. features [] for name, layer in self.vgg._modules.items(): x layer(x) if name in self.select: features.append(x) return features关键点select [0, 5, 10, 19, 28]是 VGG19features模块中的层索引分别对应conv1_1、conv2_1、conv3_1、conv4_1、conv5_1五个卷积层从源码注释 Select conv1_1 ~ conv5_1 activation maps 可以确认这一对应关系前向传播时逐层执行命中选中的层就保存特征图最终返回包含 5 张特征图的列表在 main.py 中模型被置于eval()模式风格迁移不更新 VGGNet 的权重它只作为固定的特征提取器。跨层使用 conv1_1 到 conv5_1 的好处是浅层捕捉局部纹理风格深层捕捉全局语义内容多尺度联合约束能让生成图像既有清晰的内容结构又有丰富的纹理细节。优化循环与迭代更新目标图像初始化为内容图像的克隆并开启梯度追踪main.pytarget content.clone().requires_grad_(True)优化器选择 Adam学习率lr0.003、动量项betas[0.5, 0.999]main.py。每一步迭代中main.py分别前向传播目标、内容、风格三张图像各得到 5 张特征图逐层累加内容损失与风格损失加权组合总损失zero_grad → backward → step更新目标图像像素按log_step间隔打印损失值按sample_step间隔保存中间结果。loss content_loss config.style_weight * style_loss optimizer.zero_grad() loss.backward() optimizer.step()中间结果保存按sample_step间隔把当前目标图像反归一化、裁剪并保存为output-{step1}.pngmain.pydenorm transforms.Normalize((-2.12, -2.04, -1.80), (4.37, 4.46, 4.44)) img target.clone().squeeze() img denorm(img).clamp_(0, 1) torchvision.utils.save_image(img, output-{}.png.format(step1))默认sample_step500时会在第 500、1000、1500、2000 步各生成一张output-*.png便于观察风格迁移从接近原图到逐步风格化的收敛过程。命令行参数详解所有可调参数由 main.py 中的argparse定义下表汇总了每个参数的语义与默认值参数类型默认值作用--contentstrpng/content.png内容图像路径默认为仓库内置的 Anne Hathaway 照片--stylestrpng/style.png风格图像路径默认为仓库内置的波普艺术画作--max_sizeint400内容图像缩放后的最长边像素数越小训练越快、显存占用越低--total_stepint2000总优化迭代步数步数越多风格化越充分--log_stepint10每多少步打印一次内容/风格损失--sample_stepint500每多少步保存一张中间结果图output-*.png--style_weightfloat100风格损失在总损失中的权重控制内容保真 vs 风格强化的平衡--lrfloat0.003Adam 优化器的学习率其中--style_weight对成图效果影响最大增大它会让纹理风格更浓烈减小它则更贴近原始照片--max_size与--total_step则直接决定计算开销与收敛程度可依 GPU 显存和耐心程度灵活调整。运行与复现在仓库的tutorials/03-advanced/neural_style_transfer目录下执行与 README 中的 Usage 一致$ pip install -r requirements.txt $ python main.py --contentpng/content.png --stylepng/style.png仓库为png/目录内置了完整的输入素材与示例结果内容图像 png/content.pngAnne Hathaway 的人物照片风格图像 png/style.png、png/style2.png、png/style3.png、png/style4.png分别对应波普艺术、表现主义肖像、古典油画蒙娜丽莎与视错觉版画等多种风格可直接替换--style参数体验不同风格的迁移效果结果示例 png/neural_style.png 与 png/neural_style2.png展示了多风格迁移的对比效果。执行后终端会每隔log_step步打印一次损失例如Step [10/2000], Content Loss: 2.3156, Style Loss: 12.4839 Step [20/2000], Content Loss: 1.8034, Style Loss: 9.2172随着迭代推进内容损失与风格损失整体呈下降趋势同时目录下会逐步生成output-500.png、output-1000.png等中间结果。下图为单一风格迁移的示例输出输入为人物照片风格为表现主义肖像画将同一张人物照片分别与波普、古典油画、素描等多种艺术风格融合可以得到风格差异显著的多组结果其效果合集如下图所示参数调优与实战建议基于源码的实现机制可以从以下几个方面入手调优风格强度增大--style_weight如 300、1000会让纹理更浓烈但过大会破坏内容结构减小如 10则接近照片原貌。建议先在 10300 区间做小步长对比迭代步数--total_step默认 2000。实际观察损失曲线若到 2000 步仍未收敛可适当增大若显存或时间紧张1000 步通常已能获得可用结果分辨率与速度的权衡--max_size控制内容图最长边默认 400。分辨率翻倍特征图面积约翻 4 倍计算量与显存会显著上升适合追求高清晰度成图时使用观察收敛过程利用--sample_step的中间输出output-500.png、output-1000.png等检查风格迁移轨迹可以直观判断是风格不够还是内容被破坏从而决定调整方向更换风格素材将--style指向仓库png/下的任意画作即可在几秒内生成不同艺术流派的风格化图像适合快速验证算法对不同纹理的鲁棒性。小结神经风格迁移是理解用优化而非生成来制造图像的代表性案例。本教程实现以预训练 VGG19 为固定特征提取器通过内容损失特征图 MSE约束高层语义、风格损失Gram 矩阵 MSE约束通道相关性配合 Adam 优化器直接更新目标图像像素完整覆盖了算法从原理到工程实现的全部环节。核心代码集中在 main.py图像加载与归一化L15-L63、VGGNet 特征提取L33-L47、损失计算与优化循环L71-L100、结果保存L106-L111、参数入口L114-L124。在此基础上你可以进一步尝试增加更多特征层、改用不同预训练网络如 ResNet、加入总变差正则抑制噪声乃至把该流程演化为风格迁移的快速前馈网络向更深层的生成式建模方向延伸。赞分享示例工程【免费下载链接】pytorch-tutorialPyTorch Tutorial for Deep Learning Researchers项目地址https://gitcode.com/gh_mirrors/py/pytorch-tutorial点击查看免费下载相关推荐Deep Image Prior风格损失实现指南基于Gram矩阵的完整解析Deep Image Prior风格损失实现指南基于Gram矩阵的完整解析 在深度学习图像处理领域 Deep Image Prior 项目提出了一种无需预训深度学习计算机视觉图像处理PyTorch实现神经风格迁移教程PyTorch实现神经风格迁移教程 项目介绍 本项目基于PyTorch实现了论文《A Neural Algorithm of Artistic Style》中的clickhouse-backup常见问题排查从备份失败到恢复异常的解决方案clickhouse backup常见问题排查从备份失败到恢复异常的解决方案 clickhouse backup是一款专为ClickHouse数据库设计的备份后端运维上一篇OptiScaler跨GPU升级技术与帧生成的高效分布式渲染优化方案下一篇10分钟搞定Scoop仓库故障转移从崩溃到自愈的完整指南创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考