Universal Style Transfer via Feature Transforms (WCT,风格迁移,NIPS2017)

Li Y, Fang C, Yang J, et al. Universal Style Transfer via Feature Transforms. NIPS 2017

风格迁移的关键问题是如何提取有效果的风格特征并且让输入的内容图像去匹配这种风格。前人的工作证明了协方差矩阵和Gram矩阵能较好地反映视觉风格。

基于优化的风格迁移方法,可以处理任意风格并且达到满意的效果但是计算代价太大(时间太长);基于前馈网络的方法可以高效运行,但是局限于固定种类的风格或者不太好的视觉效果。

同时实现generalization , quality ,efficiency的任意风格转换时一个挑战性的任务。

generalization: 说的应该是处理多种甚至任意风格图像的能力。

这篇工作提出的方法是用whitening and coloring变换来实现风格迁移, 思想是将风格迁移任务看做是一个图像重构并进行特征变换的任务。WCT操作:输入内容图像特征和风格特征,输出调整后的内容特征使得输入内容特征的协方差矩阵和输入风格特征的协方差矩阵相匹配。

事先需要预训练一个VGG作为encoder和一个与之对称的decoder。它们的参数在后续实验中保持固定。

在这里插入图片描述

在这里插入图片描述

输入的内容图像C和风格图像S经过VGG提取出high-level高层特征 (Relu5_1),进行Whitening and Coloring Transform (WCT),然后通过decoder恢复到原图大小。

再将变换后的图像C和风格图像S经过VGG提取出较低一层的特征(Relu4_1),进行WCT,然后通过decoder恢复到原图大小。

再将变换后的图像C和风格图像S经过VGG提取出低层的特征(Relu1_1),进行WCT,然后通过decoder恢复到原图大小。

The result obtained by matching higher level statistics of the style is treated as the new content to continue to match lower-level information of the style.

也就是说经过匹配了风格图像高层统计量的图像作为新的内容图像继续去匹配风格图像的低层信息。这样各层统计量都得到了匹配。 (Multi-level coarse-to-fine stylization)

重构误差
在这里插入图片描述

特征进行whitening,之后decode 操作效果:
在这里插入图片描述
保持了图像的全局内容,移除了与风格有关的信息。细节处的笔画图案被移除了

在这里插入图片描述

It clearly shows that the higher layer features capture more complicated local structures, while lower layer features carry more low-level information (e.g., colors).

高层特征反映了复杂的局部结构,低层特征具有更多的低层(细节)信息。工作的优化顺序是先匹配高层统计量,再匹配低层统计量。

which indicates that the higher layer features first capture salient patterns of the style and lower layer features further improve details
高层特征捕捉到了风格的显著模式,低层特征进一步优化细节。实验证明:如果先匹配低层统计量,再匹配高层统计量,低层细节信息在高层特征经过操作之后不能被保留。

控制风格化程度
在这里插入图片描述
α \alpha α被称之为style weight.
where α \alpha α serves as the style weight for users to control the transfer effect.

拓展到纹理生成 Texture synthesis:

将输入内容图像替换成随机噪声图像

生成新纹理的插值方式:

在这里插入图片描述

之后将 f c s ^ \hat{f_{cs}} fcs^送入decoder

在这里插入图片描述
In contrast, our approach explains each input noise better because the network is unlikely to absorb the variations in input noise since it is never trained for learning textures.
对于纹理生成一个重要的评价指标是diversity, [27]通过输入噪声生成不同的结果图像。但是实验结果证明噪声被吸收/发挥出了微不足道的效果,因此难以驱动网络去生成较大的视觉变化/差异。相比较而言, 由于proposed mehod对于纹理生成不需要经过训练过程,所以proposed method吸收噪声的能力并不那么强。

WCT操作

目标:在这里插入图片描述

其中 f c s ^ \hat{f_{cs}} fcs^是指匹配之后的特征, f s f_s fs是指风格特征。

1) Whitening操作:

先对 f c f_c fc中心化 (We first center f s f_s fs by subtracting its mean vector m s m_s ms)

