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

简介: 在 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 对象。

在 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);
        }
目录
相关文章
|
移动开发 机器学习/深度学习 安全
|
机器学习/深度学习 存储 人工智能
压缩大型语言模型(LLMs):缩小10倍、性能保持不变
尽管大规模语言模型(LLMs)在多种应用场景中表现出色,但其庞大的规模也带来了实际部署难题。本文探讨了通过模型压缩技术解决这些问题的方法,介绍了量化、剪枝和知识蒸馏三种主要压缩技术,并通过具体Python代码示例展示了如何将一个100M参数的文本分类模型压缩至52.8M参数,再通过4位量化进一步减小至原来的1/7,同时保持甚至提升性能。示例代码展示了从数据预处理、模型训练到评估的完整流程,证明了压缩技术的有效性。
749 6
|
机器学习/深度学习 网络协议 PyTorch
【文献学习】DCCRN: Deep Complex Convolution Recurrent Network for Phase-Aware Speech Enhancement
本文介绍了一种新的深度复数卷积递归网络(DCCRN),用于处理语音增强问题,特别是针对低模型复杂度的实时处理。
809 5
|
10月前
|
机器学习/深度学习 人工智能
《模型压缩与量化:提升性能与降低成本的关键策略》
在人工智能领域,模型压缩和量化是优化模型大小与性能的关键技术。模型压缩包括剪枝(去除不重要连接)、低秩近似(矩阵分解)和模型融合(合并多个模型),减少冗余并提高效率。量化则通过将参数从连续值转为离散值(如8位、16位),减小存储空间。这些方法能在不降低性能的前提下显著减小模型大小,适用于不同应用场景。未来研究将更注重性能与效率的平衡。
471 10
|
11月前
|
人工智能 文字识别 语音技术
Megrez-3B-Omni: 首个端侧全模态理解开源模型
Megrez-3B-Omni是由无问芯穹(Infinigence AI)研发的端侧全模态理解模型,基于无问大语言模型Megrez-3B-Instruct扩展,同时具备图片、文本、音频三种模态数据的理解分析能力。
611 3
Megrez-3B-Omni: 首个端侧全模态理解开源模型
|
IDE 开发工具 C++
qt creator + vs2019编译记录
本文记录了作者在使用qt creator和vs2019编译项目时遇到的困难和解决方案,包括编译环境设置、qt creator编译脚本的成功案例、不带Ninja的编译脚本问题、错误示范以及相关参考链接。
626 0
qt creator + vs2019编译记录
|
机器学习/深度学习 存储 监控
基于YOLOv8深度学习的智能车牌检测与识别系统【python源码+Pyqt5界面+数据集+训练代码】目标检测、深度学习实战
基于YOLOv8深度学习的智能车牌检测与识别系统【python源码+Pyqt5界面+数据集+训练代码】目标检测、深度学习实战
|
前端开发 小程序 JavaScript
基于Uniapp的体育场馆预约系统的设计与实现
`code袁`是一名热爱分享的在校大学生,专注于毕业设计、微信小程序和Vue开发。他提供了个人CSDN博客和QQ联系方式。文章介绍了体育场预约管理系统,采用前后端分离,前端Vue+Element,后端Node.js,数据库为MySQL。系统包括登录、预约和签到等功能,通过uniapp微信小程序和Web管理端实现。此外,还展示了部分代码和数据库设计。读者可以通过作者提供的链接获取更多源码信息。
306 0
基于Uniapp的体育场馆预约系统的设计与实现
|
Java Maven
(短信服务)java SpringBoot 阿里云短信功能实现发送手机验证码
(短信服务)java SpringBoot 阿里云短信功能实现发送手机验证码
3205 0
下一篇
oss云网关配置