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 之間的圖像 上能夠得到更好的結果。但不管怎樣,你都可以在任何尺寸和任何比例的圖像上運行同樣的代碼

 

 

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