具体实施方式
在图1中,用户使用手机、电话或PDA等工具进行语音查询,首先我们利用现有的语音识别接口(如IBM ViaVoice)进行识别,得到语音查询文本,其中可能包含各种错误;然后利用辨音系统在知识查询语言和大规模知识库的基础上进行分析推理,得到正确的用户查询,最后调用我们的自然语言查询模块找到符合用户需求的知识信息并反馈给用户。如果我们的知识库没有答案,会通过索引去查询用户定制的知识库,以达到通用性的目的。
在图3中,先根据辨音模型及查询模板库、知识库,对用户语音查询文本进行相似智能分词,再检索查询模板库,找到与之匹配的模板,然后对各候选模板进行知识验证。如果找到了相关的知识,则辨音成功,该分词结果对应的句子就是对用户语音查询文本的辨音结果,并将查询答案反馈给用户。
1.我们介绍本发明中的多层次、领域可定制的知识查询语言和存储模式。
首先,我们对知识库中的所有属性进行聚类,将查询方式相似的属性聚在一起,抽象出共同的查询模式,形成具有继承关系的知识查询语言;其次定义具体属性的提问方式;最后利用编译程序自动生成查询模板集。
基本符号描述:
■defquery:查询语言引导关键词
■继承:查询语言之间的继承关系。它继承所有的上层语言,使得自身的表达能力比上层语言更强
■<关于本层语言的解释>:对本层语言的说明,是一个字符串。
■提问触发器:表示用户提问的触发条件。一旦用户提问触发此条件时,立即执行查询动作getc(A,C’)或getv(C,A)
■<?C>:待查询概念的标示变量
■<?C’>:待查询相关概念的标示变量
■<?C>={getc(A,C’)}:从知识库中提取那些槽A的值为C’的所有概念C。
■<?C’>={getc(C,A)}:从知识库中提取概念C在槽A的上的值。
■<可领域定制术语>:可以是用户提问中可能出现的一般性关键词,也可以是表示领域可定制的术语变量。
■<X|Y|...|Z>:这是我们发明的一项缩写符号。它表示两个含义。第一,X,Y,...Z为查询语言关键词。第二,在用户查询中,使用X,Y,...,或Z的意义是一样的,均得到相同的答案。用巴克斯范式表示就是,<X|Y|...|Z>∷=X|Y|...|Z。另外,我们将X,Y...Z称为必要词,它们在当前位置必须且只能出现其中一个。
■[<X|Y|...|Z>]:表示X,Y,...Z这些词在该处可以省略,我们将其称为可去词,将[]称为可去符。
■<!提问主题词>:一个有着相同或相似意义的词的聚类,如:<!什么疑问词>=<什|什么|哪|哪些|何|啥|...>。
■<?C的提问模式>:表示查询<?C>时可能的提问方式。其语法是:?C<可领域定制疑问词>
■<?C’的提问模式>:表示查询<?C>时可能的提问方式。其语法是:?C’<可领域定制疑问词>
通用查询语言的巴克斯范式如下:
defquery<本层语言>[继承<上层语言>]
{
说明:<关于本层语言的解释>
提问触发器:<可领域定制术语>,<?C>={getc(A,C’)},<可领域定制术语>,<?C’>={getc(C,A)},<可领域定制术语>
:<?C>的提问模式
:<?C’>的提问模式
}
为了具体应用通用查询语言,我们以“事件地点”为例,关于“事件地点”的提问主题描述如下:
defquery事件地点()
{
说明:用于提问事件的地点。
提问触发器1:<?C>={getc(A,C’)};<?副词>;[<是|为>][<在|于>];<?C’>={getc(C,A)};<?事件>
:?C <!什么疑问词><?本体词>
:?C’ <!地点疑问词>
}
在“defquery事件地点语言”中有1个提问触发器。根据具体情况,设计者可以定义任意多个。利用这一语言,设计者可以定义更具体的事件地点查询语言。对具体属性来说,例如,为定义“出生地点”和“发生地点”的查询语言,设计者可以简单地采用继承的方法,定义如下:
defquery出生地点(?事件={<出生|生>},?本体词={<人>})继承事件地点
defquery发生地点(?事件={<发生|出现>},?本体词={<人>})继承事件地点
为便于进行模板匹配,我们用一个编译程序将定义好的知识查询语言编译为知识查询模板,然后写入查询模板库里。
例如,对属性“出生地点”对应的查询语言编译后的查询模板为:
#出生地点
<C>;[<是|为>][<在|于>];<!地点疑问词>;<出生|生>@C’
<!什么疑问词><人>;[<是|为>][<在|于>];<C’>;<出生|生>@C
其中“@C’”表示该模板提问属性值,即某概念C的属性“出生地点”的值;“@C”表示该模板是提问概念,即知识库中哪个概念的属性“出生地点”的值为C’。
2.我们介绍本发明中的辨音模型。未经语音训练的非特定人在非特定场合下进行语音查询时,由于受到噪声、电话线路及朗读者的发音等因素的影响,目前的语音识别技术还很难得到满意的识别效果,识别后的文本会带有各种各样的错误,有些错误非常离谱,人看了都搞不清是什么意思。因此为了使计算机能够真正“辨音”,首先我们需要设计一种辨音模型,对用户可能出现的语音错误进行归类、定量分析和准确测度。
辨音模型包括:错误的发生原因、相似度的计算、辨音的触发条件、多种辨音结果中最优解的选取规则以及知识的推理机制等。我们要实现一个最佳平衡:既要纠正最多的错字(哪怕错的比较离谱),又要保证正确的字不被误纠,而在实际中是很难找到这样一个最佳点的。在上面我们举过一个例子,用IBM ViaVoice朗读“糖尿病有哪些症状”,识别结果竟为“糖尿病有哪些振作”。其原因是ViaVoice没有从知识的角度来分析,它认为“振作”本身是一个词,而且离“症状”的距离也不是很近,即相似度不够高,所以没有纠正这个错误。当然这是一种保险的做法,保证正确的字或词语不会被误纠,但是却降低了纠错率,影响了识别精度。我们需要结合本体和知识,研究一种达到最佳平衡的辨音模型,以最大限度地提高纠错率。
1)错误原因。由于用户是利用语音查询的,那么语音查询文本中出现的错误都是语音错误,其特点是,错别字是字形不一定相似,但发音相同或相似的汉字。如上例中的“振”与“症”发音相同,“作”与“状”虽然发音不同但相似。
2)错误分类。从知识的角度来分,用户出现的错误可分为以下三类:
●概念错误
例1:提出有多少人
正确:彝族有多少人
例2:黄旗的原料有哪些
正确:黄芪的原料有哪些
例1的“提出”,例2的“黄旗”,都属于概念错误,该类错误的特点是知识库的概念弄错了,提问句型并没错。
●句型错误
例3:中国有那些城市
正确:中国有哪些城市
对应的知识查询模板为:
<C>;<下辖|包括|有>;<!什么疑问词>[<!地区地点名词>]@C′
(“!什么疑问词”中没有“那些”,只有“哪些”)
例4:美国和十独具
正确:美国何时独立
对应的知识查询模板为:
<C>;<!时间疑问词>;<独立|自由>@C′
(“!时间疑问词”中没有“和十”,只有“何时”)
该类错误的特点是知识库的概念C没错,但是提问句型有错,我们将这种错误称作句型错误。
●混合错误
例5:肩负着是核实独立的
正确:柬埔寨是何时独立的
该类错误的特点是概念错误和模板错误同时出现。
3)相似度的计算。我们纠正的错字都有一个共同点,错别字和正确字语音相似,因此我们需要通过相似度的计算来确定某汉字纠不纠正,如何纠正。为了对语音错误进行准确测度,本发明提出了一种相似度的计算模型(本发明中提到的相似均指语音相似)。
相似度用来表示两个字之间或两个词之间的相似程度,值域为[0,1]。从拼音的角度来看,一个汉字C是由一个声母和一个韵母组成的,我们可以用(ic,v)来表示汉字,其中ic和v分别表示组成该汉字的声母和韵母(有些汉字没有声母,则对应ic=空)。于是我们可以将汉字“是”和“四”表示为(sh,i)和(s,i),这种表示形式与汉字的无调拼音一致。尽管GB-2312汉字共有6700多个,但是所有的汉字最终可以归结为大约400个类。然后,我们从语音学的角度对这400个类进行分析,总结类间的发音相似度,表1出了部分类间的相似数据。
给定任意两个汉字C1=(ic1,v1)和C2=(ic2,v2),我们将它们的发音相似度PSIM(C1,C2)定义为:
●1,如果ic1=ic2且v1=v2
●CSIM([(ic1,v1)],[(ic2,v2)]),如果ic1≠ic2或v1≠v2
两个汉语词组W1=C1C2...Cn和W2=D1D2...Dn之间的发音相似度为:
PSIM(W
1,W
2)=∑PSIM(C
i,D
i)/n
类1 |
类2 |
CSIM(Class,Class) |
[(b,ai)] |
[(b,ei)] |
0.8 |
[(ch,i)] |
[(c,i)] |
0.92 |
[(ch,i)] |
[(q,i)] |
0.8 |
[(k,e) |
[(g,e)] |
0.75 |
[(zh,eng)] |
[(zh,en)] |
0.95 |
[(zh,uang)] |
[(z,uo)] |
0.7 |
[(sh,i)] |
[(s,i)] |
0.92 |
[(sh,i)] |
[(s,e)] |
0.65 |
[(y,un)] |
[(y,uan)] |
0.7 |
... |
... |
... |
表1部分类间的发音相似度
我们再来介绍几个定义:
定义1同音字如果字C和源字C’之间的相似度为1,则称C是C’的同音字。
定义2相似字如果字C和源字C’之间的相似度大于某阈值μ1,则称C是相似字,且C相似于C’。
定义3相似词如果词W和源词W’之间的相似度大于某阈值μ2,而且词中的字都对应相似,则称W为相似词,且W相似于W’。
定义4精确词如果词W在原文本对应位置出现,则称W为精确词。
经实验测试,μ1=0.6,μ2=0.7。
例如:“症状”与“振作”
PSIM(“症”,“振”)=CSIM([(zh,eng)],[(zh,en)])=0.95>μl
PSIM(“状”,“作”)=CSIM([(zh,uang)],[(z,uo)])=0.7>μl
因为“症”与“振”,“状”与“作”都对应相似,而且PSIM(“症状”,“振作”)=[PSIM(“症”,“振”)+PSIM(“状”,“作”)]/2=[0.95+0.7]/2=0.825>μ2,所以“振作”相似于“症状”,相似度为0.825。
4)相似规则。在对用户查询进行辨音分析时,由于错误经常很离谱,与正确的句子间的相似度不够高,所以我们将相似字及相似词的阈值放得很低,这样一个句子就会出现成千上万种相似结果,给辨音带来了很大的工作量。为了实现快速辨音,我们要按照一定的规则来产生这些相似结果,使正确的结果最早出现。
例如对用户语音查询“美国和十独具”进行相似分析,以“美”为首的相似词有:“美国”,“湄公河”,“外国”,“美观”,“韦伯”,“美”等;以“和”为首的相似词有“何食物”,“何时”,“何事”,“合适”,“核实”,“合十”,“何”,“河”等。按这样组合下去该语音查询就有几千种相似结果,而对每种结果我们都需要进行分析处理,所以我们要比较相似词间的优先级,先去处理最相似的词。
词间优先级的比较分为三种情况:精确词和精确词的比较,相似词和相似词的比较,精确词和相似词的比较,我们针对这三种情况分别总结了相应的优先规则。
●如果两个词都是精确词,则长度优先。如上例中“美国”优先于“美”。
●如果两个词都为相似词,则同音字数多者优先;若两词同音字数相同,则相似度优先。如上例中“何时”优先于“何”。
●如果两个词一个为精确词,另一个为相似词,则相似词优于精确词
相似词字数>=精确词字数*2,且相似词中的同音字数>=精确词字数。如上例中相似词“何时”优先于精确词“和”。
5)辨音的触发条件,即何时对用户语音查询进行辨音。因为辨音是需要消耗一定时间的,语音软件识别后的用户语音查询文本可能有错,也可能没错。我们不能对每次都执行辨音处理,需要定义辨音的触发条件。
首先,对原查询文本进行分词,然后和知识查询模板进行模板匹配。当出现以下情形之一时,触发辨音操作。
●分词失败;
●找不到和原查询文本有任何匹配的知识查询模板;
●找到了和原查询文本匹配的知识查询模板,但相差较远(知识查询模板字数/原查询文本字数<0.7);
●找到了和原查询文本完全匹配的知识查询模板,但在知识库里没找到相关的知识。
如果原查询文本找到了相关的知识,则说明无误,将该知识反馈给用户。
3.我们介绍本发明中的辨音算法。
本发明中的辨音算法的本质就是在多层次、可按领域定制的知识查询语言和NKI知识库的引导下,找到和用户语音查询文本最相似的语言形式。
基本符号描述:
知识库词典: char*knodic[knodic_num];
查询模板词典:char*keydic[keydic_num];
相似字结构:
typedef struct class_simzidata
{
char zi[2]; ∥相似字
int simdegree;∥该字与原字的相似度
int dic_flag; ∥查询语言和知识库中是否有该字为首的词
}class_simzidata;
汉字相似表结构:
typedef struct class_simzitable
{
char zi[2]; ∥汉字
long keydic_lb;∥该字在查询模板词典中的起始位置
long keydic_hb;∥该字在查询模板词典中的最后位置
long knodic_lb;∥该字在知识库词典中的起始位置
long knodic_hb;∥该字在知识库词典中的最后位置
int simzi_num; ∥该字的相似字数
class_simzidata*simzi;∥各相似字的信息
}class_simzitable;
∥分词中的词结构
typedef struct phrase
{
char*phrase_str;∥该词内容
long lexi_no; ∥该词在查询模板库里的位置索引
int var_flag; ∥该词是知识库概念还是查询模板的词
}phrase;
∥句子分词信息表
typedef struct decompose_info
{
int phrase_count; ∥包含的词数
int var_phrase_count;∥概念数
struct phrase*phrase_head;∥该分词结果中各词的信息
}decompose_info;
用户提问反馈的信息表结构:
typedef struct info_table
{
char*access_time; ∥访问时间
<!-- SIPO <DP n="12"> -->
<dp n="d12"/>
char*action; ∥动作:查询or添加
char*question; ∥对应的完整问题
char match_type[6]; ∥精确还是模糊匹配
char*query_type; ∥用户提问的查询类型
char*concept; ∥概念
char*attr_name; ∥属性名
char*attr_value; ∥属性值
int var_num; ∥概念数
char*var_list[VAR_COUNT]; ∥变量列表
char*answer; ∥反馈答案
}info_table;<br/>
∥变量描述
question: 用户查询
IdentifyInfoTable: 辨音得到的知识反馈信息
IdentifyResult: 辨音结果
wordsegment: 用户语音查询文本的某相似分词结果
sen_set: 候选模板集
sen: 某个候选模板
SimziList: 与某字符相似的汉字集合
SimciList: 相似词集,按相似度递减排序
Success: 辨音成功的标记
∥函数描述
AddSegTail(wordsegment,Wi)
将词Wi加入分词结果wordsegment
CompWordSim(W1,W2)
计算词W1和W2的相似值
GetText(wordsegment)
得到分词结果wordsegment对应的句子
InsertSimci(SimciList,W,simdata)
将相似词W及其相似值simdata插入到SimciList中,并保持SimciList的相似度递减次序
辨音主程序:
输入:用户语音查询文本question
输出:辨音结果IdentifyResult,知识反馈信息IdentifyInfoTable
void IdentifyProun(char*question,decompose_info wordsegment)
{
∥若辨音已成功,则返回
if(Success=1)
return;
if(question为空)
{
∥如果该句已分词完毕,则得到了一种完整的分词结果,进
行匹配验证
IdentifyInfoTable=ProcessSegment(wordsegment);
∥如果该分词找到了相关知识,则辨音成功
if(IdentifyInfoTable非空)
{
Success=1;
∥该分词对应句子即为辨音结果
IdentifyResult=GetText(wordsegment);
}
}
else
{
∥继续分词
Char=question[0];
∥找到Char的相似字集SimziList
For every Siin SimziList
{
<!-- SIPO <DP n="14"> -->
<dp n="d14"/>
∥在知识库词典中查找以Si为首的相似词
if(zisim[neima].knodic_lb>0)
{
for(i=Si.knodic_lb;i<=Si.knodic_hb;i++)
{
∥得到该词在原用户查询中对应的字符串
Initword=SubString(question,0,len(knodic[i]))
∥计算该词和原字符串的相似度
simdata=CompWordSim(knodic[i],Initword);
if(simdata>相似词阈值)
{
∥若相似,则将该词相似结果按优先度递减
的次序加入相似词列表中
InsertSimci(SimciList,knodic[i],simdata);
}
}
}
∥在查询模板词典中查找以Si为首的相似词
if(zisim[neima].keydic_lb>0)
{
for(i=Si.keydic_lb;i<=Si.keydic_hb;i++)
{
∥得到该词在原用户查询中对应的字符串
Initword=SubString(question,0,len(keydic[i]))
∥计算该词和原字符串的相似度
simdata=Comp WordSim(keydic[i],Initword);
if(simdata>相似词阈值)
{
∥若相似,则将该词相似结果按优先度递减
的次序加入相似词列表中
<!-- SIPO <DP n="15"> -->
<dp n="d15"/>
InsertSimci(SimciList,keydic[i],simdata);
}
}
}
}
∥按相似度优先级递减次序生成分词
For every Wi in SimciList
{
∥将该相似词加到当前分词结果
AddSegTail(wordsegment,Wi);
∥得到尚未处理的串
RemainStr=SubString(question,0,len(Wi));
∥递归处理剩下的串
IdentifyProun(RemainStr,wordsegment);
}
}
}
匹配验证程序
输入:用户查询句子的某分词结果wordsegment
输出:该分词结果的反馈信息表
info_table ProcessSegment(decompose_info wordsegment)
{
∥求wordsegment中各词在查询模板库里位置索引集的交集,得
到该分词结果在查询模板库中的出现空间
sen_set=GetIntersection(wordsegment);
∥对每个候选模板进行判断筛选,看其是否与wordsegment匹配
for every sen in sen_set
{
if(wordsegment.变量个数!=sen.变量个数)
<!-- SIPO <DP n="16"> -->
<dp n="d16"/>
continue;∥不匹配
if(wordsegment.词数<sen.必要词数‖wordsegment.词数>sen.
词数)
continue;
if(sen.必要词位置序列-wordsegment.非变量词在模板中的
位置序列!=wordsegmenmt.变量)
continue;
∥如果该模板满足上述条件,而且成功地进行了知识验证,
则模板匹配成功。
query_info_table=VerifyKnowledge(sen);
if(query_info_table.answer!=NULL)
retum query_info_table;
}
return empty;
}
如图3所示,辨音的处理步骤如下:
1)根据辨音模型及查询模板库、知识库,对用户语音查询文本进行相似智能分词,每得到一种分词结果,则转2)。
2)根据分词结果检索查询模板库,找到与之匹配的模板,然后判断该模板在形式上是否与当前分词结果相匹配,从而得到候选模板集合。
3)对各候选模板进行知识验证。根据模板的提问类型以及实现的KAPI函数进行知识库检索。
如果找到了相关的知识,则辨音成功,该分词结果对应的句子就是对用户查询文本的辨音结果,并将查询答案反馈给用户。
如果没找到相关知识,则转1),继续相似分词处理。
下面我们对各部分进行详细说明。
I.相似智能分词
分词所用的词典是知识库词典和查询模板词典,知识库词典包括知识库出现的所有概念,而查询模板词典包括查询模板库里出现的所有关键词及其在模板库里的位置。用户查询文本中出现的词既可能是知识库概念的相似词,也可能是查询模板词的相似词。
这里的分词是相似分词,生成与原查询句子语音相似的所有分词结果。经实验分析,非特定人在非特定场合下语音查询的识别结果中的错误和正确的结果经常有很大的差异,所以我们将相似度的阈值定义的很低,以提高辨音的正确率。这样便使得相似分词结果的数目非常庞大,多达几千甚至几万个。我们采用相似词排序的方法,使各分词结果按照相似度递减的次序出现,每得到一种分词结果,就去模板库和知识库里匹配验证。一旦找到相关知识,则辨音成功,立刻返回,此时后面那些相似度低的分词结果尚未出现。这样便大大降低了辨音的时间复杂度。
示例如图4示,其中虚线部分的分词结果程序没有执行到。
II.模板匹配
模板匹配的问题实际上就是判断一个样本属于哪个类的问题,用户提问句是待分析样本,查询模板库里的各个模板是各种提问形态的类别。
模板匹配的步骤如下:
对用户查询句子的某种相似分词结果,作以下处理。
1)首先根据各关键词在模板库里的位置索引,找到它们的出现空间,然后通过求交集得到该分词结果的样本出现空间。
2)对样本出现空间中的候选模板进行筛选,筛选的条件如下:
●分词结果中的变量个数=模板的变量个数
●模板的必要词个数<=分词结果总词数<=模板总词数
分词结果必须含有模板中所有的必要词,缺一不可,即{模板中的必要词位置序列}-{分词结果中各非变量词在模板中的位置序列}={分词结果中出现的所有变量}
●分词结果中各词出现次序和模板中各词出现次序一致。
这个条件决定是否有序匹配,考虑到用户提问的自由性,可以排除该条件来实现无序匹配。
根据这些条件的筛选我们得到了与该分词结果在形式上相匹配的候选模板集合。
III.知识验证
此时得到的候选模板还需要进行知识检查,我们根据模板对应的属性以及提问类型去调用相应的知识库API函数,看看能不能找到正确答案。
KAPI是我们开发的关于知识库操作的接口函数,为上层应用程序提供服务。常见KAPI的有:
∥根据概念和属性得到属性值
get_attribute_value(concept,attribute),简称getv(C,A)
∥根据属性和属性值得到概念
get_concepts(attribute,attribute_value),简称getc(A,C’)
∥得到一个概念所有的属性
get_all_attributes(concept)
∥isa推理,判断一个概念是不是另一个概念
isa_reasoning(concept1,concept2)
∥partof推理,判断一个概念是不是另一个概念的一部分
partof_reasoning(concept1,concept2)
IV.实验数据
我们以IBM ViaVoice2000作为语音识别接口,由多个没有经过任何语音训练的人在有噪声的环境下来朗读100个问题,图5列出了部分数据。实验数据表明经过辨音,错误率从原来的65%降低到12%,取得了满意的结果。