天天看點

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的損失,實際上就相當于預            測了)

繼續閱讀