TensorFlow笔记--Deep Dream模型(上)

简介: TensorFlow学习笔记--Deep Dream模型

零、目标

Deep Dream是谷歌推出的一个有意思的技术。在训练好的CNN上,设定几个参数就可以生成一张图象。具体目标是:


了解Deep Dream基本原理

掌握实现生成Deep Dream 模型

一、技术原理

在卷积网络中,通常输入的是一张图象,经过若干层的卷积运算,最终输出图像的类别。这期间使用到了图片计算梯度,网络根据梯度不断的调整和学习最佳的参数。但是卷积层究竟学习到了什么,卷积层的参数代表了什么,浅层卷积和深层卷积学习到的内容有哪些区别,这些问题Deep Dream可以解答。

假设输入网络的图像为X,网络输出的各个类别的概率为t(t是一个多维向量,代表了多种类别的概率)。设定t[N]为优化目标,不断的让神经网络去调整输入图像X的像素值,让输出t[N]尽可能的大,最后极大化第N类别的概率得到图片。

关于卷积层究竟学到了什么,只需要最大化卷积层的某一个通道数据就可以了。折输入的图像为X,中间某个卷积层的输出是Y,Y的形状是hwc,其中h为Y的高度,w为Y的宽度,c为通道数。卷积的一个通道就可以代表一种学习到的信息。以某一个通道的平均值作为优化目标,就可以弄清楚这个通道究竟学习到了什么,这也是Deep Dream的基本原理。


二、在TensorFlow中使用

1.导入Inception模型

原始的Deep Dream 模型只需要优化ImageNet 模型卷积层某个通道的激活值就可以。因此,应该先导入ImageNet图像识别模型,这里以 Inception 为例。创建 load_inception.py 文件,输入如下代码:

# 导入基本模块
import numpy as np
import tensorflow as tf
# 创建图和会话
graph = tf.Graph()
sess = tf.InteractiveSession(graph=graph)
# 导入Inception模型
# tensorflow_inception_graph.pb 文件存储了inception的网络结构和对应的数据
model_fn = 'tensorflow_inception_graph.pb'
with tf.gfile.FastGFile(model_fn, 'rb') as f:
    graph_def = tf.GraphDef()
    graph_def.ParseFromString(f.read())
# 导入的时候需要给网络制定一个输入图像,因此定义一个t_input作为占位符
# 需要注意的是,使用的图像数据通常的格式为:(height,width,channel),
# 其中height为图像的像素高度,width为图像的像素宽度,chaneel为图像的通道数,一般使用RGB图像,所以通道数为3
t_input = tf.placeholder(np.float32, name='input')
imagenet_mean = 117.0
# 处理输入图像
# 虽然图像的格式是(height,width,channel),但是Inception模型所需的输入格式是(batch,height,width,channel)
# 这是因为(height,width,channel)只能表示一张图片,但在训练神经网络时往往需要多张图片
# 因此在前面加了一维,让输入的图片符合Inception需要的格式
# 尽管这里一次只需要输入一张图片,但是同样也需要将数据变为Inception所需的格式,只不过这里的batch等于1
# 对图像减去一个像素均值
# 原因是在训练Inception 模型的时候,已经做了减去均值的预处理,因此这里使用同样的方法处理,才能保持输入一致
# t_input-imagenet_mean 减去均值,这里使用的Inception模型减去的是一个固定均值117,所以这里也减去117
# expand_dims 执行加一维操作,从[height,width,channel] 变为[1,height,width,channel]
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))
# 输出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())))

这段代码运行后,会输出卷积层总数是59个


注1:

在输出卷积层“mixed4d_3x3_bottleneck_pre_relu”的形状时,输出的结果是(?,?,?,144),原因是此时还不清楚输入图像的个数以及大小,所以前三维的值不确定


2. 生成原始图像
以 mixed4d_3x3_bottleneck_pre_relu 卷积层为例,最大化它的某一个通道的平均值,以达到生成图像的目的。
创建 gen_naive.py 文件,导入Inception模型,导入方法同上节。首先定义保存图片的函数:

def savearray(img_array, img_name):
    scipy.misc.toimage(img_array).save(img_name)
    print('img saved : %s' % img_name)

接着创建程序的主要部分:

# 定义卷积层、通道数,并去除对应的Tensor
name = 'mixed4d_3x3_bottleneck_pre_relu'
# 选择任意的通道,这里是139
channel = 139
# 取出 mixed4d_3x3_bottleneck_pre_relu 卷积层的输出层
layer_output = graph.get_tensor_by_name("import/%s:0" % name)
# 定义原始的图像噪声
# 他是一个形状为(224,224,3)的张量,表示初始化图像优化起点
img_noise = np.random.uniform(size=(224, 224, 3)) + 100.0
# 调用 render_navie 函数渲染
render_naive(layer_output[:, :, :, channel], img_noise, iter_n=20)

最后定义渲染函数

