浅谈分词算法(5)基于字的分词要领(bi-LSTM)


玖富娱乐是一家为代理招商,直属主管信息发布为主的资讯网站,同时也兼顾玖富娱乐代理注册登录地址。

目次

  • 媒介
  • 目次
  • 轮回神经收集
  • 基于LSTM的分词
    • Embedding
    • 数据预处理
    • 模子
    • 怎样增加用户辞书

媒介

很早便计划的浅谈分词算法,统共分为了五个局部,想聊聊本身在各种场景中运用到的分词要领做个总结,各种事变一向拖到如今,本日抽闲赶忙将末了一篇补上。前面几篇博文中我们已论述了岂论分词、词性标注亦或NER,都可以或许笼统成一种序列标注模子,seq2seq,就是将一个序列映照到另一个序列,这在NLP范畴黑白经常见的,因为NLP中语序、上下文黑白常主要的,那末推断以后字或词是甚么,我们必需转头看看之前说了甚么,以至以后说了甚么,这也相符人类在浏览明白时的习气。因为笼统成了Seq2Seq的模子,那末我们便可以或许套用相干模子来求解,好比HMM、CRF和深度中的RNN,本文我们就来聊聊LSTM在分词中的运用,和运用中的一些trick,好比怎样增加字典等。

目次

