ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

OpenMed Indic 文本归一化实战:九种婆罗米系文字的确定性规范化与偏移安全重映射

OpenMed Indic 文本归一化实战:九种婆罗米系文字的确定性规范化与偏移安全重映射 OpenMed Indic 文本归一化实战九种婆罗米系文字的确定性规范化与偏移安全重映射【免费下载链接】openmedLocal-first healthcare AI: clinical NER HIPAA PII de-identification that runs 100% on-device. 2,200 medical models, 21 languages, Apple MLX Python, no cloud, no patient data leaving your network. Apache-2.0项目地址: https://gitcode.com/GitHub_Trending/ope/openmedIndicNormalizer是 OpenMed 中面向天城文Devanagari、孟加拉文Bengali/Assamese、泰米尔文Tamil、泰卢固文Telugu、卡纳达文Kannada、马拉雅拉姆文Malayalam、古吉拉特文Gujarati、古木基文Gurmukhi与奥里亚文Odia的本地化 Unicode 规范化器在临床模型推理之前将同一种书写系统的各种编码变体收敛为确定性规范形式。它在纯 Python 标准库unicodedata之上实现完全本地运行、无网络依赖并且为每一次字符变换保留原始文本偏移映射使模型输出的实体区间可以精确回溯到原始病历文本。读完本文你将掌握IndicNormalizer的全部配置选项、偏移安全重映射机制、九种脚本的底层规则表以及它在 OpenMed PII 检测管线中的实际调用方式。IndicNormalizer 的定位与适用范围IndicNormalizer处理以下九种源自婆罗米系Brahmi-derived的 Unicode 文字区块定义于 openmed/processing/text.py 的INDIC_SCRIPTS脚本名称源码常量Unicode 区块天城文DevanagariU0900–U097F孟加拉文/阿萨姆文BengaliU0980–U09FF古木基文GurmukhiU0A00–U0A7F古吉拉特文GujaratiU0A80–U0AFF奥里亚文OdiaU0B00–U0B7F泰米尔文TamilU0B80–U0BFF泰卢固文TeluguU0C00–U0C7F卡纳达文KannadaU0C80–U0CFF马拉雅拉姆文MalayalamU0D00–U0D7F从源码结构看规范化器会在内部先按脚本切分文本再对每个脚本运行段应用各自的规则表非 Indic 脚本运行段如拉丁文仅做 NFC 归一化后原样通过。这意味着它可以安全地处理多脚本混排的临床文本而不影响其他语种的内容。快速上手核心 API 与最小示例IndicNormalizer从openmed.processing包导出见 openmed/processing/init.py无需任何第三方依赖即可使用from openmed.processing import IndicNormalizer normalizer IndicNormalizer() canonical normalizer.normalize(क़ासिम और अङ्क) mapped normalizer.normalize_with_offsets(ID: ൻ രോഗി) raw_start, raw_end mapped.remap_span(4, 5)normalize(text, scriptNone)返回规范化后的字符串。当script为None时内部会调用openmed.core.script_detect.segment_by_script自动检测脚本运行段逐段规范化后拼接text.py#L474-L517也可以显式传入脚本名支持hi、bn、ta等别名见_SCRIPT_ALIASES以跳过脚本检测。normalize_with_offsets(text, scriptNone)返回一个IndicNormalization对象包含规范化文本、原始文本长度、以及每个规范化码点对应的原始字符起止偏移offset_starts/offset_ends。remap_span(start, end)把规范化文本上的半开区间[start, end)映射回原始文本的字符边界且做了越界钳制text.py#L389-L406。IndicNormalizer是可复用对象构造与规范化过程均为确定性、无状态的纯函数变换同一输入在任何环境都会得到完全相同的输出这保证了后续模型推理与审计的可复现性。默认策略一次调用完成的六类规范化默认构造IndicNormalizer()即启用以下完整策略NFC 归一化先按基字符 附加符号簇为单位做 NFC_nfc_unitstext.py#L617-L636再进入脚本规则这一步消除组合序列与预组合字符的差异。保留 nuktanukta 分解后默认不删除因为 nukta 承载音位区分见下文参数。剥离 ZWJ/ZWNJ 编码变体默认移除零宽连接符 U200D 与零宽不连接符 U200C 造成的形式差异使क्\u200dष与क्\u200cष均收敛为规范形क्ष。严格的显式鼻音簇转 anusvara形如鼻音 元音删除符virama 同组辅音的显式拼写收敛为 anusvara 记法。chandrabindu / chandra 变体归一将月亮点及其变体映射为规范 anusvara 与元音形式。词尾保持不变默认不插入显式词尾元音。测试 tests/unit/processing/test_indic_normalizer.py 验证了这些变体在规范化后产生逐字节相同的文本normalizer.normalize(ऩ) normalizer.normalize(न\u093c) # nukta 分解收敛 normalizer.normalize(अंक) normalizer.normalize(अङ्क) # 鼻音簇收敛 normalizer.normalize(क्\u200dष) normalizer.normalize(क्ष) # ZWJ 变体收敛 normalizer.normalize(क्\u200cष) normalizer.normalize(क्ष) # ZWNJ 变体收敛这套默认行为的设计意图非常明确编码变体常被用来绕过临床 PII如患者姓名的检测而规范化把这些变体统一到同一形式使检测模型只需要学习一种规范表示。五个可调选项何时开启、何时关闭构造函数签名text.py#L446-L467暴露五个关键字参数全部有安全默认值参数默认值取值说明remove_nuktasFalsebool是否在分解后删除 nukta。默认关闭因为删除会抹掉音位区分如क़与क只有下游模型明确要求时才开启nasals_modeto_anusvarapreserve/to_anusvara/to_anusvara_relaxed/to_nasal_consonants鼻音簇的收敛策略同时接受 Indic NLP Library 的旧拼写别名do_nothing、to_anusvaara_strict、to_anusvaara_relaxednormalize_chandraTruebool是否把 chandrabindu/chandra 变体映射到规范 anusvara 与元音形式设为False可保留月亮点形式normalize_vowel_endingFalsebool是否为以辅音结尾的词插入脚本对应的显式词尾。默认关闭opt-in因为这会改变词形joiner_policystripstrip/preserveZWJ/ZWNJ 处理策略。PII 推理之外若必须保留连接符区分如马拉雅拉姆文 chillu 的显式拼写可设为preserve参数校验采用fail-closed策略传入未知的nasals_mode或非法的joiner_policy会立即抛出带可选值列表的ValueError而不是静默降级text.py#L455-L463。测试 test_indic_normalizer.py 专门覆盖了这一行为。选项行为对照测试 test_indic_normalizer.py 验证default IndicNormalizer() ़ in default.normalize(क़) # 默认保留 nukta IndicNormalizer(remove_nuktasTrue).normalize(क़) क # 显式开启删除 IndicNormalizer(joiner_policypreserve).normalize(क्\u200dष) क्\u200dष IndicNormalizer(normalize_chandraFalse).normalize(अँ) अँ IndicNormalizer(nasals_modepreserve).normalize(अङ्क) अङ्क IndicNormalizer(normalize_vowel_endingTrue).normalize(नाम) नाम्偏移安全重映射审计元数据不存原文的关键机制normalize_with_offsets()的核心价值在于它为每个规范化码点返回一个原始字符区间。因此模型在规范化文本上预测出的实体区间可以通过remap_span()精确映射回原始文本而无需在审计元数据中存储原文也无需在原始文本上按字素簇grapheme cluster手工切片——后者在叠加符号复杂的婆罗米系文字中极易出错。remap_span的映射语义text.py#L389-L406区间起点映射为offset_starts[start]区间终点开区间映射为offset_ends[end - 1]对越界输入做钳制保证返回的原始区间始终合法且起点不大于终点。测试 test_indic_normalizer.py 用一个跨九种脚本的多语言句子验证了往返映射对每个原始词条先取其规范化形式在规范化文本中的位置再remap_span回原始文本结果与预期原始跨度逐一对齐。测试注释还特意说明了 Gurmukhi 附加符号 U0A71 在 UAX #29 规则下的边界行为证明偏移映射对非边界起始的复杂簇也保持正确。九种脚本的底层规则表IndicNormalizer的脚本特定规则全部以纯数据表形式内联在 text.py逐项说明如下。nukta 分解Nukta Decomposition将预组合的 nukta 字符分解为基字符 nukta序列覆盖 Devanagari11 组、Bengali3 组、Gurmukhi6 组、Odia2 组例如天城文ऩ → ऩ、क़ → क़分解后保留 nukta除非显式开启删除。源码中另有_NUKTA_OFFSETS表记录各脚本 nukta 的块内偏移均为0x3C供删除操作定位。鼻音与 chandra 归一_normalize_chandras按脚本块基址 块内偏移定义六组替换text.py#L720-L741将 chandrabindu/chandra 变体映射为规范 anusvara 与元音。_normalize_nasals实现了三种模式text.py#L744-L814to_anusvara仅当鼻音 virama 同组辅音严格匹配签名表时才收敛为 anusvarato_anusvara_relaxed不要求后续辅音在签名范围内直接收敛to_nasal_consonants反向把 anusvara 展开为对应鼻音 virama。显式鼻音簇与序列替换_SEQUENCE_REPLACEMENTS针对各脚本的双部件元音符号与旧式拼写进行替换例如Gurmukhiਅਾ → ਆ、ਅੈ → ਐ等 8 组含 addak 相关收敛Odiaଅା → ଆ、ଏୗ → ଐ等 9 组Bengaliো → ো、ৌ → ৌ等 4 组Tamilொ → ொ、ோ → ோ、ௌ → ௌ等 7 组Teluguై → ై等 2 组Kannadaೀ → ೀ、ೇ → ೇ、ೈ → ೈ等 10 组Malayalamൊ → ൊ、ോ → ോ、ൌ → ൗ及独立ൗ → ൗ共 7 组。马拉雅拉姆文 chillu_MALAYALAM_CHILLUStext.py#L324-L331把显式辅音 virama ZWJ序列收敛为预组合的 chillu 字符如ന്\u200d → ൻ、ര്\u200d → ർ。注意该项处理发生在 joiner 剥离之前因此即便joiner_policystripchillu 也能先收敛为单字符。Gurmukhi addak / tippi 与元音基座_canonicalize_gurmukhi_addaktext.py#L697-L717将ਅੱਕ → ਅੱਕ之类的 addakU0A71后跟辅音的模式改写为辅音 virama 辅音的规范拼写同时ਁtippi映射为 anusvaraਂ。_SEQUENCE_REPLACEMENTS中还有针对ੲ/ੳ等独立元音基座的组合替换。Odia 的 va/v 映射Odia 规则把ଵU0B35与ଵ的变体ୱU0B71统一替换为ବtext.py#L562-L565测试中以ଵ → ବ验证test_indic_normalizer.py#L100。标点与 virama 归一poorna virama将各脚本块内专用的句号字符映射为天城文।U0964与॥U0965例如 Bengali৴→।、Tamil௔→।同时各脚本的 ASCII 竖线|统一替换为।text.py#L579-L593。冒号转 visarga当冒号:出现在脚本块字符之后时替换为该脚本的 visarga如天城文ः、孟加拉文ঃ测试以নাম: → নামঃ验证text.py#L817-L830。词尾元音仅normalize_vowel_endingTrue对以辅音块内偏移 0x15–0x39结尾且后随空白或文本结尾的词追加脚本对应的词尾——达罗毗荼系脚本泰米尔、泰卢固、卡纳达、马拉雅拉姆追加ಾ0x3E其余脚本追加 viramatext.py#L833-L849。与 PII 检测管线的集成方式IndicNormalizer并非孤立工具而是 OpenMed 对抗性 Unicode 防御的一部分。在 openmed/core/script_detect.py 的_normalize_unicode_for_pii_detection中先按脚本切分文本对落在INDIC_SCRIPTS的运行段调用indic_normalizer.normalize_with_offsets(run, scriptscript)将规范化输出的偏移累加回全文本坐标随后依次执行宽度折叠normalize_width、Indic 数字折叠fold_indic_digits、剥离独立组合标记等步骤全部结果汇总到DetectionNormalization对象script_detect.py#L567-L616其remap_span与indic_changes、indic_scripts等字段供 PII 检测与审计使用。DetectionNormalization同样被 openmed/core/pii.py 引用作为实体解码与区间回溯的契约见 openmed/core/decoding/spans.py 对normalization字段的说明。也就是说Indic 规范化产出的偏移映射会一路贯穿到模型预测的 span 解码层保证脱敏区间落在原始病历的精确位置。此外对于历史遗留的 ISCII-1991 编码或视觉序visual-order旧字体文本openmed.processing.text还提供了normalize_indic_text()text.py#L882-L999它只做天城文前置元音ि的重排与 nukta/virama 顺序修正不做IndicNormalizer的广泛拼写规范化从而保证 ISCII 往返字节一致该函数与convert_legacy_encoding见 openmed/processing/legacy_encoding.py组合后可把旧编码文本先转换再送入检测管线偏移经DetectionNormalization重新合成回原始字节坐标script_detect.py#L1410-L1459。安全性设计两个刻意为之的差异与上游 Indic NLP Library 相比OpenMed 在两个安全领域刻意不同docs/indic-normalization.md默认绝不删除脚本承载字符。所有规则要么保留原字符要么替换为规范的脚本内等价字符没有任何默认规则会把承载字母/符号的码点丢弃成空。测试 test_indic_normalizer.py 遍历九个脚本区块的全部字母类与标记类码点逐一验证规范化后输出非空且仍落在脚本区块内。每一次变换都携带原始偏移溯源。IndicNormalization的changes、removed_joiners计数与逐码点偏移表使临床脱敏可审计——这正是文档所称无需在审计元数据中存储文本的工程基础。同时规范化是幂等的测试验证对多脚本文本规范化两次结果一致test_indic_normalizer.py#L24-L34意味着重复调用不会引入新的差异适合在批处理与流式管线中安全复用。规则与许可溯源IndicNormalizer的脚本规则行为以 Anoop Kunchukuttan 发布的Indic NLP Library归一化器为建模参考该上游项目采用MIT License。OpenMed 对其中的 nukta 分解、鼻音与 chandra 归一、双部件元音符号、标点、马拉雅拉姆 chillu、Gurmukhi addak/tippi 与元音基座、Odia 元音/va 映射等独立实现了紧凑的纯数据等价表且不复制、不捆绑上游包体、上游资源或任何第三方模型权重源码注释见text.py#L256-L258。因此该模块可以安心用于本地化、离线、可审计的临床 PII 脱敏部署无额外许可负担。【免费下载链接】openmedLocal-first healthcare AI: clinical NER HIPAA PII de-identification that runs 100% on-device. 2,200 medical models, 21 languages, Apple MLX Python, no cloud, no patient data leaving your network. Apache-2.0项目地址: https://gitcode.com/GitHub_Trending/ope/openmed创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表