跳到主要内容

文本分词器模块

文本分词器模块负责把字符串转换成模型可用的 token ID 序列。
这层只做分词、编码与反向解码,不负责模型推理。典型流程是先把文本编码成 MLMultiArrayonnxruntime.tensor,再把编码结果传给对应的 CoreML 或 ONNX Runtime 推理器。

当前这套模块的目标是“端侧推理够用”:

  • WordPiece 兼容度最高,适合 BERTCN-CLIP 一类模型
  • BPESentencePiece 采用轻量兼容策略,适合多数端侧编码场景
  • 不把复杂分词器训练、采样或完整上游生态行为搬到运行时里

该模块在 20260319 以后版本方可使用

创建分词器

coreml.new_text_tokenizer(opts)

文本分词器对象, 错误信息 = coreml.new_text_tokenizer({
type = 分词器类型,
vocab_path = 词表路径,
merges_path = merges 文件路径,
model_path = SentencePiece 模型路径,
pattern = 正则表达式,
context_length = 上下文长度,
do_lower_case = 是否转小写,
vocab_limit = 词表上限,
clean_text = 是否先清洗文本,
add_bos = 是否添加起始 token,
add_eos = 是否添加结束 token,
bos_token = 起始 token 文本,
eos_token = 结束 token 文本,
pad_token = 填充 token 文本,
unk_token = 未知 token 文本,
})

type 取值

  • wordpiece / bert / cn_clip
  • bpe / gpt2_bpe / clip_bpe
  • sentencepiece / spm
  • regex / pattern
  • byte / bytes
  • whitespace / space
  • character / char

默认 wordpiece

如果 coreml.new_text_tokenizer(...) 的第一个参数不是 table,会直接按 wordpiece 快捷构造处理,也就是等价于 coreml.new_wordpiece_tokenizer(vocab_path) 这类用法。

常用参数

  • vocab_path
    文本型,词表文件路径。

  • merges_path
    文本型,BPE 系分词器使用的 merges 文件路径。

  • model_path
    文本型,SentencePiece 兼容模式可使用的 .model 文件路径。

  • pattern
    文本型,Regex 分词器使用的正则表达式。

  • context_length
    整数型,可选参数,输出 token 序列长度。

  • do_lower_case
    布尔型,可选参数,是否先转小写。

  • vocab_limit
    整数型,可选参数,仅 WordPiece 常用,用于限制词表上限。

  • clean_text
    布尔型,可选参数,是否在分词前先做基础文本清洗。

  • add_bos / add_eos
    布尔型,可选参数,是否在编码结果前后附加起始 / 结束 token。

  • bos_token / eos_token / pad_token / unk_token
    文本型,可选参数,对应特殊 token 在词表中的文本。

不是所有分词器类型都支持上面所有字段。当前实现的必填项与默认值如下:

  • wordpiece 支持直接传 vocab_path 字符串,或传 table;要求 vocab_path 存在;默认 context_length = 52do_lower_case = truevocab_limit = 21128,并要求词表里存在 [PAD][UNK][CLS][SEP]
  • bpe 只接受 table;要求 vocab_pathmerges_path;默认 context_length = 77do_lower_case = falseclean_text = falseadd_bos = falseadd_eos = false
  • sentencepiece 只接受 table;要求 vocab_pathmodel_path 至少一个;默认 context_length = 77do_lower_case = falseclean_text = truebos_token = "<s>"eos_token = "</s>"pad_token = "<pad>"unk_token = "<unk>"
  • regex 只接受 table;要求 vocab_pathpattern;默认 context_length = 77do_lower_case = falseclean_text = true
  • whitespace / character / byte 只接受 table;要求 vocab_path;默认 context_length = 77do_lower_case = falseclean_text = true

选择建议:

  • 已知模型使用 vocab.txt + WordPiece,就选 wordpiece
  • 已知模型使用 vocab.json + merges.txt,就选 bpe
  • 已知模型使用 .vocab.model,就选 sentencepiece
  • 只有简单规则切词需求时,再考虑 regexwhitespacecharacterbyte

