天天看點

吳恩達深度學習 deeplearning.ai (4-4) 程式設計作業第二部分 - 神經風格轉換深度學習在藝術上的應用:神經風格轉換

本文參考何寬大神的部落格https://blog.csdn.net/u013733326/article/details/80767079

首先先放一下第一個程式設計作業的代碼

from keras.models import Sequential
from keras.layers import Conv2D, ZeroPadding2D, Activation, Input, concatenate
from keras.models import Model
from keras.layers.normalization import BatchNormalization
from keras.layers.pooling import MaxPooling2D, AveragePooling2D
from keras.layers.merge import Concatenate
from keras.layers.core import Lambda, Flatten, Dense
from keras.initializers import glorot_uniform
from keras.engine.topology import Layer
from keras import backend as K
#------------用于繪制模型細節,可選--------------#
from IPython.display import SVG
from keras.utils.vis_utils import model_to_dot
from keras.utils import plot_model
#------------------------------------------------#

K.set_image_data_format('channels_first')

import time
import cv2
import os
import numpy as np
from numpy import genfromtxt
import pandas as pd
import tensorflow as tf
import fr_utils
from inception_blocks_v2 import *
import matplotlib.pyplot as plt
plt.show()
np.set_printoptions(threshold=np.nan)

#擷取模型
FRmodel = faceRecoModel(input_shape=(3,96,96))
#列印模型的總參數數量
print("參數數量:" + str(FRmodel.count_params()))


def triplet_loss(y_true, y_pred, alpha=0.2):
    """
    根據公式(4)實作三元組損失函數

    參數:
        y_true -- true标簽,當你在Keras裡定義了一個損失函數的時候需要它,但是這裡不需要。
        y_pred -- 清單類型,包含了如下參數:
            anchor -- 給定的“anchor”圖像的編碼,次元為(None,128)
            positive -- “positive”圖像的編碼,次元為(None,128)
            negative -- “negative”圖像的編碼,次元為(None,128)
        alpha -- 超參數,門檻值

    傳回:
        loss -- 實數,損失的值
    """
    # 擷取anchor, positive, negative的圖像編碼
    anchor, positive, negative = y_pred[0], y_pred[1], y_pred[2]

    # 第一步:計算"anchor" 與 "positive"之間編碼的距離,這裡需要使用axis=-1
    pos_dist = tf.reduce_sum(tf.square(tf.subtract(anchor, positive)), axis=-1)

    # 第二步:計算"anchor" 與 "negative"之間編碼的距離,這裡需要使用axis=-1
    neg_dist = tf.reduce_sum(tf.square(tf.subtract(anchor, negative)), axis=-1)

    # 第三步:減去之前的兩個距離,然後加上alpha
    basic_loss = tf.add(tf.subtract(pos_dist, neg_dist), alpha)

    # 通過取帶零的最大值和對訓練樣本的求和來計算整個公式
    loss = tf.reduce_sum(tf.maximum(basic_loss, 0))

    return loss


with tf.Session() as test:
    tf.set_random_seed(1)
    y_true = (None, None, None)
    y_pred = (tf.random_normal([3, 128], mean=6, stddev=0.1, seed=1),
              tf.random_normal([3, 128], mean=1, stddev=1, seed=1),
              tf.random_normal([3, 128], mean=3, stddev=4, seed=1))
    loss = triplet_loss(y_true, y_pred)

    print("loss = " + str(loss.eval()))


#開始時間
start_time = time.process_time()

#編譯模型
FRmodel.compile(optimizer = 'adam', loss = triplet_loss, metrics = ['accuracy'])

#加載權值
fr_utils.load_weights_from_FaceNet(FRmodel)

#結束時間
end_time = time.process_time()

#計算時差
minium = end_time - start_time

print("執行了:" + str(int(minium / 60)) + "分" + str(int(minium%60)) + "秒")
           

輸出結果:

參數數量:3743280
loss = 528.1432
執行了:1分33秒
           

繼續:

