PaddleNLP 词法分析(Lexical Analysis)实践指南:从 LAC 原理到训练、预测与部署
2026/9/23 17:51:27 网站建设 项目流程
  • 人工智能
  • 大模型
  • NLP
  • 深度学习
  • 预训练
  • 微调
  • RLHF
  • 模型量化

【免费下载链接】PaddleNLP

Easy-to-use and powerful LLM and SLM library with awesome model zoo.

项目地址:https://gitcode.com/gh_mirrors/pa/PaddleNLP
点击查看免费下载

导读

词法分析(Lexical Analysis)是自然语言处理(NLP)的基石任务之一:它把连续的中文文本切分为词语序列,并标注每个词的词性与专名类别,是分词、词性标注、命名实体识别等下游应用的基础能力。本文以 PaddleNLP 开源仓库中的 Lexical Analysis 教程 为骨架,结合仓库内 词法分析示例工程、Taskflow 一键预测实现 与 BiGruCrf 模型源码,系统讲解词法分析的任务定义、GRU+CRF 序列标注原理、数据格式与标签体系、从单卡/多卡训练到评估、模型导出、部署预测再到 Taskflow 一键调用的完整实战链路,帮助读者掌握一套可复现、可定制的中文词法分析方案。

词法分析任务概述

在编译原理中,词法分析(Lexical Analysis)是将字符序列转换为词法单元(token)序列的过程,是编译的第一阶段;在自然语言处理中,它同样是基础中的基础——中文没有天然的空格分词,必须由词法分析器完成"切词 + 打标"两项工作。

文档将词法分析的主要任务归纳为四类:

  1. Tokenization(分词):将连续字符序列切分为有意义的词;
  2. Removing whitespace/comments(去除空白与注释):过滤无信息量的噪音字符;
  3. Tracking line numbers(追踪行号):在代码分析场景记录 token 的原始位置;
  4. Generating symbol tables(生成符号表):为编译器/解释器维护标识符等符号信息。

其抽象数学表示为:

$$ T = Lex(S) $$

其中 $S$ 是输入字符串,$T$ 是输出的 token 序列。在 PaddleNLP 的中文 NLP 场景下,这条"从字符串到 token 序列"的映射具体落地为:输入一句中文,输出该句的切分结果(segs)与每个词的词性/专名标签(tags)。

中文词法分析的建模方式:GRU + CRF 序列标注

在 NLP 中,词法分析通常被建模为**序列标注(Sequence Labeling)**问题:为输入句子的每个"字"打上一个标签,标签的-B(Begin)/-I(Inside)后缀组合即可还原词边界与词类别。PaddleNLP 仓库中 词法分析示例工程 采用经典做法——两层双向 GRU 学习特征 + 一层 CRF 解码完成序列标注

从 模型实现源码 可以看出完整的数据流:

def forward(self, inputs, lengths, labels=None): word_embed = self.word_embedding(inputs) # 1. 字 id -> 字向量 bigru_output, _ = self.gru(word_embed, sequence_length=lengths) # 2. 双向 GRU 特征 emission = self.fc(bigru_output) # 3. 线性层得到发射分数 if labels is not None: loss = self.crf_loss(emission, lengths, labels) # 训练:CRF 损失 return loss else: _, prediction = self.viterbi_decoder(emission, lengths) # 推理:Viterbi 解码 return prediction

对应文档中描述的四步建模流程:

  1. 输入 one-hot 化:每个字以词典中的一个 id 表示;
  2. 字向量映射:one-hot 序列通过字表(nn.Embedding,词向量维度emb_dim=128)转换为实向量表示的字向量序列;
  3. 双向 GRU 特征学习:字向量序列作为输入送入nn.GRUnum_layers=2direction="bidirectional"),堆叠两层以增强学习能力,得到融合上下文的新特征序列;
  4. CRF 序列标注:CRF 以 GRU 输出经线性层(fc,输入维度hidden_size*2)得到的发射分数为输入,以标记序列为监督信号完成序列标注;推理时使用ViterbiDecoder全局搜索最优标签路径,而不是逐位置独立取最大值,从而显式建模标签间的转移约束(如-B后面必须跟同类型的-I)。

模型关键超参数及源码默认值如下表:

