好玩的Deep Dream模型

目录

1.Deep Dream是什么?

2.Tensorflow中Deep Dream模型实践 

1)导入inception模型

2)生成原始的DeepDream图像

3)生成更多尺寸的DeepDream图像

4)生成更高质量的DeepDream图像

5)构建最终的DeepDream模型

3.总结


本文为笔者学习《21个项目玩转深度学习:基于TensorFlow的实践详解》这本书第四章的学习笔记。

1.Deep Dream是什么?

        《21个项目玩转深度学习:基于TensorFlow的实践详解》一书对Deep Dream解释如下:Deep Dream是Google公司在2015年公布的一项有趣的技术。在训练好的卷积神经网络中,只需要设定几个参数,就可以通过这项技术生成一张图像。

        在卷积神经网络中,输入的时一张图片,中间经过若干层卷积层来提取feature map,然后将feature map输入到全连接层中,通过全连接层最后进行分类。那么,卷积层中到底学到了什么?获取的feature map到底是什么样的呢?

        “卷积的一个通道就可以代表一种学习到”信息”,以某一个通道的平均值作为优化目标,就可以搞清楚这个通道究竟学习到了什么,这就是Deep Dream的基本原理。

2.Tensorflow中Deep Dream模型实践 

1)导入inception模型

原始的Deep Dream模型只需要优化ImageNet模型卷积层某个通道的激活值就可以了,因此需要先导入一个ImageNet图像识别模型。这里以Inception为例。TensorFlow将训练的模型导入到.pb为扩展名的文件中,在使用的时候再导出。对于inception模型,对应的pb模型文件名为tensorflow_inceptioin_graph.pb。

tensorflow_inceptioin_graph.pb也可以去百度或者Google来下载。导入inception的模型代码如下:

# coding:utf-8
# 导入要用到的基本模块。
from __future__ import print_function
import numpy as np
import tensorflow as tf

# 创建图和Session
graph = tf.Graph()
sess = tf.InteractiveSession(graph=graph)

# tensorflow_inception_graph.pb文件中,既存储了inception的网络结构也存储了对应的数据
# 使用下面的语句将之导入
model_fn = 'tensorflow_inception_graph.pb'
#tf.gfile.FastGFile(path,decodestyle)
#功能:实现对图片的读取。
#参数:(1)path:图片所在路径 (2)decodestyle:图片的解码方式。(‘r’:UTF-8编码; ‘rb’:非UTF-8编码)
with tf.gfile.FastGFile(model_fn, 'rb') as f:
    #先创建一个空的图
    graph_def = tf.GraphDef()
    graph_def.ParseFromString(f.read())
# 定义t_input为我们输入的图像
t_input = tf.placeholder(np.float32, name='input')
imagenet_mean = 117.0
# 输入图像需要经过处理才能送入网络中
# expand_dims是加一维,从[height, width, channel]变成[1, height, width, channel]
# t_input - imagenet_mean是减去一个均值
t_preprocessed = tf.expand_dims(t_input - imagenet_mean, 0)
#导入模型
tf.import_graph_def(graph_def, {'input': t_preprocessed})

# 找到所有卷积层
layers = [op.name for op in graph.get_operations() if op.type == 'Conv2D' and 'import/' in op.name]

# 输出卷积层层数
print('Number of layers', len(layers))
#输出各个层的名称
print('Layers:', layers)
# 特别地,输出mixed4d_3x3_bottleneck_pre_relu的形状
name = 'mixed4d_3x3_bottleneck_pre_relu'
print('shape of %s: %s' % (name, str(graph.get_tensor_by_name('import/' + name + ':0').get_shape())))

需要注意以下几点:

(1)在导入的时候需要给网络指定一个输入图像,为此设置了一个占位符t_input,输入图像时将图像传给t_input,需要修改图像格式为(batch,height,width,channel),这里batch为1,因为在训练图像时都是一个batch一个batch来输入的,每个batch中有多张图像。

(2)为图像减去一个像素均值。原因是训练inception的时候做了减去均值的预处理,因此,应该使用同样的预处理方法才能保持输入的一致。这里的固定均值为117。

经过减去均值和 添加batch维度这两项处理后,得到了要实际输入网络的图像t_preprocessed。

运行程序会输出共有59个卷积层,代码中的print('Layers:', layers)打印了各个层的名称,名称如下,我们可以对照着名称来了解网络模型。

