当前位置:   article > 正文

基于Seq2Seq的机器人对话_infer_predict

infer_predict

文章最前: 我是Octopus,这个名字来源于我的中文名--章鱼;我热爱编程、热爱算法、热爱开源。所有源码在我的个人github ;这博客是记录我学习的点点滴滴,如果您对 Python、Java、AI、算法有兴趣,可以关注我的动态,一起学习,共同进步

本项目采用tensorflow2.4

目录

1)引入包

2)Encoder编码部分

3)Decode解码部分

3)定义Seq2Seq方法

4)读取单词

5)处理数据

6) 训练模型

7)保存与加载模型

8)编码

9)解码

10)进行预测


1)引入包

导入 TensorFlow 和 Keras 相关的模块和类,以便在代码中使用它们构建和训练神经网络模型。

首先,使用以下代码导入 TensorFlow 模块和 Keras 模块,然后使用from tensorflow import keras导入 Keras 模块,这样可以在代码中使用 Keras 提供的高级 API 来构建和训练深度学习模型。

接下来,使用以下代码导入一些特定的 Keras 类和模块。

  • from tensorflow.keras import backend as K导入 Keras 的 backend 模块,并将其命名为 K。这个模块提供了对底层 TensorFlow 操作和函数的访问。

  • from tensorflow.keras import activations导入 Keras 的 activations 模块,它包含了各种激活函数的定义,如 sigmoidrelu 等。

  • from tensorflow.keras.layers import Layer, Input, Embedding, LSTM, Dense, Attention导入 Keras 的一些常用层类,包括自定义层、输入层、嵌入层、LSTM 层、全连接层和注意力层。

  • from tensorflow.keras.models import Model导入 Keras 的模型类 Model,它用于定义和组装神经网络模型

通过导入这些模块和类,可以在代码中使用它们来构建和训练深度学习模型,使用各种层、激活函数和优化器等来定义模型的架构和行为。

  1. import tensorflow as tf
  2. from tensorflow import keras
  3. from tensorflow.keras import backend as K
  4. from tensorflow.keras import activations
  5. from tensorflow.keras.layers import Layer, Input, Embedding, LSTM, Dense, Attention
  6. from tensorflow.keras.models import Model

2)Encoder编码部分

这段代码定义了一个名为Encoder的Keras模型类。该类继承自keras.Model,表示它是一个自定义模型。调用父类keras.Model的构造函数,确保正确地初始化继承的模型类。

Encoder类的构造函数__init__中,接收三个参数:vocab_size(词汇表大小)、embedding_dim(嵌入维度)和hidden_units(隐藏层单元数)。

创建了一个嵌入层Embedding。嵌入层将词汇表中的整数索引转换为密集向量表示,以便能够在模型中进行处理。vocab_size表示词汇表的大小,embedding_dim表示嵌入向量的维度,而mask_zero=True表示将序列中的0值掩盖,以便在后续处理中忽略它们。

  1. class Encoder(keras.Model):
  2. def __init__(self, vocab_size, embedding_dim, hidden_units):
  3. super(Encoder, self).__init__()
  4. # Embedding Layer
  5. self.embedding = Embedding(vocab_size, embedding_dim, mask_zero=True)
  6. # Encode LSTM Layer
  7. self.encoder_lstm = LSTM(hidden_units, return_sequences=True, return_state=True, name="encode_lstm")
  8. def call(self, inputs):
  9. encoder_embed = self.embedding(inputs)
  10. encoder_outputs, state_h, state_c = self.encoder_lstm(encoder_embed)
  11. return encoder_outputs, state_h, state_c

3)Decode解码部分

定义了一个名为Decoder的Keras模型类。该类继承自keras.Model,表示它是一个自定义模型。

Decoder类的构造函数__init__中,接收三个参数:vocab_size(词汇表大小)、embedding_dim(嵌入维度)和hidden_units(隐藏层单元数)。

调用父类keras.Model的构造函数,确保正确地初始化继承的模型类。

用于将词汇表中的整数索引转换为密集向量表示。与Encoder类中的嵌入层类似,vocab_size表示词汇表的大小,embedding_dim表示嵌入向量的维度,而mask_zero=True表示将序列中的0值掩盖,以便在后续处理中忽略它们。

  1. class Decoder(keras.Model):
  2. def __init__(self, vocab_size, embedding_dim, hidden_units):
  3. super(Decoder, self).__init__()
  4. # Embedding Layer
  5. self.embedding = Embedding(vocab_size, embedding_dim, mask_zero=True)
  6. # Decode LSTM Layer
  7. self.decoder_lstm = LSTM(hidden_units, return_sequences=True, return_state=True, name="decode_lstm")
  8. # Attention Layer
  9. self.attention = Attention()
  10. def call(self, enc_outputs, dec_inputs, states_inputs):
  11. decoder_embed = self.embedding(dec_inputs)
  12. dec_outputs, dec_state_h, dec_state_c = self.decoder_lstm(decoder_embed, initial_state=states_inputs)
  13. attention_output = self.attention([dec_outputs, enc_outputs])
  14. return attention_output, dec_state_h, dec_state_c

3)定义Seq2Seq方法

这段代码定义了一个名为`Seq2Seq`的函数,用于构建序列到序列(seq2seq)模型。

以下是对代码的解释:

1. `def Seq2Seq(maxlen, embedding_dim, hidden_units, vocab_size):`:这行代码定义了一个名为`Seq2Seq`的函数,它接受四个参数:`maxlen`(输入序列的最大长度)、`embedding_dim`(嵌入维度)、`hidden_units`(隐藏层单元数)和`vocab_size`(词汇表大小)。

2. `encoder_inputs = Input(shape=(maxlen,), name="encode_input")`:这行代码创建了一个输入层`Input`,用于接收编码器的输入序列。输入序列的形状为`(maxlen,)`,表示输入是一个长度为`maxlen`的一维整数数组。

3. `decoder_inputs = Input(shape=(None,), name="decode_input")`:这行代码创建了另一个输入层`Input`,用于接收解码器的输入序列。解码器的输入序列长度可以是可变的,因此形状被设置为`(None,)`,表示接受任意长度的一维整数数组。

4. `encoder = Encoder(vocab_size, embedding_dim, hidden_units)`:这行代码创建了一个编码器对象`Encoder`,并传入词汇表大小、嵌入维度和隐藏层单元数作为参数。

5. `enc_outputs, enc_state_h, enc_state_c = encoder(encoder_inputs)`:这行代码调用编码器对象的`call`方法,对编码器的输入序列进行编码处理,得到编码器的输出序列`enc_outputs`以及最后一个时间步的隐藏状态`enc_state_h`和`enc_state_c`。

6. `dec_states_inputs = [enc_state_h, enc_state_c]`:这行代码将编码器的最后一个时间步的隐藏状态作为解码器的初始隐藏状态。

7. `decoder = Decoder(vocab_size, embedding_dim, hidden_units)`:这行代码创建了一个解码器对象`Decoder`,并传入词汇表大小、嵌入维度和隐藏层单元数作为参数。

8. `attention_output, dec_state_h, dec_state_c = decoder(enc_outputs, decoder_inputs, dec_states_inputs)`:这行代码调用解码器对象的`call`方法,对解码器的输入序列进行解码处理,得到注意力机制的输出`attention_output`以及最后一个时间步的隐藏状态`dec_state_h`和`dec_state_c`。

9. `dense_outputs = Dense(vocab_size, activation='softmax', name="dense")(attention_output)`:这行代码创建一个全连接层`Dense`,用于将注意力机制的输出映射为词汇表大小的向量,并应用softmax激活函数。

10. `model = Model(inputs=[encoder_inputs, decoder_inputs], outputs=dense_outputs)`:这行代码创建一个`Model`模型对象,将编码器的输入序列和解码器的输入序列作为输入,将全连接层的输出作为

  1. def Seq2Seq(maxlen, embedding_dim, hidden_units, vocab_size):
  2. """
  3. seq2seq model
  4. """
  5. # Input Layer
  6. encoder_inputs = Input(shape=(maxlen,), name="encode_input")
  7. decoder_inputs = Input(shape=(None,), name="decode_input")
  8. # Encoder Layer
  9. encoder = Encoder(vocab_size, embedding_dim, hidden_units)
  10. enc_outputs, enc_state_h, enc_state_c = encoder(encoder_inputs)
  11. dec_states_inputs = [enc_state_h, enc_state_c]
  12. # Decoder Layer
  13. decoder = Decoder(vocab_size, embedding_dim, hidden_units)
  14. attention_output, dec_state_h, dec_state_c = decoder(enc_outputs, decoder_inputs, dec_states_inputs)
  15. # Dense Layer
  16. dense_outputs = Dense(vocab_size, activation='softmax', name="dense")(attention_output)
  17. # seq2seq model
  18. model = Model(inputs=[encoder_inputs, decoder_inputs], outputs = dense_outputs)
  19. return model

4)读取单词

这段代码定义了三个函数,用于读取和处理文本数据。

1. `def read_vocab(vocab_path):`:这个函数接受一个参数`vocab_path`,表示词汇表文件的路径。函数通过打开文件并逐行读取其中的内容,将每个词汇去除首尾的空白字符后添加到`vocab_words`列表中。最后,返回包含所有词汇的`vocab_words`列表。

2. `def read_data(data_path):`:这个函数接受一个参数`data_path`,表示数据文件的路径。函数通过打开文件并逐行读取其中的内容,将每行内容按空格分割成单词列表,并将每个单词列表添加到`datas`列表中。最后,返回包含所有数据的`datas`列表。

