内容


针对电话号码、缩略词和其他语音单词创建自动化语言交谈注释

使用自定义字典 Sphinx-4 和文本处理工具从交谈中提取相关数据

Comments

卡内基梅隆大学的 Sphinx 项目为开发人员和用户创建了开源语音识别工具。本文将使用 Sphinx-4 代码库为小型常用字母和数字字典提供自动识别。通过把语音信息转换为文本并处理具有特定数据结构的字符串(例如电话号码和缩略词),可以为语言交谈自动创建描述性注释。

此项目的应用领域之一是电话会议注释应用程序。下次参加开发会议时,请启动交谈注释程序,然后可以在发表会议演讲时根据电话号码自动查找个人,也可以根据 Web 搜索引擎查看最新的缩略词。您不必停止正在做的事情就可以输入会议中提到的最新缩略词或员工编号来查找相关数据。Sphinx-4 和本文构建的交谈注释程序可以为您完成大部分繁琐的工作。

要求

硬件

Sphinx 非常占用资源,因此,需要配备高速硬件才能有效利用该软件。必须配备大量专用内存才能提供有用性能,因此要求在至少配有 1 GB RAM 的 Intel® Pentium® 4-class 计算机上运行 Sphinx 应用程序。相比之下,文本处理的硬件要求微不足道,并且可以在同一台计算机上运行,而不会影响语音识别处理的性能。

软件

可以在运行 Linux® 或 Microsoft® Windows® 的硬件上运行本文中创建的应用程序。Sphinx-4 使用最新的 JDK 和 Apache Ant 来创建自定义语法处理器。需要使用 Perl 及相关的查找模块。要了解更多信息和下载要求的软件包,请参阅 参考资料 部分中的链接。

安装 Sphinx-4

Sphinx 提供了多种形式,可实现各种类型的语音识别和功能。本文将使用 Sphinx-4 包,这是最具用户友好性和开发人员友好性的最新版本。Sphinx-4 的安装较为严格,因此考虑安装说明中强调的重点步骤:

  1. 下载并解压缩 Apache Ant。
  2. 下载并解压缩 Sun JDK(撰写本文时,V1.6.0_02 是最新版本)。
  3. 下载并解压缩 Sphinx-4 源代码包,因为将修改其中一个演示程序来达到我们的目的。
  4. 用下列命令设置环境变量:
    export ANT_HOME=${PWD}/apache-ant-1.7.0
    export JAVA_HOME=${PWD}/jdk1.6.0_02
    export PATH=${PATH}:${ANT_HOME}/bin

    对于 Windows,可能需要在 Control Panel > System > Advanced > Environment variables 下设置环境变量。
  5. 切换到 sphinx4-beta 目录,然后切换到 lib 子目录。
  6. 通过运行 jsapi.sh shell 脚本激活 JSAPI 二进制许可证。Sphinx-4 将通过二进制许可证来提供对 JSAPI 的支持,因此需要接受协议。
  7. 可能要求您安装 uudecode 来解压缩 JSAPI 要求的组件。大多数 Linux 发行版都提供了以某种形式包含 uudecode 的包,因此如果需要安装 uudecode,请先考虑查看可用包。对于 Windows,双击 jsapi.exe 文件并接受许可证协议。
  8. 退出并切换到主 Sphinx4 目录。
  9. 运行 ant 命令,然后构建过程应当开始。

状态消息 “BUILD SUCCESSFUL” 表示您已经正确设置环境并且已经准备执行修改步骤。如果收到其他消息,请查看构建目录和环境变量,或者查阅 Apache Ant 和 Sphinx-4 文档以获得环境的详细安装说明。

从与说话者无关的语音中提取字母和数字的策略

要实现与说话者不相关的大型词汇表识别,语言识别技术还要 2 到 10 年的路要走。市场中现有的所有用户级软件几乎都不能记录会议中的多种语音,包括重叠语音、全球范围的口音及各种技术词汇表和口语词汇表。Sphinx 特别是 Sphinx-4 包提供了所有必需选项,可以在与说话者不相关的环境中可靠识别非常小(但仍然有用)的词汇表。

