边学深度边撸代码之快速Neural style艺术风格转换

主要参考资料: 两分钟demo:快速Neural style艺术风格转换
不过,上面的资料主要还是抛砖引玉用(或者说是推销mxnet啦),要了解细节最好还是得读读原版论文,甚至源代码。所以本篇笔记主要是记录一下算法核心idea和代码实现细节。

Neural Style 基础版

  • 原版论文 A Neural Algorithm of Artistic Style
    边学深度边撸代码之快速Neural style艺术风格转换_第1张图片
    核心就在论文的这张图上。

作者定义了一个5层的CNN网络,梵高的星空在通过第一二三层的时候保留了一些原图的细节,但是在第四第五层的时候,就变成了“看起来是梵高星空的样子”这样的抽象特征。
这时候作者机智的想到了,如果把一张梵高一张其他照片同时都放到这个CNN网络里,经过合适的调整让第二张照片在第四五层接近梵高,而第一二三层保持和原来差不多,那就可以模仿梵高了!
————–摘自 http://phunter.farbox.com/post/mxnet-tutorial2

主要idea就是上面说的。但具体实现就有一些细节问题要处理了。
1. 具体的网络怎么train。先把目标style的艺术图送进去网络,得到卷积层的值。再把我们的输入content图送进去网路,得到卷积层的值。最后输入一个白噪声的图片或者原始content图作为初始值开始训练,使这张图片的style在卷积层的特征跟艺术图相似, content跟原先自己相似。有个要注意的地方就是普通训练cnn网络是image作为数据,训练出网络的参数。这里网络参数其实是固定的,我们要训练的“权重”其实是图片,但一样也是通过BP。所以有点费时间的,后面引出优化方法。
2. style的相似度怎么衡量。content的相似度比较好办,就是资料里提到的per-pixel loss,像素级diff一下就行,简单明了。style的话,用了gram matrix,有点像协方差矩阵。至于这个gram matrix怎么推导的就不清楚了。暂时不求甚解。

源码

后来找到了这么一个神奇的网站 http://www.gitxiv.com/posts/jG46ukGod8R7Rdtud/a-neural-algorithm-of-artistic-style,搞到一个torch的源码https://github.com/jcjohnson/neural-style/blob/master/neural_style.lua。lua我也不懂,硬着头皮看吧。

关键点

  -- content和style用的layers
  cmd:option('-content_layers', 'relu4_2', 'layers for content')
  cmd:option('-style_layers', 'relu1_1,relu2_1,relu3_1,relu4_1,relu5_1', 'layers for style')


  -- 网络有一个自定义的特殊capture模式,把图送进去forward一把,然后把值记下来
  -- Capture content targets
  for i = 1, #content_losses do
    content_losses[i].mode = 'capture'
  end
  print 'Capturing content targets'
  print(net)
  content_image_caffe = content_image_caffe:type(dtype)
  net:forward(content_image_caffe:type(dtype))


  -- style同理,注意送进去的图片是不一样的,换成style_image_caffe了
  -- Capture style targets
  for i = 1, #content_losses do
    content_losses[i].mode = 'none'
  end
  for i = 1, #style_images_caffe do
    print(string.format('Capturing style target %d', i))
    for j = 1, #style_losses do
      style_losses[j].mode = 'capture'
      style_losses[j].blend_weight = style_blend_weights[i]
    end
    net:forward(style_images_caffe[i]:type(dtype))
  end

  -- 初始化训练的图片,白噪声或者原图
  -- Initialize the image
  if params.seed >= 0 then
    torch.manualSeed(params.seed)
  end
  local img = nil
  if params.init == 'random' then
    img = torch.randn(content_image:size()):float():mul(0.001)
  elseif params.init == 'image' then
    if init_image then
      img = init_image:clone()
    else
      img = content_image_caffe:clone()
    end
  else
    error('Invalid init type')
  end
  img = img:type(dtype)

  -- 最后把训练完的img保存下来即可

TVLoss是什么鬼?

Total Variation (TV) regularization encourages neighboring pixels to have similar values. For noise initializations this regularizer is critical; without it the generated image will exhibit large amounts of high-frequency noise. For image initializations it is less critica
———— https://github.com/jcjohnson/cnn-vis

所以就是一个类似L1正则的东西,避免图片有高频噪点。

Perceptual Losses 加速

  • 原版论文 Perceptual Losses
    上面提到的方法啊,要BP,慢得很。那既然神经网络是个“万能的大黑箱”,我们能不能离线调用上面的算法,生成一堆<原始图,风格图>的pair对作为训练数据,然后train一个网络来直接学习生成风格图呢?那这样新来一个图片,我们forward一把不就得到结果了?
    边学深度边撸代码之快速Neural style艺术风格转换_第2张图片
    我们把上面提到的两步操作合并到一起,那就是上图这个网络结构了。

源码

我fork了一把原始的repo,然后加了一点小注释吧。
https://github.com/dinosoft/neural_style/blob/master/perceptual/train.py
左边生成图片对应gene_executor,右边是原来的网络结构desc_executor, gram matrix对应 gram_executors

你可能感兴趣的:(机器学习)