命名实体识别之动态融合不同bert层的特征(基于tensorflow)

2020-12-16 15:31:10 浏览数 (1)

代码语言:javascript复制
    num_labels = self.config.relation_num
    bert_config_file = self.config.bert_config_file
    bert_config = BertConfig.from_json_file(bert_config_file)

    model = BertModel(
        config=bert_config,
        is_training=self.is_training,  # 微调
        input_ids=self.input_x_word,
        input_mask=self.input_mask,
        token_type_ids=None,
        use_one_hot_embeddings=False)

    # If you want to use the token-level output, use model.get_sequence_output()
    # output_layer = model.get_pooled_output() # [?,768]
    # print("output_layer.shape:",output_layer)
    output_layer = model.get_sequence_output()
    print("output_layer.shape:",output_layer.shape)
    hidden_size = output_layer.shape[-1].value # 768
    print("=============================")
    print("打印融合特征的相关张量的形状")
    layer_logits = []
    for i, layer in enumerate(model.all_encoder_layers):
        print("layer:",layer)
        layer_logits.append(
            tf.layers.dense(
                layer, 1,
                kernel_initializer=tf.truncated_normal_initializer(stddev=0.02),
                name="layer_logit%d" % i
            )
        )
    print("np.array(layer_logits).shape:",np.array(layer_logits).shape)
    layer_logits = tf.concat(layer_logits, axis=2)  # 第三维度拼接[batchsize,max_len,12]
    print("layer_logits.shape:",layer_logits.shape)
    layer_dist = tf.nn.softmax(layer_logits) #[batchszie,max_len,12]
    print("layer_dist.shape:",layer_dist.shape)
    # [batchsize,max_len,12,768]
    seq_out = tf.concat([tf.expand_dims(x, axis=2) for x in model.all_encoder_layers], axis=2)
    print("seq_out.shape:",seq_out.shape)
    #[batchsize,max_len,1,12] × [batchsize,max_len,12,768]
    pooled_output = tf.matmul(tf.expand_dims(layer_dist, axis=2), seq_out)
    pooled_output = tf.squeeze(pooled_output, axis=2)
    print("pooled_output.shape:",pooled_output.shape)
    pooled_layer = pooled_output
    print("=============================")

输出:

代码语言:javascript复制
=============================
打印融合特征的相关张量的形状
layer: Tensor("bert/encoder/Reshape_2:0", shape=(?, ?, 768), dtype=float32)
layer: Tensor("bert/encoder/Reshape_3:0", shape=(?, ?, 768), dtype=float32)
layer: Tensor("bert/encoder/Reshape_4:0", shape=(?, ?, 768), dtype=float32)
layer: Tensor("bert/encoder/Reshape_5:0", shape=(?, ?, 768), dtype=float32)
layer: Tensor("bert/encoder/Reshape_6:0", shape=(?, ?, 768), dtype=float32)
layer: Tensor("bert/encoder/Reshape_7:0", shape=(?, ?, 768), dtype=float32)
layer: Tensor("bert/encoder/Reshape_8:0", shape=(?, ?, 768), dtype=float32)
layer: Tensor("bert/encoder/Reshape_9:0", shape=(?, ?, 768), dtype=float32)
layer: Tensor("bert/encoder/Reshape_10:0", shape=(?, ?, 768), dtype=float32)
layer: Tensor("bert/encoder/Reshape_11:0", shape=(?, ?, 768), dtype=float32)
layer: Tensor("bert/encoder/Reshape_12:0", shape=(?, ?, 768), dtype=float32)
layer: Tensor("bert/encoder/Reshape_13:0", shape=(?, ?, 768), dtype=float32)
np.array(layer_logits).shape: (12,)
layer_logits.shape: (?, ?, 12)
layer_dist.shape: (?, ?, 12)
seq_out.shape: (?, ?, 12, 768)
pooled_output.shape: (?, ?, 768)
=============================

说明:

bert中文base版总共有12层,也就是每一层都可以输出相应的特征,我们可以使用model.all_encoder_layers来获取,然后我们将每一层的768维度的特征映射成1维,对每一个特征进行最后一个维度的拼接后经过softmax层,得到每一层特征相对应的权重,最后经过[batchsize,max_len,1,12] × [batchsize,max_len,12,768],得到[batchszie,max_len,1,768],去除掉一维得到[batchsize,max_len,768],这样我们就得到了可以动态选择的特征,接下来就可以利用该特征进行相关的微调任务了。

比如:

代码语言:javascript复制
output_weights = tf.get_variable(
        "output_weights", [num_labels, hidden_size],
        initializer=tf.truncated_normal_initializer(stddev=0.02)) # [768, 11]
print("output_weights.shape:",output_weights)

output_bias = tf.get_variable(
        "output_bias", [num_labels], initializer=tf.zeros_initializer()) # [11]

with tf.variable_scope("loss"):

      logits = tf.matmul(pooled_layer, output_weights, transpose_b=True) # [?,?,768]*[768,11] = [?,?,11]
      #print("logits.shape:",logits.shape)
      self.logits = tf.nn.bias_add(logits, output_bias)
      self.probabilities = tf.nn.softmax(self.logits, axis=-1)
      log_probs = tf.nn.log_softmax(self.logits, axis=-1) # [?,?,11]
      print("log_probs.shape:",log_probs.shape)

      self.predictions = tf.argmax(self.logits, axis=-1, name="predictions")

      one_hot_labels = tf.one_hot(self.input_relation, depth=num_labels, dtype=tf.float32) # [?,512,11]
      #print(one_hot_labels)
      #print("one_hot_labels.shape:",one_hot_labels.shape)
      self.per_example_loss = -tf.reduce_sum(one_hot_labels * log_probs, axis=-1)
      #print("self.per_example_loss.shape:",self.per_example_loss.shape)
      self.loss = tf.reduce_mean(self.per_example_loss)

0 人点赞