Layers: ['import/conv2d0_pre_relu/conv', 'import/conv2d1_pre_relu/conv',
'import/conv2d2_pre_relu/conv','import/mixed3a_1x1_pre_relu/conv',
'import/mixed3a_3x3_bottleneck_pre_relu/conv', 'import/mixed3a_3x3_pre_relu/conv',
'import/mixed3a_5x5_bottleneck_pre_relu/conv', 'import/mixed3a_5x5_pre_relu/conv',
'import/mixed3a_pool_reduce_pre_relu/conv', 'import/mixed3b_1x1_pre_relu/conv',
'import/mixed3b_3x3_bottleneck_pre_relu/conv', 'import/mixed3b_3x3_pre_relu/conv',
'import/mixed3b_5x5_bottleneck_pre_relu/conv', 'import/mixed3b_5x5_pre_relu/conv',
'import/mixed3b_pool_reduce_pre_relu/conv', 'import/mixed4a_1x1_pre_relu/conv',
'import/mixed4a_3x3_bottleneck_pre_relu/conv', 'import/mixed4a_3x3_pre_relu/conv',
'import/mixed4a_5x5_bottleneck_pre_relu/conv', 'import/mixed4a_5x5_pre_relu/conv',
'import/mixed4a_pool_reduce_pre_relu/conv', 'import/mixed4b_1x1_pre_relu/conv',
'import/mixed4b_3x3_bottleneck_pre_relu/conv', 'import/mixed4b_3x3_pre_relu/conv',
'import/mixed4b_5x5_bottleneck_pre_relu/conv', 'import/mixed4b_5x5_pre_relu/conv',
'import/mixed4b_pool_reduce_pre_relu/conv', 'import/mixed4c_1x1_pre_relu/conv',
'import/mixed4c_3x3_bottleneck_pre_relu/conv', 'import/mixed4c_3x3_pre_relu/conv',
'import/mixed4c_5x5_bottleneck_pre_relu/conv', 'import/mixed4c_5x5_pre_relu/conv',
'import/mixed4c_pool_reduce_pre_relu/conv', 'import/mixed4d_1x1_pre_relu/conv',
'import/mixed4d_3x3_bottleneck_pre_relu/conv', 'import/mixed4d_3x3_pre_relu/conv',
'import/mixed4d_5x5_bottleneck_pre_relu/conv', 'import/mixed4d_5x5_pre_relu/conv',
'import/mixed4d_pool_reduce_pre_relu/conv', 'import/mixed4e_1x1_pre_relu/conv',
'import/mixed4e_3x3_bottleneck_pre_relu/conv', 'import/mixed4e_3x3_pre_relu/conv',
'import/mixed4e_5x5_bottleneck_pre_relu/conv', 'import/mixed4e_5x5_pre_relu/conv',
'import/mixed4e_pool_reduce_pre_relu/conv', 'import/mixed5a_1x1_pre_relu/conv',
'import/mixed5a_3x3_bottleneck_pre_relu/conv', 'import/mixed5a_3x3_pre_relu/conv',
'import/mixed5a_5x5_bottleneck_pre_relu/conv', 'import/mixed5a_5x5_pre_relu/conv',
'import/mixed5a_pool_reduce_pre_relu/conv', 'import/mixed5b_1x1_pre_relu/conv',
'import/mixed5b_3x3_bottleneck_pre_relu/conv', 'import/mixed5b_3x3_pre_relu/conv',
'import/mixed5b_5x5_bottleneck_pre_relu/conv', 'import/mixed5b_5x5_pre_relu/conv',
'import/mixed5b_pool_reduce_pre_relu/conv', 'import/head0_bottleneck_pre_relu/conv',
'import/head1_bottleneck_pre_relu/conv']

2)生成原始的DeepDream图像

这里以mixed4d_3x3_bottleneck_pre_relu层为例,最大化某一个通道的平均值来生成图像。

首先,取出对应名称为mixed4d_3x3_bottleneck_pre_relu的卷积层输出layer_output,这里选择通道channel=139来进行最大化,最后用渲染函数render_naive的时候传递layer_output[:, :, :, channel]即可。render_naive中传入的img0是随机构造的初始图像,它是一个形状为(224,224,3)的张量,表示初始的图像优化起点。

