├── README.md └── deep_dream.py /README.md: -------------------------------------------------------------------------------- 1 | # deep_dream_challenge 2 | Deep Dream Challenge code by @SIrajology on [Youtube](https://youtu.be/MrBzgvUNr4w) 3 | 4 | ##Overview 5 | 6 | This is the code for the Deep Dream challenge for 'Learn Python for Data Science #5' by @Sirajology on [YouTube](https://youtu.be/MrBzgvUNr4wY). The code uses the Tensorflow Machine Learning library to generate a trippy image 7 | from a given input image. 8 | 9 | ##Dependencies 10 | 11 | * numpy (http://www.numpy.org/) 12 | * functools 13 | * PIL (http://stackoverflow.com/questions/20060096/installing-pil-with-pip) 14 | * tensorflow (https://www.tensorflow.org/versions/r0.10/get_started/os_setup.html#pip-installation) 15 | * matplotlib (http://matplotlib.org/1.5.1/users/installing.html) 16 | * urllib (https://pypi.python.org/pypi/urllib3) 17 | * os 18 | * zipfile 19 | 20 | Install missing dependencies using [pip](https://pip.pypa.io/en/stable/installing/) 21 | 22 | ##Demo Usage 23 | 24 | Once you have your dependencies installed via pip, run the demo script in terminal via 25 | 26 | ``` 27 | python deep_dream.py 28 | ``` 29 | 30 | ##Challenge 31 | 32 | The instructions are 33 | 34 | 1. Add a function to the existing deep dream python file that converts not just an image, but a video clip to deep dream. 35 | 36 | *HINT* Think of a video as a collection of images (frames). 37 | 38 | If you want to use your own template, that's fine too. Submit your code in the comments section and I'll announce the winner in 39 | the next video. Good luck! 40 | 41 | ##Credits 42 | 43 | Thanks Google and [Liu](https://github.com/LiuzcEECS) I've reformatted this code to make it easier to grok. 44 | -------------------------------------------------------------------------------- /deep_dream.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | from functools import partial 3 | import PIL.Image 4 | import tensorflow as tf 5 | import matplotlib.pyplot as plt 6 | import urllib.request 7 | import os 8 | import zipfile 9 | 10 | def main(): 11 | #Step 1 - download google's pre-trained neural network 12 | url = 'https://storage.googleapis.com/download.tensorflow.org/models/inception5h.zip' 13 | data_dir = '../data/' 14 | model_name = os.path.split(url)[-1] 15 | local_zip_file = os.path.join(data_dir, model_name) 16 | if not os.path.exists(local_zip_file): 17 | # Download 18 | model_url = urllib.request.urlopen(url) 19 | with open(local_zip_file, 'wb') as output: 20 | output.write(model_url.read()) 21 | # Extract 22 | with zipfile.ZipFile(local_zip_file, 'r') as zip_ref: 23 | zip_ref.extractall(data_dir) 24 | 25 | # start with a gray image with a little noise 26 | img_noise = np.random.uniform(size=(224,224,3)) + 100.0 27 | 28 | model_fn = 'tensorflow_inception_graph.pb' 29 | 30 | #Step 2 - Creating Tensorflow session and loading the model 31 | graph = tf.Graph() 32 | sess = tf.InteractiveSession(graph=graph) 33 | with tf.gfile.FastGFile(os.path.join(data_dir, model_fn), 'rb') as f: 34 | graph_def = tf.GraphDef() 35 | graph_def.ParseFromString(f.read()) 36 | t_input = tf.placeholder(np.float32, name='input') # define the input tensor 37 | imagenet_mean = 117.0 38 | t_preprocessed = tf.expand_dims(t_input-imagenet_mean, 0) 39 | tf.import_graph_def(graph_def, {'input':t_preprocessed}) 40 | 41 | layers = [op.name for op in graph.get_operations() if op.type=='Conv2D' and 'import/' in op.name] 42 | feature_nums = [int(graph.get_tensor_by_name(name+':0').get_shape()[-1]) for name in layers] 43 | 44 | print('Number of layers', len(layers)) 45 | print('Total number of feature channels:', sum(feature_nums)) 46 | 47 | #####HELPER FUNCTIONS. I didn't go over these in the video for times sake. They are mostly just formatting functions. Scroll 48 | #to the bottom ######################################################################################################### 49 | ######################################################################################################################## 50 | ############################################################ 51 | 52 | # Helper functions for TF Graph visualization 53 | #pylint: disable=unused-variable 54 | def strip_consts(graph_def, max_const_size=32): 55 | """Strip large constant values from graph_def.""" 56 | strip_def = tf.GraphDef() 57 | for n0 in graph_def.node: 58 | n = strip_def.node.add() #pylint: disable=maybe-no-member 59 | n.MergeFrom(n0) 60 | if n.op == 'Const': 61 | tensor = n.attr['value'].tensor 62 | size = len(tensor.tensor_content) 63 | if size > max_const_size: 64 | tensor.tensor_content = ""%size 65 | return strip_def 66 | 67 | def rename_nodes(graph_def, rename_func): 68 | res_def = tf.GraphDef() 69 | for n0 in graph_def.node: 70 | n = res_def.node.add() #pylint: disable=maybe-no-member 71 | n.MergeFrom(n0) 72 | n.name = rename_func(n.name) 73 | for i, s in enumerate(n.input): 74 | n.input[i] = rename_func(s) if s[0]!='^' else '^'+rename_func(s[1:]) 75 | return res_def 76 | 77 | def showarray(a): 78 | a = np.uint8(np.clip(a, 0, 1)*255) 79 | plt.imshow(a) 80 | plt.show() 81 | 82 | def visstd(a, s=0.1): 83 | '''Normalize the image range for visualization''' 84 | return (a-a.mean())/max(a.std(), 1e-4)*s + 0.5 85 | 86 | def T(layer): 87 | '''Helper for getting layer output tensor''' 88 | return graph.get_tensor_by_name("import/%s:0"%layer) 89 | 90 | def render_naive(t_obj, img0=img_noise, iter_n=20, step=1.0): 91 | t_score = tf.reduce_mean(t_obj) # defining the optimization objective 92 | t_grad = tf.gradients(t_score, t_input)[0] # behold the power of automatic differentiation! 93 | 94 | img = img0.copy() 95 | for _ in range(iter_n): 96 | g, _ = sess.run([t_grad, t_score], {t_input:img}) 97 | # normalizing the gradient, so the same step size should work 98 | g /= g.std()+1e-8 # for different layers and networks 99 | img += g*step 100 | showarray(visstd(img)) 101 | 102 | def tffunc(*argtypes): 103 | '''Helper that transforms TF-graph generating function into a regular one. 104 | See "resize" function below. 105 | ''' 106 | placeholders = list(map(tf.placeholder, argtypes)) 107 | def wrap(f): 108 | out = f(*placeholders) 109 | def wrapper(*args, **kw): 110 | return out.eval(dict(zip(placeholders, args)), session=kw.get('session')) 111 | return wrapper 112 | return wrap 113 | 114 | def resize(img, size): 115 | img = tf.expand_dims(img, 0) 116 | return tf.image.resize_bilinear(img, size)[0,:,:,:] 117 | resize = tffunc(np.float32, np.int32)(resize) 118 | 119 | def calc_grad_tiled(img, t_grad, tile_size=512): 120 | '''Compute the value of tensor t_grad over the image in a tiled way. 121 | Random shifts are applied to the image to blur tile boundaries over 122 | multiple iterations.''' 123 | sz = tile_size 124 | h, w = img.shape[:2] 125 | sx, sy = np.random.randint(sz, size=2) 126 | img_shift = np.roll(np.roll(img, sx, 1), sy, 0) 127 | grad = np.zeros_like(img) 128 | for y in range(0, max(h-sz//2, sz),sz): 129 | for x in range(0, max(w-sz//2, sz),sz): 130 | sub = img_shift[y:y+sz,x:x+sz] 131 | g = sess.run(t_grad, {t_input:sub}) 132 | grad[y:y+sz,x:x+sz] = g 133 | return np.roll(np.roll(grad, -sx, 1), -sy, 0) 134 | 135 | #BACK TO CODE IN THE VIDEO########################################################################################### 136 | ######################################################################################################## 137 | ############################################################################## 138 | 139 | #CHALLENGE - Write a function that outputs a deep dream video 140 | #def render_deepdreamvideo(): 141 | 142 | 143 | def render_deepdream(t_obj, img0=img_noise, 144 | iter_n=10, step=1.5, octave_n=4, octave_scale=1.4): 145 | t_score = tf.reduce_mean(t_obj) # defining the optimization objective 146 | t_grad = tf.gradients(t_score, t_input)[0] # behold the power of automatic differentiation! 147 | 148 | # split the image into a number of octaves 149 | img = img0 150 | octaves = [] 151 | for _ in range(octave_n-1): 152 | hw = img.shape[:2] 153 | lo = resize(img, np.int32(np.float32(hw)/octave_scale)) 154 | hi = img-resize(lo, hw) 155 | img = lo 156 | octaves.append(hi) 157 | 158 | # generate details octave by octave 159 | for octave in range(octave_n): 160 | if octave>0: 161 | hi = octaves[-octave] 162 | img = resize(img, hi.shape[:2])+hi 163 | for _ in range(iter_n): 164 | g = calc_grad_tiled(img, t_grad) 165 | img += g*(step / (np.abs(g).mean()+1e-7)) 166 | 167 | #this will usually be like 3 or 4 octaves 168 | #Step 5 output deep dream image via matplotlib 169 | showarray(img/255.0) 170 | 171 | 172 | 173 | #Step 3 - Pick a layer to enhance our image 174 | layer = 'mixed4d_3x3_bottleneck_pre_relu' 175 | channel = 139 # picking some feature channel to visualize 176 | 177 | #open image 178 | img0 = PIL.Image.open('pilatus800.jpg') 179 | img0 = np.float32(img0) 180 | 181 | #Step 4 - Apply gradient ascent to that layer 182 | render_deepdream(tf.square(T('mixed4c')), img0) 183 | 184 | 185 | if __name__ == '__main__': 186 | main() 187 | --------------------------------------------------------------------------------