近来Neural style很火, 所以Deep Vision第二篇就讲一下Neural style, 下面这张图是在这个领域方面的进展. 从2015年出来最初的简单的风格重构(速度很慢, 需要实时优化), 到2016年的就出来的fast Nerual Style, 同时这篇新的论文也探讨了其在super-resolution上的应用, 可以说这个方向的进展非常快, 并且也开始向其他的方向开始展开应用.

原理

neural style的想法是利用了CNN抽象图像高阶信息的思想, 用其来提取图片的风格信息. 为了对图片进行风格混合, 我们需要定义一个损失包含, 其包含了两方面的信息.

  1. 生成图片与原始图片在CNN输出上的差异
  2. 提取特征的相关性作为风格上的差异.

算法的流程如下

  1. 预处理, 即归一化
  2. 选择卷积网络
  3. 选择中间到最高层中间的某一层来代表内容信息, 平方差作为内容损失, 这里的原因是高层的图片会损失掉详细的像素信息, 但是会保留更高层的内容信息.
  4. 对于风格损失, 我们首先需要定义Gram矩阵, 可由内积计算, 其内容为特征的相关性, 这样的表示可以从全局捕捉风格(文理)信息而非内容信息.(风格信息需要提取CNN的多个中间特征, 计算出Gram矩阵, 然后计算风格损失)

最主要的发现是内容和风格在CNN里的表征是可以分离的, 合成图片分别由风格图片提供风格, 内容图片提供内容, 在这之前的方法都是像素级的非参数操作, 相反, 在DL中, 我们可以直接操控图片表示高层内容的特征空间.

整个的计算流程包括内容重构和风格重构, 如下

内容重构

需要注意的是在高层内容重构的时候, 是构建了一个优化模型, 输入高层表征和CNN操作, 输出是重构的图片.

$$L_{content}(p,x,l)=\frac{1}{2}\sum_{i,j}(F_{ij}^l-P_{ij}^l)^2$$

这样操作可以利用反向传播计算出损失函数对$x$的梯度, 进而利用梯度下降法进行求解, 以此来重构图片.

风格重构

利用Gram矩阵来表示特征相关性. 其计算为向量化特征图的内积.

$$G_{ij}^l=\sum_kF_{ik}^lF_{jk}^l$$

其具体计算可以将比如50x224x224的数组flatten为50x(224x224)的矩阵$X$, 然后$G=XX^T$即可直接计算.

同样, 在这里构建风格的损失函数, 输入是风格图片在高层的Gram矩阵, CNN结构, 输出是重构的风格. 初始化是一个白噪声图片, 这与上面的内容重构是一致的. 有某层的总损失为

$$E_l=\frac{1}{4N_l^2M_l^2}\sum_{i,j}(G_{ij}^l-A_{ij}^l)^2$$

因此总损失为

$$L_{style}(a,x)=\sum_{l=0}^Lw_lE_l$$

这里$w_l$是每层对总损失的共享, 一般是归一化的权重, 这样的损失同样可以利用反向传播很容易的计算其对重构图片的梯度, 接下来利用梯度下降法进行优化计算即可.

内容和风格混合

将上述两种损失函数结合在一起, 我们要得到一张重构图片, 使得他在两种损失的结合下都足够小.

$$L_{total}(p,a,x)=\alpha L_{content}(p,x)+\beta L_{style}(a,x)$$

这里$\alpha,\beta$是两个权重因子, 在原论文中, 作者选择了conv4_2作为内容重构, 选择了conv1_1,conv2_1,conv3_1,conv4_1以及conv5_1作为风格重构. 一般$\frac{\alpha}{\beta}$等于$1x10^{-3}$或者$1x10^{-4}$, 即风格损失的系数要大上千级别. 结果如下

参数

当重构风格采用不同的层时的结果如下

可以看到采用更高层的表征作为风格重构的依据可以更好的抽象出风格图片的风格. 同时可以看到$\frac{\alpha}{\beta}$可以对重构的图片对风格和内容上的倾向有明显的作用.

Some thoughts

There are two kinds of reconstruction in this work. One is called content reconstruction. It tries to reconstruct the input image using the feature of original image (in different layers) and the preset network. The objective is to let the generated image and the original image have the nearest features in the same layer. So the loss function is square loss.

Another reconstruction is a little trickier, called style reconstruction. The only difference to content reconstruction is the objective. We don’t care about content of the image; we care about the style, or in another word, pattern. So, to lead to this final objective, the author defines a matrix called Gram matrix. For each layer, there is a Gram matrix, which is correlation matrix of different filter responses on this layer. That is, for each layer, we have multiple channels, for each channel, we have a filter response (either pooling or rectfication or convolution), then for each pair of filter responses, we calculate a correlation, so finally there is a square correlation matrix.

