CRF keras代码实现

这份代码来自于苏剑林

 

# -*- coding:utf-8 -*-

from keras.layers import Layer
import keras.backend as K

class CRF(Layer):
    """纯Keras实现CRF层
    CRF层本质上是一个带训练参数的loss计算层,因此CRF层只用来训练模型,
    而预测则需要另外建立模型,但是还是要用到训练好的转移矩阵
    """
    def __init__(self, ignore_last_label=False, **kwargs):
        """ignore_last_label:定义要不要忽略最后一个标签,起到mask的效果
        """
        self.ignore_last_label = 1 if ignore_last_label else 0
        super(CRF, self).__init__(**kwargs)
    def build(self, input_shape):
        self.num_labels = input_shape[-1] - self.ignore_last_label
        self.trans = self.add_weight(name='crf_trans',
                                     shape=(self.num_labels, self.num_labels),
                                     initializer='glorot_uniform',
                                     trainable=True)
    def log_norm_step(self, inputs, states):
        """递归计算归一化因子
        要点:1、递归计算;2、用logsumexp避免溢出。
        技巧:通过expand_dims来对齐张量。
        """
        states = K.expand_dims(states[0], 2) # previous
        inputs = K.expand_dims(inputs, 2) # 这个时刻的对标签的打分值,Emission score
        trans = K.expand_dims(self.trans, 0) # 转移矩阵

        output = K.logsumexp(states+trans+inputs, 1) # e 指数求和,log是防止溢出
        return output, [output] 

    def path_score(self, inputs, labels):
        """计算目标路径的相对概率(还没有归一化)
        要点:逐标签得分,加上转移概率得分。
        技巧:用“预测”点乘“目标”的方法抽取出目标路径的得分。
        """
        # 在CRF中涉及到标签得分加上转移概率,而这个point score就是相当于是标签得分(在真是标签的情况下,查看预测对于真实标签位置的总得分),因为labels的shape是[B, T, N],而在N这个维度是one-hot,
        # 这里再乘以pred,相当于是对labels存在1的地方进行打分,其余地方全为0,再进行第2个维度相加表示去除0的值,再相加表示求一个总的标签得分
        point_score = K.sum(K.sum(inputs*labels, 2), 1, keepdims=True) # 逐标签得分, shape [B, 1]
        labels1 = K.expand_dims(labels[:, :-1], 3) # shape [B, T-1, N, 1]
        labels2 = K.expand_dims(labels[:, 1:], 2) # shape [B, T-1, 1, N]
        # 这里相乘的目的相当于从上一时刻转移到当前时刻,确定当前时刻是从上一时刻哪一个标签转移过来的,因为labels是one-hot的形式,所以在最后两个维度只有1个元素为1,其他全部为0,表示转移标志
        labels = labels1 * labels2 # 两个错位labels,负责从转移矩阵中抽取目标转移得分 shape [B, T-1, N, N]
        trans = K.expand_dims(K.expand_dims(self.trans, 0), 0)
        # K.sum(trans*labels, [2, 3]),因为trans*labels的结果是[B, T-1, N, N], 而后面两个维度中只有1个有值,表示转移得分
        trans_score = K.sum(K.sum(trans*labels, [2, 3]), 1, keepdims=True) # 求出所有T-1时刻的概率转移总得分,K.sum(trans*labels, [2, 3]), 表示每个时刻的转移得分
        return point_score+trans_score # 两部分得分之和

    def call(self, inputs): # CRF本身不改变输出,它只是一个loss
        return inputs

    def loss(self, y_true, y_pred): # 目标y_pred需要是one hot形式
        mask = 1-y_true[:, 1:, -1] if self.ignore_last_label else None
        y_true, y_pred = y_true[:, :, :self.num_labels], y_pred[:, :, :self.num_labels]
        init_states = [y_pred[:, 0]] # 初始状态
        log_norm, _, _ = K.rnn(self.log_norm_step, y_pred[:, 1:], init_states, mask=mask) # 计算Z向量(对数) shape[batch_size, output_dim]
        log_norm = K.logsumexp(log_norm, 1, keepdims=True) # 计算Z(对数)shape [batch_size, 1] 计算一个总的
        path_score = self.path_score(y_pred, y_true) # 计算分子(对数)
        return log_norm - path_score # 即log(分子/分母)

    def accuracy(self, y_true, y_pred): # 训练过程中显示逐帧准确率的函数,排除了mask的影响
        mask = 1-y_true[:,:,-1] if self.ignore_last_label else None
        y_true,y_pred = y_true[:,:,:self.num_labels],y_pred[:,:,:self.num_labels]
        isequal = K.equal(K.argmax(y_true, 2), K.argmax(y_pred, 2))
        isequal = K.cast(isequal, 'float32')
        if mask == None:
            return K.mean(isequal)
        else:
            return K.sum(isequal*mask) / K.sum(mask)

 

