You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

120 lines
14 KiB
Markdown

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# 33 | 解读TPU设计和拆解一块ASIC芯片
过去几年最知名、最具有实用价值的ASIC就是TPU了。各种解读TPU论文内容的文章网上也很多。不过这些文章更多地是从机器学习或者AI的角度来讲解TPU。
上一讲我为你讲解了FPGA和ASIC讲解了FPGA如何实现通过“软件”来控制“硬件”以及我们可以进一步把FPGA设计出来的电路变成一块ASIC芯片。
不过呢这些似乎距离我们真实的应用场景有点儿远。我们怎么能够设计出来一块有真实应用场景的ASIC呢如果要去设计一块ASIC我们应该如何思考和拆解问题呢今天我就带着你一起学习一下如何设计一块专用芯片。
## TPU V1想要解决什么问题
黑格尔说“世上没有无缘无故的爱也没有无缘无故的恨”。第一代TPU的设计并不是异想天开的创新而是来自于真实的需求。
从2012年解决计算机视觉问题开始深度学习一下子进入了大爆发阶段也一下子带火了GPUNVidia的股价一飞冲天。我们在[第31讲](https://time.geekbang.org/column/article/105401)讲过GPU天生适合进行海量、并行的矩阵数值计算于是它被大量用在深度学习的模型训练上。
不过你有没有想过,在深度学习热起来之后,计算量最大的是什么呢?并不是进行深度学习的训练,而是深度学习的推断部分。
所谓**推断部分**,是指我们在完成深度学习训练之后,把训练完成的模型存储下来。这个存储下来的模型,是许许多多个向量组成的参数。然后,我们根据这些参数,去计算输入的数据,最终得到一个计算结果。这个推断过程,可能是在互联网广告领域,去推测某一个用户是否会点击特定的广告;也可能是我们在经过高铁站的时候,扫一下身份证进行一次人脸识别,判断一下是不是你本人。
虽然训练一个深度学习的模型需要花的时间不少但是实际在推断上花的时间要更多。比如我们上面说的高铁去年2018年一年就有20亿人次坐了高铁这也就意味着至少进行了20亿次的人脸识别“推断“工作。
所以第一代的TPU首先优化的并不是深度学习的模型训练而是深度学习的模型推断。这个时候你可能要问了那模型的训练和推断有什么不同呢主要有三个点。
**第一点,深度学习的推断工作更简单,对灵活性的要求也就更低。**模型推断的过程我们只需要去计算一些矩阵的乘法、加法调用一些Sigmoid或者RELU这样的激活函数。这样的过程可能需要反复进行很多层但是也只是这些计算过程的简单组合。
**第二点,深度学习的推断的性能,首先要保障响应时间的指标。**我们在[第4讲](https://time.geekbang.org/column/article/93246)讲过计算机关注的性能指标有响应时间Response Time和吞吐率Throughput。我们在模型训练的时候只需要考虑吞吐率问题就行了。因为一个模型训练少则好几分钟多的话要几个月。而推断过程像互联网广告的点击预测我们往往希望能在几十毫秒乃至几毫秒之内就完成而人脸识别也不希望会超过几秒钟。很显然模型训练和推断对于性能的要求是截然不同的。
**第三点,深度学习的推断工作,希望在功耗上尽可能少一些**。深度学习的训练对功耗没有那么敏感只是希望训练速度能够尽可能快多费点电就多费点儿了。这是因为深度学习的推断要7×24h地跑在数据中心里面。而且对应的芯片要大规模地部署在数据中心。一块芯片减少5%的功耗,就能节省大量的电费。而深度学习的训练工作,大部分情况下只是少部分算法工程师用少量的机器进行。很多时候,只是做小规模的实验,尽快得到结果,节约人力成本。少数几台机器多花的电费,比起算法工程师的工资来说,只能算九牛一毛了。
这三点的差别也就带出了第一代TPU的设计目标。那就是在保障响应时间的情况下能够尽可能地提高**能效比**这个指标也就是进行同样多数量的推断工作花费的整体能源要显著低于CPU和GPU。
## 深入理解TPU V1
### 快速上线和向前兼容一个FPU的设计
如果你来设计TPU除了满足上面的深度学习的推断特性之外还有什么是你要重点考虑的呢你可以停下来思考一下然后再继续往下看。
不知道你的答案是什么我的第一反应是有两件事情必须要考虑第一个是TPU要有向前兼容性第二个是希望TPU能够尽早上线。我下面说说我考虑这两点的原因。
![](https://static001.geekbang.org/resource/image/f6/5e/f6637990792e8de1ef84891fadd11e5e.png)
[图片来源](https://arxiv.org/ftp/arxiv/papers/1704/1704.04760.pdf)
第一代的TPU就像一块显卡一样可以直接插在主板的PCI-E口上
第一点,向前兼容。在计算机产业界里,因为没有考虑向前兼容,惨遭失败的产品数不胜数。典型的有我在[第26讲](https://time.geekbang.org/column/article/102888)提过的安腾处理器。所以TPU并没有设计成一个独立的“CPU“而是设计成一块像显卡一样插在主板PCI-E接口上的板卡。更进一步地TPU甚至没有像我们之前说的现代GPU一样设计成自己有对应的取指令的电路而是通过CPU向TPU发送需要执行的指令。
这两个设计使得我们的TPU的硬件设计变得简单了我们只需要专心完成一个专用的“计算芯片”就好了。所以TPU整个芯片的设计上线时间也就缩短到了15个月。不过这样一个TPU其实是第26讲里我们提过的387浮点数计算芯片是一个像FPU浮点数处理器的协处理器Coprocessor而不是像CPU和GPU这样可以独立工作的Processor Unit。
### 专用电路和大量缓存,适应推断的工作流程
明确了TPU整体的设计思路之后我们可以来看一看TPU内部有哪些芯片和数据处理流程。我在文稿里面放了TPU的模块图和对应的芯片布局图你可以对照着看一下。
![](https://static001.geekbang.org/resource/image/6a/ae/6a14254b2bda4dd42adac6a2129e8bae.jpeg)
[图片来源](https://arxiv.org/ftp/arxiv/papers/1704/1704.04760.pdf)
模块图整个TPU的硬件完全是按照深度学习一个层Layer的计算流程来设计的
你可以看到在芯片模块图里面有单独的矩阵乘法单元Matrix Multiply Unit、累加器Accumulators模块、激活函数Activation模块和归一化/池化Normalization/Pool模块。而且这些模块是顺序串联在一起的。
这是因为一个深度学习的推断过程是由很多层的计算组成的。而每一个层Layer的计算过程就是先进行矩阵乘法再进行累加接着调用激活函数最后进行归一化和池化。这里的硬件设计呢就是把整个流程变成一套固定的硬件电路。这也是一个ASIC的典型设计思路其实就是把确定的程序指令流程变成固定的硬件电路。
接着我们再来看下面的芯片布局图其中控制电路Control只占了2%。这是因为TPU的计算过程基本上是一个固定的流程。不像我们之前讲的CPU那样有各种复杂的控制功能比如冒险、分支预测等等。
你可以看到超过一半的TPU的面积都被用来作为Local Unified Buffer本地统一缓冲区29%和矩阵乘法单元Matrix Mutliply Unit了。
相比于矩阵乘法单元,累加器、实现激活函数和后续的归一/池化功能的激活管线Activation Pipeline也用得不多。这是因为在深度学习推断的过程中矩阵乘法的计算量是最大的计算也更复杂所以比简单的累加器和激活函数要占用更多的晶体管。
而统一缓冲区Unified Buffer则由SRAM这样高速的存储设备组成。SRAM一般被直接拿来作为CPU的寄存器或者高速缓存。我们在后面的存储器部分会具体讲。SRAM比起内存使用的DRAM速度要快上很多但是因为电路密度小所以占用的空间要大很多。统一缓冲区之所以使用SRAM是因为在整个的推断过程中它会高频反复地被矩阵乘法单元读写来完成计算。
![](https://static001.geekbang.org/resource/image/08/2a/08e29a700898e5dabf60fbf0f026082a.jpeg)
[图片来源](https://arxiv.org/ftp/arxiv/papers/1704/1704.04760.pdf)
芯片布局图从尺寸可以看出统一缓冲区和矩阵乘法单元是TPU的核心功能组件
可以看到整个TPU里面每一个组件的设计完全是为了深度学习的推断过程设计出来的。这也是我们设计开发ASIC的核心原因用特制的硬件最大化特定任务的运行效率。
### 细节优化使用8 Bits数据
除了整个TPU的模块设计和芯片布局之外TPU在各个细节上也充分考虑了自己的应用场景我们可以拿里面的矩阵乘法单元Matrix Multiply Unit来作为一个例子。
如果你仔细一点看的话会发现这个矩阵乘法单元没有用32 Bits来存放一个浮点数而是只用了一个8 Bits来存放浮点数。这是因为在实践的机器学习应用中会对数据做[归一化](https://en.wikipedia.org/wiki/Normalization)Normalization和[正则化](https://en.wikipedia.org/wiki/Regularization_(mathematics))Regularization的处理。咱们毕竟不是一个机器学习课所以我就不深入去讲什么是归一化和正则化了你只需要知道这两个操作呢会使得我们在深度学习里面操作的数据都不会变得太大。通常来说呢都能控制在-3到3这样一定的范围之内。
因为这个数值上的特征,我们需要的浮点数的精度也不需要太高了。我们在[第16讲](https://time.geekbang.org/column/article/98312)讲解浮点数的时候说过32位浮点数的精度差不多可以到1/1600万。如果我们用8位或者16位表示浮点数也能把精度放到2^6或者2^12也就是1/64或者1/4096。在深度学习里常常够用了。特别是在模型推断的时候要求的计算精度往往可以比模型训练低。所以8 Bits的矩阵乘法器就可以放下更多的计算量使得TPU的推断速度更快。
## 用数字说话TPU的应用效果
那么综合了这么多优秀设计点的TPU实际的使用效果怎么样呢不管设计得有多好最后还是要拿效果和数据说话。俗话说是骡子是马总要拿出来溜溜啊。
Google在TPU的论文里面给出了答案。一方面在性能上TPU比现在的CPU、GPU在深度学习的推断任务上要快1530倍。而在能耗比上更是好出3080倍。另一方面Google已经用TPU替换了自家数据中心里95%的推断任务,可谓是拿自己的实际业务做了一个明证。
## 总结延伸
这一讲我从第一代TPU的设计目标讲起为你解读了TPU的设计。你可以通过这篇文章回顾我们过去32讲提到的各种知识点。
第一代TPU是为了做各种深度学习的推断而设计出来的并且希望能够尽早上线。这样Google才能节约现有数据中心里面的大量计算资源。
从深度学习的推断角度来考虑TPU并不需要太灵活的可编程能力只要能够迭代完成常见的深度学习推断过程中一层的计算过程就好了。所以TPU的硬件构造里面把矩阵乘法、累加器和激活函数都做成了对应的专门的电路。
为了满足深度学习推断功能的响应时间短的需求TPU设置了很大的使用SRAM的Unified BufferUB就好像一个CPU里面的寄存器一样能够快速响应对于这些数据的反复读取。
为了让TPU尽可能快地部署在数据中心里面TPU采用了现有的PCI-E接口可以和GPU一样直接插在主板上并且采用了作为一个没有取指令功能的协处理器就像387之于386一样仅仅用来进行需要的各种运算。
在整个电路设计的细节层面TPU也尽可能做到了优化。因为机器学习的推断功能通常做了数值的归一化所以对于矩阵乘法的计算精度要求有限整个矩阵乘法的计算模块采用了8 Bits来表示浮点数而不是像Intel CPU里那样用上了32 Bits。
最终综合了种种硬件设计点之后的TPU做到了在深度学习的推断层面更高的能效比。按照Google论文里面给出的官方数据它可以比CPU、GPU快上1530倍能耗比更是可以高出3080倍。而TPU也最终替代了Google自己的数据中心里95%的深度学习推断任务。
## 推荐阅读
既然要深入了解TPU自然要读一读关于TPU的论文[In-Datacenter Performance Analysis of a Tensor Processing Unit](https://arxiv.org/ftp/arxiv/papers/1704/1704.04760.pdf)。
除了这篇论文之外你也可以读一读Google官方专门讲解TPU构造的博客文章 [An in-depth look at Googles first Tensor Processing Unit(TPU)](https://cloud.google.com/blog/products/gcp/an-in-depth-look-at-googles-first-tensor-processing-unit-tpu)。
## 课后思考
你能想一想如果我们想要做一个能够进行深度学习模型训练的TPU我们应该在第一代的TPU的设计之上做怎么样的修改呢
欢迎留言和我分享你的想法。如果这篇文章对你有收获,你也可以把他分享给你的朋友。