3. `def process_data_index(datas, vocab2id):`:这个函数接受两个参数`datas`和`vocab2id`,分别表示数据列表和词汇到索引的映射字典。函数遍历`datas`中的每个单词列表,并根据`vocab2id`将单词转换为对应的索引值。如果单词不在`vocab2id`中,则使用"<UNK>"的索引代替。将每个单词列表转换为索引列表后,将其添加到`data_indexs`列表中。最后,返回包含所有数据索引的`data_indexs`列表。

这些函数可以用于读取和处理文本数据,并将其转换为模型可以处理的索引表示形式。

  1. def read_vocab(vocab_path):
  2. vocab_words = []
  3. with open(vocab_path, "r", encoding="utf8") as f:
  4. for line in f:
  5. vocab_words.append(line.strip())
  6. return vocab_words
  7. def read_data(data_path):
  8. datas = []
  9. with open(data_path, "r", encoding="utf8") as f:
  10. for line in f:
  11. words = line.strip().split()
  12. datas.append(words)
  13. return datas
  14. def process_data_index(datas, vocab2id):
  15. data_indexs = []
  16. for words in datas:
  17. line_index = [vocab2id[w] if w in vocab2id else vocab2id["<UNK>"] for w in words]
  18. data_indexs.append(line_index)
  19. return data_indexs

这段代码展示了如何使用之前定义的函数来读取和处理文本数据,并输出一些示例数据。

以下是代码的解释:

1. `vocab_words = read_vocab("./data/ch_word_vocab.txt")`:调用`read_vocab`函数读取词汇表文件`ch_word_vocab.txt`,将返回的词汇列表赋值给`vocab_words`。

2. `special_words = ["<PAD>", "<UNK>", "<GO>", "<EOS>"]`:定义一个包含特殊词汇的列表。

3. `vocab_words = special_words + vocab_words`:将特殊词汇列表和之前读取的词汇列表连接起来,得到最终的词汇列表。

4. `vocab2id = {word: i for i, word in enumerate(vocab_words)}`:创建一个将词汇映射到索引的字典`vocab2id`,其中索引是从0开始递增的。

5. `id2vocab = {i: word for i, word in enumerate(vocab_words)}`:创建一个将索引映射到词汇的字典`id2vocab`,与上述字典相反。

6. `num_sample = 1000`:定义一个样本数量的变量,限制数据集中的样本数量。

7. `source_data = read_data("./data/ch_source_data_seg.txt")[:num_sample]`:调用`read_data`函数读取源数据文件`ch_source_data_seg.txt`中的内容,并将其限制在前`num_sample`个样本,得到源数据列表`source_data`。

8. `source_data_ids = process_data_index(source_data, vocab2id)`:调用`process_data_index`函数将源数据列表转换为索引形式,使用之前创建的`vocab2id`字典进行映射,得到源数据索引列表`source_data_ids`。

9. `target_data = read_data("./data/ch_target_data_seg.txt")[:num_sample]`:调用`read_data`函数读取目标数据文件`ch_target_data_seg.txt`中的内容,并将其限制在前`num_sample`个样本,得到目标数据列表`target_data`。

10. `target_data_ids = process_data_index(target_data, vocab2id)`:调用`process_data_index`函数将目标数据列表转换为索引形式,使用之前创建的`vocab2id`字典进行映射,得到目标数据索引列表`target_data_ids`。

11. `print("vocab test: ", [id2vocab[i] for i in range(10)])`:打印前10个索引对应的词汇,用于测试词汇表的映射。

12. `print("source test: ", source_data[0])`:打印源数据中的第一个样本,用于测试源数据的读取。

13. `print("source index: ", source_data_ids[0])`:打印源数据中的第一个样本的索引表示形式,用于测试源数据的索引转换。

14. `print("target test: ", target_data[0])`:打印目标数据中的

 

  1. vocab_words = read_vocab("./data/ch_word_vocab.txt")
  2. special_words = ["<PAD>", "<UNK>", "<GO>", "<EOS>"]
  3. vocab_words = special_words + vocab_words
  4. vocab2id = {word: i for i, word in enumerate(vocab_words)}
  5. id2vocab = {i: word for i, word in enumerate(vocab_words)}
  6. num_sample = 1000
  7. source_data = read_data("./data/ch_source_data_seg.txt")[:num_sample]
  8. source_data_ids = process_data_index(source_data, vocab2id)
  9. target_data = read_data("./data/ch_target_data_seg.txt")[:num_sample]
  10. target_data_ids = process_data_index(target_data, vocab2id)
  11. print("vocab test: ", [id2vocab[i] for i in range(10)])
  12. print("source test: ", source_data[0])
  13. print("source index: ", source_data_ids[0])
  14. print("target test: ", target_data[0])
  15. print("target index: ", target_data_ids[0])