转载于:https://www.cnblogs.com/callyblog/p/11289566.html

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: LSTM-CRF模型是一种将长短期记忆网络(LSTM)与条件随机场(CRF)结合的序列标注模型。下面是一个简单的LSTM-CRF模型的代码示例: ```python import tensorflow as tf from tensorflow.keras import Sequential from tensorflow.keras.layers import LSTM, Embedding, Dense, TimeDistributed, Dropout, Bidirectional, Input from tensorflow_addons import crf # 定义模型 def build_model(input_dim, output_dim): model = Sequential() model.add(Input(shape=(None,))) model.add(Embedding(input_dim, output_dim)) model.add(Bidirectional(LSTM(units=output_dim, return_sequences=True))) model.add(Dropout(0.5)) model.add(TimeDistributed(Dense(output_dim, activation="relu"))) crf_layer = crf.CRF(output_dim) model.add(crf_layer) model.compile(loss=crf_layer.loss, optimizer="adam", metrics=[crf_layer.accuracy]) return model # 构建训练数据 train_x = [...] # 输入序列 train_y = [...] # 标签序列 # 构建模型 input_dim = 100 # 输入维度,例如词汇表大小 output_dim = 64 # 输出维度,例如标签种类数 model = build_model(input_dim, output_dim) # 训练模型 model.fit(train_x, train_y, epochs=10, validation_split=0.2) # 预测 test_x = [...] # 测试输入序列 predictions = model.predict(test_x) ``` 以上代码中,首先定义了一个LSTM-CRF模型,并使用了双向LSTM层以增强模型的学习能力。接着使用TimeDistributed层将Dense层应用于每个时间步上的输入。然后使用了CRF层作为模型的输出层,并使用Adam优化器进行训练。最后利用训练好的模型进行预测。在实际使用中,需要根据具体的任务和数据进行参数的调整和调优。 ### 回答2: LSTM-CRF模型是一种用于序列标注任务的深度学习模型。它结合了LSTM(长短时记忆网络)和CRF(条件随机场)两种方法。以下是一个简单的LSTM-CRF模型代码示例: 首先,导入所需的库: import tensorflow as tf import numpy as np 然后,定义模型的超参数: input_size = 100 # 输入大小 hidden_size = 128 # LSTM隐藏层大小 num_classes = 10 # 标签类别数 接着,构建LSTM-CRF模型: class LSTM_CRF_Model(tf.keras.Model): def __init__(self, input_size, hidden_size, num_classes): super(LSTM_CRF_Model, self).__init__() self.hidden_size = hidden_size self.num_classes = num_classes # 定义LSTM层 self.lstm = tf.keras.layers.LSTM(hidden_size, return_sequences=True) # 定义CRF层 self.transition_params = tf.Variable(tf.random.uniform(shape=(num_classes, num_classes))) def call(self, inputs): sequence_length = tf.shape(inputs)[1] batch_size = tf.shape(inputs)[0] # 将输入传入LSTM层 lstm_output = self.lstm(inputs) # 将LSTM输出转换为CRF需要的形状 flattened_output = tf.reshape(lstm_output, [-1, self.hidden_size]) logits = tf.keras.layers.Dense(self.num_classes)(flattened_output) logits = tf.reshape(logits, [batch_size, sequence_length, self.num_classes]) return logits 现在,我们可以使用该模型对序列进行标注。假设我们有输入数据x和对应的标签y: # 创建模型实例 model = LSTM_CRF_Model(input_size, hidden_size, num_classes) # 定义损失函数 loss_object = tf.keras.losses.CategoricalCrossentropy(from_logits=True) # 定义优化器 optimizer = tf.keras.optimizers.Adam() # 定义评估指标 accuracy_metric = tf.keras.metrics.CategoricalAccuracy() # 迭代训练模型 for epoch in range(num_epochs): for inputs, labels in dataset: with tf.GradientTape() as tape: # 前向传播 logits = model(inputs) # 计算损失 loss = loss_object(labels, logits) # 反向传播 gradients = tape.gradient(loss, model.trainable_variables) optimizer.apply_gradients(zip(gradients, model.trainable_variables)) # 更新评估指标 accuracy_metric(labels, logits) # 输出每个epoch的损失和精度 print('Epoch: {}, Loss: {}, Accuracy: {}'.format(epoch+1, loss, accuracy_metric.result())) 通过上述步骤,我们可以构建和训练一个简单的LSTM-CRF模型。实际应用中,可能会对其进行更复杂的改进和调整,以适应具体任务的需求。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值