The loss is the square loss between gram matrix of generated image and original image. So, here what the author claims is that this gram matrix can capture the similarity of the style of different images.

There is an example of style reconstruction and content reconstruction in their paper.

So, how do we generate the artistic picture? For lower layers, we calculate loss of style reconstruction, and for higher layers, we calculate loss of content reconstruction. And to minimize the aggregated loss, we can generate a cool picture.

具体实现

为简单起见, 这里的实现是fast neural style, 并使用了别人训练好的模型. fast neural style和之前的不同之处在于之前讨论的是构建优化模型, 每一个图片, 我们都要重新进行优化计算, fast则不同, 直接训练好生成对应风格的一个图片重构网络, 这样对一个图片输入到这个卷积网络就可以直接生成对应风格图片, 而不用建立优化模型了.

首先引入一些必要的库

import hickle as hkl
import torch
import torch.nn.functional as F
from torch.autograd import Variable
from PIL import Image
import requests
import numpy as np
from StringIO import StringIO
import torchnet as tnt
import matplotlib.pyplot as plt
from visualize import make\_dot
import cv2
%config InlineBackend.figure\_format = 'jpeg'
%matplotlib inline

定义卷积网络

def f(o, params):
    def g(f, x, name, stride=1, padding=0):
        return f(x, params['%s.weight'%name], params['%s.bias'%name], stride, padding)
    o = F.relu(g(F.conv2d, o, 'c1', 1, 4))
    o = F.relu(g(F.conv2d, o, 'c2', 2, 1))
    o = F.relu(g(F.conv2d, o, 'c3', 2, 1))
    for i in range(1, 6):
        o += g(F.conv2d, F.relu(g(F.conv2d, o, 'r%d.c1'%i, padding=1)), 'r%d.c2'%i, padding=1)
    o = F.relu(g(F.conv\_transpose2d, o, 'd1', 2, 1))
    o = F.relu(g(F.conv\_transpose2d, o, 'd2', 2, 1))
    return g(F.conv2d, o, 'd3', 1, 4).clamp(0,255)

导入要转换的图片

import scipy.misc
def load(url):
    response = requests.get(url)
    return np.ascontiguousarray(Image.open(StringIO(response.content)), dtype=np.uint8)

im = load('https://ooo.0o0.ooo/2017/04/20/58f8ce3d53ab1.png')

对图片进行预处理

tr = tnt.transform.compose([
        lambda x: cv2.cvtColor(x, cv2.COLOR\_RGB2BGR),
        lambda x: cv2.resize(x, (0,0), fx=0.5, fy=0.5),
        lambda x: x.transpose(2, 0, 1).astype(np.float32),
        torch.from\_numpy,
        lambda x: x.contiguous().unsqueeze(0),
    ])

tr\_backward = tnt.transform.compose([
        lambda x: x.byte().numpy(),
        lambda x: x.transpose(1,2,0),
        lambda x: cv2.cvtColor(x, cv2.COLOR\_BGR2RGB),
    ])

导入训练好的模型forward输出

def stylize(im, params):
    return f(Variable(tr(im)), params)
def load\_params(filename, verbose=False):
    params = hkl.load(filename)

    # convert numpy arrays to torch Variables
    for k,v in params.iteritems():
        if verbose:
            print k, v.shape
        params[k] = Variable(torch.from\_numpy(v))

    if verbose:
        print '\nTotal parameters:', sum([v.numel() for v in params.itervalues()])
    return params
Wave风格
stylized = stylize(im, load\_params('wave.hkl', verbose=True))
plt.imshow(tr\_backward(stylized.data[0]))
plt.savefig('wave\_style.png')
plt.axis('off')
make\_dot(stylized)


Feather 风格
stylized = stylize(im, load\_params('feathers.hkl', verbose=False))
plt.imshow(tr\_backward(stylized.data[0]))
plt.axis('off')
plt.savefig('feathers\_style.png')

candy风格
stylized = stylize(im, load\_params('candy.hkl', verbose=False))
plt.imshow(tr\_backward(stylized.data[0]))
plt.axis('off')
plt.savefig('candy\_style.png')


References

A Neural Algorithm of Artistic Style
Convolutional neural networks for artistic style transfer
Perceptual Losses for Real-Time Style Transfer and Super-Resolution.
cs20si

Pretrained Models