选用PTB数据集。
首先将这10000个不同的词汇分别映射到0~9999之间的整数编号。下面代码为每个词汇分配一个编号,然后将词汇表保存到一个独立的vocab文件中。
# -*- coding: utf-8 -*- import codecs import collections from operator import itemgetter RAW_DATA="E:/PTB数据集/simple-examples/simple-examples/data/ptb.train.txt" VOCAB_OUTPUT="ptb.vocab"#输出的词汇表文件 counter=collections.Counter()#统计单词出现的频率 with codecs.open(RAW_DATA, "r", "utf-8") as f: for line in f: for word in line.strip().split(): counter[word]+=1 #print(counter)#Counter({'the': 50770, '<unk>': 45020, 'N': 32481, 'of': 24400, 'to': 23638,.....}) #按照词频顺序对单词进行排序 sorted_word_to_cnt = sorted(counter.items(), key=itemgetter(1), reverse=True) sorted_words = [x[0] for x in sorted_word_to_cnt] #print(sorted_words)#['the', '<unk>', 'N', 'of', 'to', 'a', 'in', 'and', "'s", sorted_words = ["<eos>"]+ sorted_words #print(sorted_words)#['<eos>', 'the', '<unk>', 'N', 'o with codecs.open(VOCAB_OUTPUT,"w","utf-8") as file_output: for word in sorted_words: file_output.write(word+'\n') print(sorted_words)
vocab文件如下所示,共10000个词:
确定词汇表后,将表中词汇转化为单词编号
# -*- coding: utf-8 -*- import codecs import sys RAW_DATA="E:/PTB数据集/simple-examples/simple-examples/data/ptb.train.txt" VOCAB="ptb.vocab" OUTPUT_DATA="ptb.train"#将单词替换为数字编号后的输出文件 with codecs.open(VOCAB, "r", "utf-8") as f_vocab: vocab = [w.strip() for w in f_vocab.readlines()] word_to_id = {k: v for (k,v) in zip (vocab, range(len(vocab)))} #print(word_to_id)#{'<eos>': 0, 'the': 1, '<unk>': 2, 'N': 3, 'of': 4, 'to': 5, 'a': 6, 'in': 7, 'and': 8,...} def get_id(word):#如果出现了被删除的低频词,则替换为"<unk>" return word_to_id[word] if word in word_to_id else word_to_id["<unk>"] fin = codecs.open(RAW_DATA, "r", "utf-8") fout = codecs.open(OUTPUT_DATA,"w","utf-8") for line in fin: words = line.strip().split() + ["<eos>"]#读取单词并添加<eos>结束符 out_line=' '.join([str(get_id(w)) for w in words]) +'\n' #将每个单词替换为词汇表中的编号,并给词之间加上空格 fout.write(out_line) fin.close() fout.close()
处理好的ptb.train如下图所示
从上图可以看出,每个句子的长度是不一样的,生成的数字序列长度也是不一样的,因此在对文本数据进行batching时需要采取一些特殊操作,比如填充(padding),将同一batch内的句子长度补齐。
在喂数据时候,不可能将所有句子连接起来一起送入网络,序列过长可能导致训练中梯度爆炸的问题。对此问题的解决方法是,将长序列切割为固定长度的子序列。
循环神经网络在处理完一个子序列后,它最终的隐藏状态将复制到下一个序列中作为初值,这样在前向计算时,效果等同于一次性顺序地读取了整个文档。
为了利于计算时的并行能力,我们希望每一次可以对多个句子进行并行处理,同时又要尽量保证batch之间的上下文连续。解决方法是,先将整个文档且分为若干连续段落,再让batch中的每一个位置负责其中一段。例如,如果batch大小是4,则先将整个文档平均分成4个子序列,让batch中的每一个位置负责其中一个子序列,这样子序列内部的所有数据仍可以被顺序处理。