0 简介
今天学长向大家分享一个毕业设计项目
毕业设计 深度学习图像风格迁移系统(源码分享)
项目运行效果:
毕业设计 深度学习图像风格迁移系统
🧿 项目分享:见文末!
图片风格迁移指的是将一个图片的风格转换到另一个图片中,如图所示:
原图片经过一系列的特征变换,具有了新的纹理特征,这就叫做风格迁移。
1 VGG网络
在实现风格迁移之前,需要先简单了解一下VGG网络(由于VGG网络不断使用卷积提取特征的网络结构和准确的图像识别效率,在这里我们使用VGG网络来进行图像的风格迁移)。
如上图所示,从A-E的每一列都表示了VGG网络的结构原理,其分别为:VGG-11,VGG-13,VGG-16,VGG-19,如下图,一副图片经过VGG-19网络结构可以最后得到一个分类结构。
2 风格迁移
对一副图像进行风格迁移,需要清楚的有两点。
- 生成的图像需要具有原图片的内容特征
- 生成的图像需要具有风格图片的纹理特征
根据这两点,可以确定,要想实现风格迁移,需要有两个loss值:
一个是生成图片的内容特征与原图的内容特征的loss,另一个是生成图片的纹理特征与风格图片的纹理特征的loss。
而对一张图片进行不同的特征(内容特征和纹理特征)提取,只需要使用不同的卷积结构进行训练即可以得到。这时我们需要用到两个神经网络。
再回到VGG网络上,VGG网络不断使用卷积层来提取特征,利用特征将物品进行分类,所以该网络中提取内容和纹理特征的参数都可以进行迁移使用。故需要将生成的图片经过VGG网络的特征提取,再分别针对内容和纹理进行特征的loss计算。
如图,假设初始化图像x(Input image)是一张随机图片,我们经过fw(image Transform Net)网络进行生成,生成图片y。
此时y需要和风格图片ys进行特征的计算得到一个loss_style,与内容图片yc进行特征的计算得到一个loss_content,假设loss=loss_style+loss_content,便可以对fw的网络参数进行训练。
现在就可以看网上很常见的一张图片了:
相较于我画的第一张图,这即对VGG内的loss求值过程进行了细化。
细化的结果可以分为两个方面:
- (1)内容损失
- (2)风格损失
3 内容损失
由于上图中使用的模型是VGG-16,那么即相当于在VGG-16的relu3-3处,对两张图片求得的特征进行计算求损失,计算的函数如下:
简言之,假设yc求得的特征矩阵是φ(y),生成图片求得的特征矩阵为φ(y^),且c=φ.channel,w=φ.weight,h=φ.height,则有:
代码实现:
def content_loss(content_img, rand_img):
content_layers = [('relu3_3', 1.0)]
content_loss = 0.0
# 逐个取出衡量内容损失的vgg层名称及对应权重
for layer_name, weight in content_layers:
# 计算特征矩阵
p = get_vgg(content_img, layer_name)
x = get_vgg(rand_img, layer_name)
# 长x宽xchannel
M = p.shape[1] * p.shape[2] * p.shape[3]
# 根据公式计算损失,并进行累加
content_loss += (1.0 / M) * tf.reduce_sum(tf.pow(p - x, 2)) * weight
# 将损失对层数取平均
content_loss /= len(content_layers)
return content_loss
4 风格损失
风格损失由多个特征一同计算,首先需要计算Gram Matrix
Gram Matrix实际上可看做是feature之间的偏心协方差矩阵(即没有减去均值的协方差矩阵),在feature map中,每一个数字都来自于一个特定滤波器在特定位置的卷积,因此每个数字就代表一个特征的强度,而Gram计算的实际上是两两特征之间的相关性,哪两个特征是同时出现的,哪两个是此消彼长的等等,同时,Gram的对角线元素,还体现了每个特征在图像中出现的量,因此,Gram有助于把握整个图像的大体风格。有了表示风格的Gram Matrix,要度量两个图像风格的差异,只需比较他们Gram Matrix的差异即可。 故在计算损失的时候函数如下:
在实际使用时,该loss的层级一般选择由低到高的多个层,比如VGG16中的第2、4、7、10个卷积层,然后将每一层的style loss相加。
第三个部分不是必须的,被称为Total Variation Loss。实际上是一个平滑项(一个正则化项),目的是使生成的图像在局部上尽可能平滑,而它的定义和马尔科夫随机场(MRF)中使用的平滑项非常相似。 其中yn+1是yn的相邻像素。
代码实现以上函数:
# 求gamm矩阵
def gram(x, size, deep):
x = tf.reshape(x, (size, deep))
g = tf.matmul(tf.transpose(x), x)
return g
def style_loss(style_img, rand_img):
style_layers = [('relu1_2', 0.25), ('relu2_2', 0.25), ('relu3_3', 0.25), ('reluv4_3', 0.25)]
style_loss = 0.0
# 逐个取出衡量风格损失的vgg层名称及对应权重
for layer_name, weight in style_layers:
# 计算特征矩阵
a = get_vgg(style_img, layer_name)
x = get_vgg(rand_img, layer_name)
# 长x宽
M = a.shape[1] * a.shape[2]
N = a.shape[3]
# 计算gram矩阵
A = gram(a, M, N)
G = gram(x, M, N)
# 根据公式计算损失,并进行累加
style_loss += (1.0 / (4 * M * M * N * N)) * tf.reduce_sum(tf.pow(G - A, 2))