import tensorflow as tf

# 1.参数设置。
# 假设输入数据已经转换成了单词编号的格式。
SRC_TRAIN_DATA = "F:\\TensorFlowGoogle\\201806-github\\TensorFlowGoogleCode\\Chapter09\\train.en" # 源语言输入文件。
TRG_TRAIN_DATA = "F:\\TensorFlowGoogle\\201806-github\\TensorFlowGoogleCode\\Chapter09\\train.zh" # 目标语言输入文件。
CHECKPOINT_PATH = "F:\\temp\\attention_ckpt" # checkpoint保存路径。 HIDDEN_SIZE = 1024 # LSTM的隐藏层规模。
DECODER_LAYERS = 2 # 解码器中LSTM结构的层数。这个例子中编码器固定使用单层的双向LSTM。
SRC_VOCAB_SIZE = 10000 # 源语言词汇表大小。
TRG_VOCAB_SIZE = 4000 # 目标语言词汇表大小。
BATCH_SIZE = 100 # 训练数据batch的大小。
NUM_EPOCH = 5 # 使用训练数据的轮数。
KEEP_PROB = 0.8 # 节点不被dropout的概率。
MAX_GRAD_NORM = 5 # 用于控制梯度膨胀的梯度大小上限。
SHARE_EMB_AND_SOFTMAX = True # 在Softmax层和词向量层之间共享参数。 MAX_LEN = 50 # 限定句子的最大单词数量。
SOS_ID = 1 # 目标语言词汇表中<sos>的ID。
# 2.读取训练数据并创建Dataset。
# 使用Dataset从一个文件中读取一个语言的数据。
# 数据的格式为每行一句话,单词已经转化为单词编号。
def MakeDataset(file_path):
dataset = tf.data.TextLineDataset(file_path)
# 根据空格将单词编号切分开并放入一个一维向量。
dataset = dataset.map(lambda string: tf.string_split([string]).values)
# 将字符串形式的单词编号转化为整数。
dataset = dataset.map(lambda string: tf.string_to_number(string, tf.int32))
# 统计每个句子的单词数量,并与句子内容一起放入Dataset中。
dataset = dataset.map(lambda x: (x, tf.size(x)))
return dataset # 从源语言文件src_path和目标语言文件trg_path中分别读取数据,并进行填充和
# batching操作。
def MakeSrcTrgDataset(src_path, trg_path, batch_size):
# 首先分别读取源语言数据和目标语言数据。
src_data = MakeDataset(src_path)
trg_data = MakeDataset(trg_path)
# 通过zip操作将两个Dataset合并为一个Dataset。现在每个Dataset中每一项数据ds
# 由4个张量组成:
# ds[0][0]是源句子
# ds[0][1]是源句子长度
# ds[1][0]是目标句子
# ds[1][1]是目标句子长度
dataset = tf.data.Dataset.zip((src_data, trg_data)) # 删除内容为空(只包含<EOS>)的句子和长度过长的句子。
def FilterLength(src_tuple, trg_tuple):
((src_input, src_len), (trg_label, trg_len)) = (src_tuple, trg_tuple)
src_len_ok = tf.logical_and(tf.greater(src_len, 1), tf.less_equal(src_len, MAX_LEN))
trg_len_ok = tf.logical_and(tf.greater(trg_len, 1), tf.less_equal(trg_len, MAX_LEN))
return tf.logical_and(src_len_ok, trg_len_ok)
dataset = dataset.filter(FilterLength) # 解码器需要两种格式的目标句子:
# 1.解码器的输入(trg_input),形式如同"<sos> X Y Z"
# 2.解码器的目标输出(trg_label),形式如同"X Y Z <eos>"
# 上面从文件中读到的目标句子是"X Y Z <eos>"的形式,我们需要从中生成"<sos> X Y Z"
# 形式并加入到Dataset中。
def MakeTrgInput(src_tuple, trg_tuple):
((src_input, src_len), (trg_label, trg_len)) = (src_tuple, trg_tuple)
trg_input = tf.concat([[SOS_ID], trg_label[:-1]], axis=0)
return ((src_input, src_len), (trg_input, trg_label, trg_len))
dataset = dataset.map(MakeTrgInput) # 随机打乱训练数据。
dataset = dataset.shuffle(10000) # 规定填充后输出的数据维度。
padded_shapes = (
(tf.TensorShape([None]), # 源句子是长度未知的向量
tf.TensorShape([])), # 源句子长度是单个数字
(tf.TensorShape([None]), # 目标句子(解码器输入)是长度未知的向量
tf.TensorShape([None]), # 目标句子(解码器目标输出)是长度未知的向量
tf.TensorShape([]))) # 目标句子长度是单个数字
# 调用padded_batch方法进行batching操作。
batched_dataset = dataset.padded_batch(batch_size, padded_shapes)
return batched_dataset
# 3.定义翻译模型。
# 定义NMTModel类来描述模型。
class NMTModel(object):
# 在模型的初始化函数中定义模型要用到的变量。
def __init__(self):
# 定义编码器和解码器所使用的LSTM结构。
self.enc_cell_fw = tf.nn.rnn_cell.BasicLSTMCell(HIDDEN_SIZE)
self.enc_cell_bw = tf.nn.rnn_cell.BasicLSTMCell(HIDDEN_SIZE)
self.dec_cell = tf.nn.rnn_cell.MultiRNNCell([tf.nn.rnn_cell.BasicLSTMCell(HIDDEN_SIZE) for _ in range(DECODER_LAYERS)]) # 为源语言和目标语言分别定义词向量。
self.src_embedding = tf.get_variable("src_emb", [SRC_VOCAB_SIZE, HIDDEN_SIZE])
self.trg_embedding = tf.get_variable("trg_emb", [TRG_VOCAB_SIZE, HIDDEN_SIZE]) # 定义softmax层的变量
if SHARE_EMB_AND_SOFTMAX:
self.softmax_weight = tf.transpose(self.trg_embedding)
else:
self.softmax_weight = tf.get_variable("weight", [HIDDEN_SIZE, TRG_VOCAB_SIZE])
self.softmax_bias = tf.get_variable("softmax_bias", [TRG_VOCAB_SIZE]) # 在forward函数中定义模型的前向计算图。
# src_input, src_size, trg_input, trg_label, trg_size分别是上面
# MakeSrcTrgDataset函数产生的五种张量。
def forward(self, src_input, src_size, trg_input, trg_label, trg_size):
batch_size = tf.shape(src_input)[0] # 将输入和输出单词编号转为词向量。
src_emb = tf.nn.embedding_lookup(self.src_embedding, src_input)
trg_emb = tf.nn.embedding_lookup(self.trg_embedding, trg_input) # 在词向量上进行dropout。
src_emb = tf.nn.dropout(src_emb, KEEP_PROB)
trg_emb = tf.nn.dropout(trg_emb, KEEP_PROB) # 使用dynamic_rnn构造编码器。
# 编码器读取源句子每个位置的词向量,输出最后一步的隐藏状态enc_state。
# 因为编码器是一个双层LSTM,因此enc_state是一个包含两个LSTMStateTuple类
# 张量的tuple,每个LSTMStateTuple对应编码器中的一层。
# 张量的维度是 [batch_size, HIDDEN_SIZE]。
# enc_outputs是顶层LSTM在每一步的输出,它的维度是[batch_size,
# max_time, HIDDEN_SIZE]。Seq2Seq模型中不需要用到enc_outputs,而
# 后面介绍的attention模型会用到它。
# 下面的代码取代了Seq2Seq样例代码中forward函数里的相应部分。
with tf.variable_scope("encoder"):
# 构造编码器时,使用bidirectional_dynamic_rnn构造双向循环网络。
# 双向循环网络的顶层输出enc_outputs是一个包含两个张量的tuple,每个张量的
# 维度都是[batch_size, max_time, HIDDEN_SIZE],代表两个LSTM在每一步的输出。
enc_outputs, enc_state = tf.nn.bidirectional_dynamic_rnn(self.enc_cell_fw, self.enc_cell_bw, src_emb, src_size, dtype=tf.float32)
# 将两个LSTM的输出拼接为一个张量。
enc_outputs = tf.concat([enc_outputs[0], enc_outputs[1]], -1) with tf.variable_scope("decoder"):
# 选择注意力权重的计算模型。BahdanauAttention是使用一个隐藏层的前馈神经网络。
# memory_sequence_length是一个维度为[batch_size]的张量,代表batch
# 中每个句子的长度,Attention需要根据这个信息把填充位置的注意力权重设置为0。
attention_mechanism = tf.contrib.seq2seq.BahdanauAttention(HIDDEN_SIZE, enc_outputs,memory_sequence_length=src_size) # 将解码器的循环神经网络self.dec_cell和注意力一起封装成更高层的循环神经网络。
attention_cell = tf.contrib.seq2seq.AttentionWrapper(self.dec_cell, attention_mechanism,attention_layer_size=HIDDEN_SIZE) # 使用attention_cell和dynamic_rnn构造编码器。
# 这里没有指定init_state,也就是没有使用编码器的输出来初始化输入,而完全依赖
# 注意力作为信息来源。
dec_outputs, _ = tf.nn.dynamic_rnn(attention_cell, trg_emb, trg_size, dtype=tf.float32) # 计算解码器每一步的log perplexity。这一步与语言模型代码相同。
output = tf.reshape(dec_outputs, [-1, HIDDEN_SIZE])
logits = tf.matmul(output, self.softmax_weight) + self.softmax_bias
loss = tf.nn.sparse_softmax_cross_entropy_with_logits(labels=tf.reshape(trg_label, [-1]), logits=logits) # 在计算平均损失时,需要将填充位置的权重设置为0,以避免无效位置的预测干扰
# 模型的训练。
label_weights = tf.sequence_mask(trg_size, maxlen=tf.shape(trg_label)[1], dtype=tf.float32)
label_weights = tf.reshape(label_weights, [-1])
cost = tf.reduce_sum(loss * label_weights)
cost_per_token = cost / tf.reduce_sum(label_weights) # 定义反向传播操作。反向操作的实现与语言模型代码相同。
trainable_variables = tf.trainable_variables() # 控制梯度大小,定义优化方法和训练步骤。
grads = tf.gradients(cost / tf.to_float(batch_size),trainable_variables)
grads, _ = tf.clip_by_global_norm(grads, MAX_GRAD_NORM)
optimizer = tf.train.GradientDescentOptimizer(learning_rate=1.0)
train_op = optimizer.apply_gradients(zip(grads, trainable_variables))
return cost_per_token, train_op
# 4.训练过程和主函数。
# 使用给定的模型model上训练一个epoch,并返回全局步数。
# 每训练200步便保存一个checkpoint。
def run_epoch(session, cost_op, train_op, saver, step):
# 训练一个epoch。
# 重复训练步骤直至遍历完Dataset中所有数据。
while True:
try:
# 运行train_op并计算损失值。训练数据在main()函数中以Dataset方式提供。
cost, _ = session.run([cost_op, train_op])
if step % 10 == 0:
print("After %d steps, per token cost is %.3f" % (step, cost))
# 每200步保存一个checkpoint。
if step % 200 == 0:
saver.save(session, CHECKPOINT_PATH, global_step=step)
step += 1
except tf.errors.OutOfRangeError:
break
return step def main():
# 定义初始化函数。
initializer = tf.random_uniform_initializer(-0.05, 0.05) # 定义训练用的循环神经网络模型。
with tf.variable_scope("nmt_model", reuse=None, initializer=initializer):
train_model = NMTModel() # 定义输入数据。
data = MakeSrcTrgDataset(SRC_TRAIN_DATA, TRG_TRAIN_DATA, BATCH_SIZE)
iterator = data.make_initializable_iterator()
(src, src_size), (trg_input, trg_label, trg_size) = iterator.get_next() # 定义前向计算图。输入数据以张量形式提供给forward函数。
cost_op, train_op = train_model.forward(src, src_size, trg_input,trg_label, trg_size) # 训练模型。
saver = tf.train.Saver()
step = 0
with tf.Session() as sess:
tf.global_variables_initializer().run()
for i in range(NUM_EPOCH):
print("In iteration: %d" % (i + 1))
sess.run(iterator.initializer)
step = run_epoch(sess, cost_op, train_op, saver, step) if __name__ == "__main__":
main()