浅谈分词算法(1)分词中的基本题目
浅谈分词算法(2)基于辞书的分词要领
[浅谈分词算法(3)基于字的分词要领(HMM)](https://www.cnblogs.com/xlturing/p/8467033.html
浅谈分词算法(4)基于字的分词要领(CRF)
浅谈分词算法(5)基于字的分词要领(LSTM)

轮回神经收集

在之前的博文马里奥AI完成体式格局探究 ——神经收集 增强进修,我论述了关于神经收集的进程,和近来这波人工智能海潮的肇端CNN,即卷积神经收集的观点。卷积神经收集给图象范畴带来了质的飞越,也将之前由李飞飞传授竖立的ImageNet竞赛提拔到了新的高度,图象识别范畴,计算机第一次逾越了人类,从而引爆了近来两三年来对人工智能、深度进修的延续存眷。
当CNN在图象范畴火爆以后,天然作为人工智能三大范畴之一的NLP,也很快拿来运用,即有名的Text-CNN,人人感兴趣的可以或许去看看这篇论文Convolutional Neural Networks for Sentence Classification,对NLP范畴也具有主要的里程碑意义,如今引用量也达到了3436。
然则CNN有个比较严峻的题目是,其没有序列的观点在里面,若是我们将一个句子做好embedding丢到CNN中做分类模子,那末CNN更多的是将这个句子看作一个词袋(bag-of-words bag),如许在NLP范畴主要的语序信息就丧失了,那末我们便引出了RNN,即轮回神经收集或说递归神经收集(这里值得注重的是,若是是对语句做分类模子,那末用CNN举行分歧kernel的卷积,然后拼接是可以或许提取到一些语序信息,这个中也涉及到各种厘革的CNN,人人可以或许多查查材料)。
关于轮回神经收集,实在与CRF、HMM有许多共通的地方,关于每一个输入(x_t),我们经由历程收集变更都邑获得一个状况(h_t),关于一个序列来讲,每一个token(可以或许是字也可以或许是词,在分词时是字)都邑进入收集迭代,注重收集中的参数是同享的。这里弗成免俗的放上典范图象吧:

这里将轮回神经收集睁开,就是背面那样。人人注重下图中的(A),在RNN中就是一个比较简朴的前馈神经收集,在RNN中会有一个严峻的题目,就是当序列很长的时刻,BP算法在反应时,梯度会趋于零,即所谓的梯度消逝(vanishing gradient)题目,这便引出了LSTM(Long Short Term Memory)。
LSTM本质上照样轮回神经收集,只不外呢它把上面我们提到的(A)换了换,加了三个门,实在就是关于向量的几个变更表达式,来躲避这类梯度消逝题目,使得LSTM的逻辑单位可以或许更好的生存序列信息,一样弗成免俗上下面这张典范的图片:

图中对应了四个表达式以下:
忘记门:
[f_t=sigma (W_fcdot [h_{t-1},x_t] b_f]
输入门:
[i_t=sigma (W_icdot [h_{t-1},x_t] b_i]
[widetilde{C}=tanh(W_Ccdot [h_{t-1},x_t] b_C]
状况更新:
[C_t=f_t*C_{t-1} i_t*widetilde{C}_t]
输出门:
[O_t=sigma (W_o[h_{t-1},x_t] b_o)]
[h_t=O_t*tanh(C_t)]
一样平常呢LSTM都是一个偏向将序列轮回输入到收集当中,但是有时刻我们须要两端存眷序列的信息,如许便引出了Bi-LSTM,即双向LSTM,很简朴,就是关于一个序列,我们有两个LSTM收集,一个正向输入序列,一个反向输入序列,然后将输出的state拼接在一起,供后续运用。
到这里我们简朴的说了下关于轮回神经收集的事变,下面我们看下在分词中运用LSTM

基于LSTM的分词

前文和之前的系列博文,我们已熟习分词转换为Seq2Seq的思绪,那末关于LSTM,我们须要做的是将一串句子映照成为Embedding,然后逐一输出到收集中,获得状况输出,举行序列标注。我们接纳TensorFlow来开辟。

Embedding

关于Embedding,我们可以或许直接下载网上公然的Wiki数据集练习好的Embedding,一样平常维度是100,也可以或许本身依据场景,应用Word2Vec、Fasttext等练习本身的Embedding。

数据预处理

实在深度的很多模子已很成熟,最贫苦的是数据的预处理,在数据预处理阶段中心要做的是将序列映照到Embedding文件对应的id序列,而且依照Batch来切分,一样平常依据数据集的巨细会设置64、128、256等分歧的batch巨细,在向收集输入数据,举行epoch迭代时,注重举行须要的shuffle操纵,关于结果进步很有效,shuffle相似以下:

-玖富娱乐是一家为代理招商,直属主管信息发布为主的资讯网站,同时也兼顾玖富娱乐代理注册登录地址。-
def shuffle(char_data, tag_data, dict_data, len_data):
    char_data = np.asarray(char_data)
    tag_data = np.asarray(tag_data)
    dict_data = np.asarray(dict_data)
    len_data = np.asarray(len_data)
    idx = np.arange(len(len_data))
    np.random.shuffle(idx)

    return (char_data[idx], tag_data[idx], dict_data[idx], len_data[idx])

数据预处理我这里未几讲了,读者可以或许直接看github上开源的代码,有题目随时留言,我有空会来解答~

模子

我们的中心模子构造也很简朴,将输入的id序列,经由历程Tensorflow 的查表操纵,映照成对应的Embedding,然后输入到收集中,获得终究结果,举行Decode操纵,获得每一个字符的符号(BEMS),中心代码以下:

    def __init__(self, config, init_embedding = None):
        self.batch_size = batch_size = config.batch_size
        self.embedding_size = config.embedding_size # column
        self.hidden_size = config.hidden_size
        self.vocab_size = config.vocab_size # row

        # Define input and target tensors
        self._input_data = tf.placeholder(tf.int32, [batch_size, None], name="input_data")
        self._targets = tf.placeholder(tf.int32, [batch_size, None], name="targets_data")
        self._dicts = tf.placeholder(tf.float32, [batch_size, None], name="dict_data")
        self._seq_len = tf.placeholder(tf.int32, [batch_size], name="seq_len_data")

        with tf.device("/cpu:0"):
            if init_embedding is None:
                self.embedding = tf.get_variable("embedding", [self.vocab_size, self.embedding_size], dtype=data_type())
            else:
                self.embedding = tf.Variable(init_embedding, name="embedding", dtype=data_type())
        inputs = tf.nn.embedding_lookup(self.embedding, self._input_data)
        inputs = tf.nn.dropout(inputs, config.keep_prob)
        inputs = tf.reshape(inputs, [batch_size, -1, 9 * self.embedding_size])
        d = tf.reshape(self._dicts, [batch_size, -1, 16])
        self._loss, self._logits, self._trans = _bilstm_model(inputs, self._targets, d, self._seq_len, config)
        # CRF decode
        self._viterbi_sequence, _ = crf_model.crf_decode(self._logits, self._trans, self._seq_len)
        with tf.variable_scope("train_ops") as scope:
            # Gradients and SGD update operation for training the model.
            self._lr = tf.Variable(0.0, trainable=False)
            tvars = tf.trainable_variables()  # all variables need to train
            # use clip to avoid gradient explosion or gradients vanishing
            grads, _ = tf.clip_by_global_norm(tf.gradients(self._loss, tvars), config.max_grad_norm)
            self.optimizer = tf.train.AdamOptimizer(self._lr)
            self._train_op = self.optimizer.apply_gradients(
                zip(grads, tvars),
                global_step=tf.contrib.framework.get_or_create_global_step())

            self._new_lr = tf.placeholder(data_type(), shape=[], name="new_learning_rate")
            self._lr_update = tf.assign(self._lr, self._new_lr)
        self.saver = tf.train.Saver(tf.global_variables())

代码逻辑很清楚,将各种输入获得后,embedding查表完毕后,放入Bi-LSTM模子,获得的结果举行Decode,这里注重我们用了一个CRF举行尾部Decode,经由实验结果更好,实在直接上一层Softmax也ok。关于bilstm以下:

def _bilstm_model(inputs, targets, dicts, seq_len, config):
    '''
    @Use BasicLSTMCell, MultiRNNCell method to build LSTM model
    @return logits, cost and others
    '''
    batch_size = config.batch_size
    hidden_size = config.hidden_size
    vocab_size = config.vocab_size
    target_num = config.target_num  # target output number
    seq_len = tf.cast(seq_len, tf.int32)

    fw_cell = lstm_cell(hidden_size)
    bw_cell = lstm_cell(hidden_size)

    with tf.variable_scope("seg_bilstm"): # like namespace
        # we use only one layer
        (forward_output, backward_output), _ = tf.nn.bidirectional_dynamic_rnn(
            fw_cell,
            bw_cell,
            inputs,
            dtype=tf.float32,
            sequence_length=seq_len,
            scope='layer_1'
        )
        # [batch_size, max_time, cell_fw.output_size]/[batch_size, max_time, cell_bw.output_size]
        output = tf.concat(axis=2, values=[forward_output, backward_output])  # fw/bw dimension is 3
        if config.stack: # False
            (forward_output, backward_output), _ = tf.nn.bidirectional_dynamic_rnn(
                fw_cell,
                bw_cell,
                output,
                dtype=tf.float32,
                sequence_length=seq_len,
                scope='layer_2'
            )
            output = tf.concat(axis=2, values=[forward_output, backward_output])

        output = tf.concat(values=[output, dicts], axis=2)  # add dicts to the end
        # outputs is a length T list of output vectors, which is [batch_size*maxlen, 2 * hidden_size]
        output = tf.reshape(output, [-1, 2 * hidden_size   16])
        softmax_w = tf.get_variable("softmax_w", [hidden_size * 2   16, target_num], dtype=data_type())
        softmax_b = tf.get_variable("softmax_b", [target_num], dtype=data_type())

        logits = tf.matmul(output, softmax_w)   softmax_b
        logits = tf.reshape(logits, [batch_size, -1, target_num])

    with tf.variable_scope("loss") as scope:
        # CRF log likelihood
        log_likelihood, transition_params = tf.contrib.crf.crf_log_likelihood(
            logits, targets, seq_len)
        loss = tf.reduce_mean(-log_likelihood)
    return loss, logits, transition_params

注重这里做了两次LSTM,并将结果拼接在一起,而我们的丧失函数是关于crf_log_likelihood。

怎样增加用户辞书

我们可以或许看到在全部模子练习好后,inference的历程是直接依据收集权重举行的,那末怎样增加用户辞书呢,这里我们接纳的体式格局是将用户辞书作为分外的特性拼接在Bi-LSTM结果的背面,就是在上面代码的output = tf.concat(values=[output, dicts], axis=2) # add dicts to the end这里,这个辞书会分红四个局部,head、mid、single、tail,词头、词中、词尾和单字词,如许关于用户辞书是不是出现用one-hot情势表达,不外实际运用历程当中也照样存在切不出来的题目,读者可以或许斟酌增强这局部特性。

全部代码我放在github上了,感兴趣的读者直接看源代码,有题目迎接留言~
https://github.com/xlturing/machine-learning-journey/tree/master/seg_bilstm

终究写好这个系列了,以后感谢近来在弄的Attention、Transformer和BERT这一套在文本分类中的运用哈,迎接人人交换。

-玖富娱乐是一家为代理招商,直属主管信息发布为主的资讯网站,同时也兼顾玖富娱乐代理注册登录地址。