FPGA HLS Matrix_MUL 矩阵乘法的计算与优化
新建Vivado工程
设置clock,10表示一个周期10ns,带宽100M
vivado工具比较保守,计算需要的延迟是14,实际优化可以在10,设置大一点,优化的计算更多,一般约束设置大一点在30-50
选择开发板 xc7z020clg400-1
Source:描述功能模块的cpp和h代码
Test Bench:测试代码的main.cpp
C Code
matrix_mul.h
#ifndef __MATRIX_MUL__
#define __MATRIX_MUL__#include "ap_fixed.h"void matrix_mul(ap_int<8> A[4][4], ap_int<8> B[4][4], ap_int<16> C[4][4]);#endif
#ifndef __xxxx__
#define __xxxx__
#endif
用于放置重复引入头文件ap_fixed.h
:arbitrary precision data types 用于自定义精度整形(FPGA的浮点数运算很慢,在后面的模型推理的时候 整形数运算比较快)- 两个8位数相乘,结果最大可以是16位
.h文件包含了一个矩阵乘法的函数声明
matrix_mul.cpp
#include "matrix_mul.h"void matrix_mul(ap_int<8> A[4][4], ap_int<8> B[4][4], ap_int<16> C[4][4])
{for(int i = 0; i < 4; ++ i){for(int j = 0; j < 4; ++ j){C[i][j] = 0;for(int k = 0; k < 4; ++ k){C[i][j] += A[i][k]*B[k][j];}}}
}
i行k列乘k行j列
main.cpp
#include "matrix_mul.h"
#include <iostream>int main()
{ap_int<8> A[4][4], B[4][4];ap_int<16> C[4][4];// initial A&Bfor(int i = 0; i < 4; ++ i)for(int j = 0; j < 4; ++ j)A[i][j] = B[i][j] = i*4 + j;// inferencematrix_mul(A, B, C);// print C matrixfor(int i = 0; i < 4; ++ i){for(int j = 0; j < 4; ++ j){std::cout << "C["<<i<<"] = " << C[i][j] << "\t";}std::cout << std::endl;}return 0;
}
C Simulation
当有许多模块的时候需要指定顶层函数,设置顶层模块(top function):
C仿真主要用于编译C代码与HLS无关,测试功能是否与预期一致。使用C++完成testbench,同样地,C语言可以编译为对应的激励,驱动上一步骤完成的电路模块
_csim.log
文件显示仿真结果
INFO: [SIM 2] *************** CSIM start ***************
INFO: [SIM 4] CSIM will launch GCC as the compiler.Compiling ../../../main.cpp in debug modeCompiling ../../../matrix_mul.cpp in debug modeGenerating csim.exe
C[0] = 56 C[0] = 62 C[0] = 68 C[0] = 74
C[1] = 152 C[1] = 174 C[1] = 196 C[1] = 218
C[2] = 248 C[2] = 286 C[2] = 324 C[2] = 362
C[3] = 344 C[3] = 398 C[3] = 452 C[3] = 506
INFO: [SIM 1] CSim done with 0 errors.
INFO: [SIM 3] *************** CSIM finish ***************
C Synthesis
C++代码综合成RTL逻辑,生成综合报告,包括时序,延时,资源占用,端口信息等。
Loop Latency:完成所有循环需要的时钟周期
Iteration Latency:循环里面,迭代一次需要的周期
Initiation Interval(II):两次迭代之间的时钟间隔
Trip Count:循环次数
工程的资源占用情况(工程使用的资源数目&FPGA的总可用资源):
端口信息,ABC数组默认存在存储器ap_memory中,以下ap_clk、ap_rst、ap_start、ap_done、ap_idle、ap_ready都是控制信号
端口分析:
- 控制端口用于控制和显示该模块的工作状态。各个端口的功功能如下,默认情况下会生成下面四个控制端口。
- ap_start(in):为高时,该模块开始处理数据。
- ap_done(out):为高时,表示模块处理数据完成。
- ap_idle(out):表明模块是否处于空闲态。高电平有效。为高时,该处于空闲态。
- ap_ready(out):为高时,表示模块可以接受新的数据。
- 数据端口用于传递模块的输入输出参数。
参数d_o,d_i 为数组类型,故默认状态下回生成内存接口。内存接口 (数组类型参数)数据来自外部的memory,通过地址信号读取相应的数据,输入到该模块中。输入数组从外部内存中读源数据,输出数组从向外部内存写入结果数据。各个端口的定义如下。- address:地址信号
- ce0:片选信号
- we0:写使能信号
- d0 :数据信号
并行优化
A和B的四个数同时相乘,让原先一行乘一列需要8个周期完成,变成一个周期完成
两种实现方法:
- unroll,手动展开循环
- pipline,系统自动推断展开
- partiotion,切分数组
- reshape,改变存储长度
unroll
source文件自动添加优化代码:#pragma HLS UNROLL
#include "matrix_mul.h"void matrix_mul(ap_int<8> A[4][4], ap_int<8> B[4][4], ap_int<16> C[4][4])
{for(int i = 0; i < 4; ++ i){for(int j = 0; j < 4; ++ j){C[i][j] = 0;for(int k = 0; k < 4; ++ k){#pragma HLS UNROLLC[i][j] += A[i][k]*B[k][j];}}}
}
运行C综合的结果:((1+2)*4+2)*4+1 =57
pipeline
选择第二个for循环,设置pipeline的迭代间隔等于1
自动添加优化语句:#pragma HLS PIPELINE II=1
#include "matrix_mul.h"void matrix_mul(ap_int<8> A[4][4], ap_int<8> B[4][4], ap_int<16> C[4][4])
{for(int i = 0; i < 4; ++ i){for(int j = 0; j < 4; ++ j){#pragma HLS PIPELINE II=1C[i][j] = 0;for(int k = 0; k < 4; ++ k){C[i][j] += A[i][k]*B[k][j];}}}
}
C综合结果:
计算一共需要34个周期,这已经比以前的169个周期快了不少了,但是我们希望16个周期就能计算完。
没有达到预期的目标是因为没有指定数组A和B的端口类型,默认为双端口。读取数据时一次只能读取2个,所以16次计算,每次读取4个数据,一共16*4
个数据需要花费16*4/2=32
个周期
端口只有ce0和ce1:
所以需要同时取出四个数据,可以通过ArrayPartition和ArrayReshape实现
Array_Partition
数组分割:A竖着切割(按照维度2),分成4份分别存储在4个存储器里面;B横着切割(按照维度1)分别存储在4个存储器里面;
计算时同时各取出4个进行运算:
注意维度:高是维度1,宽是维度2
#include "matrix_mul.h"void matrix_mul(ap_int<8> A[4][4], ap_int<8> B[4][4], ap_int<16> C[4][4])
{// partiton 优化语句#pragma HLS ARRAY_PARTITION variable=B complete dim=1#pragma HLS ARRAY_PARTITION variable=A complete dim=2for(int i = 0; i < 4; ++ i){for(int j = 0; j < 4; ++ j){#pragma HLS PIPELINE II=1C[i][j] = 0;for(int k = 0; k < 4; ++ k){C[i][j] += A[i][k]*B[k][j];}}}
}
C综合结果:
1*16+2 = 18
数组A和B都有四个端口同时读数据了:
Array_Reshape
重定义数组在存储器中的排列方式。原来默认一个地址行放一个数据,宽度只占8位。
A每次计算取一行,所以按照维度 2的方向放置数据:
#include "matrix_mul.h"void matrix_mul(ap_int<8> A[4][4], ap_int<8> B[4][4], ap_int<16> C[4][4])
{#pragma HLS ARRAY_RESHAPE variable=B complete dim=1#pragma HLS ARRAY_RESHAPE variable=A complete dim=2for(int i = 0; i < 4; ++ i){for(int j = 0; j < 4; ++ j){#pragma HLS PIPELINE II=1C[i][j] = 0;for(int k = 0; k < 4; ++ k){C[i][j] += A[i][k]*B[k][j];}}}
}
C综合结果:
latency约束
这里Latency指的是每次迭代的花费的周期数
设置计算消耗的周期数设置为5
#include "matrix_mul.h"void matrix_mul(ap_int<8> A[4][4], ap_int<8> B[4][4], ap_int<16> C[4][4])
{#pragma HLS ARRAY_RESHAPE variable=B complete dim=1#pragma HLS ARRAY_RESHAPE variable=A complete dim=2for(int i = 0; i < 4; ++ i){for(int j = 0; j < 4; ++ j){#pragma HLS LATENCY min=5 max=5#pragma HLS PIPELINE II=1C[i][j] = 0;for(int k = 0; k < 4; ++ k){C[i][j] += A[i][k]*B[k][j];}}}
}
所以最后使用的周期数一共是:16×( Initiation Interval -1 ) + Latency = (16-1)×1+5 = 20
原来不加latency时,延时是1,所以是(16-1)*1+1=16
FPGA HLS Matrix_MUL 矩阵乘法的计算与优化相关推荐
- HLS:矩阵乘法单元设计与SDK测试
目录 一.引言 二.程序框架 三.初步设计 四.报告分析 五.优化操作 六.接口优化 七.上板测试 八.补充部分 九.时间与参考 一.引言 矩阵乘法,涉及数组优化.循环优化和接口优化等.是一个学习HL ...
- 矩阵乘法的计算和来源
矩阵乘法的计算 矩阵,是线性代数中的基本概念之一.一个m×n的矩阵就是m×n个数排成m行n列的一个数阵. 矩阵乘法是一种高效的算法可以把一些一维递推优化到log(n),还可以求路径方案等,所以更是一种 ...
- 矩阵乘法的计算规则,为什么是A矩阵的行元素分别乘以B矩阵的列元素?
转:https://www.cnblogs.com/alantu2018/p/8528299.html Matrix 相关api: https://blog.csdn.net/gb702250823/ ...
- 矩阵乘法递推的优化艺术
对于一个线性递推式,求它第项的值,通常的做法是先构造一个的矩阵,然后在时间内求出. 其实,由于这个矩阵的特殊性,可以将时间优化到.接下来我会以一个题目来讲解矩阵乘法递推的优化. 题目:http://w ...
- 基于FPGA的脉动阵列矩阵乘法
部分信号的时序图: 模块代码: `timescale 1ns / 1ps /////////////////////////////////////////////////////////////// ...
- c语言定义int 输出4386,C语言 · 矩阵乘法
问题描述 输入两个矩阵,分别是m*s,s*n大小.输出两个矩阵相乘的结果. 输入格式 第一行,空格隔开的三个正整数m,s,n(均不超过200). 接下来m行,每行s个空格隔开的整数,表示矩阵A(i,j ...
- python实现矩阵叉乘_矩阵乘法的纯Python实现 | 离开Python库!!
点击关注我哦 一篇文章带你了解矩阵乘法的纯Python实现 在<这篇文章>中,我们有简单提到"矩阵乘法"的相关知识,如果你不记得了,可以复习一下这张图片. 想起来了没? ...
- 【C语言】矩阵乘法(二维数组)
编写程序,实现矩阵乘法.计算两个矩阵A和B的乘积.输入要求:第一行三个正整数m.p和n,0<=m,n,p<=10,表示矩阵A是m行p列,矩阵B是p行n列:接下来的m行是矩阵A的内容,每行p ...
- 分治-Strassen矩阵乘法
A和B的乘积矩阵C中的元素C[i,j]定义为: 若依此定义来计算A和B的乘积矩阵C,则每计算C的一个元素C[i][j],需要做n次乘法和n-1次加法.因此,算出矩阵C的个元素所需的计算时间为O(n3) ...
最新文章
- 2021春季每日一题【week6 未完结】
- 流控制、FlowControl
- javafx爬取网页并且初始化网页数据
- perl数组硬引用_Perl 继续前行,Perl 7 将是下一代(硬核老王点评版)
- linux 物理内存用完了_调整linux内核尽量用内存,而不用swap
- 【STL学习】堆相关算法详解与C++编程实现(Heap)
- pcb只开窗不镀锡_FPC、PCB和FFC的关系和区别-美好精密
- Sql UNION 合并多个结果集并排序
- 不知不觉 CDSN 也有了百万访问量了
- mysql查询所有男生中姓王的_数据库6.22
- Windows10安装ubuntu18.04双系统教程(双硬盘)
- 计算机命令无法到达打印机,单击打印命令时打印机无响是怎么回事
- ps修改图像像素压缩图片大小
- 利用FFmpeg合并音频和视频
- HDU 5745 La Vie en rose(水~)
- 笔记本电脑外接显示屏的分辨率设置,外接显示屏分辨率总是低一点的解决方法
- HDU 6411 带劲的and和
- request to https://registry.npm.taobao.org/jsprim failed, reason: connect ETIMEDOUT 错误解决方案
- OllyDbg断点详解
- MRI血管造影技术之最大密度投影法(maximum intensity projection)重建
热门文章
- 产品经理学习手册(一)产品经理:挖掘发现用户需求、满足用户需求;让世界变得更美好
- PDF与word互相转换
- Python3 使用企业微信 API 发送消息
- 三星a5000刷Android原生,Samsung-A5000安卓5.0刷机包
- PowerDesigner常见使用
- 鱼眼:一:一分钟详解鱼眼镜头标定基本原理及实现
- 免费开源的建站程序大全,不会编程也可以自助搭建网站了哦
- 小程序textarea在ios中内边距的解决办法
- BORLAND 在“迫害”程序员?
- c++找出1000以内的完数