谈谈图像的Style Transfer(一)

版权声明:要转随便转,如果能加上原文的链接就感谢各位了。( ⊙ o ⊙ ) https://blog.csdn.net/Hungryof/article/details/53981959

总说

最近更新:17-5-9 增加Neural style使用Gram矩阵的前提工作

其实这个方向火起来是从2015年Gatys发表的一篇文章 A Neural Algorithm of Artistic Style, 当然了,当时新闻报道还是很标题党的,看的我热血沸腾。。言归正传,虽然只过了短短一年多,但是相关的论文已经有二三十篇了,这些论文在原有的基础上进行了极大的扩展。从最初的Neural Style,到Ulyanov的Texture Networks: Feed-forward Synthesis of Textures and Stylized Images以及李飞飞老师的Perceptual Losses for Real-Time Style Transfer and Super-Resolution。 一般来说主要就是这3篇,后面两篇是差不多的,都是将原来的求解全局最优解问题转换成用前向网络逼近最优解,原版的方法每次要将一幅内容图进行风格转换,就要进行不断的迭代,而后两篇的方法是先将其进行训练,训练得到前向生成网络,以后再来一张内容图,直接输入到生成网络中,即可得到具有预先训练的风格的内容图。 除了这3篇主要的,还有就是将style transfer应用到视频中的,以及一些在改变Gram矩阵的,还有其他很多。这里只写其中某几篇。

下面是最初版本的效果图
这里写图片描述

Prisma上的一些图片,用的应该是改进版本的方法
这里写图片描述
这里写图片描述

额,别跟我提新海诚滤镜,能把人变成二次元?我直接呵呵。你用多了就知道,它的天空就是直接从原著漫画中截取的,就几种,根本不管你现实中有没有云彩。试用“新海诚风”滤镜后 我忍不住戳穿了它。 原理的话,自己百度一下“新海诚滤镜特效的实现解密”就可以了。在此不做评论。

说一下Neural style的工作用Gram的前些工作

在neural style出来之前,Gatys还做了这个工作Texture Synthesis Using Convolutional Neural
Networks
,他们发现如果让隐藏层的特征用协方差来进行进行约束,可以得到较好的纹理生成。
这里写图片描述
他们发现如果用协方差(也就是Gram矩阵)来进行约束隐藏层特征的话,重建出来的特征虽然有些会保持,但是有些可能位置会打散。比如最右侧的一张图,人还是人,但是重建出来相当于“拼图”效果了。这是因为协方差本身就是去除了位置信息。 那么既然协方差可以用于纹理生成,那么如果我们加上 “让生成图的隐藏层特征与原图尽量一样,另一方面让生成图的打散特征与画的打散特征尽量相似”,这就是用神经网络做风格转换的最初想法。这也比较符合“风格”的定义,毕竟风格不应该具有位置信息,一种风格应该是与位置无关的。

注意:Gatys的几篇论文没有解释为什么用Gram矩阵, 其实可以这样认为, 协方差就是一种二阶统计信息, 我们要求输出图的什么信息与风格图相近, 肯定不是feature map上单纯的逐点的相近, Gram矩阵描述的就是全局特征的自相关, 如果输出图与风格图的这种自相关相近, 那么差不多是我们所理解的”风格”. 当然, 其实也可以用很多其他的统计信息进行描绘风格. 这也就是后面有用直方图的, 甚至直接简化成”均值+方差”进行描绘风格的.

A Neural Algorithm of Artistic Style

下面约定 p 为风格图, a 为待转换的图,即内容图。比如 p 为某张梵高的画, a 为某个场景,生成为 f ,即具有梵高的画的风格的场景图。首先定义两个损失, l s t y l e l c o n t e n t ,前者希望 f p 在“风格”上尽量一致,后者则希望 f a 在内容上尽量一致。

l ( a , f , p ) = α l s t y l e ( p , f ) + β l c o n t e n t ( a , f )