vocab test:  ['<PAD>', '<UNK>', '<GO>', '<EOS>', '呵呵', '不是', '怎么', '了', '开心', '点']
source test:  ['呵呵']
source index:  [4]
target test:  ['是', '王若', '猫', '的', '。']
target index:  [27, 37846, 756, 45, 180]

5)处理数据

这段代码定义了一个名为`process_input_data`的函数,用于将源数据索引列表和目标数据索引列表进行处理,生成模型的输入数据。

以下是代码的解释:

1. `def process_input_data(source_data_ids, target_indexs, vocab2id):`:这个函数接受三个参数,分别是源数据索引列表`source_data_ids`、目标数据索引列表`target_indexs`,以及词汇到索引的映射字典`vocab2id`。

2. `source_inputs = []`:定义一个空列表`source_inputs`,用于存储处理后的源输入数据。

3. `decoder_inputs, decoder_outputs = [], []`:定义两个空列表`decoder_inputs`和`decoder_outputs`,分别用于存储处理后的解码器输入和解码器输出数据。

4. `for source, target in zip(source_data_ids, target_indexs):`:通过`zip`函数将源数据和目标数据一一对应地迭代。

5. `source_inputs.append([vocab2id["<GO>"]] + source + [vocab2id["<EOS>"]])`:将源数据加上起始标记"<GO>"和结束标记"<EOS>"后,添加到`source_inputs`列表中。

6. `decoder_inputs.append([vocab2id["<GO>"]] + target)`:将目标数据加上起始标记"<GO>"后,添加到`decoder_inputs`列表中。

7. `decoder_outputs.append(target + [vocab2id["<EOS>"]])`:将目标数据加上结束标记"<EOS>"后,添加到`decoder_outputs`列表中。

8. `return source_inputs, decoder_inputs, decoder_outputs`:返回处理后的源输入数据、解码器输入数据和解码器输出数据。

9. `source_input_ids, target_input_ids, target_output_ids = process_input_data(source_data_ids, target_data_ids, vocab2id)`:调用`process_input_data`函数,将源数据索引列表、目标数据索引列表和词汇到索引的映射字典作为参数,得到处理后的源输入数据、解码器输入数据和解码器输出数据。

10. `print("encoder inputs: ", source_input_ids[:2])`:打印前两个样本的源输入数据,用于测试处理结果。

11. `print("decoder inputs: ", target_input_ids[:2])`:打印前两个样本的解码器输入数据,用于测试处理结果。

12. `print("decoder outputs: ", target_output_ids[:2])`:打印前两个样本的解码器输出数据,用于测试处理结果。

  1. def process_input_data(source_data_ids, target_indexs, vocab2id):
  2. source_inputs = []
  3. decoder_inputs, decoder_outputs = [], []
  4. for source, target in zip(source_data_ids, target_indexs):
  5. source_inputs.append([vocab2id["<GO>"]] + source + [vocab2id["<EOS>"]])
  6. decoder_inputs.append([vocab2id["<GO>"]] + target)
  7. decoder_outputs.append(target + [vocab2id["<EOS>"]])
  8. return source_inputs, decoder_inputs, decoder_outputs
  9. source_input_ids, target_input_ids, target_output_ids = process_input_data(source_data_ids, target_data_ids, vocab2id)
  10. print("encoder inputs: ", source_input_ids[:2])
  11. print("decoder inputs: ", target_input_ids[:2])
  12. print("decoder outputs: ", target_output_ids[:2])
encoder inputs:  [[2, 4, 3], [2, 5, 3]]
decoder inputs:  [[2, 27, 37846, 756, 45, 180], [2, 38, 27, 84, 49272]]
decoder outputs:  [[27, 37846, 756, 45, 180, 3], [38, 27, 84, 49272, 3]]

这段代码使用Keras的`pad_sequences`函数对源输入数据、解码器输入数据和解码器输出数据进行填充,使它们具有相同的固定长度。

以下是代码的解释:

1. `maxlen = 10`:定义最大长度为10,用于指定填充后的序列长度。

2. `source_input_ids = keras.preprocessing.sequence.pad_sequences(source_input_ids, padding='post', maxlen=maxlen)`:使用`pad_sequences`函数对源输入数据进行填充,使其长度为`maxlen`,填充的方式是在序列末尾进行填充('post'),将结果赋值给`source_input_ids`。

3. `target_input_ids = keras.preprocessing.sequence.pad_sequences(target_input_ids, padding='post',  maxlen=maxlen)`:使用`pad_sequences`函数对解码器输入数据进行填充,使其长度为`maxlen`,填充的方式是在序列末尾进行填充('post'),将结果赋值给`target_input_ids`。

4. `target_output_ids = keras.preprocessing.sequence.pad_sequences(target_output_ids, padding='post',  maxlen=maxlen)`:使用`pad_sequences`函数对解码器输出数据进行填充,使其长度为`maxlen`,填充的方式是在序列末尾进行填充('post'),将结果赋值给`target_output_ids`。

