[譯] TensorFlow 教程 #14 – DeepDream

thrillerist發表於2019-03-04

本文主要實現了DeepDream演算法。

另外,在原文中每次迭代都列印出輸入影像以及新增梯度後的影像。為了閱讀體驗,本文每次迭代只列印一張影像。另外github上傳檔案的大小限制在25M,因此python notebook中也沒有顯示出所有的輸出結果,完整的輸出要執行notebook才能看到。

01 – 簡單線性模型 | 02 – 卷積神經網路 | 03 – PrettyTensor | 04 – 儲存& 恢復
05 – 整合學習 | 06 – CIFAR 10 | 07 – Inception 模型 | 08 – 遷移學習
09 – 視訊資料 | 11 – 對抗樣本 | 12 – MNIST的對抗噪聲 | 13 – 視覺化分析

by Magnus Erik Hvass Pedersen / GitHub / Videos on YouTube
中文翻譯 thrillerist / Github

如有轉載,請附上本文連結。


介紹

在上一篇教程中,我們看到了如何用神經網路的梯度來生成影像。教程#11和#12展示瞭如何用梯度來生成對抗噪聲。教程#13展示了怎麼用梯度來生成神經網路內部特徵所響應的影像。

本文會使用一個與之前類似的方法。現在我們會用神經網路的梯度來放大輸入影像中的圖案(patterns)。這個通常稱為DeepDream演算法,但這個技術實際上有許多不同的變體。

