首页 > 其他分享 >(继续)完善PS端YOLO网络前向计算函数

(继续)完善PS端YOLO网络前向计算函数

时间:2023-08-14 19:23:55浏览次数:40  
标签:PS cnt ch u8 tx 卷积 YOLO batch 前向

继续完善PS端YOLO网络前向计算函数

目标

  • 在PS端实现YOLO网络的前向计算
  • 对不同的卷积层进行配置和优化
  • 比较PS端和Python端的计算结果

前提

  • PS端使用卷积计算模块,可以同时处理8个通道的数据
  • PS端使用量化模块,可以对数据进行量化和反量化,以减少内存占用和提高运算速度
  • PS端使用激活模块,可以对数据进行ReLU或LeakyReLU激活
  • PS端使用路由模块,可以对不同层的数据进行拼接或分割
  • PS端使用检测模块,可以对最后一层的数据进行解析,得到目标的位置和类别

步骤

layer 12

  • layer 12是一个3x3卷积层,输入通道为512,输出通道为1024,没有池化层
  • 配置信息如下:
    • 卷积类型:0(3x3)
    • 输入通道:512
    • 输出通道:1024
    • 池化类型:0(无)
    • 图像尺寸:13x13
    • 量化信息:
      • mult:17866
      • shift:11
      • zero_point_in:12
      • zero_point_out:48
    • 发送地址:0x3000000(layer 11的接收地址)
    • 接收地址:0x3100000(新分配的地址)
  • 子函数如下:
    • 发送配置信息、偏置、权重、命令和数据地址给卷积计算模块
    • 接收卷积计算模块返回的数据,并进行量化、激活和发送操作

image

layer 13

  • layer 13是一个1x1卷积层,输入通道为1024,输出通道为256,没有池化层
  • 配置信息如下:
    • 卷积类型:1(1x1)
    • 输入通道:1024
    • 输出通道:256
    • 池化类型:0(无)
    • 图像尺寸:13x13
    • 量化信息:
      • mult:23354
      • shift:8
      • zero_point_in:7
      • zero_point_out:41
    • 发送地址:0x3100000(layer 12的接收地址)
    • 接收地址:0x3200000(新分配的地址)
  • 子函数如下:
    • 发送配置信息、偏置、权重、命令和数据地址给卷积计算模块
    • 接收卷积计算模块返回的数据,并进行量化、激活和发送操作
      image

layer 14

  • layer 14是一个3x3卷积层,输入通道为256,输出通道为512,没有池化层
  • 配置信息如下:
    • 卷积类型:0(3x3)
    • 输入通道:256
    • 输出通道:512
    • 池化类型:0(无)
    • 图像尺寸:13x13
    • 量化信息:
      • mult:28523
      • shift:8
      • zero_point_in:6
      • zero_point_out:63
    • 发送地址:0x3200000(layer 13的接收地址)
    • 接收地址:0x3000000(layer 12的发送地址,覆盖原来的数据)
  • 子函数如下:
    • 发送配置信息、偏置、权重、命令和数据地址给卷积计算模块
    • 接收卷积计算模块返回的数据,并进行量化、激活和发送操作
      image

layer 15

  • layer 15是一个1x1卷积层,输入通道为512,输出通道为18(根据类别数计算得到),没有池化层

    我们只检测人脸,所以目标类别只有一个,每个网格单元预测三个边界框,所以输出通道数是 3×(1+5)=183×(1+5)=18,其中 11 是类别数,55 是边界框的参数(中心坐标、宽高和置信度)。但是由于 PS 端内部是同时运行八个通道的卷积计算,所以我们需要将输出通道数填充为八的整数倍,即 24
    
  • 配置信息如下:

    • 卷积类型:1(1x1)
    • 输入通道:512
    • 输出通道:24(填充为8的整数倍)
    • 池化类型:0(无)
    • 图像尺寸:13x13
    • 量化信息:
      • mult:27118
      • shift:6
      • zero_point_in:11
      • zero_point_out:51
    • 发送地址:0x3000000(layer 14的接收地址)
    • 接收地址:0x3300000(新分配的地址)
  • 子函数如下:

    • 发送配置信息、偏置、权重、命令和数据地址给卷积计算模块
    • 接收卷积计算模块返回的数据,并进行量化、激活和发送操作

image

代码清单:

yolo_accel_ctrl.c

char InterruptProcessed = FALSE;

