动手写一个简单版的谷歌TPU-矩阵乘法和卷积
深度学习飞速发展过程中,人们发现原有的处理器无法满足神经网络这种特定的大量计算,大量的开始针对这一应用进行专用芯片的设计。谷歌的张量处理单元(Tensor Processing Unit,后文简称TPU)是完成较早,具有代表性的一类设计,基于脉动阵列设计的矩阵计算加速单元,可以很好的加速神经网络的计算。本系列文章将利用公开的TPU V1相关资料,对其进行一定的简化、推测和修改,来实际编写一个简单版本的谷歌TPU,以更确切的了解TPU的优势和局限性。
动手写一个简单版的谷歌TPU系列目录
拓展
TPU的边界(规划中)
重新审视深度神经网络中的并行(规划中)
本文将对TPU中的矩阵计算单元进行分析,并给出了SimpleTPU中32×32的脉动阵列的实现方式和采用该阵列进行卷积计算的方法,以及一个卷积的设计实例,验证了其正确性。代码地址https://github.com/cea-wind/SimpleTPU/tree/master/lab1
1. 脉动阵列和矩阵计算
脉动阵列是一种复用输入数据的设计,对于TPU中的二维脉动阵列,很多文章中构造了脉动阵列的寄存器模型,导致阅读较为困难,而实际上TPU中的二维脉动阵列设计思路十分直接。譬如当使用4×4的脉动阵列计算4×4的矩阵乘法时,有


如上图所示,右侧是一个乘加单元的内部结构,其内部有一个寄存器,在TPU内对应存储Weight,此处存储矩阵B。左图是一个4×4的乘加阵列,假设矩阵B已经被加载到乘加阵列内部;显然,乘加阵列中每一列计算四个数的乘法并将其加在一起,即得到矩阵乘法的一个输出结果。依次输入矩阵A的四行,可以得到矩阵乘法的结果。
由于硬件上的限制,需要对传播路径上添加寄存器,而添加寄存器相对于在第i个时刻处理的内容变成了i+1时刻处理;这一过程可以进行计算结果上的等效。如下图所示,采用z-1代表添加一个延时为1的寄存器,如果在纵向的psum传递路径上添加寄存器,为了保证结果正确,需要在横向的输入端也添加一个寄存器(即原本在i进行乘加计算的两个数均在i+1时刻进行计算)。给纵向每个psum路径添加寄存器后,输入端处理如右图所示。(下图仅考虑第一列的处理)

当在横向的数据路径上添加寄存器时,只要每一列都添加相同延时,那么计算结果会是正确的,但是结果会在后一个周期输出,如下图所示

上述分析可以,一个4×4的乘加阵列可以计算一组4×4的乘加阵列完成计算,而对于其他维度的乘法,则可以通过多次调用的方式完成计算。譬如(4×4)×(4×8),可以将(4×8)的乘法拆分乘两个4×4的矩阵乘;而对于(4×8)×(8×4),两个矩阵计算完成后还需要将其结果累加起来,这也是为何TPU在乘加阵列后需要添加Accumulators的原因。最终脉动阵列设计如下所示(以4×4为例)

2. 脉动阵列的实现
如第一节所述,可通过HLS构建一个脉动阵列并进行仿真。类似TPU中的设计,采用INT8作为计算阵列的输入数据类型,为防止计算过程中的溢出,中间累加结果采用INT32存储。由于INT32的表示范围远高于INT8,认为计算过程中不存在上溢的可能性,因此没有对溢出进行处理。脉动阵列的计算结果数据类型为INT32,会在后文进行下一步处理。
脉动阵列实现的关键代码包括
1. Feature向右侧移动
for(int j=;j<MXU_ROWNUM;j++){
for(int k=MXU_ROWNUM+MXU_COLNUM-;k>=;k--){
if(k>)
featreg[j][k] = featreg[j][k-];
else
if(i<mxuparam.ubuf_raddr_num)
featreg[j][k] = ubuf[ubuf_raddr][j];
else
featreg[j][k] = ;
}
}
2. 乘法计算以及向下方移动的psum
for(int j=MXU_ROWNUM-;j>=;j--){
for(int k=;k<MXU_COLNUM;k++){
ap_int<> biasreg;
biasreg(,)=weightreg[MXU_ROWNUM+][k];
biasreg(,)=weightreg[MXU_ROWNUM+][k];
biasreg(, )=weightreg[MXU_ROWNUM+][k];
biasreg( , )=weightreg[MXU_ROWNUM+][k];
if(j==)
psumreg[j][k] = featreg[j][k+j]*weightreg[j][k] + biasreg;
else
psumreg[j][k] = featreg[j][k+j]*weightreg[j][k] + psumreg[j-][k];
}
}
完成代码编写后可进行行为级仿真,可以看出整个计算阵列的时延关系
1. 对于同一列而言,下一行的输入比上一行晚一个周期