我们已经指定了有限的词汇表:字母 A 到 Z 及数字 0 到 9。我们的策略是仅提取说出这些字母或数字的所有位置。通常将这种方法称为单词定位(word spotting)。虽然 Sphinx-4 目前不支持单词定位,但是仍然可以通过强制所有发音至少在语法上匹配一个单词来获得有用的结果。有了通过猜测获得的字母和数字列表后,就可以应用标准文本处理工具和信息查找来提取有用信息。

自定义字典,修改 Hello World 示例

创建字典文件

创建 pseudo 单词定位设置的第一步是构建所需的字典文件。在 Sphinx-4 字典树中,有一个名为 bld/models/edu/cmu/sphinx/model/acoustic/WSJ_8gau_13dCep_16k_40mel_130Hz_6800Hz/dict/ 的目录。此目录包含 alpha.dict 和 digit.dict 字典文件。乍看之下,结合这两个字典文件似乎将生成所需文件。但是,事实并非如此,因为我们需要通过同一个目录中的 cmudict.0.6d 文件构建字典文件。

切换到 bld/models/edu/cmu/sphinx/model/acoustic/WSJ_8gau_13dCep_16k_40mel_130Hz_6800Hz/dict/ 目录并发出下列命令构建所需字典文件:

perl -ne 'print if( /^[A-Z]\ / )'                       cmudict* >  alN.dict
perl -ne 'print if(/^(ZERO|ONE|TWO|THREE|FOUR)[ (]/)'   cmudict* >> alN.dict
perl -ne 'print if(/^(FIVE|SIX|SEVEN|EIGHT|NINE)[ (]/)' cmudict* >> alN.dict

清单 1 显示了用简单字母和数字作为字典惟一内容创建的 alN.dict 文件。

清单 1. alN.dict 字典文件中的片段
...
W                    D AH B AH L Y UW
X                    EH K S
Y                    W AY
Z                    Z IY
FOUR                 F AO R
ONE                  HH W AH N
ONE(2)               W AH N
THREE                TH R IY
...

修改 Hello World 示例

Sphinx-4 提供了许多配置选项,几乎可以满足语音识别领域中的所有需求。出于演示目的,最有效的方法是简单地修改现有 Hello World 示例。在 Sphinx-4 根目录下,切换到 demo/sphinx/helloworld 目录,然后编辑 helloworld.config.xml 文件。清单 2 显示了一行更改,以使用我们构建的 alN.dict 字典文件。

清单 2. helloworld.config.xml 更改
original (line 114):
        <property name="dictionaryPath"
   value="resource:/edu.cmu.sphinx.model.acoustic.WSJ_8gau_13dCep_16k_40mel_130Hz_6800Hz.
Model!/edu/cmu/sphinx/model/acoustic/WSJ_8gau_13d
Cep_16k_40mel_130Hz_6800Hz/dict/cmudict.0.6d"/>

new:
        <property name="dictionaryPath"
   value="resource:/edu.cmu.sphinx.model.acoustic.WSJ_8gau_13dCep_16k_40mel_130Hz_6800Hz.
Model!/edu/cmu/sphinx/model/acoustic/WSJ_8gau_13d
Cep_16k_40mel_130Hz_6800Hz/dict/alN.dict"/>

还必须对同一个目录中的 hello.gram 语法文件进行修改。清单 3 显示的更改可以只提取字典文件中的字母和数字。

清单 3. hello.gram 更改
original:
public <greet> = (Good morning | Hello) 
( Bhiksha | Evandro | Paul | Philip | Rita | Will );

new:
public <greet> = ( zero | one | two | three | four | five | six |seven | eight | nine | 
a | b | c | d | e | f | g | h | i | j | k | l | m | n | o | p | q | r | s | t | u | v | 
w | x | y | z) * ;

还需要对 HelloWorld.java 文件进行修饰性更改,如下所示:

清单 4. HelloWorld.java 更改
original (line 59):
    System.out.println
        ("Say: (Good morning | Hello) " +
                     "( Bhiksha | Evandro | Paul | Philip | Rita | Will )");

new:
    System.out.println
        ("Listening for letters and numbers");

