谁有梦三国刷关卡英雄的脚本,最好是能循环的,有的发759...

(更新历史:&br&10.5号更新,加入了DianNao部分的内容;&br&
10.4号更新,加入了DaDianNao部分的内容;&br&
10.2号更新,加入了ShiDianNao部分的内容;)&br&最近正好在比较系统地关注AI硬件加速的东东。&br&前几天比较细致的读了一下ISCA16上关于寒武纪指令集的文章,在这里(&a href=&http://zhihu.com/question//answer/& class=&internal&&寒武纪神经网络处理器效能如何 ? - 杨军的回答&/a&)有一个当时写的paper reading notes。&br&这两天花了一些时间,又把发在ASPLOS 15、ISCA 15、Micro 14以及ASPLOS 14上的PuDianNao/ShiDianNao/DaDianNao/DianNao这四篇文章也读了一下,整理了一份reading notes,分享出来供参考。在我看来,系统性地把DianNao项目的相关重点论文一起梳理一遍,对于透过陈氏兄弟的工作来把握AI硬件加速器这个技术trend会更有助益。&br&---------------------------------------------------------------------------------------------------------------&br&&b&1. PuDianNao&br&&/b&[1]是陈氏兄弟发起的Diannao项目[2]中的最后一篇论文,文章对七种常见的机器学习算法的计算操作类型和访存模式进行了总结。包括:
&br&kNN/k-Means/DNN/Linear Regression/Support Vector Machine/Naive Bayes/Classification Tree。
&br&基于对这七种算法的分析,提出了一种能够同时支持七种算法的硬件加速器的设计方案。
&br&发在ASPLOS这种国际顶会上的文章,写作风格通常也非常干净清晰,结构明了,这篇文章也秉持了这个传统,即使是非体系结构出身的人,读起来也会感觉很清爽。 &br&文章先是对七种机器学习算法的计算及访存范式进行了分析,这也是后续的硬件加速器的基础,套用工业界的说法,这属于我们的“业务问题”,只有先对业务问题认识清楚了,才能给出好的解决方案。 &br&以kNN算法[3]为例,这个算法的核心思想比较直观,并不需要显式的训练环节,而是直接根据已经获取到的有标签的reference sample,对于待预测样本,通过给定的distance function,找到距离待预测样本最近的k个reference sample,然后再根据这k个reference sample的标签决议出待预测样本的标签,核心的代码逻辑如下:
&br&&figure&&img src=&https://pic4.zhimg.com/50/bccab55f682_b.jpg& data-rawwidth=&383& data-rawheight=&118& class=&content_image& width=&383&&&/figure&&br&主要的计算开销花在了distance function的计算上(具体distance function根据业务、数据的特点来进行design,常用的比如cosine similarity[4]/Euclidean distance[5]/Hamming distance[6])。
&br&如果我们把计算开销拆解得再细致一些,会发现,计算开销由&b&纯计算时间&/b&+&b&访存时间&/b&构成。纯计算时间的优化,可以通过定制硬件资源来获取到,而访存时间的优化则需要结合具体的访存模式来展开。
&br&在计算机体系结构领域,常用的提升访存性能的方案是缓存机制的引入,这在Pattern 04年的talk[7]里,也将其列为解决计算机系统里bandwidth与latency的gap的1st solution。
&br&&i&我个人比较直观的印象是,在读master的时候,自己做过一段时间硬件模拟器的开发工作,当时的工作现在看起来并不复杂,参考VMIPS[8]实现了一个基于龙芯1号的SoC模拟器,当时的实际观测里,运行非常简单的benchmark(因为是裸芯片,所以为了简单,这个benchmark就是一个类似于简易BIOS的bootloader + 硬件测试逻辑的组合),能够观察到cache生效与否对性能带来几十倍以上的影响。
&br&&/i&回到我们讨论的这篇文章,访存性能的提升,往往对于最终系统的性能会带来显著的影响。在文章里也基于一个cache仿真器,对七类机器学习算法的访存行为进行了仿真评估,并发现kNN算法的原始实现会引入大量的访存行为,这个访存行为的频繁度会随着reference sample集合的增加而增加(原因很简单,cache无法装下所有 的reference sample,所以,即便这些reference sample会不断地被重复访问,也无法充分挖掘data locality所带来的cache收益)。针对这种应用类型,实际上存在成熟的优化范式——Loop tiling[9]。
&br&Loop tiling的基本思想是,&b&对于循环逻辑,通过将大块的循环迭代拆解成若干个较小的循环迭代块,减少一个内存元素的re-use distance,换句话说,也就是确保当这个内存元素被加载到cache以后,尽可能保留在cache中,直到被再次访问,这样就达到了减少了昂贵的片外访存的开销的目的&/b&。对体系结构不太熟悉的同学,可能未必能一下子感知到这样做的意义,参考[10][11][12][16][17]里的一些number,能够更为量化地感知到数据访问落在不同的存储部件上(CPU寄存器/Cache/内存/磁盘外存/网络)的差异,也许就可以更为深刻地理解到loop tiling这个看起来不起眼的优化技巧对性能带来的潜在提升。
&br&&figure&&img src=&https://pic4.zhimg.com/50/1bfa971dc72ca766def71_b.jpg& data-rawwidth=&692& data-rawheight=&319& class=&origin_image zh-lightbox-thumb& width=&692& data-original=&https://pic4.zhimg.com/50/1bfa971dc72ca766def71_r.jpg&&&/figure&&br&针对kNN算法,使用loop tiling优化后的代码逻辑会长成这样:
&br&&figure&&img src=&https://pic1.zhimg.com/50/07acc73e932ddc377f57d29d657e4f63_b.jpg& data-rawwidth=&389& data-rawheight=&166& class=&content_image& width=&389&&&/figure&&br&优化后相较于优化之前的实现,片外访存带宽减少了 90%:&br&&figure&&img src=&https://pic3.zhimg.com/50/c7ebd6304fda2fe24433_b.jpg& data-rawwidth=&348& data-rawheight=&97& class=&content_image& width=&348&&&/figure&&br&针对kNN算法的分析套路,也可以套用在剩下的6种算法上,每种算法的most time-consuming的主要计算逻辑类型不同(kNN/k-Means对应的是distance function的计算,DNN/Linear Regression对应的则是向量点积和矩阵乘法计算, Naive Bayes对应的是计数),为了充分挖掘data locality的优化技巧细节也有所差异,但基本上都是loop tiling的应用。
&br&比如&b&k-Means里,聚类中心点会被反复访问,其data locality就是需要着力优化的地方;DNN里,两层layer之间的线性变换操作中,weight和上层layer不具备data locality,不需要进行优化,而下层layer的神经元会被访问多次,就需要充分挖掘其data locality&/b&,这里就不再详述,可以直接参考原始论文。
&br&在这7个算法中,基于loop tiling优化技巧,kNN/k-Means/Linear Regression/DNN/SVM具有较好的data locality挖掘空间,而Naive Bayes/Classification Tree的data locality挖掘空间则较小。这从下图可以表现得更为形象:
&br&&figure&&img src=&https://pic4.zhimg.com/50/51d4a03ded222cbf020dfe2c9ad78ea1_b.jpg& data-rawwidth=&368& data-rawheight=&170& class=&content_image& width=&368&&&/figure&&br&对跑在加速器上的这7类算法任务的认识,对于加速器的结构设计有着重要的影响。
&br&比如,在kNN为代表的5算法都表现出相似的data locality,带来的一个直观启示就是对于reuse distance & 1的两大类变量,分别提供两种不同尺寸的cache,来配合loop tiling充分挖掘data locality。
&br&另外,对于不同算法里耗时最多的计算任务的理解,对于具体的硬件执行流水线的设计也有着重要的启示。
&br&下面我们可以来看一下PuDianNao的结构设计图:
&br&&figure&&img src=&https://pic2.zhimg.com/50/d151d2dbfd532f03007b2_b.jpg& data-rawwidth=&375& data-rawheight=&173& class=&content_image& width=&375&&&/figure&&br&PuDiannao的结构主要由&b&若干个Function Unit(每个FU的功能是相同的),三个数据缓存(Hot Buffer, Cold Buffer, Output Buffer),一个指令缓存(Inst Buffer),一个控制模块(Control Module),以及DMA控制器&/b&组成。
&br&Function Unit是PuDiannao的基本执行单元,每个FU又由两个部件构成,分别是用于机器学习算法硬件定制支持的Machine Learning Unit,以及用于常规计算控制任务的Arithmetic Logic Unit。
&br&作为提供机器学习硬件加速支持的MLU,其内部由Counter、Adder、Multiplier、Adder Tree、Acc、Misc 6级流水线组成。MLU的流水线微结构图如下:
&br&&figure&&img src=&https://pic3.zhimg.com/50/fae7d1ccf72e4ffcd60b6cd88b017433_b.jpg& data-rawwidth=&393& data-rawheight=&235& class=&content_image& width=&393&&&/figure&&br&关于流水线的设计,值得一提的是Multiplier + Adder Tree提供了dot product的支持,这也是LR/SVM/DNN里的高频操作。当样本维度高于流水线运算部件的计算宽度时,可以通过Acc stage对Multiplier + Adder Tree输出的partial sum结果进行累积,来给以支持。Misc stage提供了对非线性函数(比如sigmoid/tanh函数)的线性插值近似和top-k/tail-k功能(在kNN和k-Means里会用到)的硬件支持。
&br&为了减少芯片面积及功耗,在Adder/Multipler/Adder tree这三个stage里支持的是16位的浮点计算,而对于Counter/Acc/Misc这三个stage则仍然使用32位浮点数,这种设计也是考虑到Counter/Acc/Misc离最终计算结果比较近,overflow的风险较高,而Adder/Multiplier/Adder tree对应于中间计算结果,overflow风险较低,所以会做出这种设计trade-off。
&br&在文章里,也对于这种16-bit的trade-off所可能带来的算法精度下降进行了量化评估:
&br&&figure&&img src=&https://pic3.zhimg.com/50/d2984e4ddffe7741cac7cb_b.jpg& data-rawwidth=&407& data-rawheight=&186& class=&content_image& width=&407&&&/figure&&br&基准线是所有pipeline stage都采用32-bit浮点数的精度,能够看到,32bi&16bit的混合设计,对于模型精度影响并不大。
&br&&br&&b&相较于MLU,ALU的设计则比较简单,主要实现了MLU里未支持,也即是在机器学习算法中非高频操作的逻辑。比如除法、条件赋值等。这样设计的考虑是希望PuDiannao能够尽可能自治地支持起机器学习算法运行所需的基础部件支持,因为PuDiannao本质上还是一个加速器,所以会作为协处理器[15]嵌入到宿主系统里,协同支持完整计算任务的执行。如果对于机器学习算法中非典型高频操作不提供支持,那么这些操作就需要回落到宿主cpu上,这会增加宿主系统与PuDiannao的协同开销,对加速效果也会带来影响。
&br&&/b&&br&关于存储部件的设计,在上面已经提了引入多种data buffer的设计动机(支持计算任务里不同的reuse distance),需要再补充一下的是,为了减少芯片面积和功耗,hot buffer/code buffer使用的是单端口的SRAM,而output buffer则因为其支持的操作类型(同时读写),使用了双端口的SRAM。
&br&&b&在[13]里,可以了解到,相较于单端口RAM,双端口RAM无论是在基本存储单元cell的面积上,还是控制逻辑上,都引入了额外的代价,这也是这里做这个设计trade-off的考量。另外,为了提升主存到PuDiannao的数据交换性能,对于inst buffer和data buffer都采取了DMA与宿主系统进行交互。
&br&&/b&PuDiannao的Control Module扮演的是指令译码器和dispatcher的功能。PuDiannao里,计算任务的描述,通过control instruction来描述,而control module就是对control instruction进行译码,然后把需要执行的操作指令发送给所有 的FU上。PuDiannao的指令抽象度比较低,所以使用control instruction编程需要对PuDiannao的架构实现细节非常了解,看一下control instruction的格式会有助于建立这个认识:
&br&&figure&&img src=&https://pic4.zhimg.com/50/5a2a9c5e8fcefd5fb4e40_b.jpg& data-rawwidth=&356& data-rawheight=&91& class=&content_image& width=&356&&&/figure&&br&以及基于control instruction所编写的k-Means的code snippet:
&br&&figure&&img src=&https://pic3.zhimg.com/50/49c77d88e98a8ddfc539d1_b.jpg& data-rawwidth=&382& data-rawheight=&226& class=&content_image& width=&382&&&/figure&&br&最后基于PuDianNao的评估集中在性能加速比以及功耗这两个方面。分别基于verilog和C仿真器完成了评估环境的搭建。verilog评估环境(&b&65nm工艺&/b&)的精度更高,但速度慢,C仿真器的速度快,但评估精度会有一定的损失。
&br&评估使用的数据集描述如下:
&br&&figure&&img src=&https://pic4.zhimg.com/50/90d8ae2f99dccf0f7350_b.jpg& data-rawwidth=&362& data-rawheight=&166& class=&content_image& width=&362&&&/figure&&br&评估的baseline是GPU(&b&NVIDIA K20M, 3.2TFlops peak,5GB显存,208GB/s显存带宽,28nm工艺, CUDA SDK5.5&/b&)。
&br&性能评估的策略是将7个算法的不同phase拆分开来与baseline进行评估对比:
&br&&figure&&img src=&https://pic2.zhimg.com/50/cb214ef510d_b.jpg& data-rawwidth=&358& data-rawheight=&206& class=&content_image& width=&358&&&/figure&&br&在上面的评估结果中,能够看到,有某些phase里,GPU baseline的表现要比PuDianNao要好,比如Naive Bayes的prediction phase,这跟Naive Bayes的prediction的计算类型涉及到大量的乘法计算有关,PuDianNao并没有配置大规模的寄存器堆,所以需要在on-chip的data buffer和FU之间频繁地进行数据交互,而K20M则有64K个寄存器可供给计算,所以不会存在这个问题,于是造成了这种performance差异(&i&&b&说到这里,我有些好奇的是在[14]里,对于这个问题是怎样解决的。因为在[14]里,我并没有看到在regisger上面的额外设计资源投入,仍是通过data buffer来完成计算任务所需的数据存储,看起来似乎应该存在跟PuDianNao相同的问题。但是在[14]里,工艺与PuDianNao相同,都是65nm,相较于相同的GPU baseline,averagely却获得了3X的性能提升,这是一个让我暂时未解的疑问&/b&&/i&)。性能提升最明显的SVM prediction则主要是FU里提供了kernel函数的插值逻辑硬件实现带来的。
&br&如果说PuDianNao带来的性能提升相较于GPU并不显著的话(&b&in average 1.2X&/b&),那么在计算能耗比上的提升,就相当显著了:
&br&&figure&&img src=&https://pic1.zhimg.com/50/be7e13e40af6b0afcc3af0c_b.jpg& data-rawwidth=&361& data-rawheight=&196& class=&content_image& width=&361&&&/figure&&br&最后可以看一下PuDianNao的layout信息:
&br&&figure&&img src=&https://pic2.zhimg.com/50/d252ec7a93bf4ee83cecd9_b.jpg& data-rawwidth=&216& data-rawheight=&209& class=&content_image& width=&216&&&/figure&&figure&&img src=&https://pic2.zhimg.com/50/926cfdb075ba0b9ac9d9_b.jpg& data-rawwidth=&396& data-rawheight=&220& class=&content_image& width=&396&&&/figure&&br&&br&能够看到,FU(Functional Unit)和CB(Cold Buffer)是面积大户,CM(Control Module)的面积不大,但是功耗并不小。
&br&&br&&i&正好前不久刚刚精读了Cambricon指令集的论文[14],把两篇论文联系在一起来看,还是隐约能够感知到一些脉络。PuDianNao里给出的流水线设计,更像是一个特殊的定制硬件逻辑,ad-hoc的味道更浓,而[14]里给出的流水线设计则比较接近于一个中规中矩的处理器的设计了。[14]里也能够看到更明显的抽象的味道,把Add/Multplication这些操作都集中在了Vector/Matrix Func Unit里,不像PuDianNao这样,会在不同的流水线stage里,分别提供了看起来有些相近的实现(Add逻辑在多个pipeline stage里出现)。在片上存储体系的设计里,[14]也更为general,通过更为精巧的crossbar scratchpad memory来统一提供片上访存支持。最重要的是,PuDianNao只提供了针对7种算法的操作码,而[14]则在指令集的层次为更丰富的应用类型提供了支持。
&br&&/i&&br&接下来计划再去读一下DianNao系列的其他几篇文章,以作相互映照。
&br&在阅读PuDianNao的时候,还是发现对于[14]的理解,有些地方并不如之前所以为的那样深入,因为在PuDianNao里看到的一些问题(比如Naive Bayes prediction的问题),似乎并没有理解清楚在[14]里是如何针对性解决的,也许随着对整个系列论文的深入阅读 ,能够形成一个更为完整系统化的认识吧。
&br&&br&References:
&br&[1]. Daofu Liu. PuDianNao: A Polyvalent Machine Learning Accelerator. ASPLOS, 2015.
&br&[2]. A Brief Introduction to The Dianao Project.
&a href=&//link.zhihu.com/?target=http%3A//novel.ict.ac.cn/diannao/& class=& external& target=&_blank& rel=&nofollow noreferrer&&&span class=&invisible&&http://&/span&&span class=&visible&&novel.ict.ac.cn/diannao&/span&&span class=&invisible&&/&/span&&span class=&ellipsis&&&/span&&/a&&br&[3]. k-nearest neighbors algorithm. &a href=&//link.zhihu.com/?target=https%3A//en.wikipedia.org/wiki/K-nearest_neighbors_algorithm& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&k-nearest neighbors algorithm&/a&&br&[4]. cosine similarity. &a href=&//link.zhihu.com/?target=https%3A//en.wikipedia.org/wiki/Cosine_similarity& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Cosine similarity&/a&&br&[5]. Euclidean distance. &a href=&//link.zhihu.com/?target=https%3A//en.wikipedia.org/wiki/Euclidean_distance& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Euclidean distance&/a&&br&[6]. Hamming distance. &a href=&//link.zhihu.com/?target=https%3A//en.wikipedia.org/wiki/Hamming_distance& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Hamming distance&/a&&br&[7]. David Patterson. Why Latency Lags Bandwidth and What It Means to Computing.
&a href=&//link.zhihu.com/?target=https%3A//www.ll.mit.edu/HPEC/agendas/proc04/invited/patterson_keynote.pdf& class=& external& target=&_blank& rel=&nofollow noreferrer&&&span class=&invisible&&https://www.&/span&&span class=&visible&&ll.mit.edu/HPEC/agendas&/span&&span class=&invisible&&/proc04/invited/patterson_keynote.pdf&/span&&span class=&ellipsis&&&/span&&/a&&br&[8]. VMIPS. &a href=&//link.zhihu.com/?target=http%3A//vmips.sourceforge.net/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&The vmips Project&/a&&br&[9]. Loop tiling. &a href=&//link.zhihu.com/?target=https%3A//en.wikipedia.org/wiki/Loop_tiling& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Loop tiling&/a&&br&[10]. Approximate cost to access various caches and main memory. &a href=&//link.zhihu.com/?target=http%3A//stackoverflow.com/questions/4087280/approximate-cost-to-access-various-caches-and-main-memory& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&latency - Approximate cost to access various caches and main memory?&/a&&br&[11]. CPU Cache Flushing Fallacy. &a href=&//link.zhihu.com/?target=http%3A//mechanical-sympathy.blogspot.com/2013/02/cpu-cache-flushing-fallacy.html& class=& external& target=&_blank& rel=&nofollow noreferrer&&&span class=&invisible&&http://&/span&&span class=&visible&&mechanical-sympathy.blogspot.com&/span&&span class=&invisible&&/2013/02/cpu-cache-flushing-fallacy.html&/span&&span class=&ellipsis&&&/span&&/a&&br&[12]. Answers from Peter Norvig. &a href=&//link.zhihu.com/?target=http%3A//norvig.com/21-days.html%23answers& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Teach Yourself Programming in Ten Years&/a&&br&[13]. What is dual-port RAM. &a href=&//link.zhihu.com/?target=http%3A//www.futureelectronics.com/en/memory/dual-ports.aspx& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Dual port memory, dual ported memory, Ports, sdram, sram, sdram, memories&/a&&br&[14]. Shaoli Liu. Cambricon: An Instruction Set Architecture for Neural Networks&, in Proceedings of the 43rd ACM/IEEE International Symposium on Computer Architecture. ISCA, 2016.
&br&[15]. Coprocessor. &a href=&//link.zhihu.com/?target=https%3A//en.wikipedia.org/wiki/Coprocessor& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Coprocessor&/a&&br&[16]. Visualization of Latency Numbers Every Programmer Should Know. &a href=&//link.zhihu.com/?target=https%3A//people.eecs.berkeley.edu/%7Ercs/research/interactive_latency.html& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Numbers Every Programmer Should Know By Year&/a&&br&[17]. Latency Numbers Every Programmer Should Know. &a href=&//link.zhihu.com/?target=https%3A//gist.github.com/jboner/2841832& class=& external& target=&_blank& rel=&nofollow noreferrer&&&span class=&invisible&&https://&/span&&span class=&visible&&gist.github.com/jboner/&/span&&span class=&invisible&&2841832&/span&&span class=&ellipsis&&&/span&&/a&&br&---------------------------------------------------------------------------------------------------------------&br&&b&2. ShiDianNao&/b&&br&这[1]是陈氏兄弟DianNao项目[2]的第三篇论文,发在了ISCA 2015上。
&br&之前阅读了这个系列里的Cambricon[4]和PuDianNao[3]这两篇论文,感觉ShiDianNao这篇论文在立意的创新性上比起[3][4]略逊了一筹,更像是一个针对具体应用场景的一个偏工程层面的体系结构设计&优化工作,但是在加速器的设计细节上却是touch得最为详细的,无论是访存体系的设计,还是计算单元的设计,介绍得都非常的细致,看完这个设计,说对一个比较naive的GPGPU这样的硬件加速器建立起一定的sense并不为过。
&br&&br&文章的核心思想是利用CNN网络weight sharing的特性,将CNN模型整体加载入SRAM构成的高速存储里,减少了访问DRAM带来的内存开销。同时,将加速器直接与视频图像传感器相连接,传感器采集到的图像数据直接作为加速器的输入进行处理,减少了额外的访存操作(传统模式下,会先将传感器采集到的数据放入DRAM,再知会加速器进行处理,于是会有至少两次的额外DRAM访问操作)。
&br&&br&Overall的思想听起来很直观,但真正操作起来,有着大量的设计细节需要去考量,列举几个文章中提到的挑战以及我在文章阅读过程中想到的挑战:
&br&&i&&b&1.与传感器直连的加速器芯片中的SRAM尺寸取多大比较合适?太大了,功耗、面积就上去了。太小了,对性能会带来明显的影响(想象一下如果模型不能全部hold到加速器的SRAM里,对计算过程带来的影响)。所以这很考究架构师对目标问题以及技术实现方案细节的把控和理解。
&br&2.对于会跑在这款加速器上的CNN模型,采取什么样的方式来映射到硬件计算资源?比较natural且高效的方式是,每个神经元都要对应于一个硬件计算单位,但这样很容易因为模型尺寸超出硬件物理计算单元个数而限制加速器所能支持的应用类型。而如果不强求一个神经元对应一个硬件计算单位,采用时分复用的方法,也还有小的设计权衡要考虑,以卷积层为例,在计算一个特定的feature map的output neuron的时候,在同一个时刻是只为一个output neuron进行计算,还是同时为多个output neuron进行计算,这在硬件复杂性/面积/灵活性上都会有不同的影响。
&br&3.跑在加速器芯片上的应用任务,存在一定的data locality,对这种data locality是否需要进行挖掘,以榨取更多的性能加速的空间?比如,在计算卷积层feature map的时候,卷积输入层的input neuron实际上是会被多个output neuron使用到的,这些input neuron是每次为某个output neuron计算的时候,都去从SRAM中访问获取,还是在计算单元中,引入一些local storage,进行计算单元之间的内部通信。虽然说SRAM已经比DRAM的性能要好了一个数量级[7],但是计算单元之间的直连通信能够带来更多的性能收益。当然,这样做的代价是硬件设计的复杂性。
&br&&/b&&/i&硬件开发工作不像软件开发,一次性成本非常高,所以在设计环节往往需要食不厌精,反复雕琢。也只有这样做,当芯片大规模量产以后,ROI优势才能突显出来。
&br&&b&ShiDianNao的工作,最出彩的,就是针对上面提到的具体问题场景,给出了比较精巧的硬件设计方案。
&br&&/b&首先来看一下ShiDianNao的顶层结构:
&br&&figure&&img src=&https://pic1.zhimg.com/50/d3ccba7b98b4c907934aa_b.jpg& data-rawwidth=&453& data-rawheight=&276& class=&origin_image zh-lightbox-thumb& width=&453& data-original=&https://pic1.zhimg.com/50/d3ccba7b98b4c907934aa_r.jpg&&&/figure&&br&在这个设计方案里,左侧是SRAM堆起来的数据存储(共计288KB,见下图片上SRAM的具体功用分配),
&br&&figure&&img src=&https://pic4.zhimg.com/50/9b911ecc2345ecee60e40_b.jpg& data-rawwidth=&224& data-rawheight=&144& class=&content_image& width=&224&&&/figure&&br&根据CNN计算任务的特点(一组input neurons通过一层数学计算,生成一组output neurons),设计了三类SRAM存储:
&br&&i&NBin:存取input neurons。
&br&NBout:存放输出output neurons。
&br&SB:存放完整的模型参数。
&br&&/i&在这三类存储中,SB要求能够hold住模型的全部参数,而NBin/NBout要求能够hold住神经网络一个layer的完整input/output neurons。原因是因为,&b&&i&模型参数会被反复使用,所以需要放在SRAM里以减少从DRAM里加载模型参数的时间开销,而作为CNN模型输入数据的一张特定的图片/视频帧的raw data被模型处理完毕后不会被反复使用,所以只需要确保每个神经层计算过程中所需的input/output neurons都hold在SRAM里,就足以满足性能要求&/i&&/b&。
&br&右侧则是一个NFU(Neural Functional Unit),这是一个由若干个PE组成的计算阵列。每个PE内部由一个乘法器、一个加法器、若干个寄存器、两组用于在PE阵列水平/垂直方向进行数据交互的FIFO以及一些辅助的控制逻辑组成:
&br&&figure&&img src=&https://pic3.zhimg.com/50/3bec5ff00603a5abe773b9405cdee37b_b.jpg& data-rawwidth=&317& data-rawheight=&262& class=&content_image& width=&317&&&/figure&&br&NFU的计算结果会输出到一个ALU,通过ALU最终写入到NBOut里。ALU里实现了一些并行度要求不那么高的运算支持,比如average pooling会用到的除法操作,以及非线性激活函数的硬件实现等。其中非线性激活函数的实现,使用了分段函数进行插值近似[8],以求在精度损失较小的情况下,获取功耗和性能的收益。
&br&&br&在ShiDianNao里,所有的数值计算均使用的是16位定点计算[6],而没有使用32位的浮点计算。这种策略在其他硬件加速器的设计[5]里也有过成功的应用。
&br&&br&NFU的PE阵列设计里,值得一提的是对Inter-PE data propagation的支持。引入这层支持的考虑是减少NFU与SRAM的数据通讯量。&b&我们回顾一下卷积层Feature Map的计算细节,会注意到同一个feature map里不同的output neuron,在stride没有超过kernel size的前提下,其输入数据存在一定的overlap,这实际上就是Inter-PE data propagation的引入动机,通过将不同的output neuron之间overlap的那部分input neuron直接在PE之间进行传播,从而减少访问SRAM的频次,可以在性能和功耗上都获得一定的收益。&/b&这个收益,会随着卷积核尺寸的增加而变得更加明显。
&br&以32x32 input feature map + 5x5 卷积核为例,通过下图,可以看到,随着PE个数的增加,对SRAM带宽需求的增加,以及Inter-PE data propagation优化的效果:
&br&&figure&&img src=&https://pic2.zhimg.com/50/f523f4dc063a94ce6e4aa_b.jpg& data-rawwidth=&438& data-rawheight=&255& class=&origin_image zh-lightbox-thumb& width=&438& data-original=&https://pic2.zhimg.com/50/f523f4dc063a94ce6e4aa_r.jpg&&&/figure&&br&ShiDianNao另一个重要的部件是Buffer Controller,这是用于在片上存储NBin/NBout/SB与计算部件NFU之间协调数据交互的co-ordinator。Buffer Controller负责完成两个功能:以流式的方式,layer-wise的为NFU提供计算所需数据的供给,以及缓冲NFU计算的partial输出结果,汇总完一个完整layer/feature map上所有的output neuron之后才写回到NBout。这里比较关键的细节是,为了能够高效地支持CNN模型中的不同操作对应的访存特点,在Buffer Controller里提供了对多种read mode的支持:
&br&&figure&&img src=&https://pic1.zhimg.com/50/d925ebfef36b9_b.jpg& data-rawwidth=&464& data-rawheight=&321& class=&origin_image zh-lightbox-thumb& width=&464& data-original=&https://pic1.zhimg.com/50/d925ebfef36b9_r.jpg&&&/figure&&br&稍微选几个典型的读取模式进行介绍。在上面这个图里,(a)/(b)/(e)模式主要用于为卷积层提供数据读取,读取的每个input neuron会对应于一个output neuron(注意:&b&在ShiDianNao里,这些已经通过Buffer Controller读取到PE中作为输入的input neuron接下来会通过Inter-PE data propagation的机制进行传递,从而节省了SRAM的访问带宽&/b&),其中(e)对应于卷积核step size & 1的情形。(d)对应于全连接层,读取一个input neuron,会用作多个output neuron的输入。
&br&&br&至此,ShiDianNao的设计思想的核心基本介绍完了,一些更为detail的细节,在论文里描述得很细致,比如,NFU里支持CNN/Pooling/Normalization/DNN layer的细节、为了节省指令cache对控制指令进行了一层抽象。我认为已经不再影响把握论文的核心设计思想,所以这里就不再详述了。
&br&&br&最后还是评估环节,评估环境的搭建使用的是Synopsys提供的EDA工具,65nm(跟[1][3]相同)。Baseline则选取了CPU(Intel Xeon E7-GHZ/1TB Memory/gcc 4.4.7/MMX/SSE/SSE2/SSE4/SSE4.2)、GPU(NVIDIA K20M/5GB显存/3.52TFlops/28nm/Caffe)以及DianNiao项目的第一个工作成果[9]。
&br&评估的Benchmark使用了下表中所列出的10类较小规模的CNN模型(受限于片上SRAM的尺寸,在ShiDianNao里不能支持太大的CNN model,比如AlexNet。在这10个Benchmark model里,layer wise的神经元最多消耗45KB SRAM存储,而模型的权重最多只消耗118KB SRAM,足以被ShiDianNao目前配备的288KB SRAM所支持):
&br&&figure&&img src=&https://pic2.zhimg.com/50/5dbb263c0a54b8a43d6abfc7867a6fec_b.jpg& data-rawwidth=&315& data-rawheight=&538& class=&content_image& width=&315&&&/figure&&br&评估所用的ShiDianNao,其NFU由8*8共计64个PE组成,也即在一个cycle里。同时支持64组乘/加组合运算,存储上,由64KB NBin、64KB NBout、128KB SB和32KB的指令buffer组成。
&br&评估指标还是集中在计算性能以及功耗两个方面:
&br&&figure&&img src=&https://pic2.zhimg.com/50/3aef217db37d08b54dfdba_b.jpg& data-rawwidth=&510& data-rawheight=&287& class=&origin_image zh-lightbox-thumb& width=&510& data-original=&https://pic2.zhimg.com/50/3aef217db37d08b54dfdba_r.jpg&&&/figure&&br&&figure&&img src=&https://pic1.zhimg.com/50/5abc594c39acad0d25af0d_b.jpg& data-rawwidth=&486& data-rawheight=&296& class=&origin_image zh-lightbox-thumb& width=&486& data-original=&https://pic1.zhimg.com/50/5abc594c39acad0d25af0d_r.jpg&&&/figure&&br&能够看到,ShiDianNao在性能上相较于CPU/GPU的baseline都有显著的speed up(46.38X than CPU,28.94X than GPU),相较于[9]里提出的加速器,也有1.87X的加速,这主要是因为ShiDianNao将模型全部hold在片上的SRAM里以及为了进一步减少SRAM访存开销设计的Inter-PE data propagation机制。
&br&在功耗上,ShiDianNao的优势则更为明显,具体数字可以直接阅读原始论文,值得一提的是ShiDianNao的功耗在不同硬件部件上的分配:
&br&&figure&&img src=&https://pic2.zhimg.com/50/a20cfbe9e18dfb97acf9f_b.jpg& data-rawwidth=&457& data-rawheight=&145& class=&origin_image zh-lightbox-thumb& width=&457& data-original=&https://pic2.zhimg.com/50/a20cfbe9e18dfb97acf9f_r.jpg&&&/figure&&br&我们能够看到,在ShiDianNao里,主要的功耗都集中在计算部件(NFU)上了,访存部件带来的功耗开销并不大(小于15%),这与[9里的DianNao加速器]形成了巨大的差异:
&br&&figure&&img src=&https://pic4.zhimg.com/50/96c693d51f7e82d7c3ae_b.jpg& data-rawwidth=&421& data-rawheight=&265& class=&origin_image zh-lightbox-thumb& width=&421& data-original=&https://pic4.zhimg.com/50/96c693d51f7e82d7c3ae_r.jpg&&&/figure&&br&不过,这个关于功耗的评估对比结果里有些tricky的地方是,在ShiDianNao里,一部分数据传输操作实际上从SRAM访问操作里转移到PE之间的Inter-PE data propagation之上了,这部分功耗被计算入了NFU里,但实际上还是属于数据访问相关的功耗开销。这是我们在观察这些实验结果时要注意的地方。
&br&&br&最后说说我对这篇论文的一些思考。
&br&这篇论文propose的加速器,适用面其实还是比较窄的,尺寸超过片上SRAM存储极限的模型都无法支持。比如包含几千万权重参数的AlexNet这样的model,肯定无法在ShiDianNao里被支持。当然这两年来,有不少研究团队提出了一些模型压缩的技术,比如DeepScale提出的SqueezeNet[10]和ICLR16上提出的Deep Compression[11],能够缓解ShiDianNao这样的加速器的片上模型存储的压力,但ShiDianNao要求模型能够全部hold在片上SRAM的约束,对于其通用性还是带来了一些挑战(相比而言,要求神经层的输入/输出神经元全部能够hold在NBin/NBout倒并不是一个苛刻的约束),这个约束在[3][4]里并没有看到。也许未来的一种可能是将ShiDianNao这样专门针对特定场景的加速芯片与[3][4]这种更具通用性的加速器设计融合在一起,可以获取到更好的性能/通用性的trade-off,当然其代价是芯片设计的复杂性。
&br&最后想说的,真的是no free lunch。记得以前Knuth说过,&i&系统的复杂性是恒定的,无非是在硬件和软件之间的分配&/i&。当硬件遇到了阶段性极限的时候,软件设计人员就要去填充更多的复杂性。当软件也遇到极限的时候,就需要硬件与软件进行协同设计来改善系统复杂性。在DianNao系列工作中,能够明显看到这个trend。在[12]里也通过对体系结构顶会的技术主题的变迁进行了回顾分析,能够看到软硬件协同设计、应用驱动设计的趋势。我个人相信,随着计算资源越来越可以便利地获取,网络带宽的使用成本日益降低,通过计算设备满足人类形形色色需求的应用驱动年代会更快/已经到来,在这个时代,应用/软件/硬件相结合来提供更具ROI的解决方案会是相当长一段时间内的趋势性现象。
&br&&br&References:
&br&[1]. Zidong Du.
ShiDianNao: Shifting Vision Processing Closer to the Sensor. ISCA, 2015.
&br&[2]. A Brief Introduction to The Dianao Project.
&a href=&//link.zhihu.com/?target=http%3A//novel.ict.ac.cn/diannao/& class=& external& target=&_blank& rel=&nofollow noreferrer&&&span class=&invisible&&http://&/span&&span class=&visible&&novel.ict.ac.cn/diannao&/span&&span class=&invisible&&/&/span&&span class=&ellipsis&&&/span&&/a&&br&[3]. Daofu Liu. PuDianNao: A Polyvalent Machine Learning Accelerator. ASPLOS, 2015.
&br&[4]. Shaoli Liu. Cambricon: An Instruction Set Architecture for Neural Networks&, in Proceedings of the 43rd ACM/IEEE International Symposium on Computer Architecture. ISCA, 2016.
&br&[5]. Olivier Temam. A Defect-Tolerant Accelerator for Emerging High-Performance Applications. ISCA, 2012.
&br&[6]. Fixed-point arithmetic. &a href=&//link.zhihu.com/?target=https%3A//en.wikipedia.org/wiki/Fixed-point_arithmetic& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Fixed-point arithmetic&/a&&br&[7]. Latency Numbers Every Programmer Should Know. &a href=&//link.zhihu.com/?target=https%3A//gist.github.com/jboner/2841832& class=& external& target=&_blank& rel=&nofollow noreferrer&&&span class=&invisible&&https://&/span&&span class=&visible&&gist.github.com/jboner/&/span&&span class=&invisible&&2841832&/span&&span class=&ellipsis&&&/span&&/a&&br&[8]. D. Larkin, A. Kinane, V. Muresan, and N. E. O’Connor. An Efficient Hardware Architecture for a Neural Network Activation Function Generator. Advances in Neural Networks, ser. Lecture Notes in Computer Science, vol. 3973. Springer, 2006, pp. .
&br&[9] T. Chen, Z. Du, N. Sun, J. Wang, and C. Wu. DianNao: a small-footprint high-throughput accelerator for ubiquitous machine learning. Proceedings of the 19th International Conference on Architectural Support for Programming Languages and Operating Systems (ASPLOS), Salt Lake City, UT, USA, 2014, pp. 269–284.
&br&[10]. Song Han. Deep Compression: Compressing Deep Neural Networks with Pruning, Trained Quantization and Huffman Coding.
&br&[11]. Forrest N. Iandola. SqueezeNet: AlexNet-level accuracy with 50x fewer parameters and &0.5MB model size. Arxiv, 2016.
杨军. ISCA 2016有哪些看点. &a href=&https://www.zhihu.com/question//answer/& class=&internal&&ISCA 2016 有哪些看点? - 杨军的回答&/a&&br&--------------------------------------------------------------------------------------------------------------&br&&b&3. DaDianNao&/b&&br&DaDianNao[1]这篇文章是Diana项目[5]的第二篇代表性论文,发表在Micro 2014[6],并且获得了当届的best paper。这篇论文里针对主流神经网络模型尺寸较大的应用场景(想像一下AlexNet这样的模型已经包含约6千万个权重参数),提出了一种具备伸缩性,并通过这种伸缩性可以承载较大尺寸模型的加速器设计架构。”Da”也取得是中文“大”的谐音,用来意指伸缩性。这款加速器与针对嵌入式设备应用场景提出的ShiDianNao[13]不同,针对的应用场景是服务器端的高性能计算,所以在计算能耗比上虽然相比于baseline(GPU/CPU)会有提升,但其设计核心还是专注于高性能地支持大尺寸模型,所以在硬件资源的使用上也远比[13]要更为大方一些。
&br&在我的理解中,这款加速器的核心设计思想包括几个:
&br&&b&&i& I. 使用eDRAM[3]代替SRAM/DRAM,在存储密度/访存延迟/功耗之间获得了大模型所需的更适宜的trade-off(参见下表)。
&/i&&/b&&br&&figure&&img src=&https://pic1.zhimg.com/50/44b116f0fe6684dca85d86d2fb5839ca_b.jpg& data-rawwidth=&715& data-rawheight=&219& class=&origin_image zh-lightbox-thumb& width=&715& data-original=&https://pic1.zhimg.com/50/44b116f0fe6684dca85d86d2fb5839ca_r.jpg&&&/figure&&b&&i&II. 在体系结构设计中以模型参数为中心。模型参数(对应于神经网络中的突触连接)存放在固定的eDRAM存储区域中,需要通过访存操作完成加载的是网络神经元(即对应于神经层layer的input/outout neurons)。这样设计考虑的原因是,无论是神经网络的training还是inference环节,对于于DaDianNao的问题场景,模型的尺寸要远远大于数据尺寸以及网络神经层的神经元数据尺寸,所以将尺寸更大的神经网络模型参数固定,而将尺寸较小的神经元通过访存操作进行加载、通信,可以减少消耗在访存上的开销。此外,模型参数会布署在距离计算部件很近的布局区域里,以减少计算部件工作过程中的访存延时(这也是Computational RAM思想[10]的典型应用)。另一个原因在文章里没有提到,而是我个人结合DianNao系列论文的解读,模型参数在整体计算过程中会不断地被复用,而神经元被复用的频率则并不高,所以将模型参数存放在固定的存储区域里,可以充分挖掘模型参数的data locality,减少片外访存带宽,同时提升整体加速器的性能。&/i&&/b&&br&&b&&i&III. 神经网络模型具备良好的模型可分特性。以常用的CNN/DNN这两类神经层为例。 当单层CNN/DNN layer对应的模型参数较大,超过了DaDianNao单片存储极限时(参见下图的一下大尺寸的CNN/DNN layer,具体到这些layer所对应的应用场景,可以参见DaDianNao的原始论文中的参考文献),可以利用这种模型可分性,将这个layer划分到多个芯片上,从而通过多片连接来支持大尺寸模型。想更具体的把握这个问题,不妨这样思考,对于CNN layer来说,每个feature map的计算(以及计算这个feature map所需的模型参数)实际上都是可以分配在不同的芯片上的,而DNN layer来说,每个output neuron的计算(以及计算这个output neuron所需的模型参数)也都是可以分配在不同的芯片上的。&/i&&/b&&br&&figure&&img src=&https://pic1.zhimg.com/50/567f97ae32da5ac73003d9_b.jpg& data-rawwidth=&529& data-rawheight=&396& class=&origin_image zh-lightbox-thumb& width=&529& data-original=&https://pic1.zhimg.com/50/567f97ae32da5ac73003d9_r.jpg&&&/figure&&b&正是基于上面的三个设计原则,在这篇论文中给出了DaDianNao的设计方案。在我的理解中,DaDianNao的逻辑结构与DianNao[11](见下图)是非常相似的:
&/b&&br&&figure&&img src=&https://pic4.zhimg.com/50/67e006e465ffda4c007c278b3c76aa5a_b.jpg& data-rawwidth=&341& data-rawheight=&198& class=&content_image& width=&341&&&/figure&&br&&b&DaDianNao的主要区别还是在于针对存储神经层输入输出数据的NBin/NBout,存储神经连接参数的SB的组织方式,以及其与核心计算单元NFU的数据交互方式进行了针对大模型的专门考量。
&/b&&br&&b&把握DaDianNao的核心要素,也在于理解其访存体系的设计思想及细节。
&/b&&br&单个DaDianNao芯片内的访存体系设计的高层次图如下:
&br&&figure&&img src=&https://pic4.zhimg.com/50/fd821d3f1efbd59f09431_b.jpg& data-rawwidth=&513& data-rawheight=&202& class=&origin_image zh-lightbox-thumb& width=&513& data-original=&https://pic4.zhimg.com/50/fd821d3f1efbd59f09431_r.jpg&&&/figure&左图是单个芯片的高层次图,可以看到,单个芯片由16个Tile组成。右图则是单个Tile的顶层结构图。
&br&每个tile内部会由一个NFU配上4个用于存储SB的eDRAM rank组成。而NBin/NBout则对应于左图eDRAM router所连接的两条棕色的eDRAM rank。
&br&看到上面的高层次图,会感受到在DaDianNao里,SB其实是采用了distributed的方式完成设计的,并不存在一个centralized的storage用于存储模型的参数。这个设计细节的选取考量我是这样理解的:
&br&&i&&b&I.eDRAM与DRAM相比,虽然因为其集成在了芯片内部,latency显著变小,但是因为仍然有DRAM所存在的漏电效应,所以还是需要周期性的刷新,并且这个刷新周期与DRAM相比会变得更高[4],而周期性的刷新会对访存性能带来一定的负面影响。所以通过将SB存储拆分成多个Bank,可以将周期性刷新的影响在一定程度上减小。
&/b&&/i&&br&&i&&b&II.将SB拆分开,放置在每个NFU的周围,可以让每个计算部分在计算过程中,访问其所需的模型参数时,访存延迟更小,从而获得计算性能上的收益。
&/b&&/i&&br&NFU的内部结构图如下所示:
&br&&figure&&img src=&https://pic2.zhimg.com/50/dba1eab213_b.jpg& data-rawwidth=&312& data-rawheight=&232& class=&content_image& width=&312&&&/figure&从上图,能够看到NFU的每个Pipeline Stage与NBin/NBout/SB的交互连接通路。 而针对不同的神经层,NFU的流水线工作模式可以见下图:
&br&&figure&&img src=&https://pic2.zhimg.com/50/c7f1bf778fe449ba0a7c3fa1fb10aa18_b.jpg& data-rawwidth=&517& data-rawheight=&289& class=&origin_image zh-lightbox-thumb& width=&517& data-original=&https://pic2.zhimg.com/50/c7f1bf778fe449ba0a7c3fa1fb10aa18_r.jpg&&&/figure&&br&注意,上图里红色的“The eDram”代表的就是SB存储。
&br&&br&以上是单个DaDianNao芯片的设计,而单个DaDianNao的片上用于存储模型参数的SB存储仍然有限(见下图,单个芯片里,用于NBin/NBout的central eDRAM尺寸是4MB,而每个Tile里用于SB的eDRAM尺寸则是2MB,每个芯片由16个Tile组成,所以单个芯片的eDRAM总量是&b&2 * 16 + 4 = 36MB&/b&),所以为了支持大模型,就需要由多个DaDianNao芯片构成的多片系统。
&br&&figure&&img src=&https://pic1.zhimg.com/50/df7d22e5bb6b_b.jpg& data-rawwidth=&478& data-rawheight=&127& class=&origin_image zh-lightbox-thumb& width=&478& data-original=&https://pic1.zhimg.com/50/df7d22e5bb6b_r.jpg&&&/figure&DaDianNao里的多片互联部分并没有进行定制开发,而是直接使用了HyperTransport 2.0[12]通信IP,在每个DaDianNao芯片的四周(每个芯片会跟上下左右四个邻近的DaDianNao芯片连接)提供了共四组HT 2.0的通信通道,每个通道的通信带宽是在in/out方向分别达到6.6GB/s,支持全双工通信,inter-chip的通讯延迟是80ns。
&br&有了inter-chip的连接支持,DaDianNao就可以支持大尺寸的模型了。不同模型,在inter-chip的工作模式下,通信的数据量也有较大的差异:
&br&&figure&&img src=&https://pic4.zhimg.com/50/d4abea6e9c0e89fc4fd179_b.jpg& data-rawwidth=&523& data-rawheight=&280& class=&origin_image zh-lightbox-thumb& width=&523& data-original=&https://pic4.zhimg.com/50/d4abea6e9c0e89fc4fd179_r.jpg&&&/figure&能够看到,相较于卷积层(CONV),全连接层(full NN)在多片模式下,通信耗时明显更多。 同样,卷积层的多片加速比也远大于全连接层(&b&对于一些全连接层,甚至在Inference环节,出现多片性能低于单片的情形,这也算make sense,毕竟,inference环节的计算通信比要小于training环节&/b&):
&br&&figure&&img src=&https://pic3.zhimg.com/50/cdea8a27ecf0f_b.jpg& data-rawwidth=&498& data-rawheight=&260& class=&origin_image zh-lightbox-thumb& width=&498& data-original=&https://pic3.zhimg.com/50/cdea8a27ecf0f_r.jpg&&&/figure&&figure&&img src=&https://pic3.zhimg.com/50/15c486fc0aab547c522a126f53486c0b_b.jpg& data-rawwidth=&537& data-rawheight=&296& class=&origin_image zh-lightbox-thumb& width=&537& data-original=&https://pic3.zhimg.com/50/15c486fc0aab547c522a126f53486c0b_r.jpg&&&/figure&具体的细节评估指标,在这里就不再引入,感兴趣的同学可以直接参考原始论文。
&br&&br&&br&References:
&br&[1]. Yunji Chen. DaDianNao: A Machine-Learning Supercomputer. Micro, 2014.
&br&[2]. S.-N. Hong and G. Caire. Compute-and-forward strategies for cooperative distributed antenna systems. In IEEE Transactions on Information Theory, 2013.
&br&[3] eDRAM. &a href=&//link.zhihu.com/?target=https%3A//en.wikipedia.org/wiki/EDRAM& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&eDRAM&/a&&br&[4]. Mittal. A Survey Of Architectural Approaches for Managing Embedded DRAM and Non-volatile On-chip Caches. IEEE TPDS, 2014.
&br&[5]. A Brief Introduction to The Dianao Project.
&a href=&//link.zhihu.com/?target=http%3A//novel.ict.ac.cn/diannao/& class=& external& target=&_blank& rel=&nofollow noreferrer&&&span class=&invisible&&http://&/span&&span class=&visible&&novel.ict.ac.cn/diannao&/span&&span class=&invisible&&/&/span&&span class=&ellipsis&&&/span&&/a&&br&[6]. Micro 2014. &a href=&//link.zhihu.com/?target=http%3A//www.microarch.org/micro47/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&MICRO-47 Home Page&/a&&br&[7]. N. Maeda, S. Komatsu, M. Morimoto, and Y. Shimazaki. A 0.41a standby leakage 32kb embedded sram with lowvoltage resume-standby utilizing all digital current comparator in 28nm hkmg cmos. In International Symposium on VLSI Circuits (VLSIC), 2012.
&br&[8]. G. Wang, D. Anand, N. Butt, A. Cestero, M. Chudzik, J. Ervin, S. Fang, G. Freeman, H. Ho, B. Khan, B. Kim, W. Kong, R. Krishnan, S. Krishnan, O. Kwon, J. Liu, K. McStay, E. Nelson, K. Nummy, P. Parries, J. Sim, R. Takalkar, A. Tessier, R. Todi, R. Malik, S. Stiffler, and S. Iyer. Scaling deep trench based edram on soi to 32nm and beyond. In IEEE International Electron Devices Meeting (IEDM), 2009.
&br&[9]. DDR3 SDRAM Part Catalog. &a href=&//link.zhihu.com/?target=https%3A//www.micron.com/products/dram/ddr3-sdram/ddr3-sdram-part-catalog%23/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Micron Technology, Inc.&/a&&br&[10]. Computational RAM. &a href=&//link.zhihu.com/?target=https%3A//en.wikipedia.org/wiki/Computational_RAM& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Computational RAM&/a&&br&[11] T. Chen, Z. Du, N. Sun, J. Wang, and C. Wu. DianNao: a small-footprint high-throughput accelerator for ubiquitous machine learning. Proceedings of the 19th International Conference on Architectural Support for Programming Languages and Operating Systems (ASPLOS), Salt Lake City, UT, USA, 2014, pp. 269–284.
&br&[12]. HyperTransport. &a href=&//link.zhihu.com/?target=https%3A//en.wikipedia.org/wiki/HyperTransport& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&HyperTransport&/a&&br&[13]. Zidong Du.
ShiDianNao: Shifting Vision Processing Closer to the Sensor. ISCA, 2015.&br&---------------------------------------------------------------------------------------------------------------&br&&b&4.DianNao&/b&&br&[1]是DianNao项目[2]的第一篇,也是篇开创性论文,发在了ASPLOS 14上,并且获得了当年的best paper。
&br&如果用一句话来提炼这篇论文的核心思想,我想可以这样总结:
&br&&b&结合神经网络模型的数据局部性特点以及计算特性,进行存储体系以及专用硬件设计,从而获取更好的性能加速比以及计算功耗比。
&br&&/b&因为我阅读DianNao项目系列论文是按时间序反序延展的,先后读的是&i&PuDianNao[5]-&ShiDianNao[4]-&DaDianNao[3],最后读的是DianNao这篇论文&/i&。所以从设计复杂性来说,ASPLOS 14的这篇论文应该说是最简单的。当然,这样说并不是说这篇论文的价值含量比其他论文低。恰恰相反,&b&&i&我个人以为这篇论文的价值其实是最高的,因为这是一篇具备开创性意义的论文,在科研领域,我认为starter要比follower更有意义的多,这种意义并不会因为follower在执行操作层面的出色表现就可以减色starter的突破性贡献。 因为starter是让大家看到了一种之前没有人看到的可能性,而follower则是在看到了这种可能性之后,在执行操作层面的精雕细琢。几个经典的例子就是第一个超导材料的发现带动了后续多种超导材料的发现,以及刘易斯百米短跑突破10秒之后带动了多位运动员跑入10秒之内的成绩。&/i&&/b&&br&在[1]这篇论文里,先是回顾了之前常见的神经网络的全硬件实现方案(full-hardware implementation)——将每个神经元都映射到具体的硬件计算单元上,模型权重参数则作为latch或是RAM块实现,具体的示意结构图如下:
&br&&figure&&img src=&https://pic2.zhimg.com/50/94fe44696bbc31f064de_b.jpg& data-rawwidth=&463& data-rawheight=&307& class=&origin_image zh-lightbox-thumb& width=&463& data-original=&https://pic2.zhimg.com/50/94fe44696bbc31f064de_r.jpg&&&/figure&&br&这种方案的优点很明显,实现方案简洁,计算性能高,功耗低。缺点也不难想象,扩展性太差,无论是模型topology的变化,还是模型尺寸的增加都会使得这种方案无法应对。下面针对不同 input neurons/网络权重数 的network layer给出了full-hardware implementation在硬件关键路径延时/芯片面积/功耗上的变化趋势,能够直观地反映出full-hardware这种实现方案的伸缩性问题:
&br&&figure&&img src=&https://pic1.zhimg.com/50/bfc542a762da7bb90c48e538ab1910fe_b.jpg& data-rawwidth=&400& data-rawheight=&284& class=&content_image& width=&400&&&/figure&&br&针对full-hardware方案的不足,在[1]里提出了基于时分复用原则的加速器设计结构:
&br&&figure&&img src=&https://pic3.zhimg.com/50/ede54de51ca91_b.jpg& data-rawwidth=&533& data-rawheight=&397& class=&origin_image zh-lightbox-thumb& width=&533& data-original=&https://pic3.zhimg.com/50/ede54de51ca91_r.jpg&&&/figure&&br&在这个设计结构里,加速器芯片里包含三块片上存储,分别是用于存储input neurons的NBin、存储output neurons的NBout以及用于存储神经网络模型权重参数的SB。这三块存储均基于SRAM实现,以获取低延时和低功耗的收益。片上存储与片外存储的数据交互方式通过DMA来完成,以尽可能节省通讯延时。
&br&除了片上存储以外,另一个核心部件则是由三级流水线组成的NFU(Neural Functional Unit),完成神经网络的核心计算逻辑。
&br&&b&&i&时分复用的思想,正是体现在NFU和片上存储的时分复用特性。针对一个大网络,其模型参数会依次被加载到SB里,每层神经layer的输入数据也会被依次加载到NBin,layer计算结果写入到NBout。NFU里提供的是基础计算building block(乘法、加法操作以及非线性函数变换),不会与具体的神经元或权重参数绑定,通过这种设计,DianNao芯片在支持模型灵活性和模型尺寸上相较于full-hardware implementation有了明显的改进。
&br&&/i&&/b&DianNao加速器的设计中一些比较重要的细节包括:
&br&&b&&i&I. 使用16位定点操作代替32位浮点,这在模型的精度方面,损失并不大&/i&&/b&:
&br&&figure&&img src=&https://pic1.zhimg.com/50/d9dccc8ff_b.jpg& data-rawwidth=&507& data-rawheight=&517& class=&origin_image zh-lightbox-thumb& width=&507& data-original=&https://pic1.zhimg.com/50/d9dccc8ff_r.jpg&&&/figure&&br&&b&&i&但是在芯片面积和功耗上都获得了明显的收益&/i&&/b&:
&br&&figure&&img src=&https://pic2.zhimg.com/50/263fbe261c1bedcabea427f_b.jpg& data-rawwidth=&489& data-rawheight=&120& class=&origin_image zh-lightbox-thumb& width=&489& data-original=&https://pic2.zhimg.com/50/263fbe261c1bedcabea427f_r.jpg&&&/figure&&br&&b&&i&II. 之所以将片上SRAM存储划分为NBin/NBout/SB这三个分离的模块,是考虑到SRAM的不同访存宽度(NBin/NBout与SB的访存宽度存在明显差异,形象来说,NBin/NBout的访存宽度是向量,而SB则会是矩阵)在功耗上存在比较明显的差异:&/i&&/b&&br&&figure&&img src=&https://pic3.zhimg.com/50/9e7b19d84a1b35e6bd9afaa9_b.jpg& data-rawwidth=&431& data-rawheight=&231& class=&origin_image zh-lightbox-thumb& width=&431& data-original=&https://pic3.zhimg.com/50/9e7b19d84a1b35e6bd9afaa9_r.jpg&&&/figure&&br&&b&&i&拆分成不同的模块,可以在功耗/性能上找到更佳的设计平衡点。而将访存宽度相同的NBin/NBout也拆分开来的原因则是为了减少data conflict,因为NBin/NBout扮演的还是类似于cache的角色,而这两类数据的访存pattern并不尽相同,如果统一放在一块SRAM里,cache conflict的概率会增大,所以通过将访存pattern相近的数据对应于不同的SRAM块,“专款专用”,可以进一步减少cache conflict,而cache conflict的减少,无论是对于性能的提升,还是功耗的减少都会有着正面的意义。
&br&III. 对input neurons数据以及SB数据局部性的挖掘。用通俗一些的说法,其实就是把输入数据的加载与计算过程给overlap起来。在针对当前一组input neurons进行计算的同时,可以通过DMA启动下一组input neurons/SB参数的加载。当然,这要求精细的co-ordination逻辑保证。另外,这也会要求NBin/SB的SRAM存储需要支持双端口访问,这对功耗和面积会带来一定的影响[6]。
&br&IV. 对output neurons数据局部性的挖掘。在设计上,为NFU引入了专用寄存器,用于存储output neurons对应的partial计算结果(想象一下对应于全连接层的一个output neuron,input neurons太多,NBin放不下,需要进行多次加载计算才能完成一个output neuron的完整结果的输出)。并且会在设计上将NBout用作专用寄存器的扩展,存放partial计算结果,以减少将partial计算结果写入片外存储的性能开销。
&br&&/i&&/b&&br&整体上的设计思想大体上如上所述。
&br&在实验评估上,可能是因为作为第一个milestone的工作结果,还有很多细节有待雕琢,所以在baseline的选取上与后续的几篇论文相比,显得有些保守,在这篇论文里只选取了CPU作为baseline,并未将GPU作为baseline。具体的评估细节及指标可以直接参看原始论文,我这里不再重复。&br&&br&References:
&br&[1]. Tianshi Chen. DianNao: A Small-Footprint High-Throughput Accelerator for Ubiquitous Machine-Learning. ASPLOS, 2014.
&br&[2]. A Brief Introduction to The Dianao Project.
&a href=&//link.zhihu.com/?target=http%3A//novel.ict.ac.cn/diannao/& class=& external& target=&_blank& rel=&nofollow noreferrer&&&span class=&invisible&&http://&/span&&span class=&visible&&novel.ict.ac.cn/diannao&/span&&span class=&invisible&&/&/span&&span class=&ellipsis&&&/span&&/a&&br&[3]. Yunji Chen. DaDianNao: A Machine-Learning Supercomputer. Micro, 2014.
&br&[4]. Zidong Du.
ShiDianNao: Shifting Vision Processing Closer to the Sensor. ISCA, 2015.
&br&[5]. Daofu Liu. PuDianNao: A Polyvalent Machine Learning Accelerator. ASPLOS, 2015.
&br&[6]. What is dual-port RAM. &a href=&//link.zhihu.com/?target=http%3A//www.futureelectronics.com/en/memory/dual-ports.aspx& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Dual port memory, dual ported memory, Ports, sdram, sram, sdram, memories&/a&
(更新历史: 10.5号更新,加入了DianNao部分的内容; 10.4号更新,加入了DaDianNao部分的内容; 10.2号更新,加入了ShiDianNao部分的内容;) 最近正好在比较系统地关注AI硬件加速的东东。 前几天比较细致的读了一下ISCA16上关于寒武纪指令集的文章,在这里(
&p&&/p&&p&把完整的《出乌兰记》贴上来吧:&/p&&p&盘先生管匈奴乳业记(上):&/p&&p&出乌兰记——盘先生在美丽坚&/p&&p&(本故事纯属虚构,如有雷同,纯属巧合。勿将现实人事物对号入座。)&/p&&p&在山的那边水的那边有一个乌兰国,乌兰国有一个大省叫匈奴省,匈奴省有一个乳业公司叫匈奴乳业,因为是上市公司,大家也叫它匈奴股份。&/p&&p&匈奴股份的董事长盘盘先生去了更远的山的那边水的那边的美丽坚果已有半年。乌兰国很多有钱人甚至是官员的家属都爱去这个叫美丽坚果的国家定居,官员退休后爱也在美丽坚果养老。&/p&&p&匈奴股份是上市公司,董事长离岗半年时间不回来,按说此事非同小可,但上市公司没有发布公告,像我大天朝有一家叫乐视的公司,董事长贾布斯离开期间还会定期说下周回国。盘先生干脆来个封锁消息。所以这事分外蹊跷。&/p&&p&这事还要从丁酉年说起,丁酉年乌兰国的建国节,盘先生对内说要去美丽坚果的弗哈大学讲课。&/p&&p&丁酉年晚秋乌兰国长老要进行换届选举,盘先生作为长老院议员,要参与选举,但他却在选择前将近一个月离开,并以去美丽坚果治病为由请假。&/p&&p&有人说盘先生 的妻子和儿女早就去了美丽坚果,并且获得了美丽坚果的国籍。盘先生的父母也紧随其后去了美丽坚果。今年盘先生的弟弟小盘先生全家也去了美丽坚果,他们不但全家团聚,还幸福地生活在一起。&/p&&p&盘先生是个成功的企业家,一向非常低调,所以大家对他了解不多。他在30岁就当了匈奴股份的董事长。&/p&&p&大家或许不以为然,认为他这么快成功可能是他有一个有本事的爹,天禄君拍着胸脯向大家打保票,他真没有,他的成功全靠个人努力。&/p&&p&不过他是有脑子的努力,这个世界到处都是才华横溢并非常努力的穷人,比如天禄君,怎么努力到目前也没有成功,主要是源于天禄君情商太低。&/p&&p&盘盘先生靠自己的努力乘着蹿天猴迅速登上董事长高位。他的情商成就了他的今天。表现之一在于他抱对了两个人的大腿。&/p&&p&他不但成功的把第一个大腿送进了牢中,还代替他坐上了董事长位置,这个人就是关耳先生。大家都叫他关老爷子或关大先生。自此后盘先生就牢牢地控制了匈奴股份,以至他出走半年匈奴股份的人也没有把这事发布公告。&/p&&p&丁酉年子月,匈奴股份召开管理层会议,盘先生不回乌兰国,他是主事人,他不回来这会怎么开呢?不愧是有脑子的聪明人,盘先生有的是办法。他让所有的高管都去美丽坚果。虽然匈奴股份是乌兰国行业龙头,但也不是所有的高管都去过美丽坚果。并且让高管去美丽坚果开会也算奖励。大家何乐不为呢?这个一箭双雕利人利己的举动颇得匈奴股份的高管的好感。&/p&&p&各位看官,话说乌兰国以上国自居,一个小小的企业的董事长本是不值得一提之人,想必会疑惑天禄君为何对他大书特书。&/p&&p&各位有所不知,我天朝到处都是想成功的人,成功学也是一门显学,盘先生的成功何尝不是一个励志故事,他山之石可以攻玉,乌兰国的成功故事谁说我国的人就不能从中有所斩获?&/p&&p&各位看了或许小有裨益。天禄君的小号本是供列位茶余饭后消遣之所,不是资治经国之处,所以,盘先生的事值得各位一看,想看帝王将相、才子佳人的故事,请移步去看红楼梦三国演义。&/p&&p&盘先生从一个地方院校的大专学生成本上国大公司董事长,只用了不到十年,并且身家过亿。在人称杀猪榜的富布斯富豪榜上有名。这是绝大多数人包括天禄君一辈子达不到的高度。&/p&&p&盘先生的发迹要从他小学说起,当年他考上的是匈奴农牧学院,是检验检疫专业的专科生,本来这样的学生要分配回原籍西林河市。但他不想回去。&/p&&p&但农牧学院的人都知道匈奴股份的董事长关大先生的弟弟关二先生是农奴学院的一位副处级干部,通过他的关系可以进入匈奴股份。&/p&&p&关二先生和关公关二爷一样为人比较义气。盘先生通过他的班主任跟关二先生接上头,表示想进匈奴股份。不知是出于什么原因,二先生或许对他很欣赏,就给自己的大哥打电话推荐盘先生也就是当时的小盘。了解了情况后,关大先生对关二先生说:“我们是挤奶的,不是杀猪的,检验检疫专业不对口啊!”&/p&&p&关于先生一听急了说:“大哥,你可以让他负责化验啊,都是用一样的知识。”&/p&&p&碍于弟弟的面子,也不能不接收,于是当时的小盘就成了匈奴股份的一名化验员。&/p&&p&盘先生虽然只是最底层的化验员,但毕竟有关二先生的关照,关大先生也对他颇为照顾。所以升迁的特别快。并且盘先生对关老爷子的家人也特别殷勤,因此小盘颇得关家人喜欢。&/p&&p&他升到一定高位后,盘先生仍然每天到办公室后先向各位比他级别高的人请安,然后才回自己的办公室。&/p&&p&因此他这样的人升迁快是必然的,否则是没天理的。盘盘先生迅速的就成了二把手,位居关大先生之下,成为关大先生的接班人。&/p&&p&储君要么格外小心的忍,要么迅速取而代之。小盘先生选择了后者。&/p&&p&不过小盘先生接替关大先生做了董事长,还要提一件事。匈奴股份的竞争对手柔然乳业发展的特别快,尤其是小盘先生分管的液态奶这块儿,更让他感觉害怕。癸卯年,他为了压过柔然乳业。他就找了乌兰国首都平都的一家公关公司发布抹黑柔然乳业的假新闻。这事被匈奴省警察察出是小盘盘操作,于是将小盘先生抓捕归案。&/p&&p&按说这事应该会将小盘盘的前途毁掉,但人走运了跌倒在地啃的不是狗屎而是黄金,小盘先生就走了比这还走运的运。&/p&&p&一是关大先生将小盘保了出来,做内部处理。按说关大先生再一次有恩于小盘盘,是小盘的再生父母,他应该对关大先生的保护之恩铭记五内、永世不忘。但他没有。&/p&&p&话说小盘出事的头一年也就是壬午年,匈奴省决定将部分国有资产转让给国企的管理层,在匈奴颇有势力的神秘人,江湖人称灰哥。他的来历谁也不知道,反正在匈奴地界儿,谁都得给他三分面儿了。&/p&&p&灰哥听说匈奴股份要进行MBO,于是就想把这部分股份拿到自己手里,过几年通过资本市场一转让,就是十几几十倍的收益,这服水既然在自己地界上,肯定不能流了外人田。&/p&&p&但关大先生就是不同意,怕他这样做一则是违法,二是把企业搞坏了。毕竟匈奴股份是在他手上做大的。像自己的孩子一样,不容易别人来插手。&/p&&p&灰哥找到了因发布友商假新闻而失意的小盘先生,双方一拍即合,内外合作,双方举报正在收购国有股份的关大先生违规,本来乌兰国证监会调查得出结论是违规操作,不过匈奴省相关部门却对乌兰国证监会说我们匈奴省的事自己处理,最后匈奴检察院以侵吞国有资产的罪名起诉,关大先生被判了六年。&/p&&p&小盘先生于是接手了关大先生的职务,成了匈奴股份的董事长。一坐就是十几年,真是稳如泰山。&/p&&p&话说丁酉年乌兰国长老院换届,部分长老引退,匈奴省就传盘先生可能要出事。但早在换届前的30天,就是建国节前,盘先生就离开乌兰国,但对内称要去美丽坚果的弗哈大学讲课。对换届选举称是治病请假。业界也有传盘先生出走是与一位长老引退有关。&/p&&p&此前,关大先生谈及此事,他说盘先生这人特点特别明显:一是见风使舵,谁得势就跟谁亲近;二是翻脸不认人,虽然利用人时恨不给叫人爹,但利用完了则翻脸不认人;三是比翻脸不认人还狠的是过河拆桥,对恩人心狠手辣,他对关大先生就是例子。&/p&&p&但就是这样的成就让盘先生走上高位,所以说诸位欲成大事还得心狠手辣,不择手段。&/p&&p&后来有一家叫《乌兰企业家》的杂志一个爱多事的包打听报道了此事。灰哥非常恼怒,他带着盘先生找到乌兰企业家杂志社长西华帝君,让他把这个多事的包打听处理了,不过西华帝君不干。他说:“如果报道失实我们处理,如果没有失实我们怎么能处理?”&/p&&p&虽然西华帝君有骨气顶住了压力,但一年后西华帝君离开了这家杂志社,或许与此事有关。据说西华帝君办了一个叫桃花岛的会所,没事经常召集他的企业家好友谈玄论道。&/p&&p&盘先生故事三箩筐,一篇文章讲不完,欲知后事如何,且听下回分解。&/p&&p&&br&&/p&&p&上回介绍了盘先生的发家史,以及滞留美丽坚果长达半年不归的消息,其实乌兰上国是在他们的星球上力量很强大,能把美丽坚果一锤子砸个窟窿,只是盘先生无足轻重,所以一时没有理会他,并不是弄不回来他。&/p&&p&但需要他配合时,小盘盘还是乖乖回来,一下飞机就被检察机关带走去协助调查。很多人说他是无足轻重的人物,所以配合调查后就暂时无事。目前安全。&/p&&p&但这事还是传开了,匈奴股份的股价下跌的厉害。&/p&&p&盘盘和匈奴股份的人还是要想办法挺住股价的。否则要像我天朝的乐视一样,那就惨了。&/p&&p&据传戊戌年巳月将于北方小岛举办厚龟论坛,这个厚龟论坛每年的巳月都要举办,虽是北方,但到了巳月春暖花开,气侯宜人,正好是举行论坛的好时节。经济界和政界大咖共处一室,商讨全球经济事宜,这在乌兰国是逼格很高的大会。&/p&&p&乌兰国电视台一个奶油小生主持人经常说这是他和他的老朋友聚会的节日。&/p&&p&盘盘先生被传闻缠身,也影响了公司发展。股价跌的有点难看,为了重振股价,盘盘先生决定参加厚龟论坛。据说是花了重金的,不低于500万乌兰币,反正是一定要参与,还要在论坛上发言。就是为了挽回形象。也是为了挺住股价,说不定某些股东把股票已经质押了,如果股价再跌,股票就要平仓了。&/p&&p&而某些股东的股票要是不保,小盘盘下场是什么样子也是个问题!&/p&&p&所以说,盘盘先生不但是个努力的人,还是个有担当的人。愿意为了公司和家人做出牺牲的人。全家安排在美丽坚果,但人必须回来奋斗。这么做不排除是拿自己当人质保家人安全。&/p&&p&再说说关大先生。关大小先生把小盘盘一手培养起来,却没想被到被他害的这么惨。关大先生羁押期间的两年工资一直不给。关大先生在看过所押着,小盘盘却派律师去跟关大先生解除工作关系。&/p&&p&关大先生的儿女都在上学,尤其是女儿学费特别贵,但关大先生家人如何求着要求关大先生的工资,小盘盘都不给。最后还是竞争对手柔然乳业的董事长帮助筹的学费。&/p&&p&之所以这么狠,关大先生说,做贼的人都心虚,杀人的人都心狠,害了人他就怕你翻身,再找他的事。小盘盘害怕关大先生手里有钱就可以运作翻身,毕竟没钱的人是翻不起大浪来。&/p&&p&就像天禄君曾爱上过一个母夜叉,但母夜叉觉得天禄君是屌丝,配不上他,想尽办法害天禄君,天禄君为此母夜叉不放弃了一份工作,但此母夜叉还到处说天禄君对她性骚扰,把天禄君名声弄的很狼狈,并且还说要让天禄君混不下去。反正目的就是让天禄君此生不得翻身,天禄君对此倒是无所谓,去工地搬砖也能混出一口饭吃来。母夜叉是记者,但却自己拉广告,拉来广告也只让经营人员走手续,钱全装自己腰包了,按说这是典型的违法犯罪的事。但没底限的人什么事都做得出来,别人不敢干的事,在她不过是寻常小事。&/p&&p&天禄君在某报做记者,收到某些大公司欺负小公司的消息,就想报道,报道不了就想在外面八卦一下。此母夜叉虽然是报社养的狗,却经常替企业看家。不知道是不是拿了企业的好处,企业公关给他说我坏话后,她经常骂天禄君,以致大家都说她拿了某企业的钱,拿没拿钱不知道,那个做狗的劲儿的确让人感觉有点下贱。&/p&&p&天禄君向来是吃软不吃硬的主,谁敢对老子说话不中听,老子灭他全家,但被母夜叉迷的五迷三道,竟然不以为意,有紫微斗数高手说天禄君命宫煞星多,然爱上丑女,就像有人吃饭爱吃卤煮大肠、炒肝之类的怪味道的东西一样。如果像现在天禄君脑子这么清醒,母夜叉为了给企业当狗敢对天禄君这么说话,她的牙不知道会被天禄群抽掉几颗。&/p&&p&听说这个母夜叉被富二代老公甩了后,脑子变的不正常,身为采编人员,却天天拉广告,像上海啊什么的各地经营人员拉来的广告她非要别人让给她,变成自己的业绩,只给人一个虚拟任务,她天天和怨妇式的说自己孤儿寡母不容易。大家包括天禄君心软就让着他了,但此人不知进退,不懂适可而止。现在天下不知道有多少在盼她赚钱多的乐死、打炮高潮爽死、排挤其他同事成功把她膨胀死。&/p&&p&当然以上的故事也是纯属虚构,本来就是为了配合这个虚构的故事说说道理。天禄君爱现身说法,我想哪天天禄群当了导演,一定会参与其中的角色,过过戏瘾,哪怕只是一个死跑龙套的。&/p&&p&扯远了,再说这事乌兰佚事,出来混迟早要还,挡人财路如杀人父母,所以害人之事做不得,更何况还对你有天大的栽培之恩。天禄君是个很厚道的人,如果想起欠某个人的情,一定会还,哪怕两个人已经没有来往,也会想办法补偿,为的是问心无愧。不欺鬼神不欺心,否则夜里睡不着觉。&/p&&p&眼看他起高楼,眼看他宴宾客,眼看他楼要塌了。&/p&&p&关大先生说,当年如果顺了灰哥,当时不出事,现在肯定会出事。看来不同意灰哥的要求并没有错,最起码现在心安!&/p&&p&本故事到此先告一段落,天禄君脑洞有限,编不下去了,以后有缘定会再讲。&/p&&p&(再次申明,本故事纯属虚构,切勿对号入座。)&/p&&p&&/p&
把完整的《出乌兰记》贴上来吧:盘先生管匈奴乳业记(上):出乌兰记——盘先生在美丽坚(本故事纯属虚构,如有雷同,纯属巧合。勿将现实人事物对号入座。)在山的那边水的那边有一个乌兰国,乌兰国有一个大省叫匈奴省,匈奴省有一个乳业公司叫匈奴乳业,因…
&p&蔡依林演唱会上翻唱的《小幸运》,没有找到官方版本,但是不影响去体会那个feel&/p&&a class=&video-box& href=&//link.zhihu.com/?target=https%3A//www.zhihu.com/video/589248& target=&_blank& data-video-id=&& data-video-playable=&true& data-name=&& data-poster=&https://pic1.zhimg.com/80/v2-dd551279fee227b6ba138c_b.jpg& data-lens-id=&589248&&
&img class=&thumbnail& src=&https://pic1.zhimg.com/80/v2-dd551279fee227b6ba138c_b.jpg&&&span class=&content&&
&span class=&title&&&span class=&z-ico-extern-gray&&&/span&&span class=&z-ico-extern-blue&&&/span&&/span&
&span class=&url&&&span class=&z-ico-video&&&/span&https://www.zhihu.com/video/589248&/span&
&/a&&p&把转载的链接也放在这&/p&&a href=&//link.zhihu.com/?target=http%3A//v.youku.com/v_show/id_XMzM3MDI4MjczNg%3D%3D.html%3Fspm%3Da2h0k..0%26from%3Ds1.8-1-1.2& data-draft-node=&block& data-draft-type=&link-card& data-image=&https://pic3.zhimg.com/v2-6ddbe150de_180x120.jpg& data-image-width=&200& data-image-height=&112& class=& external& target=&_blank& rel=&nofollow noreferrer&&&span class=&invisible&&http://&/span&&span class=&visible&&v.youku.com/v_show/id_X&/span&&span class=&invisible&&MzM3MDI4MjczNg==.html?spm=a2h0k..0&from=s1.8-1-1.2&/span&&span class=&ellipsis&&&/span&&/a&&p&侵删&/p&
蔡依林演唱会上翻唱的《小幸运》,没有找到官方版本,但是不影响去体会那个feel把转载的链接也放在这侵删
&figure&&img src=&https://pic3.zhimg.com/v2-88b3fd101b830ed0a2eab_b.jpg& data-rawwidth=&640& data-rawheight=&426& class=&origin_image zh-lightbox-thumb& width=&640& data-original=&https://pic3.zhimg.com/v2-88b3fd101b830ed0a2eab_r.jpg&&&/figure&今日头条当前后端服务超过80%的流量是跑在 Go 构建的服务上。微服务数量超过100个,高峰 QPS 超过700万,日处理请求量超过3000亿,是业内最大规模的 Go 应用。&h1&&b&Go 构建微服务的历程&/b&&/h1&&p&在2015年之前,头条的主要编程语言是 Python 以及部分 C++。随着业务和流量的快速增长,服务端的压力越来越大,随之而来问题频出。Python 的解释性语言特性以及其落后的多进程服务模型受到了巨大的挑战。此外,当时的服务端架构是一个典型的单体架构,耦合严重,部分独立功能也急需从单体架构中拆出来。&/p&&p&&b&为什么选择 Go 语言?&/b&&/p&&p&Go 语言相对其它语言具有几点天然的优势:&/p&&ol&&li&&p&语法简单,上手快&/p&&/li&&li&&p&性能高,编译快,开发效率也不低&/p&&/li&&li&&p&原生支持并发,协程模型是非常优秀的服务端模型,同时也适合网络调用&/p&&/li&&li&&p&部署方便,编译包小,几乎无依赖&/p&&/li&&/ol&&p&当时 Go 的1.4版本已经发布,我曾在 Go 处于1.1版本的时候,开始使用 Go 语言开发后端组件,并且使用 Go 构建过超大流量的后端服务,因此对 Go 语言本身的稳定性比较有信心。再加上头条后端整体服务化的架构改造,所以决定使用 Go 语言构建今日头条后端的微服务架构。&/p&&p&2015年6月,今日头条开始使用 Go 语言重构后端的 Feed 流服务,期间一边重构,一边迭代现有业务,同时还进行服务拆分,直到2016年6月,Feed 流后端服务几乎全部迁移到 Go。由于期间业务增长较快,夹杂服务拆分,因此没有横向对比重构前后的各项指标。但实际上切换到 Go 语言之后,服务整体的稳定性和性能都大幅提高。&/p&&h1&&b&微服务架构&/b&&/h1&&p&对于复杂的服务间调用,我们抽象出五元组的概念:(From, FromCluster, To, ToCluster, Method)。每一个五元组唯一定义了一类的RPC调用。以五元组为单元,我们构建了一整套微服务架构。&/p&&p&我们使用 Go 语言研发了内部的微服务框架 kite,协议上完全兼容 Thrift。以五元组为基础单元,我们在 kite 框架上集成了服务注册和发现,分布式负载均衡,超时和熔断管理,服务降级,Method 级别的指标监控,分布式调用链追踪等功能。目前统一使用 kite 框架开发内部 Go 语言的服务,整体架构支持无限制水平扩展。&/p&&p&关于 kite 框架和微服务架构实现细节后续有机会会专门分享,这里主要分享下我们在使用 Go 构建大规模微服务架构中,Go 语言本身给我们带来了哪些便利以及实践过程中我们取得的经验。内容主要包括并发,性能,监控以及对Go语言使用的一些体会。&/p&&p&&b&并发&/b&&/p&&p&Go 作为一门新兴的编程语言,最大特点就在于它是原生支持并发的。和传统基于 OS 线程和进程实现不同,Go 语言的并发是基于用户态的并发,这种并发方式就变得非常轻量,能够轻松运行几万甚至是几十万的并发逻辑。因此使用 Go 开发的服务端应用采用的就是“协程模型”,每一个请求由独立的协程处理完成。&/p&&p&比进程线程模型高出几个数量级的并发能力,而相对基于事件回调的服务端模型,Go 开发思路更加符合人的逻辑处理思维,因此即使使用 Go 开发大型的项目,也很容易维护。&/p&&p&&b&并发模型&/b&&/p&&p&Go 的并发属于 CSP 并发模型的一种实现,CSP 并发模型的核心概念是:“不要通过共享内存来通信,而应该通过通信来共享内存”。这在 Go 语言中的实现就是 Goroutine 和 Channel。在1978发表的 CSP 论文中有一段使用 CSP 思路解决问题的描述。&/p&&p&“Problem: To print in ascending order all primes less than 10000. Use an array of processes, SIEVE, in which each process inputs a prime from its predecessor and prints it. The process then inputs an ascending stream of numbers from its predecessor and passes them on to its successor, suppressing any that are multiples of the original prime.”&/p&&p&要找出10000以内所有的素数,这里使用的方法是筛法,即从2开始每找到一个素数就标记所有能被该素数整除的所有数。直到没有可标记的数,剩下的就都是素数。下面以找出10以内所有素数为例,借用 CSP 方式解决这个问题。&/p&&p&&figure&&img src=&https://pic3.zhimg.com/v2-6bbd02063b8faa409b07_b.jpg& data-rawwidth=&640& data-rawheight=&257& class=&origin_image zh-lightbox-thumb& width=&640& data-original=&https://pic3.zhimg.com/v2-6bbd02063b8faa409b07_r.jpg&&&/figure&从上图中可以看出,每一行过滤使用独立的并发处理程序,上下相邻的并发处理程序传递数据实现通信。通过4个并发处理程序得出10以内的素数表,对应的 Go 实现代码如下:&br&&/p&&figure&&img src=&https://pic1.zhimg.com/v2-f8a5a200e4dcc06cde9c_b.jpg& data-rawwidth=&640& data-rawheight=&266& class=&origin_image zh-lightbox-thumb& width=&640& data-original=&https://pic1.zhimg.com/v2-f8a5a200e4dcc06cde9c_r.jpg&&&/figure&&figure&&img src=&https://pic2.zhimg.com/v2-bb5dfc1a3ec_b.jpg& data-rawwidth=&640& data-rawheight=&333& class=&origin_image zh-lightbox-thumb& width=&640& data-original=&https://pic2.zhimg.com/v2-bb5dfc1a3ec_r.jpg&&&/figure&&p&这个例子体现使用 Go 语言开发的两个特点:&/p&&ol&&li&&p&Go 语言的并发很简单,并且通过提高并发可以提高处理效率。&/p&&/li&&li&&p&协程之间可以通过通信的方式来共享变量。&/p&&/li&&/ol&&p&&b&并发控制&/b&&/p&&p&当并发成为语言的原生特性之后,在实践过程中就会频繁地使用并发来处理逻辑问题,尤其是涉及到网络I/O的过程,例如 RPC 调用,数据库访问等。下图是一个微服务处理请求的抽象描述:&/p&&figure&&img src=&https://pic3.zhimg.com/v2-648fa97c53d8f3ac111a3d30a7caf8df_b.jpg& data-rawwidth=&640& data-rawheight=&359& class=&origin_image zh-lightbox-thumb& width=&640& data-original=&https://pic3.zhimg.com/v2-648fa97c53d8f3ac111a3d30a7caf8df_r.jpg&&&/figure&&p&当 Request 到达 GW 之后,GW 需要整合下游5个服务的结果来响应本次的请求,假定对下游5个服务的调用不存在互相的数据依赖问题。那么这里会同时发起5个 RPC 请求,然后等待5个请求的返回结果。为避免长时间的等待,这里会引入等待超时的概念。超时事件发生后,为了避免资源泄漏,会发送事件给正在并发处理的请求。在实践过程中,得出两种抽象的模型。&/p&&ul&&li&&p&Wait&/p&&/li&&li&&p&Cancel &figure&&img src=&https://pic2.zhimg.com/v2-3bc90ee0c_b.jpg& data-rawwidth=&640& data-rawheight=&290& class=&origin_image zh-lightbox-thumb& width=&640& data-original=&https://pic2.zhimg.com/v2-3bc90ee0c_r.jpg&&&/figure&&figure&&img src=&https://pic4.zhimg.com/v2-f5c07a9df9aa97_b.jpg& data-rawwidth=&640& data-rawheight=&289& class=&origin_image zh-lightbox-thumb& widt

我要回帖

更多关于 梦三国刷关卡英雄 的文章

 

随机推荐