基于深度学习的图像风格转换
距离上次写博客已经好久好久好久了,真是懈怠的⽣活节奏,整天混吃等死玩游戏,前些⽇⼦做毕业设计时总算⼜学了点新东西。学了⼀点深度学习和卷积神经⽹络的知识,附带着详细学习了⼀下前段时间我觉得⽐较有意思的图像风格转换。毕竟是初学,顺便把神经⽹络⽅⾯的知识也写在前⾯了,便于理解。若有不对的地⽅的话,希望指正。
主要参考的⽂献有和这两篇论⽂,以及等⽂章,代码参考了和等⼤神的。
先说⼀下卷积神经⽹络。卷积神经⽹络(CNN)是⼀种前馈神经⽹络,了解机器学习中⼈⼯神经⽹络的话应该对这个概念不陌⽣。神经⽹络中的感知器模型如下图所⽰。
输⼊神经元与其各⾃权重相乘再相加得到z,利⽤激活函数g(z)进⾏变换得到神经元y。输⼊层神经元与其权重相乘再相加的过程可以⽤矩阵相乘相乘来表⽰,这点在下⾯的卷及神经⽹络⾥可以看到。神经⽹络⾥输⼊层和输出层中间的是隐藏层。
在卷积神经⽹络⾥,⽹络结构⼀般是由多个卷积层、⾮线性化层、池化层以及最后的全连接层组成。卷积层对输⼊进⾏卷积计算,得到的结果经过⾮线性化层的激活函数,再经过池化层进⾏采样,最后是全连接层。
先介绍卷积操作。假设输⼊图⽚是⼆维矩阵,每个像素值都是输⼊层的⼀个神经元,权值也⽤矩阵来表⽰,这个权值矩阵叫做卷积核,也可以成为滤波器,卷积核代表了你看这个图像时的感受野。不过卷积核是与输⼊图⽚的⼆维矩阵滑动计算的,这⾥涉及到了权值共享的问题。计算的过程如下图所⽰。
图中黄⾊部分为3x3卷积核,绿⾊的为5x5输⼊矩阵。卷积核在输⼊矩阵上滑动计算,每次都计算相应位置的乘积再相加,得到卷积后的矩阵中的新的元素。每次滑动的⼀格代表步长(stride)为1,也可以为其它值。然后再对右⾯矩阵的每⼀个得到的元素的值通过激励函数进⾏⾮线性化处理,⼀般是⽤的ReLU函数。如下图所⽰。
池化层进⾏下采样,⽬的是减⼩特征图,池化规模⼀般为2×2。常⽤的池化⽅法之⼀是最⼤池化(Max Pooling),即取4个点的最⼤值,如下图所⽰,⾮常简单。
卷积神经⽹络通过这样可以不断提取图像的不同层次的特征图,然后⽤于分类问题等等。关于卷积神经⽹络的详细解释可以参考和这两篇⽂章,这⾥就不多作解释了。下⾯进⼊正题,图像风格转换的原理。
图像风格转换
以⽬前的深度学习技术,如果给定两张图像,完全有能⼒让计算机识别出图像具体内容。⽽图像的风格是⼀种很抽象的东西,⼈眼能够很有效地的辨别出不同画家不同流派绘画的风格,⽽在计算机的眼中,本质上就是⼀些像素,多层⽹络的实质其实就是出更复杂、更内在的特性(features),所以图像的风格理论上可以通过多层⽹络来提取图像⾥⾯可能含有的⼀些有意思的特征。
根据前⾯第⼀篇论⽂中提出的⽅法,风格迁移的速度⾮常慢的。在风格迁移过程中,把⽣成图⽚的过程当做⼀个“训练”的过程。每⽣成⼀张图⽚,都相当于要训练⼀次模型,这中间可能会迭代⼏百⼏千次。从头训练⼀个模型相对于执⾏⼀个已经训练好的模型来说相当费时。现在根据前⾯第⼆篇论⽂提出的另⼀种模型,使得把⽣成图⽚当做⼀个“执⾏”的过程,⽽不是⼀个“训练”的过程。
正则匹配一张图片快速风格迁移的⽹络结构包含两个部分。⼀个是“⽣成⽹络”(Image Transform Net),⼀个是“损失⽹络”(Loss Network)。⽣成⽹络输⼊层接收⼀个输⼊图⽚,最终输出层输出也是⼀张图⽚(即风格转换后的结果)。模型总体分为两个阶段,训练阶段和执⾏阶段。模型如图所⽰。其中左侧是⽣成⽹络,右侧为损失⽹络。
训练阶段:选定⼀张风格图⽚。训练过程中,将数据集中的图⽚输⼊⽹络,⽣成⽹络⽣成结果图⽚y,损失⽹络提取图像的特征图,将⽣成图⽚y分别与⽬标风格图⽚ys和⽬标输⼊图⽚(内容图⽚)yc做损失计算,根据损失值来调整⽣成⽹络的权值,通过最⼩化损失值来达到⽬标效果。
执⾏阶段:给定⼀张图⽚,将其输⼊已经训练好的⽣成⽹络,输出这张图⽚风格转换后的结果。
⽣成⽹络
对于⽣成⽹络,本质上是⼀个卷积神经⽹络,这⾥的⽣成⽹络是⼀个深度残差⽹络,不⽤任何的池化层,取⽽代之的是⽤步幅卷积或微步幅卷积做⽹络内的上采样或者下采样。这⾥的神经⽹络有五个残差块组成。除了最末的输出层以外,所有的⾮残差卷积层都跟着⼀个空间性的instance-normalization,和RELU的⾮线性层,instance-normalization正则化是⽤来防⽌过拟合的。最末层使⽤⼀个缩放的Tanh来确保输出图像的像素在[0,255]之间。除开第⼀个和最后⼀个层⽤9x9的卷积核(kernel),其他所有卷积层都⽤3x3的卷积核。
损失⽹络
损失⽹络φ是能定义⼀个内容损失(content loss)和⼀个风格损失(style loss),分别衡量内容和风格上的差距。对于每⼀张输⼊的图⽚x我们有⼀个内容⽬标yc⼀个风格⽬标ys,对于风格转换,内容⽬标yc是输⼊图像x,输出图像y,应该把风格ys结合到内容x=yc上。系统为每⼀个⽬标风格训练⼀个⽹络。
为了明确逐像素损失函数的缺点,并确保所⽤到的损失函数能更好的衡量图⽚感知及语义上的差距,需要使⽤⼀个预先训练好⽤于图像分类的CNN,这个CNN已经学会感知和语义信息编码,这正是图像风格转换系统的损失函数中需要做的。所以使⽤了⼀个预训练好⽤于图像分类的⽹络φ,来定义系统的损失函数。之后使⽤同样是深度卷积⽹络的损失函数来训练我们的深度卷积转换⽹络。
这⾥的损失⽹络虽然也是卷积神经⽹络(CNN),但是参数不做更新,只⽤来做内容损失和风格损失的计算,训练更新的是前⾯的⽣成⽹络的权值参数。所以从整个⽹络结构上来看输⼊图像通过⽣成⽹络得到转换的图像,然后计算对应的损失,
整个⽹络通过最⼩化这个损失去不断更新前⾯的⽣成⽹络权值。
感知损失
对于求损失的过程,不⽤逐像素求差构造损失函数,转⽽使⽤感知损失函数,从预训练好的损失⽹络中提取⾼级特征。在训练的过程中,感知损失函数⽐逐像素损失函数更适合⽤来衡量图像之间的相似程度。
(1)内容损失
上⾯提到的论⽂中设计了两个感知损失函数,⽤来衡量两张图⽚之间⾼级的感知及语义差别。内容的损失计算⽤VGG计算来⾼级特征(内容)表⽰,因为VGG模型本来是⽤于图像分类的,所以⼀个训练好的VGG模型可以有效的提取图像的⾼级特征(内容)。计算的公式如下:
到⼀个图像 y使较低的层的特征损失最⼩,往往能产⽣在视觉上和y不太能区分的图像,如果⽤⾼层来重建,内容和全局结构会被保留,但是颜⾊纹理和精确的形状不复存在。⽤⼀个特征损失来训练我们的图像转换⽹络能让输出⾮常接近
⽬标图像y,但并不是让他们做到完全的匹配
(2)风格损失
内容损失惩罚了输出的图像(当它偏离了⽬标y时),所以同样的,我们也希望对输出的图像去惩罚风格上的偏离:颜⾊,纹理,共同的模式,等⽅⾯。为了达成这样的效果,⼀些研究⼈员等⼈提出了⼀种风格重建的损失函数:让φj(x)代表⽹络φ的第j层,输⼊是x。特征图谱的形状就是Cj x Hj x Wj、定义矩阵Gj(x)为Cj x Cj矩阵(特征矩阵)其中的元素来⾃于:
如果把φj(x)理解成⼀个Cj维度的特征,每个特征的尺⼨是Hj x Wj,那么上式左边Gj(x)就是与Cj维的⾮中⼼的协⽅差成⽐例。每⼀个⽹格位置都可以当做⼀个独⽴的样本。这因此能抓住是哪个特征能带动其他的信息。梯度矩阵可以很⾼效的计算,通过调整φj(x)的形状为⼀个矩阵ψ,形状为Cj x HjWj,然后Gj(x)就是ψψT/CjHjWj。风格重建的损失是定义的很好的,甚⾄当输出和⽬标有不同的尺⼨是,因为有了梯度矩阵,所以两者会被调整到相同的形状。
具体实现
GitHub地址,实现基本上参考了的代码,代码从原版迁移到了python3.5,TensorFlow1.0,具体实现代码基本没变,加了⼀些注释,添加了⼀个web页⾯,效果如下。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论