自然语言处理和图像处理不同,作为人类抽象出来的高级表达形式,它和图像、声音不同,图像和声音十分直觉,比如图像的像素的颜色表达可以直接量化成数字输入到神经网络中,当然如果是经过压缩的格式jpeg等必须还要经过一个解码的过程才能变成像素的高阶矩阵的形式,而自然语言则不同,自然语言和数字之间没有那么直接的相关关系,也就不是那么容易作为特征输入到神经网络中去了,所以,用神经网络处理自然语言,不可避免的在数据预处理方面更加繁琐,也更加细致!自然语言处理的另外一个不同之处在于语言之间的相关关系,举一个最简单的例子,在做智能助理机器人的时候,一句“我将在上午十点到达北京”和“我将在上午十点离开北京” 如果你只考虑每个独立的词汇的话,那么“北京”到底是作为始发地还是目的地是不得而知的,也就是说你必须得联系上下文才能够更好的理解整个句子的意思!这也是自然语言的特别之处!当然针对语言的这种特性,也有相应的用于处理的网络——RNN(recurrent neural network)循环神经网络!

作为分类到Tensorflow编程实战里的一篇博客,当然以解释代码为主,具体的理论部分这里不过多解释,开门见山,本次处理的数据集是PTB数据集,它是目前语言模型学习中使用的最为广泛的数据集,PTB数据集的下载地址是: http://www.fit.vutbr.cz/~imikolov/rnnlm/simple-examples.tgz

将数据集解压之后将会得到好几个文件夹,重点看/data文件夹下的三个文件,ptb.test.txt,   ptb.train.txt,   ptb.valid.txt 这三个数据文件已经经过了预处理,相邻的单词之间用空格隔开,以ptb.train.txt为例,看一下它里面的具体内容:

no it was n't black monday  but while the new york stock exchange did n't fall apart friday as the dow jones industrial average plunged N points most of it in the final hour it barely managed to stay this side of chaos 

some circuit breakers installed after the october N crash failed their first test traders say unable to cool the selling panic in both stocks and futures

the N stock specialist firms on the big board floor 

数据集中包含了9998个词汇,加上稀有词语的特殊符号 <unk>和语句的结束标记,一共是10000个! 为了能够将数据输入到神经网络,我们首先需要做的就是这10000个词汇按照其出现的频率进行编号,形成词汇表,然后按照词汇表的对应关系,将train/test/valid数据集分别转换成编号的形式!

按照单词出现的频率进行编号的代码如下:

 import codecs
import collections
from operator import itemgetter RAW_DATA = "C:\\Users\\Yang\\Desktop\\nlp\\ptb.train.txt" #数据的输入路径/
VOCAB_OUTPUT ="ptb.vocab" #词汇表的输出路径 counter = collections.Counter() #counter 顾名思义是一个计数器 with codecs.open(RAW_DATA,"r","utf-8") as f: 以read的方式,utf-8编码的形式打开上述路径
for line in f: #读行
for word in line.strip().split(): #以空格作为划分,将文件里面的每一个词汇都切开! strip()默认用于去掉收尾的空格和换行符
counter[word] += #统计单词出现的次数 sorted_word_to_cnt = sorted(counter.items(),key=itemgetter(),reverse=True) 按照itemgetter(1)属性进行排序,应该就是按照单词出现的次数排序,例如:and:981
sorted_words = [x[] for x in sorted_word_to_cnt] #之所以取x[]是因为格式是 the: 这种形式,x[]就是为了将单词取出来 排好序的word sorted_words = ["<eos>"] + sorted_words #将句子的结束符添加到排好序的list中
#因为PTB数据中已经将低频词汇替换成了<"unk">所以下面这步没必要 <"eos">是句子结束符 <"sos">是句子开始符 <"unk">是句子的低频词汇
#sorted_words = ["<unk>","<sos>","<eos>"] + sorted_words
21 #if len(sorted_words) >10000:
22 #sorted_words = sorted_words[:10000] 标红的这三句没必要出现!

with codecs.open(VOCAB_OUTPUT,"w",'utf-8') as file_output : for word in sorted_words:
file_output.write(word + "\n") #将排序好的词汇再写回输出的文件目录里面,那么就算完成了词汇对应表的构建

