稀疏矩阵向量乘法
CRS数据结构
b即为a的CRS表示,值(values)数组保存矩阵中非零元素的值。列索引(columnIndex)数组和行指针(rowPtr)数组对非零元素的位置信息进行编码。(我看了一下rowPtr意思是在第几个元素处换行是吧)
对稀疏性没有要求。
稀疏矩阵向量乘
#include "spmv.h"
void spmv(int rowPtr[NUM_ROWS+1], int columnIndex[NNZ],
DTYPE values[NNZ], DTYPE y[SIZE], DTYPE x[SIZE]){
L1: for (int i = 0; i < NUM_ROWS; i++) {
DTYPE y0 = 0;
L2: for (int k = rowPtr[i]; k < rowPtr[i+1]; k++) {
#pragma HLS unroll factor=8
#pragma HLS pipeline
y0 += values[k] * x[columnIndex[k]];
}
y[i] = y0;
}
}
其头文件为
#ifndef __SPMV_H__
#define __SPMV_H__
const static int SIZE = 4; // SIZE of square matrix
const static int NNZ = 9; //Number of non-zero elements
const static int NUM_ROWS = 4;// SIZE;
typedef float DTYPE;
void spmv(int rowPtr[NUM_ROWS+1], int columnIndex[NNZ],
DTYPE values[NNZ], DTYPE y[SIZE], DTYPE x[SIZE]);
#endif // __MATRIXMUL_H__ not defined
函数spmv函数有5个参数,分别是rowPtr、columnIndex ,以及 values 对应矩阵 M 的 CRS 格式中包含的3个参数。参数 y 用于保存输出的结果,参数x表示输入的被乘向量x。变量NUM_ROWS表示矩阵M中行号。变量NNZ表示矩阵中非0元素的个数。最后,变量SIZE表示数组x和数组y中元素的个数。
外层for循环标签为L1,对矩阵的行进行遍历。将矩阵当前的行与向量x相乘,得到输出的结果y。内层循环标签为L2,实现对矩阵M中每列元素的遍历。L2循环迭代计算rowPtr[i + 1] − rowPtr[i]计算每一行非0元素的个数。每次循环计算,能从value数组中读取矩阵M的非0元素然后对应的从x数组中取得被乘向量x的值,对应相乘。cloumnIndex[k] 中的值保存了对应的列号k。
Test bench 测试用例
#include "spmv.h"
#include <stdio.h>
void matrixvector(DTYPE A[SIZE][SIZE], DTYPE *y, DTYPE *x)
{
for (int i = 0; i < SIZE; i++) {
DTYPE y0 = 0;
for (int j = 0; j < SIZE; j++)
y0 += A[i][j] * x[j];
y[i] = y0;
}
}
int main(){
int fail = 0;
DTYPE M[SIZE][SIZE] = {{3,4,0,0},{0,5,9,0},{2,0,3,1},{0,4,0,6}};
DTYPE x[SIZE] = {1,2,3,4};
DTYPE y_sw[SIZE];
DTYPE values[] = {3,4,5,9,2,3,1,4,6};
int columnIndex[] = {0,1,1,2,0,2,3,1,3};
int rowPtr[] = {0,2,4,7,9};
DTYPE y[SIZE];
spmv(rowPtr, columnIndex, values, y, x);
matrixvector(M, y_sw, x);
for(int i = 0; i < SIZE; i++)
if(y_sw[i] != y[i])
fail = 1;
if(fail == 1)
printf("FAILED\n");
else
printf("PASS\n");
return fail;
}
连同之前的源文件头文件一同创建工程
优化
稀疏矩阵向量乘法可优化的方式
广告时间
FPGA入门
FPGA实战训练精粹
Xilinx FPGA权威设计指南:基于Vivado 2018集成开发环境
Xilinx Zynq7020
FPGA设计技巧与案例开发详解(第2版)