上式子的 α β 为两个损失的平衡参数。我们希望 l 尽量小,采用梯度下降即可优化。所用的CNN网络是VGG-19。开始训练时,随机生成 a 同等大小的随机噪声图 x ,通过指定不同的层作为content损失的提取层 L c 以及style损失的提取层 L s ,使得 x L c 层得到的内容损失 l c o n t e n t ( L c , x ) l c o n t e n t ( L c , a ) 尽量一样。同时,使得 x L s 层得到的风格损失 l s t y l e ( L s , x ) l s t y l e ( L s , p ) 也尽量一样。其中 l c o n t e n t 的具体形式可以由MSE来指定,而 l s t y l e 可由对应的Gram矩阵来计算。

Gram矩阵则是计算feature map内部特征的互相关,由于采用的是VGG19较后层的feature map,因此提出的特征具有更多的语义性。

这个论文的方法是采用直接修改随机噪声,使得总体的误差最小。该方法每进行一次前向反向传播,都使得原有噪声得到微调,逐步逼近最终的效果图。主要缺点是速度慢,其次就是如果有大量的图要转换成同一种风格效果,比如我有很多图都想转换成古代文人墨客的山水画效果,我得一张一张的前向反向训练,效率实在太低,针对这一问题,有了下面的论文。

原版代码地址

https://github.com/jcjohnson/neural-style

Texture Networks: Feed-forward Synthesis of Textures and Stylized Images

该论文采用的方法就是根据Neural Style的速度慢的问题。他们通过两个网络,前一个是生成网络 G 和后一个是描述网络 D 。这样的话,就是学习 D 的权值。这就需要大量的内容图 a ,风格图仍旧是一张 p 。首先计算内容图的VGG特征 F c ( a ) ,并全部存储。训练时,假设某一次取的图是: a b a t c h , 对应的已存储的VGG特征是 F c ( a b a t c h ) , 将内容图 a b a t c h 作为输入 z 的前3个通道内容, z 的其他通道是噪声通道,从而得到 z b a t c h ,通过 G 网络得到 G ( z b a t c h ) ,再提取 G ( z b a t c h ) 在描述网络 D 中的content层的特征 F c ( G ( z b a t c h ) ) 。同时 提取 G ( z b a t c h ) 在描述网络中的style层,得到特征 F s ( G ( z b a t c h ) ) 。之后内容损失 L c o n t e n t 采用的是 F c ( G ( z b a t c h ) ) F c ( a b a t c h ) 的MSE,同时风格损失 L s t y l e 则先计算 F s ( G ( z b a t c h ) ) F s ( p ) 各自的Gram矩阵,再求MSE。其中Gram矩阵定义如下:

G i j l = 1 M l k = 1 M l F i k l F j k l = 1 M l F i : l , F j : l
,文章末尾是对Gram的解释。
其中 F i : l 是第 l 层的的第 i 个feature map的竖直向量化表示。可以看出是将每一个feature map相互内积。个人认为,同一层得到的不同个feature map可以认为是“同等非线性复杂程度的feature map”。这种特征对物体的特征表达能力是相近的,可以进行互相关操作,进而综合利用这些特征从而表示图像的风格。

该方法的模型一旦训练好,则生成网络 G 就会将输入 z 转换成符合风格 p 的效果图,同时保持其原本内容的语义信息。从这里就可以看出,如果要想两个图像在语义层次上的信息匹配,那么就要减少高层的特征之间的差异。图像的风格似乎还需要进行Gram矩阵运算,从而找到这些feature map之间的特征的互相关,而这些互相关可以作为一张图片的风格表达。由于Neural Style在content loss和style loss之间是有比例的,不同比例可以设置效果图的风格化程度。但是该论文的方法当模型训练时,两个loss的比例已经固定,然而在测试时仍旧可以将 z 的噪声通道乘上一个系数 k 来得到不同的风格化程度。至于为什么要选用内容图 a 作为 z 的前3个通道,很简单。因为你最终得到的效果图在内容上是 a 的,所以图像的概率分布应该类似,所以这样做就是为了加速学习效果。

