条件随机场(CRF)

Featured image

随机场 & 马尔可夫随机场 & 条件随机场

随机场:在一个包含多个位置的空间内,为每个位置按照特定的分布赋值便得到一个样本,类似这种事情称之为随机场;比如句子分词,实际上是为句子中每个字符位置赋予B、I、O等标签,这就是随机场。

马尔可夫随机场:每个位置的值与相邻位置相关,而与不相邻的位置无关,称为马尔可夫随机场;

条件随机场:每个位置的值是在给定一系列条件下得到的,所以马尔可夫随机场可以认为是条件随机场的特例,条件随机场更加一般化。

条件随机场

看了好多介绍,从云雾缭绕的感觉到自以为基本理清,其实我个人理解条件随机场就是在每一个时间步使用逻辑回归求解各个状态的概率p(yi|x),最终利用动态规划求全局最优(而不是每个时间步概率最大的状态)。求全局最优的过程中仍然会用到转移矩阵,这个矩阵参数是怎么来的暂时不清楚(推测可能跟HMM相同);

模型训练的目标是最大化:∏ ∏p(yi|x) 这里的yi代表真实标签,为什么用两个连乘符号,因为一个样本的每一个时间步对于一组x,y;所以连乘求这个样本的最大概率,第二个连乘符号表示所有样本,这与逻辑回归是一致的,损失函数仍然是最大似然估计;最终求得X中每个特征对应的权重,但由于y往往有多个状态,因此每个特征对应权重个数等于y类别的数量(类似于逻辑回归处理多分类问题);

tensorflow的crf Decoder


import tensorflow as tf
import numpy as np
from tensorflow.contrib.crf import viterbi_decode
from tensorflow.contrib.crf import crf_decode

print("tf_version:", tf.__version__)
step_score = np.array([[
    [9, 2, 1],
    [9, 1, 1],
    [1, 3, 2],
    [3, 2, 1],
    [4, 5, 6],
    [8, 4, 1]
]])  # (batch_size, time_step, num_tabs)
transition = np.array([
    [2, 1, 3],
    [1, 3, 2],
    [3, 2, 1]
])  # (num_tabs, num_tabs)

lengths = [len(step_score[0])]  # (batch_size, time_step)
score_t = tf.constant(step_score, dtype=tf.int64)
transition_t = tf.constant(transition, dtype=tf.int64)
lengths_t = tf.constant(lengths, dtype=tf.int64)

tf_op = crf_decode(
    potentials=score_t,
    transition_params=transition_t,
    sequence_length=lengths_t)
with tf.Session() as sess:
    paths_tf, scores_tf = sess.run(tf_op)
    print("[tensorflow]")
    print(paths_tf)
    print(scores_tf)

print("----------custom--------------")


class CrfDecoder:
    def __init__(self, trans):
        self._trans = trans

    def crf_decoder(self, steps_score):
        states = []
        max_score, last_state, log = self.max_score(steps_score)
        states.append(last_state)

        i = len(log) - 1
        while i >= 0:
            t = log[i][last_state]
            last_state = t[0]
            states.append(last_state)
            i -= 1
        return np.array(states)[::-1], max_score

    def max_score(self, steps_score):
        log = []
        step_state_max_score = steps_score[0][0]
        for i in range(1, steps_score.shape[1]):
            step_state_max_score, ts = self.max_score_cur_step(step_state_max_score, steps_score[0][i])
            log.append(ts)
        return np.max(step_state_max_score), np.argmax(step_state_max_score), log

    def max_score_cur_step(self, last_state, now_state):
        ts = []
        for i in range(len(now_state)):
            t = None
            tmp_max_score = 0
            for j in range(len(last_state)):
                tmp_score = last_state[j] + self._trans[j][i] + now_state[i]
                if tmp_score > tmp_max_score:
                    tmp_max_score = tmp_score
                    t = (j, i)
            ts.append(t)
            now_state[i] = tmp_max_score
        return now_state, ts


if __name__ == '__main__':
    decoder = CrfDecoder(transition)
    print(decoder.crf_decoder(step_score))