kaldi中的hmm-topology介绍

kaldi中的hmm-topology介绍

kaldi中是对音素进行建模,使用HMM模型。一般情况下每个音素有3个状态,每个状态有2个弧。静音音素sil可能有5个状态,且每个状态可能不止2个弧。

kaldi中音素的HMM模型的topo文件,一般是由脚本utils/gen_topo.pl生成。一个示例如下:

<Topology>
<TopologyEntry>
<ForPhones> 1 2 3 4 5 6 7 8 </ForPhones>
<State> 0 <PdfClass> 0
<Transition> 0 0.5
<Transition> 1 0.5
</State>
<State> 1 <PdfClass> 1
<Transition> 1 0.5
<Transition> 2 0.5
</State>
<State> 2 <PdfClass> 2
<Transition> 2 0.5
<Transition> 3 0.5
</State>
<State> 3
</State>
</TopologyEntry>
</Topology>
上面的示例topo文件,描述了音素1、2、3、4、5、6、7和8这8个音素的拓扑结构。它们这8个音素的拓扑结构是一模一样的,都是3个状态,序号为0到2;最后一个3状态是结束状态,或叫“非发射状态”。


hmm-topology.h文件中定义了类HmmTopology,用来表示所有音素的topo结构。这个类是比较简单和形象的。这里给出类的定义。
注意:这里对源代码进行了修改,以方面阅读和理解
class HmmTopology {
 public:
  /// A structure defined inside HmmTopology to represent a HMM state.
  struct HmmState {
    int32 forward_pdf_class;
    int32 self_loop_pdf_class;
    std::vector<std::pair<int32, BaseFloat> > transitions;

    HmmState(): forward_pdf_class(-1), self_loop_pdf_class(-1) { }
    HmmState(int32 i): forward_pdf_class(i), self_loop_pdf_class(i) { }
  };

  /// TopologyEntry is a typedef that represents the topology of
  /// a single (prototype) state.
  typedef std::vector<HmmState> TopologyEntry;

  void Read(std::istream &is, bool binary);
  void Write(std::ostream &os, bool binary) const;

  /// Returns the topology entry (i.e. vector of HmmState) for this phone;
  /// will throw exception if phone not covered by the topology.
  const TopologyEntry &TopologyForPhone(int32 phone) const{
    return entries_[phone2idx_[phone]];
  }

  HmmTopology() {}

 private:
  std::vector<int32> phones_;  // list of all phones we have topology for.  Sorted, uniq.  no epsilon (zero) phone.
  std::vector<int32> phone2idx_;  // map from phones to indexes into the entries vector (or -1 for not present).
  std::vector<TopologyEntry> entries_;
};
可以看出来,这个类其实是很简单的。
音素的HMM结构,在被指定之后,在后面的训练或者解码过程中,都不会再改变。所以这里也只要理解成员变量的意义,能看懂最基本的读和写函数已经基本的使用就可以了。
HmmTopology的成员变量很少,只有3个。phones_存放了音素,phone2idx是个索引表,根据这个索引表,能找到音素的拓扑结构。通过阅读上面的TopologyForPhone函数可以清楚看出其作用。entries_存放了具体的拓扑结构。就像上面的例子一样,8个音素的拓扑结构是一模一样的,所以entries_中,只要存放一份拓扑结构就可以了,这个是所有音素共享的。
如果用一个图来表示上面例子中的topo在类中的样子,可以看下图。


几个问题的说明:
1、为什么HmmState中的pdf_class有两个。
在早先版本的kaldi中,是只有一个pdf_class的。后来为了支持更复杂的一些hmm结构,就设计为了两个pdf_class。不过,对于一般的情况,跑普通的gmm-hmm模型,跑tdnn等,完全不用担心。这两个pdf_class的值是完全一样的。

2、HmmState中的transitions中,给出了下一跳的概率,这个值会随着训练而不断更新吗?
不会。这个概率值只在初始化的时候使用一次,今后不再使用。训练生成的新的转移概率,会保存在transition-model中。

--------------------- 
作者:shzyiwai 
来源:CSDN 
原文:https://blog.csdn.net/u013677156/article/details/79133123 
版权声明:本文为博主原创文章,转载请附上博文链接!

猜你喜欢

转载自blog.csdn.net/lbaihao/article/details/84855129
HMM