keras實現Deep Dream
阿新 • • 發佈:2018-11-30
本文主要介紹通過keras提供的Inception V3實現Deep Dream,keras提供了許多類似的可用網路,如VGG16,VGG19, Xception,ResNet50。
下面是示例程式碼:
# coding: utf-8 # In[2]: from keras.applications import inception_v3 from keras import backend as K # 不需要訓練模型, # 所以此命令禁用所有特定於訓練的操作 K.set_learning_phase(0) # 構建InceptionV3網路,該模型將載入預先訓練的ImageNet權重。 model = inception_v3.InceptionV3(weights='imagenet', include_top=False) # In[4]: ''' 接下來,計算“損失”,即在梯度上升過程中尋求最大化的數量。 同時最大化多個層中所有過濾器的啟用。具體來說,將最大化一組高階層啟用的L2範數的加權和。 選擇的確切圖層集(以及它們對最終損失的貢獻)對將能夠生成的視覺效果有很大影響,因此 使這些引數易於配置。較低層會產生幾何圖案,而較高層會產生視覺效果, 可以在其中識別ImageNet中的某些類(例如鳥或狗)。 將從一個涉及四層的任意配置開始 ''' # Dict將層名稱對映到一個係數,該係數量化了層的啟用將導致尋求最大化的損失。 # 這些是在內建的InceptionV3應用程式中出現的圖層名稱。可以使用`model.summary()`列出所有圖層名稱。 model.summary() layer_contributions = { 'mixed2': 0.2, 'mixed3': 3., 'mixed4':2., 'mixed5':1.5, } # In[6]: # 定義一個包含損失的張量,即上面列出的啟用的L2範數的加權和。 layer_dict = dict([(layer.name, layer) for layer in model.layers]) # 定義損失 loss = K.variable(0.) for layer_name in layer_contributions: # 將丟失的圖層特徵的L2範數新增到損失中。 coeff = layer_contributions[layer_name] activation = layer_dict[layer_name].output # 通過僅涉及損失中的非邊界畫素來避免邊界偽影。 scaling = K.prod(K.cast(K.shape(activation), 'float32')) loss += coeff * K.sum(K.square(activation[:, 2: -2, 2: -2, :])) / scaling # In[8]: # 設定梯度上升過程: # 儲存生成的圖片 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) def eval_loss_and_grads(x): outs = fetch_loss_and_grads([x]) loss_value = outs[0] grad_values = outs[1] return loss_value, grad_values 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 # In[15]: ''' 最後,這是實際的Deep Dream演算法。 首先,定義一個“尺度”列表(也稱為“octaves”),在其中處理影象。 每個連續的比例比前一個比例大1.4倍(即大40%):首先處理一個小影象,然後逐漸升級它: 然後,對於每個連續的比例,從最小到最大,們執行梯度上升以最大化先前在該比例下定義的損失。在 每次漸變上升執行後,將得到的影象放大40%。 為了避免在每次連續放大後丟失大量影象細節(導致影象越來越模糊或畫素化),利用一個簡單的技巧: 在每次放大之後,將丟失的細節重新注入影象,這是可能的,因為知道什麼是原始影象看起來應該更大。 給定一個小影象S和一個較大的影象尺寸L,可以計算原始影象(假設大於L)重新調整大小L和原始大小 調整為大小S之間的差異 - 這個差異量化從S開始時丟失的細節到L. 下面的程式碼利用了以下簡單的輔助Numpy函式。 ''' import scipy import numpy as np from keras.preprocessing import image 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 deprocess_image(x): # Util函式將張量轉換為有效影象。 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 save_img(img, fname): pil_img = deprocess_image(np.copy(img)) scipy.misc.imsave(fname, pil_img) def preprocess_image(image_path): # Util函式:調整圖片大小並將圖片格式化為適當的張量。 img = image.load_img(image_path) img = image.img_to_array(img) img = np.expand_dims(img, axis=0) img = inception_v3.preprocess_input(img) return img # In[16]: import numpy as np # 使用超引數獲得新效果 step = 0.01 # 梯度上升步長 num_octave = 3 # 執行梯度上升的比例數 octave_scale = 1.4 # 尺度之間的尺寸比 iterations = 20 # 每個比例的上升步數 #如果損失大於10,我將中斷梯度上升過程,以避免ugly artifacts max_loss = 10. # 將其填充到要使用的影象的路徑 base_image_path = './test.png' # 將影象載入到Numpy陣列中 img = process_image(base_image_path) # 準備一個形狀元組列表,定義了我們將執行梯度上升的不同尺度 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) # 反轉shape列表,使它們按順序遞增 successive_shapes = successive_shapes[::-1] # 將影象的Numpy陣列調整為最小比例 original_img = np.copy(img) shrunk_original_img = resize_img(img, successive_shapes[0]) 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) lost_detail = same_size_original - upscaled_shrunk_original_img 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') # In[17]: from matplotlib import pyplot as plt plt.imshow(deprocess_image(np.copy(img))) plt.show()
測試圖片:
結果:
Processing image shape (138, 136) ...Loss value at 0 : 0.26012674 ...Loss value at 1 : 0.42666528 ...Loss value at 2 : 0.6801994 ...Loss value at 3 : 1.0506611 ...Loss value at 4 : 1.5495763 ...Loss value at 5 : 1.89506 ...Loss value at 6 : 2.2689116 ...Loss value at 7 : 2.726926 ...Loss value at 8 : 3.0781224 ...Loss value at 9 : 3.5114133 ...Loss value at 10 : 3.947701 ...Loss value at 11 : 4.4308066 ...Loss value at 12 : 4.7854958 ...Loss value at 13 : 5.20111 ...Loss value at 14 : 5.642894 ...Loss value at 15 : 5.903351 ...Loss value at 16 : 6.480799 ...Loss value at 17 : 6.803378 ...Loss value at 18 : 7.2163234 ...Loss value at 19 : 7.672877 Processing image shape (194, 190) ...Loss value at 0 : 1.8239505 ...Loss value at 1 : 2.7991168 ...Loss value at 2 : 3.6743054 ...Loss value at 3 : 4.4888363 ...Loss value at 4 : 5.387617 ...Loss value at 5 : 6.206719 ...Loss value at 6 : 7.1246104 ...Loss value at 7 : 7.971635 ...Loss value at 8 : 8.978709 Processing image shape (272, 267) ...Loss value at 0 : 2.776465 ...Loss value at 1 : 5.7171583
結果圖片: