DeepDream是利用指定标签,通过方向传播调整输入图像来让固有的CNN网络能够生成出目标标签图像。它与CNN的不同在于,CNN是利用真实标签对训练图片集的误差来修正神经网络,让神经网络能够识别图像。而DeepDream则是利用一个固定的网络,让一个随机图像能够逼近网络的识别图像。

!

深度学习特征可视化热图 deep可视化_神经网络

下图就是deep_dream生成的海星图

深度学习特征可视化热图 deep可视化_ci_02


下面的代码是经过优化的,可生成高质量deep_dream图像的代码,可以直接运行测试。使用的模型是训练好的GoogleNet的Inception。

#导入库与inception模型
from __future__ import print_function
import os
from io import BytesIO
import numpy as np
from functools import partial
import PIL.Image
import scipy.misc
import tensorflow as tf

#新建一个图像
graph = tf.Graph()
#从inception读入模型,该模型文件存放在当前目录下
model_fn = 'tensorflow_inception_graph.pb'
sess = tf.InteractiveSession(graph=graph)
with tf.gfile.GFile(model_fn, 'rb') as f:
	graph_def = tf.GraphDef()
	#对模型文件进行解析
	graph_def.ParseFromString(f.read())
t_input = tf.placeholder(np.float32,name='input')
imagenet_mean = 117.0
#将要输入的占位符做扩维预处理
t_preprocessed = tf.expand_dims(t_input-imagenet_mean,0)
#读入模型,并将数据送入模型
tf.import_graph_def(graph_def,{'input':t_preprocessed})

#定义相关函数
#保存图像
def savearray(img_array,img_name):
	scipy.misc.toimage(img_array).save(img_name)
	print("img saved:%s"%img_name)

#将图像放大ratio倍
def resize_ratio(img,ratio):
	min = img.min()
	max = img.max()
	img = (img-min)/(max-min)*255
	img = np.float32(scipy.misc.imresize(img,ratio))
	img = img/255*(max-min)+min
	return img

#调整图像尺寸
def resize(img,hw):
	min = img.min()
	max = img.max()
	img = (img-min)/(max-min)*255
	img = np.float32(scipy.misc.imresize(img,hw))
	img = img/255*(max-min) +min
	return img

#每次只对tile_sieze*tile_size大小的图像计算梯度,避免内存问题
def calc_grad_tiled(img,t_grad,tile_size=512):
	sz = tile_size
	h,w=img.shape[:2]
	sx,sy = np.random.randint(sz,size=2)
	#先在行上做整体移动,再在列上做整体移动
	img_shift = np.roll(np.roll(img,sx,1),sy,0)
	grad = np.zeros_like(img)
	for y in range(0,max(h-sz//2,sz),sz):
		for x in range(0,max(w-sz//2,sz),sz):
			sub = img_shift[y:y+sz,x:x+sz]
			g= sess.run(t_grad,{t_input:sub})
			grad[y:y+sz,x:x+sz] = g
	return np.roll(np.roll(grad,-sx,1),-sy,0)

#改进的渲染函数,octave_n是金字塔的层数,octive_scale是层与层之间的倍数
def render_deepdream(t_obj,img0,iter_n=10,step=1.5,octave_n =4,octave_scale=1.4):
	t_score = tf.reduce_mean(t_obj)
	t_grad = tf.gradients(t_score,t_input)[0]
	img = img0.copy()

	#将图像进行金字塔分解
	#分成高频和低频部分
	octaves = []
	for i in range(octave_n -1):
		#获取图像尺寸的前两位 高和宽
		hw=img.shape[:2]
		lo = resize(img,np.int32(np.float32(hw)/octave_scale))
		hi = img - resize(lo,hw)
		img = lo
		octaves.append(hi)
	#首先生成低频的图像,再以此放大并加上高频
	for octave in range(octave_n):
		if octave>0:
			hi = octaves[-octave]
			img = resize(img,hi.shape[:2])+hi
		for i in range(iter_n):
			g = calc_grad_tiled(img,t_grad)
			img += g*(step/(np.abs(g).mean()+1e-7))
	img = img.clip(0,255)
	savearray(img,'test_deepdream.jpg')
	im = PIL.Image.open("test_deepdream.jpg").show()

#生成以背景图像作为起点的DeepDream图像
#从incption模型中取出某层卷积张量
name = 'mixed4c'
layer_output = graph.get_tensor_by_name("import/%s:0"%name)
img0 = PIL.Image.open('test.jpg')
img0 = np.float32(img0)
render_deepdream(tf.square(layer_output),img0,iter_n=100)

从代码可以看到,从训练好了的网络模型中取出mixed4c这一层的卷积张量。利用该卷积张量对预置图像做训练,训练后可以看到这一层卷积对图像的作用效果。

训练前的原图:

深度学习特征可视化热图 deep可视化_tensorflow_03


训练后的deep_dream图片

深度学习特征可视化热图 deep可视化_深度学习特征可视化热图_04


能够直观地观察到某一层的卷积提取的是图像的什么信息。总体概括来说,卷积层越深,提取的特征就越抽象,卷积核的通道越多,提取的特征就越抽象。

PS:本例的模型tensorflow_inception_graph.pb从https://storage.googleapis.com/download.tensorflow.org/models/inception5h.zip下载

PS:本例的图像预处理是根据tensorflow_inception_graph模型做的预处理,目的就是保证输入图像与模型训练输入图像的维度保持一致