关于yolov8的DFL模块(pytorch以及tensorrt)

先看代码

class DFL(nn.Module):"""Integral module of Distribution Focal Loss (DFL).Proposed in Generalized Focal Loss https://ieeexplore.ieee.org/document/9792391"""def __init__(self, c1=16):"""Initialize a convolutional layer with a given number of input channels."""super().__init__()self.conv = nn.Conv2d(c1, 1, 1, bias=False).requires_grad_(False)x = torch.arange(c1, dtype=torch.float)self.conv.weight.data[:] = nn.Parameter(x.view(1, c1, 1, 1))self.c1 = c1def forward(self, x):"""Applies a transformer layer on input tensor 'x' and returns a tensor."""b, c, a = x.shape  # batch, channels, anchorsprint("self.conv.weight.data[:] is : ",self.conv.weight.data[:])print("self.conv.weight.data[:] shape is : ",self.conv.weight.data[:].shape)print("x is : ",x)print("x.shape is : ",x.shape)print("x.view(b,4,self.c1,a) is : ",x.view(b,4,self.c1,a))print("x.view(b,4,self.c1,a).shape is : ",x.view(b,4,self.c1,a).shape)return self.conv(x.view(b, 4, self.c1, a).transpose(2, 1).softmax(1)).view(b, 4, a)# return self.conv(x.view(b, self.c1, 4, a).softmax(1)).view(b, 4, a)

这个类 DFL 是一个神经网络模块,继承自 nn.Module,是在PyTorch框架中定义自定义神经网络层的标准方式。这个 DFL 类实现了分布焦点损失(Distribution Focal Loss, DFL),这是在论文 “Generalized Focal Loss” 中提出的一个概念。下面是对这段代码的详细解释:

1、class DFL(nn.Module):定义了一个名为 DFL 的类,它继承自 nn.Module,使其成为一个PyTorch的网络层。
2、def init(self, c1=16):DFL 类的初始化方法。接收一个参数 c1,默认值是 16,代表输入通道的数量。
3、super().init():调用父类 nn.Module 的初始化函数,这是在定义PyTorch模型时的标准做法。
4、self.conv = nn.Conv2d(c1, 1, 1, bias=False).requires_grad_(False):定义了一个卷积层,该层有 c1 个输入通道,1个输出通道,卷积核大小1x1,没有偏置项,且不需要梯度更新(即在训练过程中不会更新这个卷积层的权重)。
5、x = torch.arange(c1, dtype=torch.float):创建一个大小为 c1 的一维张量,这个张量包含了从0到 c1-1 的连续整数。
6、self.conv.weight.data[:] = nn.Parameter(x.view(1, c1, 1, 1)):初始化卷积层的权重。x 被转换成形状为 (1, c1, 1, 1) 的四维张量,并作为卷积层权重的值。
7、self.c1 = c1:存储输入通道数目的属性。
8、def forward(self, x):定义了模块的前向传播方法,其中 x 是输入张量。
9、b, c, a = x.shape:获取输入张量 x 的形状,假设其是三维的,其中 b 是批处理大小,c 是通道数量,a 是锚点数量(注:锚点通常用于目标检测任务中)。
10、这段代码中还包含了一些打印语句,用于输出卷积层的权重和输入张量的形状等调试信息。
11、return self.conv(x.view(b, 4, self.c1, a).transpose(2, 1).softmax(1)).view(b, 4, a):这是前向传播的关键操作。输入张量 x 首先被重塑为 (b, 4, self.c1, a),这里假定 c 是 4*self.c1。然后 transpose(2, 1) 交换了通道和锚点的维度。softmax(1) 在第二个维度上(即原来的 self.c1 维度、现在的通道维度)应用softmax函数。最后,应用卷积操作并将结果重塑为 (b, 4, a)。

综上所述,DFL 类使用了卷积核对输入张量进行变换,旨在学习一种分布式的表示,其在目标检测等任务中可能用于学习预测概率分布。这种方法可能有利于模型更好地理解目标的不确定性。

以下是调试输出:

Ultralytics YOLOv8.1.8 🚀 Python-3.11.5 torch-2.0.0+cu118 CUDA:0 (NVIDIA GeForce RTX 3060 Laptop GPU, 6144MiB)
self.conv.weight.data[:] is :  tensor([[[[ 0.]],[[ 1.]],[[ 2.]],[[ 3.]],[[ 4.]],[[ 5.]],[[ 6.]],[[ 7.]],[[ 8.]],[[ 9.]],[[10.]],[[11.]],[[12.]],[[13.]],[[14.]],[[15.]]]], device='cuda:0')
self.conv.weight.data[:] shape is :  torch.Size([1, 16, 1, 1])
x is :  tensor([[[ 7.9609,  3.9328,  1.2542,  ...,  7.9261,  3.7103,  6.1628],[ 7.8865,  8.2141,  3.6136,  ...,  7.7927,  7.2668,  5.9885],[ 2.1200,  8.2323,  7.2977,  ...,  3.5018,  7.1541,  3.2515],...,[-1.6378, -2.2544, -2.0439,  ..., -1.8033, -1.7783, -1.4680],[-1.9045, -2.5544, -2.3420,  ..., -2.0054, -1.9784, -1.6110],[-1.1409, -2.4363, -2.1418,  ..., -1.7273, -1.7041, -1.6811]]], device='cuda:0')
x.shape is :  torch.Size([1, 64, 21])
x.view(b,4,self.c1,a) is :  tensor([[[[ 7.9609,  3.9328,  1.2542,  ...,  7.9261,  3.7103,  6.1628],[ 7.8865,  8.2141,  3.6136,  ...,  7.7927,  7.2668,  5.9885],[ 2.1200,  8.2323,  7.2977,  ...,  3.5018,  7.1541,  3.2515],...,[-1.3957, -2.2859, -2.3732,  ..., -1.6756, -1.7059, -1.4575],[-1.6145, -2.3682, -2.4476,  ..., -1.7892, -1.7984, -1.5309],[-0.8706, -1.7938, -1.8388,  ..., -1.6522, -1.6732, -1.5332]],[[ 8.3572,  9.8892,  9.1272,  ...,  4.1972,  4.2291,  6.8087],[ 8.2836,  9.8511,  9.0978,  ...,  7.4077,  7.2967,  6.6090],[ 2.7911,  2.6250,  2.3740,  ...,  7.2771,  7.1356,  3.5323],...,[-1.6353, -2.0540, -1.9561,  ..., -0.9167, -1.0320, -1.4185],[-1.8191, -2.3518, -2.2370,  ..., -1.1207, -1.2171, -1.5694],[-1.1255, -2.2479, -2.0955,  ..., -0.5296, -0.6821, -1.8163]],[[-0.2927,  0.9935,  4.8185,  ...,  4.0401,  8.2405,  5.8280],[ 1.8495,  4.0922,  8.9220,  ...,  7.8240,  8.1252,  5.9634],[ 3.7216,  8.0900,  8.7783,  ...,  7.6322,  3.4239,  3.9682],...,[-1.7413, -2.0473, -2.3148,  ..., -1.7863, -1.6267, -1.3612],[-1.9912, -2.2312, -2.4779,  ..., -1.9319, -1.7893, -1.5738],[-1.3506, -1.7374, -1.8736,  ..., -1.7203, -1.5202, -1.5913]],[[ 0.9126,  0.7135,  0.5577,  ...,  8.0598,  8.0426,  6.3850],[ 2.6471,  2.7828,  2.6682,  ...,  7.9502,  7.9280,  6.1044],[ 3.7130,  4.0446,  3.8203,  ...,  3.9169,  4.0009,  3.2179],...,[-1.6378, -2.2544, -2.0439,  ..., -1.8033, -1.7783, -1.4680],[-1.9045, -2.5544, -2.3420,  ..., -2.0054, -1.9784, -1.6110],[-1.1409, -2.4363, -2.1418,  ..., -1.7273, -1.7041, -1.6811]]]], device='cuda:0')
x.view(b,4,self.c1,a).shape is :  torch.Size([1, 4, 16, 21])