完成以上更改后,可以构建并运行修改后的示例。更改 Sphinx-4 主目录并发出命令 ant(“BUILD SUCCESSFUL” 消息将使您了解到更改是否正确)。对于 Linux,用 $JAVA_HOME/bin/java -mx312m -jar bin/HelloWorld.jar 命令运行更新后的示例。对于 Windows,命令为:java -mx312m -jar bin/HelloWorld.jar。朗读 “The phone number for IBM tech support is one eight zero zero four two six seven three seven eight”,然后应当看到类似如下所示的输出:

f o nine r four i b m x a four t one eight zero zero four two six seven three seven eight

文本处理

可以看到,发出声音的句子被处理为字母和数字,但并不完全正确。字母 “IBM” 和电话号码中的数字将被正确识别,但是句子的其余部分将被错误地归类为最佳匹配特定声音的各个字母和数字。

您可能想知道:为什么不简单地使用包括几千个单词的字典来识别那些错误的最佳猜测?毕竟,Sphinx-4 提供了大型词汇表字典和语言模型。为什么不将演示示例配置为识别其余部分:“The phone number for tech support is” 和可能说出的任何其他单词?

答案是因为 Sphinx-4 十分优秀,但并不完美。扩展字典文件来识别成百上千的单词将大大降低简单数字和字符匹配的效率。您可以通过检验 Sphinx-4 “demo” 目录中的某些其他程序,或者通过把现有示例修改为使用大型字典文件和扩展语法列表,亲自测试这一点。要使用开源系统开发实用的注释系统,对只有字母和数字组成的文本进行后处理以获得更有条理的数据,这种方法更加简便。

遵循两个简单规则,从输出文本中提取缩略词和电话号码将变得相对简单:任何三个连续字母都被视为缩略词,而任何五个或更多的连续数字都被视为电话号码。清单 5、6、7 将显示执行这些提取和查找的 annotateAcrNum.pl 程序的组成部分:

清单 5. annotateAcrNum.pl 的第 1 部分 —— 主程序逻辑
#!/usr/bin/perl -w
# annotateAcrNum.pl - extract and lookup acronyms and numbers from speech 
#                     recognition text output
use strict;
use Yahoo::Search;
use Net::Dict;
$|=1;  # non buffered output for better user feedback

my %numHash =
("zero" => "0",
"one"   => "1",
"two"   => "2",
"three" => "3",
"four"  => "4",
"five"  => "5",
"six"   => "6",
"seven" => "7",
"eight" => "8",
"nine"  => "9" );

while( my $line = <STDIN> )
{
  print "$line" if( $line =~ /(Start|You said:)/ );

  next unless ( $line =~ /You said:/ );
  my @words = split " ", substr($line,9);  # ignore the "You said:" prefix

  my @numArr = ();
  my @letArr = ();

  foreach my $chunk ( @words )
  {
    if( length($chunk) == 1 )
    { 
      phoneNmSearch(@numArr) if( @numArr > 4 );
      @numArr = ();

      push @letArr, $chunk;

      if( @letArr > 2 )
      { 
        acronymSearch( @letArr );
        shift( @letArr );
      }

    }elsif( length($chunk) > 1 )
    { 
      push @numArr, $numHash{$chunk};
      @letArr = ();
    }#if length greater
  }#for each word

  phoneNmSearch( @numArr ) if( @numArr > 4 );
  acronymSearch( @letArr ) if( @letArr > 2 );

}#while stdin

上面的主程序逻辑将搜索匹配简单标准的字母和数字字符串。对于修改后的 Hello World 代码输出的每行语音识别文本,构建只有字母和数字的独立数组。使用如下所示的 acronymSearch 子例程搜索字母数组。注意,每执行完一次缩略词查找后都轮换字母数组中字母的位置,以便从字符串 “i b m x” 中搜索 “ibm” 和 “bmx”。数字数组不执行这种位置轮换,而是获取可以找到的最大数字并执行 Web 搜索。