返回值

  • 文本分词器对象
    对象型,创建失败返回 nil

  • 错误信息
    文本型,成功时为 nil,失败时返回错误信息。

说明

  • 分词器对象适合创建一次后复用,不建议每次编码都重新构造
  • 创建阶段主要决定三件事:分词算法、词表来源、固定输出长度
  • 如果模型效果明显不对,优先检查分词器类型、词表文件、special token 配置和 context_length 是否与训练时一致
  • WordPiece 是当前最完整、最稳的一类
  • BPESentencePiece 以端侧编码兼容为目标,不承诺复刻所有上游实现的全部细节

快捷构造器

以下快捷函数本质上都是对 coreml.new_text_tokenizer(...) 的转发,适合在你已经确定分词器类型时直接使用。

coreml.new_wordpiece_tokenizer(opts)

  • 等价于 coreml.new_text_tokenizer({ type = "wordpiece", ... })
  • 适合 BERTCN-CLIPWordPiece 风格文本模型
  • 也支持直接传词表路径字符串:coreml.new_wordpiece_tokenizer(vocab_path)

coreml.new_bpe_tokenizer(opts)

  • 等价于 coreml.new_text_tokenizer({ type = "bpe", ... })
  • 同时覆盖 gpt2_bpeclip_bpe 一类 vocab.json + merges.txt 模型

coreml.new_sentencepiece_tokenizer(opts)

  • 等价于 coreml.new_text_tokenizer({ type = "sentencepiece", ... })
  • 使用面向端侧推理的轻量兼容实现
  • 支持 .vocab.model

coreml.new_regex_tokenizer(opts)

  • 等价于 coreml.new_text_tokenizer({ type = "regex", ... })
  • 适合基于规则切词和简单词表映射的场景

coreml.new_byte_tokenizer(opts)

  • 等价于 coreml.new_text_tokenizer({ type = "byte", ... })
  • 会先把文本转成 UTF-8 字节流,再按字节查词表

coreml.new_whitespace_tokenizer(opts)

  • 等价于 coreml.new_text_tokenizer({ type = "whitespace", ... })
  • 适合空格切词、词表直查的轻量文本模型

coreml.new_character_tokenizer(opts)

  • 等价于 coreml.new_text_tokenizer({ type = "character", ... })
  • 适合字符级文本模型

类型判断

coreml.is_text_tokenizer(value)

是否文本分词器 = coreml.is_text_tokenizer(需要判断的值)

用于判断一个值是否为 coreml_text_tokenizer_object

对象方法

:encode(text[, opts])

编码结果, 错误信息 = 文本分词器对象:encode(文本)

编码结果, 错误信息 = 文本分词器对象:encode(文本, {
output = "table""MLMultiArray""ort_tensor",
data_type = 数据类型,
pair_text = 配对文本,
max_length = 最大长度,
padding = 填充策略,
truncation = 截断策略,
return_attention_mask = 是否返回 attention mask,
return_token_type_ids = 是否返回 token type ids,
return_special_tokens_mask = 是否返回 special tokens mask,
})

把单个文本编码成 token 序列。

:encode_batch(texts[, opts])

编码结果, 错误信息 = 文本分词器对象:encode_batch(文本数组)

编码结果, 错误信息 = 文本分词器对象:encode_batch(文本数组, {
output = "table""MLMultiArray""ort_tensor",
data_type = 数据类型,
pair_text = 配对文本或配对文本数组,
max_length = 最大长度,
padding = 填充策略,
truncation = 截断策略,
return_attention_mask = 是否返回 attention mask,
return_token_type_ids = 是否返回 token type ids,
return_special_tokens_mask = 是否返回 special tokens mask,
})

一次编码多个文本,返回 batch 形式的 token 序列。

:decode(ids)

