keras深度学习实战(20)——deepdream模型详解(代码片段)

盼小辉丶 盼小辉丶     2022-12-02     304

关键词:

Keras深度学习实战(20)——DeepDream模型详解

0. 前言

《对抗样本生成》一节中,我们通过略微修改输入图像的像素值以改变模型对图像类别的预测。在本节中,我们同样对输入图像略微进行一些修改,但并不以改变图像的标签为目标,本节的目标是令修改后的图像比原始图像更具艺术感,而且能够帮助我们理解卷积神经网络背后的机制。同时,本节所介绍算法也是我们之后将要介绍的神经风格迁移技术的核心。

1. DeepDream 的技术原理

首先,我们先了解 DeepDream 的技术原理。在图像识别相关博文中,我们学习了如何利用卷积神经网络进行图像识别,利用若干卷积操作处理输入图像,输入图像类别标签。在模型训练阶段,使用大量训练图像计算梯度信息,网络根据梯度信息调整和学习最佳参数。
《对抗攻击》中,我们知道,如果想让一张图像被判断为某一指定类别,可以将输出概率作为优化目标,不断调整输入图像的像素值,让指定类别的输出概率尽可能大。类似的,假设我们想知道神经网络中间的卷积层究竟学到了什么,只需要最大化卷积层某一通道的输出,由于在大多数卷积层中都包含多个通道,因此卷积的一个通道就可以代表一种学习到的“信息”。以某个通道的值作为优化目标,就可以明白这个通道究竟学习到了什么,这也就是 DeepDream 的基本原理。
我们通过预训练的模型传递图像,并使用我们希望获得激活的神经网络层。神经网络会调整输入像素值,直到令所选网络层的激活值最大。同时,我们还需要确保激活的最大值不超过设定的阈值,因为我们不希望生成的图像与原始图像有巨大差异。

2. DeepDream 模型分析

DeepDream 有了简单的了解后,接下来,我们制定实现 DeepDream 算法的策略:

  • 选择需要最大化激活的神经网络层,并给这些网络层分配更大的权重以增加它们在总损失中的比重
  • 提取给定神经网络层得到的图像特征,并计算每一层的损失值:
    • 当该层中图像输出的平方和最高时,该图像在该层的激活值最大
    • 提取输入像素值相对于损失的梯度变化
  • 根据提取的梯度变化更新输入图像像素值
  • 为更新的输入图像像素值计算所有选定网络层上的损失值,即网络层激活值的平方和
  • 如果损失值大于预定义的阈值,则停止更新图像

3. DeepDream 算法实现

在本节中,我们使用 keras 实现 DeepDream 算法,生成更具艺术风格的图像。

3.1 数据加载与预处理

导入相关的库,并加载图片:

from keras import backend as K
from keras.applications.vgg19 import VGG19
from keras.preprocessing import image
import matplotlib.pyplot as plt
import numpy as np
import cv2
from PIL import Image

file_path = '5.png'
img_nrows = 224
img_ncols = 224
original_shape = cv2.imread(file_path).shape

同样与对抗样本生成一样,如果使用 TensorFlow2 作为 Keras 的后端,需要在代码开头加上以下代码,切换梯度求解的执行模型:

import tensorflow as tf
tf.compat.v1.disable_eager_execution()

定义图像预处理函数,以便随后可以将其传递给 VGG19 模型:

def preprocess_image(image_path):
    img = image.load_img(image_path, target_size=(img_nrows, img_ncols))
    img = image.img_to_array(img)
    # 维度扩展
    img = np.expand_dims(img, axis=0)
    # 数据预处理
    img[:, :, :, 0] -= 103.939
    img[:, :, :, 1] -= 116.779
    img[:, :, :, 2] -= 123.68
    img = img[:, :, :, ::-1] / 255
    return img

构建一个对处理后的图像进行逆操作的函数,以进行可视化:

def deprocess_image(x):
    x = x[:, :, :, ::-1] * 225
    x[:, :, :, 0] += 103.939
    x[:, :, :, 1] += 116.779
    x[:, :, :, 2] += 123.68
    x = np.clip(x, 0, 255).astype('uint8')[0]
    x = Image.fromarray(x).resize((original_shape[1], original_shape[0]))
    return x

使用以上预处理函数 preprocess_image,预处理图像,并加载预训练的 VGG19 模型:

img = preprocess_image(file_path)
model = VGG19(include_top=False, weights='imagenet')

3.2 DeepDream 生成模型

定义用于总损失值计算的神经网络层,使用第 2 个和第 5 个池化层用于总损失的计算,并为它们分配权重,使不同层将对总损失值具有不同贡献,可以使用其他的网络层和权重组合,生成不同图片:

layer_contributions = 
    'block2_pool':0.5,
    'block5_pool': 1.2

初始化损失函数以及模型中各个网络层的字典:

layer_dict = dict([(layer.name, layer) for layer in model.layers])
loss = K.variable(0.)

计算激活的总损失值,遍历选定用于计算激活的网络层 (layer_contributions),并记录分配给每个网络层的权重 (coeff)。另外,我们计算选定神经网络层的输出 (activation),并在缩放后使用激活值的平方和来更新损失值:

for layer_name in layer_contributions:
    coeff = layer_contributions[layer_name]
    activation = layer_dict[layer_name].output
    scaling = K.prod(K.cast(K.shape(activation), 'float32'))
    loss = loss + coeff * K.sum(K.square(activation)) / scaling
    print(loss)

初始化梯度值,使用 K.gradients 方法可以用于计算损失相对于输入 dream 的梯度变化:

dream = model.input
grads = K.gradients(loss, dream)[0]
print(dream, grads)

标准化梯度值,以使梯度的变化更加平缓:

grads /= K.maximum(K.mean(K.abs(grads)), 1e-7)

创建函数,将输入图像 dream 映射到损失值和损失值相对于输入像素值的梯度变化:

outputs = [loss, grads]

fetch_loss_and_grads = K.function([dream], outputs)

定义函数 eval_loss_and_grads,使用 fetch_loss_and_grads 函数计算输入图像的损失和梯度变化,并返回:

def eval_loss_and_grads(img):
    outs = fetch_loss_and_grads([img])
    loss_value = outs[0]
    grad_values = outs[1]
    return loss_value, grad_values

多次迭代计算的损失和梯度变化更新原始图像,我们循环遍历图像 100 次,首先定义更改学习率以及最大的损失上限,即图像修改的上限:

for i in range(100):
    learning_rate = 0.01
    max_loss = 30

接下来,计算图像的损失和梯度变化值,如果损失值大于定义的阈值,则停止修改图像:

    loss_value, grad_values = eval_loss_and_grads(img)
    if max_loss is not None and loss_value > max_loss:
        print(loss_value)
        break
    print('...Loss value at', i, ':', loss_value)

基于梯度变化修改图像,并对图像进行逆向处理并进行可视化:

    img += learning_rate * grad_values
    img2 = deprocess_image(img.copy())
    plt.imshow(img2)
    plt.axis('off')
    plt.show()

代码生成的最终图像如下所示:

从上图可以看到,图像中的包含波浪形的模式,这些模式是由于令各个网络层的激活最大化的结果。

小结

DeepDream 利用训练完成的深度卷积神经网络,仅需要优化模型卷积层某个通道的激活值即可生成令人印象深刻的图像。本节首先介绍了 DeepDream 的基本原理,并使用 Keras 实现了 DeepDream 生成模型,不仅能够生成富有艺术感的图像,同时加深对卷积神经网络的背后运行机制的理解。

系列链接

