转:使用RNN解决NLP中序列标注问题的通用优化思路
http://blog.csdn.net/malefactor/article/details/50725480
/* 版权声明:可以任意转载,转载时请标明文章原始出处和作者信息 .*/
author: 张俊林
序列标注问题应该说是自然语言处理中最常见的问题,而且很可能是最而没有之一。在深度学习没有广泛渗透到各个应用领域之前,传统的最常用的解决序列标注问题的方案是最大熵、CRF等模型,尤其是CRF,基本是最主流的方法。随着深度学习的不断探索和发展,很可能RNN模型会取代CRF的传统霸主地位,会成为解决序列标注问题的标配解决方案。
本文主要抽象出利用RNN解决序列标注问题的通用优化思路。这个RNN优化思路应该说是使用场景非常广泛,目前NLP中绝大多数问题都可以套用这套优化思路来统一解决问题。它有个独特的好处,就是说只要你构建好完整的这一套优化模型,绝大多数NLP的问题,包括分词、词性标注、命名实体识别、关键词抽取、语义角色标注等等,等于说问题已经被解决了,只需要你使用不同问题对应的训练数据跑一遍,就等于说上面问题的实际解决工具你就拥有了,而不用像传统模型一样还需要不断定义问题特征模板等,这就是End-to-End的好处。
再啰嗦两句,为什么说RNN一定会取代CRF?当然这不代表CRF完全会被抛弃,以后一定有人去研究怎么结合RNN和CRF,这个估计也没有疑问。但是RNN取代CRF获得主流地位是一定的,原因就是上面说的DL的End-to-End的优势。意思是,即使RNN只能取得和CRF方法类似的效果,但是由于End-to-End的优势,你不需要对研究领域有任何领域知识也能把它干好,因为有用的领域特征DL自己会去学,这个好处是巨大的(但是对于传统依靠NLP经验混饭吃的NLP老手们来说,这是个坏消息),况且目前看RNN在不少领域已经获得了最好的结果。结合这些特点,这就是为何说RNN会取代CRF成为新的主流模型的原因。
如果看将来的技术发展趋势,从目前情况看,如果再把Encoder-Decoder框架引进来,加上这篇文章讲的RNN解决序列标注问题,以及后面可能会写的用RNN解决句子分类问题的通用思路,我相信NLP中90%以上的问题都可以被这两个模型覆盖(当然Encoder-Decoder实际上和RNN不是一个层级的模型,这个我们暂且放一边,但且把它们并列来提)。所谓:RNN在手,全都我有,此言诚不我欺也。
我觉得还在坚韧不拔地坚持用传统方法搞NLP的同志应该好好读一读我上面这几段话,里面有深意,自己去体会。
|序列标注问题
如上文所述,序列标注问题是NLP中最常见的问题,因为绝大多数NLP问题都可以转化为序列标注问题,虽然很多NLP任务看上去大不相同,但是如果转化为序列标注问题后其实面临的都是同一个问题。所谓“序列标注”,就是说对于一个一维线性输入序列:
给线性序列中的每个元素打上标签集合中的某个标签
所以,其本质上是对线性序列中每个元素根据上下文内容进行分类的问题。一般情况下,对于NLP任务来说,线性序列就是输入的文本,往往可以把一个汉字看做线性序列的一个元素,而不同任务其标签集合代表的含义可能不太相同,但是相同的问题都是:如何根据汉字的上下文给汉字打上一个合适的标签。
我们以中文分词任务来说明序列标注的过程。图1给出了个例子,假设现在输入句子“跟着TFboys学左手右手一个慢动作”,我们的任务是正确地把这个句子进行分词。首先,把句子看做是一系列单字组成的线性输入序列,即:
“跟 着 Tfboys 学 左 手 右 手 一 个 慢 动 作”
序列标注的任务就是给每个汉字打上一个标签,对于分词任务来说,我们可以定义标签集合为:
其中B代表这个汉字是词汇的开始字符,M代表这个汉字是词汇的中间字符,E代表这个汉字是词汇的结束字符,而S代表单字词。
图1. 中文分词序列标注过程
有了这四个标签就可以对中文进行分词了。这时你看到了,中文分词转换为对汉字的序列标注问题,假设我们已经训练好了序列标注模型,那么分别给每个汉字打上标签集合中的某个标签,这就算是分词结束了,因为这种形式不方便人来查看,所以可以增加一个后处理步骤,把B开头,后面跟着M的汉字拼接在一起,直到碰见E标签为止,这样就等于分出了一个单词,而打上S标签的汉字就可以看做是一个单字词。于是我们的例子就通过序列标注,被分词成如下形式:
{跟着 Tfboys 学 左手 右手 一个 慢动作}
要学习NLP,首先要把面对问题时的思维意识转换一下,就是如上所示,把你直观感觉的问题转换为序列标注思维,这个思维意识转换过程很重要,如果你没有这种意识,那很明显属于业余选手,专业选手看NLP问题肯定首先是把它们看做一个序列标注问题的。
为了促进意识转换,下面再用命名实体识别(NER)问题举个序列标注解决问题的例子,命名实体识别任务是识别句子中出现的实体,通常识别人名、地名、机构名这三类实体。现在的问题是:假设输入中文句子
{花园北路的北医三院里,昏迷三年的我听杨幂的爱的供养时起身关了收音机。}
我们要识别出里面包含的人名、地名和机构名。如果以序列标注的角度看这个问题,应该怎么解决呢?图2给出了整个流程的说明。
首先,我们把输入序列看成一个个汉字组成的线性序列,这是基础。
然后,我们定义标签集合如下(这个标签用什么代表不重要,重要的是它们代表的含义):
其中,BA代表这个汉字是地址首字,MA代表这个汉字是地址中间字,EA代表这个汉字是地址的尾字;BO代表这个汉字是机构名的首字,MO代表这个汉字是机构名称的中间字,EO代表这个汉字是机构名的尾字;BP代表这个汉字是人名首字,MP代表这个汉字是人名中间字,EP代表这个汉字是人名尾字,而O代表这个汉字不属于命名实体。
图2. 命名实体(NER)序列标注过程
有了输入汉字序列,也有了标签集合,那么剩下的问题是训练出一个序列标注ML系统,能够对每一个汉字进行分类,假设我们已经学好了这个系统,那么就给输入句子中每个汉字打上标签集合中的标签,于是命名实体就被识别出来了,为了便于人查看,增加一个后处理步骤,把人名、地名、机构名都明确标识出来即可。
很多NLP中的其它任务同样可以转换为序列标注问题,比如词性标注、CHUNK识别、句法分析、语义角色识别,甚至包括关键词抽取等很多应用问题也是如此。
传统解决序列标注问题的方法包括HMM/MaxEnt/CRF等,很明显RNN很快会取代CRF的主流地位,成为解决序列标注问题的标准解决方案,那么如果使用RNN来解决各种NLP基础及应用问题,有什么优化轨迹可循吗?有的,下面我们就归纳一下使用RNN解决序列标注问题的一般优化思路。
|使用RNN解决序列标注问题的一般优化思路
首先,我们可以说,对于序列标注问题,都可以用RNN来替代传统解决方案,这个目前看没什么问题,也是大势所趋。
然后,如果归纳的话,一般的优化流程是:首先用RNN来解决序列标注问题,然后可以上LSTM或者GRU来替代RNN中的隐层单元,因为LSTM或GRU对于解决长距离依赖的场景明显要优于RNN本身,接着可以上BLSTM,即双向LSTM,因为双向RNN或者双向LSTM相对RNN来说,能够看到下文特征,所以明显引入了更多的特征,如果你觉得效果还是不够好,那么可以增加BLSTM的深度,不断叠加网络形成深度BLSTM网络,当然,这里要注意,随着优化的进行,模型越来越复杂,如果训练数据规模不够的话,很可能会出现过拟合现象,所以使用LSTM的时候,记得用上DropOut以及L1/L2正则来避免过拟合,但是如果模型相对训练数据规模确实复杂,你加上这些可能也没用。至于GRU和LSTM两者相比,到底哪个更好目前并无定论,倾向于认为两者性能差不多,但是GRU是LSTM的简化模型,所以同样结构的神经网络其参数要少,在训练数据不太大情况下,优先考虑使用GRU。
当然,根据NLP的不同任务特点,是先上BiRNN好还是先上LSTM好这个可能不同任务情况不一样,比如对于分词、POS、NER这种依赖不会太远的任务,RNN应该就够了,但是BiRNN肯定是要上的,因为下文特征有重要参考意义,但是对于语义级别的任务比如指代消解、语义角色标注等,估计肯定是要上LSTM的。所以要根据具体情况具体分析,不过通用的优化手段也不外乎以上几种。
下面给出深层双向LSTM来做NER的神经网络结构示意图:
图3. 深层双向LSTM做NER
图比较直观,就不解释了,其它的NLP序列标注任务其实都可以套用这个模型来解决。