另一篇与之有异曲同工之妙的是李飞飞的Perceptual Losses for Real-Time Style Transfer and Super-Resolution。只不过后者生成网络没有用多个分辨率的 ,其在style transfer中是先将input进行stride-2的下采样,然后再接上数个残差网络,再用stride为1/2的fractionally convolution进行上采样。而Texture Nets则是采用金字塔模型,其相比Percentual Losses的模型缺少一定程度的自适应性。貌似有一种趋势,普通的Pooling和直接的上/下采样正在逐渐被stride>1的convolution和fractionally convolution所取代。人们解释说这种采样方式可能更加具有自适应性。
图1. Texture Nets的网络
这里写图片描述


这里写图片描述


图2. Percentual Losses的G
这里写图片描述

代码地址

https://github.com/DmitryUlyanov/texture_nets ,他们不久后又发了一篇论文Instance Normalization: The Missing Ingredient for Fast Stylization,因此代码其实实现了他们自己的2篇,也是李飞飞的非官方Torch7实现。
李飞飞的原版代码是chainer框架的:https://github.com/yusuketomoto/chainer-fast-neuralstyle

Incorporating long-range consistency in CNN-based texture generation

该论文解释了Gram矩阵为什么可以用于图像风格提取。其认为feature map经过Gram矩阵后,就是将各个特征进行内积。论文指出:Gram矩阵只能提取静态特征,而且是将整幅图片进行空间平均(spatial averaging)。其对参考图像中的物体的空间排列是完全blind。因此,作者希望能找到一种特征的表达方式,使得物体的空间排列信息保留。论文中采用feature maps F l 和feature maps的一个空间变换 T ( F l ) 进行内积。由于 F l T ( F l ) 具有空间的偏移,进而进行Gram矩阵计算得到互相关,这种互相关包含 的空间偏移,即保留了物体的空间排列信息。
这里写图片描述

论文中实现了平移和翻转的空间变换,并且通过这些变换计算出来的style loss可以组合,从而得到具有特定对称信息的图片。在某种程度上,可以这样认为该论文通过对Gram的空间变换,从而赋予特征互相关信息额外的空间信息。这种丰富化的互相关信息在可以进行更加有效地风格化表达。

代码

这个论文不太有名。。 https://github.com/guillaumebrg/texture_generation
其实直接用原版代码改改Gram矩阵就可以了。

Deep Identity-aware Transfer of Facial Attributes

这篇论文将GAN与Style Transfer结合在一起,实现了一些人脸属性的风格转换。以前的GAN是由噪声直接通过minmax过程生成与数据集具有类似分布的图片,而Style Transfer是将一幅图的属性迁移到另一幅图上面。如果要实现自身属性的变换,假设原图为 x ,属性变换后的图为 T ( x ) ,而由于一般情况下没有可以参照的“风格图(即 的GroundTruth)”,因此无法像常规的Style Transfer那样进行优化。该论文以眼镜去除为例, x 为戴眼镜的一些图,想得到去除眼镜的 T ( x ) , 利用其他一些图片 x (未戴眼镜)作为引导。由于 x x 的概率分布不会相差特别大,因此可以作为一个引导。采用GAN的思想,使得 T ( x ) x 让判别网络 D 无法分辨。此时即可认为 T ( x ) 接近 x 的GroundTruth。

论文的关键是目标函数,提出了DIAT和DIAT-A。由于前者效果较后者差,而且方法较为繁琐,因而这里只说DIAT-A。个人认为DIAT-A最关键的一点是将属性损失定义在 D 上。这一点好像是Improved GAN的思想中的Feature Matching。主要是认为,先前的定义在固定的VGG-Face网络中的损失在优化上不容易,如果能在 D 的隐藏层 l 进行加入监督项,用以衡量 生成的效果。使得 D l ( T ( x ) ) 能在网络 T 更新时随时更改,此时更易得到更好的 T

l i d d y n a m i c ( x ) = l = 4 5 w l l d y n a m i c D , l ( T ( x ) , x )

