美文网首页
kaldi 源码分析(九) - topo 文件分析

kaldi 源码分析(九) - topo 文件分析

作者: 走在成长的道路上 | 来源:发表于2018-08-30 11:26 被阅读0次

    在 egs/wsj/s5/steps/nnet3/chain/gen_topo*.py 与 src/hmm/hmm-topology.cc 文件进行对应

    在 gen_topo*.p{l, y} 文件中进行自动创建 topo 文件, 然后在 hmm-topology.cc 文件中的 HmmTopology::Read() 函数中解析 topo 文件生成 HmmTopology 对象。

    在 steps/nnet3/chain/gen_topo*.p{l, y} 文件中可以看到 topo 文件大致结构:

    
    args = parser.parse_args()
    
    silence_phones = [ int(x) for x in args.silence_phones.split(":") ]
    nonsilence_phones = [ int(x) for x in args.nonsilence_phones.split(":") ]
    all_phones = silence_phones +  nonsilence_phones
    
    print("<Topology>")
    print("<TopologyEntry>")
    # 当前 TopologyEntry 配置相关的所有 Phone 元素
    print("<ForPhones>")
    print(" ".join([str(x) for x in all_phones]))
    print("</ForPhones>")
    # 当前 State 配置相关
    # state 0 is nonemitting
    print("<State> 0 <Transition> 1 0.5 <Transition> 2 0.5 </State>")
    # state 1 is for when we traverse it in 1 state
    print("<State> 1 <PdfClass> 0 <Transition> 4 1.0 </State>")
    # state 2 is for when we traverse it in >1 state, for the first state.
    print("<State> 2 <PdfClass> 2 <Transition> 3 1.0 </State>")
    # state 3 is for the self-loop.  Use pdf-class 1 here so that the default
    # phone-class clustering (which uses only pdf-class 1 by default) gets only
    # stats from longer phones.
    print("<State> 3 <PdfClass> 1 <Transition> 3 0.5 <Transition> 4 0.5 </State>")
    print("<State> 4 </State>")
    print("</TopologyEntry>")
    print("</Topology>")
    
    

    在 hmm-topology.h 文件中

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

    对于 HmmTopology::Read() 函数中可以了解 topo 文件解析的过程

            ExpectToken(is, binary, "<ForPhones>");
            std::vector<int32> phones;
            std::string s;
            // 获取所有 phones 列表
            while (1) {
              is >> s;
              if (is.fail()) KALDI_ERR << "Reading HmmTopology object, unexpected end of file while expecting phones.";
              if (s == "</ForPhones>") break;
              else {
                int32 phone;
                if (!ConvertStringToInteger(s, &phone))
                  KALDI_ERR << "Reading HmmTopology object, expected "
                            << "integer, got instead " << s;
                phones.push_back(phone);
              }
            }
            // 构建状态转换概率
            std::vector<HmmState> this_entry;
            std::string token;
            ReadToken(is, binary, &token);
            while (token != "</TopologyEntry>") {
              if (token != "<State>")
                KALDI_ERR << "Expected </TopologyEntry> or <State>, got instead "<<token;
              int32 state;
              ReadBasicType(is, binary, &state);
              if (state != static_cast<int32>(this_entry.size()))
                KALDI_ERR << "States are expected to be in order from zero, expected "
                          << this_entry.size() <<  ", got " << state;
              ReadToken(is, binary, &token);
              int32 forward_pdf_class = kNoPdf;  // -1 by default, means no pdf.
              if (token == "<PdfClass>") {
                // 根据 pdfClass 来创建一个 HmmState
                ReadBasicType(is, binary, &forward_pdf_class);
                this_entry.push_back(HmmState(forward_pdf_class));
                ReadToken(is, binary, &token);
                if (token == "<SelfLoopPdfClass>")
                  KALDI_ERR << "pdf classes should be defined using <PdfClass> "
                            << "or <ForwardPdfClass>/<SelfLoopPdfClass> pair";
              } else if (token == "<ForwardPdfClass>") {
                // 根据 <ForwardPdfClass> <SelfLoopPdfClass> 组合, 来创建一个 HmmState
                int32 self_loop_pdf_class = kNoPdf;
                ReadBasicType(is, binary, &forward_pdf_class);
                ReadToken(is, binary, &token);
                KALDI_ASSERT(token == "<SelfLoopPdfClass>");
                ReadBasicType(is, binary, &self_loop_pdf_class);
                this_entry.push_back(HmmState(forward_pdf_class, self_loop_pdf_class));
                ReadToken(is, binary, &token);
              } else {
                // 若 <State> 后没有 <PdfClass>, <ForwardPdfClass> , 则添加 kNoPdf 的 HmmState
                this_entry.push_back(HmmState(forward_pdf_class));
              }
              while (token == "<Transition>") {
                int32 dst_state;
                BaseFloat trans_prob;
                ReadBasicType(is, binary, &dst_state);
                ReadBasicType(is, binary, &trans_prob);
                // 获取最后一个 HmmState 状态 并将 transitions 中配置 状态切换的概率
                this_entry.back().transitions.push_back(std::make_pair(dst_state, trans_prob));
                ReadToken(is, binary, &token);
              }
              if(token == "<Final>") // TODO: remove this clause after a while.
                KALDI_ERR << "You are trying to read old-format topology with new Kaldi.";
              if (token != "</State>")
                KALDI_ERR << "Reading HmmTopology,  unexpected token "<<token;
              ReadToken(is, binary, &token);
            }
            int32 my_index = entries_.size();
            // entries_ 中为 TopologyEntry 列表
            entries_.push_back(this_entry);
    
            // 注意: 这里将所有涉及的 phones 通过 phone2idx 数组将 phone 与 my_index 进行对应起来,这样获取 phone 的状态相关的 HmmState
            for (size_t i = 0; i < phones.size(); i++) {
              int32 phone = phones[i];
              if (static_cast<int32>(phone2idx_.size()) <= phone)
                phone2idx_.resize(phone+1, -1);  // -1 is invalid index.
              KALDI_ASSERT(phone > 0);
              if (phone2idx_[phone] != -1)
                KALDI_ERR << "Phone with index "<<(i)<<" appears in multiple topology entries.";
              // 这里将每个 phone 相关的 HmmState 切换过程TopologyEntry的 index 设置到 phone2idx 中
              phone2idx_[phone] = my_index;
              phones_.push_back(phone);
            }
    

    相关文章

      网友评论

          本文标题:kaldi 源码分析(九) - topo 文件分析

          本文链接:https://www.haomeiwen.com/subject/jzqrwftx.html