卷积神经网络硬件加速——INT8数据精度加速

卷积神经网络硬件加速——INT8数据精度加速


  上一专题已介绍了一种通用的卷积神经网络硬件加速方法——Supertile,本文将介绍一种特殊的硬件加速方案,一种INT8数据精度下的双倍算力提升方案。

  目前大部分卷积神经网络模型的数据类型都是32-bits单精度浮点型,或者16-bits,但对于实际应用而言,99%和99.5%的网络准确率是没有区别的。所以,对于某些场景下,网络的数据精度使用INT8的数据类型就能较好的胜任工作。



INT8数据硬件加速原理

  Xilinx DSP48E2系列的硬核乘法器最大支持27-bits * 18-bits位宽的乘法,而对于INT8数据的卷积运算而言,其只需要使用8-bits * 8-bits的数据位宽,这过多的浪费了DSP资源。

  于是乎,我们可以考虑是否可以利用1个DSP资源,同时计算多个INT8数据的卷积。幸运的是,DSP的结构恰好满足我们的要求,可以通过将两个乘数拼接在一个数据中进行计算,完成计算后再将两个结果分离,具体的并行原理见下图:


请添加图片描述

  DSP的两个预加法器端口A、D最小位宽是27-bits,而两个8-bits数相乘最大位宽为16-bits,所以第二个权重放在高于16-bits的位置就可以避免低位乘法溢出带来的数据紊乱,具体DSP结构图在Supertile专题中有展示:FPGA在卷积神经网络中的双倍算力应用——Supertile技术分析

  为保证后续DSP级联完成累加功能,高位乘积和低位乘积间还需空余部分数据位保证累加不会发生加法溢出导致的错误。所以将权重w1放在低八位,权重w2放置高八位,中间留出11-bits的空档。

  通过如此拼接数据,可以在一个DSP的低8-bits和高8-bits中分别完成两个通道的卷积操作。如果使用的是Xilinx DSP48E2型号的DSP,结果中两个数据会存放在[15:0]和[34:19],中间存在3-bits的空挡,将DSP前后级联正好满足16次的累加操作的空间需求,如果再结合Supertile加速方法,最多可以在一个系统时钟周期内完成4次INT8数据精度的卷积运算



最后本文给出一个不同加速方案的性能对比:
方案 / 性能原始FP32卷积Supertile-FP32卷积Supertile-INT8卷积
1X2X4X

其中性能表示一个时钟周期内方案能完成的卷积个数,由于本文仅关注加速效率,所以将不对量化后的网络精度等进行比对。




