【问题标题】:Variable length output in keraskeras中的可变长度输出
【发布时间】:2017-12-20 10:22:26
【问题描述】:

我正在尝试在 keras 中创建一个自动编码器,其中输入和输出具有不同的时间步长。

model = Sequential()

#encoder
model.add(Embedding(vocab_size, embedding_size, mask_zero=True))
model.add(LSTM(units=hidden_size, return_sequences=False))

#decoder
model.add(RepeatVector(max_out_length))
model.add(LSTM(units=hidden_size, return_sequences=True))
model.add(TimeDistributed(Dense(num_class, activation='softmax')))

对于输入没有问题,因为只要整个批次的长度相同,网络就可以接受不同长度的输入。然而,问题在于输出大小由 RepeatVector 长度决定,并且没有简单的方法来改变它。

这样的问题有解决办法吗?

【问题讨论】:

  • 你想要多长?或者它应该遵循什么规则?

标签: deep-learning keras


【解决方案1】:

如果您的意思是“具有可变长度的输入”和“具有与输入相同长度的输出”,您可以这样做:

警告:此解决方案必须适用于批量大小 = 1
您将需要创建一个外部循环并将每个样本作为具有确切长度的 numpy 数组传递
您不能在此解决方案中使用掩码,正确的输出取决于输入的正确长度

这是一个使用 Keras + Tensorflow 的工作代码:

进口:

from keras.layers import *
from keras.models import Model
import numpy as np
import keras.backend as K
from keras.utils.np_utils import to_categorical

在 Lambda 层中使用的自定义函数:

#this function gets the length from the original input 
#and stores it in the final output of the encoder
def storeLength(x):
    inputTensor = x[0]
    storeInto = x[1] #the final output

    length = K.shape(inputTensor)[1]
    length = K.cast(length,K.floatx())
    length = K.reshape(length,(1,1))

    #will put length as the first element in the final output
    return K.concatenate([length,storeInto])


#this function expands the length of the input in the decoder
def expandLength(x):
    #lenght is the first element in the encoded input
    length = K.cast(x[0,0],'int32') #or int64 if necessary

    #the remaining elements are the actual data to be decoded
    data = x[:,1:]

    #a tensor with shape (length,)
    length = K.ones_like(K.arange(0,length))

    #make both length tensor and data tensor 3D and with paired dimensions 
    length = K.cast(K.reshape(length,(1,-1,1)),K.floatx())
    data = K.reshape(data,(1,1,-1))

    #this automatically repeats the elements based on the paired shapes
    return data*length 

创建模型:

我假设输出等于输入,但由于您使用的是嵌入,我使“num_classes”等于单词数。

对于这个解决方案,我们使用了分支,因此我不得不使用函数式 API Model。稍后会更好,因为您将希望使用autoencoder.train_on_batch 进行训练,然后使用encoder.predict() 进行编码或使用decoder.predict() 进行解码。

vocab_size = 100
embedding_size = 7
num_class=vocab_size
hidden_size = 3

#encoder
inputs = Input(batch_shape = (1,None))
outputs = Embedding(vocab_size, embedding_size)(inputs)
outputs = LSTM(units=hidden_size, return_sequences=False)(outputs)
outputs = Lambda(storeLength)([inputs,outputs])
encoder = Model(inputs,outputs)

#decoder
inputs = Input(batch_shape=(1,hidden_size+1))
outputs = Lambda(expandLength)(inputs)
outputs = LSTM(units=hidden_size, return_sequences=True)(outputs)
outputs = TimeDistributed(Dense(num_class, activation='softmax'))(outputs)
decoder = Model(inputs,outputs)

#autoencoder
inputs = Input(batch_shape=(1,None))
outputs = encoder(inputs)
outputs = decoder(outputs)
autoencoder = Model(inputs,outputs)

#see each model's shapes 
encoder.summary()
decoder.summary()
autoencoder.summary()

只是一个假数据的例子和应该用于训练的方法:

inputData = []
outputData = []
for i in range(7,10):
    inp = np.arange(i).reshape((1,i))
    inputData.append(inp)

    outputData.append(to_categorical(inp,num_class))

autoencoder.compile(loss='mse',optimizer='adam')

for epoch in range(1):
    for inputSample,outputSample in zip(inputData,outputData):

        print(inputSample.shape,outputSample.shape)
        autoencoder.train_on_batch(inputSample,outputSample)

for inputSample in inputData:
    print(autoencoder.predict(inputSample).shape)

【讨论】:

  • 澄清一下,您上面提出的编码器是否创建了一个固定长度的特征向量,无论输入长度如何?
  • 没错。但是,由于批量大小的限制,该解决方案并不是“很好”。但是您可以花一些时间通过对非掩码比较求和来检测填充序列的长度。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-11-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多