清单 6. annotateAcrNum.pl 的第 2 部分 —— acronymSearch
sub acronymSearch
{
  my $dict = Net::Dict->new('dict.org');

  my $str = @_; $str =~ s/ //g;

  my $eref = $dict->define($str);
  next if ($eref eq "" );
  foreach my $entry (@$eref)
  {   
      my ($db, $definition) = @$entry;
      next if (   !(defined($definition)) || !(defined($db))  );
      if( $db =~ /(wn|vera|gazetteer|foldoc)/ ){ print "$db: $definition\n" }
  }#for each definition

}#acronymSearch

子例程 acronymSearch 将使用有用的 Net::Dict 模块。只需指定字典服务器和查询就可以在大量可用数据库中进行查找。正则表达式 /(wn|vera|gazetteer|foldoc)/ 将把打印输出限定到提供相关简要描述的那些数据库。您会发现使用在 dict.org 中获得的其他数据库可以更好地表示缩略词空间,这需要删除正则表达式限制程序。

清单 7. annotateAcrNum.pl 的第 3 部分 —— phoneNmSearch
sub phoneNmSearch
{
  my $str = @_; $str =~ s/ //g;
  if( length($str) == 11 )
  {
    $str =~ /(\d)(\d\d\d)(\d\d\d)(\d\d\d\d)/;
    $str = "$1-$2-$3-$4\n";
  }elsif( length($str) == 10 )
  {
    $str =~ /(\d\d\d)(\d\d\d)(\d\d\d\d)/;
    $str = "$1-$2-$3\n";
  }elsif( length($str) == 7 )
  {
    $str =~ /(\d\d\d)(\d\d\d\d)/;
    $str = "$1-$2\n";
  }
  print "Results for: $str\n";

  my @results = Yahoo::Search->Results(Doc => "$str", AppId => "PhNmLookup" );
  warn $@ if $@; # report any errors
  
  my $recCount = 0;
  for my $res (@results)
  {   
      print "Title: ", $res->Title, " \n";
      print $res->Summary, "\n";
      print $res->Url, "\n";
      print "\n";
      last if( $recCount > 1 ); # print first 3 results only
      $recCount++;
  }#for each result

}#phoneNmSearch

对于某些搜索引擎,可以通过向电话号码数字添加格式来获得更准确的搜索结果。例如,把 18004267378 改为 1-800-426-7378 或者把 4152042 改为 415-2042 将由 phoneNmSearch 子例程的第一部分来执行。这个稍微修改过的电话号码随后在 Yahoo! 搜索参数中用作查询,使用便捷的 Jeffrey Friedl Yahoo::Search Perl 模块。

使用自定义 Sphinx-4 语音识别和 annotateAcrNum Perl 程序,您现在可以开始对语音交谈进行注释。对于 Linux,用命令 $JAVA_HOME/bin/java -mx312m -jar bin/HelloWorld.jar | perl annotateAcrNum.pl 运行注释程序。对于 Windows,命令为 java -mx312m -jar bin/HelloWorld.jar | perl annotateAcrNum.pl

图 1 显示 “Terminal” 在 Vector Linux 中的注释程序设置输出。注意,带下划线的链接文本可用于根据 Web 搜索结果启动页面。

图 1. Terminal 在 Vector Linux 中的交谈注释程序屏幕快照
Terminal 在 Vector Linux 中的交谈注释程序屏幕快照
Terminal 在 Vector Linux 中的交谈注释程序屏幕快照

结束语

本文中选择的查询和数据库类型只是注释的一般示例。您会发现使用 Google 进行 Web 搜索查找更加有效,或者可以把电话号码查找与员工通讯录联系起来。同样,也可将这些方法用于从识别出的字母和数字中提取更有条理的数据。交谈可能更多地集中在 IP 地址或者员工编号上。使用上述的一些技术,可以提取 IP 地址和惟一标识符,并把查找与您自己的数据库联系起来。

Sphinx-4 还提供了多种方法增强语音识别效率。考虑为您和团队成员创建专门制作的声音模型来提供更高的准确率。扩展字典文件来包括大量常用口语词汇并测试 Sphinx-4 的实时转录质量。


下载资源


相关主题


评论

添加或订阅评论,请先登录注册

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=10
Zone=Open source
ArticleID=286702
ArticleTitle=针对电话号码、缩略词和其他语音单词创建自动化语言交谈注释
publish-date=02042008