5. `print(source_data_ids[:5])`:打印源数据索引列表的前5个样本,用于比较填充前后的结果。

6. `print(target_input_ids[:5])`:打印解码器输入数据的前5个样本,用于比较填充前后的结果。

7. `print(target_output_ids[:5])`:打印解码器输出数据的前5个样本,用于比较填充前后的结果。

  1. maxlen = 10
  2. source_input_ids = keras.preprocessing.sequence.pad_sequences(source_input_ids, padding='post', maxlen=maxlen)
  3. target_input_ids = keras.preprocessing.sequence.pad_sequences(target_input_ids, padding='post', maxlen=maxlen)
  4. target_output_ids = keras.preprocessing.sequence.pad_sequences(target_output_ids, padding='post', maxlen=maxlen)
  5. print(source_data_ids[:5])
  6. print(target_input_ids[:5])
  7. print(target_output_ids[:5])
[[4], [5], [6, 7], [8, 9, 10, 11, 12, 13, 14, 15], [16, 17, 18, 19, 11, 20]]
[[    2    27 37846   756    45   180     0     0     0     0]
 [    2    38    27    84 49272     0     0     0     0     0]
 [    2    16  6692    82 49273   320    16   518     0     0]
 [    2   526     0     0     0     0     0     0     0     0]
 [   16   438    22   328    19 49272 15817   254  1764 49272]]
[[   27 37846   756    45   180     3     0     0     0     0]
 [   38    27    84 49272     3     0     0     0     0     0]
 [   16  6692    82 49273   320    16   518     3     0     0]
 [  526     3     0     0     0     0     0     0     0     0]
 [  438    22   328    19 49272 15817   254  1764 49272     3]]

这段代码包含以下操作:

1. `K.clear_session()`:这是TensorFlow的函数,用于清除当前会话中的所有图和变量,以便重新构建模型。

2. `maxlen = 10`:定义最大长度为10,用于指定输入序列的固定长度。

3. `embedding_dim = 50`:定义嵌入维度为50,用于指定嵌入层的输出维度。

4. `hidden_units = 128`:定义隐藏单元数为128,用于指定LSTM层的隐藏单元数量。

5. `vocab_size = len(vocab2id)`:计算词汇表的大小,即词汇表中唯一词语的数量。

6. `model = Seq2Seq(maxlen, embedding_dim, hidden_units, vocab_size)`:创建一个名为`model`的Seq2Seq模型,使用之前定义的最大长度、嵌入维度、隐藏单元数和词汇表大小作为参数。

7. `model.summary()`:打印模型的摘要信息,包括模型的层次结构、参数数量和每层的输出形状。该信息有助于了解模型的架构和参数情况。

 

  1. K.clear_session()
  2. maxlen = 10
  3. embedding_dim = 50
  4. hidden_units = 128
  5. vocab_size = len(vocab2id)
  6. model = Seq2Seq(maxlen, embedding_dim, hidden_units, vocab_size)
  7. model.summary()