本文基於之前的教程。你需要大概地熟悉神經網路(詳見教程 #01和 #02)。

流程圖

下面的流程圖粗略展示了DeepDream演算法的想法。我們使用的是Inception模型,它的層次要比這邊顯示的更多。我們使用TensorFlow自動匯出網路中一個給定層相對於輸入影像的梯度。然後用梯度來更新輸入影像。這個過程重複多次,直到出現圖案並且我們對所得到的影像滿意為止。

這裡的原理就是,神經網路在影像中看到一些圖案的痕跡,然後我們只是用梯度把它放大了。

這裡沒有顯示DeepDream演算法的一些細節,例如梯度被平滑了,後面會討論它的一些優點。梯度也是分塊計算的,因此它可以在高解析度的影像上工作,而不會耗盡計算機記憶體。

from IPython.display import Image, display
Image(`images/14_deepdream_flowchart.png`)複製程式碼

遞迴優化

Inception模型是在相當低解析度的影像上進行訓練的,大概200-300畫素。所以,當我們使用更大解析度的影像時,DeepDream演算法會在影像中建立許多小的圖案。

一個解決方案是將輸入影像縮小到200-300畫素。但是這麼低的解析度(的結果)是畫素化而且醜陋的。

另一個解決方案是多次縮小原始影像,在每個較小的影像上執行DeepDream演算法。這樣會在影像中建立更大的圖案,然後以更高的解析度進行改善。

這個流程圖粗略顯示了這個想法。演算法遞迴地實現並且支援任何數量的縮小級別。演算法有些細節並未在這裡展示,比如,影像在縮小之前會做一些模糊處理,並且原始影像只是與DeepDream影像混合在一起,來增加一些原始的細節。

Image(`images/14_deepdream_recursive_flowchart.png`)複製程式碼

匯入

%matplotlib inline
import matplotlib.pyplot as plt
import tensorflow as tf
import numpy as np
import random
import math

# Image manipulation.
import PIL.Image
from scipy.ndimage.filters import gaussian_filter複製程式碼

使用Python3.5.2(Anaconda)開發,TensorFlow版本是:

tf.__version__複製程式碼

`1.1.0`

Inception 模型

前面的一些教程都使用了Inception v3模型。本文將會使用Inception模型的另一個變體。由於Google開發者並沒有很好的為其撰寫文件(跟通常一樣),不太清楚模型是哪個版本。我們在這裡用“Inception 5h”來指代它,因為zip包的檔名就是這樣,儘管看起來這是Inception模型的一個早期的、更簡單的版本。

這裡使用Inception 5h模型是因為它更容易使用:它接受任何尺寸的輸入影像,然後建立比Inception v3模型(見教程 #13)更漂亮的影像。

import inception5h複製程式碼

從網上下載Inception 5h模型。這是你儲存資料檔案的預設資料夾。如果資料夾不存在就自動建立。

# inception.data_dir = `inception/5h/`複製程式碼

如果資料夾中不存在Inception模型,就自動下載。
它有50MB。

inception5h.maybe_download()複製程式碼

Downloading Inception 5h Model …
Data has apparently already been downloaded and unpacked.

載入模型,以便使用。

model = inception5h.Inception5h()複製程式碼

Inception 5h模型有許多層可用來做DeepDreaming。我們列出了12個最常用的層,以供參考。

len(model.layer_tensors)複製程式碼

12

操作影像的幫助函式

這個函式載入一張影像,並返回一個浮點型numpy陣列。

def load_image(filename):
    image = PIL.Image.open(filename)

    return np.float32(image)複製程式碼

將影像儲存成jpeg檔案。影像是儲存著0-255畫素的numpy陣列。

def save_image(image, filename):
    # Ensure the pixel-values are between 0 and 255.
    image = np.clip(image, 0.0, 255.0)

    # Convert to bytes.
    image = image.astype(np.uint8)

    # Write the image-file in jpeg-format.
    with open(filename, `wb`) as file:
        PIL.Image.fromarray(image).save(file, `jpeg`)複製程式碼

這是繪製影像的函式。使用matplotlib將得到低解析度的影像。使用PIL效果比較好。

def plot_image(image):
    # Assume the pixel-values are scaled between 0 and 255.

    if False:
        # Convert the pixel-values to the range between 0.0 and 1.0
        image = np.clip(image/255.0, 0.0, 1.0)

        # Plot using matplotlib.
        plt.imshow(image, interpolation=`lanczos`)
        plt.show()
    else:
        # Ensure the pixel-values are between 0 and 255.
        image = np.clip(image, 0.0, 255.0)

        # Convert pixels to bytes.
        image = image.astype(np.uint8)

        # Convert to a PIL-image and display it.
        display(PIL.Image.fromarray(image))複製程式碼

歸一化影像,則畫素值在0.0到1.0之間。這個在繪製梯度時很有用。

def normalize_image(x):
    # Get the min and max values for all pixels in the input.
    x_min = x.min()
    x_max = x.max()

    # Normalize so all values are between 0.0 and 1.0
    x_norm = (x - x_min) / (x_max - x_min)

    return x_norm複製程式碼

對梯度做歸一化之後,用這個函式繪製。

def plot_gradient(gradient):
    # Normalize the gradient so it is between 0.0 and 1.0
    gradient_normalized = normalize_image(gradient)

    # Plot the normalized gradient.
    plt.imshow(gradient_normalized, interpolation=`bilinear`)
    plt.show()複製程式碼

這個函式調整影像的大小。函式的引數是你指定的具體的影像解析度,比如(100,200),它也可以接受一個縮放因子,比如,引數是0.5時,影像每個維度縮小一半。

這個函式用PIL來實現,程式碼有點長,因為我們用numpy陣列來處理影像,其中畫素值是浮點值。PIL不支援這個,因此需要將影像轉換成8位位元組,來確保畫素值在合適的範圍內。然後,影像被調整大小並轉換回浮點值。

def resize_image(image, size=None, factor=None):
    # If a rescaling-factor is provided then use it.
    if factor is not None:
        # Scale the numpy array`s shape for height and width.
        size = np.array(image.shape[0:2]) * factor

        # The size is floating-point because it was scaled.
        # PIL requires the size to be integers.
        size = size.astype(int)
    else:
        # Ensure the size has length 2.
        size = size[0:2]

    # The height and width is reversed in numpy vs. PIL.
    size = tuple(reversed(size))

    # Ensure the pixel-values are between 0 and 255.
    img = np.clip(image, 0.0, 255.0)

    # Convert the pixels to 8-bit bytes.
    img = img.astype(np.uint8)

    # Create PIL-object from numpy array.
    img = PIL.Image.fromarray(img)

    # Resize the image.
    img_resized = img.resize(size, PIL.Image.LANCZOS)

    # Convert 8-bit pixel values back to floating-point.
    img_resized = np.float32(img_resized)

    return img_resized複製程式碼

DeepDream 演算法

梯度

下面的幫助函式計算了在DeepDream中使用的輸入影像的梯度。Inception 5h模型可以接受任意尺寸的影像,但太大的影像可能會佔用千兆位元組的記憶體。為了使記憶體佔用最低,我們將輸入影像分割成小的圖塊,然後計算每小塊的梯度。

然而,這可能會在DeepDream演算法最終生成的影像中產生肉眼可見的線條。因此我們隨機地挑選小塊,這樣它們的位置就是不同的。這使得在最終的DeepDream影像裡,小塊之間的縫隙不可見。

這個幫助函式用來確定合適的圖塊尺寸。比如,期望的圖塊尺寸為400×400畫素,但實際大小取決於影像尺寸。

def get_tile_size(num_pixels, tile_size=400):
    """
    num_pixels is the number of pixels in a dimension of the image.
    tile_size is the desired tile-size.
    """

    # How many times can we repeat a tile of the desired size.
    num_tiles = int(round(num_pixels / tile_size))

    # Ensure that there is at least 1 tile.
    num_tiles = max(1, num_tiles)

    # The actual tile-size.
    actual_tile_size = math.ceil(num_pixels / num_tiles)

    return actual_tile_size複製程式碼

這個幫助函式計算了輸入影像的梯度。影像被分割成小塊,然後分別計算各個圖塊的梯度。圖塊是隨機選擇的,避免在最終的DeepDream影像內產生可見的縫隙。

def tiled_gradient(gradient, image, tile_size=400):
    # Allocate an array for the gradient of the entire image.
    grad = np.zeros_like(image)

    # Number of pixels for the x- and y-axes.
    x_max, y_max, _ = image.shape

    # Tile-size for the x-axis.
    x_tile_size = get_tile_size(num_pixels=x_max, tile_size=tile_size)
    # 1/4 of the tile-size.
    x_tile_size4 = x_tile_size // 4

    # Tile-size for the y-axis.
    y_tile_size = get_tile_size(num_pixels=y_max, tile_size=tile_size)
    # 1/4 of the tile-size
    y_tile_size4 = y_tile_size // 4

    # Random start-position for the tiles on the x-axis.
    # The random value is between -3/4 and -1/4 of the tile-size.
    # This is so the border-tiles are at least 1/4 of the tile-size,
    # otherwise the tiles may be too small which creates noisy gradients.
    x_start = random.randint(-3*x_tile_size4, -x_tile_size4)

    while x_start < x_max:
        # End-position for the current tile.
        x_end = x_start + x_tile_size

        # Ensure the tile`s start- and end-positions are valid.
        x_start_lim = max(x_start, 0)
        x_end_lim = min(x_end, x_max)

        # Random start-position for the tiles on the y-axis.
        # The random value is between -3/4 and -1/4 of the tile-size.
        y_start = random.randint(-3*y_tile_size4, -y_tile_size4)

        while y_start < y_max:
            # End-position for the current tile.
            y_end = y_start + y_tile_size

            # Ensure the tile`s start- and end-positions are valid.
            y_start_lim = max(y_start, 0)
            y_end_lim = min(y_end, y_max)

            # Get the image-tile.
            img_tile = image[x_start_lim:x_end_lim,
                             y_start_lim:y_end_lim, :]

            # Create a feed-dict with the image-tile.
            feed_dict = model.create_feed_dict(image=img_tile)

            # Use TensorFlow to calculate the gradient-value.
            g = session.run(gradient, feed_dict=feed_dict)

            # Normalize the gradient for the tile. This is
            # necessary because the tiles may have very different
            # values. Normalizing gives a more coherent gradient.
            g /= (np.std(g) + 1e-8)

            # Store the tile`s gradient at the appropriate location.
            grad[x_start_lim:x_end_lim,
                 y_start_lim:y_end_lim, :] = g

            # Advance the start-position for the y-axis.
            y_start = y_end

        # Advance the start-position for the x-axis.
        x_start = x_end

    return grad複製程式碼

優化影像

這個函式是DeepDream演算法的主要優化迴圈。它根據輸入影像計算Inception模型中給定層的梯度。然後將梯度新增到輸入影像,從而增加層張量(layer-tensor)的平均值。多次重複這個過程,並放大Inception模型在輸入影像中看到的任何圖案。

def optimize_image(layer_tensor, image,
                   num_iterations=10, step_size=3.0, tile_size=400,
                   show_gradient=False):
    """
    Use gradient ascent to optimize an image so it maximizes the
    mean value of the given layer_tensor.

    Parameters:
    layer_tensor: Reference to a tensor that will be maximized.
    image: Input image used as the starting point.
    num_iterations: Number of optimization iterations to perform.
    step_size: Scale for each step of the gradient ascent.
    tile_size: Size of the tiles when calculating the gradient.
    show_gradient: Plot the gradient in each iteration.
    """

    # Copy the image so we don`t overwrite the original image.
    img = image.copy()

    print("Image before:")
    plot_image(img)

    print("Processing image: ", end="")

    # Use TensorFlow to get the mathematical function for the
    # gradient of the given layer-tensor with regard to the
    # input image. This may cause TensorFlow to add the same
    # math-expressions to the graph each time this function is called.
    # It may use a lot of RAM and could be moved outside the function.
    gradient = model.get_gradient(layer_tensor)

    for i in range(num_iterations):
        # Calculate the value of the gradient.
        # This tells us how to change the image so as to
        # maximize the mean of the given layer-tensor.
        grad = tiled_gradient(gradient=gradient, image=img)

        # Blur the gradient with different amounts and add
        # them together. The blur amount is also increased
        # during the optimization. This was found to give
        # nice, smooth images. You can try and change the formulas.
        # The blur-amount is called sigma (0=no blur, 1=low blur, etc.)
        # We could call gaussian_filter(grad, sigma=(sigma, sigma, 0.0))
        # which would not blur the colour-channel. This tends to
        # give psychadelic / pastel colours in the resulting images.
        # When the colour-channel is also blurred the colours of the
        # input image are mostly retained in the output image.
        sigma = (i * 4.0) / num_iterations + 0.5
        grad_smooth1 = gaussian_filter(grad, sigma=sigma)
        grad_smooth2 = gaussian_filter(grad, sigma=sigma*2)
        grad_smooth3 = gaussian_filter(grad, sigma=sigma*0.5)
        grad = (grad_smooth1 + grad_smooth2 + grad_smooth3)

        # Scale the step-size according to the gradient-values.
        # This may not be necessary because the tiled-gradient
        # is already normalized.
        step_size_scaled = step_size / (np.std(grad) + 1e-8)

        # Update the image by following the gradient.
        img += grad * step_size_scaled

        if show_gradient:
            # Print statistics for the gradient.
            msg = "Gradient min: {0:>9.6f}, max: {1:>9.6f}, stepsize: {2:>9.2f}"
            print(msg.format(grad.min(), grad.max(), step_size_scaled))

            # Plot the gradient.
            plot_gradient(grad)
        else:
            # Otherwise show a little progress-indicator.
            print(". ", end="")

    print()
    print("Image after:")
    plot_image(img)

    return img複製程式碼

影像遞迴優化

Inception模型在相當小的影像上進行訓練。不清楚影像的確切大小,但可能每個維度200-300畫素。如果我們使用較大的影像,比如1920×1080畫素,那麼上面的optimize_image()函式會在影像上新增很多小的圖案。

這個幫助函式將輸入影像多次縮放,然後用每個縮放影像來執行上面的optimize_image()函式。這在最終的影像中生成較大的圖案。它也能加快計算速度。

def recursive_optimize(layer_tensor, image,
                       num_repeats=4, rescale_factor=0.7, blend=0.2,
                       num_iterations=10, step_size=3.0,
                       tile_size=400):
    """
    Recursively blur and downscale the input image.
    Each downscaled image is run through the optimize_image()
    function to amplify the patterns that the Inception model sees.

    Parameters:
    image: Input image used as the starting point.
    rescale_factor: Downscaling factor for the image.
    num_repeats: Number of times to downscale the image.
    blend: Factor for blending the original and processed images.

    Parameters passed to optimize_image():
    layer_tensor: Reference to a tensor that will be maximized.
    num_iterations: Number of optimization iterations to perform.
    step_size: Scale for each step of the gradient ascent.
    tile_size: Size of the tiles when calculating the gradient.
    """

    # Do a recursive step?
    if num_repeats>0:
        # Blur the input image to prevent artifacts when downscaling.
        # The blur amount is controlled by sigma. Note that the
        # colour-channel is not blurred as it would make the image gray.
        sigma = 0.5
        img_blur = gaussian_filter(image, sigma=(sigma, sigma, 0.0))

        # Downscale the image.
        img_downscaled = resize_image(image=img_blur,
                                      factor=rescale_factor)

        # Recursive call to this function.
        # Subtract one from num_repeats and use the downscaled image.
        img_result = recursive_optimize(layer_tensor=layer_tensor,
                                        image=img_downscaled,
                                        num_repeats=num_repeats-1,
                                        rescale_factor=rescale_factor,
                                        blend=blend,
                                        num_iterations=num_iterations,
                                        step_size=step_size,
                                        tile_size=tile_size)

        # Upscale the resulting image back to its original size.
        img_upscaled = resize_image(image=img_result, size=image.shape)

        # Blend the original and processed images.
        image = blend * image + (1.0 - blend) * img_upscaled

    print("Recursive level:", num_repeats)

    # Process the image using the DeepDream algorithm.
    img_result = optimize_image(layer_tensor=layer_tensor,
                                image=image,
                                num_iterations=num_iterations,
                                step_size=step_size,
                                tile_size=tile_size)

    return img_result複製程式碼

TensorFlow 會話

我們需要一個TensorFlow會話來執行圖。這是一個互動式的會話,因此我們可以繼續往計算圖中新增梯度方程。

session = tf.InteractiveSession(graph=model.graph)複製程式碼

Hulk

在第一個例子中,我們有一張綠巨人的影像。注意看看DeepDream影像是如何保留絕大部分原始影像顏色的。這是由於梯度在其顏色通道中被平滑處理了,因此變得有點像灰階的,主要改變影像的形狀,而不改變其顏色。

image = load_image(filename=`images/hulk.jpg`)
plot_image(image)複製程式碼

首先,我們需要Inception模型中的張量的引用,它將在DeepDream優化演算法中被最大化。在這個例子中,我們選擇Inception模型的第3層(層索引2)。它有192個通道,我們將嘗試最大化這些通道的平均值。

layer_tensor = model.layer_tensors[2]
layer_tensor複製程式碼

現在執行DeepDream優化演算法,總共10次迭代,步長為6.0,這是下面遞迴優化的兩倍。每次迭代我們都展示它的梯度,你可以看到影像方塊之間的痕跡。

img_result = optimize_image(layer_tensor, image,
                   num_iterations=10, step_size=6.0, tile_size=400,
                   show_gradient=True)複製程式碼

Image before:

Processing image: Gradient min: -26.993517, max: 25.577057, stepsize: 3.35

>Gradient min: -15.383774, max: 12.962121, stepsize:      5.97複製程式碼

Gradient min: -5.993865, max: 6.191866, stepsize: 10.42

Gradient min: -3.638639, max: 3.307561, stepsize: 15.68

Gradient min: -2.407669, max: 2.166253, stepsize: 22.57

Gradient min: -1.716694, max: 1.467488, stepsize: 29.86

Gradient min: -1.153857, max: 1.025310, stepsize: 38.37

Gradient min: -1.026255, max: 0.869002, stepsize: 48.34

Gradient min: -0.634610, max: 0.765562, stepsize: 63.08

Gradient min: -0.585900, max: 0.485299, stepsize: 83.16

Image after:

如果你願意的話,可以儲存DeepDream影像。

# save_image(img_result, filename=`deepdream_hulk.jpg`)複製程式碼

現在,遞迴呼叫DeepDream演算法。我們執行5個遞迴(num_repeats + 1),每個步驟中影像都被模糊並縮小,然後在縮小影像上執行DeepDream演算法。接著,在每個步驟中,將產生的DeepDream影像與原始影像混合,從原始影像獲取一點細節。這個過程重複了多次。

注意,現在DeepDream的圖案更大了。這是因為我們先在低解析度影像上建立圖案,然後在較高解析度影像上進行細化。

img_result = recursive_optimize(layer_tensor=layer_tensor, image=image,
                 num_iterations=10, step_size=3.0, rescale_factor=0.7,
                 num_repeats=4, blend=0.2)複製程式碼

Recursive level: 0
Image before:

Processing image: . . . . . . . . . .
Image after:

Recursive level: 1
Image before:

Processing image: . . . . . . . . . .
Image after:

Recursive level: 2
Image before:

Processing image: . . . . . . . . . .
Image after:

Recursive level: 3
Image before:

Processing image: . . . . . . . . . .
Image after:

Recursive level: 4
Image before:

Processing image: . . . . . . . . . .
Image after:

現在我們將最大化Inception模型中的較高層。使用7號層(索引6)為例。該層識別輸入影像中更復雜的形狀,所以DeepDream演算法也將產生更復雜的影像。這一層似乎識別了狗的臉和毛髮,因此DeepDream演算法往影像中新增了這些東西。

再次注意,與DeepDream演算法其他變體不同的是,這裡輸入影像的大部分顏色被保留了下來,建立了更多柔和的顏色。這是因為我們在顏色通道中平滑了梯度,使其變得有點像灰階,因此不會太多地改變輸入影像的顏色。

layer_tensor = model.layer_tensors[6]
img_result = recursive_optimize(layer_tensor=layer_tensor, image=image,
                 num_iterations=10, step_size=3.0, rescale_factor=0.7,
                 num_repeats=4, blend=0.2)複製程式碼

下面這個例子用DeepDream演算法來最大化層的特徵通道的子集。此時層的索引為7,並且只有前3個特徵通道被最大化。

layer_tensor = model.layer_tensors[7][:,:,:,0:3]
img_result = recursive_optimize(layer_tensor=layer_tensor, image=image,
                 num_iterations=10, step_size=3.0, rescale_factor=0.7,
                 num_repeats=4, blend=0.2)複製程式碼

這個例子展示了最大化Inception模型最後一層的第一個特徵通道的結果。不太清楚這一層及這個特徵可能會在輸入影像中識別出什麼來。

(譯者注:原文的num_repeates引數設為4,我在配有NVIDIA GT 650M的筆記本上執行程式時,會出現記憶體不足的情況。因此,下面將num_repeates設為3,需要的話可以自己改回來。)

layer_tensor = model.layer_tensors[11][:,:,:,0]
img_result = recursive_optimize(layer_tensor=layer_tensor, image=image,
                 num_iterations=10, step_size=3.0, rescale_factor=0.7,
                 num_repeats=3, blend=0.2)複製程式碼

Giger

image = load_image(filename=`images/giger.jpg`)
plot_image(image)複製程式碼
layer_tensor = model.layer_tensors[3]
img_result = recursive_optimize(layer_tensor=layer_tensor, image=image,
                 num_iterations=10, step_size=3.0, rescale_factor=0.7,
                 num_repeats=3, blend=0.2)複製程式碼

Recursive level: 0
Processing image: . . . . . . . . . .

Recursive level: 1
Processing image: . . . . . . . . . .

Recursive level: 2
Processing image: . . . . . . . . . .

Recursive level: 3
Processing image: . . . . . . . . . .

layer_tensor = model.layer_tensors[5]
img_result = recursive_optimize(layer_tensor=layer_tensor, image=image,
num_iterations=10, step_size=3.0, rescale_factor=0.7,
num_repeats=3, blend=0.2)

Recursive level: 0
Processing image: . . . . . . . . . .

Recursive level: 1
Processing image: . . . . . . . . . .

Recursive level: 2
Processing image: . . . . . . . . . .

Recursive level: 3
Processing image: . . . . . . . . . .

layer_tensor = model.layer_tensors[5]
img_result = recursive_optimize(layer_tensor=layer_tensor, image=image,
                 num_iterations=10, step_size=3.0, rescale_factor=0.7,
                 num_repeats=3, blend=0.2)複製程式碼

Escher

image = load_image(filename=`images/escher_planefilling2.jpg`)
plot_image(image)複製程式碼
layer_tensor = model.layer_tensors[6]
img_result = recursive_optimize(layer_tensor=layer_tensor, image=image,
                 num_iterations=10, step_size=3.0, rescale_factor=0.7,
                 num_repeats=3, blend=0.2)複製程式碼

Recursive level: 0
Processing image: . . . . . . . . . .

Recursive level: 1
Processing image: . . . . . . . . . .

Recursive level: 2
Processing image: . . . . . . . . . .

Recursive level: 3
Processing image: . . . . . . . . . .

關閉TensorFlow會話

現在我們已經用TensorFlow完成了任務,關閉session,釋放資源。

# This has been commented out in case you want to modify and experiment
# with the Notebook without having to restart it.
# session.close()複製程式碼

總結

這篇教程展示瞭如何使用神經網路的梯度來放大影像中的圖案。輸出影像似乎已經用抽象的或類似動物的圖案來重新繪製了。

還有許多這種技術的變體,來生成不同的輸出影像。我們鼓勵你修改上述引數和演算法進行實驗。

練習

下面使一些可能會讓你提升TensorFlow技能的一些建議練習。為了學習如何更合適地使用TensorFlow,實踐經驗是很重要的。

在你對這個Notebook進行修改之前,可能需要先備份一下。

  • 嘗試使用自己的影像。
  • 試試optimize_image()recursive_optimize()的不同引數,看看它如何影響結果。
  • 試著去掉optimize_image()中的梯度。會發生什麼?
  • 在執行optimize_image()時繪製梯度。會看到一些失真嗎?你認為是什麼原因?這重要嗎?你能找到一種方法來去掉它們嗎?
  • 嘗試使用隨機噪聲作為輸入影像。這與教程#13中用於視覺化分析的類似。會生成比本教程中更好的影像嗎?為什麼?
  • inception5h.py這個檔案的Inception5h.get_gradient()裡,刪除tf.square()。 DeepDream影像會發生什麼變化?為什麼?
  • 你可以將梯度移到optimize_image()外面以節省記憶體嗎?
  • 你能使程式執行得更快嗎?一個想法是直接在TensorFlow中實現高斯模糊和調整大小。
  • 通過重複呼叫optimize_image()並在影像上放大一點,製作一個DeepDream電影。
  • 逐幀處理電影。您可能需要在幀間保持穩定。
  • 向朋友解釋程式如何工作。

相關文章