文章目錄
- 庫的匯入
- 模型建立
- 構建Loss函式
- 輔助函式
- 實驗測驗
本文是個人對《Deep Learning with Python》一書的學習筆記,使用 VSCode 下的 ipynb (python notebook, python 3.8.4 64-bit).
由于原書的代碼使用的tensorflow,keras,scipy的版本較為古老,在新版本(tensorflow 2.x 等)條件下已無法直接運行,經過不斷調整后代碼能成功在新的版本下運行,
庫的匯入
先來看一下使用的庫及版本,
import tensorflow as tf
import tensorflow.keras as keras
import numpy as np
import cv2 as cv
print("Tf version =",tf.__version__)
print("Keras version =",keras.__version__)
print("Numpy version =",np.__version__)
print("Opencv version =",cv.__version__)
輸出:
Tf version = 2.3.1
Keras version = 2.4.0
Numpy version = 1.19.3
Opencv version = 4.2.0
模型建立
直接匯入現成的 InceptionV3 模型,并設定 trainable = False
注意在匯入前需要如下禁止 eager_execution 模式,這是 tensorflow 2.x 所需要的,
tf.compat.v1.disable_eager_execution()
model = keras.applications.inception_v3.InceptionV3(weights='imagenet',include_top=False)
model.trainable = False
構建Loss函式
注意此處用 loss = 0 初始化,這是與原書不同的地方,
如果查看 loss 的型別,會發現不是普通的float,而是Tensor:
<class ‘tensorflow.python.framework.ops.Tensor’>.
所以 K.gradients可以根據計算圖求得 model.input 到 loss 的函式的梯度,
修改 layers_contibution 引數可以調整不同層的貢獻從而得到不同的效果,
import tensorflow.keras.backend as K
layers_contribution = {'mixed2':3.0,'mixed3':1.0,'mixed4':0.2,'mixed5':0.5}
layer_dict = {layer.name : layer for layer in model.layers}
loss = 0 # 不要用 K.variable(0.)
for layer_name, contribution in layers_contribution.items():
activation = layer_dict[layer_name].output
scaling = K.prod(K.cast(K.shape(activation),'float32'))
loss += ( contribution * K.sum(K.square(activation[:, 2:-2, 2:-2, :]))/scaling )
grads = K.gradients(loss, model.get_layer('input_1').input)[0]
#grads = K.gradients(loss,model.input)[0]
grads /= K.maximum(K.mean(K.abs(grads)), 1e-7)
fetch_loss_and_grads = K.function([model.input], [loss, grads])
輔助函式
定義一些輔助函式,原書使用的 scipy.misc.imsave 已經被移除,這里替換成了 opencv.imwrite.
def deprocess_image(x):
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))
# 將 [-1,1] 的值線性映射到 [0,255] 的整數
x /= 2.
x += 0.5
x *= 255.
x = np.clip(x, 0, 255).astype('uint8')
return x[:,:,[2,1,0]] # 需要把 RGB 通道轉化為cv.imwrite需要的 BGR 通道
def resize_img(img, size):
# 注意 opencv的resize的形狀引數是 (width, height)
return np.expand_dims(cv.resize(img[0], (size[1],size[0]) ) , axis = 0)
def save_img(img, fname):
cv.imwrite(fname , deprocess_image(np.copy(img)))
def preprocess_image(image_path):
img = keras.preprocessing.image.load_img(image_path)
img = keras.preprocessing.image.img_to_array(img)
img = np.expand_dims(img, axis=0)
# 回傳值的 shape 是 (1,height,width,3)
return keras.applications.inception_v3.preprocess_input(img)
def gradient_ascent(x, iterations, step, max_loss=None):
for i in range(iterations):
loss_value, grad_values = fetch_loss_and_grads([x])
print('...Loss value at', i, ':', loss_value)
if max_loss is not None and loss_value > max_loss:
break
x += step * grad_values
return x
梯度上升(gradien_ascent)與梯度下降相反,可以認為是將結果加上梯度*系數,讓圖片產生了變化,
實驗測驗
選擇影像的路徑后,運行該段代碼即可,
程式會先把原圖縮小,從縮小后的圖片開始處理,再逐步放大圖片處理,直至大小和輸入影像相同,
因為不涉及神經網路訓練,所以運行時間不長,我的運行時間:98.1s.
step = 1e-2 # 系數
num_octave = 3 # 放大 num_octave 次
octave_scale = 1.4 # 每次放大的比例
iterations = 20 # 每次圖片處理的最大次數
max_loss = 10. # 最大允許損失值
# 修改為自己的路徑
origin_dir = 'D:\\Python Projects\\Neural Network\\GAN\\DeepDream'
# img 的 shape 是 (1,height,width,3)
img = preprocess_image(origin_dir + '\\base_image.png')
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)
successive_shapes = successive_shapes[::-1]
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)
# 向 img 加入因為放大而失真的部分
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=origin_dir + '\\dream_at_scale_' + str(shape) + '.png')
測驗用原圖:

最終結果:出現了很多奇幻的紋理,

轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/295514.html
標籤:其他
上一篇:Google Earth Engine(GEE)——簡單快速生成圖形chart!
下一篇:分布式架構常見面試問題
