基于字符的NLP

背景

以往基于单词的NLP,一般是为要处理的词建立词向量空间,然后再对词向量进行NLP。这个处理会带来两个方面的问题是:

  • 对于出现频率比较低的词,建立的词向量有可能不准确
  • 无法处理不在单词表中的单词。比如网络上经常会出现一些新词,比如不明觉厉之类,英文的社交网络,还会出现比如loooooooooooooook之类的词。
  • 有些语言还会有合成词。比如德语就会有大量的合成词,如Lebensversicherungsgesellschaftsangestellter=Leben versicherung gesellschaft angestellter:寿险公司的雇员。而该合成词中的每个词都有可能会在词表里,但是合成词不身却不在词表。
  • 对于中文来说,要进行单词的NLP,还需要对其进行分词。而不同的分词器,分出的单词组合也不同。部分分词器对于人名之类的词也会分错。

于是,就有人提出为每个字符建立向量空间,再对其进行NLP。07年和13年的都有相应的论文进行了相应的尝试,但是不尽人意。15年之后的论文开始有比较好性能的字符级NLP。有些算法是直接将原单词级的神经网络直接替换为字符,有些比如只是在decoder端进行替换,还有些只是将单词切成segment,对每个segment建立向量空间。

基本结构

这里以英文NLP为例,介绍一个混合字符和单词、用于自动翻译的神经网络。该神经网络由斯坦福大学于2016年提出。

神经网络具体结构如图
在这里插入图片描述
其基本思想是基本结构仍然采用基于word级的encoder-decoder的LSTM。只不过进行了两处变化。

  • encoder:原输入端是直接在encoder的各个LSTM cell输入词向量。而该做法则是在输入词向量之前,先把词拆成一个个的字符,输入的是字符向量,通过神经网络,由字符向量算出词向量之后,再将词向量加到各个LSTM cell上。
  • decoder:在decoder端,原来的做法是产生一个个单词,如果该单词不在单词表中的话,用<unk>表示。而该做法是,如果某个LSTM cell输出了<unk>,则将该输出再接到另一个神经网络,逐个产生相应的字符,再将该神经网络产生的字符组成对应的单词。

基于word级的RNN的机器翻译技术在前文已经有介绍,这里不再重复叙述。这里重点介绍encoder和decoder处的变化。

Encoder

首先要对输入文本进行预处理,有以下步骤:

  1. 首先对输入的所有文本,计算其每句话的长度(单词个数),得到最大的长度 N N N。将所有没有到最大长度的句子加上<pad>。(确保word的Encoder端LSTM Cell数量是一定的)
  2. 设定每个单词的最大长度 m w o r d m_{word} mword。对于没有达到最大长度的单词,也全部加上<pad>。(确保处理字符的LSTM Cell数量是一定的)。
    然后再逐句输入到Encoder端,输入到Encoder端的tensor的shape为 ( N , b , m w o r d ) (N, b, m_{word}) (N,b,mword),其中 b b b为batch的大小(即句子的数量)。
    Encoder端的处理字符向量的模块如图所示。
    在这里插入图片描述
    对于单个单词,首先要确定每个字符在字典中的位置,即
    x p a d d e d = ( c 1 , c 2 , . . . , c m w o r d ) ∈ Z m w o r d \mathbf x_{padded} = (c_1,c_2,...,c_{m_{word}}) \in \mathbb Z^{m_{word}} xpadded=(c1,c2,...,cmword)Zmword
    其中 c i c_i ci为单词 x x x的第 i i i个字符在字典中的位置。这样根据 x p a d d e d \mathbf x_{padded} xpadded,就可以建立字符向量
    x e m b e d = C h a r E m b e d d i n g ( x p a d d e d ) ∈ R m w o r d × e c h a r \mathbf x_{embed} = CharEmbedding(\mathbf x_{padded}) \in \mathbb R^{m_{word} \times e_{char}} xembed=CharEmbedding(xpadded)Rmword×echar
    其中, e c h a r e_{char} echar为字符向量的长度。

在神经网络实现框架里,都有Embedding的函数,用于建立输入变量的向量空间,初始值随机。这样,模型训练时,向量可以跟着一起进行训练。如果直接用gensim之类的word2vec,而且不用Embedding,向量就不会训练。

