精华内容
下载资源
问答
  • Keras实现Seq2Seq预测模型

    千次阅读 热门讨论 2019-04-17 14:55:36
    一个基于keras实现seq2seq(Encoder-Decoder)的序列预测例子 序列预测问题描述: 输入序列为随机产生的整数序列,目标序列是对输入序列前三个元素进行反转后的序列,当然这只是我们自己定义的一种形式,可以...

    一个基于keras实现seq2seq(Encoder-Decoder)的序列预测例子

    NLP中常见任务的开源解决方案、数据集、工具、学习资料

    • 序列预测问题描述:
    • 输入序列为随机产生的整数序列,目标序列是对输入序列前三个元素进行反转后的序列,当然这只是我们自己定义的一种形式,可以自定义更复杂的场景。
    输入序列		                目标序列
    [13, 28, 18, 7, 9, 5]		[18, 28, 13]
    [29, 44, 38, 15, 26, 22]	[38, 44, 29]
    [27, 40, 31, 29, 32, 1]		[31, 40, 27]
    ...
    
    • 输入序列与目标序列的构造及向量化
    from numpy import array
    from numpy import argmax
    from keras.utils import to_categorical
     
    # 随机产生在(1,n_features)区间的整数序列,序列长度为n_steps_in
    def generate_sequence(length, n_unique):
    	return [randint(1, n_unique-1) for _ in range(length)]
     
    # 构造LSTM模型输入需要的训练数据
    def get_dataset(n_in, n_out, cardinality, n_samples):
    	X1, X2, y = list(), list(), list()
    	for _ in range(n_samples):
    		# 生成输入序列
    		source = generate_sequence(n_in, cardinality)
    		# 定义目标序列,这里就是输入序列的前三个数据
    		target = source[:n_out]
    		target.reverse()
    		# 向前偏移一个时间步目标序列
    		target_in = [0] + target[:-1]
    		# 直接使用to_categorical函数进行on_hot编码
    		src_encoded = to_categorical(source, num_classes=cardinality)
    		tar_encoded = to_categorical(target, num_classes=cardinality)
    		tar2_encoded = to_categorical(target_in, num_classes=cardinality)
    		
    		X1.append(src_encoded)
    		X2.append(tar2_encoded)
    		y.append(tar_encoded)
    	return array(X1), array(X2), array(y)
     
    # one_hot解码
    def one_hot_decode(encoded_seq):
    	return [argmax(vector) for vector in encoded_seq]
     
    # 输入参数
    n_features = 50 + 1
    n_steps_in = 6
    n_steps_out = 3
    # 生成处理后的输入序列与目标序列,这里测试产生了一个序列样本
    X1, X2, y = get_dataset(n_steps_in, n_steps_out, n_features, 1)
    print(X1.shape, X2.shape, y.shape)
    print('X1=%s, X2=%s, y=%s' % (one_hot_decode(X1[0]), one_hot_decode(X2[0]), one_hot_decode(y[0])))
    
    # 结果如下:
    (1, 6, 51) (1, 3, 51) (1, 3, 51)
    X1=[32, 16, 12, 34, 25, 24], X2=[0, 12, 16], y=[12, 16, 32]
    
    • 构造Seq2Seq模型,参考官网 github
    # 构造Seq2Seq训练模型model, 以及进行新序列预测时需要的的Encoder模型:encoder_model 与Decoder模型:decoder_model
    def define_models(n_input, n_output, n_units):
    	# 训练模型中的encoder
    	encoder_inputs = Input(shape=(None, n_input))
    	encoder = LSTM(n_units, return_state=True)
    	encoder_outputs, state_h, state_c = encoder(encoder_inputs)
    	encoder_states = [state_h, state_c]   #仅保留编码状态向量
    	# 训练模型中的decoder
    	decoder_inputs = Input(shape=(None, n_output))
    	decoder_lstm = LSTM(n_units, return_sequences=True, return_state=True)
    	decoder_outputs, _, _ = decoder_lstm(decoder_inputs, initial_state=encoder_states)
    	decoder_dense = Dense(n_output, activation='softmax')
    	decoder_outputs = decoder_dense(decoder_outputs)
    	model = Model([encoder_inputs, decoder_inputs], decoder_outputs)
    	# 新序列预测时需要的encoder
    	encoder_model = Model(encoder_inputs, encoder_states)
    	# 新序列预测时需要的decoder
    	decoder_state_input_h = Input(shape=(n_units,))
    	decoder_state_input_c = Input(shape=(n_units,))
    	decoder_states_inputs = [decoder_state_input_h, decoder_state_input_c]
    	decoder_outputs, state_h, state_c = decoder_lstm(decoder_inputs, initial_state=decoder_states_inputs)
    	decoder_states = [state_h, state_c]
    	decoder_outputs = decoder_dense(decoder_outputs)
    	decoder_model = Model([decoder_inputs] + decoder_states_inputs, [decoder_outputs] + decoder_states)
        # 返回需要的三个模型
    	return model, encoder_model, decoder_model
    
    • 序列预测过程
    def predict_sequence(infenc, infdec, source, n_steps, cardinality):
    	# 输入序列编码得到编码状态向量
    	state = infenc.predict(source)
    	# 初始目标序列输入:通过开始字符计算目标序列第一个字符,这里是0
    	target_seq = array([0.0 for _ in range(cardinality)]).reshape(1, 1, cardinality)
    	# 输出序列列表
    	output = list()
    	for t in range(n_steps):
    		# predict next char
    		yhat, h, c = infdec.predict([target_seq] + state)
    		# 截取输出序列,取后三个
    		output.append(yhat[0,0,:])
    		# 更新状态
    		state = [h, c]
    		# 更新目标序列(用于下一个词预测的输入)
    		target_seq = yhat
    	return array(output)
    
    • 模型结果评估
    # 评估模型效果
    total, correct = 100, 0
    for _ in range(total):
    	X1, X2, y = get_dataset(n_steps_in, n_steps_out, n_features, 1)
    	target = predict_sequence(infenc, infdec, X1, n_steps_out, n_features)
    	if array_equal(one_hot_decode(y[0]), one_hot_decode(target)):
    		correct += 1
    print('Accuracy: %.2f%%' % (float(correct)/float(total)*100.0))
    
    
    • 模型完整代码
    from numpy import array
    from numpy import argmax
    from numpy import array_equal
    from keras.utils import to_categorical
    from keras.models import Model
    from keras.layers import Input
    from keras.layers import LSTM
    from keras.layers import Dense
     
    # 随机产生在(1,n_features)区间的整数序列,序列长度为n_steps_in
    def generate_sequence(length, n_unique):
    	return [randint(1, n_unique-1) for _ in range(length)]
     
    # 构造LSTM模型输入需要的训练数据
    def get_dataset(n_in, n_out, cardinality, n_samples):
    	X1, X2, y = list(), list(), list()
    	for _ in range(n_samples):
    		# 生成输入序列
    		source = generate_sequence(n_in, cardinality)
    		# 定义目标序列,这里就是输入序列的前三个数据
    		target = source[:n_out]
    		target.reverse()
    		# 向前偏移一个时间步目标序列
    		target_in = [0] + target[:-1]
    		# 直接使用to_categorical函数进行on_hot编码
    		src_encoded = to_categorical(source, num_classes=cardinality)
    		tar_encoded = to_categorical(target, num_classes=cardinality)
    		tar2_encoded = to_categorical(target_in, num_classes=cardinality)
    		
    		X1.append(src_encoded)
    		X2.append(tar2_encoded)
    		y.append(tar_encoded)
    	return array(X1), array(X2), array(y)
     
    # 构造Seq2Seq训练模型model, 以及进行新序列预测时需要的的Encoder模型:encoder_model 与Decoder模型:decoder_model
    def define_models(n_input, n_output, n_units):
    	# 训练模型中的encoder
    	encoder_inputs = Input(shape=(None, n_input))
    	encoder = LSTM(n_units, return_state=True)
    	encoder_outputs, state_h, state_c = encoder(encoder_inputs)
    	encoder_states = [state_h, state_c]   #仅保留编码状态向量
    	# 训练模型中的decoder
    	decoder_inputs = Input(shape=(None, n_output))
    	decoder_lstm = LSTM(n_units, return_sequences=True, return_state=True)
    	decoder_outputs, _, _ = decoder_lstm(decoder_inputs, initial_state=encoder_states)
    	decoder_dense = Dense(n_output, activation='softmax')
    	decoder_outputs = decoder_dense(decoder_outputs)
    	model = Model([encoder_inputs, decoder_inputs], decoder_outputs)
    	# 新序列预测时需要的encoder
    	encoder_model = Model(encoder_inputs, encoder_states)
    	# 新序列预测时需要的decoder
    	decoder_state_input_h = Input(shape=(n_units,))
    	decoder_state_input_c = Input(shape=(n_units,))
    	decoder_states_inputs = [decoder_state_input_h, decoder_state_input_c]
    	decoder_outputs, state_h, state_c = decoder_lstm(decoder_inputs, initial_state=decoder_states_inputs)
    	decoder_states = [state_h, state_c]
    	decoder_outputs = decoder_dense(decoder_outputs)
    	decoder_model = Model([decoder_inputs] + decoder_states_inputs, [decoder_outputs] + decoder_states)
        # 返回需要的三个模型
    	return model, encoder_model, decoder_model
     
    def predict_sequence(infenc, infdec, source, n_steps, cardinality):
    	# 输入序列编码得到编码状态向量
    	state = infenc.predict(source)
    	# 初始目标序列输入:通过开始字符计算目标序列第一个字符,这里是0
    	target_seq = array([0.0 for _ in range(cardinality)]).reshape(1, 1, cardinality)
    	# 输出序列列表
    	output = list()
    	for t in range(n_steps):
    		# predict next char
    		yhat, h, c = infdec.predict([target_seq] + state)
    		# 截取输出序列,取后三个
    		output.append(yhat[0,0,:])
    		# 更新状态
    		state = [h, c]
    		# 更新目标序列(用于下一个词预测的输入)
    		target_seq = yhat
    	return array(output)
     
    # one_hot解码
    def one_hot_decode(encoded_seq):
    	return [argmax(vector) for vector in encoded_seq]
     
    # 参数设置
    n_features = 50 + 1
    n_steps_in = 6
    n_steps_out = 3
    # 定义模型
    train, infenc, infdec = define_models(n_features, n_features, 128)
    train.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['acc'])
    # 生成训练数据
    X1, X2, y = get_dataset(n_steps_in, n_steps_out, n_features, 100000)
    print(X1.shape,X2.shape,y.shape)
    # 训练模型
    train.fit([X1, X2], y, epochs=1)
    # 评估模型效果
    total, correct = 100, 0
    for _ in range(total):
    	X1, X2, y = get_dataset(n_steps_in, n_steps_out, n_features, 1)
    	target = predict_sequence(infenc, infdec, X1, n_steps_out, n_features)
    	if array_equal(one_hot_decode(y[0]), one_hot_decode(target)):
    		correct += 1
    print('Accuracy: %.2f%%' % (float(correct)/float(total)*100.0))
    # 查看预测结果
    for _ in range(10):
    	X1, X2, y = get_dataset(n_steps_in, n_steps_out, n_features, 1)
    	target = predict_sequence(infenc, infdec, X1, n_steps_out, n_features)
    	print('X=%s y=%s, yhat=%s' % (one_hot_decode(X1[0]), one_hot_decode(y[0]), one_hot_decode(target)))
    
    • 结果展示
    100000/100000 [==============================] - 28s 284us/step - loss: 0.6441 - acc: 0.7941
    Accuracy: 99.00%
    X=[16, 14, 28, 22, 9, 17] y=[28, 14, 16], yhat=[28, 14, 16]
    X=[48, 36, 32, 49, 13, 5] y=[32, 36, 48], yhat=[32, 36, 48]
    X=[27, 37, 6, 50, 30, 16] y=[6, 37, 27], yhat=[6, 37, 27]
    X=[7, 7, 4, 45, 6, 16] y=[4, 7, 7], yhat=[4, 7, 7]
    X=[4, 25, 33, 34, 21, 12] y=[33, 25, 4], yhat=[33, 25, 4]
    X=[44, 44, 9, 35, 5, 16] y=[9, 44, 44], yhat=[9, 44, 44]
    X=[20, 29, 3, 7, 17, 29] y=[3, 29, 20], yhat=[3, 29, 20]
    X=[38, 45, 5, 35, 46, 21] y=[5, 45, 38], yhat=[5, 45, 38]
    X=[16, 10, 48, 27, 39, 3] y=[48, 10, 16], yhat=[48, 10, 16]
    X=[16, 45, 7, 45, 29, 25] y=[7, 45, 16], yhat=[45, 45, 16]
    
    • 参考文献
    • https://blog.keras.io/a-ten-minute-introduction-to-sequence-to-sequence-learning-in-keras.html
    • https://machinelearningmastery.com/define-encoder-decoder-sequence-sequence-model-neural-machine-translation-keras/
    • https://machinelearningmastery.com/return-sequences-and-return-states-for-lstms-in-keras/
    • https://machinelearningmastery.com/develop-encoder-decoder-model-sequence-sequence-prediction-keras/
    展开全文
  • 港口进出口货物吞吐量是反映港口业务状况的重要指标,其准确预测...在真实的天津港进出口集装箱数据集上进行了实验,结果表明Seq2Seq模型的深度学习预测方法效果优于传统的时间序列模型以及其他现有的机器学习预测模型.
  • Keras实现带attention的seq2seq预测模型

    千次阅读 2019-04-16 16:44:41
    注意是一种机制,它解决了编码器-解码器体系结构在长序列上的局限性,并且通常加快了学习速度,提高了序列到序列预测问题模型的技能。 在本教程中,您将了解如何在Keras中实现一个带有注意力机制的编码器-解码器...

    参考:https://machinelearningmastery.com/encoder-decoder-attention-sequence-to-sequence-prediction-keras/

    转自:https://blog.csdn.net/baidu_33718858/article/details/85988935

    目录

    带有注意力机制的编码器-解码器(Encoder-Decoder with Attention)

    一个测试注意力机制的问题(Test Problem for Attention)

    没有注意力机制的编码-解码(Encoder-Decoder Without Attention)

    自定义Keras中的Attention层(Custom Keras Attention Layer)

    带有注意力机制的编码器-解码器(Encoder-Decoder With Attention)

    模型比较(Comparison of Models)


    事实证明,递归神经网络的编码器-解码器体系结构在自然语言处理领域的一系列序列到序列预测问题上非常强大。
    注意是一种机制,它解决了编码器-解码器体系结构在长序列上的局限性,并且通常加快了学习速度,提高了序列到序列预测问题模型的技能。

    在本教程中,您将了解如何在Keras中实现一个带有注意力机制的编码器-解码器卷积神经网络。

    完成本教程后,您将知道:

    • 如何设计一个小而可配置的问题来评估有无注意机制的编码器-解码器循环神经网络。
    • 针对序列预测问题,如何设计和评价一个有无注意机制的编码器-解码器网络。
    • 如何在有无注意机制的情况下,鲁棒比较编码器-解码器网络的性能。

    带有注意力机制的编码器-解码器(Encoder-Decoder with Attention)

    循环神经网络中的编码器-解码器模型是一种序列到序列预测问题的体系结构。
    它由两个子模型组成,顾名思义:

    • 编码器:编码器负责单步执行输入时间步骤,并将整个序列编码为一个固定长度的向量,称为上下文向量(context vector)。
    • 解码器:解码器负责逐步执行输出时间步骤,并从上下文向量读取信息。

    该体系结构的一个问题是,长输入或输出序列的性能较差。原因被认为是编码器使用了固定尺寸的上下文向量进行内部表示。
    注意力机制是对解决这个限制的体系结构的扩展。它首先提供从编码器到解码器的更丰富的上下文,以及一种学习机制,在该机制中,解码器可以在预测输出序列中的每个时间步的输出时,在更丰富的编码中学习应注意的位置。
    有关编码器-解码器体系结构的更多注意事项,请参阅以下文章:


    一个测试注意力机制的问题(Test Problem for Attention)

    在我们开发带有注意力机制的模型之前,我们首先定义一个人为的可伸缩的测试问题,我们可以用它来确定注意力机制是否带来了任何好处。
    在这个问题中,我们将生成随机整数序列作为输入并匹配输出序列,输出序列由输入序列中整数的子集组成。
    例如,输入序列可以是[1,6,2,7,3],预期的输出序列可以是序列[1,6]中的前两个随机整数。
    我们将定义问题,使输入和输出序列的长度相同,并根据需要用“0”值填充输出序列。
    首先,我们需要一个函数来生成随机整数序列。我们将使用python的randint()函数生成介于0和最大值之间的随机整数,并将此范围用作问题的基数(例如,特征数)。

    下面的generate_sequence()函数将生成一个具有固定长度和指定基数的随机整数序列。

    
     
    1. from random import randint
    2. # generate a sequence of random integers
    3. def generate_sequence(length, n_unique):
    4. return [randint( 0, n_unique -1) for _ in range(length)]
    5. # generate random sequence
    6. sequence = generate_sequence( 5, 50)
    7. print(sequence)

    运行此示例将生成一个具有5个时间步的序列,其中序列中的每个值都是0到49之间的随机整数。

    [43, 3, 28, 34, 33]
     

    接下来,我们需要一个函数将离散整数值独热编码为二进制向量。
    如果使用的基数为50,则每个整数将由0和指定整数值索引处的1表示的50-元素的向量。
    下面的one_hot_encode()函数将对给定的整数序列进行一次独热编码。

    
     
    1. # one hot encode sequence
    2. def one_hot_encode(sequence, n_unique):
    3. encoding = list()
    4. for value in sequence:
    5. vector = [ 0 for _ in range(n_unique)]
    6. vector[value] = 1
    7. encoding.append(vector)
    8. return array(encoding)

    我们还需要能够解码独热编码后的序列。这将需要把从模型的预测或独热编码的预期序列转换回我们可以读取和计算的整数序列。

    下面的one_hot_decode()函数将把一个独热编码序列解码回一个整数序列。

    
     
    1. # decode a one hot encoded string
    2. def one_hot_decode(encoded_seq):
    3. return [argmax(vector) for vector in encoded_seq]

    我们可以在下面的示例中测试这些操作。

    
     
    1. from random import randint
    2. from numpy import array
    3. from numpy import argmax
    4. # generate a sequence of random integers
    5. def generate_sequence(length, n_unique):
    6. return [randint( 0, n_unique -1) for _ in range(length)]
    7. # one hot encode sequence
    8. def one_hot_encode(sequence, n_unique):
    9. encoding = list()
    10. for value in sequence:
    11. vector = [ 0 for _ in range(n_unique)]
    12. vector[value] = 1
    13. encoding.append(vector)
    14. return array(encoding)
    15. # decode a one hot encoded string
    16. def one_hot_decode(encoded_seq):
    17. return [argmax(vector) for vector in encoded_seq]
    18. # argmax()为返回沿轴axis最大值的索引,也就是独热编码后1所在的索引,即原整数数值
    19. # generate random sequence
    20. sequence = generate_sequence( 5, 50)
    21. print(sequence)
    22. # one hot encode
    23. encoded = one_hot_encode(sequence, 50)
    24. print(encoded)
    25. # decode
    26. decoded = one_hot_decode(encoded)
    27. print(decoded)

    运行这个示例首先打印一个随机生成的序列,然后打印一个独热编码的版本,最后再次打印解码的序列。

    
     
    1. [ 3, 18, 32, 11, 36]
    2. [[ 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
    3. [ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
    4. [ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
    5. [ 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
    6. [ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0]]
    7. [ 3, 18, 32, 11, 36]

    最后,我们需要一个可以创建输入和输出序列对的函数来训练和评估模型。
    下面名为get_pair()的函数将返回一个给定了输入长度、输出长度和基数的,输入-输出序列对。输入序列和输出序列的长度相同,即等于输入序列的长度,但输出序列将表示为输入序列的前N个字符,并用零值填充到所需的长度。
    然后对整数序列进行独热编码,然后将其reshape为循环神经网络所需的三维格式,其尺寸为:样本、时间步和特征。在这种情况下,样本总是1,因为我们只生成一个输入-输出对,时间步数是输入序列长度,特征是每个时间步数的基数。

    
     
    1. # prepare data for the LSTM
    2. def get_pair(n_in, n_out, n_unique):
    3. # generate random sequence
    4. sequence_in = generate_sequence(n_in, n_unique)
    5. sequence_out = sequence_in[:n_out] + [ 0 for _ in range(n_in-n_out)]
    6. # one hot encode
    7. X = one_hot_encode(sequence_in, n_unique)
    8. y = one_hot_encode(sequence_out, n_unique)
    9. # reshape as 3D
    10. X = X.reshape(( 1, X.shape[ 0], X.shape[ 1]))
    11. y = y.reshape(( 1, y.shape[ 0], y.shape[ 1]))
    12. return X,y

    我们可以把这些放在一起并演示数据准备部分的代码。

    
     
    1. from random import randint
    2. from numpy import array
    3. from numpy import argmax
    4. # generate a sequence of random integers
    5. def generate_sequence(length, n_unique):
    6. return [randint( 0, n_unique -1) for _ in range(length)]
    7. # one hot encode sequence
    8. def one_hot_encode(sequence, n_unique):
    9. encoding = list()
    10. for value in sequence:
    11. vector = [ 0 for _ in range(n_unique)]
    12. vector[value] = 1
    13. encoding.append(vector)
    14. return array(encoding)
    15. # decode a one hot encoded string
    16. def one_hot_decode(encoded_seq):
    17. return [argmax(vector) for vector in encoded_seq]
    18. # prepare data for the LSTM
    19. def get_pair(n_in, n_out, n_unique):
    20. # generate random sequence
    21. sequence_in = generate_sequence(n_in, n_unique)
    22. sequence_out = sequence_in[:n_out] + [ 0 for _ in range(n_in-n_out)]
    23. # one hot encode
    24. X = one_hot_encode(sequence_in, n_unique)
    25. y = one_hot_encode(sequence_out, n_unique)
    26. # reshape as 3D
    27. X = X.reshape(( 1, X.shape[ 0], X.shape[ 1]))
    28. y = y.reshape(( 1, y.shape[ 0], y.shape[ 1]))
    29. return X,y
    30. # generate random sequence
    31. X, y = get_pair( 5, 2, 50)
    32. print(X.shape, y.shape)
    33. print( 'X=%s, y=%s' % (one_hot_decode(X[ 0]), one_hot_decode(y[ 0])))

    运行该示例将生成一个输入输出对,并打印两个数组的形状。
    然后以解码的形式打印生成的对,我们可以看到序列的前两个整数在输出序列中被复制,后面是零值的填充。

    
     
    1. ( 1, 5, 50) ( 1, 5, 50)
    2. X=[ 12, 20, 36, 40, 12], y=[ 12, 20, 0, 0, 0]

    没有注意力机制的编码-解码(Encoder-Decoder Without Attention)

    在这一部分中,我们将开发一个解决上述问题的编码器-解码器模型作为评估的基准。
    首先,我们将重复问题的定义:5个时间步长的输入和输出序列,输出序列中的值为输入序列的前2个元素,以50为基数(特征的个数)。

    
     
    1. # configure problem
    2. n_features = 50
    3. n_timesteps_in = 5
    4. n_timesteps_out = 2

    我们可以通过从编码器lstm模型中获取输出编码向量,并按照输出序列中的时间步数重复输入编码向量n次,然后使用解码器预测输出序列,从而在keras中开发一个简单的编码器-解码器模型。
    有关如何在Keras中定义编码器-解码器体系结构的详细信息,请参阅以下文章:

    我们将使用相同数量的单元(units,代表循环神经网络中隐藏层的单元个数,也代表了循环神经网络的输出维度)配置编码器和解码器,在本例中为150。我们将利用Adam有效实现梯度下降,并优化分类交叉熵损失函数,前提是该问题在技术上是一个多分类问题。
    模型的配置是经过一点尝试和错误后发现的,决不是最优化的。
    下面列出了keras中编码器-解码器体系结构的代码。

    
     
    1. # define model
    2. model = Sequential()
    3. model.add(LSTM( 150, input_shape=(n_timesteps_in, n_features)))
    4. model.add(RepeatVector(n_timesteps_in))
    5. model.add(LSTM( 150, return_sequences= True))
    6. model.add(TimeDistributed(Dense(n_features, activation= 'softmax')))
    7. model.compile(loss= 'categorical_crossentropy', optimizer= 'adam', metrics=[ 'acc'])

    我们将在5000个整数序列的随机输入输出对上训练模型。

    
     
    1. # train LSTM
    2. for epoch in range( 5000):
    3. # generate new random sequence
    4. X,y = get_pair(n_timesteps_in, n_timesteps_out, n_features)
    5. # fit model for one epoch on this sequence
    6. model.fit(X, y, epochs= 1, verbose= 2)

    经过训练后,我们将在100个新的随机生成的整数序列上评估模型,并且仅在整个输出序列与预期值匹配时标记预测正确。

    
     
    1. # evaluate LSTM
    2. total, correct = 100, 0
    3. for _ in range(total):
    4. X,y = get_pair(n_timesteps_in, n_timesteps_out, n_features)
    5. yhat = model.predict(X, verbose= 0)
    6. if array_equal(one_hot_decode(y[ 0]), one_hot_decode(yhat[ 0])):
    7. correct += 1
    8. print( 'Accuracy: %.2f%%' % (float(correct)/float(total)* 100.0))

    最后,我们将打印10个期望输出序列和模型预测序列的例子。
    将所有这些放在一起,下面列出了完整的示例。

    
     
    1. from random import randint
    2. from numpy import array
    3. from numpy import argmax
    4. from numpy import array_equal
    5. from keras.models import Sequential
    6. from keras.layers import LSTM
    7. from keras.layers import Dense
    8. from keras.layers import TimeDistributed
    9. from keras.layers import RepeatVector
    10. # generate a sequence of random integers
    11. def generate_sequence(length, n_unique):
    12. return [randint( 0, n_unique -1) for _ in range(length)]
    13. # one hot encode sequence
    14. def one_hot_encode(sequence, n_unique):
    15. encoding = list()
    16. for value in sequence:
    17. vector = [ 0 for _ in range(n_unique)]
    18. vector[value] = 1
    19. encoding.append(vector)
    20. return array(encoding)
    21. # decode a one hot encoded string
    22. def one_hot_decode(encoded_seq):
    23. return [argmax(vector) for vector in encoded_seq]
    24. # prepare data for the LSTM
    25. def get_pair(n_in, n_out, cardinality):
    26. # generate random sequence
    27. sequence_in = generate_sequence(n_in, cardinality)
    28. sequence_out = sequence_in[:n_out] + [ 0 for _ in range(n_in-n_out)]
    29. # one hot encode
    30. X = one_hot_encode(sequence_in, cardinality)
    31. y = one_hot_encode(sequence_out, cardinality)
    32. # reshape as 3D
    33. X = X.reshape(( 1, X.shape[ 0], X.shape[ 1]))
    34. y = y.reshape(( 1, y.shape[ 0], y.shape[ 1]))
    35. return X,y
    36. # configure problem
    37. n_features = 50
    38. n_timesteps_in = 5
    39. n_timesteps_out = 2
    40. # define model
    41. model = Sequential()
    42. model.add(LSTM( 150, input_shape=(n_timesteps_in, n_features)))
    43. model.add(RepeatVector(n_timesteps_in))
    44. model.add(LSTM( 150, return_sequences= True))
    45. model.add(TimeDistributed(Dense(n_features, activation= 'softmax')))
    46. model.compile(loss= 'categorical_crossentropy', optimizer= 'adam', metrics=[ 'acc'])
    47. # train LSTM
    48. for epoch in range( 5000):
    49. # generate new random sequence
    50. X,y = get_pair(n_timesteps_in, n_timesteps_out, n_features)
    51. # fit model for one epoch on this sequence
    52. model.fit(X, y, epochs= 1, verbose= 2)
    53. # evaluate LSTM
    54. total, correct = 100, 0
    55. for _ in range(total):
    56. X,y = get_pair(n_timesteps_in, n_timesteps_out, n_features)
    57. yhat = model.predict(X, verbose= 0)
    58. if array_equal(one_hot_decode(y[ 0]), one_hot_decode(yhat[ 0])):
    59. correct += 1
    60. print( 'Accuracy: %.2f%%' % (float(correct)/float(total)* 100.0))
    61. # spot check some examples
    62. for _ in range( 10):
    63. X,y = get_pair(n_timesteps_in, n_timesteps_out, n_features)
    64. yhat = model.predict(X, verbose= 0)
    65. print( 'Expected:', one_hot_decode(y[ 0]), 'Predicted', one_hot_decode(yhat[ 0]))

    在CPU上运行这个例子不会花费很长时间,可能几分钟,不需要GPU。
    根据实验该模型的准确度略低于20%。考虑到神经网络的随机性,您的结果会有所不同;可以运行示例几次并取平均值。

    Accuracy: 19.00%
     

    我们可以从样本输出中看到,模型在输出序列中得到的第一个数字对于大多数或所有情况都是正确的,并且只与第二个数字发生冲突。所有零填充值都是正确预测的。

    
     
    1. Expected: [ 47, 0, 0, 0, 0] Predicted [ 47, 47, 0, 0, 0]
    2. Expected: [ 43, 31, 0, 0, 0] Predicted [ 43, 31, 0, 0, 0]
    3. Expected: [ 14, 22, 0, 0, 0] Predicted [ 14, 14, 0, 0, 0]
    4. Expected: [ 39, 31, 0, 0, 0] Predicted [ 39, 39, 0, 0, 0]
    5. Expected: [ 6, 4, 0, 0, 0] Predicted [ 6, 4, 0, 0, 0]
    6. Expected: [ 47, 0, 0, 0, 0] Predicted [ 47, 47, 0, 0, 0]
    7. Expected: [ 39, 33, 0, 0, 0] Predicted [ 39, 39, 0, 0, 0]
    8. Expected: [ 23, 2, 0, 0, 0] Predicted [ 23, 23, 0, 0, 0]
    9. Expected: [ 19, 28, 0, 0, 0] Predicted [ 19, 3, 0, 0, 0]
    10. Expected: [ 32, 33, 0, 0, 0] Predicted [ 32, 32, 0, 0, 0]

    自定义Keras中的Attention层(Custom Keras Attention Layer)

    现在我们需要将注意力机制引入编码器-解码器模型。
    在Keras发布正式的注意力机制之前(查Keras的官网发现了一段模糊的话,没看到专门的介绍attention的文档,如果已经有官方实现了,欢迎留言告诉我),我们可以开发自己的实施方案,也可以使用现有的第三方实施方案。


    为了加快速度,让我们使用现有的第三方实现。
    Zafarali Ahmed ,一位在数据日志网站上的实习生,在2017年发表的题为“How to Visualize Your Recurrent Neural Network with Attention in Keras”的文章和名为“Keras attention”的Github项目中,为Keras开发了一个定制层,为attention提供支持。
    自定义关注层称为AttentionDecoder,可在github项目中的custom_recurrents.py文件中找到。我们可以在项目的GNU affero通用公共许可v3.0许可证下重用此代码。
    为了完整起见,下面列出了自定义层的副本。复制并粘贴到当前工作目录中名为“attention_decoder.py”的新的单独文件中。

    
     
    1. import tensorflow as tf
    2. from keras import backend as K
    3. from keras import regularizers, constraints, initializers, activations
    4. from keras.layers.recurrent import Recurrent, _time_distributed_dense
    5. from keras.engine import InputSpec
    6. tfPrint = lambda d, T: tf.Print(input_=T, data=[T, tf.shape(T)], message=d)
    7. class AttentionDecoder(Recurrent):
    8. def __init__(self, units, output_dim,
    9. activation='tanh',
    10. return_probabilities=False,
    11. name='AttentionDecoder',
    12. kernel_initializer='glorot_uniform',
    13. recurrent_initializer='orthogonal',
    14. bias_initializer='zeros',
    15. kernel_regularizer=None,
    16. bias_regularizer=None,
    17. activity_regularizer=None,
    18. kernel_constraint=None,
    19. bias_constraint=None,
    20. **kwargs):
    21. """
    22. Implements an AttentionDecoder that takes in a sequence encoded by an
    23. encoder and outputs the decoded states
    24. :param units: dimension of the hidden state and the attention matrices
    25. :param output_dim: the number of labels in the output space
    26. references:
    27. Bahdanau, Dzmitry, Kyunghyun Cho, and Yoshua Bengio.
    28. "Neural machine translation by jointly learning to align and translate."
    29. arXiv preprint arXiv:1409.0473 (2014).
    30. """
    31. self.units = units
    32. self.output_dim = output_dim
    33. self.return_probabilities = return_probabilities
    34. self.activation = activations.get(activation)
    35. self.kernel_initializer = initializers.get(kernel_initializer)
    36. self.recurrent_initializer = initializers.get(recurrent_initializer)
    37. self.bias_initializer = initializers.get(bias_initializer)
    38. self.kernel_regularizer = regularizers.get(kernel_regularizer)
    39. self.recurrent_regularizer = regularizers.get(kernel_regularizer)
    40. self.bias_regularizer = regularizers.get(bias_regularizer)
    41. self.activity_regularizer = regularizers.get(activity_regularizer)
    42. self.kernel_constraint = constraints.get(kernel_constraint)
    43. self.recurrent_constraint = constraints.get(kernel_constraint)
    44. self.bias_constraint = constraints.get(bias_constraint)
    45. super(AttentionDecoder, self).__init__(**kwargs)
    46. self.name = name
    47. self.return_sequences = True # must return sequences
    48. def build(self, input_shape):
    49. """
    50. See Appendix 2 of Bahdanau 2014, arXiv:1409.0473
    51. for model details that correspond to the matrices here.
    52. """
    53. self.batch_size, self.timesteps, self.input_dim = input_shape
    54. if self.stateful:
    55. super(AttentionDecoder, self).reset_states()
    56. self.states = [ None, None] # y, s
    57. """
    58. Matrices for creating the context vector
    59. """
    60. self.V_a = self.add_weight(shape=(self.units,),
    61. name= 'V_a',
    62. initializer=self.kernel_initializer,
    63. regularizer=self.kernel_regularizer,
    64. constraint=self.kernel_constraint)
    65. self.W_a = self.add_weight(shape=(self.units, self.units),
    66. name= 'W_a',
    67. initializer=self.kernel_initializer,
    68. regularizer=self.kernel_regularizer,
    69. constraint=self.kernel_constraint)
    70. self.U_a = self.add_weight(shape=(self.input_dim, self.units),
    71. name= 'U_a',
    72. initializer=self.kernel_initializer,
    73. regularizer=self.kernel_regularizer,
    74. constraint=self.kernel_constraint)
    75. self.b_a = self.add_weight(shape=(self.units,),
    76. name= 'b_a',
    77. initializer=self.bias_initializer,
    78. regularizer=self.bias_regularizer,
    79. constraint=self.bias_constraint)
    80. """
    81. Matrices for the r (reset) gate
    82. """
    83. self.C_r = self.add_weight(shape=(self.input_dim, self.units),
    84. name= 'C_r',
    85. initializer=self.recurrent_initializer,
    86. regularizer=self.recurrent_regularizer,
    87. constraint=self.recurrent_constraint)
    88. self.U_r = self.add_weight(shape=(self.units, self.units),
    89. name= 'U_r',
    90. initializer=self.recurrent_initializer,
    91. regularizer=self.recurrent_regularizer,
    92. constraint=self.recurrent_constraint)
    93. self.W_r = self.add_weight(shape=(self.output_dim, self.units),
    94. name= 'W_r',
    95. initializer=self.recurrent_initializer,
    96. regularizer=self.recurrent_regularizer,
    97. constraint=self.recurrent_constraint)
    98. self.b_r = self.add_weight(shape=(self.units, ),
    99. name= 'b_r',
    100. initializer=self.bias_initializer,
    101. regularizer=self.bias_regularizer,
    102. constraint=self.bias_constraint)
    103. """
    104. Matrices for the z (update) gate
    105. """
    106. self.C_z = self.add_weight(shape=(self.input_dim, self.units),
    107. name= 'C_z',
    108. initializer=self.recurrent_initializer,
    109. regularizer=self.recurrent_regularizer,
    110. constraint=self.recurrent_constraint)
    111. self.U_z = self.add_weight(shape=(self.units, self.units),
    112. name= 'U_z',
    113. initializer=self.recurrent_initializer,
    114. regularizer=self.recurrent_regularizer,
    115. constraint=self.recurrent_constraint)
    116. self.W_z = self.add_weight(shape=(self.output_dim, self.units),
    117. name= 'W_z',
    118. initializer=self.recurrent_initializer,
    119. regularizer=self.recurrent_regularizer,
    120. constraint=self.recurrent_constraint)
    121. self.b_z = self.add_weight(shape=(self.units, ),
    122. name= 'b_z',
    123. initializer=self.bias_initializer,
    124. regularizer=self.bias_regularizer,
    125. constraint=self.bias_constraint)
    126. """
    127. Matrices for the proposal
    128. """
    129. self.C_p = self.add_weight(shape=(self.input_dim, self.units),
    130. name= 'C_p',
    131. initializer=self.recurrent_initializer,
    132. regularizer=self.recurrent_regularizer,
    133. constraint=self.recurrent_constraint)
    134. self.U_p = self.add_weight(shape=(self.units, self.units),
    135. name= 'U_p',
    136. initializer=self.recurrent_initializer,
    137. regularizer=self.recurrent_regularizer,
    138. constraint=self.recurrent_constraint)
    139. self.W_p = self.add_weight(shape=(self.output_dim, self.units),
    140. name= 'W_p',
    141. initializer=self.recurrent_initializer,
    142. regularizer=self.recurrent_regularizer,
    143. constraint=self.recurrent_constraint)
    144. self.b_p = self.add_weight(shape=(self.units, ),
    145. name= 'b_p',
    146. initializer=self.bias_initializer,
    147. regularizer=self.bias_regularizer,
    148. constraint=self.bias_constraint)
    149. """
    150. Matrices for making the final prediction vector
    151. """
    152. self.C_o = self.add_weight(shape=(self.input_dim, self.output_dim),
    153. name= 'C_o',
    154. initializer=self.recurrent_initializer,
    155. regularizer=self.recurrent_regularizer,
    156. constraint=self.recurrent_constraint)
    157. self.U_o = self.add_weight(shape=(self.units, self.output_dim),
    158. name= 'U_o',
    159. initializer=self.recurrent_initializer,
    160. regularizer=self.recurrent_regularizer,
    161. constraint=self.recurrent_constraint)
    162. self.W_o = self.add_weight(shape=(self.output_dim, self.output_dim),
    163. name= 'W_o',
    164. initializer=self.recurrent_initializer,
    165. regularizer=self.recurrent_regularizer,
    166. constraint=self.recurrent_constraint)
    167. self.b_o = self.add_weight(shape=(self.output_dim, ),
    168. name= 'b_o',
    169. initializer=self.bias_initializer,
    170. regularizer=self.bias_regularizer,
    171. constraint=self.bias_constraint)
    172. # For creating the initial state:
    173. self.W_s = self.add_weight(shape=(self.input_dim, self.units),
    174. name= 'W_s',
    175. initializer=self.recurrent_initializer,
    176. regularizer=self.recurrent_regularizer,
    177. constraint=self.recurrent_constraint)
    178. self.input_spec = [
    179. InputSpec(shape=(self.batch_size, self.timesteps, self.input_dim))]
    180. self.built = True
    181. def call(self, x):
    182. # store the whole sequence so we can "attend" to it at each timestep
    183. self.x_seq = x
    184. # apply the a dense layer over the time dimension of the sequence
    185. # do it here because it doesn't depend on any previous steps
    186. # thefore we can save computation time:
    187. self._uxpb = _time_distributed_dense(self.x_seq, self.U_a, b=self.b_a,
    188. input_dim=self.input_dim,
    189. timesteps=self.timesteps,
    190. output_dim=self.units)
    191. return super(AttentionDecoder, self).call(x)
    192. def get_initial_state(self, inputs):
    193. # apply the matrix on the first time step to get the initial s0.
    194. s0 = activations.tanh(K.dot(inputs[:, 0], self.W_s))
    195. # from keras.layers.recurrent to initialize a vector of (batchsize,
    196. # output_dim)
    197. y0 = K.zeros_like(inputs) # (samples, timesteps, input_dims)
    198. y0 = K.sum(y0, axis=( 1, 2)) # (samples, )
    199. y0 = K.expand_dims(y0) # (samples, 1)
    200. y0 = K.tile(y0, [ 1, self.output_dim])
    201. return [y0, s0]
    202. def step(self, x, states):
    203. ytm, stm = states
    204. # repeat the hidden state to the length of the sequence
    205. _stm = K.repeat(stm, self.timesteps)
    206. # now multiplty the weight matrix with the repeated hidden state
    207. _Wxstm = K.dot(_stm, self.W_a)
    208. # calculate the attention probabilities
    209. # this relates how much other timesteps contributed to this one.
    210. et = K.dot(activations.tanh(_Wxstm + self._uxpb),
    211. K.expand_dims(self.V_a))
    212. at = K.exp(et)
    213. at_sum = K.sum(at, axis= 1)
    214. at_sum_repeated = K.repeat(at_sum, self.timesteps)
    215. at /= at_sum_repeated # vector of size (batchsize, timesteps, 1)
    216. # calculate the context vector
    217. context = K.squeeze(K.batch_dot(at, self.x_seq, axes= 1), axis= 1)
    218. # ~~~> calculate new hidden state
    219. # first calculate the "r" gate:
    220. rt = activations.sigmoid(
    221. K.dot(ytm, self.W_r)
    222. + K.dot(stm, self.U_r)
    223. + K.dot(context, self.C_r)
    224. + self.b_r)
    225. # now calculate the "z" gate
    226. zt = activations.sigmoid(
    227. K.dot(ytm, self.W_z)
    228. + K.dot(stm, self.U_z)
    229. + K.dot(context, self.C_z)
    230. + self.b_z)
    231. # calculate the proposal hidden state:
    232. s_tp = activations.tanh(
    233. K.dot(ytm, self.W_p)
    234. + K.dot((rt * stm), self.U_p)
    235. + K.dot(context, self.C_p)
    236. + self.b_p)
    237. # new hidden state:
    238. st = ( 1-zt)*stm + zt * s_tp
    239. yt = activations.softmax(
    240. K.dot(ytm, self.W_o)
    241. + K.dot(stm, self.U_o)
    242. + K.dot(context, self.C_o)
    243. + self.b_o)
    244. if self.return_probabilities:
    245. return at, [yt, st]
    246. else:
    247. return yt, [yt, st]
    248. def compute_output_shape(self, input_shape):
    249. """
    250. For Keras internal compatability checking
    251. """
    252. if self.return_probabilities:
    253. return ( None, self.timesteps, self.timesteps)
    254. else:
    255. return ( None, self.timesteps, self.output_dim)
    256. def get_config(self):
    257. """
    258. For rebuilding models on load time.
    259. """
    260. config = {
    261. 'output_dim': self.output_dim,
    262. 'units': self.units,
    263. 'return_probabilities': self.return_probabilities
    264. }
    265. base_config = super(AttentionDecoder, self).get_config()
    266. return dict(list(base_config.items()) + list(config.items()))

    我们可以在项目中使用这个自定义层,通过用如下的方式导入它:

    from attention_decoder import AttentionDecoder
     

    该层实现了Bahdanau等人在他们的“Neural Machine Translation by Jointly Learning to Align and Translate.”论文中所描述的注意力机制。
    这段代码在文章中解释得很好,并且与LSTM和注意力方程式都有关联。
    这种实现的一个限制是,它必须输出与输入序列长度相同的序列,而这是编码器-解码器体系结构设计要克服的特定限制。(确实是这样,如果输入和输出序列长度不一样,可以采用补0措施,将短的序列补为和长的一样的;或者在得到这层输出之后,再通过一层GRU改变序列长度)
    重要的是,该层不但避免了第二个LSTM层作为解码器的代码重复,还在这个编码器-解码器模型中通过不加注意机制的Dense层得到SoftMax后的输出。这大大简化了模型的代码。
    需要注意的是,自定义层是建立在Keras中的循环层(继承了Recurrent)之上的,在编写时,它被标记为遗留代码,并且可能会在某个时刻从项目中删除。


    带有注意力机制的编码器-解码器(Encoder-Decoder With Attention)

    既然我们已经有了可以使用的注意力实现,那么我们就可以为我们设计的序列预测问题开发一个有注意力的编码器-解码器模型。
    下面定义了具有注意层的模型。我们可以看到,该层能处理编码器-解码器模型本身的一些机制,使得定义模型更简单。

    
     
    1. # define model
    2. model = Sequential()
    3. model.add(LSTM( 150, input_shape=(n_timesteps_in, n_features), return_sequences= True))
    4. model.add(AttentionDecoder( 150, n_features))
    5. model.compile(loss= 'categorical_crossentropy', optimizer= 'adam', metrics=[ 'acc'])

    就是这样。其余的例子是相同的。
    下面列出了完整的示例。

    
     
    1. from random import randint
    2. from numpy import array
    3. from numpy import argmax
    4. from numpy import array_equal
    5. from keras.models import Sequential
    6. from keras.layers import LSTM
    7. from attention_decoder import AttentionDecoder
    8. # generate a sequence of random integers
    9. def generate_sequence(length, n_unique):
    10. return [randint( 0, n_unique -1) for _ in range(length)]
    11. # one hot encode sequence
    12. def one_hot_encode(sequence, n_unique):
    13. encoding = list()
    14. for value in sequence:
    15. vector = [ 0 for _ in range(n_unique)]
    16. vector[value] = 1
    17. encoding.append(vector)
    18. return array(encoding)
    19. # decode a one hot encoded string
    20. def one_hot_decode(encoded_seq):
    21. return [argmax(vector) for vector in encoded_seq]
    22. # prepare data for the LSTM
    23. def get_pair(n_in, n_out, cardinality):
    24. # generate random sequence
    25. sequence_in = generate_sequence(n_in, cardinality)
    26. sequence_out = sequence_in[:n_out] + [ 0 for _ in range(n_in-n_out)]
    27. # one hot encode
    28. X = one_hot_encode(sequence_in, cardinality)
    29. y = one_hot_encode(sequence_out, cardinality)
    30. # reshape as 3D
    31. X = X.reshape(( 1, X.shape[ 0], X.shape[ 1]))
    32. y = y.reshape(( 1, y.shape[ 0], y.shape[ 1]))
    33. return X,y
    34. # configure problem
    35. n_features = 50
    36. n_timesteps_in = 5
    37. n_timesteps_out = 2
    38. # define model
    39. model = Sequential()
    40. model.add(LSTM( 150, input_shape=(n_timesteps_in, n_features), return_sequences= True))
    41. model.add(AttentionDecoder( 150, n_features))
    42. model.compile(loss= 'categorical_crossentropy', optimizer= 'adam', metrics=[ 'acc'])
    43. # train LSTM
    44. for epoch in range( 5000):
    45. # generate new random sequence
    46. X,y = get_pair(n_timesteps_in, n_timesteps_out, n_features)
    47. # fit model for one epoch on this sequence
    48. model.fit(X, y, epochs= 1, verbose= 2)
    49. # evaluate LSTM
    50. total, correct = 100, 0
    51. for _ in range(total):
    52. X,y = get_pair(n_timesteps_in, n_timesteps_out, n_features)
    53. yhat = model.predict(X, verbose= 0)
    54. if array_equal(one_hot_decode(y[ 0]), one_hot_decode(yhat[ 0])):
    55. correct += 1
    56. print( 'Accuracy: %.2f%%' % (float(correct)/float(total)* 100.0))
    57. # spot check some examples
    58. for _ in range( 10):
    59. X,y = get_pair(n_timesteps_in, n_timesteps_out, n_features)
    60. yhat = model.predict(X, verbose= 0)
    61. print( 'Expected:', one_hot_decode(y[ 0]), 'Predicted', one_hot_decode(yhat[ 0]))

    运行这个示例可以在100个随机生成的输入输出对进行训练来评估模型的性能。在相同的资源和相同的训练量下,具有注意力的模型表现得更好。
    考虑到神经网络的随机性,你的结果可能会有所不同。尝试运行该示例几次。

    Accuracy: 95.00%
     

    抽查一些样本输出和预测序列,我们可以看到即使在前两个元素中有零值的情况下,都很少有错误。

    
     
    1. Expected: [ 48, 47, 0, 0, 0] Predicted [ 48, 47, 0, 0, 0]
    2. Expected: [ 7, 46, 0, 0, 0] Predicted [ 7, 46, 0, 0, 0]
    3. Expected: [ 32, 30, 0, 0, 0] Predicted [ 32, 2, 0, 0, 0]
    4. Expected: [ 3, 25, 0, 0, 0] Predicted [ 3, 25, 0, 0, 0]
    5. Expected: [ 45, 4, 0, 0, 0] Predicted [ 45, 4, 0, 0, 0]
    6. Expected: [ 49, 9, 0, 0, 0] Predicted [ 49, 9, 0, 0, 0]
    7. Expected: [ 22, 23, 0, 0, 0] Predicted [ 22, 23, 0, 0, 0]
    8. Expected: [ 29, 36, 0, 0, 0] Predicted [ 29, 36, 0, 0, 0]
    9. Expected: [ 0, 29, 0, 0, 0] Predicted [ 0, 29, 0, 0, 0]
    10. Expected: [ 11, 26, 0, 0, 0] Predicted [ 11, 26, 0, 0, 0]

    模型比较(Comparison of Models)

    尽管我们在有注意力机制的情况下从模型中得到了更好的结果,但是那只是从模型的一次运行中得到的结果。
    在这种情况下,我们通过多次重复对每个模型的评估,并报告这些运行的平均性能,来寻求更可靠的模型评估结果。有关评估神经网络模型的这种稳健方法的更多信息,请参阅以下文章:

    我们可以定义一个函数来创建每种类型的模型,如下所示。

    
     
    1. # define the encoder-decoder model
    2. def baseline_model(n_timesteps_in, n_features):
    3. model = Sequential()
    4. model.add(LSTM( 150, input_shape=(n_timesteps_in, n_features)))
    5. model.add(RepeatVector(n_timesteps_in))
    6. model.add(LSTM( 150, return_sequences= True))
    7. model.add(TimeDistributed(Dense(n_features, activation= 'softmax')))
    8. model.compile(loss= 'categorical_crossentropy', optimizer= 'adam', metrics=[ 'acc'])
    9. return model
    10. # define the encoder-decoder with attention model
    11. def attention_model(n_timesteps_in, n_features):
    12. model = Sequential()
    13. model.add(LSTM( 150, input_shape=(n_timesteps_in, n_features), return_sequences= True))
    14. model.add(AttentionDecoder( 150, n_features))
    15. model.compile(loss= 'categorical_crossentropy', optimizer= 'adam', metrics=[ 'acc'])
    16. return model

    然后我们可以定义一个函数来拟合和评估模型的精度,并返回精度分数。

    
     
    1. # train and evaluate a model, return accuracy
    2. def train_evaluate_model(model, n_timesteps_in, n_timesteps_out, n_features):
    3. # train LSTM
    4. for epoch in range( 5000):
    5. # generate new random sequence
    6. X,y = get_pair(n_timesteps_in, n_timesteps_out, n_features)
    7. # fit model for one epoch on this sequence
    8. model.fit(X, y, epochs= 1, verbose= 0)
    9. # evaluate LSTM
    10. total, correct = 100, 0
    11. for _ in range(total):
    12. X,y = get_pair(n_timesteps_in, n_timesteps_out, n_features)
    13. yhat = model.predict(X, verbose= 0)
    14. if array_equal(one_hot_decode(y[ 0]), one_hot_decode(yhat[ 0])):
    15. correct += 1
    16. return float(correct)/float(total)* 100.0

    综合起来,我们可以多次重复创建、训练和评估每种模型的过程,并报告多次评估的平均准确性。为了减少运行时间,我们将重复评估每个模型10次,如果您有资源,您可以将其增加到30或100次。
    下面列出了完整的示例。

    
     
    1. from random import randint
    2. from numpy import array
    3. from numpy import argmax
    4. from numpy import array_equal
    5. from keras.models import Sequential
    6. from keras.layers import LSTM
    7. from keras.layers import Dense
    8. from keras.layers import TimeDistributed
    9. from keras.layers import RepeatVector
    10. from attention_decoder import AttentionDecoder
    11. # generate a sequence of random integers
    12. def generate_sequence(length, n_unique):
    13. return [randint( 0, n_unique -1) for _ in range(length)]
    14. # one hot encode sequence
    15. def one_hot_encode(sequence, n_unique):
    16. encoding = list()
    17. for value in sequence:
    18. vector = [ 0 for _ in range(n_unique)]
    19. vector[value] = 1
    20. encoding.append(vector)
    21. return array(encoding)
    22. # decode a one hot encoded string
    23. def one_hot_decode(encoded_seq):
    24. return [argmax(vector) for vector in encoded_seq]
    25. # prepare data for the LSTM
    26. def get_pair(n_in, n_out, cardinality):
    27. # generate random sequence
    28. sequence_in = generate_sequence(n_in, cardinality)
    29. sequence_out = sequence_in[:n_out] + [ 0 for _ in range(n_in-n_out)]
    30. # one hot encode
    31. X = one_hot_encode(sequence_in, cardinality)
    32. y = one_hot_encode(sequence_out, cardinality)
    33. # reshape as 3D
    34. X = X.reshape(( 1, X.shape[ 0], X.shape[ 1]))
    35. y = y.reshape(( 1, y.shape[ 0], y.shape[ 1]))
    36. return X,y
    37. # define the encoder-decoder model
    38. def baseline_model(n_timesteps_in, n_features):
    39. model = Sequential()
    40. model.add(LSTM( 150, input_shape=(n_timesteps_in, n_features)))
    41. model.add(RepeatVector(n_timesteps_in))
    42. model.add(LSTM( 150, return_sequences= True))
    43. model.add(TimeDistributed(Dense(n_features, activation= 'softmax')))
    44. model.compile(loss= 'categorical_crossentropy', optimizer= 'adam', metrics=[ 'acc'])
    45. return model
    46. # define the encoder-decoder with attention model
    47. def attention_model(n_timesteps_in, n_features):
    48. model = Sequential()
    49. model.add(LSTM( 150, input_shape=(n_timesteps_in, n_features), return_sequences= True))
    50. model.add(AttentionDecoder( 150, n_features))
    51. model.compile(loss= 'categorical_crossentropy', optimizer= 'adam', metrics=[ 'acc'])
    52. return model
    53. # train and evaluate a model, return accuracy
    54. def train_evaluate_model(model, n_timesteps_in, n_timesteps_out, n_features):
    55. # train LSTM
    56. for epoch in range( 5000):
    57. # generate new random sequence
    58. X,y = get_pair(n_timesteps_in, n_timesteps_out, n_features)
    59. # fit model for one epoch on this sequence
    60. model.fit(X, y, epochs= 1, verbose= 0)
    61. # evaluate LSTM
    62. total, correct = 100, 0
    63. for _ in range(total):
    64. X,y = get_pair(n_timesteps_in, n_timesteps_out, n_features)
    65. yhat = model.predict(X, verbose= 0)
    66. if array_equal(one_hot_decode(y[ 0]), one_hot_decode(yhat[ 0])):
    67. correct += 1
    68. return float(correct)/float(total)* 100.0
    69. # configure problem
    70. n_features = 50
    71. n_timesteps_in = 5
    72. n_timesteps_out = 2
    73. n_repeats = 10
    74. # evaluate encoder-decoder model
    75. print( 'Encoder-Decoder Model')
    76. results = list()
    77. for _ in range(n_repeats):
    78. model = baseline_model(n_timesteps_in, n_features)
    79. accuracy = train_evaluate_model(model, n_timesteps_in, n_timesteps_out, n_features)
    80. results.append(accuracy)
    81. print(accuracy)
    82. print( 'Mean Accuracy: %.2f%%' % (sum(results)/float(n_repeats)))
    83. # evaluate encoder-decoder with attention model
    84. print( 'Encoder-Decoder With Attention Model')
    85. results = list()
    86. for _ in range(n_repeats):
    87. model = attention_model(n_timesteps_in, n_features)
    88. accuracy = train_evaluate_model(model, n_timesteps_in, n_timesteps_out, n_features)
    89. results.append(accuracy)
    90. print(accuracy)
    91. print( 'Mean Accuracy: %.2f%%' % (sum(results)/float(n_repeats)))

    运行这个示例可以打印每个模型重复的精度,从而让您了解运行的进度。

    
     
    1. Encoder-Decoder Model
    2. 20.0
    3. 23.0
    4. 23.0
    5. 18.0
    6. 28.000000000000004
    7. 28.999999999999996
    8. 23.0
    9. 26.0
    10. 21.0
    11. 20.0
    12. Mean Accuracy: 23.10%
    13. Encoder-Decoder With Attention Model
    14. 98.0
    15. 91.0
    16. 94.0
    17. 93.0
    18. 96.0
    19. 99.0
    20. 97.0
    21. 94.0
    22. 99.0
    23. 96.0
    24. Mean Accuracy: 95.70%

    我们可以看到,即使运行10次,注意力模型仍然比没有注意力的编码器-解码器模型表现出更好的性能。
    对这种评估的一个很好的扩展是捕获每个模型的每个epoch的模型损失,取平均值,并比较有或无注意力机制的模型中损失随时间的变化情况。我希望这个跟踪会显示出注意力比非注意力模型更快地获得更好的技能,进一步突出了该方法的好处。

     

    展开全文
  • PyTorch中seq2seq模型的一个框架
  • 这是Tensorflow 2seq2seq模型结构。 有三种模型架构,RNNSeq2Seq,RNNSeq2SeqWithAttention,TransformerSeq2Seq。 该存储库包含训练,评估,推断,转换为保存的模型格式脚本。 火车 例子 您可以通过运行以下脚本...
  • Seq2seq模型 当输入和输出都是不定长序列时,可以使⽤编码器—解码器(encoder-decoder) 或者seq2seq模型。这两个模型本质上都⽤到了两个循环神经⽹络,分别叫做编码器和解码器。编码器⽤来分析输⼊序列,解码器⽤...
  • 最近学习了seq2seq模型的内容,发现seq2seq模型实际上训练过程和输出过程是一个分离的过程,这里我们采用解决小学生数学问题的数据例子作为一个示例,来详细地讲解seq2seq通过小学生数学问题的句子去预测对应的数学...

    seq2seq训练模型的过程

    最近学习了seq2seq模型的内容,发现seq2seq模型实际上训练过程和输出过程是一个分离的过程,这里我们采用解决小学生数学问题的数据例子作为一个示例,来详细地讲解seq2seq通过小学生数学问题的句子去预测对应的数学公式的过程。
    具体的数据
    比如数据为(‘小王要将150千克含药量20%的农药稀释成含药量5%的药水,需要加水多少千克?’)
    对应的equation = “x=150*20%/5%-150”,结果ans = 450。
    这里输入的过程将输入和输出的公式结合起来:

    [CLS]+'小王要将150千克含药量20%的农药稀释成含药量5%的药水,
    需要加水多少千克?'+[SEP]+'x=150*20%/5%-150'+[SEP]
    

    假设输入的position_embedding为(5,128,768),输入的segment_embedding为(5,128,768),
    则经过bert模型之后输出的内容为(5,128,768),然后反接一个反向的embedding层,得到的对应的输出内容为(5,128,30522),此时使用输出的(5,128,30522)和对应输出公式的(5,128)进行一个计算交叉熵的过程,进而提升模型之中各种参数权重的内容信息。

    loss = K.sparse_categorical_crossentropy(y_true,y_pred)
    loss = K.sum(loss*y_mask)/K.sum(y_mask)
    

    通过训练不断降低最终的loss值。
    上面这一过程整个就是一个模型对应的训练过程。
    注意:这里输入的过程之中,输入的内容为输入加输出,看上面的内容就是[cls]+原文+[sep]+得到的公式+[sep]
    模型的输入输出训练过程这里的训练过程跟模型的预训练过程相同,一个需要注意的过程是这里的输入也需要进行mask的操作
    接下来分析模型相应的预测过程内容。

    seq2seq预测模型的过程

    预测的内容属于使用新开的一部分预测集的内容,然后对每一个部分使用seq2seq预测部分并计算得分
    模型对应的预测过程比如输入的为(5,36),预测下一位最大的概率为(5,36,30522),取出最后一位对应的概率为(5,30522)(五位数值同时进行预测),取出最大的对应数值,判断是否为结束标志,如果为结束标志的时候输出,不为结束标志的时候继续进行判断。

    在预测的时候,一般使用beam search的搜索方法来做,
    它的思想是:在每步计算时,只保留当前最优的topk个候选结果。比如取topk=3,那么第一步时,我们只保留使得p(Y1|X)最大的前3个Y1,然后分别代入p(Y2|X,Y1),然后各取前三个Y2,这样一来我们就有 3 2 = 9 3^2=9 32=9个组合了,这时我们计算每一种组合的总概率,然后还是只保留前三个,依次递归,直到出现了第一个。显然,它本质上还属于贪心搜索的范畴,只不过贪心的过程中保留了更多的可能性,普通的贪心搜索相当于topk=1。
    这两个可以结合起来,每训练一个epoch之后预测一波数据。
    这里beam search这一步真实的概率为上一步的对应概率乘上当前步骤的真实概率
    具体的思路可以概括如下:
    1.最开始的时候,放入最高概率的三个索引
    2.接下来的步骤中,每次在之前的三个索引继续延伸三个索引,构成九个索引,然后在这九个索引之中取出分数最高的对应3个索引以及现在相应的概率,并记录下来

    unilm代码部分讲解

    unilm对应的内容可以参考本人的这篇博客
    unilm的对应内容

    import keras.backend as K
    import tensorflow as tf
    s=[[0,0,0,1,1]]
    idxs = K.cumsum(s, axis=1)
    mask =idxs[:, None, :] <= idxs[:, :, None]
    mask = K.cast(mask, K.floatx())
    with tf.Session() as sess:
        a=sess.run(mask)
    print(a)
    运行结果:
    [[[1. 1. 1. 0. 0.]
      [1. 1. 1. 0. 0.]
      [1. 1. 1. 0. 0.]
      [1. 1. 1. 1. 0.]
      [1. 1. 1. 1. 1.]]]
    

    这里使用unilm之后还需要加上mask掩码的内容

    def seq2seq_compute_attention_bias(self,s):
        idxs = K.cumsum(s, axis=1)
        mask =idxs[:, None, :] <= idxs[:, :, None]
        mask = K.cast(mask, K.floatx())
        return -(1-mask) * 1e12
    

    超出长度了是截取原始的部分还是截取摘要的部分???

    beam_search束搜索过程之中的batch问题

    在beam_search束搜索的过程之中,刚开始的时候是用[cls]+原文+[sep]放入seq2seq模型之中进行,此时这里就出现一个重要的问题:需不需要进行padding操作?
    因为如果padding操作会影响后续的生成过程,所以这里实际上是不需要padding操作的,而由于每一个文本内容的长短不一,所以这里的batch_size只能设定为1。

    展开全文
  • PyTorch中的Seq2seq代码 根据和 数据预处理: 我使用以下步骤 > config/WMT14/download.sh # download WMT14 data into raw_data/WMT14 > config/WMT14/prepare.sh # preprocess the data, and copy the files to ...
  • 简单的Seq2Seq递归模型 带注意解码器的递归Seq2Seq (GNMT)递归模型 变形金刚-来自的仅关注模型 数据集 当前可用的数据集: WMT16 WMT17 OpenSubtitles 2016 COCO图片标题 可以使用3种可用的分割方法对所有...
  • Seq2Seq模型结构

    2020-03-15 09:48:00
    Seq2Seq(Sequence to Sequence) 是一个处理序列问题的模型,传统的 RNN 或 LSTM 只能处理 输入及输出是定长即 一对一或多对多的问题,而 Seq2Seq 则能处理一对多的问题,它也是 RNN 最重要的一个变种:N vs M(输入...

    Seq2Seq(Sequence to Sequence) 是一个处理序列问题的模型,传统的 RNN 或 LSTM 只能处理 输入及输出是定长即 一对一或多对多的问题,而 Seq2Seq 则能处理一对多的问题,它也是 RNN 最重要的一个变种:N vs M(输入与输出序列长度不同),

    如:输入(你是谁),输出(我是某某某)。因此 Seq2Seq 在很多方面也得到应用:机器翻译、QA 系统、文档摘要、图片描述问题

    基本结构

    上图为最常见的 Seq2Seq 模型,又叫做 编码-解码 模型,主要的思想就是二个 RNN,一个 RNN 作为 Encoder,另一个 RNN 作为 Decoder

    Encoder 主要负责将输入序列压缩成指定长度向量,这个向量可以看成是这个序列的语义,这个过程叫做编码

    获取词向量的方式分为多种:

    • 一种是直接将最后一个输出的隐状态作为语义词向量 C,假设网络单元为 f , 那么 hidden state为 h t = f ( x t , h t − 1 ) h_t = f(x_t,h_{t-1}) ht=f(xt,ht1)
    • 第二种是对最后一个隐状态作一次变换得到语义词向量,如取平均等方法

    Decoder 主要负责将语义词向量分成指定的序列,这个过程叫解码

    • 最简单的方式是将 语义词向量作为初始状态输入到 RNN 中,得到输出序列,语义词向量 C 只作为初始状态参与运算,与后面的运算无关

    • 另一种将语义词向量参与所有时刻的运算,上一时刻的输出仍然作为当前时刻的输入参与运算

    Attention 机制

    在上面的 decoder 步骤中我们可以看到,各个时刻使用的都是相同的 content vector(词语义向量),而 Attention 是一种让模型在解码过程中学习集中关注输入序列特定部分的模型

    以 英-中 翻译为例,给定 "Cat chase mouse ", 输出 “猫捉老鼠”,在翻译 “mouse” 时,我们发现 “cat”、“chase”、“mouse” 对 “老鼠” 的关注度都是一样的,但实际上 “mouse” 才是对 “猫” 影响最大的,因此我们需要在解码时,对输入序列在不同时刻分配不同的注意力,这就是注意力机制的由来

    在 encoder 中我们使用的都是同一个语义向量 C,我们想使用不同的向量来表示不同时刻的 C,那么可以写成 C 1 C_1 C1 C 2 C_2 C2 C 3 C_3 C3 C i C_i Ci

    C i C_i Ci 来表示 i 时刻的语义向量,我们之前用过最后一个值或者平均值,很容易的想到可以用加权求和来表示 c i = ∑ j = 1 T ∂ i j h j c_i = \sum_{j=1}^{T}\partial_{ij}h_j ci=j=1Tijhj ,其中 h j h_j hj 表示 encoder 中的隐层状态, ∂ i j \partial_{ij} ij 表示的是一个分布概率,即 softmax 值

    ∂ i j \partial_{ij} ij 既然是一个 softmax 值,那么可以写成 ∂ i j = e x p ( e t j ) ∑ k = 1 T e x p ( e t j ) \partial_{ij} = \frac{exp(e_tj)}{\sum_{k=1}^{T}exp(e_tj)} ij=k=1Texp(etj)exp(etj) ,其中 e t j e_tj etj 表示的是当前时刻 encoder 的隐层状态 h t h_t ht 与 上一时刻 decoder 的隐层状态 s t − 1 s_{t-1} st1 的相似程度

    e t j e_{tj} etj 既然表示的是 h1~ht 之间的相似程度,那么我们可以用一个 score 函数来表示 e i j = s c o r e ( s t − 1 , h j ) e_{ij} =score(s_{t-1},h_j) eij=score(st1,hj),score 函数可以是多样的,后面会介绍

    为了方便理解,我们可以结合下面的示意图来更清楚的了解其中的步骤:

    Encoder 输出状态 h t h_t ht 表示,Decoder 输出状态 S t S_t St 表示

    • 首先,我们用一个 score 函数来表示 h t h_t ht S t S_t St 之间的相似度,用 e t j e_{tj} etj 来表示:

    e t j = s c o r e ( S t − 1 , h j ) e_{tj} = score(S_{t-1}, h_j) etj=score(St1,hj)

    • 通过 softmax 作归一化操作方便计算:

    ∂ t j = e x p ( e i j ) ∑ k = 1 T e x p ( e t k ) \partial_{tj} = \frac{exp(e_{ij})}{\sum_{k=1}^{T}exp(e_{tk})} tj=k=1Texp(etk)exp(eij)

    • 再对归一化的值进行一个加权求和即可得到每个时刻的 content vector:

    C t = ∑ j = 1 T ∂ t j h j C_t = \sum_{j=1}^{T}\partial_{tj}h_j Ct=j=1Ttjhj

    • 最终我们根据每个时刻的 C t C_t Ct 可以计算 Decoder 的输出 S t S_t St

    S t = f ( S t − 1 , y t − 1 , C t ) S_t = f(S_{t-1}, y_{t-1}, C_t) St=f(St1,yt1,Ct)

    至此,attention 机制的结构与运行方式就很清晰了,在上面我们使用了一个 score 函数来表示 h t h_t ht S t S_t St 之间的相似度,一般来说常用的也就下面的几种:
    s c o r e ( s t − 1 , h j ) = { s t − 1 T h j s t − 1 T W a h j v a T t a n h ( W a [ s t − 1 ; h j ] ) score(s_{t-1},h_j) = \begin{cases}s_{t-1}^{T}h_j\\s_{t-1}^{T}W_ah_j\\v_a^{T}tanh(W_a[s_{t-1};h_j])\end{cases} score(st1,hj)=st1Thjst1TWahjvaTtanh(Wa[st1;hj])

    总结

    此处介绍的是最基础的 attention 结构,具体细节仍然需要在代码中仔细理解,还有 self-attention 机制及针对不同 score 函数的选取而得到的不同的注意力机制,留在以后的文章中再学习

    展开全文
  • 这里有一个很好的专栏:https://www.dazhuanlan.com/2020/03/30/5e81581e3c05a/
  • 更多干货内容敬请关注「平安寿险PAI」(公众号ID:PAL-...所以,在实际运用中往往需要对模型做出更多的调整和控制,使生成的对话更适用于具体场景。1月8日,由平安寿险AI团队在Paper Weekly直播间进行的主题为「对话...
  • seq2seq模型 基本概念 顾名思义,seq2seq模型是指,模型的输入是一个sequence序列,而模型的输出也是sequence序列,其模型结构可以表示为Encoder-Decoder结构,如下图: 其中encoder与decoder都是使用循环神经网络...
  • Seq2Seq模型

    千次阅读 2019-08-12 00:41:11
    Seq2Seq,全称为Sequence to Sequence模型(序列到序列模型,目前还没有很好的翻译),意思可以解释为将一个序列信号(词序列,字序列),通过编码和解码生成一个新的序列信号(词序列,字序列),通常用于机器翻译、图片描述、...
  • Seq2Seq-PyTorch 使用PyTorch的序列到序列实现 安装 克隆项目,进入项目目录并执行 python setup.py install 或者 pip install ./ 或简单地复制源代码。 推荐使用pip install ./ ,因为您可以先激活虚拟环境,...
  • 求教,在使用tensorflow中的tf.contrib.legacy_seq2seq.basic_rnn_seq2seq进行预测时, 应将上一步输出的结果作为decoder_input的输入。可传入参数过程中,decoder_input需 一次传完。怎么才能将上一步的结果传入呢?
  • 电气论文实现:通过电力光伏预测讲解seq2seq翻译模型 (python实现)
  • seq2seq模型实现

    千次阅读 2018-09-05 13:21:56
    本文是基于TensorFlow 1.6版本的Seq2Seq模型实现了一个机器翻译(Machine Translation)模型的baseline。 本篇代码与去年我在知乎专栏上发表的从Encoder到Decoder实现Seq2Seq模型大同小异,更新的原...
  • 本文使用seq2seq模型来做若干组时间序列的预测任务,目的是验证RNN这种网络结构对时间序列数据的pattern的发现能力,并在小范围内探究哪些pattern是可以被识别的,哪些pattern是无法识别的。 本文是受github上一个...
  • encoder_decoder, python Theano Keras和Seq2Seq四种编码解码器模型 encoder_decoder漫谈四种神经网络序列解码模型 [ http://jacoxu.com/?p=1852 ]requirements=Keras [ https://github.com/fchollet/keras ],S
  • 编者按:过去十年,得益于人工智能与机器学习的突破、算法与硬/软件能力的进步,以及拥有既多样又大量的语音数据库,用以训练多参数的、大规模的语音识别与合成模型,使得语音处理技术获得飞跃性进展。 随着端到端...
  • 时间序列预测可以根据短期预测,长期预测,以及具体场景选用不同的方法,如ARMA、ARIMA...本文通过生成的随机数利用tensorflow的seq2seq模型进行单变量时间序列预测实验,目的是理解seq2seq模型基础架构以及验证模...
  • seq2seq-pytorch是一个框架,用于在实现的基于注意力的序列到序列模型。 该框架具有用于seq2seq模型,训练,推理,检查点等的模块化和可扩展组件。 介绍 Seq2seq将一个序列转换为另一序列。 它通过使用递归神经网络...
  • Seq2Seq模型及Attention机制

    万次阅读 多人点赞 2019-09-21 17:19:07
    seq2seq模型 seq2seq模型虽然简单,但是特别经典,它的出现可以说给整个NLP带来个翻天覆地的变化。网上已经有很多人做了相关的总结,但是翻看起来还是感觉有点乱,于是想自己总结一个版本,方便自己回忆,也希望所...
  • Seq2Seq模型的原理

    2021-02-20 00:27:18
    Seq2Seq模型的原理 目标 知道seq2seq的常见应用场景 能够说出常见的seq2seq的结构 能够使用代码完成基础的seq2seq的结构 1. Seq2Seq的介绍 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传...
  • Seq2Seq 是自然语言处理中的一种重要模型,可以用于机器翻译、对话系统、自动文摘。 1. RNN 结构及使用RNN 模型在之前的文章《循环神经网络 RNN、LSTM、GRU》中介绍了 RNN 模型,RNN 基本的模型如上图所示,每个神经...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 15,211
精华内容 6,084
关键字:

seq2seq预测模型