Advertisement

【Neural Style Transfer】Stroke Controllable Fast Style Transfer(含代码详解)

阅读量:

在介绍我们这次的论文之前,我们先来思考一些问题:

  • 在NST中,什么是风格图像中的风格信息? 个人理解,风格图像中的风格信息指的是风格图像中的色彩、纹理、笔触等因素 ,这些因素的不同组合使得图像呈现出不同的风格信息。
  • 那么,再进一步的思考,我们怎样提取这些风格图像中的风格信息呢? 在深度学习没有出现之前,大多数是利用图像处理和滤波来实现的,例如高斯滤波或者双边滤波;有了深度学习以后,开始从图像中提取高维的特征信息来表示风格信息,例如2015年Gatys提出利用Gram矩阵来表示图像中的风格信息,并且这一想法使其成为NST的基石和开山之作。
  • 那么,再思考一个问题,为什么Gram矩阵可以表示图像中的风格信息? 推荐给大家一篇博客:(高能预警!)为什么Gram矩阵可以代表图像风格?带你揭开图像风格迁移的神秘面纱!,我觉得博主对于这个问题分析比较透彻,伙伴们可以去学习一下。简单来说,图像的风格迁移是在不断缩小生成图像和内容图像,生成图像和风格图像的距离,那么对于内容图像和风格图像来说,需要忽略特征的位置,减小分布的差异。也就是说,图像的风格迁移可以看作内容图像到风格图像的分布对齐过程。更进一步地,如果我们将内容图像集合和风格图像集合看作两个域,那么这就是域迁移的问题了。

项目链接

既然对风格信息有了基础认识后,在研究者们的深入探讨下(笔触大小是否会影响风格迁移效果?) ,这篇论文得以展开。此外,在项目页面中(https://yongchengjing.com/StrokeControllable),发表于2018ECCV的资源也进行了详细展示。特别提醒关注:我们有关NST方向的论文及代码已在专栏中做了全面介绍(深度学习艺术与专栏),感兴趣的朋友不妨自行访问[()

本文的论文资源链接:https://arxiv.org/abs/1802.07101
代码开源位置及详细说明:https://github.com/LouieYang/stroke-controllable-fast-style-transfer
项目官方网站链接:https://yongchengjing.com/StrokeControllable

在这里插入图片描述

0. Pre-analysis

论文在正式介绍自己的网络结构之前,以增强论证的说服力,通过不同的笔触处理(实质上是内容图像与风格图像的比例不同)证明了必然会产生不同的效果,如图3所示。Small stroke size处理后的迁移图像具有较高的纹理细节度,而对于细节刻画则较为精准;相比之下,Large stroke size处理后能够较好地保持色块完整性,避免过于模糊的现象出现;然而,我们的目标是致力于实现混合笔触下的效果,如图3所展示的效果

在这里插入图片描述

1. Proposed Approach

1.1 Network Architecture
在这里插入图片描述

这篇论文所提出来的网络结构主要有三个部分。主要如下:

  • StrokePyramid Module 笔触金字塔模块:通过调整卷积核尺寸实现各层级感知域逐渐增大,并在相邻层级之间促进笔触一致性和相似性( stroke consistency and similarity)。
  • Pre-encoder Module 预编码器模块:设计了一系列权重共享层以学习内容图像语义与风格图像的核心特征表达。
  • Stroke-decoder Module 笔触解码器模块:基于相应的分辨率设置将风格特征从编码空间映射回绘画空间以生成最终艺术效果。

此外也构建了一个门函数gating function G,并用于判断哪些笔触特征需解码后同时传递给触控解码模块。

在这里插入图片描述
1.2 Loss Function

在Neural Style Transfer算法框架下,在通常情况下, 损失函数由三部分组成: 内容项、风格项以及正则化项。其中, 内容项通过VGG网络在特定层级上提取内容图像与生成图像的特征表示差异; 风格项则通过Gram矩阵量化不同风格间的差异; 正则化项采用L1或L2范数作为约束手段. 在本研究中, 损失函数被系统性地划分为语义项、笔触项以及变异性正则化三项要素

Semantic Loss语义损失定义为:

在这里插入图片描述

先定义了Gram矩阵的计算方式,而后将Stroke Loss笔触损失定义为:

在这里插入图片描述

因此,总损失定义为,\alpha\beta\gamma为超参数:

在这里插入图片描述
1.3 Other Details

在论文中, 作者对训练策略进行了深入阐述, 不再赘述具体内容, 若有兴趣可参考原论文及相关博文. 在实验部分, 作者主要采用Qualitative Evaluation与Quantitative Evaluation相结合的方法, 验证该算法已达到最优性能, 包括对训练曲线的详细分析以及平均损失值的变化趋势等. 此外, 文章提到该算法可通过调节笔触大小来实现风格迁移功能, 如下图所示. 然而, 笔者观察到代码部分并未实现这一特性, 若有相关兴趣可尝试自行复现.

在这里插入图片描述

2. 代码详解

2.1 每个.py文件介绍

train.py:定义main函数,包括参数的传入,创建tf的图,调用和训练Model,传入内容图像和风格图像等;
model.py:定义了n种笔触大小(论文种用的768、512和256的风格图像大小,和内容图像大小的比例是1.5、1和0.5),风格层和内容层,定义了DataLoader类和Model类;
class DataLoader :训练的时候用了2014COCO数据集或者从MSCOCO中随机抽取2000张图像。
Model :定义模型的前向传播过程和loss损失计算方式。

2.2 部分代码重点备注
2.2.1 Tensorflow使用GPU训练现存占用问题

TensorFlow在训练过程中默认占据所有可用的GPU内存。我们可以通过多种方法来应对这一问题:

  1. 在创建tf.Session()时,可以通过指定tf.GPUOptions参数来设定内存分配比例;例如:
  2. 我们可以采取另一种优化策略以提升资源利用率;(该方法仅能均匀分配内存资源给所有使用的GPU)
复制代码
    gpu_options = tf.GPUOptioins(per_process_gpu_memory_fraction=0.33) # 占用1/3的显存
    sess = tf.Session(config = tf.ConfigProto(gpu_option=gpu_options))

2.按需增长的指定所有GPU内存,例如:

复制代码
    config = tf.ConfigProto()
    config.gpu_options.allow_growth = True
    sess = tf.Session(config=config)

3.指定可见的服务器(但是指定的可见服务器也会所有被占满),例如:

复制代码
    export CUDA_VISIBLE_DEVICES = 0,1
2.2.2 for i in xrange() 和range()的区别

用于循环的for语句中,在Python2中使用的是for i in xrange()和for i in range()。其中前者属于生成器类序列迭代器;而后者则属于列表类序列迭代器。需要注意的是,在Python3中range的作用与Python2中的xrange一致。两者的功能差别并不显著,在实际应用中基本可以互替使用。它们都能遍历区间内的全部数值,并且其中xrange()更为节省内存空间。

复制代码
    x = range(0,3)   # Python3
    print(type(x))   # Output:<class 'range'>
    print(x)         # output:range(0,3)

全部评论 (0)

还没有任何评论哟~