python深度学习--DeepDream

 #DeepDream 是一种艺术性的图像修改技术,它用到了卷积神经网络学到的表示 '''

#DeepDream 算法与前面的卷积神经网络过滤器可视化技术几乎相同,都是反向运行一个cnn:对cnn的输入做梯度上升,以便将cnn靠顶部的某一层的某个过滤器激活最大化。

# 但有几个简单区别:

           1.使用 DeepDream,我们尝试将所有层的激活最大化,而不是将某一层的激活最大化,因此需要同时将大量特征的可视化混合在一起。

          2.不是从空白的、略微带有噪声的输入开始,而是从现有的图像开始,因此所产生的效果 能够抓住已经存在的视觉模式,并以某种艺术性的方式将图像元素扭曲.

         3.输入图像是在不同的尺度上[叫作八度(octave)]进行处理的,这可以提高可视化的质量。 '''

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import pylab
from pandas import DataFrame, Series
from keras import models, layers, optimizers, losses, metrics
from keras.utils.np_utils import to_categorical

plt.rcParams['font.sans-serif'] = ['SimHei']  #指定默认字体
plt.rcParams['axes.unicode_minus'] = False  #解决保存图像是负号'-'显示为方块的问题

#在实践中,人们已 经知道 Inception 能够生成漂亮的 DeepDream 图像,所以我们将使用 Keras 内置的 Inception V3 模型

#加载预训练的Inception V3模型
from keras.applications import inception_v3
from keras import backend as K
from deepdream_img_utils import preprocess_image,save_img,resize_img
# #注意检查数据类型和shape是否一致ValueError: Tensor conversion requested dtype int32 for Tensor with dtype float32: 'Tensor("strided_slice/stack_1:0", shape=(3,), dtype=float32)'

K.set_learning_phase(0)#我们不需要训练模型,所以这个命令 会禁用所有与训练有关的操作
model=inception_v3.InceptionV3(
    weights='imagenet',#使用预训练的 ImageNet权重来加载模型
    include_top=False)#构建不包括全连接层的 Inception V3网络。
#计算损失(loss),即在梯度上升过程中需要最大化的量。
model.summary()
'''
前面写道的过滤器可视化中,我们试图将某一层的某个过滤器的值最大化。
这里,我们要将多个层的所有过滤器的激活同时最大化。具体来说,就是对一组靠近顶部的层激活的 L2 范数进行加权求和,然后将其最大化。
    选择哪些层(以及它们对最终损失的贡献)对生成的可视化结果具有很大影响, 所以我们希望让这些参数变得易于配置。更靠近底部的层生成的是几何图案,而更靠近顶部的层生成的则是从中能够看出某些 ImageNet 类别(比如鸟或狗)的图案。
    我们将随意选择 4 层的 配置,但你以后一定要探索多个不同的配置。
