编译概述

编译流程将Nnet和ComputationRequest作为输入,输出NnetComputation。ComputationRequest包含可用的输入索引
以及
请求的输出索引。

不提供输出索引并让编译器找出需要的输入索引的原因是,某些网络,比如RNNs,为输出给定输出,可能会消耗任意数量的输入特征

 
 

struct ComputationRequest包含除Nnet之外计算所需的所有数据。该结构体用于创建Computation。

ComputationRequest中最重要的信息是:

  1. 各个输入结点处提供的可用索引;
  2. 各个输出节点处请求的索引;
  3. 是否要执行反向传播;

相同的输入结点不能在IoSpecification数组input中出现两次,输出结点亦然;

 
 

创建计算图

详述ComputationGraph

 
 

为了提高效率,ComputationGraph会将Cindex映射为cindex_id,反之亦然。

 
 

ComputationGraph类的定义如下:

struct ComputationGraph {

//cindex_id到Cindex的映射

std::vector<Cindex> cindexes;

 
 

//is_input[cindex_id]表示cindex_id对应的Cindex是否在输入中是可用的

std::vector<bool> is_input;

 
 

// dependencies[cindex_id]表示计算cindex_id所依赖的其他cindex_id列表

std::vector<std::vector<int32> > dependencies;

private:

//Cindex到cindex_id的映射

// 必须通过GetCindexId()函数来调用

unordered_map<Cindex, int32, CindexHasher> cindex_to_cindex_id_;

};

 
 

dependencies成员的确切意义依赖于编译阶段。

在编译的初始阶段,dependencies包含函数Descriptor::GetDependencies()返回的Cindexes对应的所有cindex_ids。

之后,对dependencies进行修剪,只保留在实际计算中使用到的cindex_ids。

 
 

注意,与Descriptor类似的,Component也有GetDependencies()以及IsComputable()函数。然而,当且仅当Component是GeneralComponent时才有用。

 
 

创建计算图——ComputationGraph

详述计算图

 
 

ComputationGraphBuilder用于构建ComputationGraph。对于一个最简单的例子,从网络请求的输出开始,并沿着网络向前计算其依赖,并添加到ComputationGraph中,直至计算到输入结点。

研究所实习时,为现有DNN添加一输出层后,脚本得出无法计算的结论,就是依赖于此)。

 
 

基础算法

本算法不实际使用。

构建计算图时,需要使用如下算法来确定每个Cindex是否可以从提供的输入计算得到:

  • 调用Descriptor::GetDependencies()得到输出层处的所有依赖项;
  • 调用IsComputable()确定输入中哪些Cindexes可以用于计算,对实际不参与计算的依赖关系进行修剪
  • 检查所有请求的输出都是可计算的
  • 修脚掉所有不需要参与计算的cindex_ids

 
 

将计算组织为多步

根据拓扑顺序对Cindex排序并分组,使同组Cindexes可同时计算。

 
 

使用该算法的动机

ComputationGraphBuilder接口

 
 

 
 

将网络计算组织为一系列的步骤

介绍计算步骤序列

一旦有了计算图,那么原则上就有足够的信息来执行计算了。可以对计算图中的Cindexes以拓扑顺序排序,可以依赖关系作为输入,以单独计算每个Cindex。不幸的是,这并不十分有效,因为进行的矩阵操作不能发挥全部效率,除非矩阵相当大;使用GPU时尤其如此。所以需要将多个Cindexes合为一个批次(batch),这样同一batch中的Cindex可以同时计算。该batch被称为一个步骤step),大致对应于NnetComputation中的一个命令。

 
 

接下来将计算中所有的cindex_ids划分为一个step序列

step序列有以下属性:

  1. 给定step中所有cindex_ids对应于计算图中的一个节点(component-node)
  2. 给定step中所有cindex_ids的所有依赖以及在之前的step中计算完成了

 
 

step序列还需要满足一些额外的、模糊的属性:

  1. ComputationRequest中的任何输入Cindex或输出Cindex必须在一个step中,step序列中索引的顺序与ComputationRequest中指定的顺序相同。(注意:输入可以是kComponent或kInput类型的节点)。
  2. 如果一个step对应于kComponent类型的节点(并且不对应于ComputationRequest中的输入),那么紧接着的下一个step必须对应于kDescriptor类型的节点,并且这两个step中的索引序列必须是相同的。
  3. 如果一个step对应于kDimRange类型的节点,则必须有另一个对应与源节点的step,这两个step中的索引和顺序完全相同。(这允许我们为kDimRange节点使用子矩阵)

 
 

规则b是确保Component可以直接以Descriptor的输出作为其输入,而无需任何额外的重排或重组(因为按照设计,这样的重排或重组需要Descriptor来完成)。由于这个规则,原则上,一个来自于kDescriptor节点的cindex_id可以出现在多个step中,尽管这只有在使用非简单组件时才会发生。此外,为了确保满足规则c,我们偶尔可能需要在计算图中添加新的cindex_ids。

 
 

创建计算步骤序列(基础算法)

这里,介绍一个用于创建step序列的基本算法(但不实际使用),只用于为稍后介绍的实际算法做铺垫。这个基本算法分为以下几步:

  • 首先保留对应于输入和输出节点的Cindex;将它们按节点索引分开;将这些step按照ComputationRequests中相同顺序排序。
  • 接下来处理非输入或输出的中间Cindex:
    • 将中间Cindex按神经网络层的依赖关系划分为多个"阶段"(phase,其中第一个phase包含仅依赖于输入的所有Cindex;并且通常第n阶段包含仅依赖于小于第n个phase的Cindex
    • 从每个phase移除所有不对应于kComponent节点的Cindexes(这些Cindexes将在稍后处理)。
    • 使用struct Index的排序运算符对step进行排序。
    • 按如下方式创建component-input(组件输入)节点的step
      • 对于kComponent类型的每个step,使用ComputationGraph的dependencies成员计算其所依赖的Cindex的集合。
      • 使用struct Index的排序运算符对上述每个step的集合进行排序。(对于简单的组件,这确保它们与组件的输出的顺序相同)。
      • (模糊特征):此时非简单组件的输入进行重排(如果需要);具体请参阅Component::ReorderIndexes()。
      • 将该组件输入节点的step防止在Component的对应step之前。
    • 按如下方式创建dim-range节点的step
      • 从网络图中取对应于dim-range节点的所有Cindex,并得出其输入所属的step
      • 注意,对于每个现有step,拥有Cindex的dim-range节点的集合从该step中获取输入。
      • 对于每个现有步骤s,对于拥有从该step获取输入的现有Cindex的每个dim-range节点,创建包含与step s相同的索引序列的step,并将新step放在step s之后。
  • 对所有step排序:输入step、中间step、输出step

 
 

上述算法最终将将它最终将Cindexes分成许多step

例如,假设我们有一个RNN层,后接一个标准的前馈层。RNN层必须将Cindexs分成与时间索引一样多step,但是上述算法也会将完连接层的计算分成多个step,因为RNN输出Cindexes后,全连接层对应的Cindexes就立即可计算。我们希望能够先完成RNN层的所有计算,然后再完成全连接层的计算。

 
 

创建计算步骤序列(实际算法)

class Compiler

介绍class Compiler

创建网络计算

设定位置信息

检查是否需要梯度

计算StepInfo

计算input_output_info

分配矩阵空间

前向计算

反向计算

释放矩阵空间

添加调试信息

快捷编译

Kaldi版本5.1提供的功能,并默认启用。

条件是:

  1. ComputationRequest中有两个以上不同的"n"索引;
  2. 对于每个索引,请求的"t"和"x"索引是相同且有序的

 
 

和1);

编译mini_request,得到mini_computation

根据mini_computation,将所有原始计算请求的编译结果推导出来;

 
 

快捷方式编译能显着缩短编译时间。