参数默认值含义
emb_dim128字向量(word embedding)维度
hidden_size128单层 GRU 隐层节点数(双向输出维度为 2×)
emb_lr2.0Embedding 层学习率缩放系数
crf_lr0.2CRF 层学习率缩放系数
init_bound0.1参数 Uniform 初始化的上下界
with_start_stop_tagTrue是否启用 CRF 起止标签

CRF 部分复用了 PaddleNLP 的 LinearChainCrf 与 LinearChainCrfLoss,训练时计算 CRF 负对数似然损失,推理时通过ViterbiDecoder求最优路径;训练脚本中还使用 ChunkEvaluator(见 train.py 中的chunk_evaluator = ChunkEvaluator(label_list=label_vocab.keys(), suffix=True))按"块"统计 Precision / Recall / F1。

数据准备:下载示例数据与数据格式说明

进入 slm/examples/lexical_analysis 目录,执行以下命令即可下载并解压示例数据集(对应 download.py,其数据源为lexical_analysis_dataset_tiny.tar.gz小样本数据集):

python download.py --data_dir ./

训练数据格式

训练数据(train.tsv/test.tsv)除首行为固定的text_a\tlabel开头外,其余每行由两列组成、以制表符分隔:

  • 第一列:utf-8 编码的中文文本,字符之间以\002分割;
  • 第二列:每个字对应的标注,同样以\002分隔。

采用IOB2 标注体系X-B表示类型为 X 的词的开始,X-I表示该词的持续,O表示不关注的字(在词性、专名联合标注中实际上不存在O)。示例数据(摘自 示例工程 README):

除\002了\002他\002续\002任\002十\002二\002届\002政\002协\002委\002员\002,\002马\002化\002腾\002,\002雷\002军\002,\002李\002彦\002宏\002也\002被\002推\002选\002为\002新\002一\002届\002全\002国\002人\002大\002代\002表\002或\002全\002国\002政\002协\002委\002员 p-B\002p-I\002r-B\002v-B\002v-I\002m-B\002m-I\002m-I\002ORG-B\002ORG-I\002n-B\002n-I\002w-B\002PER-B\002PER-I\002PER-I\002w-B\002PER-B\002PER-I\002w-B\002PER-B\002PER-I\002PER-I\002d-B\002p-B\002v-B\002v-I\002v-B\002a-B\002m-B\002m-I\002ORG-B\002ORG-I\002ORG-I\002ORG-I\002n-B\002n-I\002c-B\002n-B\002n-I\002ORG-B\002ORG-I\002n-B\002n-I

从 数据读取源码 可以确认:load_dataset\t切分字序列与标签序列,再用CHAR_DELIMITER = "\002"拆分并断言二者长度一致;convert_example通过word.dic/tag.dic/q2b.dic三个词典完成 token→id 转换,超过max_seq_len(默认 64)的部分截断,未登录字用"OOV"替换。

词性 / 专名标签体系

文档与示例 README 给出了完整的标签集合,包含24 个词性标签(小写字母)4 个专名类别标签(大写字母)

标签含义标签含义标签含义标签含义
n普通名词f方位名词s处所名词t时间
nr人名ns地名nt机构名nw作品名
nz其他专名v普通动词vd动副词vn名动词
a形容词ad副形词an名形词d副词
m数量词q量词r代词p介词
c连词u助词xc其他虚词w标点符号
PER人名LOC地名ORG机构名TIME时间

需要注意:人名、地名、机构名、时间四类存在两套标签PER/LOC/ORG/TIMEnr/ns/nt/t)。被标注为第二套(小写)标签的词,是模型判断为低置信度的人名、地名、机构名和时间词。开发者可以基于这两套标签,在四个类别的准确率与召回率之间做出自己的权衡。

模型训练:单卡与多卡

单卡训练

在 slm/examples/lexical_analysis 目录下执行(对应 train.py):

python train.py \ --data_dir ./lexical_analysis_dataset_tiny \ --model_save_dir ./save_dir \ --epochs 10 \ --batch_size 32 \ --device gpu \ # --init_checkpoint ./save_dir/final