def render_naive(t_obj, img0, iter_n=20, step=1.0):
    '''
    渲染函数
    :param t_obj:卷积层某个通道的值
    :param img0:初始化图像
    :param iter_n:迭代的步数
    :param step:
    :return:
    '''
    # t_score 是优化目标。他是t_obj的平均值
    # t_score 越大,就说明神经网络卷积层对应的通道的平均激活越大
    t_score = tf.reduce_mean(t_obj)
    # 计算t_score对t_input的梯度
    # 代码的目标是通过调整输入图像 t_input ,来让 t_score 尽可能的大
    # 因此使用体服下降法
    t_grad = tf.gradients(t_score, t_input)[0]
    # 创建新图
    img = img0.copy()
    # 迭代 iter_n 每一步都将梯度应用到图像上
    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, 'navie.jpg')

运行程序后,将得到20次迭代后的图像,如下图

image.png

3.生成大尺寸图片

上节生成的图片尺寸太小,这节通过代码,将生成的大尺寸的图片。上节中传递图片尺寸的参数是 img_noise ,如果 img_noise 传递更大的值,那么生成的图片尺寸就会更大。但是这样就出现一个问题,生成图片的过程是需要消耗内存/显存的,img_noise 传递的尺寸越大,消耗的内存/显存就越多,最终会因为内存/显存不足,导致渲染失败。如何解决这个问题呢,其实很简单,每次不对整张图片做优化,而是把图片分为几个部分,每次只对一部分做优化,这样消耗的内存/显存就是固定大小的。

新建 gen_multiscale.py 文件,写入如下代码,这个函数可以对任意大小的图像进行提督计算:

def calc_grad_tiled(img, t_grad, title_size=512):
    '''
    对任意大小的图像计算梯度
    :param img:
    :param t_grad:
    :param title_size:每次优化的大小
    :return:
    '''
    # 每次只对title_size*title_size大小的图像计算梯度
    sz = title_size
    h, w = img.shape[:2]
    # 如果直接计算梯度,在每个 title_size * title_size 的边缘会出现比较明显的边缘效应,影响美观
    # 解决的办法是:生成两个随机数 sx、sy,对图片进行整体移动
    # img_shift 先在行上做整体移动,再在列上做整体移动
    # 防止出现边缘效应
    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的大小是title_size*title_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)

为了加快图像的收敛速度,可以采用先生成小尺寸,再将图片放大:

# 将图片放大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))
    # 使用完 scipy.misc.imresize 函数后,将像素缩放回去
    img = img / 255 * (max - min) + min
    return img
# 生成大尺寸图片
def render_multiscale(t_obj, img0, iter_n=10, step=1.0, octave_n=3, octave_scale=1.4):
    '''
    生成大尺寸图片
    :param t_obj:
    :param img0:
    :param iter_n:
    :param step:
    :param octave_n:放大次数
    :param octave_scale:放大倍数
    :return:
    '''
    # 同样定义目标梯度
    t_score = tf.reduce_mean(t_obj)
    t_grad = tf.gradients(t_score, t_input)[0]
    img = img0.copy()
    # 先生成小尺寸图像
    # 然后调用 resize_ratio 将小尺寸图像放大 octave_scale 倍
    # 再使用放大后的图像作为初始值进行计算
    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):
            # 计算任意大小图像的梯度
            g = calc_grad_tiled(img, t_grad)
            g /= g.std() + 1e-8
            img += g * step
            print('.', end=' ')
    savearray(img, 'multiscale.jpg')
