SunPinyin代码导读(十)

本来计划这一回介绍主要数据结构的,但是出于篇幅和连贯性的考虑,把它们附到上一回了。这一回主要介绍构造和搜索Word Lattice的方法。

CIMIContext类是整个ime部分代码的核心,对应上一回中的概念模型,它充当了Syllable Segmentor、Lattice Builder和Context Searcher的角色:

CIMIContext::modifyAndReseg (boneStart, boneEnd, skel, cursor, cursorIdx, candiStart):

实际使用时,boneStart、boneEnd、candiStart均指向m_Skeleton中的节点。调用segPinyin(),对参数skel中的诸Bone节点(外加boneStart之前的2/3个节点,避免切分的不充分),和[boneEnd, T1-1)进行重新切分,得到的结果保存在newskel中。重新计算cursor及其index。然后调用modify(its, T1-1, newskel),重新进行搜索。

CIMIContext::segPinyin (head1, tail1, head2, tail2, newskel):

[head1, tail1)和[head2, tail2)在逻辑上组成一个待切分的拼音串儿。实际使用时,[head2, tail2)是CIMIContex::m_Skeleton中的节点。将切分的结果保存到newskel变量中。

CIMIContext::modify (boneStart, boneEnd, skel):

将[boneStart, boneEnd)中的bone从其所在的skeleton列表(即m_Skeleton)中删除,将参数skel中的bone插入其间。调用searchFrom(),从新插入的Bone开始,重新进行搜索。

CIMIContext::searchFrom (boneStart):

遍历boneStart到第二个尾节点(T2),根据前一个Bone,调用forwardXXX()方法扩展自己的Lexicon状态节点,然后调用buildLatticeStates()构造自己的Lattice状态节点。遍历结束之后,回溯得到最佳路径。

从某一个bone开始进行搜索,意味着从这个Bone到T2,每个Lattice Frame上原有的Lexicon和Lattice状态节点都被清空并重新计算。

CIMIContext::forwardOnePinyinBone (bone):

将该bone的后续(boneNext)中的Lexicon状态节点集合(lexss2)清空。遍历bone上的Lexicon状态节点,用本bone上的拼音字符串,尝试扩展它,并将新的Lexicon节点加入到lexss2中。迭代结束之后,尝试用bone上的拼音字符串,从Pinyin Trie的根节点进行扩展,并加入到lexss2中。最后返回boneNext。其它的forwardXXX()方法比较简单,这里就不多介绍了。

CIMIContext::buildLatticeStates (bone):

得到bone的前继bonePrev(这意味着传入的参数不能是第一个Bone节点),清空bone的Lattice状态节点。遍历当前bone的Lexicon状态节点,找到该节点的起始bone,对Pinyin Trie节点上对应的词表,调用transferBetween(boneFrom, boneTo, wid, 1.0),构造bone上的Lattice状态节点。

上一回的插图3来说,B3上有两个Lexicon状态,(B1, shi'pin')和(B2, pin'),可以用“食品”、“视频”、“饰品”等词来扩展B1上的Lattice节点,然后用“品”、“频”、“拼”等词再次来扩展B2上的Lattice节点,将新得到的状态节点加入到B3的Lattice状态节点集合中。

CIMIContext::transferBetween (from, to, wid, ic):

得到from Bone的Lattice状态节点集合latss1。遍历latss1,对每个LatticeState节点,用其中保存的SLM状态节点m_State(即后续Lattice状态节点的history),调用CThreadSlm::transfer()来计算Pslm(wid|history)的值。

如果转移之后的状态节点,其历史(回退)节点为pseudo root节点(即level为0,表示平均分布),而最近的历史记录中却见到过这个词,则将这个pseudo unigram节点的index设置为wid;这样对下一个词w',才能通过CThreadSlm::lastWordId(state)得到上一个词的ID(即wid),以正确计算Pcache(w'|wid)的概率值。

然后计算Pcache(w|h),和Pslm(w|h)进行插值,得到句子的概率评分保存到node.m_Score中。将这个新的Lattice节点,插入到to Bone的Lattice状态节点集合latss2中(同时也进行了beam pruning)。

下一回我们会介绍如何利用搜索的结果,以及对用户选择的处理。

Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

To submit your comment, click the image below where it asks you to...
Clickcha - The One-Click Captcha