def img_to_encoding(image_path, model):
    img1 = cv2.imread(image_path, 1)
    img = img1[...,::-1]
    img = np.around(np.transpose(img, (2,0,1))/255.0, decimals=12)
    x_train = np.array([img])
    embedding = model.predict_on_batch(x_train)
    return embedding
           

人臉驗證

 我們建構一個資料庫,裡面包含了允許進入的人員的編碼向量,我們使用

fr_uitls.img_to_encoding(image_path, model)

函數來生成編碼,它會根據圖像來進行模型的前向傳播。

 我們這裡的資料庫使用的是一個字典來表示,這個字典将每個人的名字映射到他們面部的128維編碼上

database = {}
database["danielle"] = img_to_encoding("images/danielle.png", FRmodel)
database["younes"] = img_to_encoding("images/younes.jpg", FRmodel)
database["tian"] = img_to_encoding("images/tian.jpg", FRmodel)
database["andrew"] = img_to_encoding("images/andrew.jpg", FRmodel)
database["kian"] = img_to_encoding("images/kian.jpg", FRmodel)
database["dan"] = img_to_encoding("images/dan.jpg", FRmodel)
database["sebastiano"] = img_to_encoding("images/sebastiano.jpg", FRmodel)
database["bertrand"] = img_to_encoding("images/bertrand.jpg", FRmodel)
database["kevin"] = img_to_encoding("images/kevin.jpg", FRmodel)
database["felix"] = img_to_encoding("images/felix.jpg", FRmodel)
database["benoit"] = img_to_encoding("images/benoit.jpg", FRmodel)
database["arnaud"] = img_to_encoding("images/arnaud.jpg", FRmodel)
           

現在,當有人出現在你的門前刷他們的身份證的時候,你可以在資料庫中查找他們的編碼,用它來檢查站在門前的人是否與身份證上的名字比對。

 現在我們要實作 verify() 函數來驗證攝像頭的照片(

image_path

)是否與身份證上的名稱比對,這個部分可由以下步驟構成:

  1. 根據

    image_path

    來計算編碼。
  2. 計算與存儲在資料庫中的身份圖像的編碼的差距。
  3. 如果差距小于0.7,那麼就打開門,否則就不開門。

 如上所述,我們使用L2(np.linalg.norm)來計算差距。(注意:在本實作中,将L2的誤差(而不是L2誤差的平方)與門檻值0.7進行比較。)

def verify(image_path, identity, database, model):
    """
    對“identity”與“image_path”的編碼進行驗證。
    
    參數:
        image_path -- 攝像頭的圖檔。
        identity -- 字元類型,想要驗證的人的名字。
        database -- 字典類型,包含了成員的名字資訊與對應的編碼。
        model -- 在Keras的模型的執行個體。
        
    傳回:
        dist -- 攝像頭的圖檔與資料庫中的圖檔的編碼的差距。
        is_open_door -- boolean,是否該開門。
    """
    #第一步:計算圖像的編碼,使用fr_utils.img_to_encoding()來計算。
    encoding = fr_utils.img_to_encoding(image_path, model)
    
    #第二步:計算與資料庫中儲存的編碼的差距
    dist = np.linalg.norm(encoding - database[identity])
    
    #第三步:判斷是否打開門
    if dist < 0.7:
        print("歡迎 " + str(identity) + "回家!")
        is_door_open = True
    else:
        print("經驗證,您與" + str(identity) + "不符!")
        is_door_open = False
    
    return dist, is_door_open
           

現在younes在門外,相機已經拍下了照片并存放在了(“images/camera_0.jpg”),現在我們來驗證一下~