搜索关注我的微信公众号【IC墨鱼仔】,获取我的更多IC干货分享!

  • 5
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
利用tensorflow实现的卷神经网络来进行MNIST手写数字图像的分类。 #导入numpy模块 import numpy as np #导入tensorflow模块,程序使用tensorflow来实现卷神经网络 import tensorflow as tf #下载mnist数据集,并从mnist_data目录中读取数据 from tensorflow.examples.tutorials.mnist import input_data mnist = input_data.read_data_sets('mnist_data',one_hot=True) #(1)这里的“mnist_data” 是和当前文件相同目录下的一个文件夹。自己先手工建立这个文件夹,然后从https://yann.lecun.com/exdb/mnist/ 下载所需的4个文件(即该网址中第三段“Four files are available on this site:”后面的四个文件),并放到目录MNIST_data下即可。 #(2)MNIST数据集是手写数字字符的数据集。每个样本都是一张28*28像素的灰度手写数字图片。 #(3)one_hot表示独热编码,其值被设为true。在分类问题的数据集标注时,如何不采用独热编码的方式, 类别通常就是一个符号而已,比如说是9。但如果采用独热编码的方式,则每个类表示为一个列表list,共计有10个数值,但只有一个为1,其余均为0。例如,“9”的独热编码可以为[00000 00001]. #定义输入数据x和输出y的形状。函数tf.placeholder的目的是定义输入,可以理解为采用占位符进行占位。 #None这个位置的参数在这里被用于表示样本的个数,而由于样本个数此时具体是多少还无法确定,所以这设为None。而每个输入样本的特征数目是确定的,即为28*28。 input_x = tf.placeholder(tf.float32,[None,28*28])/255 #因为每个像素的取值范围是 0~255 output_y = tf.placeholder(tf.int32,[None,10]) #10表示10个类别 #输入层的输入数据input_x被reshape成四维数据,其中第一维的数据代表了图片数量 input_x_images = tf.reshape(input_x,[-1,28,28,1]) test_x = mnist.test.images[:3000] #读取测试集图片的特征,读取3000个图片 test_y = mnist.test.labels[:3000] #读取测试集图片的标签。就是这3000个图片所对应的标签
Verilog HDL语言是数字电路设计领域的一种硬件描述语言,可用于设计各种数字电路,包括卷神经网络加速模块。以下是一个简单的卷神经网络加速模块的Verilog HDL代码示例: ```verilog module conv_accelerator( input clk, input rst, input [31:0] input_data, output reg [31:0] output_data ); // 定义卷核 parameter FILTER_WIDTH = 3; parameter FILTER_HEIGHT = 3; parameter FILTER_DEPTH = 3; parameter FILTER_SIZE = FILTER_WIDTH * FILTER_HEIGHT * FILTER_DEPTH; reg signed [7:0] filter [0:FILTER_SIZE-1]; // 定义输入和输出缓冲区 parameter INPUT_WIDTH = 32; parameter INPUT_HEIGHT = 32; parameter INPUT_DEPTH = 3; parameter INPUT_SIZE = INPUT_WIDTH * INPUT_HEIGHT * INPUT_DEPTH; reg [INPUT_WIDTH-1:0] input_buffer [0:INPUT_SIZE-1]; parameter OUTPUT_WIDTH = 30; parameter OUTPUT_HEIGHT = 30; parameter OUTPUT_DEPTH = 1; parameter OUTPUT_SIZE = OUTPUT_WIDTH * OUTPUT_HEIGHT * OUTPUT_DEPTH; reg [OUTPUT_WIDTH-1:0] output_buffer [0:OUTPUT_SIZE-1]; // 定义卷操作中的一些常量 parameter STRIDE = 1; parameter PADDING = 1; parameter ACTIVATION_THRESHOLD = 0; // 定义卷核寄存器 reg signed [31:0] filter_reg [0:FILTER_SIZE-1]; // 定义处理单元计数器 reg [31:0] unit_count; // 初始化卷核寄存器和处理单元计数器 initial begin for (int i = 0; i < FILTER_SIZE; i = i + 1) begin filter_reg[i] = filter[i]; end unit_count = 0; end // 定义卷操作的处理单元 always @(posedge clk) begin if (rst) begin unit_count <= 0; output_data <= 0; end else begin if (unit_count < OUTPUT_SIZE) begin // 计算输出像素的坐标 reg [7:0] x = (unit_count % OUTPUT_WIDTH) * STRIDE - PADDING; reg [7:0] y = (unit_count / OUTPUT_WIDTH) * STRIDE - PADDING; reg [31:0] sum = 0; // 进行卷操作 for (int i = 0; i < FILTER_SIZE; i = i + 1) begin reg [7:0] fx = i % FILTER_WIDTH - FILTER_WIDTH / 2; reg [7:0] fy = (i / FILTER_WIDTH) % FILTER_HEIGHT - FILTER_HEIGHT / 2; reg [7:0] fz = i / FILTER_SIZE - FILTER_DEPTH / 2; reg [31:0] pixel = input_buffer[(x+fx)*INPUT_WIDTH+(y+fy)*INPUT_DEPTH+fz]; sum = sum + filter_reg[i] * pixel; end // 使用激活函数判断输出像素是否激活 if (sum > ACTIVATION_THRESHOLD) begin output_buffer[unit_count] = sum; end else begin output_buffer[unit_count] = 0; end // 更新处理单元计数器和输出数据寄存器 unit_count <= unit_count + 1; output_data <= output_buffer[unit_count]; end end end endmodule ``` 上述代码实现了一个简单的卷神经网络加速模块,可接收32x32x3的输入数据,使用3x3x3的卷核进行卷操作,并输出30x30x1的特征图。在实际应用中,需要根据具体的卷神经网络结构和数据格式进行修改和优化。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值