0. 风一更 雪一更

有几天没有更新了,因为不知道小白喵的学习情况。小黑喵学习深度学习主要还是更偏NLP一点。在文本数据使用word2vec处理为向量矩阵这部分是视觉方向接触不到的,之前想更这部分内容,不过既然是个方法与工具,就觉得意义不是很大,本质上要处理文本还是将其转换为适合神经网络的矩阵向量输入。

前面的章节介绍了LeNet-5和CNN的基本网络构成,代码给出的是这两种网络解决MNIST手写识别问题。如果能对CNN类卷积神经网络有大致印象(它有哪些层,大体上是如何完成conv-relu-pool,层与层参数个数如何计算,全连接层如何工作,原始输入是如何被一层一层的网络层操作、矩阵的大小怎么一步步变化的),我觉得就已经非常好了。更细节的问题需要对照博客内容和代码一步一步的细致看看。比如代码这一步在构建网络的conv层,那么查一下该函数的参数说明,对照论文或博客中的原理,可能认识会更清晰一点。把代码跑起来,会更有成就感一些。

这一个博客要实现的是,利用CNN网络,完成对某一名画A的作画风格的学习后,将这种风格应用于另外一幅画B。即使用A的作画风格,保留B的骨架,将两者融合。本次仿真就没什么数据集了,只需要两幅画。原理其实比较简单,利用CNN网络,将名画A的作画特征进行存取,然后保留这些训练好的过程矩阵(参数),输入画B后将这些参数矩阵与B的矩阵融合(参数矩阵相当于滤镜,用滤镜去看画B)。

代码还在调试中,之后再继续更了。


(Continue...小黑喵施工现场...)


1. 聒碎乡心梦不成

