Xilinx FPGA实现LSTM算法时对ROM的初始化
将pytorch框架的权重矩阵以定点数补码的形式导入到FPGA中
文章目录
1. pytorch框架中的LSTM
pytorch框架将LSTM算法中的八个权值矩阵连接成两个矩阵,假设要导入的LSTM网络的输入维度为32,隐藏层输出维度也是32,那么,pytorch的LSTM中就有两个大小为(32 * 4 ,32)的权值矩阵。
2. 初始化一个RNN模型
为了方便演示,我们初始化一个RNN模型,里面包含一个输入维度32,隐藏层输出维度为32的单层单向LSTM层和一个输入维度32,输出维度为1的全连接层。将该模型初始化,赋值给变量rnn,我们先来查看一下该模型包含哪些参数:
for name, param in rnn.named_parameters():
print(name) #name为参数名称,param为参数
输出结果为如图所示
lstm.weight_ih_10是LSTM中与输入向量做乘法的矩阵,同理,lstm.weight_hh_10是LSTM中与隐藏层输入相乘的矩阵。这两个矩阵的大小均为(32 * 4,32)。
3. 初始化ROM的coe文件格式
我们使用coe文件来初始化Xilinx FPGA中的ROM,以存储权值矩阵;coe文件的格式为:
;
memory_initialization_radix = 2;
memory_initialization_vector=
101010
010101;
其中memory_initialization_radix可设为2,8,16,表示该文件采用2进制,8进制还是16进制;
memory_initialization_vector为初始化的值,另起一行开始写值,每一行对应ROM的一个地址。可以少写,缺省值补0,不能写多,末尾补 ; 符号。需要注意的是,coe代码中倒数第二行的值对应Xilinx FPGA ROM的地址0对应的值,测试出来是这样,也不知道为毛,不过不影响,自己复制粘贴调一下就好
4. 将参数转换为补码,并且输出到coe文件
FPGA中的运算是以补码形式进行的,而且是定点数,因此我们需要先把参数量化为定点数,补码形式。这个例子中,我们选择将其量化为16位数,首位符号位,2位整数位,13位小数位;那么ROM每一行长度为32 * 16。
量化方法和函数解释参考这篇文章 FPGA实现LSTM算法(一):将参数转换为二进制补码定点数的形式
if 'lstm.weight' in name:
f = open(name + ".coe","a")
data =';\nmemory_initialization_radix = 2;\nmemory_initialization_vector='
f.writelines(data)
para = param.data.detach().numpy()
for i in range(para.shape[0]):
f.writelines('\n')
for j in range(para.shape[1]):
data = d2b(para[i][j], 2, 13)
f.writelines(data)
f.writelines(';')
f.close()
d2b函数,将参数转化为定点数补码形式,用f.writelines()函数,将补码写入coe文件中;
运行这段程序就能得到两个coe文件,lstm.weight_hh_l0.coe和lstm.weight_ih_l0.coe;
效果如图2所示:
5. 配置一个ROM
配置一个ip核来存放lstm.weight_hh_10矩阵
ok,仿真结果如图5所示,
有一点需要注意的时,例化后的ROM存在一定的延时,大概初始化后的前两次读取,都读不出来,输出0,之后恢复正常。
6. 结论
这篇博客讲了如何将pytorch框架的参数矩阵量化为定点数补码形式,并形成coe文件,加载到Xlinx FPGA的ROM中,并以此读取ROM的值,仿真结果显示,该方法成功将参数矩阵导入到了FPGA中。
7. 代码
完整的python和verilog代码已上传到个人主页里。
下载链接:pytorch框架的权值参数导入到XIlinx FPGA中