使用TensorFlow实现RNN模型入门篇2--char-rnn语言建模模型

这是使用tf实现RNN模型的第二篇,上次用很简单的例子实现了一个简单的RNN用于解释其原理,这次我们开始结合NLP尝试构建一个char-rnn的语言建模模型。和CNN的入门篇一样,我们这里也直接来分析一个github上star很多的项目,这样我们不仅可以学习到一些编程的标准规范,还能够开始我们的RNN-NLP之旅。闲话少说,先来介绍一下此次要实现的char-rnn模型。
这个模型是Andrej Karpathy提出来的,可以去看他的一篇博文The Unreasonable Effectiveness of Recurrent Neural Networks,代码存放在其github上面,不过是用lua编程实现的,在这之后sherjilozair使用tf进行了重写,这也就是我们今天要学习的代码。这里使用的是多层RNN/LSTM模型,我们同样按照数据集、预处理、模型构建、模型训练、结果分析的思路对其代码进行分析。

数据集和预处理

首先看一下这里要用到的数据集是小莎士比亚文集。很简单就是一个txt文本文件,我们的预处理工作主要是获得该数据集中所有出现的字符,存到vocab里面,并按照其出现次数多少构建索引列表,最后将我们的数据转化为int型索引。此外也包括譬如划分batch等功能。其实要实现的功能很简单,如果要我自己写的话应该是写很多个循环把想要的数据一次次遍历出来即可,但是这里作者使用collections.Counter函数以及dict、map、zip几个功能函数很简单的实现了,这也是我们需要学习的地方。接下来看一下代码:

class TextLoader():
    def __init__(self, data_dir, batch_size, seq_length, encoding='utf-8'):
        self.data_dir = data_dir
        self.batch_size = batch_size
        self.seq_length = seq_length
        self.encoding = encoding
        #第一次运行程序时只有input.txt一个文件,剩下两个文件是运行之后产生的
        input_file = os.path.join(data_dir, "input.txt")
        vocab_file = os.path.join(data_dir, "vocab.pkl")
        tensor_file = os.path.join(data_dir, "data.npy")
        #如果是第一次执行则调用preprocess函数,否则调用load_preprocessed函数。
        if not (os.path.exists(vocab_file) and os.path.exists(tensor_file)):
            print("reading text file")
            self.preprocess(input_file, vocab_file, tensor_file)
        else:
            print("loading preprocessed files")
            self.load_preprocessed(vocab_file, tensor_file)
        self.create_batches()
        self.reset_batch_pointer()

    def preprocess(self, input_file, vocab_file, tensor_file):
        with codecs.open(input_file, "r", encoding=self.encoding) as f:
            data = f.read()
        #使用Counter函数对输入数据进行统计。counter保存data中每个字符出现的次数
        counter = collections.Counter(data)
        #对counter进行排序,出现次数最多的排在前面
        count_pairs = sorted(counter.items(), key=lambda x: -x[1])
        #将data中出现的所有字符保存,这里有65个,所以voacb_size=65
        self.chars, _ = zip(*count_pairs)
        self.vocab_size = len(self.chars)
        #按照字符出现次数多少顺序将chars保存,vocab中存储的是char和顺序,这样方便将data转化为索引
        self.vocab = dict(zip(self.chars, range(len(self.chars))))
        with open(vocab_file, 'wb') as f:
            #保存chars
            cPickle.dump(self.chars, f)
        #将data中每个字符转化为索引下标。
        self.tensor = np.array(list(map(self.vocab.get, data)))
        np.save(tensor_file, self.tensor)

    def load_preprocessed(self, vocab_file, tensor_file):
        #如果是第二次运行,则可以直接读取之前保存的chars和tensor
        with open(vocab_file, 'rb') as f:
            self.chars = cPickle.load(f)
        self.vocab_size = len(self.chars)
        self.vocab = dict(zip(self.chars, range(len(self.chars))))
        self.tensor = np.load(tensor_file)
        self.num_batches = int(self.tensor.size / (self.batch_size *
                                                   self.seq_length))

    def create_batches(self):
        #首先将数据按batch_size切割,然后每个batch_size在按照seq_length进行切割
        self.num_batches = int(self.tensor.size / (self.batch_size *
                                                   self.seq_length))

        if self.num_batches == 0:
            assert False, "Not enough data. Make seq_length and batch_size small."

        self.tensor = self.tensor[:self.num_batches * self.batch_size * self.seq_length]
        xdata = self.tensor
   
  • 3
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值