min T max D E a p a t t ( a ) [ l o g D ( a ) ] + E x p d a t a ( x ) [ 1 l o g D ( T ( x ) ) + λ l i d d y n a m i c ( x ) ]

更新 D 时, T 固定,此时 l i d d y n a m i c ( x ) 是固定的。因此损失是

E a p a t t ( a ) [ l o g D ( a ) ] + E x p d a t a ( x ) [ 1 l o g D ( T ( x ) ) ]

更新 T 时, D 固定,因此 E a p a t t ( a ) [ l o g D ( a ) ] 固定,可去除,最终损失为:

E x p d a t a ( x ) [ 1 l o g D ( T ( x ) ) + λ l i d d y n a m i c ( x ) ]

效果图
这里写图片描述

这里写图片描述

插入对Gram的解释

Gram矩阵其实是一种度量矩阵。矩阵分析中有这样的定义。
V n 维欧式空间 ϵ 1 , , ϵ n 是它的一个基, g i j = ( ϵ i , ϵ j ) , G = ( g i j ) n × n , 则称 G 为基 ϵ 1 , , ϵ n 的度量矩阵,也称为Gram矩阵。
重点解释:
因此:对于三维的向量求Gram矩阵,就是要求 g i j ,而 g i j 就是第i通道与第j通道进行点乘,然后相加。其实专业点就是i通道的feature map与j通道的feature map进行内积。查看内积定义:对于两个竖直向量 α = ( a 1 , , a n ) T , β = ( b 1 , , b n ) , 规定 < α , β >= α T β = i = 1 n a i b i 。所以可以看出,如果将矩阵先进行竖直向量化,然后将其转置,两者进行矩阵相乘,结果就是内积,或是说对应位置点乘,然后相加

Gram矩阵和卷积网络中的卷积的差别

Gram矩阵是计算每个通道i的feature map与每个通道j的feature map的内积。自然就会得到C*C的矩阵。Gram矩阵的每个值可以说是代表i通道的feature map与j通道的feature map的互相关程度。而卷积网络的卷积其实也是互相关,具体情况见CNN基本问题。 值得注意的是:卷积网络的卷积的实现与框架有关。反正torch是直接将将卷积核卷积的,并不先进行旋转卷积核,即互相关是一样的,而不是信号处理中所说的要先将卷积核旋转180再计算。 原因很简单,因为两种方式的最终学到的权值的差别,也就是旋转180°就可以了,完全不影响效果。

require("torch")
require('nn')

local  net = nn.Sequential()
local module = nn.SpatialConvolution(1,1,2,2):noBias()
net:add(module)
local wt = torch.Tensor(2,2)
wt[{1,1}]=5
wt[{1,2}]=6
wt[{2,1}]=7
wt[{2,2}]=8
print(wt)
net:get(1).weight = wt:view(1,1,2,2)

local input = torch.Tensor(2,2)
--local wt = torch.Tensor(2,2)
input[{1,1}]=1
input[{1,2}]=5
input[{2,1}]=3
input[{2,2}]=4
print(net:forward(input:view(1,1,2,2)))

print('xcorr2')
print(torch.xcorr2(input,wt))

print('conv2')
print(torch.conv2(input,wt))

-- 输出结果
[torch.DoubleTensor of size 2x2]

(1,1,.,.) =
  88
[torch.DoubleTensor of size 1x1x1x1]

xcorr2
 88
[torch.DoubleTensor of size 1x1]


-- 这里确实是卷积核旋转180度,再卷
conv2
 81
[torch.DoubleTensor of size 1x1]

结论:卷积网络中的卷积就是互相关,等价于torch.xcorr2或torch.xorr3之类的,而信号处理说的卷积等价于torch.conv2之类的

更多的style transfer可以看
超越fast style transfer—-任意风格图和内容图0.1秒出结果
后面可能会写 style transfer(二)记录最新的发展。

猜你喜欢

转载自blog.csdn.net/Hungryof/article/details/53981959