吳恩達深度學習 deeplearning.ai (4-4) 程式設計作業第二部分 - 神經風格轉換深度學習在藝術上的應用:神經風格轉換
  • verify("images/camera_0.jpg","younes",database,FRmodel)
               
  • 運作:
    吳恩達深度學習 deeplearning.ai (4-4) 程式設計作業第二部分 - 神經風格轉換深度學習在藝術上的應用:神經風格轉換
  • Benoit已經被禁止進入,也從資料庫中删除了自己的資訊,他偷了Kian的身份證并試圖通過門禁,我們來看看他能不能進入呢?
    吳恩達深度學習 deeplearning.ai (4-4) 程式設計作業第二部分 - 神經風格轉換深度學習在藝術上的應用:神經風格轉換
    verify("images/camera_2.jpg", "kian", database, FRmodel)
               
    運作:
    吳恩達深度學習 deeplearning.ai (4-4) 程式設計作業第二部分 - 神經風格轉換深度學習在藝術上的應用:神經風格轉換

人臉識别

 面部驗證系統基本運作良好,但是自從Kian的身份證被偷後,那天晚上他回到房子那裡就不能進去了!為了減少這種惡作劇,你想把你的面部驗證系統更新成面部識别系統。這樣就不用再帶身份證了,一個被授權的人隻要走到房子前面,前門就會自動為他們打開!

 我們将實作一個人臉識别系統,該系統将圖像作為輸入,并确定它是否是授權人員之一(如果是,是誰),與之前的人臉驗證系統不同,我們不再将一個人的名字作為輸入的一部分。

 現在我們要實作

who_is_it()

函數,實作它需要有以下步驟:

  1. 根據image_path計算圖像的編碼。
  2. 從資料庫中找出與目标編碼具有最小差距的編碼。
    • 初始化

      min_dist

      變量為足夠大的數字(100),它将找到與輸入的編碼最接近的編碼。
    • 周遊資料庫中的名字與編碼,可以使用

      for (name, db_enc) in database.items()

      語句。
      • 計算目标編碼與目前資料庫編碼之間的L2差距。
      • 如果差距小于min_dist,那麼就更新名字與編碼到identity與min_dist中.
def who_is_it(image_path, database,model):
    """
    根據指定的圖檔來進行人臉識别
    
    參數:
        images_path -- 圖像位址
        database -- 包含了名字與編碼的字典
        model -- 在Keras中的模型的執行個體。
        
    傳回:
        min_dist -- 在資料庫中與指定圖像最相近的編碼。
        identity -- 字元串類型,與min_dist編碼相對應的名字。
    """
    #步驟1:計算指定圖像的編碼,使用fr_utils.img_to_encoding()來計算。
    encoding = fr_utils.img_to_encoding(image_path, model)
    
    #步驟2 :找到最相近的編碼
    ## 初始化min_dist變量為足夠大的數字,這裡設定為100
    min_dist = 100
    
    ## 周遊資料庫找到最相近的編碼
    for (name,db_enc) in database.items():
        ### 計算目标編碼與目前資料庫編碼之間的L2差距。
        dist = np.linalg.norm(encoding - db_enc)
        
        ### 如果差距小于min_dist,那麼就更新名字與編碼到identity與min_dist中。
        if dist < min_dist:
            min_dist = dist
            identity = name
    
    # 判斷是否在資料庫中
    if min_dist > 0.7:
        print("抱歉,您的資訊不在資料庫中。")
        
    else:
        print("姓名" + str(identity) + "  差距:" + str(min_dist))
    
    return min_dist, identity
           

Younes站在前門,相機給他拍了張照片(“images/camera_0.jpg”)。讓我們看看who_it_is()算法是否識别Younes。

吳恩達深度學習 deeplearning.ai (4-4) 程式設計作業第二部分 - 神經風格轉換深度學習在藝術上的應用:神經風格轉換
who_is_it("images/camera_0.jpg", database, FRmodel)
           

運作結果:

吳恩達深度學習 deeplearning.ai (4-4) 程式設計作業第二部分 - 神經風格轉換深度學習在藝術上的應用:神經風格轉換

請記住:

  • 人臉驗證解決了更容易的1:1比對問題,人臉識别解決了更難的1∶k比對問題。
  • 三重損失是訓練神經網絡學習人臉圖像編碼的一種有效的損失函數。
  • 相同的編碼可用于驗證和識别。測量兩個圖像編碼之間的距離可以确定它們是否是同一個人的圖檔。