Keras深度学习实战(1)——神经网络基础与模型训练过程详解
Keras深度学习实战(2)——使用Keras构建神经网络
Keras深度学习实战(3)——神经网络性能优化技术
Keras深度学习实战(4)——深度学习中常用激活函数和损失函数详解
Keras深度学习实战(5)——批归一化详解
Keras深度学习实战(6)——深度学习过拟合问题及解决方法
Keras深度学习实战(7)——卷积神经网络详解与实现
Keras深度学习实战(8)——使用数据增强提高神经网络性能
Keras深度学习实战(9)——卷积神经网络的局限性
Keras深度学习实战(10)——迁移学习详解
Keras深度学习实战(11)——可视化神经网络中间层输出
Keras深度学习实战(12)——面部特征点检测
Keras深度学习实战(13)——目标检测基础详解
Keras深度学习实战(14)——从零开始实现R-CNN目标检测
Keras深度学习实战(15)——从零开始实现YOLO目标检测
Keras深度学习实战(16)——自编码器详解
Keras深度学习实战(17)——使用U-Net架构进行图像分割
Keras深度学习实战(18)——语义分割详解
Keras深度学习实战(19)——使用对抗攻击生成可欺骗神经网络的图像

keras深度学习实战(10)——迁移学习(代码片段)

Keras深度学习实战(10)——迁移学习0.前言1.迁移学习1.1迁移学习原理1.2ImageNet数据集介绍2.利用预训练VGG16模型进行性别分类2.1VGG16架构2.2微调模型2.3错误分类的图片示例小结系列链接0.前言在《卷积神经网络的局限性》... 查看详情

学习keras:《keras快速上手基于python的深度学习实战》pdf代码+mobi

...部分可以作为入门人的参考。《Keras快速上手基于Python的深度学习实战》系统地讲解了深度学习的基本知识、建模过程和应用,并以深度学习在推荐系统、图像识别、自然语言处理、文字生成和时间序列中的具体应用为案例,详... 查看详情

keras深度学习实战(42)——强化学习基础(代码片段)

Keras深度学习实战(42)——强化学习基础0.前言1.强化学习基础1.1基本概念1.2马尔科夫决策过程1.3目标函数2.在具有非负奖励的模拟游戏中获取最佳动作2.1问题设定2.2模型分析2.3模型构建与训练3.在模拟游戏中获取最佳动... 查看详情

keras深度学习实战(26)——文档向量详解(代码片段)

Keras深度学习实战(26)——文档向量详解0.前言1.文档向量基本概念2.神经网络模型与数据集分析2.1模型分析2.2数据集介绍3.利用Keras构建神经网络模型生成文档向量小结系列链接0.前言在《从零开始构建单词向量》一节中,我们... 查看详情

keras深度学习实战(41)——语音识别(代码片段)

Keras深度学习实战(41)——语音识别0.前言1.模型与数据集分析1.1数据集分析1.2模型分析2.语音识别模型2.1数据加载与预处理2.2模型构建与训练小结系列链接0.前言语音识别(AutomaticSpeechRecognition,ASR,或称语音转录文本)... 查看详情

keras入门实战:手写数字识别

近些年由于理论知识的硬件的快速发展,使得深度学习达到了空前的火热。深度学习已经在很多方面都成功得到了应用,尤其是在图像识别和分类领域,机器识别图像的能力甚至超过了人类。本文用深度学习Python库Keras实现深度... 查看详情

keras深度学习实战(23)——dcgan详解与实现(代码片段)

Keras深度学习实战(23)——DCGAN详解与实现0.前言1.使用DCGAN生成手写数字图像2.使用DCGAN生成面部图像2.1模型分析2.2从零开始实现DCGAN生成面部图像小结系列链接0.前言在生成对抗网络(GenerativeAdversarialNetworks,GAN)一节中,我们使用... 查看详情

keras深度学习实战(37)——手写文字识别(代码片段)

Keras深度学习实战(37)——手写文字识别0.前言1.手写文字识别相关背景1.1Connectionisttemporalclassification(CTC)1.2解码CTC1.3计算CTC损失值2.模型与数据集分析2.1数据集分析2.2模型分析3.实现手写文字识别模型3.1数据集加载与预处... 查看详情