# coding: utf-8
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()
model_fn = 'tensorflow_inception_graph.pb'
sess = tf.InteractiveSession(graph=graph)
with tf.gfile.FastGFile(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)


def render_naive(t_obj, img0, iter_n=30, step=1.0):
    # t_score是优化目标。它是t_obj的平均值
    # 结合调用处看,实际上就是layer_output[:, :, :, channel]的平均值
    t_score = tf.reduce_mean(t_obj)
    # 计算t_score对t_input的梯度
    t_grad = tf.gradients(t_score, t_input)[0]

    # 创建新图
    img = img0.copy()
    for i in range(iter_n):
        # 在sess中计算梯度,以及当前的score
        g, score = sess.run([t_grad, t_score], {t_input: img})
        # 对img应用梯度。step可以看做“学习率”
        g /= g.std() + 1e-8
        img += g * step
        print('score(mean)=%f' % (score))
    # 保存图片
    savearray(img, 'naive.jpg')

# 定义卷积层、通道数,并取出对应的tensor
name = 'mixed4d_3x3_bottleneck_pre_relu'
channel = 139
layer_output = graph.get_tensor_by_name("import/%s:0" % name)

# 定义原始的图像噪声
img_noise = np.random.uniform(size=(224, 224, 3)) + 100.0
# 调用render_naive函数渲染
render_naive(layer_output[:, :, :, channel], img_noise, iter_n=20)

以上代码保存在gen_naive.py中,执行gen_naive.py结果如下:

score(mean)=-19.891029
score(mean)=-31.205770
score(mean)=21.456114
score(mean)=108.289459
score(mean)=178.601166
score(mean)=232.210205
score(mean)=290.056335
score(mean)=335.893524
score(mean)=375.240875
score(mean)=423.900024
score(mean)=465.111328
score(mean)=513.792480
score(mean)=535.929504
score(mean)=576.985229
score(mean)=602.876892
score(mean)=638.416992
score(mean)=659.976440
score(mean)=688.588501
score(mean)=711.269775
score(mean)=733.619324
img saved: naive.jpg

这说明score(也就是卷积层对应通道的平均值)确实是按照期望在逐渐增大的。经过20次迭代后,将图片保存为naive.jpg,这个图像中能模糊的看到有花的文理图,说明mixed4d_3x3_bottleneck_pre_relu层的第139个通道学习到的特征为花的纹理图特征。生成的naive.jpg图像如下:

                                                                                        

 

3)生成更多尺寸的DeepDream图像

        以上生成的图片大小为(224,224,3),如果要想生成更大尺寸的图像,就需要调整输入初始化图片的大小。但是,这会存在一个问题:要生成的图像越大,就会占用越大的内存(或显存),若想生成更大的图像,就会因为内存不足而渲染失败。解决该问题的思路是:每次不对整张图片做优化,而是把图片分成几部分,每次只对一部分做优化,这样每次优化时只会消耗固定大小的内存。

代码如下:

