计算机体系结构 [5]:异常与中断
异常定义
异常(Exception)其实是一个硬件和软件组合到一起的处理过程。异常的前半生,也就是异常的发生和捕捉,是在硬件层面完成的。但是异常的后半生,也就是说,异常的处理,其实是由软件来完成的。
计算机会为每一种可能会发生的异常,分配一个异常代码(Exception Number),或叫作中断向量(Interrupt Vector)。异常发生的时候,通常是 CPU 检测到了一个特殊的信号。比如,你按下键盘上的按键,输入设备就会给 CPU 发一个信号。或者,正在执行的指令发生了加法溢出,同样,我们可以有一个进位溢出的信号。这些信号呢,在组成原理里面,我们一般叫作发生了一个事件(Event)。CPU 在检测到事件的时候,其实也就拿到了对应的异常代码。
这些异常代码里,I/O 发出的信号的异常代码,是由操作系统来分配的,也就是由软件来设定的。而像加法溢出这样的异常代码,则是由 CPU 预先分配好的,也就是由硬件来分配的。这又是另一个软件和硬件共同组合来处理异常的过程。
拿到异常代码之后,CPU 就会触发异常处理的流程。计算机在内存里,会保留一个异常表(Exception Table)。也 ...
计算机体系结构 [4]:流水线冒险与预测
前言
想要通过流水线设计来提高CPU的吞吐率,其实是冒着一定的风险的。就类似于接力赛跑中,交接棒时会通过提前起跑来获取优势,但这时能否以全速完成交接取决于前后两个人的步调是否能达成一致。我们在流水线也会遇到一些被称为冒险(Hazard)的场景,冒险会阻止指令流中下一条指令在其指定的时钟周期内执行,从而降低流水化所能获得的理想的吞吐量。
冒险
主要有三大冒险,分别是结构冒险(Structural Hazard)、数据冒险(Data Hazard)以及控制冒险(Control Hazard)。
结构冒险
结构冒险本质上以硬件层面的资源竞争问题,即CPU在同一个时钟周期的两条不同指令的不同阶段,用到了同一个硬件电路。一个典型的例子如下图所示:
上图是一个典型的5级流水线,其中第一条指令的访存(MEM)阶段和第四条指令的取指令(IF)都涉及对内存数据的读取。若我们只有一个地址译码器去解析内存地址,则一个时钟周期内只能读取一条数据,故第一条指令和第四条指令并不能同时执行。
对于结构冒险,显而易见的解决方案就是增加资源。比如对于上面的问题,就可以将内存分为两部分,一部分为存放指令的程序内存,一部 ...
计算机体系结构 [3]:编译与链接
前言
将一段程序源码运行起来一共需要几步?每一步都做了什么?
整体流程
C语言源码能够跑起来大致可以分为两部分:
第一部分由编译(Compile),汇编(Assemble)以及链接(Link)三个阶段组成。其中编译器将C源码文件(*.c)编译成汇编代码文件(*.asm或*.S);汇编器将汇编代码文件转换成目标代码文件(机器码,*.o);链接器将多个目标文件及其调用的各种函数库文件(*.lib/*.a或*.dll/*.so)链接起来,得到可执行文件(*.elf/*.pe);
第二部分则是通过装载器(Loader)将可执行文件装载(Load)到内存中。CPU从内存中读取指令和数据,开始执行程序。
ELF文件格式
在 Linux 下,可执行文件和目标文件所使用的都是一种叫 ELF(Execuatable and Linkable File Format)的文件格式,中文名字叫可执行与可链接文件格式,这里面不仅存放了编译成的汇编指令,还保留了很多别的数据。
ELF 文件格式把各种信息,分成一个一个的段(Section)保存起来。ELF 有一个基本的文件头(File Header),用来 ...
AI算法基础 [16]:分组网络GroupConv
前言
分组卷积(Group convolution),最早在AlexNet中出现,由于当时的硬件资源有限,训练AlexNet时卷积操作不能全部放在同一个GPU处理,因此作者把feature maps分给多个GPU分别进行处理,最后把多个GPU的结果进行融合。Alex认为group conv的方式能够增加 filter之间的对角相关性,而且能够减少训练参数,不容易过拟合,这类似于正则的效果。
原理
普通卷积和分组卷积的示意图如下所示:
按照NCHW排布来看,对普通卷积而言:
单个输入feature map尺寸:$ 1 \times c_1 \times H_{in} \times W_{in}$
c2c_2c2个卷积核的尺寸:c2×c1×h1×w1c_2 \times c_1 \times h_1 \times w_1c2×c1×h1×w1
单个输出feature map尺寸:1×c2×Hout×Wout1 \times c_2 \times H_{out} \times W_{out}1×c2×Hout×Wout
参数量(假设无bias):c2∗c1∗h1∗w1c_ ...
AI算法基础 [15]:可形变卷积网络DeformConv
前言
可形变卷积网络(Deformable Convlution Networks, DCN)来自MSRA的研究团队提出的卷积结构。DCN的核心思想是将CNN中固定形状的卷积过程改变成了能适应物体形状的卷积过程,引入了学习空间几何形变的能力,来解决传统CNN对物体几何形变适应性差的问题。
基本思想
传统CNN在featureMap上做卷积操作时,它的感受野是固定的正方形形状。DCN的做法是对感受野上的每个点加一个偏移量,偏移的大小也通过学习获得,偏移后的感受野不再是固定矩形,而是与物体的实际形状相匹配。这样做的好处是无论物体形状怎么变,卷积的区域始终覆盖在物体形状的周围。如下图所示:
网络结构
DCN的网络结构如下图所示:
如上图所示,DCN的计算大致分两步:上方的conv层的输入为input feature map,用来学习offsets信息;下方的deformable conv层的输入为input feature map和offsets,先根据offsets插值出感受野的值,再进行卷积。
公式表示
普通卷积的公式表示如下:
y(p0)=∑pn∈ℜW(pn)⋅X(p0+pn)y( ...
AI算法基础 [14]:GEMM进一步优化
前言
在上篇文章中介绍了how to optimize gemm是如何优化GEMM算法的性能,但他最终的优化结果就是理论极限吗?显然不是,下面将在其基础上进一步探究GEMM性能优化的边界。
测试环境
CPU:Intel Core i7 8700,3.2GHz主频,支持AVX2,FMA3,Coffee Lake(Skylake)架构
操作系统:WSL-Ubuntu-18.04
L1 Cache Size:32KB
Cache Line Size:64B
编译优化等级:O2
优化尝试
使用AVX2指令集
从上面可以看到,我的CPU最高支持AVX2指令集,AVX2指令集的向量寄存器为256bit,可以同时处理4个双精度浮点数据,因此用AVX2指令替换SSE指令后,性能理论上可以提升2倍。代码见这里。注意需要在makefile中添加-mavx编译选项,性能变化如下图所示:
从上图可以看出,性能提升接近预期值。
指令全覆盖
已实现的微内核中的向量的乘加计算和store操作的代码并没有写成Intrinsics指令形式(编译器可能会优化),尝试将所有代码均替换成Intrinsics指令形式, ...
计算机体系结构 [2]:指令级并行(ILP)与数据级并行(DLP)
前言
指令级并行( ILP, Instruction Level Parallelism)是指利用流水级并行和多指令发射等方式提高程序执行的并行度;
数据级并行(DLP, Data Level Parallelism)是指处理器能够同时处理多条数据的并行方式,即SIMD。
本文将对上述几种程序优化方式实现简单的测试样例进行性能提升的验证。
理论基础
周期
指令周期(Instruction Cycle):完成一条指令的时间;
机器周期(Machine Cycle,又称CPU周期):完成一条指令中单个基本操作(取指,译码,执行等)的时间;
时钟周期(Clock Cycle):主频的倒数;
三者之间的关系大致如下:
经典5级流水线
经典的5级流水线(现代CPU不止5级流水线,随着技术发展到今天,你日常用的手机 ARM 的 CPU 或者 Intel Core的CPU,流水线的深度是 14 级(存疑,暂无数据支撑找到了,看这里))如下图所示:
指令提取周期(IF):送出PC(程序计数器),并将指令从存储器提取到指令寄存器中(IR);将PC递增4,以完成下一顺序指令的寻址。
指令译码/ ...
AI算法基础 [13]:初探Transformer
前言
Google论文:Attention Is All You Need
哈佛大神笔记:The Annotated Transformer
哈佛大神代码: annotated-transformer
本文主要参考了Alexander Rush大神这篇The Annotated Transformer,但并不是逐字翻译,而是加入了自己学习过程中的一些拙见和引申,如果不喜欢别人消化过的东西,可以直接阅读原文。Pytorch等框架其实已经实现了Transformer,至于为什么选择这篇文章进行学习而不是直接阅读Pytorch源码,是因为这篇不会包含出于框架本身考虑的过多的抽象和封装,且解读和代码兼而有之,作为Transformer学习的开篇,非常合适。
环境
代码所需的运行环境是python-3.6+pytorch-0.3.0(只有x86的linux版本),这里就用wsl的ubuntu环境做配置,刚好我的ubuntu是python3.6,否则可能就需要用conda配置虚拟环境+ipykernel生成jupyter notebook的kernel,大致如下(没有实操):
cond ...
AI算法基础 [12]:GEMM优化
前言
GEMM(General Matrix Multiplication,通用矩阵乘)是深度学习或其他涉及科学计算领域中常用的计算操作,也是消耗计算资源较大的操作,对其做性能优化就很有必要。
基本概念
C=ABA,B∈Rn×nCm,n=∑k=1KAm,kBk,nm,n,k∈Rn\begin{align*}
C&=AB \quad A,B\in R^{n×n} \\
C_{m,n}&=\sum_{k=1}^KA_{m,k}B_{k,n} \quad m,n,k \in R^n
\end{align*}
CCm,n=ABA,B∈Rn×n=k=1∑KAm,kBk,nm,n,k∈Rn
其中AAA、BBB、CCC的尺寸分别为M×KM×KM×K、K×NK×NK×N、M×NM×NM×N。如下图所示:
基础实现(伪)代码如下:
for (int m = 0; m < M; m++) { for (int n = 0; n < N; n++) { C[m][n] = 0; for (int k = 0; k < K; k ...
计算机体系结构 [1]:CPU/GPU/NPU算力
基本术语
OPS
Operations Per Second的缩写。
1 TOPS代表处理器每秒钟可进行一万亿次(10^12)操作。
1 GOPS代表处理器每秒钟可进行十亿次(10^9)操作。
1 MOPS代表处理器每秒钟可进行一百万次(10^6)操作。
TOPS同GOPS与MOPS可以换算,都代表每秒钟能处理的次数,单位不同而已。
注意这里的操作并不特指float32,也可能是float16,int8,int4等。要符合实际计算时采用的数据类型。
FLOPS
Floating-point Operations Per Second的缩写。
常被用来估算芯片的计算能力,尤其是在使用到大量浮点运算的科学计算领域中。
OPS与FLOPS在AI应用中一般指乘加操作。
FLOPs
Floating-point Operations的缩写,注意s小写,表示复数。
意指浮点运算数,理解为计算量。在深度学习中,我们用FLOPs,来衡量算法/模型的复杂度。
MACs
Multiply–Accumulate Operations的缩写。
意指乘加累积操作数,同样是计算量,常常被人 ...