前几天研究生学长给我了一个图像输入的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数据,小数点位置人为定义。
从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))最后一段代码比较大小来确定位宽。一个数据的位宽取决于最大的数和要表示的最小的精度。
一个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)处理代码如下:
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)