在PyTorch框架中,x.view() 函数是非常常用来改变张量(Tensor)形状的方法。当使用x.view()时,你需要提供一个维度的新形状,而这个新形状必须要与原始张量包含的元素数量相匹配。换句话说,使用view可以在不改变数据内容的前提下,改变数据的形状。
这是 x.view() 方法的基本用法:

x.view(dim1, dim2, dim3, ...)

其中,dim1, dim2, dim3, … 是新的形状,每一个维度都是一个整数,代表了在该维度上的大小。可以使用 -1 来让PyTorch自动计算该维度的大小,但一次只能用在一个维度上。
请看以下代码中的 forward 方法里的 x.view() 的使用:

b, c, a = x.shape  # batch, channels, anchors
return self.conv(x.view(b, 4, self.c1, a).transpose(2, 1).softmax(1)).view(b, 4, a)

在这个例子中,x 是输入张量,其形状为 (b, c, a),其中 b 是批次大小(batch size),c 是通道数(channels),a 是锚点数量(anchors)。这里的 c 应该等于 4*self.c1,这样才能通过 view 进行重塑。
x.view(b, 4, self.c1, a) 的意思是将 x 的形状由 (b, c, a) 改变为 (b, 4, self.c1, a)。此时,第二维度变成了 4,第三维度变成了 self.c1,而第四维度是 a。调用 view 后,张量的总元素数不变,但将这些元素按照新的形状重新排列。
在这个转换之后,x 经过了 .transpose(2, 1),它会交换第二维和第三维。transpose(2, 1) 的结果是张量的形状变成了 (b, self.c1, 4, a)。
最后,.softmax(1) 在第二维上应用了softmax函数,它会计算该维度上的概率分布。然后经过自定义的1x1卷积核处理,并返回形状为 (b, 4, a) 的结果。
通过这种方式,x.view() 使得张量可以在不同神经网络操作中适应所需的形状,在保持数据元素不变的同时改变其结构。

tensorrt里面的dfl如下:

nvinfer1::IShuffleLayer* DFL(nvinfer1::INetworkDefinition* network, std::map<std::string, nvinfer1::Weights> weightMap, 
nvinfer1::ITensor& input, int ch, int grid, int k, int s, int p, std::string lname){nvinfer1::IShuffleLayer* shuffle1 = network->addShuffle(input);shuffle1->setReshapeDimensions(nvinfer1::Dims3{4, 16, grid});shuffle1->setSecondTranspose(nvinfer1::Permutation{1, 0, 2});nvinfer1::ISoftMaxLayer* softmax = network->addSoftMax(*shuffle1->getOutput(0));nvinfer1::Weights bias_empty{nvinfer1::DataType::kFLOAT, nullptr, 0};nvinfer1::IConvolutionLayer* conv = network->addConvolutionNd(*softmax->getOutput(0), 1, nvinfer1::DimsHW{1, 1}, weightMap[lname], bias_empty);conv->setStrideNd(nvinfer1::DimsHW{s, s});conv->setPaddingNd(nvinfer1::DimsHW{p, p});nvinfer1::IShuffleLayer* shuffle2 = network->addShuffle(*conv->getOutput(0));shuffle2->setReshapeDimensions(nvinfer1::Dims2{4, grid});return shuffle2;
}

下面放出DFL的onnx图:

在这里插入图片描述

tensorrtx里面处理的detect的代码为:

nvinfer1::IShuffleLayer* shuffle22_0 = network->addShuffle(*cat22_0->getOutput(0));
shuffle22_0->setReshapeDimensions(nvinfer1::Dims2{64 + kNumClass, (kInputH / 8) * (kInputW / 8)});nvinfer1::ISliceLayer* split22_0_0 = network->addSlice(*shuffle22_0->getOutput(0), nvinfer1::Dims2{0, 0}, nvinfer1::Dims2{64, (kInputH / 8) * (kInputW / 8)}, nvinfer1::Dims2{1, 1});
nvinfer1::ISliceLayer* split22_0_1 = network->addSlice(*shuffle22_0->getOutput(0), nvinfer1::Dims2{64, 0}, nvinfer1::Dims2{kNumClass, (kInputH / 8) * (kInputW / 8)}, nvinfer1::Dims2{1, 1});
nvinfer1::IShuffleLayer* dfl22_0 = DFL(network, weightMap, *split22_0_0->getOutput(0), 4, (kInputH / 8) * (kInputW / 8), 1, 1, 0, "model.22.dfl.conv.weight");
nvinfer1::ITensor* inputTensor22_dfl_0[] = {dfl22_0->getOutput(0), split22_0_1->getOutput(0)};
nvinfer1::IConcatenationLayer* cat22_dfl_0 = network->addConcatenation(inputTensor22_dfl_0, 2);nvinfer1::IShuffleLayer* shuffle22_1 = network->addShuffle(*cat22_1->getOutput(0));
shuffle22_1->setReshapeDimensions(nvinfer1::Dims2{64 + kNumClass, (kInputH / 16) * (kInputW / 16)});
nvinfer1::ISliceLayer* split22_1_0 = network->addSlice(*shuffle22_1->getOutput(0), nvinfer1::Dims2{0, 0}, nvinfer1::Dims2{64, (kInputH / 16) * (kInputW / 16)}, nvinfer1::Dims2{1, 1});
nvinfer1::ISliceLayer* split22_1_1 = network->addSlice(*shuffle22_1->getOutput(0), nvinfer1::Dims2{64, 0}, nvinfer1::Dims2{kNumClass, (kInputH / 16) * (kInputW / 16)}, nvinfer1::Dims2{1, 1});
nvinfer1::IShuffleLayer* dfl22_1 = DFL(network, weightMap, *split22_1_0->getOutput(0), 4, (kInputH / 16) * (kInputW / 16), 1, 1, 0, "model.22.dfl.conv.weight");
nvinfer1::ITensor* inputTensor22_dfl_1[] = {dfl22_1->getOutput(0), split22_1_1->getOutput(0)};
nvinfer1::IConcatenationLayer* cat22_dfl_1 = network->addConcatenation(inputTensor22_dfl_1, 2);nvinfer1::IShuffleLayer* shuffle22_2 = network->addShuffle(*cat22_2->getOutput(0));
shuffle22_2->setReshapeDimensions(nvinfer1::Dims2{64 + kNumClass, (kInputH / 32) * (kInputW / 32)});
nvinfer1::ISliceLayer* split22_2_0 = network->addSlice(*shuffle22_2->getOutput(0), nvinfer1::Dims2{0, 0}, nvinfer1::Dims2{64, (kInputH / 32) * (kInputW / 32)}, nvinfer1::Dims2{1, 1});
nvinfer1::ISliceLayer* split22_2_1 = network->addSlice(*shuffle22_2->getOutput(0), nvinfer1::Dims2{64, 0}, nvinfer1::Dims2{kNumClass, (kInputH / 32) * (kInputW / 32)}, nvinfer1::Dims2{1, 1});
nvinfer1::IShuffleLayer* dfl22_2 = DFL(network, weightMap, *split22_2_0->getOutput(0), 4, (kInputH / 32) * (kInputW / 32), 1, 1, 0, "model.22.dfl.conv.weight");
nvinfer1::ITensor* inputTensor22_dfl_2[] = {dfl22_2->getOutput(0), split22_2_1->getOutput(0)};
nvinfer1::IConcatenationLayer* cat22_dfl_2 = network->addConcatenation(inputTensor22_dfl_2, 2);nvinfer1::IPluginV2Layer* yolo = addYoLoLayer(network, std::vector<nvinfer1::IConcatenationLayer *>{cat22_dfl_0, cat22_dfl_1, cat22_dfl_2});
yolo->getOutput(0)->setName(kOutputTensorName);
network->markOutput(*yolo->getOutput(0));

tensorrtx里面的处理手段是将三个output分别经过dfl等一系列处理,再拼回去,再看onnx图:请添加图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/728458.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Spring MVC PathVariableMethodArgumentResolver原理解析

