图像风格迁移原理
所谓图像风格迁移,是指利用算法学习著名画作的风格,然后再把这种风格应用到另外一张图片上的技术。著名的图像处理应用Prisma是利用风格迁移技术,普通用户的照片自动变换为具有艺术家风格的图片。
一、图像风格迁移的原理
1、原始图像风格迁移的原理
在学习原始的图像风格迁移之前,可以在先看看ImageNet图像识别模型VGGNet(微调(Fine-tune)原理)。事实上,可以这样理解VGGNet的结构:前面的卷积层是从图像中提取“特征”,而后面的全连接层把图片的“特征”转换为类别概率。其中,VGGNet中的浅层(如conv1_1,conv1_2),提取的特征往往是比较简单的(如检测点、线、亮度),VGGNet中的深层(如conv5_1,conv5_2),提取的特征往往比较复杂(如有无人脸或某种特定物体)。
VGGNet本意是输入图像,提取特征,并输出图像类别。图像风格迁移正好与其相反,输入的是特征,输出对应这种特征的图片,如下图所示:
具体来说,风格迁移使用卷积层的中间特征还原出对应这种特征的原始图像。如下图所示,先选取一幅原始图像,经过VGGNet计算后得到各个卷积层的特征。接下来,根据这些卷积层的特征,还原出对应这种特征的原始图像。
下面的a、b、c、d、e分别为使用conv1_2、conv2_2、conv3_2、conv4_2、conv5_2的还原图像。可以发现:浅层的还原效果往往比较好,卷积特征基本保留了所有原始图像中形状、位置、颜色、纹理等信息;深层对应的还原图像丢失了部分颜色和纹理信息,但大体保留原始图像中物体的形状和位置。
还原图像的方法是梯度下降法。设原始图像为
→
p
,期望还原的图像为
→
x
(即自动生成的图像)。使用的卷积是第l层,原始图像
→
p
在第l层的卷积特征为P
l
ij
。i表示卷积的第i个通道,j表示卷积的第j个位置。通常卷积的特征是三维的,三维坐标分别对应(高、宽、通道)。此处不考虑具体的高和宽,只考虑位置j,相当于把卷积“压扁”了。比如一个10x10x32的卷积特征,对应1⩽i⩽32,1⩽j⩽100。对于生成图像
→
x
,同样定义它在l层的卷积特征为F
l
ij
。
有了上面这些符号后,可以写出“内容损失”(Content Loss)。内容损失Lcontent(
→
p
,
→
x
,l)的定义是:
Lcontent(
→
p
,
→
x
,l)=
1
2
∑i,j (F
l
ij
−P
l
ij
)2
Lcontent(
→
p
,
→
x
,l)描述了原始图像
→
p
和生成图像
→
x
在内容上的“差异”。内容损失越小,说明它们的内容越接近;内容损失越大,说明它们的内容差距也越大。先使用原始图像
→
p
计算出它的卷积特征P
l
ij
,同时随机初始化
→
x
。接着,以内容损失Lcontent(
→
p
,
→
x
,l)为优化目标,通过梯度下降法逐步改变
→
x
。经过一定步数后,得到的
→
x
是希望的还原图像了。在这个过程中,内容损失Lcontent(
→
p
,
→
x
,l)应该是越来越小的。
除了还原图像原本的“内容”之外,另一方面,还希望还原图像的“风格”。那么,图像的“风格”应该怎么样来表示呢?一种方法是使用图像的卷积层特征的Gram矩阵。
Gram矩阵是关于一组向量的内积的对称矩阵,例如,向量组
→
x1
,
→
x2
,...,
→
xn
的Gram矩阵是
[ (
→
x1
,
→
x1
) (
→
x1
,
→
x2
) ... (
→
x1
,
→
xn
) (
→
x2
,
→
x1
) (
→
x2
,
→
x2
) ... (
→
x2
,
→
xn
) ... ... ... ... (
→
xn
,
→
x1
) (
→
xn
,
→
x2
) ... (
→
xn
,
→
xn
) ]
通常取内积为欧几里得空间上的标准内积,即(
→
xi
,
→
xj
)=
→
xi
T
→
xj
。
设卷积层的输出为F
l
ij
,那么这个卷积特征对应的Gram矩阵的第i行第j个元素定义为
G
l
ij
= ∑k F
l
ik
F
l
jk
设在第l层中,卷积特征的通道数为Nl,卷积的高、宽乘积为Ml,那么F
l
ij
满足1⩽i⩽Nl,1⩽j⩽Ml。G实际是向量组F
l
1
,F
l
2
,...,F
l
i
,...,F
l
Nl
的Gram矩阵,其中,其中F
l
i
=(F
l
i1
,F
l
i2
,...,F
l
ij
,...,F
l
iMl
)。
此处数学符号较多,因此再举一个例子来加深读者对此Gram矩阵的理解。假设某一层输出的卷积特征为10x10x32,即它是一个宽、高均为10,通道数为32的张量。F
l
1
表示第一个通道的特征,它是一个100维的向量,F
l
2
表示第二个通道的特征,它同样是一个100维的向量,它对应的Gram矩阵G是
[ (F
l
1
)T(F
l
1
) (F
l
1
)T(F
l
2
) ... (F
l
1
)T(F
l
32
) (F
l
2
)T(F
l
1
) (F
l
2
)T(F
l
2
) ... (F
l
2
)T(F
l
32
) ... ... ... ... (F
l
32
)T(F
l
1
) (F
l
32
)T(F
l
2
) ... (F
l
32
)T(F
l
32
) ]
Gram矩阵可以在一定程度上反映原始图片中的“风格” 。仿照“内容损失”,还可以定义一个“风格损失”(Style Loss)。设原始图像为
→
a
,要还原的风格图像为
→
x
,先计算出原始图像某一次卷积的Gram矩阵为Al,要还原的图像
→
x
经过同样的计算得到对应卷积层的Gram矩阵是Gl,风格损失定义为
Lstyle(
→
p
,
→
x
,l)=
1
4N
2
l
M
2
l
∑i,j (A
l
ij
−G
l
ij
)2
分母上的4N
2
l
M
2
l
是一个归一化项,目的是防止风格损失的数量级相比内容损失过大。在实际应用中,常常利用多层而非一层的风格损失,多层的风格损失是单层风格损失的加权累加,即Lstyle(
→
p
,
→
x
)= ∑i wlLstyle(
→
p
,
→
x
,l),其中wl表示第l层权重。
利用风格损失,可以还原出图像的风格了。如下图所示,尝试还原梵高的著名画作《星空》的风格。
其中,图a是由conv1_1的风格损失还原的,图b是由conv1_1,conv2_1两层的风格损失还原的,图c是由conv1_1,conv2_1,conv3_1,图d为conv1_1,conv2_1,conv3_1,conv4_1风格损失还原的。使用浅层还原的“风格图像”的纹理尺度往往比较小,只保留了颜色和局部的纹理(如图a);组合深层、浅层还原出的“风格图像”更加真实且接近原图片(如图e)。
总结一下,到目前为止介绍了两个内容:
(1)利用内容损失还原图像内容。
(2)利用风格损失还原图像风格。
那么,可不可以将内容损失和风格损失结合起来,在还原一张图像的同时还原另一张图像的风格呢?答案是肯定的,这是图像风格迁移的基本算法。
设原始的内容图像为
→
p
,原始的风格图像为
→
a
,待生成的图像为
→
x
。希望
→
x
可以保持内容图像
→
p
的内容,同时具备风格图像
→
a
的风格。因此组合
→
p
的内容损失和
→
a
的风格损失,定义总的损失函数为
Ltotal(
→
p
,
→
a
,
→
x
)=αLcontent(
→
p
,
→
x
)+βLstyle(
→
a
,
→
x
)
α,β是平衡两个损失的超参数。如果α偏大,还原的图像会更接近于
→
p
中,如果β偏大,还原的图像会更接近
→
a
。使用总的损失函数可以组合
→
p
的内容和
→
x
的风格,这实现了图像风格的迁移。部分还原的图像如下图所示
以上是原始的图像风格迁移的基本原理。事实上,原始的图像风格迁移速度非常慢,在CPU上生成一张图片需要数十分钟甚至几个小时,即使在GPU上也需要数分钟才能生成一张较大的图片,这大大的限制了这项技术的使用场景。速度慢的原因在于,要使用总损失Ltotal(
→
p
,
→
a
,
→
x
)优化图片
→
x
,这意味着生成一张图片需要几百步梯度下降法的迭代,而每一步的迭代都需要耗费大量的时间。从另一个角度看,优化
→
x
可以看作是一个“训练模型”的过程,以往都是针对模型参数训练,而这里训练的目标是图片
→
x
,而训练模型一般都比执行训练好的模型要慢很多。下面将会讲到快速图像风格迁移,它把原来的“训练”的过程变成了一个“执行”的过程,因此大大加快了生成风格话图片的过程。
二、快速图像风格迁移的原理
原始的图像风格迁移用一个损失Ltotal(
→
p
,
→
a
,
→
x
)来衡量
→
x
是否成功组合了
→
p
的内容和
→
a
的风格。然后以Ltotal(
→
p
,
→
a
,
→
x
)为目标,用梯度下降法来逐步迭代
→
x
。因为在生成图像的过程中需要逐步对
→
x
做优化,所以速度比较慢。
快速图像风格迁移的方法是:不使用优化的方法来逐步迭代生成
→
x
,而是使用一个神经网络之间生成
→
x
。对应的网络结构如下图所示:
整个系统由两个神经网络组成,它们在图中由两个虚线框分别标出。左边的是图像生成网络,右边是损失网络。损失网络实际上是VGGNet,这与原始的风格迁移是一致的。同原始图像风格迁移一样,利用损失网络来定义内容损失、风格损失。这个损失用来训练图像生成网络。图像生成网络的职责是生成某一种风格的图像,它的输入是一个图像,输出同样是一个图像。由于生成图像只需要在网络中计算一遍,所以速度比原始图像风格迁移提高很多。
同样使用数学符号严格地阐述上面地过程:设输入的图像为
→
x
,经过图像生成网络生成的图像为
→
y
。
→
y
在内容上应该与原始的内容图像
→
y
c接近,因此可以利用损失网络定义内容损失Lcontent(
→
y
,
→
y
c),内容损失使用的是VGG-16中的relu3_3层输出的特征,对应上图中的l
ϕ,relu3_3
feat
。另一方面,我们还希望
→
y
具有目标风格图像
→
y
s的风格,因此又可以定义一个风格损失Ltotal(
→
y
,
→
y
c,
→
y
s)。定义风格损失时使用了VGG-16的四个中间层relu1_2,relu2_2,relu3_3,relu4_3,对应图中的l
ϕ,relu1_2
style
、l
ϕ,relu2_2
style
、l
ϕ,relu3_3
style
、l
ϕ,relu4_3
style
。同样组合这两个损失得到一个总损失Ltotal(
→
y
,
→
y
c,
→
y
s)。利用总损失可以训练图像生成网络。训练完成后直接使用图像生成网络生成图像。值得一提的是,在整个训练过程中,一般只固定一种风格
→
y
s,而内容图像
→
y
c取和输入
→
x
一样,即
→
y
s=
→
x
。
下面详细的比较原始图像风格迁移与快速图像风格迁移。
这篇博客详细介绍了原始图像风格迁移的基本原理,其中内容损失、风格损失两种损失函数的定义尤为关键。接着还介绍了快速图像风格迁移的原理,以及它和原始图像风格迁移的对比。https://www.cnblogs.com/xiaoyh/p/11932095.html