各参数释义如下:

  • --data_dir:数据集所在文件夹路径(需包含train.tsvtest.tsvword.dictag.dicq2b.dic);
  • --model_save_dir:训练期间模型保存路径;
  • --epochs:训练迭代轮数(默认 10);
  • --batch_size:每次迭代每张卡上的样本数目;
  • --device:训练设备,gpu表示使用 GPU,xpu表示使用百度昆仑卡,cpu表示使用 CPU(train.py 中实际限定为cpu/gpu);
  • --init_checkpoint:模型加载路径,通过设置该参数可启动增量训练。

结合训练脚本源码,还有一组常用超参数值得关注:--base_lr(基础学习率,默认 0.001,作用于全网络,优化器为 Adam)、--crf_lr(CRF 层学习率比率,默认 0.2,对应模型构造参数crf_lr=args.crf_lr)、--emb_dim(词向量维度,默认 128)、--hidden_size(GRU 隐层节点数,默认 128)、--max_seq_len(最长序列字数,默认 64)、--logging_steps(日志间隔,默认 10)、--save_steps(保存 checkpoint 间隔,默认 100)、--do_eval(是否边训练边评估,默认 True)。训练时每save_steps步保存一次model_{global_step}.pdparams,并在评估 F1 超过历史最优时额外保存best_model.pdparams

多卡训练

使用paddle.distributed.launch启动分布式训练:

python -m paddle.distributed.launch --gpus "0,1" train.py \ --data_dir ./lexical_analysis_dataset_tiny \ --model_save_dir ./save_dir \ --epochs 10 \ --batch_size 32 \ --device gpu \ # --init_checkpoint ./save_dir/final

从 train.py 可以看到多卡支持的内在逻辑:paddle.distributed.get_world_size()大于 1 时调用paddle.distributed.init_parallel_env(),使用paddle.io.DistributedBatchSampler做分布式采样,且仅rank == 0的进程执行模型保存与评估。

模型评估

通过加载训练保存的模型,对测试集进行验证(对应 eval.py):

python eval.py --data_dir ./lexical_analysis_dataset_tiny \ --init_checkpoint ./save_dir/model_100.pdparams \ --batch_size 32 \ --device gpu

其中./save_dir/model_100.pdparams是训练过程中保存的参数文件,请替换为实际得到的训练保存路径。评估基于ChunkEvaluator计算 Precision、Recall 与 F1,日志形如eval precision: 0.xx, recall: 0.xx, f1: 0.xx(具体实现见 train.py 中的evaluate函数,eval.py与其同构)。

模型导出与部署预测

动态图转静态图导出

训练结束后,可通过 export_model.py 将动态图参数导出为静态图参数:

python export_model.py --data_dir=./lexical_analysis_dataset_tiny --params_path=./save_dir/model_100.pdparams --output_path=./infer_model/static_graph_params
  • --params_path:动态图训练保存的参数路径;
  • --output_path:静态图参数导出路径。

从源码看,导出流程为:加载word.dictag.dic重建BiGruCrfpaddle.load载入权重后经paddle.jit.to_static转换,input_spec声明为[None, None]int64token_ids[None]int64length,最后paddle.jit.save保存静态图模型。

Python 部署预测

导出模型后即可用于部署,deploy/predict.py 提供了 Python 部署预测示例。

开启 PIR(PaddlePaddle 3.0.0 默认):

python deploy/predict.py --model_file=infer_model/static_graph_params.json --params_file=infer_model/static_graph_params.pdiparams --data_dir lexical_analysis_dataset_tiny

未开启 PIR:

python deploy/predict.py --model_file=infer_model/static_graph_params.pdmodel --params_file=infer_model/static_graph_params.pdiparams --data_dir lexical_analysis_dataset_tiny

模型预测

对无标签数据可启动模型预测(对应 predict.py,读取infer.tsv并输出results.txt):

python predict.py --data_dir ./lexical_analysis_dataset_tiny \ --init_checkpoint ./save_dir/model_100.pdparams \ --batch_size 32 \ --device gpu

得到类似输出:

(大学, n)(学籍, n)(证明, n)(怎么, r)(开, v) (电车, n)(的, u)(英文, nz) (什么, r)(是, v)(司法, n)(鉴定人, vn)

预测结果的组装逻辑位于 data.py 的 parse_result:将模型输出的标签 id 序列还原为标签文本后,按-B开头、O边界拼接字符还原词语,并剥离-B/-I后缀得到词性/专名主类别,最终得到(词, 标签)序列。