吴裕雄--天生自然 pythonTensorFlow自然语言处理:Attention模型--训练的更多相关文章

  1. 吴裕雄--天生自然 pythonTensorFlow自然语言处理:Seq2Seq模型--训练

    import tensorflow as tf # 1.参数设置. # 假设输入数据已经用9.2.1小节中的方法转换成了单词编号的格式. SRC_TRAIN_DATA = "F:\\Tens ...

  2. 吴裕雄--天生自然 pythonTensorFlow自然语言处理:Attention模型--测试

    import sys import codecs import tensorflow as tf # 1.参数设置. # 读取checkpoint的路径.9000表示是训练程序在第9000步保存的ch ...

  3. 吴裕雄--天生自然 pythonTensorFlow自然语言处理:Seq2Seq模型--测试

    import sys import codecs import tensorflow as tf # 1.参数设置. # 读取checkpoint的路径.9000表示是训练程序在第9000步保存的ch ...

  4. 吴裕雄--天生自然 pythonTensorFlow自然语言处理:PTB 语言模型

    import numpy as np import tensorflow as tf # 1.设置参数. TRAIN_DATA = "F:\TensorFlowGoogle\\201806- ...

  5. 吴裕雄--天生自然 pythonTensorFlow自然语言处理:文本数据预处理--生成训练文件

    import sys import codecs # 1. 参数设置 MODE = "PTB_TRAIN" # 将MODE设置为"PTB_TRAIN", &qu ...

  6. 吴裕雄--天生自然 pythonTensorFlow自然语言处理:交叉熵损失函数

    import tensorflow as tf # 1. sparse_softmax_cross_entropy_with_logits样例. # 假设词汇表的大小为3, 语料包含两个单词" ...

  7. 吴裕雄--天生自然 pythonTensorFlow图形数据处理:循环神经网络预测正弦函数

    import numpy as np import tensorflow as tf import matplotlib.pyplot as plt # 定义RNN的参数. HIDDEN_SIZE = ...

  8. 吴裕雄--天生自然 pythonTensorFlow图形数据处理:数据集高层操作

    import tempfile import tensorflow as tf # 1. 列举输入文件. # 输入数据生成的训练和测试数据. train_files = tf.train.match_ ...

  9. 吴裕雄--天生自然 pythonTensorFlow图形数据处理:数据集基本使用方法

    import tempfile import tensorflow as tf # 1. 从数组创建数据集. input_data = [1, 2, 3, 5, 8] dataset = tf.dat ...

