前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >[L1]实战语言模型~语料词典的生成

[L1]实战语言模型~语料词典的生成

作者头像
触摸壹缕阳光
发布2020-06-01 17:27:47
1.2K0
发布2020-06-01 17:27:47
举报

心宽一寸,受益三分。心宽路就宽,心窄路就窄。不争自然能得到人们的尊崇,能忍则忍,一忍百安。

全文字数:2666字

阅读时间:8分钟

前言

由于在公众号上文本字数太长可能会影响阅读体验,因此过于长的文章,我会使用"[L1]"来进行分段。这个系列将主要借鉴《Tensorflow实战Google学习框架》这本书,主要介绍实现语言模型的一些前期准备,后期会出更详细的文章。

a

PTB 数据集

PTB(Penn Treebank Dataset)文本数据集是目前语言模型学习中使用最为广泛的数据集。在使用数据集之前,我们肯定需要对PTB数据集做充分的了解,才能够为后续的处理提供方便。

PTB数据集的下载地址: https://link.zhihu.com/?target=http%3A//www.fit.vutbr.cz/~imikolov/rnnlm/simple-examples.tgz

▲下载解压后的文件目录

我们做RNN Language Mode的时候只需要使用data路径下的三个数据集即可:

ptb.test.txt #测试集数据文件 ptb.train.txt #训练集数据文件 ptb.valid.txt #验证集数据文件

当然这三个数据文件中的数据已经过预处理(未登录词都用<unk>进行替换,没有数字文本),相邻的单词之间用空格隔开。数据集中共包含了9998种不同的单词词汇。在构建词汇表的时候需要添加一些特殊的词汇:

  • <pad>填充词汇
  • <go>句子开始
  • <eos>句子结束
  • <unk>未知词

所以也就是说数据集中一共有10002种不同的词汇。

b

数据的预处理

为了方便理解讲解说明时采用了代码段的方式实现,并没有使用函数进行抽象,后面会给出详细的函数代码。

2.1 文本文件 -> 词汇表

为了将文本转换为模型可以读入的单词序列,需要将这些不同的词汇分别映射到0~10001(因为我们这里有10002种不同的单词)之间的整数编号。也就是说首先要按照词频的顺序为每个词汇分配一个编号,然后将这些词汇表保存到一个独立的vocab文件中。

代码语言:javascript
复制
import codecs
import collections
from operator import itemgetter
import re

RAW_DATA = r'./data/ptb.train.txt'
VOCAB_OUTPUT = r'./model/model_ptb/ptb.train.vocab'
_DIGIT_RE = re.compile(r"\d")
normalize_digits = True


counter = collections.Counter()
with codecs.open(RAW_DATA,'r','utf-8') as f:
    for line in f:
        for word in line.strip().split():
            #判断是否有数字,如果有的话就将其替换成"0"
            #当时ptb中没有数字,所以不需要对数字进行处理
            # word = _DIGIT_RE.sub(r"0", word) if normalize_digits else word
            counter[word] += 1

print(counter.items())

#按照词频顺序对单词进行排序
sorted_word_to_cnt = sorted(counter.items(),key = itemgetter(1),reverse = True)
sorted_words = [x[0] for x in sorted_word_to_cnt]


#然后我们需要加入那些特殊特殊的词汇,这里预先将其加入词汇表中
sorted_words = ["<pad>","<go>","<eos>"] + sorted_words

# 设置max_vocabulary_size词汇表的最大长度,如果没有超过一定频率的就认为是未登录词
# if len(sorted_words) > max_vocabulary_size:
#     sorted_words = sorted_words[:max_vocabulary_size]

with codecs.open(VOCAB_OUTPUT,'w','utf-8') as file_output:
    for word in sorted_words:
        file_output.write(word+"\n")

执行代码会发现在" r'./model/model_ptb/ptb.train.vocab'"这个路径下生成一个ptb.train.vocab的文件。当然无论是训练集、验证集还是测试集我们的字典都是一样的,这个其实很好理解,只有词与数字统一起来,在训练集上训练,验证集验证以及最后的测试才能够使其表示的单词一致。

▲目录结构

▲ptb.train.vocab文件内容

下面说一下代码中的几个关键点:

counter = collections.Counter()

Counter类的目的是用来跟踪值出现的次数。它是一个无序的容器类型(所以需要后期进行排序的处理),以字典的键值对形式存储,其中元素作为key,其计数作为value。计数值可以是任意的Interger(包括0和负数)。为hashable对象计数,是字典的子类。

代码语言:javascript
复制
from collections import Counter
cnt = Counter()
for word in ['red', 'blue', 'red', 'green', 'blue', 'blue']:
    cnt[word] += 1
print(cnt)

'''
result:
    Counter({'blue': 3, 'red': 2, 'green': 1})
'''

sorted(iterable, cmp=None, key=None, reverse=False) --> new sorted list iterable:是可迭代类型; cmp:用于比较的函数,比较什么由key决定; key:用列表元素的某个属性或函数进行作为关键字,有默认值,迭代集合中的一项; reverse:排序规则. reverse = True 降序 或者 reverse = False 升序,有默认值。 返回值:是一个经过排序的可迭代类型,与iterable一样。

counter.items()返回dict_items,将键值对变成一个个的元组。指定sorted的key为itemgetter(1),便以每个键值对元组下标为 1 的元素进行排序。这样就完成按照词频的大小进行排序构建词汇表的工作。

2.2 文本文件 -> 单词的编号

上面的2.1小节确定了词汇表以后,再将训练文本、测试文本等都根据词汇文件转换为单词编号。每个单词的编号就是他在词汇文件中的行号。这里需要注意的就是我们仅仅使用train样本构建词汇表,然后根据这个词汇表去替换ptb.test.txt,ptb.train.txt,ptb.valid.txt中的单词,也就是将单词换成对应词汇表中的词频。

下面是是对train样本中的单词进行替换:

代码语言:javascript
复制
import codecs

RAW_DATA = r"./data/ptb.train.txt"#原始的训练数据集文件
VOCAB = r"./model/model_ptb/ptb.train.vocab"#词汇表文件
OUTPUT_DATA = r"./model/model_ptb_id/ptb.train.id"#将单词替换为单词编号后的输出文件

#读取词汇表,并建立词汇到单词编号的映射
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)))}

#如果出现了被删除的低频词,则替换为'<unk>'
def get_id(word):
    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:
    #读取单词并添加<go>以及<eos>
    words = ['<go>'] + line.strip().split() + ['<eos>']
    #将每个单词替换为词汇表中的编号
    output_line = ' '.join([str(get_id(w)) for w in words]) + '\n'
    fout.write(output_line)

fin.close()
fout.close()

▲处理后的结果

对valid以及test样本同理使train中的方法即可:

▲数据处理以及处理后的结构

大致流程:

  • 构建词汇表
    • 需要在训练样本中统计语料中出现的单词,按照词频进行排序,一行一个单词;
    • 为每个单词分配一个ID,这个ID就是单词的(行数-1),因为ID从0开始;
    • 将词汇表存放到一个vocab文件中;
  • 替换文本单词
    • 将文本转化为用单词编号的形式来表示;
本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-05-24,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 AI机器学习与深度学习算法 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档