指南

泰语分词是什么,为什么它决定语音、翻译和搜索的效果

泰语分词是在不留空格的文本中找出词边界的步骤,它决定了语音的停顿、翻译、时间戳和搜索的效果。

· 阅读约 2 分钟

泰语分词,是在词与词之间没有空格的文本里,找出一个词在哪里结束、下一个词从哪里开始的步骤。所有处理泰语的系统,无论是朗读、翻译、建索引,还是给文本标注时间,都必须先完成这一步,才能开始做自己的工作。

在英语里看不到这一步,因为空格已经把活干完了。泰语也有空格,但它表示的是另一回事。这篇文章先讲泰语的空格标记什么,再列出可以有两种切法的字符串。然后跟着一处切错,看它在朗读的句子、译文、字幕文件和搜索索引里分别造成什么后果。

为什么泰语的词与词之间没有空格#

泰文在一个短语之内把词连在一起写。ผมกินข้าวที่ร้านอาหารไทย 在泰语母语者看来是六个词,在任何按空白字符切分的函数看来却只是一个 token。空格留给更大的单位使用。它标记一个短语或分句的结束,相当于英语里逗号或句号的作用,出现的频率也远低于英语读者的预期。

这一书写习惯由来已久,而且始终如一。数字、人名和外来词有时两侧各留一个空格,句末语气词有时也会单独隔开,但一个泰语短语内部的词从不分开写。读者靠词汇和上下文找出边界,就像英语读者判断句子里的 lead 用的是哪个意思一样。

泰语的词很短。在 BEST2010 语料库中,泰语词的平均长度是 3.855 个字符(COLING (2014)),本站把词数换算成计费字符数时,将其取整为 4。因此,一段一百个词的段落是一串约四百个字符的文本,其中也许只有三个空格,而这一百处边界每一处都得靠推断得出。

能切出两种结果的字符串#

只要掌握了词汇,大多数泰语文本只有一种切法。难的是这样一类字符串:两种不同的切法切出来的都是真实存在的词。词典解决不了它们,因为两边的每个词词典里都有。

字符串一种切法另一种切法
ตากลมตา กลม(圆眼睛)ตาก ลม(晾干)
ไปหามเหสีไป หา มเหสี(去见王后)ไป หาม เห สี(去抬,后接两个不成词的音节)
มากกว่ามาก กว่า(多于)มา กกว่า(来,后接一个不成词的片段)
ขนมอบขนม อบ(烘焙点心)ขน มอบ(毛,交给)

前两行是读者在实际中会遇到的情况。ตากลม 是真正的歧义,只有它周围的句子才能决定取哪种读法。ไปหามเหสี 对机器来说有歧义,对人来说却从来没有,因为第二种切法留下的音节组不成词。后两行是同一种情形:一种切法是人们真会说的短语,另一种是一串没人会这样写的词典词条。

一个字符串,两种分词
ตากลม

  ตา   กลม      圆眼睛
  ตาก  ลม       晾干

เด็กคนนี้ตากลม        这个孩子眼睛圆圆的
เอาผ้าไปตากลม        把布拿去晾干

同样的五个字母,由前面的词决定读法

整个问题都浓缩在这一行里。ตากลม 内部没有任何东西能决定读法。决定读法的是 เด็กคนนี้(这个孩子)或 เอาผ้าไป(把布拿去),而它们都在逐词匹配器所看的那个字符串之外。

切错一处,译文会怎样#

先分词、后翻译的系统,会把每一处切错都原样继承下来。เอาผ้าไปตากลม 如果被切成 ตา กลม,译出来就是一句关于布和圆眼睛的话。译文通顺、合乎语法,却是错的,不懂泰语的审校人员也收不到任何出了问题的信号。

专有名词是最常见的情况。用泰文书写的品牌名,比如聊天应用的 ไลน์、打车服务的 แกร็บ,本身就是一串普通音节。切错了,ไลน์ 就变成表示“线”的词,品牌也就从译文里消失了。翻译 API 正是为此支持术语表。按发布时的写法列入其中的术语,会作为一个整体匹配,并按调用方写的样子输出。

标记(markup)是切分出错的另一个地方。按字符偏移量重新插回的行内标签,只要偏移量差一位,就会落在一个词的中间;在泰语里,这意味着落在辅音和属于它的元音之间。format 字段的作用,就是让模型直接收到标记,并把标签保持在它能看到的词边界上。

切错一处,语音会怎样#