之后:
在这里插入图片描述
其中 E c E_c Ec f c f c T f_cf_c^T fcfcT进行特征分解后的特征向量构成的方阵, D c D_c Dc为特征值构成的对角阵。

这样变换后的 f c ^ \hat{f_c} fc^正交:

f c ^ f c ^ T = I \hat{f_c} \hat{f_c}^T= I fc^fc^T=I

证明:

因为,对于所有特征向量 x x x
f c f c T x = λ x f_c f_c^T x=\lambda x fcfcTx=λx

所以 f c f c T E c = E c D c f_c f_c^T E_c=E_c D_c fcfcTEc=EcDc

因为 E c E_c Ec为正交方阵,故 E c E c T = I E_c E_c^T=I EcEcT=I,并且 E c T E c = I E_c^T E_c=I EcTEc=I

所以 f c f c T = E c D c E c T f_c f_c^T = E_c D_c E_c^T fcfcT=EcDcEcT
所以 E c T f c f c T E c = D c E_c^T f_c f_c^T E_c = D_c EcTfcfcTEc=Dc

所以
f c ^ f c ^ T = E c D c − 1 2 E c T f c f c T E c D c − 1 2 T E c T = E c D c − 1 2 D c D c − 1 2 T E c T = E c D c − 1 2 D c D c − 1 2 E c T = E c E c T = I \begin{aligned} \hat{f_c}\hat{f_c}^T&=E_c D_c^{-\frac{1}{2}} E_c^T f_c f_c^T E_c D_c^{-\frac{1}{2}T}E_c^T \\ &=E_c D_c^{-\frac{1}{2}} D_c D_c^{-\frac{1}{2}T}E_c^T \\ &=E_c D_c^{-\frac{1}{2}} D_c D_c^{-\frac{1}{2}}E_c^T \\ &=E_c E_c^T \\ &= I \end{aligned} fc^fc^T=EcDc21EcTfcfcTEcDc21TEcT=EcDc21DcDc21TEcT=EcDc21DcDc21EcT=EcEcT=I

2) Coloring操作:

先对 f s f_s fs中心化,再进行变换:在这里插入图片描述
其中 E s E_s Es f s f s T f_sf_s^T fsfsT进行特征分解后的特征向量构成的方阵, D s D_s Ds为特征值构成的对角阵。

最后再对 f c s ^ \hat{f_{cs}} fcs^去中心化
在这里插入图片描述

