tensorflow2.1.0——如何構建網絡(二)

一、構建網絡的第二種方式

  • 通過輸入層和輸出層來構建網絡,網絡包含輸入和輸出中間的隱藏層,這會返回一個Model對象,通過該對象可以調用model.compile和model.fit函數,非常方便。
import tensorflow as tf
import tensorflow.keras.layers

x = layers.Input(shape=(784,))  # 輸入層,shape可自己定義
h_1 = layers.Dense(x)  # 隱藏層
h_2 = layers.Conv2D(h1)  # 隱藏層
... # 你可以定義任意多的層,每個層可以是任意種類
h_n = layers.Dense(h_n_1) # h_n_1表示第n-1層隱藏層
out = layers.Dense(h_n)  # 輸出層

# 構建網絡
model = Model(x,out) 

二、對比第一種構建網絡方式

第一種方式

1. 第二種方式的優點

  • 建立模型更加的泛化,更加通俗易懂
    ①第一種使用Squential來構建網絡,非常的無腦簡單,但是當我們需要Squential中間某些層的量來計算一些東西時,此時會變得比較複雜,例如VAE中要在encoder部分計算KL散度,需要對encoder網絡的輸出做一個函數變換,這其實變得優點困難,當然我們也可以自定義層(熟練之後),也可以使用lambda層,但無疑這回增加我們的難度;
    ②第二種構建方式,可以很巧妙的利用這些隱藏層的結果去做一些事情,例如構建loss,下面展示一下這種巧妙方式在VAE中是如何應用的。
    ③第二種構建模型的方式依然可以使用model.compile和model.fit函數,有幾方面的原因:
    (1)整個模型就一個model(因爲有的模型會有兩個model,例如GAN)
    (2)整個構建過程最終返回的是一個Model()對象,所以可以調用類的方法compile和fit。
# 定義自己的模型
latent_dimension = 50

# 定義重採樣函數,方便lambda使用
def sampling(agrs):
    mean,logvar = agrs[0],agrs[1]
    eps = tf.random.normal(tf.shape(mean))
    
    return mean + eps*tf.exp(logvar * 0.5)


# 編碼階段    
x = layers.Input(shape=(784*2,))  # 輸入層
    
h1 = layers.Dense(200,activation='softplus')(x)
h2 = layers.Dense(200,activation='softplus')(h1)
# 均值和方差層不需要激活函數
mean = layers.Dense(latent_dimension)(h2)
log_var = layers.Dense(latent_dimension)(h2)
    
# 將採樣過程看成一個Lambda層
z = layers.Lambda(sampling,output_shape=(latent_dimension,))([mean,log_var])
    
# 解碼階段
h3 = layers.Dense(200,activation='softplus')
h4 = layers.Dense(200,activation='softplus')
h5 = layers.Dense(200,activation='softplus')
# No activation
end = layers.Dense(784)
z1 = h3(z)
z2 = h4(z1)
z3 = h5(z2)
out = end(z3) # 輸出層
    
# 建立模型
model = tf.keras.Model(x,out)

#構建損失函數,這裏用到了網絡結構中隱藏層的信息:均值和方差    
cross_ent = tf.reduce_sum(tf.nn.sigmoid_cross_entropy_with_logits(labels=tf.split(x,num_or_size_splits=2,axis=-1)[0],logits=out),axis=-1) # 重構誤差
KL = -tf.reduce_sum(1+log_var-tf.square(mean)-tf.exp(log_var),axis=-1)
dvae_loss = tf.reduce_mean(cross_ent + KL)
model.add_loss(dvae_loss)

# 編譯
model.compile(optimizer='adam')
# fit
history = model.fit(train_dataset,epochs=80,validation_data=test_dataset) 

第二種方式的缺點

  • 相比於第一種建模方式,第二種很繁瑣,同時注意到當我們需要更改網絡結構時,第二種方式改起來也比較繁瑣

第二種方式的使用場景

  • 網絡比較簡單,不然代碼量會很多,不符合寫代碼的準則。例如加入現在我們要構建100層神經網絡,那麼如果用第二種方式,那我選擇die!

總結

  • 網絡結構比較簡單時,方式一和方式二都可以,當網絡結構很複雜時,首選用Squential構建網絡,後面會講比較複雜的用Squential構建網絡,這時候將不能使用compile和fit函數。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章