Taskflow 一键预测与自定义模型

开箱即用的一键调用

如果不想走完整训练链路,PaddleNLP 提供了 Taskflow 工具对输入文本进行一键分词与词性标注,用法见 LacTask 实现 中的 usage 与 示例工程 README:

from paddlenlp import Taskflow lac = Taskflow("lexical_analysis") lac("LAC是个优秀的分词工具") ''' [{'text': 'LAC是个优秀的分词工具', 'segs': ['LAC', '是', '个', '优秀', '的', '分词', '工具'], 'tags': ['nz', 'v', 'q', 'a', 'u', 'n', 'n']}] ''' lac(["LAC是个优秀的分词工具", "三亚是一个美丽的城市"]) ''' [{'text': 'LAC是个优秀的分词工具', 'segs': ['LAC', '是', '个', '优秀', '的', '分词', '工具'], 'tags': ['nz', 'v', 'q', 'a', 'u', 'n', 'n']}, {'text': '三亚是一个美丽的城市', 'segs': ['三亚', '是', '一个', '美丽', '的', '城市'], 'tags': ['LOC', 'v', 'm', 'a', 'u', 'n']} ] '''

任务默认路径为$HOME/.paddlenlp/taskflow/lexical_analysis/lac/,其中包含执行该任务所需的全部文件。从 源码 可以看到LacTaskresource_files_names声明了四个必需资源:model_state.pdparams(模型权重)、tag.dic(标签词典)、q2b.dic(全角/半角归一化词典)、word.dic(字词典),首次调用时自动下载。预处理阶段(_preprocess)会先用q2b.dic将半角字符归一为全角,再经word.dic转 id,OOV作为未登录字 id;推理时通过静态图 predictor 执行(_run_model),后处理(_postprocess)按-B/O边界还原词与标签,并支持_auto_splitter对超长文本自动切分(_max_seq_len = 512)、_auto_joiner拼接回原始输入。LacTask还支持batch_sizenum_workerssplit_sentence等 kwargs 参数。

通过 Taskflow 加载自定义模型

如果希望得到定制化的分词及标注结果,可以通过 Taskflow 加载自定义词法分析模型进行预测:用model_path指定用户自定义路径(示例 README 中写作task_path),自定义路径下的文件需与默认路径一致:

custom_task_path/ ├── model.pdparams ├── word.dic ├── tag.dic └── q2b.dic

加载并预测:

from paddlenlp import Taskflow my_lac = Taskflow("lexical_analysis", model_path="./custom_task_path/")

同时,LacTask.__init__还支持user_dict参数,配合 Customization 工具 实现用户自定义词典的强制切分(_custom.load_customization(self._user_dict)后在后处理阶段parse_customization修正切分与标注)。更多 Taskflow 用法可参考 Taskflow 文档。

预训练模型参考

如需直接使用已经预训练好的 LAC 模型完成词法分析任务,可参考 Lexical Analysis of Chinese 与 PaddleHub 分词模型(lac),而 PaddleNLP 仓库内的 Taskflowlexical_analysis任务即内置了 LAC 预训练权重(模型资源定义),开箱即用。

小结

本文以 PaddleNLP 的 Lexical Analysis 教程 为主线,完整串联了中文词法分析从任务定义、GRU+CRF 建模原理,到数据准备、标签体系、单卡/多卡训练、评估、动态图转静态图导出、部署预测、Taskflow 一键调用与自定义模型加载的端到端流程。读者既可以通过 slm/examples/lexical_analysis 示例工程从零训练自己的词法分析模型,也可以借助 Taskflow 一键预测 在几行代码内完成中文分词与词性标注,或基于自定义词典与自定义模型获得完全可控的切分与标注结果。

  • 人工智能
  • 大模型
  • NLP
  • 深度学习
  • 预训练
  • 微调
  • RLHF
  • 模型量化

【免费下载链接】PaddleNLP

Easy-to-use and powerful LLM and SLM library with awesome model zoo.

项目地址:https://gitcode.com/gh_mirrors/pa/PaddleNLP
点击查看免费下载
上一篇:3行代码实现智能检索:FlagEmbedding多模态嵌入模型实践指南
下一篇:GitHub_Trending/stoc/stock前端组件库:量化界面开发必备工具

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询