如何在Python中利用TensorFlow实现条件随机场CRF层

老辰小哥_6659

老辰小哥_6659

2026-09-13

1038人浏览

原创

crf层需自定义或使用tensorflow-addons;tf≤2.14用tfa.layers.crf,tf≥2.15需手写,核心是前向算法与viterbi解码,输入为logits,loss为负对数似然。

如何在python中利用tensorflow实现条件随机场crf层

CRF层在TensorFlow里必须用tf.keras.layers.Layer自定义

TensorFlow官方Keras没有内置CRF层,直接调用tf.keras.layers.CRF会报AttributeError。你得自己封装CRF逻辑,或依赖第三方库(如tensorflow-addons)。但注意:tensorflow-addons的tfa.layers.CRF只支持TensorFlow 2.8–2.14,且不兼容TF 2.15+(因底层tf.linalg.band_part行为变更)。

推荐做法是:用tfa.layers.CRF(TF ≤2.14)或手写CRF层(TF ≥2.15)。手写时核心是实现前向算法和Viterbi解码,不能只靠tf.nn.softmax——那只是逐帧归一化,不是序列级建模。

  • CRF层输入必须是logits(未softmax),shape为(batch_size, seq_len, num_tags)
  • 转移矩阵需初始化为tf.Variable,shape为(num_tags, num_tags),不能是常量
  • 训练时loss要包含标签路径得分与所有路径总分之差,即log_likelihood取负

用tensorflow-addons加载CRF层的典型报错及修复

常见错误是ModuleNotFoundError: No module named 'tfa'或InvalidArgumentError: input must be at least 2-dim。前者说明没装对版本;后者多因输入张量少了一维——CRF层要求输入是3D,而LSTM输出若用了return_sequences=False,只剩2D,必须设为True。

安装命令要严格匹配TF版本:

pip install tensorflow-addons==0.21.0  # for TF 2.11–2.14
pip install tensorflow-addons==0.20.0  # for TF 2.10

模型构建示例:

Shadows Python Sensei
Shadows Python Sensei

Python 最佳实践助手——代码规范、设计模式、性能优化、测试与类型注解。适用于编写或审查 Python 代码。

下载
import tensorflow as tf
import tensorflow_addons as tfa
<p>model = tf.keras.Sequential([
tf.keras.layers.Embedding(vocab_size, 100),
tf.keras.layers.Bidirectional(tf.keras.layers.LSTM(128, return_sequences=True)),
tf.keras.layers.Dense(num_tags),  # logits, not softmax!
tfa.layers.CRF(num_tags)  # 自动处理转移矩阵和loss
])</p>
  • 必须在Dense后接CRF,且Dense不能带activation='softmax'
  • tfa.layers.CRF默认返回(decoded_sequence, log_likelihood),训练时要用log_likelihood作为loss
  • 预测时用model.predict()得到的是decoded_sequence,不是概率分布

手动实现CRF层的关键三步:转移矩阵、前向算法、Viterbi

手写CRF不难,但容易在维度和mask处理上出错。核心不是重写整个算法,而是正确调用tf.linalg.band_part(旧版)或改用tf.where + tf.scatter_nd(新版)构造转移约束;前向算法中每步需用tf.reduce_logsumexp而非tf.reduce_sum,否则数值溢出。

  • 转移矩阵初始化建议用tf.random.normal((num_tags, num_tags), stddev=0.1),避免全零导致梯度消失
  • 输入mask必须是布尔型tf.bool,传入前向函数前要转成tf.float32并广播到logits维度
  • Viterbi回溯时,用tf.TensorArray暂存每步最大路径索引,不能用Python list

关键片段示意(简化版前向):

def crf_log_likelihood(logits, tags, trans, mask):
    # logits: [B, T, N], tags: [B, T], trans: [N, N], mask: [B, T]
    sequence_lengths = tf.reduce_sum(tf.cast(mask, tf.int32), axis=1)
    log_likelihood, _ = tfa.text.crf_log_likelihood(
        logits, tags, sequence_lengths, trans
    )
    return log_likelihood

注意:tfa.text.crf_log_likelihood是底层C++实现,比纯tf手写快且稳,只要TF版本兼容就优先用它。

训练时loss和metrics容易混淆的两个点

CRF模型的loss必须是-log_likelihood,不是sparse_categorical_crossentropy。否则模型学不会标签间依赖关系,性能掉点明显(NER任务F1常降5–10%)。同样,评估指标也不能用SparseCategoricalAccuracy——它只比对单个token,忽略序列约束。

  • 训练loss设为lambda y_true, y_pred: -crf_log_likelihood(y_pred, y_true, trans, mask)
  • 自定义metric需在update_state中调用tfa.text.crf_decode获得预测标签,再与真实标签逐元素比较
  • 如果用model.compile(loss='sparse_categorical_crossentropy'),哪怕后面接了CRF层,loss也完全失效

最稳妥的方式是把CRF loss写进训练循环里,绕过Keras自动loss机制,尤其在TF ≥2.15时更可控。

Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!

相关文章

PHP速学视频免费教程(入门到精通)
PHP速学视频免费教程(入门到精通)

PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
python打包成可执行文件
python打包成可执行文件

本专题为大家带来python打包成可执行文件相关的文章,大家可以免费的下载体验。

2023.07.20

1571

4

python能做什么
python能做什么

python能做的有:可用于开发基于控制台的应用程序、多媒体部分开发、用于开发基于Web的应用程序、使用python处理数据、系统编程等等。本专题为大家提供python相关的各种文章、以及下载和课程。

2023.07.25

3784

7

format在python中的用法
format在python中的用法

Python中的format是一种字符串格式化方法,用于将变量或值插入到字符串中的占位符位置。通过format方法,我们可以动态地构建字符串,使其包含不同值。php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

2023.07.31

1589

3

python教程
python教程

Python已成为一门网红语言,即使是在非编程开发者当中,也掀起了一股学习的热潮。本专题为大家带来python教程的相关文章,大家可以免费体验学习。

2023.08.03

21677

23

python环境变量的配置
python环境变量的配置

Python是一种流行的编程语言,被广泛用于软件开发、数据分析和科学计算等领域。在安装Python之后,我们需要配置环境变量,以便在任何位置都能够访问Python的可执行文件。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

2023.08.04

2667

5

python eval
python eval

eval函数是Python中一个非常强大的函数,它可以将字符串作为Python代码进行执行,实现动态编程的效果。然而,由于其潜在的安全风险和性能问题,需要谨慎使用。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

2023.08.04

2727

5

scratch和python区别
scratch和python区别

scratch和python的区别:1、scratch是一种专为初学者设计的图形化编程语言,python是一种文本编程语言;2、scratch使用的是基于积木的编程语法,python采用更加传统的文本编程语法等等。本专题为大家提供scratch和python相关的文章、下载、课程内容,供大家免费下载体验。

2023.08.11

1103

5

python合并两个列表
python合并两个列表

Python是一种强大的编程语言,具有许多方便的功能和工具。在Python中,有多种方法可以合并两个列表。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

2023.08.10

596

4

python是前端还是后端
python是前端还是后端

Python属于前端也属于后端,其灵活性和丰富的生态系统使得开发人员能够在不同的领域中灵活运用。本专题为大家提供python相关的文章、下载、课程内容,供大家免费下载体验。

2023.08.11

2103

5

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程