在Spring MVC中&#xff0c;PathVariableMethodArgumentResolver是一个非常重要的组件&#xff0c;它负责解析URL路径中的变量并将其绑定到处理器方法的参数上。通过PathVariable注解&#xff0c;开发者可以方便地从URL中提取参数值&#xff0c;并传递给后端逻辑进行处理。本文…

【Web前端入门学习】—CSS

目录 CSS简介CSS语法CSS三种导入方式CSS选择器元素选择器&#xff08;标签选择器&#xff09;类选择器ID选择器通用选择器子元素选择器后代选择器&#xff08;包含选择器&#xff09;并集选择器&#xff08;兄弟选择器&#xff09;伪类选择器伪元素选择器 CSS常用属性盒子模型网…

电脑工作电压是多少你要看看光驱电源上面标的输入电压范围

要确定电脑的工作电压&#xff0c;必须查看电源上标注的输入电压范围。 国内法规规定民用220V电压范围为10%-15%&#xff0c;也就是说通信220V电压正常范围为187--242V&#xff0c;供电设备一般为180V。 --250V电压范围&#xff0c;即正常情况下电脑电源电压不低于187V即可工作…

css相邻元素边框重合问题,解决方案

1、如下图所示&#xff0c;在给元素设置边框后&#xff0c;相邻元素会出现重合的问题 2、解决方案 给每个元素设置margin-top以及margin-left为负的边框 <div style"width: 300px;display: flex;flex-wrap: wrap;margin-top: 50px;"><div style"border…

【数据结构】二、线性表:5.静态链表的定义及其基本操作(定义、初始化、插入、查找、删除、遍历、长度、特点)

文章目录 5.静态链表5.1定义5.2初始化5.3插入5.4查找5.5删除5.6遍历5.7长度5.8特点 5.静态链表 静态链表是使用数组来模拟链表结构的一种数据结构&#xff0c;用数组的方式实现的链表。 它与传统链表的区别在于&#xff0c;静态链表使用数组保存节点&#xff0c;每个节点包括…

笔记77:理解C++中头文件和源文件的作用【程序编译过程】

一、C 编译模式 通常&#xff0c;在一个 C 程序中&#xff0c;只包含两类文件—— .cpp 文件和 .h 文件。其中&#xff0c;.cpp 文件被称作 C 源文件&#xff0c;里面放的都是 C 的源代码&#xff1b;而 .h 文件则被称作 C 头文件&#xff0c;里面放的也是 C 的源代码。 C 语…

mac系统Idea登录codeium不跳转,报错faild download language server

问题描述 idea通过插件中心安装Codeium以后&#xff0c;登录无法正常跳转到登录页&#xff0c;等待一段时间&#xff0c;右下角图标报错**“faild download language server”** 解决方案 根据上面的报错&#xff0c;是没有成功下载“language_server_macos_x64“&#xff0…

CSAPP-程序的机器级表示

文章目录 概念扫盲思想理解经典好图安全事件 概念扫盲 1.汇编代码使用文本格式&#xff0c;相较于汇编的二进制可读性更好 2.程序内存包括&#xff1a;可执行的机器代码、操作系统需要的信息、管理过程调用和返回的运行时栈、用户分配的内存块 3.链接器为函数调用找到匹配的可…

P9889 [ICPC2018 Qingdao R] Plants vs. Zombies 题解 二分+贪心

[ICPC2018 Qingdao R] Plants vs. Zombies 传送门 题面翻译 给定 n n n 个植物和 m m m 的步数限制&#xff0c;每个植物在位置 1 … n 1\dots n 1…n 上。你初始时在位置 0 0 0&#xff0c;每次可以移动到相邻的位置上。 每次设你走完一步后到达的位置是 i i i&#…

数学建模【模糊综合评价分析】

一、模糊综合评价分析简介 提到模糊综合评价分析&#xff0c;就先得知道模糊数学。1965年美国控制论学家L.A.Zadeh发表的论文“Fuzzy sets”标志着模糊数学的诞生。 模糊数学又称Fuzzy数学&#xff0c;是研究和处理模糊性现象的一种数学理论和方法。模糊性数学发展的主流是在…