int layers_config[9][9] = {
	// conv_type, ch_in, ch_out, is_pool, feature_size, mult, shift, zp_in, zp_out
	// conv_type: 0->3x3, 1->1x1
       {0,         8,      16,        1,      416,      19290,   9,    0,     65},
	   {0,        16,      32,        1,      208,      30363,   8,   12,     86},
	   {0,        32,      64,        1,      104,      31915,   8,   22,     80},
	   {0,        64,     128,        1,       52,      16639,   7,   19,     57},
	   {0,       128,     256,        1,       26,      20025,   8,    9,     70},
	   {0,       256,     512,        1,       13,      23363,   9,   14,     66},
	   {0,       512,    1024,        0,       13,      17866,  11,   12,     48},
	   {1,      1024,     256,        0,       13,      23354,   8,    7,     41},
	   {0,       256,     512,        0,       13,      28523,   8,    6,     63}
};

u32 layers_tx_addr[9] = {
	0x1000000, 0x3000000, 0x3100000, 0x3000000, 0x3100000, 0x3000000, 0x3100000, 0x3000000, 0x3200000
};

u32 layers_rx_addr[9] = {
	0x3000000, 0x3100000, 0x3000000, 0x3100000, 0x3000000, 0x3100000, 0x3000000, 0x3200000, 0x3000000
};

void update_tx_info()
{
	if(feature_size <= 52)
		tx_len = (feature_size*feature_size) << 3;
	else if(tx_cnt == 0) {
		tx_len = (pl_buffer_row_num * feature_size)<<3;
	}
	else if(tx_cnt == tx_cnt_end - 1)
		tx_len = (tx_last_row_num * feature_size)<<3;

	tx_addr = tx_base_addr + ((tx_row_num * feature_size)<<3)*tx_cnt + ((feature_size*feature_size)<<3)*ch_in_batch_cnt;
}

void update_rx_info()
{
	rx_addr = rx_addr + rx_len;

	if(tx_cnt == 0 && ch_out_batch_cnt == 0)
		rx_addr = rx_base_addr;

	if(feature_size <= 52) {
		if(is_pool == 0) {
			rx_len = (feature_size*feature_size) << 3;
			rx_left_row_num = 0;
		}
		else if(pool_stride == 0) {
			rx_len = ((feature_size>>1)* (feature_size>>1)) << 3;
			rx_left_row_num = 0;
		}
		else {
			rx_len = (feature_size*feature_size) << 3;
			rx_left_row_num = 0;
		}

	}
	else if(tx_cnt == 0) {
		rx_len = (((pl_buffer_row_num-1)>>1)<<3)*(feature_size>>1);
		rx_left_row_num = (pl_buffer_row_num-1)%2;
	}
	else if(tx_cnt == tx_cnt_end-1)	{
		rx_len = (((tx_last_row_num-1+rx_left_row_num)>>1)<<3)*(feature_size>>1);
	}
	else {
		rx_len = (((pl_buffer_row_num-2+rx_left_row_num)>>1)<<3)*(feature_size>>1);
		rx_left_row_num = (pl_buffer_row_num-2+rx_left_row_num)%2;
	}

}

void update_cmd()
{
	if(conv_type == 0)
		reg_cmd	= CONV_TYPE3|IS_PADDING;
	else
		reg_cmd = CONV_TYPE1;

	if(is_pool == 1)
		reg_cmd |= IS_POOL;
	if(pool_stride == 1)
		reg_cmd |= POOL_STRIDE1;

	if(feature_size <= 52)
		reg_cmd |= SITE_ALL;
	else if(tx_cnt == 0)
		reg_cmd |= SITE_FIRST;
	else if(tx_cnt == tx_cnt_end - 1)
		reg_cmd |= SITE_LAST;
	else
		reg_cmd |= SITE_MIDDLE;

	if(ch_in_batch_cnt == (ch_in_batch_cnt_end-1))
		reg_cmd |= BATCH_LAST;
	else if(ch_in_batch_cnt == 0)
		reg_cmd |= BATCH_FIRST;
	else
		reg_cmd |= BATCH_MIDDLE;

	reg_cmd = reg_cmd | SET_COL_TYPE(col_type);
	
	if(feature_size <= 52)
		reg_cmd = reg_cmd | SET_ROW_NUM(feature_size);
	else if(tx_cnt == tx_cnt_end-1)
		reg_cmd = reg_cmd | SET_ROW_NUM(tx_last_row_num);
	else
		reg_cmd = reg_cmd | SET_ROW_NUM(pl_buffer_row_num);
}

