Введение
Познакомить с принципом DeepDream и реализовать его с помощью TensorFlow.
Эффект
Давайте сначала посмотрим на эффект DeepDream, изначально это была такая картинка
После обработки DeepDream может стать так
Немного странное и мечтательное, а также немного неизвестное духовное загрязнение
принцип
Большую часть времени мы обучаем и настраиваем параметры сети на основе заданных данных и меток.
Однако иногда мы исправим параметры сети и отрегулируйте входные данные в соответствии с определенной функцией потери. Например, в передаче стиля изображения мы регулируем синтезированное изображение в соответствии с функцией потери содержимого и функцией потери стилей.
Для обычных моделей классификации изображений введите изображение, и каждый тензор в сети выдаст соответствующее значение ответа.Чем больше значение, тем больше тензору «нравится» изображение.
Например, если вы вводите изображение собаки, тензор, используемый для идентификации и классификации собак в сети, выдаст большее значение ответа.
Установите цель оптимизации, чтобы максимизировать значение отклика тензора для настройки входного изображения, что является принципом DeepDream.
Например, чтобы удовлетворить тензор, который любит собак, мы корректируем и увеличиваем некоторые подсказки, такие как собаки на исходной картинке, чтобы значение отклика этого тензора было больше.
выполнить
загрузить библиотеку
# -*- coding: utf-8 -*-
import tensorflow as tf
import numpy as np
import cv2
from imageio import imread, imsave, mimsave
import matplotlib.pyplot as plt
%matplotlib inline
from scipy.ndimage.filters import gaussian_filter
Загрузите модель классификации изображений, которая используется здесьinception5h
layer_names = ['conv2d0', 'conv2d1', 'conv2d2',
'mixed3a', 'mixed3b', 'mixed4a', 'mixed4b', 'mixed4c', 'mixed4d', 'mixed4e',
'mixed5a', 'mixed5b']
graph = tf.Graph()
with graph.as_default():
with tf.gfile.FastGFile('inception5h.pb', 'rb') as f:
graph_def = tf.GraphDef()
graph_def.ParseFromString(f.read())
tf.import_graph_def(graph_def, name='')
X = graph.get_tensor_by_name('input:0')
layers = [graph.get_tensor_by_name(name + ':0') for name in layer_names]
all_layers_names = [tensor.name for tensor in tf.get_default_graph().as_graph_def().node]
print(all_layers_names)
sess = tf.Session(graph=graph)
Определите функцию для получения тензора градиента и функцию для вычисления градиента исходного изображения в блоках.
def get_gradient(tensor):
with graph.as_default():
return tf.gradients(tf.reduce_mean(tf.square(tensor)), X)[0]
def get_tile_size(num_pixels, tile_size=400):
num_tiles = max(1, int(round(num_pixels / tile_size)))
return int(np.ceil(num_pixels / num_tiles))
def tiled_gradient(gradient, image, tile_size=400):
grad = np.zeros_like(image)
H, W, _ = image.shape
h = get_tile_size(H, tile_size)
h_4 = h // 4
w = get_tile_size(W, tile_size)
w_4 = w // 4
h_start = np.random.randint(-3 * h_4, -h_4)
while h_start < H:
h_end = h_start + h
h_start_lim = max(h_start, 0)
h_end_lim = min(h_end, H)
w_start = np.random.randint(-3 * w_4, -w_4)
while w_start < W:
w_end = w_start + w
w_start_lim = max(w_start, 0)
w_end_lim = min(w_end, W)
g = sess.run(gradient, feed_dict={X: [image[h_start_lim: h_end_lim, w_start_lim: w_end_lim, :]]})[0]
g /= (np.std(g) + 1e-8)
grad[h_start_lim: h_end_lim, w_start_lim: w_end_lim, :] = g
w_start = w_end
h_start = h_end
return grad
Настройте входное изображение в соответствии с градиентом, то есть DeepDream
def dream(layer_tensor, image, iteration=10, step=3.0, tile_size=400):
img = image.copy()
gradient = get_gradient(layer_tensor)
for i in range(iteration):
grad = tiled_gradient(gradient, img)
sigma = (i * 4.0) / iteration + 0.5
grad = gaussian_filter(grad, 0.5 * sigma) + gaussian_filter(grad, sigma) + gaussian_filter(grad, 2 * sigma)
scaled_step = step / (np.std(grad) + 1e-8)
img += grad * scaled_step
img = np.clip(img, 0, 255)
return img
Масштабируйте исходное изображение, выполняйте обработку DeepDream в нескольких масштабах и складывайте их
def recursive_dream(layer_tensor, image, repeat=3, scale=0.7, blend=0.2, iteration=10, step=3.0, tile_size=400):
if repeat > 0:
sigma = 0.5
img_blur = gaussian_filter(image, (sigma, sigma, 0.0))
h0 = img_blur.shape[0]
w0 = img_blur.shape[1]
h1 = int(scale * h0)
w1 = int(scale * w0)
img_downscaled = cv2.resize(img_blur, (w1, h1))
img_dream = recursive_dream(layer_tensor, img_downscaled, repeat - 1, scale, blend, iteration, step, tile_size)
img_upscaled = cv2.resize(img_dream, (w0, h0))
image = blend * image + (1.0 - blend) * img_upscaled
image = np.clip(image, 0, 255)
return dream(layer_tensor, image, iteration, step, tile_size)
читать картинку
image = imread('mountain.jpg')
image = image.astype(np.float32)
Исходное изображение обрабатывается с ответными значениями тензора 12 в качестве цели оптимизации.
for i in range(len(layers)):
print(layer_names[i])
result = recursive_dream(layers[i], image)
plt.figure(figsize=(10, 15))
plt.imshow(result / 255.)
plt.show()
imsave('imgs/%s.jpg' % layer_names[i], result)
DeepDream результат conv2d2
Результаты DeepDream для mix3a
Результаты DeepDream для mix4c
Результаты DeepDream для Mixed5a
По мере увеличения количества слоев, на которых расположен тензор, графика, оптимизированная DeepDream, усложняется.
Помимо использования всего тензора в качестве цели, вы также можете выбрать только значение отклика фильтра для оптимизации.
Например, если вы выберете фильтр Mixed4c, вы увидите, что графики различных настроек фильтра отличаются.
for i in range(10):
print('Filter %d of mixed4c' % i)
result = recursive_dream(layers[7][:, :, :, i], image)
plt.figure(figsize=(10, 15))
plt.imshow(result / 255.)
plt.show()
imsave('imgs/mixed4c_filter_%d.jpg' % i, result)
Соответствующий результат filter0 для Mixed4c
Соответствующий результат filter8 дляmixed4c
Конечно, вы также можете повторно запускать DeepDream на изображении, и оптимизированная графика будет становиться все более и более очевидной.
img = image.copy()
imgs = []
for i in range(20):
print('Iteration %d of mixed4c' % i)
img = recursive_dream(layers[7], img)
plt.figure(figsize=(10, 15))
plt.imshow(img / 255.)
plt.show()
imgs.append(img)
mimsave('imgs/mixed4c多轮迭代结果.gif', imgs, fps=5)
Результат немного призрачный, возможно, mix4c предпочитает собак...