深度學習第四周--第四課人臉識別、神經風格轉移代碼

聲明

本文參考何寬

前言

本文的結構:

  • 人臉識別:1對多
  • 人臉驗證:1對1
  • 神經風格遷移

人臉識別

  • 人臉驗證:這是不是本人,比如在某些機場你能夠讓系統掃描你的面部並驗證你是否爲本人從而使得你免人工檢票通過海關,又或者某些手機能夠使用人臉解鎖功能。這都是1對1匹配問題。
  • 人臉識別:這個人是誰,比如說,在視頻中的百度員工進入辦公室時的臉部識別視頻的介紹,無需使用另外的id卡。這是1對多的匹配問題
    facenet可以將人臉圖像編碼爲一個128位數字的向量從而進行學習,通過比較兩個這樣的向量,那麼就可以確定這兩張圖片是否是屬於同一個人。
    本節的結構:
  • 實現三元組損失函數
  • 使用一個已經訓練好了的模型來將人臉圖像映射到一個128位數字的向量
  • 使用這些編碼來執行人臉驗證和人臉識別
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 sys
import scipy.io
import scipy.misc
import numpy as np
from numpy import genfromtxt
import pandas as pd
import tensorflow as tf
import fr_utils
from inception_blocks_v2 import *

%matplotlib inline
%load_ext autoreload
%autoreload 2

np.set_printoptions(threshold=np.nan)

簡單的人臉驗證

在人臉驗證中,需要給出兩張照片並想知道是否是同一個人,最簡單的方法是逐像素地比較這兩幅圖像,如果圖片之間的誤差小於選擇的閾值,那麼則可能是同一個人。

將人臉圖像編碼爲128位的向量

使用卷積網絡來進行編碼

  • 該網絡使用了96x96的RGB圖像作爲輸入數據,圖像數量爲m,輸入的數據維度爲(m,nc,nh,nw)=(m,3,96,96)(m,n_c,n_h,n_w)=(m,3,96,96)
  • 輸出爲(m,128)的已經編碼的m個128位的向量
FRmodel = faceRecoModel(input_shape=(3,96,96))
print(FRmodel.count_params())

結果:

3743280

繪製模型細節:

plot_model(FRmodel,to_file="FRmodel.png")
SVG(model_to_dot(FRmodel).create(prog='dot',format='svg'))

結果:
略。
通過使用128神經元全連接層作爲最後一層,該模型確保輸出是大小爲128的編碼向量,然後使用比較兩個人臉圖像的編碼如下:
在這裏插入圖片描述
如果滿足下面兩個條件,編碼是一個比較好的方法:

  • 同一個人的兩個圖像的編碼非常相似
  • 兩個不同人物的圖像的編碼非常不同

三元組損失函數將實現上面的內容,它會是圖將同一個人的兩個圖像編碼拉近,同時將兩個不同的人的圖像進一步分離。
在這裏插入圖片描述

三元組損失函數

對於給定的圖像x,其編碼爲f(x),其中f爲神經網絡的計算函數。
將使用三元組圖像(A,P,N)進行訓練:

  • A是anchor,是一個人的圖像
  • P是positive,是相對於anchor的同一個人的另外一張圖像
  • N是negative,是相對於anchor的不同的人的另外一張圖像。
  • 這些三元組來自訓練集,使用(A(i),P(i),N(i))(A^{(i)},P^{(i)},N^{(i)})來表示第i個訓練樣本。要保證A(i)A^{(i)}與圖像P(i)P^{(i)}的差值至少比圖像N(i)N^{(i)}的差值相差α\alpha