# coding:utf-8
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()
model_fn = 'tensorflow_inception_graph.pb'
sess = tf.InteractiveSession(graph=graph)
with tf.gfile.FastGFile(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)


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 calc_grad_tiled(img, t_grad, tile_size=512):
    # 每次只对tile_size×tile_size大小的图像计算梯度,避免内存问题
    sz = tile_size
    h, w = img.shape[:2]
    # img_shift:先在行上做整体移动,再在列上做整体移动
    # 防止在tile的边缘产生边缘效应
    sx, sy = np.random.randint(sz, size=2)
    img_shift = np.roll(np.roll(img, sx, 1), sy, 0)
    grad = np.zeros_like(img)
    # y, x是开始位置的像素
    for y in range(0, max(h - sz // 2, sz), sz):
        for x in range(0, max(w - sz // 2, sz), sz):
            # 每次对sub计算梯度。sub的大小是tile_size×tile_size
            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
    # 使用np.roll移动回去
    return np.roll(np.roll(grad, -sx, 1), -sy, 0)


def render_multiscale(t_obj, img0, iter_n=20, step=1.0, octave_n=3, octave_scale=1.4):
    # 同样定义目标和梯度
    t_score = tf.reduce_mean(t_obj)
    t_grad = tf.gradients(t_score, t_input)[0]

    img = img0.copy()
    for octave in range(octave_n):
        if octave > 0:
            # 每次将将图片放大octave_scale倍
            # 共放大octave_n - 1 次
            img = resize_ratio(img, octave_scale)
        for i in range(iter_n):
            # 调用calc_grad_tiled计算任意大小图像的梯度
            g = calc_grad_tiled(img, t_grad)
            g /= g.std() + 1e-8
            img += g * step
            print('.', end=' ')
    savearray(img, 'multiscale.jpg')

if __name__ == '__main__':
    name = 'mixed4d_3x3_bottleneck_pre_relu'
    channel = 139
    img_noise = np.random.uniform(size=(224, 224, 3)) + 100.0
    layer_output = graph.get_tensor_by_name("import/%s:0" % name)
    render_multiscale(layer_output[:, :, :, channel], img_noise, iter_n=20)

运行后生成图像如下图所示。这张图确实大了许多,而且花朵的纹理更清晰了。

                                                         

4)生成更高质量的DeepDream图像

        以上的关注点是怎样将图像放大,这里关注一下图像的生成质量。在图像处理算法中,有高频成分和低频成分之分。简单来说,高频成分是指图像中灰度、颜色、透明度变化比较剧烈的地方,如边缘、细节部分。而低频成分是指,图像变化不大的地方,比如大块色块、整体风格。一般来讲,图像中的低频成分更多一些,这样图像会比较“柔和”。

        此处采用放大低频的梯度,之前生成图像时使用的梯度是统一的,如果可以对梯度做分解,将之分为“高频梯度”和“低频梯度”,再人为地去放大“低频梯度”,就可以得到较为柔和的图像了。具体实践中,使用拉普拉斯金字塔对图像进行分解。

        使用拉普拉斯金字塔( Laplacian Pyramid )对图像进行分解。这种算法可以把图片分解为多层,如图 4-5 所示 底层的 level1 level2
就对应图像的高频成分,而上层的 level3 level4 对应图像的低频成分。可以对梯度也做这样的分解。分解之后,对高频的梯度和低频的梯度都做标准化,可以让梯度的低频成分和高频成分差不多,表现在图像上就会增加图像的低频成分,从而提高生成图像的质量。通常称这种方法为拉普拉斯金字塔梯度标准化( Laplacian Pyramid Gradient Normalization )。

代码如下,可以在代码中仔细体会该算法的思路。

# coding:utf-8
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()
model_fn = 'tensorflow_inception_graph.pb'
sess = tf.InteractiveSession(graph=graph)
with tf.gfile.FastGFile(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)



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 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)

k = np.float32([1, 4, 6, 4, 1])
k = np.outer(k, k)
k5x5 = k[:, :, None, None] / k.sum() * np.eye(3, dtype=np.float32)

# 这个函数将图像分为低频和高频成分
def lap_split(img):
    with tf.name_scope('split'):
        # 做过一次卷积相当于一次“平滑”,因此lo为低频成分
        lo = tf.nn.conv2d(img, k5x5, [1, 2, 2, 1], 'SAME')
        # 低频成分放缩到原始图像一样大小得到lo2,再用原始图像img减去lo2,就得到高频成分hi
        lo2 = tf.nn.conv2d_transpose(lo, k5x5 * 4, tf.shape(img), [1, 2, 2, 1])
        hi = img - lo2
    return lo, hi

# 这个函数将图像img分成n层拉普拉斯金字塔
def lap_split_n(img, n):
    levels = []
    for i in range(n):
        # 调用lap_split将图像分为低频和高频部分
        # 高频部分保存到levels中
        # 低频部分再继续分解
        img, hi = lap_split(img)
        levels.append(hi)
    levels.append(img)
    return levels[::-1]

# 将拉普拉斯金字塔还原到原始图像
def lap_merge(levels):
    img = levels[0]
    for hi in levels[1:]:
        with tf.name_scope('merge'):
            img = tf.nn.conv2d_transpose(img, k5x5 * 4, tf.shape(hi), [1, 2, 2, 1]) + hi
    return img


# 对img做标准化。
def normalize_std(img, eps=1e-10):
    with tf.name_scope('normalize'):
        std = tf.sqrt(tf.reduce_mean(tf.square(img)))
        return img / tf.maximum(std, eps)

# 拉普拉斯金字塔标准化
def lap_normalize(img, scale_n=4):
    img = tf.expand_dims(img, 0)
    tlevels = lap_split_n(img, scale_n)
    # 每一层都做一次normalize_std
    tlevels = list(map(normalize_std, tlevels))
    out = lap_merge(tlevels)
    return out[0, :, :, :]


def tffunc(*argtypes):
    placeholders = list(map(tf.placeholder, argtypes))
    def wrap(f):
        out = f(*placeholders)
        def wrapper(*args, **kw):
            return out.eval(dict(zip(placeholders, args)), session=kw.get('session'))
        return wrapper
    return wrap


def render_lapnorm(t_obj, img0,
                   iter_n=10, step=1.0, octave_n=3, octave_scale=1.4, lap_n=4):
    # 同样定义目标和梯度
    t_score = tf.reduce_mean(t_obj)
    t_grad = tf.gradients(t_score, t_input)[0]
    # 将lap_normalize转换为正常函数
    lap_norm_func = tffunc(np.float32)(partial(lap_normalize, scale_n=lap_n))

    img = img0.copy()
    for octave in range(octave_n):
        if octave > 0:
            img = resize_ratio(img, octave_scale)
        for i in range(iter_n):
            g = calc_grad_tiled(img, t_grad)
            # 唯一的区别在于我们使用lap_norm_func来标准化g!
            g = lap_norm_func(g)
            img += g * step
            print('.', end=' ')
    savearray(img, 'lapnorm.jpg')

if __name__ == '__main__':
    name = 'mixed4d_3x3_bottleneck_pre_relu'
    channel = 139
    img_noise = np.random.uniform(size=(224, 224, 3)) + 100.0
    layer_output = graph.get_tensor_by_name("import/%s:0" % name)
    render_lapnorm(layer_output[:, :, :, channel]+layer_output[:, :, :, 99], img_noise, iter_n=20)

        运行以上代码,生成结果如下图所示。怎么样,是不是看着柔和舒服了许多啊?这样我们可以更进一步的了解这个卷积层的139通道学习到的图像特征长什么样子。

                                                    

5)构建最终的DeepDream模型

        上边的图像都是使用随机生成的图像作为初始图像(也就是说背景是随机的图像),我们也可以使用一张自己的图像作为起始图像来和特征图搭配在一起生成一张图像。

        使用下面这张图最为背景。

# coding:utf-8
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()
model_fn = 'tensorflow_inception_graph.pb'
sess = tf.InteractiveSession(graph=graph)
with tf.gfile.FastGFile(model_fn, 'rb') as f:
    graph_def = tf.GraphDef()
    graph_def.ParseFromString(f.read())
t_input = tf.placeholder(np.float32, name='input')  # define the input tensor
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)