void update_cnt_info()
{
	if(ch_in_batch_cnt == ch_in_batch_cnt_end-1) {
		ch_in_batch_cnt = 0;
		if(tx_cnt == tx_cnt_end-1) {
			tx_cnt = 0;
			ch_out_batch_cnt++;
		}
		else
			tx_cnt++;
	}
	else
		ch_in_batch_cnt++;

}


void wait_pl_finish()
{
	while(InterruptProcessed == FALSE);
	InterruptProcessed = FALSE;
}

void yolo_forward_init(int layer_config[], int i)
{
	conv_type = layer_config[0];
	ch_in = layer_config[1];
	ch_out = layer_config[2];
	is_pool = layer_config[3];
	feature_size = layer_config[4];
	mult = layer_config[5];
	shift = layer_config[6];
	zp_in = layer_config[7];
	zp_out = layer_config[8];
	if(i == 5)		// 判断当前执行的层是否为Layer10,Layer11
		pool_stride	= 1;
	else
		pool_stride = 0;

	///////////////////////////////////////////////////////////////////
	// 获取计数器相关的值
	tx_cnt = 0;
	ch_out_batch_cnt = 0;
	ch_out_batch_cnt_end = ch_out>>3;

	ch_in_batch_cnt = 0;
	ch_in_batch_cnt_end = ch_in>>3;

	if(feature_size <= 52) {
		pl_buffer_row_num = feature_size;
		tx_row_num = feature_size;
		tx_last_row_num = 0;
	}
	else {
		pl_buffer_row_num = PL_BUFFER_LEN / feature_size; 	// PL端数据BUFFER能存储特征图数据的最大行数量
		tx_row_num = pl_buffer_row_num - 2;					// PS端每次实际发送特征图数据的行数量
		tx_last_row_num = feature_size % tx_row_num;		// PS端最后一次发送特征图数据的行数量
	}

	if(tx_last_row_num == 0)
		tx_cnt_end = feature_size / tx_row_num;
	else
		tx_cnt_end = feature_size / tx_row_num + 1;

	///////////////////////////////////////////////////////////////////
	bias_buffer_rd_addr = 0;
	weight_buffer_rd_addr = 0;
	weight_tx_addr = WeightAddr[i];
	weight_batch_cnt = 0;
	bias_len = ch_out*4;
	if(conv_type == 0) {
		if(ch_in * ch_out <= 16384)
			weight_len = ch_in * ch_out * 9;
		else
			weight_len = 16384 * 9;
	}
	else {
		if(ch_in * ch_out <= 16384)
			weight_len = ch_in * ch_out;
		else
			weight_len = 16384;
	}
	///////////////////////////////////////////////////////////////////
	tx_base_addr = layers_tx_addr[i];
	rx_base_addr = layers_rx_addr[i];
	///////////////////////////////////////////////////////////////////
	if(feature_size == 416)
		col_type = 0;
	else if(feature_size == 208)
		col_type = 1;
	else if(feature_size == 104)
		col_type = 2;
	else if(feature_size == 52)
		col_type = 3;
	else if(feature_size == 26)
		col_type = 4;
	else if(feature_size == 13)
		col_type = 5;
}

