分类 技术向 下的文章

注:本文是高等计算机体系结构课程的作业,因为觉得作业不能白写,而且读书报告似乎被我写成了科普向的文章,所以打算把这些作业发在 blog 上 _(:з」∠)_

微处理器的结构曾经有过几次重大的革新:流水线和 RISC 概念的诞生,使得处理器的性能和指令吞吐量大幅度提升;多发射、超标量技术的诞生,使得指令级并行性得到了进一步的开发;乱序执行技术的推出,使得处理器的动态调度能力达到了新的顶峰。而在微结构发展的历史中,曾出现过很多让人耳目一新的设计:前有 Cray 设计的向量处理机,后有本文提出的超长指令字架构。

- 阅读剩余部分 -

注:本文是高等计算机体系结构课程的作业,因为觉得作业不能白写,而且读书报告似乎被我写成了科普向的文章,所以打算把这些作业发在 blog 上 _(:з」∠)_

自流水线的概念被提出起,处理器的性能就进入了一个飞速提升的时代。而随着 RISC、超标量等技术的诞生和发展,指令级并行性的开发越来越被人所重视,指令级并行度本身也在技术的更迭中不断上升。为了提升处理器的性能,进一步挖掘 ILP,人们选择让处理器尽可能同时分析和调度更多的指令。但由于控制转移指令的存在,尤其是条件分支,处理器不得不采用推测执行的方式来跨越基本块的边界,将流水线填得更满——由此,就诞生了分支预测技术。

“分支预测” 技术正如其名,是一种 “预测” 未来的技术。但实际上,它可以做得很简单,例如对所有分支都预测不跳转;也可以做得很复杂,例如结合过往的分支跳转情况,进行各类预测。在本科期间初次了解分支预测技术时,我曾痴迷于此——一度惊讶于简单的计数器居然也可以预知未来,而复杂的多级结构居然可以将预测正确率推上一个常人无法想象的顶峰。

借读书报告的机会,我终于能从历史的角度,学习和认识分支预测器的发展过程。这篇读书报告虽然是针对 TAGE 分支预测器的论文撰写的,但实际上我将课程中提到的所有关于分支预测的文献都大略的看了一遍。本文将结合这些文献,着重探讨 TAGE 分支预测器的技术要点,兼以浅谈分支预测器的普适设计思想。

- 阅读剩余部分 -

计算图是深度学习中最基础也最重要的一种数据结构,在计算图的运行过程中,每个节点会依次执行具体的算子操作。此时,需要有一定的内存空间来存放算子的输入和输出。这篇文档分析了 NNVM 中计算图内存分配部分的具体处理过程。

编译计算图

编译计算图的过程由 GraphCompile 执行,该 pass 位于 nnvm/src/compiler/graph_compile.cc

作为在 build 的最后阶段被调用的 pass,它的处理流程是:

  1. 处理所有可融合的算子节点,然后将其转化为融合后的节点,包括将融合后的算子编译成为 LoweredFunc
  2. 建立原图和融合后的计算图的映射关系,并且据此构建出新的计算图。这一过程中会对 assign 算子进行特殊处理:标记所有的 assign 节点,并且检测可以简化的 assign,将其特殊标记并转为空操作;
  3. 将处理完成的计算图进一步 build 为 module,得到目标代码;
  4. 执行内存分配,并且对 Placeholder、assign 节点的内存分配情况作出额外处理。

在这篇文档将讨论 NNVM 的内存分配机制,所以我们将主要关注上述第二步和第四步。

- 阅读剩余部分 -

在 NNVM 执行计算图优化的过程中,会在计算图上运行多种不同的算法,来修改计算图本身的结构或者属性。这些算法在 NNVM 中被组织成了 pass 的形式,可以使用 API ApplyPass 进行调用。

说起来,pass 这个概念在编译原理中是很常见的:在编译过程中,对输入的源代码或等价的中间表示执行一次遍历的过程,就叫做一个 pass。

传统意义上,我们可以把编译器的各个阶段都实现成一个 pass,比如:先对源代码做词法分析,待全部完成后对所有 token 进行语法分析,得到所有 AST 后再进行语义分析等等……但是通常情况下,为了节省时间,编译器会将部分或者全部的流程合并在同一个 pass 里,例如:在词法分析的过程中,语法分析器“同时”工作,构建 AST;然后在当前 AST 构建完毕后,立即对其执行语义分析和 IR 生成。

而 NNVM 中出现的 pass 则是狭义的 pass。熟悉 LLVM 的读者应该知道,LLVM 中有一个 PassManager 用于管理所有的 pass,而每一个 pass 又可以对 IR 进行一次独立的操作(优化等)。这一概念的应用使 LLVM 变得高度模块化,添加一种新的优化只需要实现一个新的 pass 即可,而不必大幅度改动 LLVM 本身的其他代码。NNVM 中 pass 的概念和 LLVM 中的基本一致。

以上是对 pass 这一概念的简单介绍。接下来的这篇文章记录了 NNVM 在执行编译优化过程中用到的一些 pass,以及这些 pass 的具体作用。

- 阅读剩余部分 -

近期在计算所一直在研究 TVM,尤其是其中 NNVM 的部分。由于之前完全没接触过深度学习,也没有系统的了解过一个实际的编译器项目,所以这些工作初期会比较费力。

之前全凭自己头铁,直接硬着头皮读源码 + debug;目前好了很多,至少可以理清楚 NNVM 这套东西的基本流程了。于是把这一阶段自己记录的一些文档稍作简单整理,放在 blog 上,供以后回顾(作为黑历史)。

这篇文章将简单介绍 NNVM 读入一个已经训练好的 model 的具体流程,包括前端如何将其他深度学习框架的 model 转成 NNVM 的计算图表示,以及 NNVM 如何将计算图构建为目标平台的二进制,等等。

写得特别乱,也没指望大家能看懂(逃 = =

- 阅读剩余部分 -