nnet3配置中的“编译”的更多相关文章

  1. nnet3配置中的上下文和chunk(块)大小

    Nnet3配置中的上下文和块大小 简介 本页讨论了nnet3配置中关于解码和训练的块大小以及左右上下文的某些术语.这将有助于理解一些脚本.目前,从脚本角度来看,没有任何关于nnet3的"概述 ...

  2. 如何在MyEclipse中配置jre的编译运行环境

    由于在MyEclipse中已经自带了jre编译环境,但由于版本太低,所以有时候需要将编译环境配置为系统的jre版本.在MyEclipse中配置jre的编译运行环境很简单,只需要全局配置一次,则所有项目 ...

  3. Webpack 2 视频教程 019 - Webpack 2 中配置多页面编译

    原文发表于我的技术博客 这是我免费发布的高质量超清「Webpack 2 视频教程」. Webpack 作为目前前端开发必备的框架,Webpack 发布了 2.0 版本,此视频就是基于 2.0 的版本讲 ...

  4. 如若已在管理后台更新域名配置,请刷新项目配置后重新编译项目,操作路径:“项目-域名信息” http://www.mysite.com 不在以下 request 合法域名列表中

    报错如图 报错文字如下: 如若已在管理后台更新域名配置,请刷新项目配置后重新编译项目,操作路径:“项目-域名信息” http://www.mysite.net 不在以下 request 合法域名列表中 ...

  5. GDAL1.9.1 IN VS2008 C#中的编译及使用

    下载gdal1.9.1到官网:http://www.gdal.org/ GDAL库的简洁.高效深受开发人员的喜爱,很多开源的GIS软件甚至是商业GIS软件都使用了这个库.GDAL使用C++,在Visu ...

  6. Ubuntu下安装并配置VS Code编译C++

    作者:tongqingliu 转载请注明出处:http://www.cnblogs.com/liutongqing/p/7069091.html Ubuntu下安装并配置VS Code编译C++ 安装 ...

  7. Openfire4源码部署到eclipse中并编译

    Openfire4源码部署到eclipse中并编译 概述 Openfire是众所周知的基于xmpp协议的IM开源服务,所有操作,配置,监控,调试等以B/S方式进行展示,非常的方便管理员进行管理.它的强 ...

  8. jenkins自动部署应用到tomcat中,编译后shell脚本的简单示例

    jenkins的安装这里就不做描述了,很简单的  百度搜索一下即可 这里安装的jenkins-2.39-1.1 wget http://pkg.jenkins-ci.org/redhat/jenkin ...

  9. Windows下为 Eclipse 配置 C/C++ 编译环境(转)

    1.Eclipse及CDT的安装 CDT的全称是C/C++ DevelopmentTools,CDT使得Eclipse能够支持C/C++的开发.直接下载 eclipse CDT 集成版 下载地址:ht ...

随机推荐

  1. Nginx负载均衡的4种方式 :轮询-Round Robin 、Ip地址-ip_hash、最少连接-least_conn、加权-weight=n

    这里对负载均衡概念和nginx负载均衡实现方式做一个总结: 先说一下负载均衡的概念: Load Balance负载均衡是用于解决一台机器(一个进程)无法解决所有请求而产生的一种算法. 我们知道单台服务 ...

  2. 网络安全实验室--SQL注入关

    第一关 万能密码:username='or '1'='1'#    password=1    即可登录得到flag. 第二关 最基础的注入,order by 判断字段数,然后 union selec ...

  3. 洛谷P4057

    题目描述 “无体育,不清华”.“每天锻炼一小时,健康工作五十年,幸福生活一辈子” 在清华,体育运动绝对是同学们生活中不可或缺的一部分.为了响应学校的号召,模范好学生王队长决定坚持晨跑.不过由于种种原因 ...

  4. linux 下一些命令

    1. 后台执行命令 nohup  http://blog.csdn.net/liuyanfeier/article/details/62422742 2. 查看日志文件 格式:tailf logfil ...

  5. codeforces#439 D. Devu and his Brother (二分)

    题意:给出a数组和b数组,他们的长度最大1e5,元素范围是1到1e9,问你让a数组最小的数比b数组最大的数要大需要的最少改变次数是多少.每次改变可以让一个数加一或减一 分析:枚举a数组和b数组的所有的 ...

  6. GET与POST类型接口

    工作当中经常用到这两种类型的接口,一直对它们两个的区别一知半解,并不能从原理上说出区别. GET和POST最直观的区别应该就是GET将url包含在参数当中,POST通过request body(请求主 ...

  7. 利用Python中SocketServer 实现客户端与服务器间非阻塞通信

    利用SocketServer模块来实现网络客户端与服务器并发连接非阻塞通信 版权声明 本文转自:http://blog.csdn.net/cnmilan/article/details/9664823 ...

  8. 【LR9】【LOJ561】CommonAnts 的调和数 数论 筛法

    题目大意 有一个长度为 \(n\) 的序列. 有 \(m\) 次修改,每次给你 \(x,y\),令 \(\forall 1\leq i\leq \lfloor\frac{n}{x}\rfloor,a_ ...

  9. JSON.stringify() 和 JSON.parse()

    stringify()用于从一个对象解析出字符串,如 var obj = {x: 1, y: 2 } console.log(JSON.stringify(obj)) //{"x" ...

  10. CAN总线报文浅析

    CAN的报文格式 在总线中传送的报文,每帧由7部分组成.CAN协议支持两种报文格式,其唯一的不同是标识符(ID)长度不同,标准格式为11位,扩展格式为29位. 在标准格式中,报文的起始位称为帧起始(S ...