void yolo_forward()
{
	for(int i=0; i<9; i++) {

		yolo_forward_init(layers_config[i], i);

		state = S_IDLE;
		while(state != S_FINISH) {
			switch(state) {
				case S_IDLE:
					Xil_Out32(Lite_Reg2, SET_SHIFT_ZP(shift,zp_out, zp_in));
					Xil_Out32(Lite_Reg1, SET_MULT_BUFFER_RDADDR(mult, bias_buffer_rd_addr, weight_buffer_rd_addr));
					Xil_Out32(Lite_Reg0, WRITE_BIAS);			// 发送bias数据
					DMA_Tx(BiasAddr[i], bias_len);
					wait_pl_finish();

					Xil_Out32(Lite_Reg0, WRITE_LEAKY_RELU);		// 发送LeakyRelu数据
					DMA_Tx(ActAddr[i], 256);
					wait_pl_finish();
					if(conv_type == 0)
						Xil_Out32(Lite_Reg0, WRITE_WEIGHT);					// 发送卷积3x3的Weight数据
					else
						Xil_Out32(Lite_Reg0, WRITE_WEIGHT|CONV_TYPE1);		// 发送卷积1x1Weight数据
					DMA_Tx(weight_tx_addr, weight_len);
					wait_pl_finish();

					state = S_FEATURE_CONV;
					break;

				case S_FEATURE_CONV:
					update_tx_info();
					update_cmd();

					Xil_Out32(Lite_Reg0, reg_cmd|WRITE_FEATURE);		// 发送Feature数据
					DMA_Tx(tx_addr, tx_len);
					wait_pl_finish();
					Xil_Out32(Lite_Reg0, reg_cmd|CONV_START);		// 卷积计算
					wait_pl_finish();


					if(ch_in_batch_cnt == ch_in_batch_cnt_end-1)
						state = S_DMA_RX;
					else {
						update_cnt_info();
						state = S_FEATURE_CONV;
						weight_buffer_rd_addr=ch_in_batch_cnt+ch_out_batch_cnt*ch_in_batch_cnt_end - (weight_batch_cnt<<8);
						Xil_Out32(Lite_Reg1, SET_MULT_BUFFER_RDADDR(mult, bias_buffer_rd_addr, weight_buffer_rd_addr));
					}
					break;


				case S_DMA_RX:
					update_rx_info();
					Xil_Out32(Lite_Reg0, reg_cmd|READ_START);	// 将PL端的数据传至PS端
					DMA_Rx(rx_addr, rx_len);					// 9行数据+1行填充=10行数据 --->卷积后,8个416的数据量---》经过池化后,变成4*208---> 总共8个通道,即最终数据量4*208*8=6656
					wait_pl_finish();
					Xil_DCacheFlushRange(rx_addr, rx_len);

					if(tx_cnt == tx_cnt_end-1 && ch_out_batch_cnt == ch_out_batch_cnt_end-1 && ch_in_batch_cnt == ch_in_batch_cnt_end-1)
						state = S_FINISH;
					else {
						state = S_FEATURE_CONV;
						update_cnt_info();
						if((ch_out_batch_cnt*ch_in_batch_cnt_end)%256==0 && ch_in_batch_cnt == 0 && tx_cnt == 0){
							weight_tx_addr = weight_tx_addr + weight_len;
							if(conv_type == 0)
								Xil_Out32(Lite_Reg0, WRITE_WEIGHT);					// 发送卷积3x3的Weight数据
							else
								Xil_Out32(Lite_Reg0, WRITE_WEIGHT|CONV_TYPE1);		// 发送卷积1x1Weight数据
							DMA_Tx(weight_tx_addr, weight_len);
							wait_pl_finish();
							weight_batch_cnt++;
						}
						bias_buffer_rd_addr = ch_out_batch_cnt;
						weight_buffer_rd_addr=ch_in_batch_cnt+ch_out_batch_cnt*ch_in_batch_cnt_end - (weight_batch_cnt<<8);
						Xil_Out32(Lite_Reg1, SET_MULT_BUFFER_RDADDR(mult, bias_buffer_rd_addr, weight_buffer_rd_addr));
					}
					break;


				case S_FINISH: break;

				default: break;
			}
		}
	}
}

yolo_accel_ctrl.h

int layers_config[9][9];

u8  conv_type ;
u16 ch_in;
u16	ch_out;
u8	is_pool;
u16	feature_size;
u16	mult;
u8	shift;
u8	zp_in;
u8	zp_out;


u8  pool_stride;
u8  col_type;
u8  ch_in_batch_cnt;
u8  ch_in_batch_cnt_end;
u8  ch_out_batch_cnt;
u8  ch_out_batch_cnt_end;
u8	tx_cnt;
u8 	tx_cnt_end;
u8	batch_cnt;
u8	batch_cnt_end;
u8 	pl_buffer_row_num;
u8  tx_row_num;
u8  tx_last_row_num;
u8  rx_left_row_num;


u8  bias_buffer_rd_addr;
u8  weight_buffer_rd_addr;
u32 weight_tx_addr;
u32 weight_batch_cnt;
u32 layers_tx_addr[9];
u32 layers_rx_addr[9];
u32 tx_base_addr;
u32 rx_base_addr;

u32 reg_cmd;

u32 tx_addr;
u32 tx_len;

u32 rx_addr;
u32 rx_len;

u32 bias_len;
u32 weight_len;


char state;
char InterruptProcessed;

void update_tx_info();
void update_rx_info();
void update_cmd();
void update_cnt_info();
void yolo_forward();
void yolo_forward_init(int layer_config[], int i);
void wait_pl_finish();

