首页 > 系统相关 >yolov5内存分布分析 转载

yolov5内存分布分析 转载

时间:2024-06-12 14:00:05浏览次数:19  
标签:yolov5 sigmoid float cell pindex 内存 boundingbox 转载 anchor

yolov5内存分布分析

Transpose输出分析

假设batch_size为1,yolov5有三个输出,shape分别是:

  • (1,3,80,80,85)
  • (1,3,40,40,85)
  • (1,3,20,20,85)

其中3代表anchor数量,20*20代表feature_map大小,85代表boundbox的(x,y,w,h,c+80个类别的概率)

其中(x,y,w,h,c+80个类别的概率)在内存中是连续分布的,即:

(1,3,20,20,85)整个数组在内存分布中也是连续分布的,

  • (0,0,0,0,0)->x->第一个anchor在第一个cell对应的boundingbox的x
  • (0,0,0,0,1)->y->第一个anchor在第一个cell对应的boundingbox的y
  • (0,0,0,0,2)->w->第一个anchor在第一个cell对应的boundingbox的w
  • (0,0,0,0,3)->h->第一个anchor在第一个cell对应的boundingbox的h
  • ​ ......
  • (0,0,0,1,0)->x->第一个anchor在第二个cell对应的boundingbox的x
  • (0,0,0,1,1)->y->第一个anchor在第二个cell对应的boundingbox的y
  • (0,0,0,1,2)->w->第一个anchor在第二个cell对应的boundingbox的w
  • (0,0,0,1,3)->h->第一个anchor在第二个cell对应的boundingbox的h
  • ......
  • (0,1,0,0,0)->x->第二个anchor在第一个cell对应的boundingbox的x
  • (0,1,0,0,1)->y->第二个anchor在第一个cell对应的boundingbox的y
  • (0,1,0,0,2)->w->第二个anchor在第一个cell对应的boundingbox的w
  • (0,1,0,0,3)->h->第二个anchor在第一个cell对应的boundingbox的h

即:

后处理代码分析

# 从第一个anchor开始获取
for (int q = 0; q < num_anchors; q++)
    {
        const float anchor_w = anchors[q * 2];
        const float anchor_h = anchors[q * 2 + 1];

        const ncnn::Mat feat = feat_blob.channel(q);
    
        #从第一个cell开始获取
        for (int i = 0; i < num_grid_y; i++)
        {
            for (int j = 0; j < num_grid_x; j++)
            {
                const float* featptr = feat.row(i * num_grid_x + j);
                #第5个是box_confidence值,需要使用sigmoid函数求值
                float box_confidence = sigmoid(featptr[4]);
                if (box_confidence >= prob_threshold)
                {
                    # 之所以这么写是因为可以减少sigmoid(class_score)的次数,sigmoid较为耗时
                    #find class index with max class score
                    int class_index = 0;
                    float class_score = -FLT_MAX;
                    for (int k = 0; k < num_class; k++)
                    {
                        # box_confidence之后是每个类别的概率
                        float score = featptr[5 + k];
                        if (score > class_score)
                        {
                            class_index = k;
                            class_score = score;
                        }
                    }
                    #论文规定
                    float confidence = box_confidence * sigmoid(class_score);
                    if (confidence >= prob_threshold)
                    {
                        # 依次获取x,y,w,h
                        float dx = sigmoid(featptr[0]);
                        float dy = sigmoid(featptr[1]);
                        float dw = sigmoid(featptr[2]);
                        float dh = sigmoid(featptr[3]);
    					
                        # 其余部分省略,可以参考ncnn代码
                        .......
   
                    }
                }
            }
        }
    }

====================================================================================

Conv输出分析

NPU对算法进行加速处理时,shape算子,如reshape、transpose通常不支持加速,有两种解决方法,

  • 使用C/C++语言重新实现reshape、transpose算子功能,使用CPU进行处理(待完善)
  • 直接按照conv层的输出内存分布获取数据进行处理

假设batch_size为1,卷积层的输出shape为:

  • (1,255,80,80)
  • (1,255,40,40)
  • (1,255,20,20)

其中255表示3*85,3代表anchor数量,,85代表boundbox的(x,y,w,h,c+80个类别的概率),20x20代表feature_map大小。

其中(x,y,w,h,c+80个类别的概率)在内存中是连续分布的,即:

(1,255,20,20)整个数组在内存分布中也是连续分布的,

  • (0,0,0,0)->x->第一个anchor在第一个cell对应的boundingbox的x

  • (0,0,0,1)->x->第一个anchor在第二个cell对应的boundingbox的x

  • (0,0,0,2)->x->第一个anchor在第三个cell对应的boundingbox的x

  • ......

  • (0,1,0,0)->x->第一个anchor在第一个cell对应的boundingbox的y

  • (0,1,0,1)->x->第一个anchor在第二个cell对应的boundingbox的y

  • (0,1,0,2)->x->第一个anchor在第三个cell对应的boundingbox的y

  • ......

  • (0,85,0,0)->x->第一个anchor在第一个cell对应的boundingbox的y

  • (0,85,0,1)->x->第二个anchor在第二个cell对应的boundingbox的y

  • (0,85,0,2)->x->第二个anchor在第三个cell对应的boundingbox的y

  • ....

    即:

后处理代码分析