keras深度学习实战——使用fasttext模型构建单词向量(代码片段)

Keras深度学习实战——使用fastText模型构建单词向量0.前言1.fastText算法模型2.模型与数据集分析2.1fastText模型分析2.2数据集分析3.使用Keras实现fastText生成单词向量相关链接0.前言fastText是另一种用于生成单词向量的神经网络模型,其... 查看详情

keras深度学习实战——新闻文本分类(代码片段)

Keras深度学习实战(9)——新闻文本分类0.前言1.新闻文本分类任务与神经网络模型分析1.1数据集1.2神经网络模型2.使用神经网络进行新闻文本分类小结系列链接0.前言在先前的应用实战中,我们分析了结构化的数据集&... 查看详情

keras深度学习实战——使用glove模型构建单词向量(代码片段)

Keras深度学习实战——使用GloVe模型构建单词向量0.前言1.GloVe算法模型1.1模型目标1.2GloVe算法计算细节3.实现GloVe模型构建单词向量3.1数据集3.2模型实现相关链接0.前言在《使用fastText模型构建单词向量》一节中,我们学习了如何构... 查看详情

keras深度学习实战(23)——dcgan详解与实现(代码片段)

Keras深度学习实战(23)——DCGAN详解与实现0.前言1.使用DCGAN生成手写数字图像2.使用DCGAN生成面部图像2.1模型分析2.2从零开始实现DCGAN生成面部图像小结系列链接0.前言在生成对抗网络(GenerativeAdversarialNetworks,GAN)一节中,... 查看详情

keras深度学习实战(13)——目标检测基础详解(代码片段)

Keras深度学习实战(13)——目标检测基础详解0.前言1.目标检测概念2.创建自定义目标检测数据集2.1windows2.2Ubuntu2.3MacOS3.使用选择性搜索在图像内生成候选区域3.1候选区域3.2选择性搜索3.3使用选择性搜索生成候选区域4.交并... 查看详情

keras深度学习实战(39)——音乐音频分类(代码片段)

Keras深度学习实战(39)——音乐音频分类0.前言1.数据集与模型分析1.1数据集分析1.2模型分析2.歌曲流派分类模型2.1数据加载与预处理2.2模型构建与训练3.聚类分析小结系列链接0.前言音乐音频分类技术能够基于音乐内容为... 查看详情

keras深度学习实战——使用fasttext模型构建单词向量(代码片段)

Keras深度学习实战——使用fastText模型构建单词向量0.前言1.fastText算法模型2.模型与数据集分析2.1fastText模型分析2.2数据集分析3.使用Keras实现fastText生成单词向量相关链接0.前言fastText是另一种用于生成单词向量的神经网络模型࿰... 查看详情

keras深度学习实战(18)——语义分割详解(代码片段)

Keras深度学习实战(18)——语义分割详解0.前言1.语义分割基本概念2.模型与数据集分析2.1模型训练流程2.2模型输出3.实现语义分割模型3.1加载数据集3.2模型构建与训练小结系列链接0.前言在《使用U-Net架构进行图像分割》... 查看详情

keras深度学习实战——使用glove模型构建单词向量(代码片段)

Keras深度学习实战——使用GloVe模型构建单词向量0.前言1.GloVe算法模型1.1模型目标1.2GloVe算法计算细节3.实现GloVe模型构建单词向量3.1数据集3.2模型实现相关链接0.前言在《使用fastText模型构建单词向量》一节中,我们学习了如... 查看详情

深度学习实战keras构建cnn神经网络完成cifar100类别分类(代码片段)

Keras构建CNN神经网络完成CIFAR100类别分类1.CIFAR100数据集介绍2.API使用3.步骤分析以及代码实现(缩减版LeNet5)4.完整代码1.CIFAR100数据集介绍这个数据集就像CIFAR-10,除了它有100个类,每个类包含600个图像。,每类各有500个... 查看详情