'''
#设置DeepDream配置
layer_contributions={
    # 'mixed2':0.2,
    'mixed3':3.,
    'mixed4':2.,
    'mixed5':1.5,
    'mixed7':1.,
    'mixed9':0.5,
}#根据model.summary()得到对应的层的名称,然后赋予相应的权重

#定义需要最大化的损失:上面配置的层激活的L2范数的加权求和
layer_dict=dict([(layer.name,layer) for layer in model.layers])
loss=K.variable(0.)#在定义损失时将层的贡献添加到这个标量变量中
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'))#K.prod()将张量中的值沿着指定的轴相乘
    loss+=coeff*K.sum(K.square(activation[:,2:-2,2:-2,:]))/scaling#将该层特征的L2范数添加到loss中。 为了避免出现边界伪影,损失中仅包含非边界的像素

#梯度上升过程

dream=model.input
grads=K.gradients(loss,dream)[0]
grads/=K.maximum(K.mean(K.abs(grads)),1e-7)#梯度标准化
outputs=[loss,grads]
fetch_loss_and_grads=K.function([dream],outputs)#给定一张输出图像,设置 一个 Keras 函数来获取损失值和梯度值
def eval_loss_and_grads(x):
    outs=fetch_loss_and_grads([x])
    loss_value,grad_value=outs[0],outs[1]
    return loss_value,grad_value

def gradient_ascent(x,iterations,step,max_loss=None):
    for i in range(iterations):
        loss_value, grad_values = eval_loss_and_grads(x)
        if max_loss is not None and loss_value > max_loss:
            break
        print('...Loss value at', i, ':', loss_value)
        x += step * grad_values
    return x

#DeepDream算法
'''
    首先,我们来定义一个列表,里面包含的是处理图像的尺度(也叫八度)。每个连续的尺度都是前一个的 1.4 倍(放大 40%),即首先处理小图像,然 后逐渐增大图像尺寸.
    对于每个连续的尺度,从最小到最大,我们都需要在当前尺度运行梯度上升,以便将之前 定义的损失最大化。每次运行完梯度上升之后,将得到的图像放大 40%。
    在每次连续的放大之后(图像会变得模糊或像素化),为避免丢失大量图像细节:每次放大之后,将丢失的细节重新注入到图像中.
    因为我们知道原始图像放大到这个尺寸应该是什么样子。给定一个较小的图像尺寸S和一个较大的图像尺寸 L,你可以计算将原始图像大小调整为L与将原始图像大小调整为S之间的区别,这个区别可以定量描述从S到L的细节损失
'''

#在多个连续尺度上运行梯度上升
step=0.01#梯度上升学习率
num_octave=3#空间处理尺度(八度)的连续放大次数
octave_scale=1.4
iterations=20
max_loss=10.
base_image_path='datasets/timg.jpg'
img=preprocess_image(base_image_path)#(1, height, width, 3)

original_shape=img.shape[1:3]#图片尺寸
print(original_shape)#(326, 490)
successive_shapes=[original_shape]

for i in range(1,num_octave):#连续2个八度
    shape=tuple([int(dim/(octave_scale**i)) for dim in original_shape])#缩小图像尺寸1.4倍
    print(shape)
    successive_shapes.append(shape)
# print(successive_shapes)#[(326, 490), (232, 350), (166, 250)]
successive_shapes=successive_shapes[::-1]#将形状列表反转,变为升序
print(successive_shapes)
original_img=np.copy(img)
shrunk_original_img=resize_img(img,successive_shapes[0])#将原始图像 Numpy 数组的大小缩放到最小尺寸
for shape in successive_shapes:
    print('Processing image shape', shape)
    img=resize_img(img,shape)#将梦境图连续放大
    img=gradient_ascent(img,iterations=iterations,step=step,max_loss=max_loss)#梯度上升,改变梦境图像

    upscaled_shrunk_original_img=resize_img(shrunk_original_img,shape)#将原始图像的缩小版放大,它会变得像素化
    same_size_original=resize_img(original_img,shape)#同shape原始图像的高质量版本
    lost_detail=same_size_original-upscaled_shrunk_original_img#二者差值作为丢失的细节,重新注入到梦境中
    img+=lost_detail
    shrunk_original_img=resize_img(original_img,shape)#更新(当前尺度)尺寸
    save_img(img,fname='datasets/dream_at_scale_'+str(shape)+'.png')#保存当前尺度梦境图像
save_img(img,fname='datasets/final_dream.png')#保存连续三次放大尺度的图像

    ------------>>>>>>生成的图                

 DeepDream过程图示:

#因为原始 Inception V3 网络训练识别尺寸为 299×299 的图像中的概念,而上述过程中将 图像尺寸减小很多,所以 DeepDream 实现在尺寸介于 300×300 和 400×400 之间的图像 上能够得到更好的结果。但不管怎样,你都可以在任何尺寸和任何比例的图像上运行同样的代码

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章