2. 对于同一行而言,下一列的输入比上一列晚一个周期(注意同一行输入数据是一样的)

3. 下一列的输出结果比上一列晚一个周期

3. 从矩阵乘法到三维卷积
卷积神经网络计算过程中,利用kh×kw×C的卷积核和H×W×C的featuremap进行乘加计算。以3×3卷积为例,如下图所示,省略Channel方向,拆分kh和kw方向分别和featuremap进行卷积,可以得到9个输出结果,这9个输出结果按照一定规律加在一起,就可以得到最后的卷积计算结果。下图给出了3×3卷积,padding=2时的计算示意图。按F1-F9给9个矩阵乘法结果编号,输出featuremap中点(2,1)——指第二行第一个点——是F1(1,1),F2(1,2),F3(1,3),F4(2,1),F5(2,2),F6(2,3),F7(3,1),F8(3,2),F9(3,3)的和。

下面的MATLAB代码阐明了这种计算三维卷积的方式,9个结果错位相加的MATLAB代码如下所示
output = out1;
output(:end,:end,:) = output(:end,:end,:) + out2(:end-,:end-,:);
output(:end,:,:) = output(:end,:,:) + out3(:end-,:,:);
output(:end,:end-,:) = output(:end,:end-,:) + out4(:end-,:end,:);
output(:,:end,:) = output(:,:end,:) + out5(:,:end-,:);
output(:,:end-,:) = output(:,:end-,:) + out6(:,:end,:);
output(:end-,:end,:) = output(:end-,:end,:) + out7(:end,:end-,:);
output(:end-,:,:) = output(:end-,:,:) + out8(:end,:,:);
output(:end-,:end-,:) = output(:end-,:end-,:) + out9(:end,:end,:);
而在实际的HLS代码以及硬件实现上,部分未使用的值并未计算,因此实际计算的index和上述示意图并不相同,具体可参考testbench中的配置方法。
4. 其他
GPU的volta架构中引入了Tensor Core来计算4×4的矩阵乘法,由于4×4的阵列规模较小,其内部可能并没有寄存器,设计可能类似第一节图1所示。由于其平均一个周期就能完成4×4矩阵计算,猜测采用第一节中阵列进行堆叠,如下图所示。