将字符向量送入到卷积核为 k k k,进行数量 f f f个卷积,就可以得到
x c o n v = c o n v 1 D ( k , f ) ( x e m b e d T ) ∈ R f × ( m w o r d − k + 1 ) \mathbf x_{conv} = conv1D(k, f)(\mathbf x_{embed}^T) \in \mathbb R^{f \times (m_{word}-k+1)} xconv=conv1D(k,f)(xembedT)Rf×(mwordk+1)
f = e w o r d f=e_{word} f=eword,其中 e w o r d e_{word} eword词向量的长度。这样,进行maxpool和Relu就可以得到
x c o n v _ o u t = M a x P o o l ( R e L U ( x c o n v ) ) ∈ R f = R e w o r d \mathbf x_{conv\_out}=MaxPool(ReLU(\mathbf x_{conv} )) \in \mathbb R^{f}=\mathbb R^{e_{word}} xconv_out=MaxPool(ReLU(xconv))Rf=Reword
然后将 x c o n v _ o u t \mathbf x_{conv\_out} xconv_out经过一个highway network,其中
x p r o j = R e L U ( W p r o j x c o n v _ o u t + b p r o j ) ∈ R e w o r d x g a t e = σ ( W g a t e x c o n v _ o u t + b g a t e ) ∈ R e w o r d x h i g h w a y = x g a t e ⊙ x p r o j + ( 1 − x g a t e ) ⊙ x c o n v _ o u t ∈ ∈ R e w o r d \begin{aligned} \mathbf x_{proj} &= ReLU(\mathbf W_{proj} \mathbf x_{conv\_out} + \mathbf b_{proj} ) \in \mathbb R^{e_{word}}\\ \mathbf x_{gate} &= \sigma(\mathbf W_{gate}\mathbf x_{conv\_out} + \mathbf b_{gate} ) \in \mathbb R^{e_{word}}\\ \mathbf x_{highway} &= \mathbf x_{gate} \odot \mathbf x_{proj} + (1-\mathbf x_{gate}) \odot \mathbf x_{conv\_out} \in \in \mathbb R^{e_{word}} \end{aligned} xprojxgatexhighway=ReLU(Wprojxconv_out+bproj)Reword=σ(Wgatexconv_out+bgate)Reword=xgatexproj+(1xgate)xconv_outReword
其中 W p r o j , W g a t e ∈ R e w o r d × e w o r d \mathbf W_{proj}, \mathbf W_{gate} \in \mathbb R^{e_{word} \times e_{word}} Wproj,WgateReword×eword, b p r o j , b g a t e ∈ R e w o r d \mathbf b_{proj}, \mathbf b_{gate} \in \mathbb R^{e_{word}} bproj,bgateReword ⊙ \odot 表示逐元素相乘。经过Dropout就可以得到输出的词向量:
x w o r d _ e m b = D r o p o u t ( x h i g h w a y ) ∈ R e w o r d \mathbf x_{word\_emb} = Dropout(\mathbf x_{highway}) \in \mathbb R^{e_{word}} xword_emb=Dropout(xhighway)Reword
注意到在上述过程中,总共需要的参数有
V c h a r × e c h a r + ( e c h a r × k + 1 ) × e w o r d + 2 ( e w o r d × e w o r d + e w o r d ) + e w o r d V_{char} \times e_{char} + (e_{char} \times k + 1) \times e_{word} + 2(e_{word} \times e_{word} + e_{word}) + e_{word} Vchar×echar+(echar×k+1)×eword+2(eword×eword+eword)+eword
其中第一项表示字符词典参数数量,第二项表示卷积的参数数量,第三项表示highway network的参数数量,第四项是Dropout的参数数量。而如果直接采用词向量,所需的参数数量为
V w o r d × e w o r d V_{word} \times e_{word} Vword×eword
对于英语而言,字符数(包括标点符号) V c h a r V_{char} Vchar一般不超过100个,而牛津英语词典的单词数 V w o r d V_{word} Vword就达到170000+,而 e c h a r e_{char} echar一般也就取20多,而 e w o r d e_{word} eword经常要取到200多,因此后者的参数数量是远大于前者的。而对于汉字,一般 e w o r d e_{word} eword e c h a r e_{char} echar基本相当,以最新版的新华词典为例, V c h a r V_{char} Vchar约为8500, V w o r d V_{word} Vword约为52000,但即便如此,前者的参数数量仍然是小于后者的。