小程序API能力集成指南——配网能力API汇总(一)

ty.playnet.autoConnectToAp 自动连接wifi 需引入PlayNetKit&#xff0c;且在>1.1.0版本才可使用 请求参数 Object object 属性类型默认值必填说明ssidstring是配网之后&#xff0c;设备工作 Wi-Fi 的名称pwdstring是配网之后&#xff0c;设备工作 Wi-Fi 的密码completef…

git之系列

git之常用ignore 。 git之常用命令 。 git之reflog分析 。 git之添加和删除全局配置 。 git之如何恢复代码到之前版本 。 git之merge和rebase 。 git之如何合并部分提交 。 git之本地有未提交代码如何切换分支 。 Git通过tag创建分支并推送到远程 。

大语言模型系列-GPT-3

文章目录 前言一、GTP-3的改进二、GPT-3的表现总结 前言 《Language Models are Few-Shot Learners&#xff0c;2020》 前文提到GPT-2进一步提升了模型的zero shot能力&#xff0c;但是在一些任务中仍可能会“胡说”&#xff0c;GTP-3基于此提出了few shot&#xff0c;即预测…

7-22 试试手气(Python)

我们知道一个骰子有 6 个面&#xff0c;分别刻了 1 到 6 个点。下面给你 6 个骰子的初始状态&#xff0c;即它们朝上一面的点数&#xff0c;让你一把抓起摇出另一套结果。假设你摇骰子的手段特别精妙&#xff0c;每次摇出的结果都满足以下两个条件&#xff1a; 1、每个骰子摇出…

ZYNQ--AXI_DMA使用

文章目录 手册阅读典型连接图SG模式关闭时的寄存器地址SG模式开启时的寄存器地址BD设计PS端设计对于DMA寄存器的控制对DMA进行初始化 手册阅读 典型连接图 SG模式关闭时的寄存器地址 SG模式开启时的寄存器地址 关于各个bit的功能&#xff0c;具体看数据手册。 BD设计 通过PL侧…

sql高级

sql高级 SQL SELECT TOP 子句 SELECT TOP 子句用于规定要返回的记录的数目。 SELECT TOP 子句对于拥有数千条记录的大型表来说&#xff0c;是非常有用的。 **注意:**并非所有的数据库系统都支持 SELECT TOP 语句。 MySQL 支持 LIMIT 语句来选取指定的条数数据&#xff0c; O…

Qt + mqtt对接阿里云平台(一)

一、阿里云平台 官网&#xff1a;点击跳转 二、创建产品与设备 1、“公共实例” 2、“设备管理”->“产品”->“创建产品” 3、“产品名称”->“自定义品类”->"确认" 4、“前往添加” 5、“添加设备” 6、摄入DeviceName和备注名称 7、"前往查…

每周一算法:A*(A Star)算法

八数码难题 题目描述 在 3 3 3\times 3 33 的棋盘上&#xff0c;摆有八个棋子&#xff0c;每个棋子上标有 1 1 1 至 8 8 8 的某一数字。棋盘中留有一个空格&#xff0c;空格用 0 0 0 来表示。空格周围的棋子可以移到空格中。要求解的问题是&#xff1a;给出一种初始布局…

文心一言 VS 讯飞星火 VS chatgpt (210)-- 算法导论16.1 1题

一、根据递归式(16.2)为活动选择问题设计一个动态规划算法。算法应该按前文定义计算最大兼容活动集的大小 c[i,j]并生成最大集本身。假定输入的活动已按公式(16.1)排好序。比较你的算法和GREEDY-ACTIVITY-SELECTOR的运行时间。如何要写代码&#xff0c;请用go语言。 文心一言&…

excel统计分析——裂区设计

参考资料&#xff1a;生物统计学 裂区设计&#xff08;split-plot design&#xff09;是安排多因素试验的一种方法&#xff0c;裂区设计对因素的安排有主次之分&#xff0c;适用于安排对不同因素试验精度要求不一的试验。 裂区设计时&#xff0c;先按第一因素的处理数划分主区&…