如果我有一个字符串,比如“abc”,其反转后的目标字符串是“cba”。
神经网络,特别是编码器-解码器模型,能否学会这种映射?如果可以,最佳的模型是什么?
我之所以问这个问题,是因为这是一种结构性翻译,而不像普通机器翻译那样只是简单的字符映射。
回答:
如果你的网络是传统的编码器-解码器模型(没有注意力机制),那么,正如@某人所说,它存在内存瓶颈(编码器维度)。因此,这样的网络无法学会反转任意长度的字符串。然而,你可以训练这样的RNN来反转有限长度的字符串。例如,以下玩具级的seq2seq LSTM能够反转长度不超过10的数字序列。以下是如何训练它的方法:
from keras.models import Modelfrom keras.layers import Input, LSTM, Dense, Embeddingimport numpy as npemb_dim = 20latent_dim = 100 # Latent dimensionality of the encoding space.vocab_size = 12 # digits 0-9, 10 is for start token, 11 for end tokenencoder_inputs = Input(shape=(None, ), name='enc_inp')common_emb = Embedding(input_dim=vocab_size, output_dim=emb_dim)encoder_emb = common_emb(encoder_inputs)encoder = LSTM(latent_dim, return_state=True)encoder_outputs, state_h, state_c = encoder(encoder_emb)encoder_states = [state_h, state_c]decoder_inputs = Input(shape=(None,), name='dec_inp')decoder_emb = common_emb(decoder_inputs)decoder_lstm = LSTM(latent_dim, return_sequences=True, return_state=True)decoder_outputs, _, _ = decoder_lstm(decoder_emb, initial_state=encoder_states)decoder_dense = Dense(vocab_size, activation='softmax')decoder_outputs = decoder_dense(decoder_outputs)model = Model([encoder_inputs, decoder_inputs], decoder_outputs)def generate_batch(length=4, batch_size=64): x = np.random.randint(low=0, high=10, size=(batch_size, length)) y = x[:, ::-1] start = np.ones((batch_size, 1), dtype=int) * 10 end = np.ones((batch_size, 1), dtype=int) * 11 enc_x = np.concatenate([start, x], axis=1) dec_x = np.concatenate([start, y], axis=1) dec_y = np.concatenate([y, end], axis=1) dec_y_onehot = np.zeros(shape=(batch_size, length+1, vocab_size), dtype=int) for row in range(batch_size): for col in range(length+1): dec_y_onehot[row, col, dec_y[row, col]] = 1 return [enc_x, dec_x], dec_y_onehotdef generate_batches(batch_size=64, max_length=10): while True: length = np.random.randint(low=1, high=max_length) yield generate_batch(length=length, batch_size=batch_size)model.compile(optimizer='rmsprop', loss='categorical_crossentropy', metrics=['categorical_accuracy'])model.fit_generator(generate_batches(), steps_per_epoch=1000, epochs=20)
现在你可以用它来反转一个序列(我的解码器效率很低,但它确实说明了原理)
input_seq = np.array([[10, 2, 1, 2, 8, 5, 0, 6]])result = np.array([[10]])next_digit = -1for i in range(100): next_digit = model.predict([input_seq, result])[0][-1].argmax() if next_digit == 11: break result = np.concatenate([result, [[next_digit]]], axis=1)print(result[0][1:])
太棒了,它打印出 [6 0 5 8 2 1 2]
!一般来说,你可以将这样的模型视为一种奇怪的自编码器(带有反转的副作用),并选择适合自编码器的架构和训练程序。关于文本自编码器的文献非常丰富。
此外,如果你构建了一个带有注意力机制的编码器-解码器模型,那么它将没有内存瓶颈,因此,理论上,可以用神经网络反转任意长度的序列。然而,注意力机制需要二次计算时间,因此在实践中,即使是带有注意力机制的网络,对于长序列也会非常低效。