Encoder剩下的部分就和基于word的LSTM encoder完全一样了,不再详述。

Decoder

Train阶段

在训练阶段时,可以在每个Word LSTM Decoder Cell上都加上Char Decoder(这些Char Decoder均共享同一参数),将该LSTM Cell输出的 o \mathbf o o(见前文基于RNN的自动翻译的技术介绍-seq2seq+attention模型)作为该Char Decoder的初始化的状态,即 h 0 = c 0 = o \mathbf h_0 = \mathbf c_0 = \mathbf o h0=c0=o,而将LSTM Decoder Cell本应输出的(注意不是实际输出的)单词对应的字符Char Decoder的输入。比如如果单词是music,那么字符 ( x 1 , . . . , x n ) = ( < s > , m , u , s , i , c ) (x_1,...,x_n) = (<s>, m, u, s, i, c) (x1,...,xn)=(<s>,m,u,s,i,c)则作为char decoder的输入, ( x 2 , . . . , x n + 1 ) = ( m , u , s , i , c , < e > ) (x_2,...,x_{n+1})=(m,u,s,i,c,<e>) (x2,...,xn+1)=(m,u,s,i,c,<e>)作为char decoder的输出。
这样
h t , c t = c h a r D e c o d e r L S T M ( x t , h t − 1 , c t − 1 ) , h t , c t ∈ R h \mathbf h_t, \mathbf c_t = charDecoderLSTM(\mathbf x_t, \mathbf h_{t-1}, \mathbf c_{t-1}), \mathbf h_t, \mathbf c_t \in \mathbb R^h ht,ct=charDecoderLSTM(xt,ht1,ct1)ht,ctRh
其中, x t \mathbf x_t xt是字符 x t x_t xt对应的向量。注意, x t x_t xt对应的字符向量是可以不同于Encoder端的字符向量的
对于每个hidden state,可以经过全连接层得到
s t = W d e c h t + b d e c ∈ R V c h a r \mathbf s_t = \mathbf W_{dec} \mathbf h_t + \mathbf b_{dec} \in \mathbb R^{V_{char}} st=Wdecht+bdecRVchar
其中, W d e c ∈ R V c h a r × h \mathbf W_{dec} \in \mathbb R^{V_{char} \times h} WdecRVchar×h以及 b d e c ∈ R V c h a r \mathbf b_{dec} \in \mathbb R^{V_{char}} bdecRVchar。这样经过softmax后,计算loss为
l o s s = − ∑ t = 1 n C r o s s E n t r o p y ( s o f t m a x ( s t ) , x t + 1 ) loss=-\sum_{t=1}^n CrossEntropy(softmax(\mathbf s_t), \mathbf x_{t+1}) loss=t=1nCrossEntropy(softmax(st),xt+1)
然后再将loss叠加到word decoder的loss上,作为总的loss函数。

Test阶段

在Test阶段,可以只考虑Word Decoder输出为<unk>的LSTM Cell上,加上char decoder。Char decoder初始的 h 0 , c 0 \mathbf h_0, \mathbf c_0 h0,c0取值仍为该word decoder LSTM Cell上对应的 o \mathbf o o,并在第一个char decoder LSTM Cell上输入单词的开始标志<s>。其后续的输入,输出的计算和Train阶段相同。
得到 s o f t m a x ( s t ) softmax(\mathbf s_t) softmax(st)后,判断究竟是哪个字符,可以采用Beam Search的方法。(见前文基于RNN的自动翻译的技术介绍-seq2seq+attention模型),直到LSTM Cell上输出结尾标志<e>或者达到最大单词长度 m w o r d m_{word} mword

分析

从结果看,由字符向量得到的词向量,相似度高的词往往是拼写和构词上相似的词。而word2vec得到的词向量,相似度高的词往往是语义上接近的词。比如前者的结果为
在这里插入图片描述
后者的结果为
在这里插入图片描述
但是字符向量的好处处理时态变位能力比词向量强。比如某些单词的时态变位不在词典里,普通的词向量级的NLP就无法识别;而字符向量则往往能识别和解码出来。

另外,针对中文汉字级别的NLP,去年已经有文章Is Word Segmentation Necessary for Deep Learning of Chinese Representations?提出其性能要优于基于分词后的NLP,这个也是可以在进一步研究的地方。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值