【TensorFlow】LSTM(基于PTB的自然语言建模)

本文介绍了使用TensorFlow基于PTB数据集构建LSTM进行自然语言建模的过程,包括PTB数据集的获取、LSTM模型的创建、训练过程中的错误与解决方法,如tf.nn.rnn_cell的更改、tf.concat参数位置调整等。通过完整代码展示了模型运行及 perplexity 计算,强调了关注工具接口变化的重要性。
摘要由CSDN通过智能技术生成

项目已上传至 GitHub —— nl-modeling

1. 下载 PTB 数据集

官方下载地址的速度可能比较慢,这里提供了其他两种下载途径:

需要的 PTB 数据集就在解压之后的 data/ 文件夹下,data/ 文件夹下有 7 个文件,要用的只有 3 个:

ptb.test.txt
ptb.train.txt
ptb.valid.txt

要读取 PTB 数据集需要用到 reader.py,在 GitHub 上面有源码,可以下载或者直接复制下来。reader.py 提供了两个函数用于读取和处理 PTB 数据集:

  • ptb_raw_data(DATA_PATH):读取原始数据
  • ptb_producer(raw_data,batch_size,num_steps):用于将数据组织成大小为 batch_size,长度为 num_steps 的数据组

原书中的代码没有将这两个函数的操作对象视为 tensor,而根据 reader.py 中的源码说明,它是对 tensor 进行操作的。并且 ptb_producer() 函数中使用了 tf.train.range_input_producer() 函数,所以需要开启多线程。

以下代码示范了如何使用这两个函数:

import reader
import tensorflow as tf

# 数据路径
DATA_PATH = 'simple-examples/data/'

# 读取原始数据
train_data, valid_data, test_data, _ = reader.ptb_raw_data(DATA_PATH)

# 将数据组织成batch大小为4,截断长度为5的数据组,要放在开启多线程之前
batch = reader.ptb_producer(train_data, 4, 5)

with tf.Session() as sess:
    tf.global_variables_initializer().run()

    # 开启多线程
    coord = tf.train.Coordinator()
    threads = tf.train.start_queue_runners(coord=coord)

    # 读取前两个batch,其中包括每个时刻的输入和对应的答案,ptb_producer()会自动迭代
    for i in range(2):
        x, y = sess.run(batch)
        print('x:', x)
        print('y:', y)

    # 关闭多线程
    coord.request_stop()
    coord.join(threads)

运行结果如下:

x: [[9970 9971 9972 9974 9975]
 [ 332 7147  328 1452 8595]
 [1969    0   98   89 2254]
 [   3    3    2   14   24]]
y: [[9971 9972 9974 9975 9976]
 [7147  328 1452 8595   59]
 [   0   98   89 2254    0]
 [   3    2   14   24  198]]
x: [[9976 9980 9981 9982 9983]
 [  59 1569  105 2231    1]
 [   0  312 1641    4 1063]
 [ 198  150 2262   10    0]]
y: [[9980 9981 9982 9983 9984]
 [1569  105 2231    1  895]
 [ 312 1641    4 1063    8]
 [ 150 2262   10    0  507]]

2. 完整代码

该代码实现自《TensorFlow:实战Google深度学习框架》

整个代码的结构如下:

  • PTBModel 类用于创建 LSTM 网络结构及维护其状态
  • run_epoch() 函数使用给定的 model 在数据集上运行 train_op 并返回 perplexity 值
  • main() 函数定义图的运行

由于原书中的代码是基于 1.0,而我用的是 1.5,所以出现了很多错误,我将所遇到的错误的解决方法都记录在了文末。源码如下:

import reader
import numpy as np
import tensorflow as tf

# 数据参数
DATA_PATH = 'simple-examples/data/'  # 数据存放路径
VOCAB_SIZE = 10000  # 单词数量

# 神经网络参数
HIDDEN_SIZE = 200  # LSTM隐藏层规模
NUM_LAYERS = 2  # LSTM结构层数
LEARNING_RATE = 1.0  # 学习速率
KEEP_PROB = 0.5  # 节点不被dropout的概率
MAX_GRAD_NORM = 5  # 用于控制梯度膨胀的参数

# 训练参数
TRAIN_BATCH_SIZE = 20  # 训练数据batch大小
TRAIN_NUM_STEP = 35  # 训练数据截断长度

# 测试参数
EVAL_BATCH_SIZE = 1  # 测试数据batch大小
EVAL_NUM_STEP = 1  # 测试数据截断
NUM_EPOCH = 2  # 使用训练数据的轮数


# 通过PTBModel描述模型,方便维护循环神经网络中的状态
class PTBModel():
    def __init__(self, is_training, batch_size, num_steps):
        # 记录batch和截断长度
        self.batch_size = batch_size
        self.num_steps = num_steps

        # 定义输入层
        self.input_data = tf.placeholder(tf.int32, [batch_size, num_steps])

        # 定义预期输出
        self.targets = tf.placeholder(tf.int32, [batch_size, num_steps])

        # 定义LSTM为使用dropout的两层网络
        lstm_cell = tf.contrib.rnn.BasicLSTMCell(HIDDEN_SIZE)
        if is_training:
            lstm_cell = tf.contrib.rnn.DropoutWrapper(
                lstm_cell, output_keep_prob=KEEP_PROB)
        cell = tf.contrib.rnn.MultiRNNCell([lstm_cell] * NUM_LAYERS)

        # 初始化state
        self.initial_state = cell.zero_state(batch_size, tf.float32)

        # 将单词ID转为单词向量。每个单词都是HIDDEN_SIZE维
        embedding = tf.get_variable('embedding', [VOCAB_SIZE, HIDDEN_SIZE])

        # 将原本batch_size*num_steps的输入层转化为batch_size*num_steps*HIDDEN_SIZE
        inputs = tf.nn.embedding_lookup(embedding, self.input_data)

        # 只在训练时使用dropout
        if is_training:
            inputs = tf.nn.dropout(inputs, KEEP_PROB)

        # 定义输出列表
        outputs = []
        state = self.initial_state
        with tf.variable_scope('RNN'):
            for time_step in range(num_steps):
                if time_step > 0:
                    tf.get_variable_scope().reuse_variables()
                cell_output, state = cell(inputs[:, time_step, :],
                                          state)  # 将当前时刻的数据和状态传入LSTM
                outputs.append(cell_output)  # 将当前输出加入输出列表

        # 将输出列表展开成[batch,hidden_size*num_steps]
        # 再reshape成[batch*num_steps,hidden_size]
        output = tf.reshape(tf.concat(outputs, 1), [-1, HIDDEN_SIZE])

        # 将输出传入全连接层,每个时刻的输出都是长度为VOCAB_SIZE的数组
        weight = tf.get_variable('weight', [HIDDEN_SIZE, VOCAB_SIZE])
        bias = tf.get_variable('bias', [VOCAB_SIZE]
评论 39
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值