资讯动态

CCKS2017电子病历NER实战:数据清洗、BiLSTM-CRF实现与医疗实体识别

发布时间:2026/10/25 6:44:40 来源:尧图企业网站定制
简介本资源是面向自然语言处理初学者与竞赛参赛者的CCKS2017中文电子病历命名实体识别完整实践项目聚焦医疗文本中“一般情况、出院情况、病史特点、诊疗经过”等关键实体的序列标注任务。项目基于字向量构建四层双向LSTM-CRF模型提供从原始XML/文本数据清洗、BiLSTMCRF训练脚本、预训练模型.h5、词向量文件.bin到预测推理的全流程代码与配套说明适合NLP进阶学习与医疗AI方向快速复现。压缩包共14个文件含3个核心Python脚本训练/转换/预测、3个原始txt/xml数据样本、1个README.md文档、1个300维token向量文件及模型权重等整体37.02MB结构紧凑、模块职责明确。已有1857人学习下载读者可直接运行训练流程、加载预训练模型进行实体识别推断并参考数据转换逻辑与目录组织方式深入理解医疗NER任务的数据建模思路。1. 为什么 CCKS2017 电子病历 NER 项目至今仍是中文医疗 NLP 的「入门必过关卡」不是因为它的模型有多先进——2017 年的 BiLSTM-CRF 在今天看早已不算新而是因为它用最朴素的方式把中文临床文本里那些「医生写得随意、系统录得混乱、术语边界模糊」的真实痛点全打碎摊在你面前主诉里混着「否认高血压病史」和「否认高血压、糖尿病史」前者是单实体后者是两个并列实体但标注规则要求拆成两个 BIO 标签「左肺下叶见磨玻璃影」中「左肺下叶」是解剖部位「磨玻璃影」是影像学术语二者在 CCKS2017 官方定义里属于不同类别ANAT vs. DISO但字面紧贴、无标点分隔更致命的是原始数据里大量手写转录错误「心电图示 ST 段压低」被录成「心电图示 ST 段压氏」「压氏」不是词典词也不是 OOV 词而是错别字——模型没见过标注也没修正。这个项目不教你怎么调大模型它逼你亲手清洗 3247 条真实门诊记录、重跑 BIO 标签校验脚本、手动比对 17 类实体在《医学名词》第三版里的标准命名、反复调整 CRF 解码约束条件。它筛掉的不是代码能力差的人而是没耐心面对「临床语言混沌性」的人。如果你正打算做医保审核、病历质控、慢病随访系统CCKS2017 不是历史资料是你必须亲手跑通的第一块「临床语义地砖」。2. 从原始数据到可训练 BIO 数据集三步清洗与四类边界陷阱CCKS2017 官方发布的电子病历数据train.txt / dev.txt / test.txt表面是纯文本实则暗藏四层结构污染字符编码错乱、实体嵌套冲突、标注粒度不一致、空格/换行语义丢失。直接喂给模型90% 的 F1 值会卡在 6265 区间且验证集波动极大。我一般会用以下三步流程重建数据流每步都附带可复现的 Python 脚本逻辑。2.1 第一步统一编码 清除不可见控制符不是简单 open(..., encodingutf-8) 就完事原始 train.txt 中约 12.7% 的样本含\x00、\x0b、\x1c等控制字符它们在 Windows 记事本里显示为空白但在jieba分词或torch加载时会触发UnicodeDecodeError或导致 token 对齐偏移。更隐蔽的是\u200b零宽空格和\u2028行分隔符它们会让 BIO 标签序列长度与字符序列长度不等。# clean_encoding.py import re def clean_control_chars(text: str) - str: # 移除所有 C0/C1 控制字符U0000–U001F 和 U007F–U009F text re.sub(r[\x00-\x08\x0b\x0c\x0e-\x1f\x7f-\x9f], , text) # 替换零宽字符为普通空格保留语义空格 text re.sub(r[\u200b\u200c\u200d\u2060\ufeff], , text) # 统一换行符为 \nWindows \r\n → \nMac \r → \n text re.sub(r\r\n|\r, \n, text) return text.strip() # 示例处理单个样本 with open(raw/train.txt, rb) as f: raw_bytes f.read() try: text raw_bytes.decode(utf-8) except UnicodeDecodeError: text raw_bytes.decode(gb18030, errorsreplace) # CCKS2017 实际多用 GB18030 cleaned clean_control_chars(text)参数说明errorsreplace是关键——GB18030 编码下部分病历含未定义字节如手写扫描 OCR 错误用ignore会丢字符用replace生成 后续清洗可定位clean_control_chars()中正则范围覆盖全部 C0/C1 控制区比string.printable更彻底零宽字符替换为 而非避免相邻汉字粘连如「左\u200b肺」→「左 肺」空格可被 tokenizer 识别为分隔。2.2 第二步BIO 标签校验与修复官方标注存在 3.2% 的非法 BIO 序列CCKS2017 的 BIO 标注规范要求B-X后必须接I-X或O不能接B-Y除非 X≠YI-X前必须是B-X或I-X不能是O或B-YY≠X实体不能跨行即\n前后不能同属一个实体。但原始数据中存在O B-DISO I-DISO B-ANAT这类非法序列B-ANAT前是I-DISO应为O以及跨行实体如「左肺\n下叶」被标为B-ANAT I-ANAT。这类错误会导致 CRF 层训练时梯度爆炸验证 loss 波动超 ±0.8。# bio_validator.py from typing import List, Tuple def validate_bio_sequence(tokens: List[str], labels: List[str]) - Tuple[bool, str]: 返回 (是否合法, 错误描述) if not labels: return True, for i, (tok, lbl) in enumerate(zip(tokens, labels)): if lbl O: continue elif lbl.startswith(B-): # 检查 B 后是否为同类型 I 或 O if i 1 len(labels): next_lbl labels[i 1] if next_lbl ! O and not next_lbl.startswith(I- lbl[2:]): return False, f位置 {i}: B-{lbl[2:]} 后接 {next_lbl}应为 O 或 I-{lbl[2:]} elif lbl.startswith(I-): # 检查 I 前是否为同类型 B 或 I if i 0 or (not labels[i-1].startswith(B- lbl[2:]) and not labels[i-1].startswith(I- lbl[2:])): return False, f位置 {i}: I-{lbl[2:]} 前无同类型 B/I前标签为 {labels[i-1]} # 检查跨行 for i, tok in enumerate(tokens): if tok \n and i 0 and i len(labels)-1: prev_lbl labels[i-1] next_lbl labels[i1] if prev_lbl.startswith(B-) or prev_lbl.startswith(I-): if next_lbl.startswith(I- prev_lbl[2:]) or next_lbl.startswith(B- prev_lbl[2:]): return False, f位置 {i}: 换行符前后同属实体 {prev_lbl[2:]} return True, # 批量修复对非法序列将后续非法 I/X 强制改为 O def repair_bio_sequence(tokens: List[str], labels: List[str]) - List[str]: repaired labels.copy() for i in range(1, len(labels)): if labels[i].startswith(I-) and not (labels[i-1].startswith(B- labels[i][2:]) or labels[i-1].startswith(I- labels[i][2:])): repaired[i] O return repaired逻辑说明validate_bio_sequence()不仅检查标签合法性还定位具体位置和错误类型便于人工复核repair_bio_sequence()采用「保守修复」策略——只改非法I-X为O不改动B-X因为B-X错误往往意味着实体漏标需人工确认实际运行中3247 条训练样本经此校验发现 107 处非法序列其中 89 处为跨行错误集中在「胸片示右肺上叶见结节影」这类多行报告中。2.3 第三步构建最终 BIO 数据集按字符级而非词级切分CCKS2017 官方未提供分词信息且临床文本中「急性心肌梗死」不能拆成「急性/心肌/梗死」——「心肌梗死」是完整疾病名「急性」是修饰词。因此必须采用字符级 BIO 标注每个汉字/标点对应一个标签。但原始数据中存在大量全角空格、中文顿号「、」、破折号「——」它们既非实体成分也不该被忽略否则影响上下文建模。# build_char_bio.py import json def build_char_bio_dataset(raw_lines: List[str]) - List[dict]: 输入原始 train.txt 每行格式文本\t标签序列 dataset [] for line_num, line in enumerate(raw_lines): if not line.strip(): continue try: text, label_seq line.strip().split(\t) # 清洗文本 text clean_control_chars(text) # 拆分为字符列表保留所有 Unicode 字符包括标点 chars list(text) # 标签序列转为列表如 B-DISO I-DISO O O B-ANAT → [B-DISO,I-DISO,O,O,B-ANAT] labels label_seq.split() # 长度校验 if len(chars) ! len(labels): # 常见原因text 含不可见字符未被 clean_control_chars 清除 # 此处强制截断或补 O选补 O因缺失标签更可能是噪声 if len(chars) len(labels): labels.extend([O] * (len(chars) - len(labels))) else: labels labels[:len(chars)] dataset.append({ id: ftrain_{line_num}, chars: chars, labels: labels }) except Exception as e: print(f第 {line_num} 行解析失败: {e}) continue return dataset # 保存为 JSONL每行一个样本兼容 HuggingFace Datasets with open(processed/train.jsonl, w, encodingutf-8) as f: for sample in build_char_bio_dataset(train_lines): f.write(json.dumps(sample, ensure_asciiFalse) \n)参数说明chars list(text)是核心——它确保每个 Unicode 码位独立成 token避免jieba等分词器将「冠状动脉」错误切分为「冠/状/动/脉」ensure_asciiFalse保证中文不转义JSONL 格式比 CSV 更稳定尤其当文本含制表符\t时CCKS2017 原始数据中确有此类情况长度不匹配时优先补O因为缺失标签大概率是标注遗漏而非实体延伸。3. BiLSTM-CRF 模型实现从 PyTorch 零开始搭建避开三个「玄学」收敛陷阱CCKS2017 官方 baseline 是 BiLSTM-CRF不是因为它是 SOTA而是它足够轻量、可解释性强、且能显式建模标签转移约束。但直接照搬经典实现如 pytorch-crf 库常遇到loss 不降、F1 卡在 50%、验证集指标剧烈震荡。根本原因在于医疗文本的三大特性未被适配长尾实体分布、低频字占比高、句长方差极大主诉 20 字入院记录 500 字。以下是我调试出的稳定版本。3.1 字符嵌入层融合字形与拼音的双通道初始化CCKS2017 中「痫」「癜」「癍」等生僻字出现频次 3单纯用随机初始化 embedding模型无法学到其语义。而「痫」与「闲」同音、「癜」与「店」同音拼音提供了强先验。我们用pypinyin提取拼音首字母如「痫」→x「癜」→d构建 26 维 one-hot 拼音 embedding与 100 维随机字向量拼接。# model/embedding.py import torch import torch.nn as nn from pypinyin import lazy_pinyin, Style class CharEmbedding(nn.Module): def __init__(self, vocab_size: int, char_dim: int 100, pinyin_dim: int 26): super().__init__() self.char_emb nn.Embedding(vocab_size, char_dim, padding_idx0) self.pinyin_emb nn.Embedding(pinyin_dim, 20) # 拼音 embedding 维度设为 20 self.proj nn.Linear(char_dim 20, char_dim) # 投影回原维度 # 初始化字向量用 Xavier拼音向量用常数避免过拟合 nn.init.xavier_uniform_(self.char_emb.weight) nn.init.constant_(self.pinyin_emb.weight, 0.01) def forward(self, chars: torch.LongTensor) - torch.Tensor: # chars: [batch, seq_len] char_vecs self.char_emb(chars) # [batch, seq_len, char_dim] # 动态计算拼音索引避免预存大字典 pinyin_ids [] for batch_i in range(chars.size(0)): sent_chars [chr(c.item()) for c in chars[batch_i] if c.item() ! 0] pinyin_seq lazy_pinyin(.join(sent_chars), styleStyle.FIRST_LETTER) # 映射 a-z → 0-25其他如声调符号→ 26unk ids [ord(p.lower()) - ord(a) if a p.lower() z else 26 for p in pinyin_seq] # 补零至与 chars 同长 ids [26] * (chars.size(1) - len(ids)) pinyin_ids.append(ids) pinyin_tensor torch.tensor(pinyin_ids, devicechars.device) pinyin_vecs self.pinyin_emb(pinyin_tensor) # [batch, seq_len, 20] fused torch.cat([char_vecs, pinyin_vecs], dim-1) # [batch, seq_len, char_dim20] return self.proj(fused) # [batch, seq_len, char_dim] # 使用示例 embedding CharEmbedding(vocab_size5000) # 输入字符 ID 张量shape [32, 128] char_ids torch.randint(0, 5000, (32, 128)) emb_out embedding(char_ids) # shape [32, 128, 100]参数说明Style.FIRST_LETTER只取拼音首字母规避多音字问题如「行」可读 xíng/háng但首字母都是 xpinyin_emb维度设为 20远小于char_dim防止拼音信息主导nn.init.constant_初始化为小常数避免拼音 embedding 初始值过大干扰字向量学习proj层保证输出维度与原char_dim一致无缝接入下游 BiLSTM。3.2 BiLSTM 层动态 batch padding 与梯度裁剪阈值重设CCKS2017 样本长度从 15 到 482 不等。若用固定max_len512paddingbatch 内 90% 位置是PADBiLSTM 计算大量冗余。我们改用torch.nn.utils.rnn.pad_sequence动态 padding并用pack_padded_sequence剔除 padding 位置的计算。# model/bilstm.py from torch.nn.utils.rnn import pack_padded_sequence, pad_packed_sequence class BiLSTM(nn.Module): def __init__(self, input_dim: int, hidden_dim: int 256, num_layers: int 2, dropout: float 0.3): super().__init__() self.lstm nn.LSTM( input_sizeinput_dim, hidden_sizehidden_dim, num_layersnum_layers, batch_firstTrue, bidirectionalTrue, dropoutdropout if num_layers 1 else 0 ) self.dropout nn.Dropout(dropout) def forward(self, x: torch.Tensor, lengths: torch.LongTensor) - torch.Tensor: # x: [batch, seq_len, input_dim], lengths: [batch] packed pack_padded_sequence(x, lengths, batch_firstTrue, enforce_sortedFalse) lstm_out, _ self.lstm(packed) unpacked, _ pad_packed_sequence(lstm_out, batch_firstTrue) return self.dropout(unpacked) # [batch, seq_len, 2*hidden_dim] # 训练时调用 lengths torch.tensor([len(sample[chars]) for sample in batch], devicedevice) lstm_out bilstm(embedded, lengths) # 自动跳过 padding 位置逻辑说明enforce_sortedFalse允许 batch 内样本按长度乱序避免预排序开销dropout仅在num_layers 1时启用因单层 LSTM dropout 会破坏时序依赖lengths必须是torch.LongTensor且在 GPU 上否则pack_padded_sequence报错实测此设置使单 batch 训练时间下降 37%且梯度更稳定。3.3 CRF 层自定义转移矩阵约束强制满足临床实体逻辑CCKS2017 的 17 类实体中SYMPTOM症状和DISEASE疾病常共现如「发热、咳嗽」但ANAT解剖部位与TREATMENT治疗绝不会相邻如「肺」后不可能接「手术」。我们在 CRF 的转移矩阵transitions中将非法转移设为-10000趋近负无穷使 Viterbi 解码时自动规避。# model/crf.py class CRF(nn.Module): def __init__(self, num_tags: int, constraints: List[Tuple[int, int]] None): super().__init__() self.num_tags num_tags # transitions[i][j] score of transitioning from tag i to tag j self.transitions nn.Parameter(torch.randn(num_tags, num_tags)) self.start_transitions nn.Parameter(torch.randn(num_tags)) self.end_transitions nn.Parameter(torch.randn(num_tags)) # 应用约束将非法转移置为极小值 if constraints: for from_tag, to_tag in constraints: self.transitions.data[from_tag, to_tag] -10000. def forward(self, emissions: torch.Tensor, tags: torch.LongTensor, mask: torch.ByteTensor) - torch.Tensor: # ... 标准 CRF loss 计算 ... pass # CCKS2017 实体约束部分 # ANAT → TREATMENT, TREATMENT → ANAT, TEST → SYMPTOM 等均为非法 constraints [ (ANAT_TAG, TREATMENT_TAG), # 解剖部位后不能接治疗 (TREATMENT_TAG, ANAT_TAG), # 治疗后不能接解剖部位 (TEST_TAG, SYMPTOM_TAG), # 检查后不能接症状应为「检查结果」 (DRUG_TAG, DISEASE_TAG), # 药物后不能接疾病应为「用于治疗XXX」 ] crf CRF(num_tags18, constraintsconstraints) # 17 类 O参数说明constraints列表需根据 CCKS2017 官方《实体定义说明书》手工整理共 23 对非法转移-10000.是经验值太小如-1e8会导致 loss 计算 underflow太大如-100约束力不足start_transitions和end_transitions不加约束因首尾标签自由度更高。4. 训练与评估避开四个「血泪经验」坑让 F1 稳定突破 82.5即使数据清洗干净、模型结构正确CCKS2017 项目仍常因训练细节翻车验证 F1 在 7881 间震荡、测试集结果比验证集低 5 个点、相同代码在不同 GPU 上结果差异超 2%。以下是我在 12 次完整训练中总结的四大避坑点。4.1 学习率调度器必须用「线性预热 余弦退火」禁用 StepLRCCKS2017 的实体分布极不均衡DISEASE出现 1247 次EXAMINATION仅 89 次。StepLR 在固定 epoch 降低 lr易导致小样本类别在后期学习停滞。实测get_linear_schedule_with_warmupHuggingFace 版配合余弦退火F1 提升 1.8%。# train.py from transformers import get_linear_schedule_with_warmup # warmup_steps 设为总 step 的 10% total_steps len(train_dataloader) * num_epochs warmup_steps int(0.1 * total_steps) scheduler get_linear_schedule_with_warmup( optimizer, num_warmup_stepswarmup_steps, num_training_stepstotal_steps ) # 自定义余弦退火在 warmup 后生效 def cosine_lr_scheduler(optimizer, epoch, total_epochs): if epoch warmup_steps // len(train_dataloader): return 1.0 progress (epoch - warmup_steps // len(train_dataloader)) / (total_epochs - warmup_steps // len(train_dataloader)) return 0.5 * (1.0 math.cos(math.pi * progress)) # 训练循环中 for epoch in range(num_epochs): for batch in train_dataloader: # ... 训练步骤 ... scheduler.step() # 注意此处用 transformers 的 scheduler.step() # 若用自定义余弦需在 epoch 级调用现象 → 原因 → 解决现象用StepLR(gamma0.5)时EXAMINATION类召回率始终低于 40%且验证 loss 在 epoch 15 后不再下降原因StepLR 在 epoch 10 降 lr此时小样本类别尚未充分学习lr 过早衰减导致梯度更新幅度过小解决get_linear_schedule_with_warmup前 10% step 缓慢提升 lr让模型先建立基础特征再用余弦退火平滑下降保证小样本持续优化。4.2 验证集必须按「实体级别」而非「token 级别」计算 F1且忽略O类CCKS2017 官方评测脚本eval.py计算的是实体级 micro-F1将预测实体与真实实体按 span 和 type 完全匹配才计为 TP。若用 sklearn 的classification_reporttoken 级F1 会虚高 57 个点且无法反映真实业务效果医生关心「是否识别出『左心室肥厚』这个完整实体」而非「每个字标对没」。# eval/entity_f1.py def compute_entity_f1(pred_labels: List[List[str]], true_labels: List[List[str]]) - dict: pred_labels: [[B-DISO,I-DISO,O,...], ...] tp, fp, fn 0, 0, 0 for pred_seq, true_seq in zip(pred_labels, true_labels): pred_entities extract_entities(pred_seq) true_entities extract_entities(true_seq) # 实体匹配span 和 type 完全相同 matched set() for p_ent in pred_entities: for t_ent in true_entities: if p_ent t_ent and t_ent not in matched: tp 1 matched.add(t_ent) break else: fp 1 for t_ent in true_entities: if t_ent not in matched: fn 1 precision tp / (tp fp) if tp fp 0 else 0 recall tp / (tp fn) if tp fn 0 else 0 f1 2 * precision * recall / (precision recall) if precision recall 0 else 0 return {precision: precision, recall: recall, f1: f1} def extract_entities(labels: List[str]) - List[tuple]: 返回 [(start, end, type), ...] entities [] i 0 while i len(labels): if labels[i].startswith(B-): ent_type labels[i][2:] start i i 1 while i len(labels) and labels[i] fI-{ent_type}: i 1 entities.append((start, i, ent_type)) else: i 1 return entities现象 → 原因 → 解决现象sklearnf1_score(y_true, y_pred, averagemacro)得到 85.2但提交官网评测得 79.6原因token 级计算将B-DISO I-DISO中一个字标错就判整个实体错而实体级要求 span 完全匹配解决严格按extract_entities()提取 spancompute_entity_f1()仅统计实体匹配数与官网eval.py逻辑一致。4.3 测试集预测必须用「滑动窗口」处理长文本禁用简单 truncationCCKS2017 测试集含多条超长病历最长 482 字而 BiLSTM-CRF 最大输入长度通常设为 128。若直接截断前 128 字会丢失「诊断XXX」等关键结尾信息。我们用 64 字重叠的滑动窗口对每个窗口独立预测再合并结果。# predict/sliding_window.py def sliding_window_predict(model, text: str, window_size: int 128, overlap: int 64) - List[str]: chars list(text) if len(chars) window_size: return model.predict([chars]) all_preds [] start 0 while start len(chars): end min(start window_size, len(chars)) window_chars chars[start:end] pred_labels model.predict([window_chars])[0] # [seq_len] # 仅保留非重叠区域的预测避免重复投票 if start 0: all_preds.extend(pred_labels) else: # 重叠区取后半段预测更准确 valid_start max(0, overlap - (end - start)) all_preds.extend(pred_labels[valid_start:]) start window_size - overlap return all_preds[:len(chars)] # 截断至原文长度 # 使用 test_text 患者男65岁……482字 pred_bio sliding_window_predict(model, test_text)现象 → 原因 → 解决现象直接text[:128]预测测试集 F1 仅 76.3且DIAGNOSIS类召回率为 0原因诊断结论常在文末截断后丢失解决滑动窗口保证每个字符至少被覆盖一次重叠区取后半段预测因模型对窗口后部 context 更敏感实测提升DIAGNOSIS召回率至 89.2%。4.4 随机种子必须固定五处否则结果不可复现PyTorch 默认随机性涉及多个源头Pythonrandom、NumPy、CUDA、CuDNN、PyTorch 自身。CCKS2017 因数据量小3k 样本微小随机差异会被放大。# utils/seed.py import random import numpy as np import torch def set_seed(seed: int 42): random.seed(seed) np.random.seed(seed) torch.manual_seed(seed) if torch.cuda.is_available(): torch.cuda.manual_seed_all(seed) # 启用确定性算法牺牲速度保证可复现 torch.backends.cudnn.deterministic True torch.backends.cudnn.benchmark False # 在 train.py 开头调用 set_seed(42)现象 → 原因 → 解决现象相同代码、相同数据在 A100 和 V100 上 F1 相差 1.2%且多次运行结果标准差达 0.8原因CuDNN 的 auto-tuner 在不同 GPU 上选择不同卷积算法导致数值微小差异累积解决torch.backends.cudnn.deterministic True强制使用确定性算法benchmark False关闭 auto-tuner虽慢 15%但结果绝对一致。5. 模型部署与业务落地用 ONNX TensorRT 加速推理单条病历耗时压至 320ms训练好的 BiLSTM-CRF 模型在 CPU 上推理一条 200 字病历需 1.8 秒无法满足线上实时质控需求要求 500ms。我们通过 ONNX 导出 TensorRT 优化将延迟压至 320msT4 GPU且支持批量推理batch_size8 时吞吐达 25 QPS。5.1 导出为 ONNX处理 CRF 层的动态解码问题PyTorch 的 CRF 层含viterbi_decode其torch.max操作在 ONNX 中需指定keepdimTrue否则导出失败。我们封装一个CRFWrapper将解码逻辑移至 forward 外部。# deploy/export_onnx.py import torch.onnx class CRFWrapper(nn.Module): def __init__(self, crf_model): super().__init__() self.crf crf_model def forward(self, emissions: torch.Tensor, mask: torch.BoolTensor): # 仅返回 emissionsCRF 解码在 ONNX 外部进行 return emissions # 导出 BiLSTM 部分不含 CRF 解码 model.eval() dummy_input torch.randint(0, 5000, (1, 128)).to(device) dummy_mask torch.ones(1, 128, dtypetorch.bool).to(device) torch.onnx.export( model.bilstm, # 仅导出 BiLSTM (dummy_input, dummy_mask), bilstm.onnx, input_names[input_ids, attention_mask], output_names[emissions], dynamic_axes{ input_ids: {0: batch, 1: seq}, attention_mask: {0: batch, 1: seq}, emissions: {0: batch, 1: seq} }, opset_version12 )逻辑说明ONNX 不支持 CRF 的 Viterbi 动态规划故只导出 BiLSTM 输出emissionsdynamic_axes声明 batch 和 seq 维度可变为 TensorRT 的动态 shape 支持铺路opset_version12兼容 TensorRT 7.2避免高版本 op 不支持。5.2 TensorRT 优化配置 profile 与精度模式T4 GPU 上FP16 模式比 FP32 快 2.1 倍且 CCKS2017 的 17 类实体对精度不敏感FP16 下 F1 仅降 0.03%。# deploy/tensorrt_engine.py import tensorrt as trt def build_engine(onnx_file_path: str, engine_file_path: str, fp16_mode: bool True): logger trt.Logger(trt.Logger.WARNING) builder trt.Builder(logger) network builder.create_network(1 int(trt.NetworkDefinitionCreationFlag.EXPLICIT_BATCH)) parser trt.OnnxParser(network, logger) with open(onnx_file_path, rb) as model: parser.parse(model.read()) config builder.create_builder_config() config.max_workspace_size 1 30 # 1GB if fp16_mode: config.set_flag(trt.BuilderFlag.FP16) # 设置优化 profile适配 6 p a hrefhttps://download.csdn.net/download/qq_41934573/19407692 stylecolor:#ec7500;font-size:14px; 本文还有配套的精品资源点击获取 /a img altmenu-r.4af5f7ec.gif srchttps://csdnimg.cn/release/wenkucmsfe/public/img/menu-r.4af5f7ec.gif stylewidth:16px;margin-left:4px;vertical-align:text-bottom;cursor:text; /p

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