Advertisement

【深度学习】谷歌deepdream原理及tensorflow实现

阅读量:

什么是DeepDream?

DeepDream是谷歌发布的对卷积神经网络(CNN)进行可视化的方法,当然它的用途不仅限于此,我们可以通过它让机器“做梦”,以下是一些效果:

可以看到计算机将自然图像的一些特征放大,生成了它想想中的一些物体。利用这个特点还可以生成一些从未有过的物体:

DeepDream的原理

卷积神经网络由于其从理论上难以解释,一直被很多学者诟病。在2013年“Visualizing and Understanding Convolutional Neural Networks”这篇文章提出了使用梯度上升 的方法可视化网络每一层的特征,即用一张噪声图像输入网络,反向更新的时候不更新网络权重,而是更新初始图像的像素值,以这种“训练图像”的方式 可视化网络。deepdream正是以此为基础。

之前说过,deepdream需要放大图像特征。比如:有一个网络学习了分类猫和狗的任务,给这个网络一张云的图像,这朵云可能比较像狗,那么机器提取的特征可能也会像狗。假设对应一个特征[0.6, 0.4], 0.6表示为狗的概率, 0.4表示为猫的概率,那么采用L2范数可以很好达到放大特征的效果。对于这样一个特征,L2 = x1^2 + x2^2,若x1越大,x2越小,则L2越大,所以只需要最大化L2就能保证当x1>x2的时候,迭代的轮数越多x1越大,x2越小,所以图像就会越来越像狗。每次迭代相当于计算L2范数,然后用梯度上升的方法调整图像。当然不一定要一张真实的图像,也可以从一张噪声图像生成梦境,只不过生成的梦境会比较奇怪。

以上是DeepDream的基本原理,具体实现的时候还要通过多尺度、随机移动等方法获取比较好的结果,在代码部分会给出详细解释。

DeepDream的tensorflow实现

先放上完整项目的代码:https://github.com/hjptriplebee/deep_dream_tensorflow 欢迎star、fork哦!

实现参考:tensorflow/example/tutorial

首先是下载google的inception模型,tensorflow_inception_graph.pb 是模型文件。

复制代码
 def get_model():

    
     """download model"""
    
     model = os.path.join("model", model_name)
    
     if not os.path.exists(model):
    
     print("Down model...")
    
     os.system("wget https://storage.googleapis.com/download.tensorflow.org/models/inception5h.zip -P model")
    
     os.system("unzip model/inception5h.zip -d model")
    
     os.system("rm model/inception5h.zip")
    
     os.system("rm model/imagenet_comp_graph_label_strings.txt")
    
     return model
    
    
    
    
    python
    
    
![](https://ad.itadn.com/c/weblog/blog-img/images/2025-07-12/Q5iSrPdEoaxzURuI23pyjgDqWmkB.png)

然后定义计算图,加载模型,将输入的placeholder加入计算图中,并定义L2范数和其对于原始图像的梯度。

复制代码
     # define graph

    
     graph = tf.Graph()
    
     sess = tf.InteractiveSession(graph=graph)
    
  
    
     # load model
    
     with tf.gfile.FastGFile(model, "rb") as f:
    
     graph_def = tf.GraphDef()
    
     graph_def.ParseFromString(f.read())
    
  
    
     # define input
    
     X = tf.placeholder(tf.float32, name="input")
    
     X2 = tf.expand_dims(X - imagenet_mean, 0)
    
     tf.import_graph_def(graph_def, {"input": X2})
    
  
    
     # L2 and gradient
    
     loss = tf.reduce_mean(tf.square(graph.get_tensor_by_name("import/%s:0" % layer)))
    
     gradient = tf.gradients(loss, X)[0]
    
    
    
    
    python
    
    
![](https://ad.itadn.com/c/weblog/blog-img/images/2025-07-12/KJnlyQ8hxjqO2TRrCH3M9BeVoDgw.png)

需要多尺度操作,原始尺寸大小的图像不需要存储,下采样再上采样的图像比原始图像模糊,边缘会钝化,做差后的图像可以保留边缘这类的显著性。

复制代码
     for i in range(octave_num - 1):

    
     size = np.shape(image)[:2]
    
     narrow_size = np.int32(np.float32(size) / octave_scale)
    
     # down sampling and up sampling equal to smooth, diff can save significance
    
     down = resize(image, narrow_size)
    
     diff = image - resize(down, size)
    
     image = down
    
     octaves.append(diff)
    
    
    
    
    python
    
    

定义计算梯度的函数。每一次对图像的一块进行梯度上升,为了防止固定区域梯度上升造成块与块之间存在明显的分界线,所以每次要现对图像进行小幅度的随意移动。

复制代码
     def cal_gradient(image, gradient):

    
     """cal gradient"""
    
     # generate offset and shift to smooth tile edge
    
     shift_x, shift_y = np.random.randint(tile_size, size=2)
    
     image_shift = np.roll(np.roll(image, shift_x, 1), shift_y, 0)
    
     total_gradient = np.zeros_like(image)
    
     # calculate gradient for each region
    
     for y in range(0, max(image.shape[0] - tile_size // 2, tile_size), tile_size):
    
         for x in range(0, max(image.shape[1] - tile_size // 2, tile_size), tile_size):
    
             region = image_shift[y:y + tile_size, x:x + tile_size]
    
             total_gradient[y:y + tile_size, x:x + tile_size] = sess.run(gradient, {X: region})
    
     return np.roll(np.roll(total_gradient, -shift_x, 1), -shift_y, 0)
    
    
    
    
    python
    
    
![](https://ad.itadn.com/c/weblog/blog-img/images/2025-07-12/m8hqCj4xiOGF6Rg0QKpbPa7dNMZH.png)

对每一个尺度进行梯度上升。

复制代码
     for i in range(octave_num):

    
     print("octave num %s/%s..." % (i+1, octave_num))
    
     if i > 0:
    
         # restore image except original image
    
         diff = octaves[-i]
    
         image = resize(image, diff.shape[:2]) + diff
    
     for j in range(iter_num):
    
         # gradient ascent
    
         g_ = cal_gradient(image, gradient)
    
         image += g_ * (learning_rate / (np.abs(g_).mean() + 1e-7))  # large learning rate for small g_
    
    
    
    
    python
    
    
![](https://ad.itadn.com/c/weblog/blog-img/images/2025-07-12/a5E2sAX4oHyue03n8iGhCfS7tpl9.png)

代码就这么多,很简短吧?全部代码见: https://github.com/hjptriplebee/deep_dream_tensorflow 欢迎star、fork哦!

采用不同层的特征、迭代轮数、多尺度缩放比例等参数会获得完全不同的结果,下面是一些效果:

我的博客即将同步至腾讯云+社区,邀请大家一同入驻。

全部评论 (0)

还没有任何评论哟~