标签:PS,cnt,ch,u8,tx,卷积,YOLO,batch,前向
From: https://www.cnblogs.com/LiamJacob/p/17629521.html

相关文章

  • 论文解读:《iRNA-PseU:鉴定RNA假尿苷位点》
    标题:iRNA-PseU:IdentifyingRNApseudouridinesites.DOI:10.1038/mtna.2016.37期刊:DOAJ:DirectoryofOpenAccessJournals-DOAJ作者:WeiChen;HuaTang;JingYe;HaoLin;Kuo-ChenChou出版日期:2016-01-01网址: https://doi.org/10.1038/mtna.2016.37老文章了,为......
  • 《yolov5 如果针对一个模型权重反复增加样本训练》
    如果你已经有了一个YOLOv5的模型权重,要使用新的图像数据进行优化,您可以使用以下方法来获得新的模型权重:1.重新训练模型:将新的图像数据与原有的图像数据一起作为训练数据,以更快的速度重新训练模型。2.增量式学习:在原有的模型权重的基础上,通过训练新的图像数据来进行更......
  • 深入解析:HTTP和HTTPS的三次握手与四次挥手
    推荐阅读AI文本OCR识别最佳实践AIGamma一键生成PPT工具直达链接玩转cloudStudio在线编码神器玩转GPUAI绘画、AI讲话、翻译,GPU点亮AI想象空间「java、python面试题」来自UC网盘app分享,打开手机app,额外获得1T空间https://drive.uc.cn/s/2aeb6c2dcedd4AIGC资料包https:......
  • PCIe卡设计方案:631-单路12Gsps 3G 带宽模拟信号源PCIe卡
     一、板卡概述    单路3G带宽模拟信号源卡由DA子卡和PCIe底板组成,二者通过标准FMC连接器互联,可以实现将PCIe总线数据转换为一路高速的模拟量输出。北京太速科技该板可广泛用于雷达、通信、光电领域的噪声信号、毛刺、脉冲信号模拟产生等领域。 二、性能指标 板卡功能......
  • 内网映射神器nps搭建
    在前面的一篇文章中。我们讲到了如何利用frp进行内网映射。使得内网的设备可以通过公网登录。但是frp相对来说都是通过配置命令参数来实现的。对小白而言还是有点挑战,今天来介绍另外一种简单的方法吧。关于NPSnps是一款轻量级、高性能、功能强大的内网穿透代理服务器。目前支持tcp......
  • 大模型时代的模型运维与部署:LLMops
    来源:https://blog.csdn.net/sinat_26917383/article/details/1315383341LLMOps介绍1.1关联定义术语LLMOps代表大型语言模型运维。它的简短定义是LLMOps是LLM的MLOps。这意味着LLMOps是一组工具和最佳实践,用于管理LLM支持的应用程序的生命周期,包括开发、部署和维护......
  • 内网穿透工具 frps
    下载linux服务器的软件,跳板https://github.com/fatedier/frp/releases选择linuxamd内核的gz软件解压缩到linux服务器,修改 frps.ini,设置配置信息[common]bind_port=7000dashboard_port=7500token=xxxxx设置文件可运行chmod+xfrps运行程序./frps-c./frp......
  • vue3+typescript中的props
     以上是子组件 以上是父组件<scriptsetuplangs="ts">letprops=defineProps(['info','money'])//父子组件的通信需要用到defineProps方法去接受父组件想要传递的数据console.info(props)</script>需要注意的就是:props可以实现父子组件的通信,但是props的......
  • 生成式AI时代的AI Infra—从DevOps->MLOps->LLMOps
    来源:https://zhuanlan.zhihu.com/p/640725385 距离上次讲LLM相关的内容已经过去2个月了LLMasController—无限拓展LLM的能力边界,本文想要从AIInfra的角度出发,从更宏观的角度看GenerativeAI对AIInfra生态产生的变化,本文不局限于LLM,文中提到的LLM泛指一切GenerativeAI或者......
  • 【笔记】YOLO v3:An Incremental Improvement
     第一部分:论文与代码论 文:https://pjreddie.com/media/files/papers/YOLOv3.pdf翻 译:https://zhuanlan.zhihu.com/p/34945787代 码:https://github.com/pjreddie/darknet官 网:https://pjreddie.com/darknet/yolo旧 版: https://pjreddie.com/darknet/yolov2/ https://p......