Model: "model"
_______________________________________________________________________________________
Layer (type)                    Output Shape         Param #     Connected to                     
=======================================================================================
encode_input (InputLayer)       [(None, 10)]         0                                            
_______________________________________________________________________________________
encoder (Encoder)               ((None, 10, 128), (N 3598348     encode_input[0][0]               
_______________________________________________________________________________________
decode_input (InputLayer)       [(None, None)]       0                                            
_______________________________________________________________________________________
decoder (Decoder)               ((None, None, 128),  3598348     encoder[0][0]                    
                                                                 decode_input[0][0]               
                                                                 encoder[0][1]                    
                                                                 encoder[0][2]                    
_______________________________________________________________________________________
dense (Dense)                   (None, None, 70134)  9047286     decoder[0][0]                    
=======================================================================================
Total params: 16,243,982
Trainable params: 16,243,982
Non-trainable params: 0

6) 训练模型

这段代码执行了以下操作:

1. `epochs = 20`:定义训练的迭代轮数为20。

2. `batch_size = 32`:定义每个批次的样本数量为32。

3. `val_rate = 0.2`:定义验证集的比例为0.2,用于划分训练集和验证集。

4. `loss_fn = keras.losses.SparseCategoricalCrossentropy()`:定义损失函数为稀疏分类交叉熵损失函数,用于计算模型的损失值。

5. `model.compile(loss=loss_fn, optimizer='adam')`:编译模型,指定损失函数和优化器。使用稀疏分类交叉熵损失函数作为损失函数,并使用Adam优化器进行参数优化。

6. `model.fit([source_input_ids, target_input_ids], target_output_ids, batch_size=batch_size, epochs=epochs, validation_split=val_rate)`:使用训练数据进行模型训练。训练数据包括源输入数据、解码器输入数据和解码器输出数据。指定批次大小、迭代轮数和验证集的比例。训练过程中,模型会自动计算损失值并进行参数更新,同时在每个迭代轮数结束后评估模型在验证集上的性能。

  1. epochs = 20
  2. batch_size = 32
  3. val_rate = 0.2
  4. loss_fn = keras.losses.SparseCategoricalCrossentropy()
  5. model.compile(loss=loss_fn, optimizer='adam')
  6. model.fit([source_input_ids, target_input_ids], target_output_ids,
  7. batch_size=batch_size, epochs=epochs, validation_split=val_rate)
Epoch 1/20
25/25 [==============================] - 29s 807ms/step - loss: 6.4676 - val_loss: 6.7728
Epoch 2/20
25/25 [==============================] - 14s 566ms/step - loss: 5.5570 - val_loss: 4.3079
Epoch 3/20
25/25 [==============================] - 14s 567ms/step - loss: 3.3806 - val_loss: 4.3989
Epoch 4/20
25/25 [==============================] - 15s 610ms/step - loss: 3.1398 - val_loss: 4.4503
Epoch 5/20
25/25 [==============================] - 15s 604ms/step - loss: 3.1003 - val_loss: 4.4969
Epoch 6/20
25/25 [==============================] - 16s 647ms/step - loss: 3.0329 - val_loss: 4.5317
Epoch 7/20
25/25 [==============================] - 16s 658ms/step - loss: 3.0294 - val_loss: 4.5666
Epoch 8/20
25/25 [==============================] - 16s 647ms/step - loss: 3.0492 - val_loss: 4.5931
Epoch 9/20
25/25 [==============================] - 15s 623ms/step - loss: 3.0186 - val_loss: 4.6177
Epoch 10/20
25/25 [==============================] - 16s 621ms/step - loss: 3.0837 - val_loss: 4.6449
Epoch 11/20
25/25 [==============================] - 14s 554ms/step - loss: 3.0654 - val_loss: 4.6655
Epoch 12/20
25/25 [==============================] - 17s 691ms/step - loss: 3.0654 - val_loss: 4.6791
Epoch 13/20
25/25 [==============================] - 16s 615ms/step - loss: 2.9685 - val_loss: 4.6993
Epoch 14/20
25/25 [==============================] - 15s 594ms/step - loss: 3.0559 - val_loss: 4.7213
Epoch 15/20
25/25 [==============================] - 15s 600ms/step - loss: 2.9749 - val_loss: 4.7328
Epoch 16/20
25/25 [==============================] - 15s 612ms/step - loss: 2.9694 - val_loss: 4.7469
Epoch 17/20
25/25 [==============================] - 16s 633ms/step - loss: 2.9646 - val_loss: 4.7588
Epoch 18/20
25/25 [==============================] - 15s 622ms/step - loss: 3.0883 - val_loss: 4.7736
Epoch 19/20
25/25 [==============================] - 14s 577ms/step - loss: 2.9960 - val_loss: 4.7863
Epoch 20/20
25/25 [==============================] - 14s 585ms/step - loss: 3.0140 - val_loss: 4.7999

7)保存与加载模型

这段代码执行了以下操作:

1. `model.save_weights("./data/seq2seq_attention_weights.h5")`:将模型的权重保存到指定路径下的HDF5文件中。这样可以在后续重新加载模型时使用这些权重。

2. `del model`:删除当前的模型实例,以释放内存空间。

3. `K.clear_session()`:清除当前会话中的所有图和变量,以便重新构建模型。

4. `model = Seq2Seq(maxlen, embedding_dim, hidden_units, vocab_size)`:创建一个新的Seq2Seq模型实例,使用之前定义的参数。

5. `model.load_weights("./data/seq2seq_attention_weights.h5")`:从指定路径的HDF5文件中加载保存的模型权重,将其应用于新创建的模型实例。

6. `print(model.summary())`:打印新模型的摘要信息,以验证加载的权重是否成功应用于模型。该信息包括模型的层次结构、参数数量和每层的输出形状。

  1. model.save_weights("./data/seq2seq_attention_weights.h5")
  2. del model
  3. K.clear_session()
  4. model = Seq2Seq(maxlen, embedding_dim, hidden_units, vocab_size)
  5. model.load_weights("./data/seq2seq_attention_weights.h5")
  6. print(model.summary())

8)编码

这段代码定义了一个名为`encoder_infer`的函数,用于创建一个仅包含编码器部分的推断模型。

以下是代码的解释:

1. `def encoder_infer(model):`:定义了一个名为`encoder_infer`的函数,接受一个模型作为输入参数。

2. `encoder_model = Model(inputs = model.get_layer('encoder').input, outputs= model.get_layer('encoder').output)`:使用Keras的`Model`函数创建一个新的模型,该模型的输入和输出与原始模型的编码器部分相同。通过`model.get_layer('encoder').input`获取原始模型的编码器输入,通过`model.get_layer('encoder').output`获取原始模型的编码器输出。将获取的输入和输出作为参数传递给`Model`函数,创建一个新的模型实例,即仅包含编码器部分的推断模型,将其赋值给`encoder_model`。

