本文共 4472 字,大约阅读时间需要 14 分钟。
在 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_phonesprint("")print(" ")")# 当前 TopologyEntry 配置相关的所有 Phone 元素print(" ")print("")print(" ".join([str(x) for x in all_phones]))print(" ")# 当前 State 配置相关# state 0 is nonemittingprint("0 ")# state 1 is for when we traverse it in 1 stateprint("1 0.5 2 0.5 1 ")# state 2 is for when we traverse it in >1 state, for the first state.print("0 4 1.0 2 ")# 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("2 3 1.0 3 ")print("1 3 0.5 4 0.5 4 ")print("
在 hmm-topology.h 文件中
/// TopologyEntry is a typedef that represents the topology of /// a single (prototype) state. typedef std::vectorTopologyEntry;
对于 HmmTopology::Read() 函数中可以了解 topo 文件解析的过程
ExpectToken(is, binary, ""); std::vector ") break; else { int32 phone; if (!ConvertStringToInteger(s, &phone)) KALDI_ERR << "Reading HmmTopology object, expected " << "integer, got instead " << s; phones.push_back(phone); } } // 构建状态转换概率 std::vectorphones; 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 == " this_entry; std::string token; ReadToken(is, binary, &token); while (token != "") { if (token != " ") KALDI_ERR << "Expected or , got instead "< (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 来创建一个 HmmState ReadBasicType(is, binary, &forward_pdf_class); this_entry.push_back(HmmState(forward_pdf_class)); ReadToken(is, binary, &token); if (token == " ") KALDI_ERR << "pdf classes should be defined using " << "or / pair"; } else if (token == " ") { // 根据 组合, 来创建一个 HmmState int32 self_loop_pdf_class = kNoPdf; ReadBasicType(is, binary, &forward_pdf_class); ReadToken(is, binary, &token); KALDI_ASSERT(token == " "); ReadBasicType(is, binary, &self_loop_pdf_class); this_entry.push_back(HmmState(forward_pdf_class, self_loop_pdf_class)); ReadToken(is, binary, &token); } else { // 若 后没有 ") KALDI_ERR << "Reading HmmTopology, unexpected token "<, , 则添加 kNoPdf 的 HmmState this_entry.push_back(HmmState(forward_pdf_class)); } while (token == " ") { 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 == " ") // TODO: remove this clause after a while. KALDI_ERR << "You are trying to read old-format topology with new Kaldi."; if (token != " (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); }
转载地址:http://xtwuo.baihongyu.com/