一些FPGA加速库中利用脉动阵列实现了矩阵乘法,不过不同与TPU中将一个输入固定在MAC内部,还可以选择将psum固定在MAC内部,而两个输入都是时刻在变化的。这几种方式是类似的,就不再展开描述了。
动手写一个简单版的谷歌TPU-矩阵乘法和卷积的更多相关文章
- 动手写一个简单版的谷歌TPU
谷歌TPU是一个设计良好的矩阵计算加速单元,可以很好的加速神经网络的计算.本系列文章将利用公开的TPU V1(后简称TPU)相关资料,对其进行一定的简化.推测和修改,来实际编写一个简单版本的谷歌TPU ...
- 动手写一个简单版的谷歌TPU-指令集
系列目录 谷歌TPU概述和简化 基本单元-矩阵乘法阵列 基本单元-归一化和池化(待发布) TPU中的指令集 SimpleTPU实例: (计划中) 拓展 TPU的边界(规划中) 重新审视深度神经网络中的 ...
- 动手写一个简单的Web框架(模板渲染)
动手写一个简单的Web框架(模板渲染) 在百度上搜索jinja2,显示的大部分内容都是jinja2的渲染语法,这个不是Web框架需要做的事,最终,居然在Werkzeug的官方文档里找到模板渲染的代码. ...
- 动手写一个简单的Web框架(Werkzeug路由问题)
动手写一个简单的Web框架(Werkzeug路由问题) 继承上一篇博客,实现了HelloWorld,但是这并不是一个Web框架,只是自己手写的一个程序,别人是无法通过自己定义路由和返回文本,来使用的, ...
- 动手写一个简单的Web框架(HelloWorld的实现)
动手写一个简单的Web框架(HelloWorld的实现) 关于python的wsgi问题可以看这篇博客 我就不具体阐述了,简单来说,wsgi标准需要我们提供一个可以被调用的python程序,可以实函数 ...
- 自己动手写一个简单的MVC框架(第一版)
一.MVC概念回顾 路由(Route).控制器(Controller).行为(Action).模型(Model).视图(View) 用一句简单地话来描述以上关键点: 路由(Route)就相当于一个公司 ...
- 自己动手写一个简单的(IIS)小型服务器
因为第一次在博客园发表随笔,不太会用,这个笔记是我之前在印象笔记中写好的,然后直接copy过来,有兴趣自己做一个IIS服务器的小伙伴们可以参照下面的流程做一次,也可以叫我要源代码,不过要做完,我觉得花 ...
- 手写一个简单版的SpringMVC
一 写在前面 这是自己实现一个简单的具有SpringMVC功能的小Demo,主要实现效果是; 自己定义的实现效果是通过浏览器地址传一个name参数,打印“my name is”+name参数.不使用S ...
- 自己动手写一个简单的MVC框架(第二版)
一.ASP.NET MVC核心机制回顾 在ASP.NET MVC中,最核心的当属“路由系统”,而路由系统的核心则源于一个强大的System.Web.Routing.dll组件. 在这个System.W ...
随机推荐
- web前端绘制0.5像素的几种方法
最近完成了公司安排的移动web触屏开发,期间涉及到在移动设备上显示线条,最开始采用PC常用的css board属性来显示1个像素的线条,但是发现在移动设备上并不美观,参考淘宝.京东的触屏发现它们均是采 ...
- 基于zepto使用swipe.js制作轮播图demo
在移动web开发中,由于手机界面较小,为了能展示更多的图片经常使用轮播图并且还需要考虑到手机流量的问题,通过请教他人以及百度,个人感觉swipe.js比较好用 它是一个纯javascript工具,不需 ...
- vs参数配置
配置属性-常规: 输出目录:工程的输出目录,主要包括.exe..dll..lib文件,是工程最后想要的文件.vs2015位于解决方案的\x64\Debug下,vs2010,vs2005位于解决方案的D ...
- [原]NYOJ-6174问题-57
大学生程序代写 /*6174问题 时间限制:1000 ms | 内存限制:65535 KB 难度:2 描述 假设你有一个各位数字互不相同的四位数,把所有的数字从大到小排序后得到a,从小到大后得到b ...
- [原]NYOJ-大数阶乘-28
大学生程序代写 //http://acm.nyist.net/JudgeOnline/problem.php?pid=28 /*题目28题目信息运行结果本题排行讨论区大数阶乘 时间限制:3000 ms ...
- FFMPEG 最简滤镜filter使用实例(实现视频缩放,裁剪,水印等)
FFMPEG官网给出了FFMPEG 滤镜使用的实例,它是将视频中的像素点替换成字符,然后从终端输出.我在该实例的基础上稍微的做了修改,使它能够保存滤镜处理过后的文件.在上代码之前先明白几个概念: Fi ...
- Simple Rtmp Server的安装与简单使用
Simple Rtmp Server是一个国人编写的开源的RTMP/HLS流媒体服务器. 功能与nginx-rtmp-module类似, 可以实现rtmp/hls的分发. 有关nginx-rtmp-m ...
- Agc019_D Shift and Flip
传送门 题目大意 给定两个长为$n$的$01$串$A,B$,每次操作有三种 将$A$整体向左移动,并将$A_1$放在原来$A_n$的位置上. 将$A$整体向有移动,并将$A_n$放在原来$A_1$的位 ...
- POJ3087(模拟)
#include"iostream" #include"string" #include"map" using namespace std; ...
- LVS实战1
(一).NAT模式:NAT模型:地址转换类型,主要是做地址转换,类似于iptables的DNAT类型,它通过多目标地址转换,来实现负载均衡:特点和要求: 1.LVS(Director)上面需要双网卡: ...