PaddleNLP paddlenlp.layers 网络层库实战指南:CRF 序列标注、TCN 时序卷积与 sequence_mask 详解

发布时间:2026/9/23 16:51:08
PaddleNLP paddlenlp.layers 网络层库实战指南:CRF 序列标注、TCN 时序卷积与 sequence_mask 详解 PaddleNLP paddlenlp.layers 网络层库实战指南CRF 序列标注、TCN 时序卷积与 sequence_mask 详解【免费下载链接】PaddleNLPEasy-to-use and powerful LLM and SLM library with awesome model zoo.项目地址: https://gitcode.com/gh_mirrors/pa/PaddleNLP导读paddlenlp.layers是 PaddleNLP 中面向自然语言处理任务封装的一组基础网络层模块本文聚焦该模块在中文 API 文档docs/zh/source/paddlenlp.layers.rst中收录的三个核心子模块线性链条件随机场LinearChainCrf及配套的LinearChainCrfLoss与ViterbiDecoder、时序卷积网络TCN与TemporalBlock以及高效序列掩码工具sequence_mask。读完本文你将掌握这三个模块的数学原理、参数语义、源码级实现细节并能在命名实体识别、词法分析、序列标注与时间序列建模等任务中直接复用它们。模块总览从文档结构到源码分布paddlenlp.layers子包源码位于 paddlenlp/layers/包含crf.py、sequence.py、tcn.py等文件。其对外导出的公开符号定义在 paddlenlp/layers/init.py包括LinearChainCrf、LinearChainCrfLoss、ViterbiDecoder来自 crf.pysequence_mask来自 sequence.pyTCN、TemporalBlock来自 tcn.py以及GlobalPointer系列与Linear等globalpointer.py、linear.py中文文档以automodule指令自动生成 API 页面主页面通过 toctree 组织三个子页面paddlenlp.layers.crf.rst、paddlenlp.layers.sequence.rst、paddlenlp.layers.tcn.rst。下文按这三个模块逐一深入。线性链 CRF为序列标注引入标签间依赖为什么需要 CRF在命名实体识别NER、词性标注等序列标注任务中如果对每个 token 独立分类如 Softmax 分类器会忽略相邻标签之间的约束关系。例如 NER 中 B-PER 之后不应紧跟 I-ORG。LinearChainCrf正是为此设计它在发射分数emission score之上叠加转移分数transition score显式建模相邻标签间的转移概率把上下文纳入预测。实现说明参见 crf.py 中类文档对线性链 CRF 的定位描述。LinearChainCrf 的参数与转移矩阵LinearChainCrf构造函数签名如下LinearChainCrf(num_labels, crf_lr0.1, with_start_stop_tagTrue)参数类型默认值说明num_labelsint必填标签类别数crf_lrfloat0.1CRF 转移参数的学习率独立于模型其余部分with_start_stop_tagboolTrue是否引入 START/STOP 哨兵标签关键实现细节对应 crf.py当with_start_stop_tagTrue时内部标签数num_tags num_labels 2额外两个位置分别作为[START]start_idx num_tags - 1与[STOP]stop_idx num_tags - 2转移矩阵形状为[num_labels2, num_labels2]当with_start_stop_tagFalse时转移矩阵形状为[num_labels, num_labels]序列首 token 无前驱标签转移矩阵通过self.create_parameter(attrpaddle.ParamAttr(learning_ratecrf_lr), shape[num_tags, num_tags], dtypefloat32)创建使用独立学习率crf_lr这是为了让转移参数可以按经验取更大的学习率默认 0.1加速收敛。forward计算配分函数归一化因子forward(inputs, lengths)计算线性链 CRF 的归一化因子log-partition functionF logZ(x) log Σ_y exp(score(x, y)) score(x, y) Σ_i Emit(x_i, y_i) Trans(y_{i-1}, y_i)其中Emit(x_i, y_i)是第 i 个 token 的发射分数Trans(y_{i-1}, y_i)是标签间转移分数。通过动态规划递推F(1) log Σ_{y1} exp(p(y1) T([START], y1)) F(n) log Σ_{yn} exp(F(n-1) p(yn) T(y_{n-1}, y_n))源码中的核心递推式crf.pyalpha_exp alpha.unsqueeze(1) mat input_exp trans_exp alpha_exp alpha log_sum_exp(mat, 2).squeeze(-1)其中log_sum_expcrf.py采用max归一化技巧避免exp上溢/下溢。初始化时crf.py非 START 位置的初始 alpha 填充-10000.0小值START 位置填充0.0从而保证第一步从 START 出发的路径得分最高。输入输出约定inputs[batch_size, sequence_length, num_tags]float32 发射分数lengths[batch_size]int64每条序列的真实长度用于处理 padding返回norm_score[batch_size]float32 归一化因子。gold_score计算真实标签序列的未归一化得分gold_score(inputs, labels, lengths)crf.py计算score(x, y) Σ_i Emit(x_i, y_i) Trans(y_{i-1}, y_i)内部由两部分组成_point_scorecrf.py通过paddle.gather从展平的发射分数中取出真实标签对应的 logit并用sequence_mask构造掩码剔除 padding 位置的贡献_trans_scorecrf.py在标签序列首尾拼接 START/STOP 哨兵_get_start_stop_tensor将相邻标签对编码为start_idx * num_tags stop_idx的一维索引再从展平的转移矩阵中 gather 出转移得分并累加。LinearChainCrfLoss负对数似然损失LinearChainCrfLoss(crf)crf.py封装了 CRF 的负对数似然loss -log p(y|x) -score(x, y) logZ(x)其forward(inputs, lengths, labels, old_version_labelsNone)实现为loss nn.functional.relu(self.crf.forward(inputs, lengths) - self.crf.gold_score(inputs, labels, lengths))两点需要注意源码注释说明接近收敛时exp在 logsumexp 中的下溢可能使 loss 变为很小的负数理论上一阶链 CRF 的 NLL 应恒大于等于 0因此用relu截断以规避负损失第 4 个参数old_version_labels仅为兼容旧版本调用约定而保留传入时会触发logger.warning提示更新用法crf.py且从 2.0.0b4 起构造LinearChainCrfLoss必须传入LinearChainCrf对象而非transitions张量传入 Tensor 会直接抛出ValueError。ViterbiDecoder解码最优标签序列ViterbiDecoder(transitions, with_start_stop_tagTrue)crf.py在测试/推理阶段用 Viterbi 算法解码得分最高的标签序列注意应只在测试时使用。参数说明transitions[num_tags, num_tags]float32 转移矩阵with_start_stop_tagTrue时转移矩阵的最后一行/列被当作 START倒数第二行/列被当作 STOP注意与LinearChainCrf中索引约定的对应关系start_idx -1stop_idx -2。forward(inputs, lengths)返回元组(scores, paths)scores[batch_size]float32Viterbi 最优路径得分paths[batch_size, sequence_length]int64最优标签索引序列。实现要点crf.py以alpha_trn_sum alpha_exp trans_exp做前向 DPalpha_max取前驱标签的最大值、alpha_argmax记录回溯索引historys随后将historys翻转从last_ids出发逐帧paddle.gather回溯得到完整最优路径并用left_length掩码保证 padding 位置不被计入路径。实战接线完整 CRF 序列标注用法以仓库中真实示例 slm/examples/information_extraction/waybill_ie/model.py 为参照典型接线方式如下from paddlenlp.layers.crf import LinearChainCrf, LinearChainCrfLoss class MyModel(nn.Layer): def __init__(self, num_labels, crf_lr0.1): super().__init__() self.crf LinearChainCrf(num_labels, crf_lrcrf_lr) self.crf_loss LinearChainCrfLoss(self.crf) # paddle 2.2.0 及以上可优先使用 paddle.text.ViterbiDecoder try: from paddle.text import ViterbiDecoder except ImportError: from paddlenlp.layers.crf import ViterbiDecoder self.viterbi_decoder ViterbiDecoder(self.crf.transitions) def forward(self, emission, lengths, labelsNone): if labels is not None: # 训练 return self.crf_loss(emission, lengths, labels) # 推理解码最优路径 return self.viterbi_decoder(emission, lengths)该文件同时演示了with_start_stop_tagFalse的用法model.pyself.crf LinearChainCrf(self.num_labels, crf_lrcrf_lr, with_start_stop_tagFalse) self.crf_loss LinearChainCrfLoss(self.crf) self.viterbi_decoder ViterbiDecoder(self.crf.transitions, False)此外slm/examples/lexical_analysis/model.py 与 slm/applications/information_extraction/text/data_distill/train.py 也使用了paddlenlp.layers的 CRF 组件可作为更多落地参考tests/test_tipc/bigru_crf/model.py 提供了可运行的 BigRUCRF 链路测试模型。sequence_mask为变长序列构造掩码sequence_mask(seq_ids, valid_lengths)定义于 sequence.py与paddle.nn.functional.sequence_mask功能等价但实现不同seq_ids[batch_size, sequence_length]全序列索引张量valid_lengths[batch_size]每条序列的有效长度返回 bool 型mask形状[batch_size, sequence_length]。实现极其简洁仅一行广播比较lengths_exp valid_lengths.unsqueeze(1) mask seq_ids lengths_exp该工具函数被 CRF 模块内部大量复用如_point_score、_trans_score中剔除 padding 贡献也可在任意变长序列任务中独立使用例如对解码输出做掩码、构造 loss 权重等。TCN时序卷积网络设计动机与结构TCNTemporal Convolutional Network是一种纯卷积的序列建模架构论文为An Empirical Evaluation of Generic Convolutional and Recurrent Networks for Sequence ModelingarXiv:1803.01271。它以膨胀因果卷积dilated causal convolution为骨干在多项任务上可作为 LSTM 等循环网络的替代。源码位于 tcn.py。TemporalBlock单层基础块TemporalBlock(n_inputs, n_outputs, kernel_size, stride, dilation, padding, dropout0.2)tcn.py对应论文图 1(b)由以下串行组件构成权重归一化的Conv1Dweight_norm来自paddle.nn.utilsChomp1d因果性裁剪。卷积前在两侧 pad(k-1)*d卷积后通过x[:, :, : -chomp_size]裁掉右侧等量元素从而保证 t 时刻输出只依赖 t 及之前时刻tcn.pyReLU激活Dropout默认 0.2。一个TemporalBlock内包含两组「卷积 Chomp ReLU Dropout」并通过nn.Sequential串接随后是残差连接当n_inputs ! n_outputs时用 1×1 卷积downsample对齐通道否则直接恒等映射最终输出relu(out res)。权重初始化使用均值为 0、标准差 0.01 的正态分布init_weightstcn.py。输入输出约定输入x形状[batch_size, input_channel, sequence_length]输出形状[batch_size, n_outputs, sequence_length]。TCN堆叠多层膨胀卷积TCN(input_channel, num_channels, kernel_size2, dropout0.2)tcn.py将多个TemporalBlock堆叠成完整网络input_channel输入通道数num_channelslist/tuple每一层的输出通道数列表长度即网络层数kernel_size卷积核大小默认 2dropout默认 0.2。核心设计是指数膨胀第 i 层dilation_size 2**i第 i 层的输入通道为num_channels[i-1]首层为input_channelpadding 取(kernel_size - 1) * dilation_size以保证因果性并保持序列长度。膨胀率随层数指数增长使得浅层捕捉近距离依赖、深层拥有指数级增大的感受野这正是 TCN 能以较少层数建模长程依赖的关键。forward直接顺序执行self.network(x)输出形状为[batch_size, num_channels[-1], sequence_length]。在 PaddleNLP 任务中的整体定位paddlenlp.layers提供的 CRF 与 TCN 组件可组合进多种下游任务CRF 系列通常接在 BiLSTM/BigRU 等编码器输出之后做结构化预测见 tests/test_tipc/bigru_crf/model.py 与 slm/examples/lexical_analysis/model.pyTCN 则适用于需要以卷积方式建模时序依赖的场景。由于它们是独立的paddle.nn.Layer子类可以无缝嵌入 PaddleNLP 的 Trainer 训练流程或自定义训练循环。使用前请确认当前环境已安装相应版本的 PaddlePaddle如ViterbiDecoder在 paddle 2.2.0 可迁移到paddle.text并以本仓库实际代码为准。【免费下载链接】PaddleNLPEasy-to-use and powerful LLM and SLM library with awesome model zoo.项目地址: https://gitcode.com/gh_mirrors/pa/PaddleNLP创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考