3. `return encoder_model`:返回创建的编码器推断模型。

4. `encoder_model = encoder_infer(model)`:使用`encoder_infer`函数创建一个仅包含编码器部分的推断模型,将其赋值给`encoder_model`。

5. `print(encoder_model.summary())`:打印编码器推断模型的摘要信息,包括模型的层次结构、参数数量和每层的输出形状。该信息有助于了解编码器推断模型的架构和参数情况。

  1. def encoder_infer(model):
  2. encoder_model = Model(inputs = model.get_layer('encoder').input,
  3. outputs= model.get_layer('encoder').output)
  4. return encoder_model
  5. encoder_model = encoder_infer(model)
  6. print(encoder_model.summary())

9)解码

这段代码定义了一个名为`decoder_infer`的函数,用于创建一个仅包含解码器部分的推断模型。

以下是代码的解释:

1. `def decoder_infer(model, encoder_model):`:定义了一个名为`decoder_infer`的函数,接受两个参数,一个是原始模型,另一个是编码器推断模型。

2. `encoder_output = encoder_model.get_layer('encoder').output[0]`:从编码器推断模型中获取编码器的输出。这里假设编码器的输出是一个列表,通过索引`[0]`获取第一个元素,即编码器的输出。

3. `maxlen, hidden_units = encoder_output.shape[1:]`:获取编码器输出的形状信息,其中`maxlen`表示序列的最大长度,`hidden_units`表示隐藏单元的数量。

4. `dec_input = model.get_layer('decode_input').input`:从原始模型中获取解码器的输入。

5. `enc_output = Input(shape=(maxlen, hidden_units), name='enc_output')`:创建一个输入张量`enc_output`,形状为`(maxlen, hidden_units)`,用于接收编码器的输出。

6. `dec_input_state_h = Input(shape=(hidden_units,), name='input_state_h')`:创建一个输入张量`dec_input_state_h`,形状为`(hidden_units,)`,用于接收解码器的初始隐藏状态`state_h`。

7. `dec_input_state_c = Input(shape=(hidden_units,), name='input_state_c')`:创建一个输入张量`dec_input_state_c`,形状为`(hidden_units,)`,用于接收解码器的初始细胞状态`state_c`。

8. `dec_input_states = [dec_input_state_h, dec_input_state_c]`:将初始隐藏状态和初始细胞状态组成一个列表`dec_input_states`。

9. `decoder = model.get_layer('decoder')`:从原始模型中获取解码器层。

10. `dec_outputs, out_state_h, out_state_c = decoder(enc_output, dec_input, dec_input_states)`:使用编码器的输出、解码器的输入和初始状态作为参数,调用解码器层,获取解码器的输出、最终的隐藏状态和细胞状态。

11. `dec_output_states = [out_state_h, out_state_c]`:将最终的隐藏状态和细胞状态组成一个列表`dec_output_states`。

12. `decoder_dense = model.get_layer('dense')`:从原始模型中获取全连接层。

13. `dense_output = decoder_dense(dec_outputs)`:将解码器的输出作为参数,通过全连接层进行处理,得到最终的输出。

14. `decoder_model = Model(inputs=[enc_output, dec_input, dec_input_states], outputs=[dense_output]+dec_output_states)`:使用Keras的`Model`函数创建一个新的模型,该模型的输入包括编码器的输出、解码器的输入和初始状态,输出包括最终的输出和最终的隐藏状态和细胞状态。

  1. def decoder_infer(model, encoder_model):
  2. encoder_output = encoder_model.get_layer('encoder').output[0]
  3. maxlen, hidden_units = encoder_output.shape[1:]
  4. dec_input = model.get_layer('decode_input').input
  5. enc_output = Input(shape=(maxlen, hidden_units), name='enc_output')
  6. dec_input_state_h = Input(shape=(hidden_units,), name='input_state_h')
  7. dec_input_state_c = Input(shape=(hidden_units,), name='input_state_c')
  8. dec_input_states = [dec_input_state_h, dec_input_state_c]
  9. decoder = model.get_layer('decoder')
  10. dec_outputs, out_state_h, out_state_c = decoder(enc_output, dec_input, dec_input_states)
  11. dec_output_states = [out_state_h, out_state_c]
  12. decoder_dense = model.get_layer('dense')
  13. dense_output = decoder_dense(dec_outputs)
  14. decoder_model = Model(inputs=[enc_output, dec_input, dec_input_states],
  15. outputs=[dense_output]+dec_output_states)
  16. return decoder_model
  17. decoder_model = decoder_infer(model, encoder_model)
  18. decoder_model.summary()

10)进行预测

这段代码定义了一个名为`infer_predict`的函数,用于进行推断预测。