第二部分 - 神經風格轉換

深度學習在藝術上的應用:神經風格轉換

在這裡,我們将:

  • 實作神經風格轉換算法
  • 用算法生成新的藝術圖像

 在之前的學習中我們都是優化了一個成本函數來獲得一組參數值,在這裡我們将優化成本函數以擷取像素值,我們先來導入包:

import time
import os
import sys
import scipy.io
import scipy.misc
import matplotlib.pyplot as plt
from matplotlib.pyplot import imshow
from PIL import Image
import nst_utils
import numpy as np
import tensorflow as tf

%matplotlib inline
           
吳恩達深度學習 deeplearning.ai (4-4) 程式設計作業第二部分 - 神經風格轉換深度學習在藝術上的應用:神經風格轉換

遷移學習

 神經風格轉換(NST)使用先前訓練好了的卷積網絡,并在此基礎之上進行建構。使用在不同任務上訓練的網絡并将其應用于新任務的想法稱為遷移學習。

 根據原始的NST論文(https://arxiv.org/abs/1508.06576 ),我們将使用VGG網絡,具體地說,我們将使用VGG-19,這是VGG網絡的19層版本。這個模型已經在非常大的ImageNet資料庫上進行了訓練,是以學會了識别各種低級特征(淺層)和進階特征(深層)。

 運作以下代碼從VGG模型加載參數。這可能需要幾秒鐘的時間。

model = nst_utils.load_vgg_model("pretrained-model/imagenet-vgg-verydeep-19.mat")

print(model)
           

 運作結果:

Colocations handled automatically by placer.
{'input': <tf.Variable 'Variable:0' shape=(1, 300, 400, 3) dtype=float32_ref>, 'conv1_1': <tf.Tensor 'Relu:0' shape=(1, 300, 400, 64) dtype=float32>, 'conv1_2': <tf.Tensor 'Relu_1:0' shape=(1, 300, 400, 64) dtype=float32>, 'avgpool1': <tf.Tensor 'AvgPool:0' shape=(1, 150, 200, 64) dtype=float32>, 'conv2_1': <tf.Tensor 'Relu_2:0' shape=(1, 150, 200, 128) dtype=float32>, 'conv2_2': <tf.Tensor 'Relu_3:0' shape=(1, 150, 200, 128) dtype=float32>, 'avgpool2': <tf.Tensor 'AvgPool_1:0' shape=(1, 75, 100, 128) dtype=float32>, 'conv3_1': <tf.Tensor 'Relu_4:0' shape=(1, 75, 100, 256) dtype=float32>, 'conv3_2': <tf.Tensor 'Relu_5:0' shape=(1, 75, 100, 256) dtype=float32>, 'conv3_3': <tf.Tensor 'Relu_6:0' shape=(1, 75, 100, 256) dtype=float32>, 'conv3_4': <tf.Tensor 'Relu_7:0' shape=(1, 75, 100, 256) dtype=float32>, 'avgpool3': <tf.Tensor 'AvgPool_2:0' shape=(1, 38, 50, 256) dtype=float32>, 'conv4_1': <tf.Tensor 'Relu_8:0' shape=(1, 38, 50, 512) dtype=float32>, 'conv4_2': <tf.Tensor 'Relu_9:0' shape=(1, 38, 50, 512) dtype=float32>, 'conv4_3': <tf.Tensor 'Relu_10:0' shape=(1, 38, 50, 512) dtype=float32>, 'conv4_4': <tf.Tensor 'Relu_11:0' shape=(1, 38, 50, 512) dtype=float32>, 'avgpool4': <tf.Tensor 'AvgPool_3:0' shape=(1, 19, 25, 512) dtype=float32>, 'conv5_1': <tf.Tensor 'Relu_12:0' shape=(1, 19, 25, 512) dtype=float32>, 'conv5_2': <tf.Tensor 'Relu_13:0' shape=(1, 19, 25, 512) dtype=float32>, 'conv5_3': <tf.Tensor 'Relu_14:0' shape=(1, 19, 25, 512) dtype=float32>, 'conv5_4': <tf.Tensor 'Relu_15:0' shape=(1, 19, 25, 512) dtype=float32>, 'avgpool5': <tf.Tensor 'AvgPool_4:0' shape=(1, 10, 13, 512) dtype=float32>}
           
吳恩達深度學習 deeplearning.ai (4-4) 程式設計作業第二部分 - 神經風格轉換深度學習在藝術上的應用:神經風格轉換

 - 神經風格轉換

 我們可以使用下面3個步驟來建構

神經風格轉換(Neural Style Transfer,NST)

算法:

  • 建構内容損失函數J c o n t e n t ( C , G ) J_{content}(C,G)Jcontent​(C,G)
  • 建構風格損失函數J s t y l e ( S , G ) J_{style}(S,G)Jstyle​(S,G)
  • 把它放在一起得到J ( G ) = α J c o n t e n t ( C , G ) + β J s t y l e ( S , G ) J(G) = \alpha J_{content}(C,G) + \beta J_{style}(S,G)J(G)=αJcontent​(C,G)+βJstyle​(S,G).

計算内容損失

 在我們的運作的例子中,内容圖像C是巴黎盧浮宮博物館的圖檔,運作下面的代碼來看看盧浮宮的圖檔:

content_image = scipy.misc.imread("images/louvre.jpg")
imshow(content_image)
           
吳恩達深度學習 deeplearning.ai (4-4) 程式設計作業第二部分 - 神經風格轉換深度學習在藝術上的應用:神經風格轉換

繼續:

def compute_content_cost(a_C, a_G):
    """
    計算内容代價的函數
    
    參數:
        a_C -- tensor類型,次元為(1, n_H, n_W, n_C),表示隐藏層中圖像C的内容的激活值。
        a_G -- tensor類型,次元為(1, n_H, n_W, n_C),表示隐藏層中圖像G的内容的激活值。
    
    傳回:
        J_content -- 實數,用上面的公式1計算的值。
        
    """
    
    #擷取a_G的次元資訊
    m, n_H, n_W, n_C = a_G.get_shape().as_list()
    
    #對a_C與a_G從3維降到2維
    a_C_unrolled = tf.transpose(tf.reshape(a_C, [n_H * n_W, n_C]))
    a_G_unrolled = tf.transpose(tf.reshape(a_G, [n_H * n_W, n_C]))
    
    #計算内容代價
    #J_content = (1 / (4 * n_H * n_W * n_C)) * tf.reduce_sum(tf.square(tf.subtract(a_C_unrolled, a_G_unrolled)))
    J_content = 1/(4*n_H*n_W*n_C)*tf.reduce_sum(tf.square(tf.subtract(a_C_unrolled, a_G_unrolled)))
    return J_content
tf.reset_default_graph()

with tf.Session() as test:
    tf.set_random_seed(1)
    a_C = tf.random_normal([1, 4, 4, 3], mean=1, stddev=4)
    a_G = tf.random_normal([1, 4, 4, 3], mean=1, stddev=4)
    J_content = compute_content_cost(a_C, a_G)
    print("J_content = " + str(J_content.eval()))
    
    test.close()
           
吳恩達深度學習 deeplearning.ai (4-4) 程式設計作業第二部分 - 神經風格轉換深度學習在藝術上的應用:神經風格轉換

我們先來看一下下面的風格圖檔:

style_image = scipy.misc.imread("images/monet_800600.jpg")

imshow(style_image)
           
吳恩達深度學習 deeplearning.ai (4-4) 程式設計作業第二部分 - 神經風格轉換深度學習在藝術上的應用:神經風格轉換
吳恩達深度學習 deeplearning.ai (4-4) 程式設計作業第二部分 - 神經風格轉換深度學習在藝術上的應用:神經風格轉換

def gram_matrix(A):
    """
    Argument:
    A -- matrix of shape (n_C, n_H*n_W)

    Returns:
    GA -- Gram matrix of A, of shape (n_C, n_C)
    """

    ### START CODE HERE ### (≈1 line)
    GA = tf.matmul(A,tf.transpose(A))
    ### END CODE HERE ###

    return GA
           
tf.reset_default_graph()

with tf.Session() as test:
    tf.set_random_seed(1)
    A = tf.random_normal([3, 2*1], mean=1, stddev=4)
    GA = gram_matrix(A)

    print("GA = " + str(GA.eval()))
           
吳恩達深度學習 deeplearning.ai (4-4) 程式設計作業第二部分 - 神經風格轉換深度學習在藝術上的應用:神經風格轉換
吳恩達深度學習 deeplearning.ai (4-4) 程式設計作業第二部分 - 神經風格轉換深度學習在藝術上的應用:神經風格轉換
# GRADED FUNCTION: compute_layer_style_cost
def compute_layer_style_cost(a_S, a_G):
    """
    Arguments:
    a_S -- tensor of dimension (1, n_H, n_W, n_C), hidden layer activations representing style of the image S
    a_G -- tensor of dimension (1, n_H, n_W, n_C), hidden layer activations representing style of the image G

    Returns:
    J_style_layer -- tensor representing a scalar value, style cost defined above by equation (2)
    """

    ### START CODE HERE ###
    # Retrieve dimensions from a_G (≈1 line)
    m, n_H, n_W, n_C = a_G.get_shape().as_list()

    # Reshape the images to have them of shape (n_H*n_W, n_C) (≈2 lines)
    a_S = tf.reshape(a_S, [n_W*n_H, n_C])
    a_G = tf.reshape(a_G, [n_W*n_H, n_C])

    # Computing gram_matrices for both images S and G (≈2 lines)
    GS = gram_matrix(tf.transpose(a_S))
    GG = gram_matrix(tf.transpose(a_G))
    # GS = gram_matrix(a_S)
    # GG = gram_matrix(a_G)

    # Computing the loss (≈1 line)
    J_style_layer = tf.reduce_sum(tf.square(tf.subtract(GS, GG))) / (4*tf.to_float(tf.square(n_C*n_H*n_W)))

    ### END CODE HERE ###

    return J_style_layer
           
tf.reset_default_graph()

with tf.Session() as test:
    tf.set_random_seed(1)
    a_S = tf.random_normal([1, 4, 4, 3], mean=1, stddev=4)
    a_G = tf.random_normal([1, 4, 4, 3], mean=1, stddev=4)
    J_style_layer = compute_layer_style_cost(a_S, a_G)
    
    print("J_style_layer = " + str(J_style_layer.eval()))
           
吳恩達深度學習 deeplearning.ai (4-4) 程式設計作業第二部分 - 神經風格轉換深度學習在藝術上的應用:神經風格轉換

風格權重

到目前為止,你獲得了一層的風格。如果我們從幾個不同的層“合并”樣式成本,我們會得到更好的結果。在完成這個練習之後,你可以自由地回來嘗試不同的權重,看看它如何改變生成的圖像G。這是一個相當合理的預設值: 

STYLE_LAYERS = [
    ('conv1_1', 0.2),
    ('conv2_1', 0.2),
    ('conv3_1', 0.2),
    ('conv4_1', 0.2),
    ('conv5_1', 0.2)]
           
吳恩達深度學習 deeplearning.ai (4-4) 程式設計作業第二部分 - 神經風格轉換深度學習在藝術上的應用:神經風格轉換
def compute_style_cost(model, STYLE_LAYERS):
    """
    計算幾個標明層的總體風格成本

    參數:
        model -- 加載了的tensorflow模型
        STYLE_LAYERS -- 字典,包含了:
                        - 我們希望從中提取風格的層的名稱
                        - 每一層的系數(coeff)
    傳回:
        J_style - tensor類型,實數,由公式(2)定義的成本計算方式來計算的值。

    """
    # 初始化所有的成本值
    J_style = 0

    for layer_name, coeff in STYLE_LAYERS:

        #選擇目前標明層的輸出
        out = model[layer_name]

        #運作會話,将a_S設定為我們選擇的隐藏層的激活值
        #sess.run實際上是 啟動一個計算
        #在tensorflow中,eval和run都是擷取目前結點的值的一種方式。
		#在使用eval時,若有一個 t 是Tensor對象,調用t.eval()相當于調用sess.run(t)
		#注意:在上面for循環的内循環中,a_G是一個張量,尚未進行評估。 當我們在下面	的model_nn()中運作TensorFlow圖時,它将在每次疊代中被評估和更新。 
        a_S = sess.run(out)

        # 将a_G設定為來自同一圖層的隐藏層激活,這裡a_G引用model[layer_name],并且		還沒有計算,
        # 在後面的代碼中,我們将圖像G指定為模型輸入,這樣當我們運作會話時,
        # 這将是以圖像G作為輸入,從隐藏層中擷取的激活值。
        a_G = out

        #計算目前層的風格成本
        J_style_layer = compute_layer_style_cost(a_S,a_G)

        # 計算總風格成本,同時考慮到系數。
        J_style += coeff * J_style_layer

    return J_style
           
# GRADED FUNCTION: total_cost

def total_cost(J_content, J_style, alpha = 10, beta = 40):
    """
    Computes the total cost function
    
    Arguments:
    J_content -- content cost coded above
    J_style -- style cost coded above
    alpha -- hyperparameter weighting the importance of the content cost
    beta -- hyperparameter weighting the importance of the style cost
    
    Returns:
    J -- total cost as defined by the formula above.
    """
    
    ### START CODE HERE ### (≈1 line)
    J = alpha * J_content + beta * J_style
    ### END CODE HERE ###
    
    return J
           
tf.reset_default_graph()

with tf.Session() as test:
    np.random.seed(3)
    J_content = np.random.randn()    
    J_style = np.random.randn()
    J = total_cost(J_content, J_style)
    print("J = " + str(J))
           
吳恩達深度學習 deeplearning.ai (4-4) 程式設計作業第二部分 - 神經風格轉換深度學習在藝術上的應用:神經風格轉換

初始化TensorFlow graph并在大量疊代中運作它,在每一次疊代中更新生成的圖像。

讓我們詳細地過一遍每個步驟。

你已經實作了總成本J(G)。現在我們将使用TensorFlow來對G進行優化。要做到這一點,你的程式必須重置graph并使用“Interactive Session”。與正常session不同,“Interactive Session”将自己安裝為建構graph的預設session。這允許你運作變量,而不需要經常引用session對象,這簡化了代碼。

讓我們開始Interactive Session吧。

# Reset the graph
tf.reset_default_graph()
# Start interactive session
sess = tf.InteractiveSession()
           

讓我們對“内容”圖像(盧浮宮的圖檔)加載、整形和歸一化操作:

content_image = scipy.misc.imread("images/louvre_small.jpg")
content_image = reshape_and_normalize_image(content_image)
           

讓我們對風格”圖像(莫奈的畫)加載、整形和歸一化操作:

style_image = scipy.misc.imread("images/monet.jpg")
style_image = reshape_and_normalize_image(style_image)
           

現在,我們将“生成的”圖像初始化為從内容圖像建立的帶噪聲圖像。通過初始化生成的圖像的像素,使其主要是噪聲,但仍然與内容圖像有輕微的相關性,這将有助于“生成”圖像的内容更快地比對“内容”圖像的内容。(可以在nst_utils.py中檢視generate_noise_image(…))

generated_image = generate_noise_image(content_image)
plt.imshow(generated_image[0])
           
  • 吳恩達深度學習 deeplearning.ai (4-4) 程式設計作業第二部分 - 神經風格轉換深度學習在藝術上的應用:神經風格轉換

接下來,如第(2)部分所述,讓我們加載VGG16模型。

model = load_vgg_model("pretrained-model/imagenet-vgg-verydeep-19.mat")
           

為了讓程式計算内容成本,我們現在将配置設定一個a_C和一個a_G作為适當的隐含層激活。我們将使用conv4_2層來計算内容成本。下面的代碼做了以下工作:

1. 将内容圖像指定為VGG模型的輸入。

2. 設a_C作為“conv4_2”層的隐含層激活的張量。

3. 設a_G作為同一層的隐含層激活的張量。

4. 使用a_C和a_G計算内容成本。

# Assign the content image to be the input of the VGG model.  
sess.run(model['input'].assign(content_image))

# Select the output tensor of layer conv4_2
out = model['conv4_2']

# Set a_C to be the hidden layer activation from the layer we have selected
a_C = sess.run(out)

# Set a_G to be the hidden layer activation from same layer. Here, a_G references model['conv4_2'] 
# and isn't evaluated yet. Later in the code, we'll assign the image G as the model input, so that
# when we run the session, this will be the activations drawn from the appropriate layer, with G as input.
a_G = out

# Compute the content cost
J_content = compute_content_cost(a_C, a_G)
# Assign the input of the model to be the "style" image 
sess.run(model['input'].assign(style_image))
           
吳恩達深度學習 deeplearning.ai (4-4) 程式設計作業第二部分 - 神經風格轉換深度學習在藝術上的應用:神經風格轉換
## 計算風格成本
J_style = compute_style_cost(model, STYLE_LAYERS)
### START CODE HERE ### (1 line)
J = total_cost(J_content, J_style, 10, 40)
### END CODE HERE ###
optimizer=tf.train.AdamOptimizer(2.0)
#train_step
train_step=optimizer.minimize(J)
           
def model_nn(sess, input_image, num_iterations = 200):

    # Initialize global variables (you need to run the session on the initializer)
    ### START CODE HERE ### (1 line)
    sess.run(tf.global_variables_initializer())
    ### END CODE HERE ###

    # Run the noisy input image (initial generated image) through the model. Use assign().
    ### START CODE HERE ### (1 line)
    sess.run(model["input"].assign(input_image))
    ### END CODE HERE ###

    for i in range(num_iterations):

        # Run the session on the train_step to minimize the total cost
        ### START CODE HERE ### (1 line)
        sess.run(train_step)
        ### END CODE HERE ###

        # Compute the generated image by running the session on the current model['input']
        ### START CODE HERE ### (1 line)
        generated_image =sess.run(model["input"])
        ### END CODE HERE ###

        # Print every 20 iteration.
        if i%20 == 0:
            Jt, Jc, Js = sess.run([J, J_content, J_style])
            print("Iteration " + str(i) + " :")
            print("total cost = " + str(Jt))
            print("content cost = " + str(Jc))
            print("style cost = " + str(Js))

            # save current generated image in the "/output" directory
            nst_utils.save_image("output/" + str(i) + ".png", generated_image)

    # save last generated image
    nst_utils.save_image('output/generated_image.jpg', generated_image)

    return generated_image
           

運作以下程式生成一個藝術圖像。在CPU上運作,每20次疊代大約需要2分鐘的時間。但是在140次疊代之後,你就可以開始觀察有吸引力的結果了。神經風格轉移通常使用gpu進行訓練。

model_nn(sess, generated_image)
           
吳恩達深度學習 deeplearning.ai (4-4) 程式設計作業第二部分 - 神經風格轉換深度學習在藝術上的應用:神經風格轉換

 程式運作完以後,可以在output檔案夾中看到生成的圖像。

用自己的圖像進行測試

1.将自己的圖檔調為(400*300)的大小;

2.将圖檔存入images檔案夾中;

3.修改3.4節中的代碼:

content_image = scipy.misc.imread("images/my_content.jpg")
style_image = scipy.misc.imread("images/my_style.jpg")
           
  • 4.重新運作程式

繼續閱讀