一、介绍
- 将一张图片的艺术风格应用在另外一张图片上
- 使用深度卷积网络CNN提取一张图片的内容和提取一张图片的风格, 然后将两者结合起来得到最后的结果
二、 方法
- 我们知道
CNN
可以捕捉图像的高层次特征,如上图所示,内容图片经过CNN
可以得到对应的图像表述(representation
, 就是经过卷积操作的feature map
),然后经过重构可以得到近似原图的效果- 特别是前面几层经过重构得到的结果和原图更接近,也说明前几层保留的图片细节会更多,因为后面还有
pooling
层,自然会丢弃调一些信息 - 这里的网络使用的是
VGG-16
(如下图),包含13
个卷积层,3
个全连接层
- 特别是前面几层经过重构得到的结果和原图更接近,也说明前几层保留的图片细节会更多,因为后面还有
1、内容损失
- 假设一个卷积层包含 ${N_l}$ 个过滤器
filters
,则可以得到 ${N_l}$ 个feature maps
,假设feature map
的大小是 $M_l$ (长乘宽),则可以通过一个矩阵来存储l
层的数据 $$F^l \in R^{N_l \times M_l} $$- $F^l_{i,j}$ 表示第
l
层的第i
个filter
在j
位置上的激活值
- $F^l_{i,j}$ 表示第
- 所以现在一张内容图片$\overrightarrow p$,一张生成图片$\overrightarrow x$(初始值为高斯分布), 经过一层卷积层l可以得到其对应的特征表示:$P^l$ 和 $F_l$, 则对应的损失采用均方误差: $$L_{content}(\overrightarrow p, \overrightarrow x, l) = {1 \over 2} \sum_{ij}(F^l_{ij}-P^l_{ij})^2$$
- $F$ 和 $P$是两个矩阵,大小是$N_l \times M_l$,即
l
层过滤器的个数 和feature map
的长乘宽的值
- $F$ 和 $P$是两个矩阵,大小是$N_l \times M_l$,即
2、风格损失
- 风格的表示这里采用格拉姆矩阵(
Gram Matrix
): $G^l \in R^{N_l \times N_l}$ $$G^l_{ij} = {\sum_k F^l_{ik}F^l_{jk}}$$- 格拉姆矩阵计算的是两两特征的相关性 , 即哪两个特征是同时出现的,哪两个特征是此消彼长的等,能够保留图像的风格
- ( 比如一幅画中有人和树,它们可以出现在任意位置,格拉姆矩阵可以衡量它们之间的关系,可以认为是这幅画的风格信息 )
假设$\overrightarrow a$是风格图像,$\overrightarrow x$是生成图像,$A^l$ 和 $G^l$ 表示在 $l$ 层的格拉姆矩阵,则这一层的损失为:$$E_l = {1 \over 4N^2_lM^2_l}{\sum_{i,j} (G^l_{ij}-A^l_{ij})^2}$$
提取风格信息是我们会使用多个卷积层的输出,所以总损失为:$$L_{style}(\overrightarrow a, \overrightarrow x) = {\sum^L_lw_lE_l}$$
- 这里$w_l$是每一层损失的权重
3、总损失函数
- 通过白噪声初始化(就是高斯分布)一个输出的结果,然后通过网络对这个结果进行风格和内容两方面的约束进行修正
$$L_{total}(\overrightarrow p,\overrightarrow a,\overrightarrow x)=\alpha L_{content}(\overrightarrow p, \overrightarrow x) +\beta L_{style}(\overrightarrow a, \overrightarrow x)$$
三、代码实现
1、说明
- 全部代码:点击查看
- 图像使用一张建筑图和梵高的星空
2、加载并预处理图片和初始化输出图片
- 输出图片采用高斯分布初始化
|
|
3、获取网络中对应层的输出
|
|
4、内容损失函数
|
|
5、Gram矩阵和风格损失
|
|
6、总损失
|
|
7、损失函数梯度
|
|
8、生成结果后处理
- 因为之
前preprocess_input
函数中做了处理,这里进行逆处理还原1234567891011121314def postprocess_array(x):'''生成图片后处理,因为之前preprocess_input函数中做了处理,这里进行逆处理还原'''if x.shape != (target_width, target_height, 3):x = x.reshape((target_width, target_height, 3))x[..., 0] += 103.939x[..., 1] += 116.779x[..., 2] += 123.68x = x[..., ::-1] # BGR-->RGBx = np.clip(x, 0, 255)x = x.astype('uint8')return x
9、定义模型并优化
|
|
10、输出结果
- 初始化输出图片
- 迭代200次,${\beta \over \alpha} = 10^3$
- 迭代
500
轮,${\beta \over \alpha} = 10^4$
四、总结
style tranfer
通过白噪声初始化(就是高斯分布)一个输出的结果,然后通过优化损失对这个结果进行风格和内容两方面的约束修正- 图片的风格信息使用的是 Gram矩阵来表示
- 其中超参数风格损失的权重
ws
、内容损失和风格损失的权重$\alpha$, $\beta$可以进行调整查看结果- 论文给出的${\beta \over \alpha} = 10^3或10^4$结果较好,可以自己适当增加看看最后的结果
Reference
- Paper: https://arxiv.org/pdf/1508.06576.pdf
- https://www.cs.toronto.edu/~frossard/post/vgg16/
- https://zhuanlan.zhihu.com/p/33910138
- 本文链接: http://lawlite.me/2018/02/28/风格迁移Style-transfer/
- 版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 3.0 许可协议 。转载请注明出处!