天天看点

BiLSTM+CRF code

开始撸代码:

1.先定义参数,

         batch_size:64

         epoch:40

         hidden_dim:300

         learning_rate:0.001

        dropout:0.5

        embedding_dim:300 

        optimizer:Adam

         clip:5.0(梯度截断,防止梯度爆炸和消失)

2.是用预训练好的字向量还是随机初始化

         随机的话:np.float(np.random.uniform(-0.25, 0.25, (len(vocab), embedding_dim))) 

         预训练:np.array(np.load(embedding_path), dtype=’float32’) 格式大概就是一个字对应一个300维的向量

3.读取train_data和test_data

         读完之后的格式是一个数组,每个元素包含的是每个段落的所有元素和标签

4.数据基本整理完了,那就开始模型的构造了,也就是单层的BiLSTM+CRF层,学完了上面的理论知识,太好理解了

  1. def__init__():相关参数赋值
  2. 相关palceholder:

          self.word_ids = tf.olaceholder(tf.int32, shape=[None, None], name=”word_ids”)

          self.labels = tf.placeholder(tf.int32, shape=[None, None], name=”labels”)

          self.sequence_lengths = tf.olaceholder(tf.int32, shape=[None], name=”sequence_lengths”)

          self.dropout_pl = tf.placeholder(tf.float32, shape=[], name=”dropout_pl”)

          self.learning_rate = tf.placeholder(tf.float32, shape=[], name=”learning_rate”)

     3. Embedding层:定义变量形状、初始化及输出相应字坐标的字向量,dropout是防止过拟合,随机不更新部分参数。                       word_ids的shape应该是batch_size * sequence_lengths

         with tf.variable_scope(“words”):

                 _word_embedding = tf.Variable(self.embeddings,dtype=tf.float32,

                                                                    trainable=True,

                                                                    name=”_word_embedding”)

                word_embedding=tf.nn.embedding_lookup(params=_word_embedding,

                                                                                     ids= self.word_ids,

                                                                                      name=”word_embedding”

       self.word_embeddings = tf.nn.dropout(word_embedding, self.dropout_pl)

    4. Bilstm层

        with tf.variable_scope(“bi-lstm”):

               cell_fw = LSTMCell(self.hidden_dim)

               cell_bw = LSTMCell(self.hidden_dim)

               (output_fw_seq, output_bw_seq), _ = tf.nn.bidirectional_dynamic_rnn(

                                                        cell_fw=cell_fw, cell_bw=cell_bw, inputs=self.word_imbeddings,

                                                         sequence_length=self.qequence_lengths, dtype=tf.float32)

                output = tf.concat([output_fw_seq, output_bw_seq], axis=-1)

                output = tf.nn.dropout(output, self.dropout_pl)

                权重层

                 with tf.variable_scope(“W”)

                        W = tf.get_variable(name=”W”, shape=[2 * self.hidden_dim, self.num_tags],

                                                          Inittializer=tf.contrib.layer.xavier_initializer(), dtype=tf.float32)

                        b = tf.get_variable(name=”b”, shape=[self.num_tags],

                                                           Inittializer=tf.contrib.layer.xavier_initializer(), dtype=tf.float32)

                        s = tf.shape(output)   我的理解这里矩阵应该是batch_size * sequence_lengths * (2 * self.hidden_dim)

                        output = tf.reshape(output, [-1, 2 * self.hidden_dim])   (batch_size* sequence_lengths) * (2 * self.hidden_dim)

                        pred = tf.matmul(output, W) + b    (batch_size* sequence_lengths) * num_tags

                        self.logits = tf.reshape(pred, [-1, s[1], self.num_tags])  a[1]是sequence_lengths

                                                                                                               batch_size* sequence_lengths* num_tags

       5. loss层

             log_likelihood, self.transition_params = crf_log_likelihood(inputs=self.logits,

                                                                                            tag_indices=self.labels,   batch_size* sequence_lengths(真实标签)

                                                                                            sequence_lengths=self.sequence_lengths)

            我必须得细讲一下crf_log_likelihood这个函数,百度别人的都是把注释翻译一遍,我现在需要了解的是里面用到了什么函               数,返回的具体是什么:

                  首先输入:inputs->batch_size * sequence_lengths * num_tags,每个元素对应每个标签的概率

                                    tag_indices-> batch_size * sequence_lengths ,每个元素对应的真是标签

                                    sequence_lengths->每个batch_size的长度

                                    transition_params->一个[num_tags, num_tags]矩阵

                  输出呢:log_likelihood->英文是说a [batch_size] tensor containing the log_likelihood of each

                                                       example, given the sequence of tag indices,应该是batch_size * 1,即

                                                        每个序列的得分,也就是真实路径的那个得分吧,在理论知识里面应该

                                                         就是那个可能性,下面求loss的时候加了负号,大概就是想要求loss

                                                         最小。这个里面应该包含了动态规划算法和viterbi算法)

                                transition_params->一个[num_tags, num_tags]矩阵

                  过程:1. 如果transition_params是None,则初始化一个

                              2. crf_sequence_score(),函数返回的是未归一化的得分,batch_size * 1

                              3. crf_log_norm(),函数返回的是归一化的得分,batch_size * 1

                              4. 两者相减肯定是batch_size * 1,这就是这个函数的结果,我有点迷惑

            self.loss = -tf.reduce_mean(log_likelihood)

            tf.summary.scalar(“loss”, self.loss)

       6. train层:

             with tf.variable_scope(“train”):

                      self.global_step = tf.Variable(0, name=”global_step”, trainable=False)

                       optim = tf.train.AdamOptimizer(learning_rate=self.learning_rate)

                       grads_and_vars = optim.compute_graduents(self.loss)

                       grads_and_vars_clip = [ [ tf.clip_by_value(g, -self.clip_grad, self.clip_grad), v] for g, v in grads_and_vars]

                       对梯度值进行截断,防止出现梯度消失和爆炸

                       self.train_op = optim.apply_gradients(grads_and_vars_clip, global_step=self.global_step)

                       self.init_op = tf.global_variables_initializer()

5. 模型架构写完之后就是加入数据集了

  1. 对训练集根据batch_size的大小随机划分
  2. 进行padding,长的截取,短的补0
  3. 对feed_dict的元素进行赋值
  4. 然后就是sess.run( [self.train_op, self.loss, self.merged, self.global_step], feed_dict=feed_dict)
  5. 这里没有评估集,直接是测试集,也可以加上评估集

          预测一个batch的结果时,

          logits, transition_params = sess.run([self.logits, self.transition_params], feed_dict=feed_dict)

          logits里面保存到的是64*300*7,每个元素对应的label的概率,然后针对 每个sequence利用veterbi_decode函数可以直接            得到最优路径,再与真实坐标多对比就可以获得test的loss和准确率(貌似也可以直接获取test的损失,实际上就相当于预            测了)

继续阅读