文章目录
背景
前几天研究生学长给我了一个图像输入的txt,和LeNet的参数文件,让我写个卷积核。
LeNet.h5打开方式:
netron
netron网页版
目前是做的AI推断加速,并非AI训练。
对cnn不了解的可以看看这个:LeNet-5详解
任务
我第一件事情是将这两个数据从定点数转化为二进制数,然后将这两个数据作为 coe文件导入BRAM ip核中。
浮点数是什么
但是我发现我好像不会浮点数了,哭。十进制浮点数转成二进制(IEEE 754 在线计算器)
对于float单精度来说,32bit=1bit符号位+8bit(有符号指数位 -128-127)+23bit(数据)
我们需要将十进制的数转变为二进制的数,然后都表示成 1.xxx*2^n 的形式,只需要记录xxx即可,因此23bit可以表示24bit。
浮点数精度: 我们知道9的二进制表示为1001,所以4bit能精确十进制中的1位小数点,24bit就能使float能精确到十进制小数点后6位。
这里用的是定点数,咳咳
后来才知道定点数就可以了,定点数一共16bit(自己设定即可),1bit符号+15bit数据,小数点位置人为定义。
netron导出的卷积核数据处理为一列数据
从LeNet导出的数据里有[],\n等,需要修改为一列数据。
strip()函数只能对字符的首尾删减!
replace倒是蛮好用的。replace后要赋值给自己(s)才行!
s=s.replace('/n','').replace('[','').replace(']','').replace(' ','')
预处理浮点数的代码
因为卷积核参数是3x3x1x64(64个3x3的卷积核,但是直接去掉括号的话,得到的前64个数据为每个卷积核的第一个数据,所以需要转换才行。lenet_new_proc.txt是经过转换的文件,连续的9个数为一个卷积核的数据)
####### lenet数组转coe文件格式(一列),不包括定点数转二进制#################################################
import numpy as np
store_data = np.zeros( (64,9)) #9列,64行
f = open('lenet.txt','r')
data = f.readlines()
# print(data)
new_data =[]
j = 0
for i in range(len(data)):
row = int(j%64)#行
column = int(j/64)#列
j = j + 1
# row = int(i % 64) # 行
# column = int(i / 64) # 列
new = str(data[i])
new = new.replace('[','').replace(']','').replace(' ','').replace(',','').lstrip('\n')#先去除逗号
if new == '':#某些行是空格,并没有处理掉
j = j - 1
# data.pop(i) #根据索引删除列表中的空格
# i = i - 1
print('空行')
continue
new = new.replace('\n', ',\n') #恢复逗号,数组表示的时候,逗号位置和一列表示不对
proc_new = new.strip(',\n')
new_data.append(new)
proc_new = float(proc_new)
print(i,'行,列:',row,column,'data:',new,'proc_data',proc_new)
store_data[row][column]= proc_new
# print(store_data)
# print(data)
# print(new_data)
np.savetxt("./store_data.v", store_data, fmt='%f', delimiter=',')
p = open ('lenet_new.txt','w') #直接转换为一列,并不正确
for i in (new_data):
p.write(i)
fp = open('lenet_new_proc.txt', 'w') # 正确的转换
for row in range(64):
for column in range(9):
data = store_data[row][column]
data = str(data)+',\n'
fp.write(data)
########################################################
########卷积核确定最大最小值,从而决定定点数 ################################################
p = open ('lenet_new.txt','r')
list=[]
for data in p.readlines():
data=data.replace(',\n','')
data=float(data) #str to float
list.append(data)
# print(list)
print('max',max(list))
print('min',min(list))
最后一段代码比较大小来确定位宽。一个数据的位宽取决于最大的数和要表示的最小的精度。
十进制浮点数预处理为二进制定点数
补码+原码=2^n
一个n位数的补码加原码等于2的n次方 这个n包括符号位。 因此一个负数可以先加上2^n,表示补码。
十进制浮点数预处理为二进制定点数代码
bin()整型转二进制
rjust() 左边填充0到固定位数
ff = open('file_float.v','r')#待处理的数据
fc = open('file_binary.v','w')#处理完成的数据
######定点数转二进制代码1 ##########################
def conInt(n):#整数部分
s = bin( int(n) ).lstrip('0b')
# print('整数', s)
s = s.rjust(8, '0') # 左补0
s = str(s)[1:8]
print('整数', s)
return s
def conFra(n):#小数部分
n = '0.'+str(n)
n = (float(n)*2**8)#若取8bit小数
print('小数', n)
n = int(n) # 得到小数位,
back =bin(n).lstrip('0b')
back = back.rjust(8, '0') # 左补0 这里必须左补0,因为整个小数左移了8bit,而整数部分多数没有8bit,所以需要补齐0
# dec, less = str(n).split('.') # 得到小数位,less表示剩下的,不用
# back = bin(int(dec)).lstrip('0b')
print('小数', back)
# for _ in range(len(back), 8):
# back +='0'
return back
def dec_bin(data):
# n=eval(input())
# data=6.06397055089473724
# data = 6
print('输入数据----------------------------------------',data)
if data<0:
sign_flag = '1'
data = data + 2**8 #取补码等于+2^8次幂。8bit小数位 一个n位数的补码加原码等于2的n次方 这个n包括符号位
else:
sign_flag = '0'
if type(data) == float:#小数
a,b = str(data).split('.')
# print('float!')
else: #整数
a = data
b = '0'
print('a',a,'b',b)
out = sign_flag + str(conInt(a))+'.'+str(conFra(b))
print('输出数据----------------------------------------',out)
fc.write(sign_flag + str(conInt(a)) + str(conFra(b))+'\n')
cnt=0
for data in ff.readlines():
data_in = float(data.strip(',\n'))
print(data_in)
dec_bin(data_in)
cnt += 1
print('cnt',cnt)
关于CSDN直接复制粘贴会多回车
处理代码如下:
f = open('old.txt','r')
data = f.readlines()
print(data)
for i in (data):
data.remove('\n')#remove删除list中与之匹配的第一个字符
# print(data)
p = open ('new.txt','w')
for i in (data):
p.write(i)