# 从第一个cell开始
for(int shiftY = 0; shiftY < gridY; shiftY++)
	{
		for(int shiftX = 0; shiftX < gridX; shiftX++)
		{
                        # 从第一个anchor开始
			for(int i = 0; i < 3; i++)
			{
				pRecord = pMatData[i];
				# 获取当前cell
				int pindex = shiftY* gridX + shiftX;
				# coordindex的坐标对应x
                                int coordindex = pindex;
                                # 指针移动到y
				pindex = pindex + gridX * gridY;
				# 指针移动到w
                                pindex = pindex + gridX * gridY;
				# 指针移动到h
                                pindex = pindex + gridX * gridY;
				# 指针移动到C
                                pindex = pindex + gridX * gridY;
				# 获取C的值
				float  precord4 = sigmoid(pRecord[pindex]);
				# 指针移动到P
                                pindex = pindex + gridX * gridY ;
	
				for (cls = 0; cls < classNum; cls++)
				{
					#获取P的值
					float  precord5 = sigmoid(pRecord[pindex]);
					#指针移动到P1
                                         pindex = pindex + gridX * gridY;
	
					score = precord5 * precord4;

	
					if (score > gYolov7Para.confidenceThreshold)
					{//大于设置的阈值
						# 获取x
						float  precord0 = sigmoid(pRecord[coordindex]);
						coordindex = coordindex + gridX * gridY;
						# 获取y	
                     	                        float  precord1 = sigmoid(pRecord[coordindex]);
						coordindex = coordindex + gridX * gridY;
						# 获取w	
                     	                        float  precord2 = sigmoid(pRecord[coordindex]);
						coordindex = coordindex + gridX * gridY;
						# 获取h	
                     	                        float  precord3 = sigmoid(pRecord[coordindex]);
						coordindex = coordindex + gridX * gridY;
						# 其余部分省略
                        .......
					}
	
				}
			}
		}
	}

标签:yolov5,sigmoid,float,cell,pindex,内存,boundingbox,转载,anchor
From: https://www.cnblogs.com/eastgeneral/p/18243816

相关文章

  • FreeRTOS学习笔记-基于stm32(14)内存管理
    一、FreeRTOS内存管理简介        FreeRTOS有两种方法来创建任务,队列,信号量等,一种动态一种静态。静态方法需要手动定义任务堆栈。使用动态内存管理的时候FreeRTOS内核在创建任务、队列、信号量的时候会动态的申请RAM。    我们在移植FreeRTOS时可以看到......
  • JavaScript判断数据为对象(转载)
    1.javaScript判断数据为对象1.1. Object.prototype.toString.call()2.JavaScript如何判断数据类型2.1. typeof2.2. Array.isArray()2.3. instanceof2.4. Object.prototype.toString.call()2.5. constructor2.6. 使用ES6的Symbol.toStringTa......
  • 记一次 .NET某游戏币自助机后端 内存暴涨分析
    一:背景1.讲故事前些天有位朋友找到我,说他们的程序内存会偶发性暴涨,自己分析了下是非托管内存问题,让我帮忙看下怎么回事?哈哈,看到这个dump我还是非常有兴趣的,居然还有这种游戏币自助机类型的程序,下次去大玩家看看他们出币的机器后端是不是C#写的?由于dump是linux上的程序,刚好windb......
  • 【C语言】12.C语言内存函数
    文章目录1.memcpy使用和模拟实现2.memmove使用和模拟实现3.memset函数的使用4.memcmp函数的使用memcpy:内存拷贝memmove:内存移动memset:内存设置memcmp:内存比较1.memcpy使用和模拟实现memcpy:内存拷贝void*memcpy(void*destination,constvoid*source,......
  • 解读surging 的内存过高的原因
    前言      对于.NET开发人员来讲,一个程序占用内存过高,是极其糟糕,是一款不合格的程序软件,.NET开发人员也不会去使用服务器垃圾收集器(ServerGarbageCollection),而是选用工作站垃圾收集器,而是对于一款低内存的程序更能给开发人员是一款稳定运行的程序,而对于今天写这篇文章......
  • C语言笔记第14篇:动态内存管理
     1、为什么要有动态内存分配我们已经掌握的内存开辟方式有:创建变量charc=0;inta=0;intarr[10]={0};但是上述的开辟空间的方式有两个特点:空间开辟大小是固定的数组在声明的时候,必须指定数组的长度,数组空间一旦确定了大小不能调整但是对于空间的需求,不仅仅是......
  • 共享内存通信shm过程
    重要!!!先看这三篇segment.h-CSDN博客block.h-CSDN博客State.h-CSDN博客然后往下看初始化在listener.cc中对cyber进行初始化操作Init,并创建一个节点listener_nodemovex::cyber::Init(argv[0]);autolistener_node=movex::cyber::CreateNode("listener");创建读节......
  • linux内存管理(四)- 用户空间的内存分配在kernel中的实现
    malloc是常用的用户态分配内存的接口,它会调用brk系统调用来请内存分配内存。下面看看该系统调用的实现。插一句,每次调用malloc的时候未必都会调用brk去从kernel分配实际的内存,因为每次系统调用都是有开销的,为了避免频繁的陷入内核,malloc会多申请一部分内存当作内存池,之后要申请内......
  • linux内存管理(七)- 写时复制
    在fork进程的时候子进程会共享父进程的页表,但并没有分配新页。此时页表时只读的,如果父进程或者子进程写内存就会触发pagefault,内核会重新分配内存更改页表,从此分道扬镳。因此写时复制包含两部分内容,第一是fork进程时复制页表并设置pte为只读,第二是写内存发生pagefault。先来看......
  • yolov5-7.0更改resnet主干网络
    参考链接ClearML教程:https://blog.csdn.net/qq_40243750/article/details/126445671b站教学视频:https://www.bilibili.com/video/BV1Mx4y1A7jy/spm_id_from=333.788&vd_source=b52b79abfe565901e6969da2a1191407开始github地址:https://github.com/z1069614715/objec......