施工基本完毕了。因为上午去值班的时候那里有人了,所以换成下午去了。这篇博客代码参考2015年的著名文章《A Neural Algorithm of Artistic Style》(https://arxiv.org/abs/1508.06576),首先需要手动下载预训练的网络,并保存为.mat格式(matlab格式的一种)至代码同一文件下,下载链接为 http://www.vlfeat.org/matconvent/models/beta16/imagenet-vgg-verydeep-19.mat,文件有549MB。

1.1 代码

# 参考文章:
# https://arxiv.org/abs/1508.06576
#
# 需要下载预训练模型 'imagenet-vgg-verydee-19.mat' 链接如下:
#   http://www.vlfeat.org/matconvnet/models/beta16/imagenet-vgg-verydeep-19.mat

import scipy.io
import scipy.misc
import numpy as np
import tensorflow as tf
from tensorflow.python.framework import ops
ops.reset_default_graph()

# 创建计算图会话
sess = tf.Session()

# 图片文件,原始图像为杂志封面图,风格图像为梵高的星空
original_image_file = '../images/book_cover.jpg'
style_image_file = '../images/starry_night.jpg'

# 导入刚刚下载的预训练模型
vgg_path = 'imagenet-vgg-verydeep-19.mat'

# 设置模型参数 网络权重、学习率、迭代次数等
original_image_weight = 5.0
style_image_weight = 500.0
regularization_weight = 100
learning_rate = 0.001
generations = 5000
output_generations = 250
beta1 = 0.9
beta2 = 0.999

# 读入两个图片文件
original_image = scipy.misc.imread(original_image_file)
style_image = scipy.misc.imread(style_image_file)

# 将原图像与风格图像整理为大小相同的矩阵
target_shape = original_image.shape
style_image = scipy.misc.imresize(style_image, target_shape[1] / style_image.shape[1])

# 按照paper定义相关layer
vgg_layers = ['conv1_1', 'relu1_1',
              'conv1_2', 'relu1_2', 'pool1',
              'conv2_1', 'relu2_1',
              'conv2_2', 'relu2_2', 'pool2',
              'conv3_1', 'relu3_1',
              'conv3_2', 'relu3_2',
              'conv3_3', 'relu3_3',
              'conv3_4', 'relu3_4', 'pool3',
              'conv4_1', 'relu4_1',
              'conv4_2', 'relu4_2',
              'conv4_3', 'relu4_3',
              'conv4_4', 'relu4_4', 'pool4',
              'conv5_1', 'relu5_1',
              'conv5_2', 'relu5_2',
              'conv5_3', 'relu5_3',
              'conv5_4', 'relu5_4']

# 定义函数,用来抽取预训练模型.mat文件中的参数
def extract_net_info(path_to_params):
    vgg_data = scipy.io.loadmat(path_to_params)
    normalization_matrix = vgg_data['normalization'][0][0][0]
    mat_mean = np.mean(normalization_matrix, axis=(0,1))
    network_weights = vgg_data['layers'][0]
    return(mat_mean, network_weights)

# 根据预训练模型加载权重和网络层定义,通过tensorflow创建网
# 迭代训练每层,并分配合适的权重和偏置
def vgg_network(network_weights, init_image):
    network = {}
    image = init_image

for i, layer in enumerate(vgg_layers):
        if layer[0] == 'c':
            weights, bias = network_weights[i][0][0][0][0]
            weights = np.transpose(weights, (1, 0, 2, 3))
            bias = bias.reshape(-1)
            conv_layer = tf.nn.conv2d(image, tf.constant(weights), (1, 1, 1, 1), 'SAME')
            image = tf.nn.bias_add(conv_layer, bias)
        elif layer[0] == 'r':
            image = tf.nn.relu(image)
        else:
            image = tf.nn.max_pool(image, (1, 2, 2, 1), (1, 2, 2, 1), 'SAME')
        network[layer] = image
    return(network)

# 参考paper的 原始图片和风格图片分配中间层的策略
# 原始图片采用relu4_2层,风格图片采用reluX_1层组合
original_layer = 'relu4_2'
style_layers = ['relu1_1', 'relu2_1', 'relu3_1', 'relu4_1', 'relu5_1']

# 通过extract_net_info函数获取网络权重和平均值
# tensorflow的图像处理针对4维,所以增加一个无关紧要的维度满足输入
normalization_mean, network_weights = extract_net_info(vgg_path)

shape = (1,) + original_image.shape
style_shape = (1,) + style_image.shape
original_features = {}
style_features = {}

# 声明image占位符,创建该占位符的网络
image = tf.placeholder('float', shape=shape)
vgg_net = vgg_network(network_weights, image)

# 归一化原始图片矩阵,并运行网络
original_minus_mean = original_image - normalization_mean
original_norm = np.array([original_minus_mean])
original_features[original_layer] = sess.run(vgg_net[original_layer],
                                             feed_dict={image: original_norm})

# 参考中间层策略,重复原始图片relu4_2层、风格图片reluX_1层
image = tf.placeholder('float', shape=style_shape)
vgg_net = vgg_network(network_weights, image)
style_minus_mean = style_image - normalization_mean
style_norm = np.array([style_minus_mean])

for layer in style_layers:
    layer_output = sess.run(vgg_net[layer], feed_dict={image: style_norm})
    layer_output = np.reshape(layer_output, (-1, layer_output.shape[3]))
    style_gram_matrix = np.matmul(layer_output.T, layer_output) / layer_output.size
    style_features[layer] = style_gram_matrix

# 使用“滤镜”融合原始图片,并引入随机噪声
initial = tf.random_normal(shape) * 0.256
image = tf.Variable(initial)
vgg_net = vgg_network(network_weights, image)

# 第一个损失函数 针对原图片
# 定义为原始图片relu4_2层与归一化后的原始图片矩阵差值的L_2范数
original_loss = original_image_weight * (2 * tf.nn.l2_loss(vgg_net[original_layer] - original_features[original_layer]) /
                original_features[original_layer].size)
               
# 第二个损失函数 针对风格图片
# 为风格图片的每个层(前面提到的reluX_1,X=1~5)计算损失函数
style_loss = 0
style_losses = []
for style_layer in style_layers:
    layer = vgg_net[style_layer]
    feats, height, width, channels = [x.value for x in layer.get_shape()]
    size = height * width * channels
    features = tf.reshape(layer, (-1, channels))
    style_gram_matrix = tf.matmul(tf.transpose(features), features) / size
    style_expected = style_features[style_layer]
    style_losses.append(2 * tf.nn.l2_loss(style_gram_matrix - style_expected) / style_expected.size)
style_loss += style_image_weight * tf.reduce_sum(style_losses)
       
# 第三个损失函数 (...不是很明白)
total_var_x = sess.run(tf.reduce_prod(image[:,1:,:,:].get_shape()))
total_var_y = sess.run(tf.reduce_prod(image[:,:,1:,:].get_shape()))
first_term = regularization_weight * 2
second_term_numerator = tf.nn.l2_loss(image[:,1:,:,:] - image[:,:shape[1]-1,:,:])
second_term = second_term_numerator / total_var_y
third_term = (tf.nn.l2_loss(image[:,:,1:,:] - image[:,:,:shape[2]-1,:]) / total_var_x)
total_variation_loss = first_term * (second_term + third_term)
   
# 将前面三个损失函数加和
loss = original_loss + style_loss + total_variation_loss

# 声明优化器函数
optimizer = tf.train.AdamOptimizer(learning_rate,beta1,beta2)
train_step = optimizer.minimize(loss)

# 初始化变量,开始训练
sess.run(tf.global_variables_initializer())
for i in range(generations):
   
    sess.run(train_step)

# 不断打印融合的图片,效果可以时即可停止
    if (i+1) % output_generations == 0:
        print('Generation {} out of {}, loss: {}'.format(i + 1, generations,sess.run(loss)))
        image_eval = sess.run(image)
        best_image_add_mean = image_eval.reshape(shape[1:]) + normalization_mean
        output_file = 'temp_output_{}.jpg'.format(i)
        scipy.misc.imsave(output_file, best_image_add_mean)
       
       
# 最优结果保存为final_output.jpg
image_eval = sess.run(image)
best_image_add_mean = image_eval.reshape(shape[1:]) + normalization_mean
output_file = 'final_output.jpg'
scipy.misc.imsave(output_file, best_image_add_mean)

1.2 运行效果

首先是两副初始的图片。作为原始图片的杂志封面book_cover.jpg,作为风格图片的星空starry_night.jpg。另存为可以不用再自己下载啦:

   

运行代码进行风格融合后(训练时间可能较长,当看到文件夹下打印的临时照片效果较好时即可停止):

2. 故园无此声

小黑喵的第五个教程就先到这里了。这次这个实战项目挺有意思的。它利用卷积神经网络对图像特征的抽取进行图片风格融合,本质上就是前面提到的“制作滤镜”。短发非常好看。

转载于:https://www.cnblogs.com/catallen/p/8888778.html

CNN实战1:实现模仿大师绘画相关推荐

  1. 用python做元旦贺卡_用AI帮你画新年贺卡:只需输入几个单词,就能模仿大师名作...

    原标题:用AI帮你画新年贺卡:只需输入几个单词,就能模仿大师名作 晓查 发自 凹非寺 量子位 出品 | 公众号 QbitAI 如果你的手法拙劣,没有任何艺术细菌,自己作画完全无法见人.但是你想给妹子送 ...

  2. 【卷积神经网络CNN 实战案例 GoogleNet 实现手写数字识别 源码详解 深度学习 Pytorch笔记 B站刘二大人 (9.5/10)】

    卷积神经网络CNN 实战案例 GoogleNet 实现手写数字识别 源码详解 深度学习 Pytorch笔记 B站刘二大人 (9.5/10) 在上一章已经完成了卷积神经网络的结构分析,并通过各个模块理解 ...

  3. CNN实战:猫狗大战

    1.猫狗大战VGG模型迁移学习 下载数据 猫和狗的图片放在单独的文件夹中. 数据处理 对图片进行预处理 创建VGG Model 使用预训练好的VGG Model,并对 输入的5张图片进行识别 可以看出 ...

  4. 微信小程序实战教程:模仿—网易云音乐(二)

    接上一篇:微信小程序实战教程:模仿-网易云音乐(一) wxml进行渲染: <!--歌词--> <view class="lyric-content" hidden ...

  5. 【TensorFlow实战笔记】卷积神经网络CNN实战-cifar10数据集(tensorboard可视化)

    IDE:pycharm Python: Python3.6 OS: win10 tf : CPU版本 代码可在github中下载,欢迎star,谢谢 CNN-CIFAR-10 一.CIFAR10数据集 ...

  6. Android实战第二篇——模仿社交软件探探(一)

    这是我的第二篇实战,相比于第一篇的看视频模仿着实战,这一篇完全是自己的实战,不借助任何视频教程,看视频的实战是在抄代码,而这一篇是完全自己构思,自己去解决问题的,这次的实战是仿照一个社交软件探探,该篇 ...

  7. 用AI帮你画新年贺卡:只需输入几个单词,就能模仿大师名作

    晓查 发自 凹非寺 量子位 出品 | 公众号 QbitAI 如果你的手法拙劣,没有任何艺术细菌,自己作画完全无法见人.但是你想给妹子送上一张有个性的新年贺卡怎么办? 虽然没有梵高.毕加索的才华,但你能 ...

  8. Python CNN卷积神经网络实例讲解,CNN实战,CNN代码实例,超实用

    一.CNN简介 1. 神经网络基础 输入层(Input layer),众多神经元(Neuron)接受大量非线形输入讯息.输入的讯息称为输入向量. 输出层(Output layer),讯息在神经元链接中 ...

  9. android 属性动画高级,Android高级UI开发(二十五)属性动画实战案例之流浪大师与乔帮主...

    在上一篇文章里我们介绍了属性动画的基础知识,今天我们综合运用属性动画的知识来完成一个动画案例.首先,看一下这个动画效果: 1.  分析这个动画案例 第一个动画(浏览大师的动画)是:当点击顶部" ...

最新文章

  1. SSC:基于点云语义上下文的大规模激光SLAM的位置识别方法
  2. Web中的XHRHttpRequest
  3. SQLite学习手册(数据类型)
  4. 音视频技术开发周刊 60期
  5. 小谈Online-game服务器端设计(3)
  6. mysql update 跳过重复_MySQL通过UPDATE / DELETE整合重复的数据记录
  7. 内核模块编程之_初窥门径【ZT】
  8. php两个编辑框一个提交按钮,一个表单中的两个提交按钮
  9. python垃圾分类图像识别算法_用算法帮上海大妈垃圾分类,扔错罚款!长点心吧你...
  10. git优点缺点(简单介绍)
  11. 从备用类型总盗用steal page
  12. weblogic下载及安装
  13. 面试手写代码的经验分享
  14. tumblr_使用Google Analytics(分析)获取有关您的Tumblr博客的详细统计信息
  15. 微信小程序常见面试题与总结
  16. UWP开发:获取用户当前所在的网络环境(WiFi、移动网络、LAN…)
  17. 2G金士顿U盘修复工具迈科微MW6208E/8208_v1.2.0.8
  18. 【10.03】富士康(世界500强第22位) 嵌入式软件相关多岗位招聘 10-45k月薪 内推...
  19. while语句计算n的阶乘
  20. SuperMap iClient3D for WebGL教程 Primitive

热门文章

  1. c语言字符蛇代码,C语言实现贪吃蛇代码
  2. DataGridView上移 下移行
  3. 程序员可以接私活的平台和一些建议
  4. wifi ap channel
  5. 基于程序员的知识付费,这个网站有点新意,但是基于程序员的知识付费,能刮起一阵凤么?
  6. python123.io---CSV 格式数据清洗
  7. 2023离职与调薪调研报告
  8. java calendar 月 加一_JAVA Calendar设置时间,月份总是加1 | 学步园
  9. Linux中grep用法(“或”、“与”)
  10. QQ图标在win7中的单个隐藏