def visstd(a, s=0.1):
    return (a - a.mean()) / max(a.std(), 1e-4) * s + 0.5


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


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)


def tffunc(*argtypes):
    placeholders = list(map(tf.placeholder, argtypes))
    def wrap(f):
        out = f(*placeholders)
        def wrapper(*args, **kw):
            return out.eval(dict(zip(placeholders, args)), session=kw.get('session'))
        return wrapper
    return wrap



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
    # 同样将图像进行金字塔分解
    # 此时提取高频、低频的方法比较简单。直接缩放就可以
    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))
            print('.', end=' ')

    img = img.clip(0, 255)
    savearray(img, 'deepdream.jpg')


if __name__ == '__main__':
    img0 = PIL.Image.open('test.jpg')
    img0 = np.float32(img0)

    name = 'mixed4d_3x3_bottleneck_pre_relu'
    #name = 'mixed5b_5x5_pre_relu'
    #name = 'mixed4c'
    channel = 139
    layer_output = graph.get_tensor_by_name("import/%s:0" % name)
    render_deepdream(layer_output[:, :, :, channel], img0)

    #name = 'mixed4c'
    #layer_output = graph.get_tensor_by_name("import/%s:0" % name)
    #render_deepdream(tf.square(layer_output), img0)

生成图像如下,怎么样,图像中确实有卷积层提取的花的纹理图案吧。

我们将卷积层换成mixed4c层,这个层提取了许多动物图案,将动物图案和我们的test.jpg相结合生成一张图像。结果如下:

3.总结

重点了解的内容:

1)deep dream的原理,以及通过deep dream来理解卷积层中提取的特征;