以下是代码的解释:

1. `def infer_predict(input_text, encoder_model, decoder_model):`:定义了一个名为`infer_predict`的函数,接受三个参数,分别是输入文本、编码器推断模型和解码器推断模型。

2. `text_words = input_text.split()[:maxlen]`:将输入文本按空格分割,并取前`maxlen`个词。

3. `input_id = [vocab2id[w] if w in vocab2id else vocab2id["<UNK>"] for w in text_words]`:将文本词转换为对应的索引,如果词不在词汇表中,则用`<UNK>`的索引代替。

4. `input_id = [vocab2id["<GO>"]] + input_id + [vocab2id["<EOS>"]]`:在输入序列的开头添加`<GO>`标记,在结尾添加`<EOS>`标记。

5. `if len(input_id) < maxlen:`:如果输入序列的长度小于`maxlen`,则使用`<PAD>`标记进行填充,使其长度为`maxlen`。

6. `input_source = np.array([input_id])`:将输入序列转换为NumPy数组。

7. `input_target = np.array([vocab2id["<GO>"]])`:创建一个长度为1的NumPy数组,包含`<GO>`标记的索引。

8. `enc_outputs, enc_state_h, enc_state_c = encoder_model.predict([input_source])`:使用编码器推断模型对输入进行预测,得到编码器的输出和最终的隐藏状态。

9. `dec_inputs = input_target`:将解码器的输入初始化为`<GO>`标记的索引。

10. `dec_states_inputs = [enc_state_h, enc_state_c]`:将解码器的初始隐藏状态和细胞状态初始化为编码器的最终隐藏状态和细胞状态。

11. `result_id = []`和`result_text = []`:用于存储预测结果的索引和文本。

12. `for i in range(maxlen):`:循环进行解码器的预测,最多进行`maxlen`次。

13. `dense_outputs, dec_state_h, dec_state_c = decoder_model.predict([enc_outputs, dec_inputs] + dec_states_inputs)`:使用解码器推断模型对当前输入进行预测,得到解码器的输出、最终的隐藏状态和细胞状态。

14. `pred_id = np.argmax(dense_outputs[0][0])`:根据解码器的输出选择概率最高的词的索引作为预测结果。

15. `result_id.append(pred_id)`和`result_text.append(id2vocab[pred_id])`:将预测结果的索引和对应的词加入到结果列表中。

16. `if id2vocab[pred_id] == "<EOS>":`:如果预测的词是`<EOS>`,则表示预测结束,跳出循环

  1. import numpy as np
  2. maxlen = 10
  3. def infer_predict(input_text, encoder_model, decoder_model):
  4. text_words = input_text.split()[:maxlen]
  5. input_id = [vocab2id[w] if w in vocab2id else vocab2id["<UNK>"] for w in text_words]
  6. input_id = [vocab2id["<GO>"]] + input_id + [vocab2id["<EOS>"]]
  7. if len(input_id) < maxlen:
  8. input_id = input_id + [vocab2id["<PAD>"]] * (maxlen-len(input_id))
  9. input_source = np.array([input_id])
  10. input_target = np.array([vocab2id["<GO>"]])
  11. # 编码器encoder预测输出
  12. enc_outputs, enc_state_h, enc_state_c = encoder_model.predict([input_source])
  13. dec_inputs = input_target
  14. dec_states_inputs = [enc_state_h, enc_state_c]
  15. result_id = []
  16. result_text = []
  17. for i in range(maxlen):
  18. # 解码器decoder预测输出
  19. dense_outputs, dec_state_h, dec_state_c = decoder_model.predict([enc_outputs, dec_inputs] + dec_states_inputs)
  20. pred_id = np.argmax(dense_outputs[0][0])
  21. result_id.append(pred_id)
  22. result_text.append(id2vocab[pred_id])
  23. if id2vocab[pred_id] == "<EOS>":
  24. break
  25. dec_inputs = np.array([[pred_id]])
  26. dec_states_inputs = [dec_state_h, dec_state_c]
  27. return result_id, result_text

根据给定的输入文本进行推断预测,并输出结果。

以下是代码的解释:

1. `input_text = "你是"`:设置输入文本为"你是"。

2. `result_id, result_text = infer_predict(input_text, encoder_model, decoder_model)`:调用`infer_predict`函数进行推断预测,得到预测结果的索引和文本。

3. `print("Input: ", input_text)`:输出输入文本。

4. `print("Output: ", result_text, result_id)`:输出预测结果的文本和索引。

  1. input_text = "你是"
  2. result_id, result_text = infer_predict(input_text, encoder_model, decoder_model)
  3. print("Input: ", input_text)
  4. print("Output: ", result_text, result_id)
Input:  你是
Output:  ['<EOS>'] [3]
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/很楠不爱3/article/detail/527420
推荐阅读
  

闽ICP备14008679号