3

我正在建立一個模型,使用週期圖層(GRUs)將字符串轉換爲另一個字符串。我已經嘗試了密集型和時間分佈(密集)層作爲最後一層,但我不明白使用return_sequences = True時兩者之間的差異,特別是因爲它們看起來具有相同數量的參數。時間分佈(密集)與密集在Keras - 相同數量的參數

我的簡化模型如下:

InputSize = 15 
MaxLen = 64 
HiddenSize = 16 

inputs = keras.layers.Input(shape=(MaxLen, InputSize)) 
x = keras.layers.recurrent.GRU(HiddenSize, return_sequences=True)(inputs) 
x = keras.layers.TimeDistributed(keras.layers.Dense(InputSize))(x) 
predictions = keras.layers.Activation('softmax')(x) 

網絡的總結是:

_________________________________________________________________ 
Layer (type)     Output Shape    Param # 
================================================================= 
input_1 (InputLayer)   (None, 64, 15)   0   
_________________________________________________________________ 
gru_1 (GRU)     (None, 64, 16)   1536  
_________________________________________________________________ 
time_distributed_1 (TimeDist (None, 64, 15)   255  
_________________________________________________________________ 
activation_1 (Activation) (None, 64, 15)   0   
================================================================= 

這是有道理的,以我爲我的TimeDistributed的理解是,它適用於同一層的所有時間點,所以密集層有16 * 15 + 15 = 255個參數(權重+偏差)。

但是,如果我切換到一個簡單的緻密層:

inputs = keras.layers.Input(shape=(MaxLen, InputSize)) 
x = keras.layers.recurrent.GRU(HiddenSize, return_sequences=True)(inputs) 
x = keras.layers.Dense(InputSize)(x) 
predictions = keras.layers.Activation('softmax')(x) 

我仍然只有255個參數:

_________________________________________________________________ 
Layer (type)     Output Shape    Param # 
================================================================= 
input_1 (InputLayer)   (None, 64, 15)   0   
_________________________________________________________________ 
gru_1 (GRU)     (None, 64, 16)   1536  
_________________________________________________________________ 
dense_1 (Dense)    (None, 64, 15)   255  
_________________________________________________________________ 
activation_1 (Activation) (None, 64, 15)   0   
================================================================= 

我不知道這是因爲密集()將只使用最後維度的形狀,並將其他所有內容有效地視爲批量維度。但是,我不確定密集和TimeDistributed(密集)之間有什麼不同。

更新看着https://github.com/fchollet/keras/blob/master/keras/layers/core.py它似乎是密集使用最後一個維度只大小本身:

def build(self, input_shape): 
    assert len(input_shape) >= 2 
    input_dim = input_shape[-1] 

    self.kernel = self.add_weight(shape=(input_dim, self.units), 

它還使用keras.dot申請權:

def call(self, inputs): 
    output = K.dot(inputs, self.kernel) 

的keras.dot意味着它可以很好地處理n維張量。我想知道它的確切行爲是否意味着Dense()將在每個時間步驟被調用。如果是這樣,這個問題仍然是TimeDistributed()在這種情況下實現的。

+0

讓我補充一點,這兩個模型在訓練過程中的表現幾乎完全相同。 – thon

+0

我也一直在想。所以你確認了Dense()和TimeDistributed(Dense())在你的情況下具有相同的性能?我認爲更好的API設計將允許用戶設置參數,無論是在時間步上使用相同的密集層,還是在每個時間步使用單獨的密集層。 – ymeng

回答

2

在GRU/LSTM單元展開期間,TimeDistributedDense對每個時間步都應用相同的密度。所以誤差函數將在預測標籤序列和實際標籤序列之間。 (這通常是序列標籤問題的順序要求)。

但是,在return_sequences = False的情況下,密集層僅在最後一個單元處應用一次。當RNN用於分類問題時通常是這種情況。如果return_sequences = True,則緊密層將應用於每個時間步,就像TimeDistributedDense一樣。

因此,根據您的模型,兩者都是相同的,但如果您將第二個模型更改爲「return_sequences = False」,那麼密度將僅應用於最後一個單元格。嘗試改變它,模型會拋出錯誤,因爲那麼Y的大小就是[Batch_size,InputSize],它不再是一個序列序列,而是一個完整序列來標記問題。

from keras.models import Sequential 
from keras.layers import Dense, Activation, TimeDistributed 
from keras.layers.recurrent import GRU 
import numpy as np 

InputSize = 15 
MaxLen = 64 
HiddenSize = 16 

OutputSize = 8 
n_samples = 1000 

model1 = Sequential() 
model1.add(GRU(HiddenSize, return_sequences=True, input_shape=(MaxLen, InputSize))) 
model1.add(TimeDistributed(Dense(OutputSize))) 
model1.add(Activation('softmax')) 
model1.compile(loss='categorical_crossentropy', optimizer='rmsprop') 


model2 = Sequential() 
model2.add(GRU(HiddenSize, return_sequences=True, input_shape=(MaxLen, InputSize))) 
model2.add(Dense(OutputSize)) 
model2.add(Activation('softmax')) 
model2.compile(loss='categorical_crossentropy', optimizer='rmsprop') 

model3 = Sequential() 
model3.add(GRU(HiddenSize, return_sequences=False, input_shape=(MaxLen, InputSize))) 
model3.add(Dense(OutputSize)) 
model3.add(Activation('softmax')) 
model3.compile(loss='categorical_crossentropy', optimizer='rmsprop') 

X = np.random.random([n_samples,MaxLen,InputSize]) 
Y1 = np.random.random([n_samples,MaxLen,OutputSize]) 
Y2 = np.random.random([n_samples, OutputSize]) 

model1.fit(X, Y1, batch_size=128, nb_epoch=1) 
model2.fit(X, Y1, batch_size=128, nb_epoch=1) 
model3.fit(X, Y2, batch_size=128, nb_epoch=1) 

print(model1.summary()) 
print(model2.summary()) 
print(model3.summary()) 

在MODEL1和MODEL2的上述示例性架構是樣品(序列到序列模型)和model3是一個完整的序列標籤模型。

+0

謝謝你的回答。我不確定我可以跟隨,但我知道這兩種情況下的輸出都是一個序列。在這兩種情況下,遞歸層都有return_sequences = True,並且兩種情況下的輸出形狀都是3D並且完全相同(batch_size,64,15)。所以在我看來,密集層也適用於每個時間步驟。 – thon

+0

我已經用更好的解釋更新了我的答案,希望它對你有所幫助。 – mujjiga

+0

謝謝。爲了避免疑問,當你說「因爲你的模型都是一樣的,但如果你改變你的第二個模型爲」return_sequences = True「,那麼密度將只應用在最後一個單元格。」 - 你是說如果我把return_sequences改成False? 你的答案似乎意味着如果return_sequences爲True,Dense()和TimeDistributed(Dense())完全一樣。你能證實這一點嗎?這是有道理的,但爲什麼Keras需要TimeDistributed()呢? – thon