2)怎样处理大图片和怎样提高图像的质量,这些原理在以后的其他地方一定会用到。

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
### 回答1: DeepDream是一种基于卷积神经网络(CNN)的图像生成算法,它通过最大限度地放大和突出图像中的纹理和模式来创建视觉上令人印象深刻的效果。 DeepDream实验最初由谷歌的工程师团队开发,目的是通过调整神经网络的内部表征来探索CNN的视觉感知能力。该算法通过多次沿着梯度逆向传播过程,将原始图像输入网络并反向增加网络的激活,使网络将注意力更多地放在它认为重要的特征上。经过多次迭代,图像逐渐被改造为充满了独特纹理和特征的幻觉般的形象。 通过DeepDream实验,我们可以发现神经网络在图像识别中使用的内部表征。例如,当我们输入一张狗的照片时,DeepDream会突出给定图像中与狗相关的纹理和特征,例如狗的眼睛、耳朵和毛发。但是,DeepDream不仅仅适用于狗的图像,它可以用于任何图像,从风景照片到抽象艺术作品。 DeepDream实验展示了深度学习算法的创造力和潜力。它不仅仅用于图像生成,还可以用于图像增强和创意艺术。DeepDream的效果被广泛运用在电影、音乐视频和艺术展览中,给人们带来了视觉上的震撼和惊喜。 总的来说,DeepDream实验是一种利用神经网络调整图像表征的方法,通过突出图像的纹理和特征来产生视觉上令人印象深刻的效果。它展示了深度学习的创造力和潜力,并广泛应用于艺术和视觉媒体领域。 ### 回答2: DeepDream是一种基于人工智能的图像处理技术。该技术利用神经网络来识别和分析图像中的不同特征,并将这些特征通过算法进行处理,生成独特的图像效果。 DeepDream的实验过程可以大致分为以下几个步骤:首先,选择一张输入图像,这可以是一张普通的照片或图画;然后,通过一个已经训练好的卷积神经网络对输入图像进行多次迭代处理,来寻找图像中的模式和特征;接下来,将网络中的某些特定层运用到输入图像上,运用梯度上升算法来放大并强调这些特征;最后,将处理后的图像输出,并通过重复这一过程来不断改进结果。 DeepDream实验的独特之处在于,它不仅仅是一种图像处理技术,更是一种艺术创作的工具。通过对图像的重复处理与调整,DeepDream可以生成奇幻、幻觉般的图像效果,不仅仅是图像的艺术变现,还可以通过这一过程来探索和观察神经网络的工作方式和特性。 此外,DeepDream实验还可以应用于图像识别的改进和优化。通过这一技术,可以发现并加强神经网络对图像中的细节和特征的关注,从而提高图像识别的准确率和精度。同时,在医学图像分析、视觉艺术、图像生成等领域也有广泛的应用。 总的来说,DeepDream实验是一种将人工智能与图像处理相结合的创新技术,具有独特的艺术创作和图像识别优化的应用潜力。 ### 回答3: Deepdream是一种基于人工智能技术的图像生成实验,它源自Google开发的深度学习算法。Deepdream通过对现有图像进行多次重复改造,创造出一种另类的图像效果,以探索并揭示神经网络的工作方式。 Deepdream实验首先需要选择一个输入图像,可以是任何一张照片或图片。然后,通过预训练的神经网络模型,将这张图像输入到算法中。算法会对图像进行分析,并逐步改变图像的像素值,以便在图像中寻找和增强神经网络最敏感的特征。 在Deepdream实验中,会对图像进行多次迭代,每次迭代都会对图像进行微小调整。通过调整图像的像素值,使其与最敏感的神经网络特征更相似。经过多次迭代,图像中原本存在的部分特征会被放大和强调,最终生成出一幅视觉上令人难以置信的图像。 这种实验的结果往往呈现出千奇百怪的特效,令人惊叹不已。它可以使普通的图像转变成充满幻想和艺术感的作品。通过Deepdream实验,我们可以更好地理解和观察神经网络的工作方式,探索其内部所学到的知识,同时也能够激发创造力,提供一个新的艺术表现形式。 总而言之,Deepdream实验是一种利用深度学习算法对图像进行改造和增强的创新实践。它不仅能够改变图像的外观,还能够揭示出神经网络的内在特征,为我们了解和探索人工智能提供了更加直观和生动的方式。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值