目录
相关文章
|
1月前
|
机器学习/深度学习 TensorFlow 算法框架/工具
深度学习之格式转换笔记(三):keras(.hdf5)模型转TensorFlow(.pb) 转TensorRT(.uff)格式
将Keras训练好的.hdf5模型转换为TensorFlow的.pb模型,然后再转换为TensorRT支持的.uff格式,并提供了转换代码和测试步骤。
82 3
深度学习之格式转换笔记(三):keras(.hdf5)模型转TensorFlow(.pb) 转TensorRT(.uff)格式
|
1月前
|
并行计算 PyTorch TensorFlow
Ubuntu安装笔记(一):安装显卡驱动、cuda/cudnn、Anaconda、Pytorch、Tensorflow、Opencv、Visdom、FFMPEG、卸载一些不必要的预装软件
这篇文章是关于如何在Ubuntu操作系统上安装显卡驱动、CUDA、CUDNN、Anaconda、PyTorch、TensorFlow、OpenCV、FFMPEG以及卸载不必要的预装软件的详细指南。
3307 3
|
4天前
|
机器学习/深度学习 人工智能 算法
【手写数字识别】Python+深度学习+机器学习+人工智能+TensorFlow+算法模型
手写数字识别系统,使用Python作为主要开发语言,基于深度学习TensorFlow框架,搭建卷积神经网络算法。并通过对数据集进行训练,最后得到一个识别精度较高的模型。并基于Flask框架,开发网页端操作平台,实现用户上传一张图片识别其名称。
21 0
【手写数字识别】Python+深度学习+机器学习+人工智能+TensorFlow+算法模型
|
4天前
|
机器学习/深度学习 人工智能 算法
基于深度学习的【蔬菜识别】系统实现~Python+人工智能+TensorFlow+算法模型
蔬菜识别系统,本系统使用Python作为主要编程语言,通过收集了8种常见的蔬菜图像数据集('土豆', '大白菜', '大葱', '莲藕', '菠菜', '西红柿', '韭菜', '黄瓜'),然后基于TensorFlow搭建卷积神经网络算法模型,通过多轮迭代训练最后得到一个识别精度较高的模型文件。在使用Django开发web网页端操作界面,实现用户上传一张蔬菜图片识别其名称。
22 0
基于深度学习的【蔬菜识别】系统实现~Python+人工智能+TensorFlow+算法模型
|
21天前
|
机器学习/深度学习 人工智能 算法
【车辆车型识别】Python+卷积神经网络算法+深度学习+人工智能+TensorFlow+算法模型
车辆车型识别,使用Python作为主要编程语言,通过收集多种车辆车型图像数据集,然后基于TensorFlow搭建卷积网络算法模型,并对数据集进行训练,最后得到一个识别精度较高的模型文件。再基于Django搭建web网页端操作界面,实现用户上传一张车辆图片识别其类型。
65 0
【车辆车型识别】Python+卷积神经网络算法+深度学习+人工智能+TensorFlow+算法模型
|
2月前
|
机器学习/深度学习 人工智能 算法
鸟类识别系统Python+卷积神经网络算法+深度学习+人工智能+TensorFlow+ResNet50算法模型+图像识别
鸟类识别系统。本系统采用Python作为主要开发语言,通过使用加利福利亚大学开源的200种鸟类图像作为数据集。使用TensorFlow搭建ResNet50卷积神经网络算法模型,然后进行模型的迭代训练,得到一个识别精度较高的模型,然后在保存为本地的H5格式文件。在使用Django开发Web网页端操作界面,实现用户上传一张鸟类图像,识别其名称。
108 12
鸟类识别系统Python+卷积神经网络算法+深度学习+人工智能+TensorFlow+ResNet50算法模型+图像识别
|
1月前
|
机器学习/深度学习 移动开发 TensorFlow
深度学习之格式转换笔记(四):Keras(.h5)模型转化为TensorFlow(.pb)模型
本文介绍了如何使用Python脚本将Keras模型转换为TensorFlow的.pb格式模型,包括加载模型、重命名输出节点和量化等步骤,以便在TensorFlow中进行部署和推理。
76 0
|
3月前
|
API UED 开发者
如何在Uno Platform中轻松实现流畅动画效果——从基础到优化,全方位打造用户友好的动态交互体验!
【8月更文挑战第31天】在开发跨平台应用时,确保用户界面流畅且具吸引力至关重要。Uno Platform 作为多端统一的开发框架,不仅支持跨系统应用开发,还能通过优化实现流畅动画,增强用户体验。本文探讨了Uno Platform中实现流畅动画的多个方面,包括动画基础、性能优化、实践技巧及问题排查,帮助开发者掌握具体优化策略,提升应用质量与用户满意度。通过合理利用故事板、减少布局复杂性、使用硬件加速等技术,结合异步方法与预设缓存技巧,开发者能够创建美观且流畅的动画效果。
79 0
|
3月前
|
C# 开发者 前端开发
揭秘混合开发新趋势:Uno Platform携手Blazor,教你一步到位实现跨平台应用,代码复用不再是梦!
【8月更文挑战第31天】随着前端技术的发展,混合开发日益受到开发者青睐。本文详述了如何结合.NET生态下的两大框架——Uno Platform与Blazor,进行高效混合开发。Uno Platform基于WebAssembly和WebGL技术,支持跨平台应用构建;Blazor则让C#成为可能的前端开发语言,实现了客户端与服务器端逻辑共享。二者结合不仅提升了代码复用率与跨平台能力,还简化了项目维护并增强了Web应用性能。文中提供了从环境搭建到示例代码的具体步骤,并展示了如何创建一个简单的计数器应用,帮助读者快速上手混合开发。
83 0
|
3月前
|
开发者 算法 虚拟化
惊爆!Uno Platform 调试与性能分析终极攻略,从工具运用到代码优化,带你攻克开发难题成就完美应用
【8月更文挑战第31天】在 Uno Platform 中,调试可通过 Visual Studio 设置断点和逐步执行代码实现,同时浏览器开发者工具有助于 Web 版本调试。性能分析则利用 Visual Studio 的性能分析器检查 CPU 和内存使用情况,还可通过记录时间戳进行简单分析。优化性能涉及代码逻辑优化、资源管理和用户界面简化,综合利用平台提供的工具和技术,确保应用高效稳定运行。
83 0

热门文章

最新文章