写完了词汇表的构建代码之后,我们还需要一个将ptb.train/test/valid.txt文件转换成对应的编号的过程! 每一个词汇对应的编号就是其在词汇表里面对应的行号! 注意到之前每一个word的输出后面都跟着"\n"

下面就来实现将单词转换成对应的编号的部分的代码:

 import codecs
import sys RAW_DATA = 'C:\\Users\\Yang\\Desktop\\nlp\\data\\ptb.valid.txt' #这里是待转换的文件的目录/相应的改成ptb.test.txt/ptb.train.txt可以用于其他的转换
VOCAB = 'ptb.vocab' #词汇表的目录
OUTPUT_DATA = 'ptb.valid' 用于输出的目录 with codecs.open(VOCAB,'r','utf-8') as f_vocab: #首先就是将词汇表以read和utf-8编码的方式打开
vocab = [w.strip() for w in f_vocab.readlines()] #我怎么感觉这里只是读到了一行然后进行收尾空格换行符去掉的处理???
#哦,我明白了 因为VOCAB中词汇的存储格式就是一个单词占一行,所以出来的就是一个个单词而不需要.split()
word_to_id = {k:v for (k,v) in zip(vocab,range(len(vocab)))} #转换成了单词序号的字典形式 这里是完成了词汇和其对应编号的对应! #将词汇转换成了对应的行号序号
def get_id(word):
return word_to_id[word] if word in word_to_id else word_to_id["<unk>"] #如果是在词汇表里面的就将它转换成对应的编号,否则的话就转换成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.txt变成了什么样子:

9994 9996 9974 9999 9972 9978 9981 9993 9977 9973 9985 9998 9992 9971 9997 9990 9995 9970 9989 9987 9988 9975 9980 9986 0

没错,全部变成了词汇表对应的行号编号的形式!

进行完上述两步处理之后,我们已经完成了数据预处理部分的一半了,接下来我们需要考虑的问题就是,处理后的编码数据不可能直接输入到网络里面去,网络接受的一般都是许多batch,但是在将数据打包成batch

的时候,又有一个十分严峻的问题需要我们考虑,那就是到底以多长的长度来打包数据呢? 每条句子的长度是不一样的,该如何打包呢? 有两种比较常见的做法,一种是根据batch_size的大小,选取里面最长的句子为

参考,剩下的padding成统一的长度!长度统一之后就可以用于batch了!

而PTB数据是一整段一整段文本,如果一句一句的进行切分的话,会破坏掉数据之间的上下文的关联,而语言模型为了利用上下文信息,必须将前面的信息传递到后面的句子中去,所以PTB通常采用的是另外一种Batch的方法!

该方法将长序列切割成固定长度的子序列,然后循环神经网络处理完这个子序列之后将最后一个隐藏层的结果复制到下一个序列中作为初始值,这样在前向计算的过程中效果就等同于一次性的读取完了全部的文档!

但是如果这样做的话会面临另外一个问题,整个数据流都是串行流动的,这对于可以并行计算的tensorflow来说简直太浪费了,所以,兼顾二者的做法是,根据batch_size的大小将整个文档划分成batch_size部分!然后让batch_size的每一个位置负责一部分数据,如果处理不完,继续横向移动到下一个batch中去,也就是说,对于batch来讲数据之间横向才是连贯的,纵向其实是互不相干的!这样既能够保证数据之间的上下文关系,也能够保证tensorflow可以并行处理数据!

画一个示意图的话,大概是下面这样:

用tensorflow实现自然语言处理——基于循环神经网络的神经语言模型的更多相关文章

  1. 深度学习项目——基于循环神经网络(RNN)的智能聊天机器人系统

    基于循环神经网络(RNN)的智能聊天机器人系统 本设计研究智能聊天机器人技术,基于循环神经网络构建了一套智能聊天机器人系统,系统将由以下几个部分构成:制作问答聊天数据集.RNN神经网络搭建.seq2s ...

  2. TensorFlow框架(6)之RNN循环神经网络详解

    1. RNN循环神经网络 1.1 结构 循环神经网络(recurrent neural network,RNN)源自于1982年由Saratha Sathasivam 提出的霍普菲尔德网络.RNN的主 ...

  3. 循环神经网络(RNN, Recurrent Neural Networks)介绍(转载)

    循环神经网络(RNN, Recurrent Neural Networks)介绍    这篇文章很多内容是参考:http://www.wildml.com/2015/09/recurrent-neur ...

  4. 循环神经网络(Recurrent Neural Networks, RNN)介绍

    目录 1 什么是RNNs 2 RNNs能干什么 2.1 语言模型与文本生成Language Modeling and Generating Text 2.2 机器翻译Machine Translati ...

  5. 循环神经网络(RNN, Recurrent Neural Networks)介绍

    原文地址: http://blog.csdn.net/heyongluoyao8/article/details/48636251# 循环神经网络(RNN, Recurrent Neural Netw ...

  6. L6循环神经网络

    循环神经网络 本节介绍循环神经网络,下图展示了如何基于循环神经网络实现语言模型.我们的目的是基于当前的输入与过去的输入序列,预测序列的下一个字符.循环神经网络引入一个隐藏变量HHH,用HtH_{t}H ...

  7. 基于TensorFlow的循环神经网络(RNN)

    RNN适用场景 循环神经网络(Recurrent Neural Network)适合处理和预测时序数据 RNN的特点 RNN的隐藏层之间的节点是有连接的,他的输入是输入层的输出向量.extend(上一 ...

  8. tensorflow实现循环神经网络

    包括卷积神经网络(CNN)在内的各种前馈神经网络模型, 其一次前馈过程的输出只与当前输入有关与历史输入无关. 递归神经网络(Recurrent Neural Network, RNN)充分挖掘了序列数 ...

  9. 学习笔记TF057:TensorFlow MNIST,卷积神经网络、循环神经网络、无监督学习

    MNIST 卷积神经网络.https://github.com/nlintz/TensorFlow-Tutorials/blob/master/05_convolutional_net.py .Ten ...

随机推荐

  1. sql得到表中的列信息

    取列全部用的 sys. 中的表 CTE:WITH name AS() 用法:   sql树形查询 ①主键信息 SELECT ic.column_id, ic.index_column_id, ic.o ...

  2. windows 安装pear & PHP_CodeSniffer

    1. download https://pear.php.net/go-pear.phar 2. install pear(http://pear.php.net/manual/en/installa ...

  3. H5新增API和操作DOM

    博客原文:https://dobinspark.com.cn/ H5-dom扩展 获取元素 document.getElementsByClassName ('class'); //通过类名获取元素, ...

  4. SpringBoot学习18:springboot使用Scheduled 定时任务器

    Scheduled 定时任务器:是 Spring3.0 以后自带的一个定时任务器. 1.在pom.xml文件中添加Scheduled依赖 <!-- 添加spring定时任务 Scheduled ...

  5. Sass 基础(六)

    join() 函数 join()函数是将两个列表连接合并成一个列表. >>join(10px 20px, 30px 40px) (10px 20px 20px 40px) >> ...

  6. oracle的局部本地分区索引

    环境:oracle 12.2.0.1 注:未确定10g,11g是否有这些特性.现在基本不用10g,主要用12c,11g. 毫无疑问,这种 特性对于dba或者实施人员而言显得很重要,尤其当你的数据库主要 ...

  7. linux 查看系统当前时间,修改时间

    linux 查看系统当前时间,修改时间1. 查看时间和日期命令 : "date"2.设置时间和日期例如:将系统日期设定成2018年6月8日的命令命令 : "date -s ...

  8. Tornado异步之-协程与回调

    回调处理异步请求 回调 callback 处理异步官方例子 # 导入所需库 from tornado.httpclient import AsyncHTTPClient def asynchronou ...

  9. sencha inspector(调试工具)

    Sencha Inspector 一:安装sencha inspector 使用Sencha Inspector下载Ext JS试用版(可在此处获得). 下载后,双击下载的文件以启动安装程序,然后按照 ...

  10. [转]Nginx伪静态配置和常用Rewrite伪静态规则集锦

    Nginx伪静态配置和常用Rewrite伪静态规则集锦 作者: 字体:[增加 减小] 类型:转载 时间:2014-06-10 我要评论 伪静态是一种可以把文件后缀改成任何可能的一种方法,如果我想把ph ...