这样先进行Whitening再进行Coloring之后,能够使变换后的特征和风格图特征的协方差矩阵匹配:在这里插入图片描述
证明:
f c s ^ f c s ^ T = E s D s 1 2 E s T f c ^ f c ^ T E s D s 1 2 T E s T = E s D s 1 2 E s T E s D s 1 2 E s T = E s D s 1 2 D s 1 2 T E s = E s D s 1 2 D s 1 2 E s = E s D s E s = f s f s T \begin{aligned} \hat{f_{cs}}\hat{f_{cs}}^T &= E_s D_s^{\frac{1}{2}} E_s^T \hat{f_c} \hat{f_c}^T E_s D_s^{\frac{1}{2}T} E_s^T \\ &=E_s D_s^{\frac{1}{2}} E_s^T E_s D_s^{\frac{1}{2}} E_s^T \\ &=E_s D_s^{\frac{1}{2}} D_s^{\frac{1}{2}T} E_s \\ &=E_s D_s^{\frac{1}{2}} D_s^{\frac{1}{2}} E_s \\ &=E_s D_s E_s \\ &= f_s f_s^T \end{aligned} fcs^fcs^T=EsDs21EsTfc^fc^TEsDs21TEsT=EsDs21EsTEsDs21EsT=EsDs21Ds21TEs=EsDs21Ds21Es=EsDsEs=fsfsT

  • 1
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
好的,关于 pytorch 神经风格迁移,我可以给你一些简单的介绍和实现方法。 神经风格迁移是一种将两张图片进行融合的技术,其中一张图片是内容图片,另一张图片是风格图片。通过神经网络的训练,可以将内容图片的内容与风格图片的风格进行融合,生成一张新的图片。 在 PyTorch 中,可以使用预训练的 VGG 网络来实现神经风格迁移。具体步骤如下: 1. 加载预训练的 VGG 网络,并将其分为两部分:特征提取器和分类器。 2. 定义损失函数,包括内容损失和风格损失。 3. 定义优化器,并对输入图片进行优化,使其逐渐接近目标图片。 4. 进行训练,并输出最终生成的图片。 下面是一个简单的 PyTorch 实现代码: ```python import torch import torch.nn as nn import torch.optim as optim import torchvision.models as models import torchvision.transforms as transforms from PIL import Image # 加载预训练的 VGG 网络 vgg = models.vgg19(pretrained=True).features # 将 VGG 网络分为特征提取器和分类器 feature_extractor = nn.Sequential() for i, layer in enumerate(vgg): if isinstance(layer, nn.Conv2d): name = f'conv_{i}' elif isinstance(layer, nn.ReLU): name = f'relu_{i}' layer = nn.ReLU(inplace=False) elif isinstance(layer, nn.MaxPool2d): name = f'pool_{i}' elif isinstance(layer, nn.BatchNorm2d): name = f'bn_{i}' else: raise RuntimeError(f'Unrecognized layer: {layer.__class__.__name__}') feature_extractor.add_module(name, layer) # 定义损失函数 class StyleContentLoss(nn.Module): def __init__(self, target_features): super().__init__() self.target_features = target_features.detach() self.content_loss = nn.MSELoss() self.style_loss = nn.MSELoss() def forward(self, input_features): content_features = input_features[0] style_features = input_features[1:] # 计算内容损失 content_loss = self.content_loss(content_features, self.target_features) # 计算风格损失 style_loss = 0 for target_feature, input_feature in zip(self.target_features, style_features): target_gram = gram_matrix(target_feature) input_gram = gram_matrix(input_feature) style_loss += self.style_loss(input_gram, target_gram) # 返回总损失 return content_loss + style_loss # 定义优化器 optimizer = optim.LBFGS([input_image.requires_grad_()]) # 对输入图片进行优化 def run_style_transfer(content_image, style_image, num_steps=300, content_weight=1, style_weight=1000): # 加载图片并进行预处理 content_tensor = preprocess_image(content_image) style_tensor = preprocess_image(style_image) input_tensor = content_tensor.clone().requires_grad_() # 提取目标特征 with torch.no_grad(): content_features = feature_extractor(content_tensor) style_features = feature_extractor(style_tensor) target_features = [content_features[2]] for style_feature in style_features: target_features.append(gram_matrix(style_feature)) # 定义损失函数 loss_fn = StyleContentLoss(target_features) # 进行训练 for i in range(num_steps): def closure(): optimizer.zero_grad() input_features = feature_extractor(input_tensor) loss = loss_fn(input_features) loss.backward() return loss optimizer.step(closure) # 返回最终生成的图片 output_tensor = input_tensor.detach().squeeze() output_image = deprocess_image(output_tensor) return output_image # 定义辅助函数 def preprocess_image(image): transform = transforms.Compose([ transforms.Resize(512), transforms.ToTensor(), transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]) ]) tensor = transform(image).unsqueeze(0) return tensor.to(device) def deprocess_image(tensor): transform = transforms.Normalize(mean=[-0.485/0.229, -0.456/0.224, -0.406/0.225], std=[1/0.229, 1/0.224, 1/0.225]) image = tensor.clone().detach().squeeze() image = transform(image).clamp(0, 1) image = transforms.ToPILImage()(image) return image def gram_matrix(input): batch_size, channel, height, width = input.size() features = input.view(batch_size * channel, height * width) gram = torch.mm(features, features.t()) return gram.div(batch_size * channel * height * width) # 加载图片 content_image = Image.open('content.jpg') style_image = Image.open('style.jpg') # 进行风格迁移 output_image = run_style_transfer(content_image, style_image) # 保存结果 output_image.save('output.jpg') ```
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值