DeepDream

DeepDream is an artistic image modification technique that leverages the representations learned by deep CNN code Inception, named after the movie of the same name. We can take any input image and process it to generate trippy pictures, full of algorithmic pareidolia artifacts, bird feathers, dog-like faces, dog eyes—a by-product of the fact that the DeepDream convent was trained on ImageNet, where dog breeds and bird species are vastly over-represented. 

The DeepDream algorithm is almost identical to the ConvNet filter visualization technique using gradient ascent, except in a few differences as follows:

  • In DeepDream, activation of entire layers is maximized, whereas in visualization only a specific filter is maximized, thus mixing together visualizations of large numbers of features maps
  • We start not from a random noise input, but rather from an existing image; thus, the resulting visualizations will modify pre-existing visual patterns, distorting elements of the image in a somewhat artistic fashion
  • The input images get processed at different scales (called octaves), which improves the quality of the visualizations

Let's now modify the visualization code in the previous section. First, we have to change the loss function and the gradient calculation. The following is the code to do the same:

layer_name = 'activation_41'
activation = model.get_layer(layer_name).output

# We avoid border artifacts by only involving non-border pixels in the #loss.
scaling = K.prod(K.cast(K.shape(activation), 'float32'))
loss = K.sum(K.square(activation[:, 2: -2, 2: -2, :])) / scaling

# This tensor holds our generated image
dream = model.input

# Compute the gradients of the dream with regard to the loss.
grads = K.gradients(loss, dream)[0]

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

iterate_grad_ac_step = K.function([dream], [loss, grads])

The second change is in the input image, so we have to supply an input image on which we want the DeepDream algorithm to run. The third change is, instead of applying gradient accent on a single image, we create input images at various scales and apply gradient accent, as shown in the following code:

num_octave = 4 # Number of scales at which to run gradient ascent
octave_scale = 1.4 # Size ratio between scales
iterations = 20 # Number of ascent steps per scale

# If our loss gets larger than 10,
# we will interrupt the gradient ascent process, to avoid ugly
# artifacts
max_loss = 20.

base_image_path = 'Path to Image You Want to Use'
# Load the image into a Numpy array
img = preprocess_image(base_image_path)
print(img.shape)
# We prepare a list of shape tuples
# defining the different scales at which we will run gradient ascent
original_shape = img.shape[1:3]
successive_shapes = [original_shape]
for i in range(1, num_octave):
shape = tuple([int(dim / (octave_scale ** i)) for dim in
original_shape])
successive_shapes.append(shape)

# Reverse list of shapes, so that they are in increasing order
successive_shapes = successive_shapes[::-1]

# Resize the Numpy array of the image to our smallest scale
original_img = np.copy(img)
shrunk_original_img = resize_img(img, successive_shapes[0])
print(successive_shapes)

#Example Octaves for image of shape (1318, 1977)
[(480, 720), (672, 1008), (941, 1412), (1318, 1977)]

The following code shows a few utility functions for the DeepDream algorithm. The function deprocess_image is basically an inverse operator of preprocess input for the InceptionV3 model:

import scipy

def deprocess_image(x):
# Util function to convert a tensor into a valid image.
if K.image_data_format() == 'channels_first':
x = x.reshape((3, x.shape[2], x.shape[3]))
x = x.transpose((1, 2, 0))
else:
x = x.reshape((x.shape[1], x.shape[2], 3))
x /= 2.
x += 0.5
x *= 255.
x = np.clip(x, 0, 255).astype('uint8')
return x

def resize_img(img, size):
img = np.copy(img)
factors = (1,
float(size[0]) / img.shape[1],
float(size[1]) / img.shape[2],
1)
return scipy.ndimage.zoom(img, factors, order=1)


def save_img(img, fname):
pil_img = deprocess_image(np.copy(img))
scipy.misc. (fname, pil_img)

At each successive scale, from the smallest to the largest octaves, we run gradient ascent to maximize the loss we have previously defined, at that scale. After each gradiant ascent run, the resulting image is upscaled by 40%. At each upscaling step, some image details are lost; but we can restore it by adding the lost information, as we know the original image at that scale:

MAX_ITRN = 20
MAX_LOSS = 20
learning_rate = 0.01

for shape in successive_shapes:
print('Processing image shape', shape)
img = resize_img(img, shape)
img = gradient_ascent(img,
iterations=MAX_ITRN,
step=learning_rate,
max_loss=MAX_LOSS)
upscaled_shrunk_original_img = resize_img(shrunk_original_img,
shape)
same_size_original = resize_img(original_img, shape)
lost_detail = same_size_original - upscaled_shrunk_original_img
print('adding lost details', lost_detail.shape)
img += lost_detail
shrunk_original_img = resize_img(original_img, shape)
save_img(img, fname='dream_at_scale_' + str(shape) + '.png')

save_img(img, fname='final_dream.png')
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
52.14.175.148