f(A(i)f(P(i))22+α<f(A(i)f(N(i))22||f(A^{(i)}-f(P^{(i)})||_2^2+\alpha < ||f(A^{(i)}-f(N^{(i)})||_2^2
讓三元組損失變爲最小:
J=i=1m[f(A(i)f(P(i))22f(A(i)f(N(i))22+α]+J=\sum_{i=1}^m[||f(A^{(i)}-f(P^{(i)})||_2^2-||f(A^{(i)}-f(N^{(i)})||_2^2+\alpha]_+

  • 使用[...]+[...]_+來表示函數max(z,0)
  • 給定三元組A與正例P之間的距離的平方,要讓它變小
  • 給定三元組A與負例N之間的距離的平方,要讓它變大
  • α\alpha是間距,這個需要手動選擇,這裏使用α=0.2\alpha=0.2
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()))

結果:

loss = 528.1432

加載訓練好了的模型

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

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

#加載權值
fr_utils.load_weights_from_FaceNet(FRmodel)

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

#計算時差
minium = end_time - start_time

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

結果:

執行了:148

模型的應用

人臉驗證

將用字典來存儲數據,代表一個數據庫。

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

當有人出現在你的門前刷他們的身份證時,你可以在數據庫中查找他們的編碼,用它來檢測站在門前的人是否與身份證上的名字匹配。
要實現verify()函數來驗證攝像頭的照片(image_path)是否與身份證上的名稱匹配。

  • 根據image_path來計算編碼
  • 計算與存儲在數據庫中的身份圖像的編碼的差距
  • 如果差距小於0.7,那麼就開門,否則不開門
def verify(image_path,identity,database,model):
    """
    對“identity”與“image_path”的編碼進行人臉驗證
    
    參數:
        imgae_path - 攝像頭的圖片
        identity - 字符類型,想要驗證的人的名字
        database - 字典類型,包含了成員的名字信息與對應的編碼
        model - 在keras的模型的實例
    返回:
        dist - 攝像頭的圖片與數據庫中的圖片的編碼的差距
        is_open_door - boolean,是否該開門
    """
    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

測試:

verify("images/camera_0.jpg","younes",database,FRmodel)

結果:

歡迎younes回家!
(0.06747335, True)

測試:

verify("images/camera_2.jpg","kian",database,FRmodel)

結果:

經驗證,您與kian不符!
(0.86224037, False)

人臉識別

步驟:
1、根據image_path計算圖像的編碼
2、從數據庫中找出與目標編碼具有最小差距的編碼
- 計算目標編碼與當前數據庫編碼之間的L2差距
- 如果差距小於min_dist,那麼就更新名字與編碼到identity與min_dist中。

def who_is_it(image_path,database,model):
    """
    根據指定的圖片來進行人臉識別
    
    參數:
        images_path - 圖像地址
        database - 包含了名字與編碼的字典
        model - 在keras中的模型的實例
    返回:
        min_dist - 在數據庫中與指定圖像最相近的編碼
        identity - 字符串類型,與min_dist編碼相對應的名字
    """
    encoding = fr_utils.img_to_encoding(image_path,model)
    min_dist = 100
    
    for(name,db_enc) in database.items():
        dist = np.linalg.norm(encoding-db_enc)
        
        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

測試:

who_is_it("images/camera_0.jpg",database,FRmodel)

結果:

姓名younes 差距:0.06747335
(0.06747335, 'younes')

神經風格轉移

本節結構:

  • 實現神經風格轉換算法
  • 用算法生成新的藝術圖像
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

遷移學習

遷移學習:神經風格轉換(NST)使用先前訓練好了的卷積網絡,並在此基礎之上進行構建,使用在不同任務上訓練的網絡並將其應用於新任務的想法。
因此我們將使用VGG網絡,先從VGG模型加載參數。

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

print(model)

結果:

{'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>}

該模型存儲在一個python字典中,其中每個變量名都是鍵,相應的值是一個包含該變量值的張量,要通過此網絡運行圖像,只需將圖像提供給模型,在tensorflow中,可以使用tf.assign函數來實現。

model["input"].assign(image)

這將圖片作爲輸入給模型,在此之後,如果想要訪問某個特定層的激活,比如4_2,

sess.run(model["conv4_2"])

神經風格轉換

步驟:

  • 構建內容損失函數J_{content}(C,G)
  • 構建風格損失函數J_{style}(S,G)
  • 把它放在一起得到J(G)=αJcontent(C,G)+βJ(style)(S,G)J(G)=\alpha J_{content}(C,G)+\beta J_{(style)}(S,G)

計算內容損失

content_image = scipy.misc.imread("images/louvre.jpg")
imshow(content_image)

在這裏插入圖片描述

如何確保生成的圖像G與圖像C的內容匹配

淺層的一個卷積網絡往往檢測到較低層次的特徵,如邊緣和簡單的紋理,更深層的往往檢測更高層次的特徵,如更復雜的紋理以及對象分類等。
希望生成的圖像G具有與輸入圖像C相似的內容,假設我們選擇了一些層的激活來表示圖像的內容,在實踐中,如果你在網絡中間選擇一個層–既不太淺也不太深,你會得到最好的視覺結果。
假設你選擇了一個特殊的隱藏層,將圖像C作爲已經訓練好的VGG網絡的輸入,然後進行前向傳播,讓a(C)a^{(C)}成爲你選擇的層中的隱藏層激活,激活值爲nH,nW,nCn_H,n_W,n_C的張量,然後用圖像G重複這個過程:將G設置爲輸入數據,並進行前向傳播,讓a(G)a^{(G)}成爲相應的隱層激活,將把內容成本函數定義爲:
Jcontent(C,G)=14×nH×nW×nC(a(C)a(G))2J_{content}(C,G)=\frac{1}{4 \times n_H \times n_W \times n_C}\sum_{所有條目}(a^{(C)}-a^{(G)})^2

步驟:

  • 從a_G中獲取維度信息:
    • 從張量X中獲取維度信息,可以使用:X.get_shape().as_list()
  • 將a_C與a_G如上圖一樣降維:
  • 計算內容代價
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計算的值。
    """
    m,n_H,n_W,n_C = a_G.get_shape().as_list()
    
    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)))
    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.eval())
    
    test.close()

結果:

6.7655935

計算風格損失

先看看風格圖片:

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

在這裏插入圖片描述

風格矩陣

風格矩陣也被叫做gram矩陣,Gij=viTvj=np.dot(vi,vj)G_{ij}=v_i^Tv_j=np.dot(v_i,v_j),換句話說,GijG_{ij}比較了ViV_iVjV_j的相似度,如果非常相似,則GijG_{ij}會非常大。

def gram_matrix(A):
    """
    參數:
        A - 維度(n_C,n_H*n_W)
    返回:
        GA - 維度(n_C,n_C)
    """
    GA = tf.matmul(A,A,transpose_b = True)
    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.eval())
    
    test.close()

結果:

[[ 6.422305 -4.429122 -2.096682]
 [-4.429122 19.465837 19.563871]
 [-2.096682 19.563871 20.686462]]

風格代價值

def compute_layer_style_cost(a_S,a_G):
    """
    參數:
        a_S -  tensor類型,維度爲(1,n_H,n_W,n_C),表示隱藏層中圖像S的內容的激活值
        a_G -  tensor類型,維度爲(1,n_H,n_W,n_C),表示隱藏層中圖像G的內容的激活值
    返回:
        J_style_layer - 實數
    """
    m,n_H,n_W,n_C = a_G.get_shape().as_list()
    
    a_S = tf.transpose(tf.reshape(a_S,[n_H*n_W,n_C]))
    a_G = tf.transpose(tf.reshape(a_G,[n_H*n_W,n_C]))
    
    GS = gram_matrix(a_S)
    GG = gram_matrix(a_G)
    
    J_style_layer = 1/(4*n_C*n_C*n_H*n_H*n_W*n_W)*tf.reduce_sum(tf.square(tf.subtract(GS,GG)))
    
    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.eval())
    
    test.close()

結果:

9.190278

風格權重

到目前爲止你已經從一層捕捉了風格,我們將得到更好的結果如果我們合成不同層的風格代價

STYLE_LAYERS = [
    ('conv1_1',0.2),
    ('conv2_1',0.2),
    ('conv3_1',0.2),
    ('conv4_1',0.2),
    ('conv5_1',0.2)
]

測試:

def compute_style_cost(model,STYLE_LAYERS):
    """
    對一些所選的層計算整體風格代價值
    
    參數:
        model - 我們的tensorflow模型
        STYLE_LAYERS - 一個python字典,包含:
                            - 我們將要抽取的層的名字
                            - 每層的係數
    返回:
        J_style - 實數,風格代價值
    """
    J_style = 0
    
    for layer_name,coeff in STYLE_LAYERS:
        out = model[layer_name]
        
        a_S = sess.run(out)
        
        a_G = out
        
        J_style_layer = compute_layer_style_cost(a_S,a_G)
        
        J_style += coeff*J_style_layer
        
    return J_style

計算總的代價值

def total_cost(J_content,J_style,alpha=10,beta=40):
    """
    計算總體代價值
    
    參數:
        J_content - 內容圖片的代價函數值
        J_style - 風格圖片的代價函數值
    返回:
        J - 生成圖片的代價函數值
    """
    J = alpha*J_content+beta*J_style
    return J

測試:

tf.reset_default_graph()

with tf.Session() as test:
    tf.set_random_seed(3)
    J_content = np.random.randn()
    J_style = np.random.randn()
    J = total_cost(J_content,J_style)
    
    print(J)
    
    test.close()

結果:

7.777902537135693

整合模型

tf.reset_default_graph()
sess = tf.InteractiveSession()

加載,重塑,並且歸一化我們的內容圖片

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

加載,重塑,並且歸一化我們的風格圖片

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

初始化生成圖片

generated_image = nst_utils.generate_noise_image(content_image)
imshow(generated_image[0])

在這裏插入圖片描述

model = nst_utils.load_vgg_model("pretrained-model/imagenet-vgg-verydeep-19.mat")
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
            save_image("output/" + str(i) + ".png", generated_image)
    
    # save last generated image
    save_image('output/generated_image.jpg', generated_image)
    
    return generated_image

測試:

model_nn(sess,generated_image)

結果:

Iteration 0 :
total cost = 5050363000.0
content cost = 7877.6846
style cost = 126257096.0
Iteration 20 :
total cost = 943313150.0
content cost = 15187.001
style cost = 23579032.0
Iteration 40 :
total cost = 484989150.0
content cost = 16786.635
style cost = 12120532.0
Iteration 60 :
total cost = 312592860.0
content cost = 17466.723
style cost = 7810455.5
Iteration 80 :
total cost = 228137340.0
content cost = 17715.082
style cost = 5699005.0
Iteration 100 :
total cost = 180674600.0
content cost = 17899.586
style cost = 4512390.0
Iteration 120 :
total cost = 149986480.0
content cost = 18028.668
style cost = 3745154.8
Iteration 140 :
total cost = 127735700.0
content cost = 18187.12
style cost = 3188845.5
Iteration 160 :
total cost = 110698030.0
content cost = 18348.55
style cost = 2762863.5
Iteration 180 :
total cost = 97329440.0
content cost = 18492.033
style cost = 2428613.0
array([[[[ -47.661247  ,  -61.453     ,   48.561188  ],
         [ -26.120216  ,  -40.544724  ,   26.910763  ],
         [ -41.77308   ,  -28.989634  ,   11.353765  ],
         ...,
         [ -26.790583  ,   -9.504678  ,   14.301171  ],
         [ -30.215399  ,   -2.8596127 ,   24.095652  ],
         [ -42.33818   ,   -4.012277  ,   49.331726  ]],

        [[ -61.118427  ,  -51.75015   ,   24.926647  ],
         [ -33.086437  ,  -31.065102  ,   -1.5538673 ],
         [ -27.143728  ,  -30.632084  ,   15.239879  ],
         ...,
         [ -26.743525  ,   -5.237683  ,   25.955444  ],
         [ -21.374044  ,  -16.847229  ,   14.027954  ],
         [ -40.673164  ,   -5.9413986 ,    9.634444  ]],

        [[ -52.304245  ,  -51.58418   ,   13.43408   ],
         [ -37.243927  ,  -41.448124  ,   -6.3468766 ],
         [ -34.209667  ,  -25.22445   ,    7.3981633 ],
         ...,
         [ -10.557919  ,  -37.255943  ,   12.633695  ],
         [ -12.206678  ,  -20.861652  ,   17.274206  ],
         [ -22.465885  ,  -18.398954  ,   14.384765  ]],

        ...,

        [[ -48.962467  ,  -54.37402   ,  -37.02361   ],
         [ -98.60941   ,  -77.45595   , -268.76196   ],
         [ -76.595856  ,  -72.34538   , -142.87724   ],
         ...,
         [ -70.069145  ,  -70.115875  ,  -28.93214   ],
         [ -79.74132   ,  -87.88023   ,  -22.402292  ],
         [   1.5839    ,  -39.094883  ,   24.227371  ]],

        [[  -0.35573652,  -74.69128   ,   14.360605  ],
         [-174.65245   , -102.71579   ,  -30.584835  ],
         [   5.712225  ,  -71.335175  ,  -20.298792  ],
         ...,
         [ -95.97943   ,  -84.18833   ,  -47.554455  ],
         [-102.51056   , -102.616905  ,  -59.301193  ],
         [ -65.34055   ,  -95.03536   ,    2.391805  ]],

        [[  50.225525  ,  -21.05201   ,   52.79938   ],
         [  31.640673  ,  -84.51524   ,   26.54396   ],
         [  29.929949  ,  -40.645756  ,   17.317034  ],
         ...,
         [ -99.936295  , -108.1952    ,  -17.179901  ],
         [-117.799355  , -144.73357   ,  -27.593529  ],
         [ -25.0283    , -104.69802   ,   21.219383  ]]]], dtype=float32)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章