随机推荐

  1. windows driver 枚举串口

    //枚举串口 NTSTATUS status; HANDLE hKey = NULL; OBJECT_ATTRIBUTES oa; UNICODE_STRING strPath = RTL_CONST ...

  2. MVC MVP MVVM 简述

    MVC 通过代理或者通知传递数据. MVP 通过P绑定model和view解耦. MVVM 通过V绑定VM(监听VM属性的变化.方法传递(改变自身被监听属性)) VM绑定model设置自身属性.

  3. mini2440 裸机程序,下载到nand 里面,复制到 sdram 中不运行

    按照韦东山的视频中 sdram的裸机代码,写了一份,通过 minitools 下载到 0x30000000,然后烧录到 nand中,接过不能正常运行. 尝试过多种方法后,只有一种解决方法,就是不要用 ...

  4. 第三章,数据和C

    3.1 数据类型关键字 位:计算机内部数据存储的最小存储单位(bit). 字节:计算机中数据处理的基本单位(Byte)),1B=8bit. 字:计算机进行数据处理时,一次存取,加工和传送的数据长度.( ...

  5. 使用openssl做CA服务器,并且生成证书。

    [root@22 conf.d]# openssl genrsa -out /etc/pki/CA/private/cakey.pem 4096  #ca私钥 [root@22 conf.d]# op ...

  6. Linux下MSSQL部署

    目前主要使用的red hat系列的linux版本,CentoS 7.X,MSSQL2017 微软官方说明地址:https://docs.microsoft.com/zh-cn/sql/linux/qu ...

  7. 吴裕雄--天生自然C++语言学习笔记:C++ 修饰符类型

    C++ 允许在 char.int 和 double 数据类型前放置修饰符.修饰符用于改变基本类型的含义,所以它更能满足各种情境的需求. 下面列出了数据类型修饰符: signed unsigned lo ...

  8. c# 数据库操作,多数据库操作、数据库操作异常报错等问题

    1.引入相关的命名空间 在C#中要操作数据库,一般情况需要引入两个命名空间,在三种连接模式中都要引入下面的命名空间: System.Data;描述与数据源连接的当前状态. // // 摘要: // 连 ...

  9. PAT Advanced 1143 Lowest Common Ancestor (30) [二叉查找树 LCA]

    题目 The lowest common ancestor (LCA) of two nodes U and V in a tree is the deepest node that has both ...

  10. SAP HANA学习笔记

    SAP HANA:High-Performance Analytic ApplianceSAP HANA XSC:Extended Application Services Classic(SAP推出 ...