语音模型需要知道词在哪里,才能确定两件事:在哪里换气,以及字母该怎么读。停顿跟着词和分句走。停顿落在词中间,听起来像口吃;整句一口气读完不停顿,听起来像机器。空格和标点都不会告诉模型词在哪里。

音节怎么读,同样取决于词。同样的字母在不同的词里切成不同的音节,只有词本身能决定。ปลา 读作一个音节 plaa,开头是复辅音,而 ปลัด 以同样两个字母开头,却读作两个音节 pa-lat。จักรยาน 读作 jak-kra-yaan,จักรี 读作 jak-kri,两者共有的 จักร 之后切分位置不同。双写的 รร 在词尾读作 un,如 สรร(san);在尾辅音之前读作 um,如 กรรม(kam)。

词读音为什么由词决定
ปลา · ปลัดplaa · pa-lat开头字母相同,一个是复辅音,另一个读作两个音节
จักรยาน · จักรีjak-kra-yaan · jak-kri前四个字母相同,音节切分不同
สรร · กรรมsan · kam双写的 รร 在词尾读 un,在尾辅音前读 um

找到了词的模型,能把上面每个词都读对。按顺序逐个读字母的模型,每个词都会在第一个音节上读错。文本转语音页面列出了更多这类读音规则,并附上泰语母语者的实际读法。

切错一处,词级时间戳会怎样#

词级时间戳是附在一个词上的一段音频区间。在英语里,词是现成的,对齐就是全部工作。在泰语里,模型得先把词切出来,时间戳再继承它切出的结果。切错一处,就会得到一个覆盖一个半词的区间,用这些区间生成的字幕会高亮错误的音节。

语音 API 可按词、句或整段语音的粒度返回时间戳,词级区间遵循模型自己对文本的分词。字幕页面展示了它作为高亮跟读时的样子。当字幕每行只要切换一次时,句级粒度能完全绕开这个问题。

搜索索引存储的是词项,一个词项就是一个词。按空格切分泰语建出的索引,会把整个短语当成一个词项存下来,查询短语里的某个词就什么也查不到。用分词器建出的索引能找到这个词,但只能按分词器选定的那种切法找到。查询也必须用同一个分词器、按同样的方式切分,否则两边就对不上。

实际的后果是:泰语搜索的质量受限于分词的质量,更换分词器就意味着重建索引。商品目录最先感受到这一点,因为商品名恰恰是分词器从未见过的字符串。

词典匹配与上下文模型#

分词方法分为两大类。词典方法沿着字符串逐位扫描,在每个位置取词典中收录的最长词,剩余部分无法切分时再回溯。这类方法速度快、过程透明,在大多数文本上都能切对。但遇到上面那些有歧义的字符串就会出错,因为两种切法都在词典里,而这种方法无从参考周围的句子。凡是词典没收录的词它也会切错,其中包括大多数新出现的名称。

上下文模型读取每个位置周围的字符,预测那里是否存在边界。它们学会了 เด็กคนนี้ 后面跟的是描述,เอาผ้าไป 后面跟的是动作,并据此切分 ตากลม。遇到没见过的词,它们按词形来处理,因为泰语词由辅音、元音和声调符号构成,结构有规律可循。代价在于它们本身就是模型,随之而来的是训练数据的需求和模型特有的失败情形。

说明

这两类方法常常结合使用:词典给出容易确定的边界,其余的由上下文模型判断。无论处理流程采用哪种方法,它得出的分词结果都会被后面的每个环节继承下来。

用泰语文本调用 API 时该怎么做#

  • 发送完整的句子,或使用分段。按任意字符数截出的片段可能在词中间开始或结束,模型就只能去猜两端的词。
  • 把品牌名、产品名和地名按您对外发布的写法放进术语表。列入的术语会作为整体匹配,永远不会被拆开。
  • 必须原样保留的字符串用 do_not_translate,文本带标记时发送 format。模型会把标签保留在它能看到的边界上。
  • 按产品需要的粒度请求 timestamps。句级区间是稳定的;词级区间是模型自己对文本的切分。
  • 对查询使用与建索引相同的分词方法。泰语搜索漏掉明显该命中的结果,通常就是因为两边不一致。
  • 在控制台里连同上下文句子一起测试上表中的歧义字符串,并像泰语母语者那样阅读输出。

分词是任何泰语处理流程做出的第一个决定,之后的每一项输出都带着它。本站的文本转语音和翻译模型在模型内部做这个决定,同时看得到整个句子。调用方借助上面这些字段,避免这个决定在缺少上下文的情况下单独做出。

继续阅读

更多指南