文本, 错误信息 = 文本分词器对象:decode(ids)

单条 token id 序列反向解码成文本。

  • ids 可以是 Lua 数组、MLMultiArray,或者 ORT tensor 之类的 tensor-like userdata
  • ids 也可以是任何实现了 shape()to_table() 的 tensor-like userdata
  • 如果传入的是 batch 数据,会报错并提示改用 decode_batch()

:decode_batch(batch_ids)

文本数组, 错误信息 = 文本分词器对象:decode_batch(batch_ids)

把 batch token id 序列反向解码成文本数组。

  • batch_ids 可以是嵌套 Lua 数组、MLMultiArray,或者 ORT tensor 之类的 tensor-like userdata
  • batch_ids 也可以是任何实现了 shape()to_table() 的 tensor-like userdata

:vocab_size()

词表大小 = 文本分词器对象:vocab_size()

返回当前分词器可用词表大小。

:context_length()

上下文长度 = 文本分词器对象:context_length()

返回当前分词器的固定输出长度,也就是单次编码会补齐或截断到的长度。

编码与返回说明

  • output 默认是 "MLMultiArray",适合直接喂给 CoreML 模型
  • output = "table" 适合调试、查看 token id,或兼容旧脚本
  • output = "ort_tensor" 适合直接喂给 ONNX Runtime 文本模型
  • output = "ort_tensor" 前必须先执行 require("onnxruntime"),这样 ORT 桥接接口才会被注入
  • output = "ort_tensor" 依赖 ONNX Runtime,因此仅支持 iOS 13+
  • 为兼容旧脚本,字段 multi_array_output 仍会被读取;但新代码建议统一使用 output

data_type 规则

  • output = "MLMultiArray" 时,data_type 可选 "int32""float32""float16""double""float64" 可作为 "double" 的别名
  • output = "MLMultiArray" 时,默认 data_type = "int32"
  • output = "ort_tensor" 时,data_type 可选 "float16""float32""uint8""int8""int32""int64""double""bool"
  • output = "ort_tensor" 时,默认 data_type = "int64"

padding / truncation

  • padding 可以是布尔值,也可以是字符串
    • true 会映射到 "max_length"
    • false 会映射到 "do_not_pad"
  • truncation 可以是布尔值,也可以是字符串
    • true 会映射到 "longest_first"
    • false 会映射到 "do_not_truncate"

pair_text

  • encode() 里可以传单个 pair_text
  • encode_batch() 里可以传单个 pair_text,也可以传与 batch 大小一致的字符串数组

结构化返回

当以下任一字段为 true 时,encode() / encode_batch() 会返回结构化结果表,而不只是裸 token 序列:

  • return_attention_mask
  • return_token_type_ids
  • return_special_tokens_mask

结构化结果常见字段:

  • input_ids
  • length
  • attention_mask
  • token_type_ids
  • special_tokens_mask

对 batch 编码来说:

  • output = "table" 时,保留每条样本自己的长度
  • output = "MLMultiArray" / "ort_tensor" 时,会把 batch 补齐成规则矩阵后再返回

示例

local tokenizer = assert(coreml.new_text_tokenizer({
type = "wordpiece",
vocab_path = XXT_HOME_PATH.."/models/demo/vocab.txt",
context_length = 52,
}))

local ids = assert(tokenizer:encode("星星", {
output = "MLMultiArray",
data_type = "int32",
}))

local structured = assert(tokenizer:encode("星星", {
output = "table",
return_attention_mask = true,
return_token_type_ids = true,
}))

local ort = require("onnxruntime")

local input_ids = assert(tokenizer:encode("星星", {
output = "ort_tensor",
data_type = "int64",
}))

local batch = assert(tokenizer:encode_batch({
"星星",
"月亮",
}, {
output = "ort_tensor",
}))

print(tokenizer:decode(structured.input_ids))
print(tokenizer:vocab_size())
print(tokenizer:context_length())