YOLO系列11:YOLOv9详解——可编程梯度信息与广义高效层聚合网络
YOLOv9通过可编程梯度信息(PGI)和广义高效层聚合网络(GELAN)两大创新解决了深度网络的信息瓶颈问题。PGI通过辅助可逆分支保留完整梯度信息,指导主网络训练;GELAN则优化了特征聚合方式。实验表明,YOLOv9在MS COCO数据集上以更少参数实现了更高精度(如YOLOv9-E达55.6% AP,优于YOLOv8-X的53.9%)。该工作从信息论角度分析了深度网络的信息损失问题,并提出
YOLO系列11:YOLOv9详解——可编程梯度信息与广义高效层聚合网络
1. 引言
YOLOv9于2024年2月由Chien-Yao Wang等人发布,论文题为"YOLOv9: Learning What You Want to Learn Using Programmable Gradient Information"。该版本从信息论角度出发,深入分析了深度网络中的信息瓶颈问题,并提出了**可编程梯度信息(PGI)和广义高效层聚合网络(GELAN)**两大创新,在MS COCO数据集上取得了当时最先进的性能。
1.1 核心贡献
| 贡献 | 描述 |
|---|---|
| 信息瓶颈分析 | 从理论层面分析深度网络中的信息损失问题 |
| PGI机制 | 可编程梯度信息,解决信息瓶颈导致的梯度退化 |
| GELAN架构 | 广义高效层聚合网络,实现高效特征提取 |
| 可逆分支 | 保留完整信息流,辅助主网络训练 |
1.2 性能表现
MS COCO 数据集性能对比:
YOLOv9-S: 46.8% AP, 7.2M参数, 26.7 GFLOPs
YOLOv9-M: 51.4% AP, 20.1M参数, 76.8 GFLOPs
YOLOv9-C: 53.0% AP, 25.5M参数, 102.8 GFLOPs
YOLOv9-E: 55.6% AP, 58.1M参数, 192.5 GFLOPs
对比 YOLOv8-X (53.9% AP, 68.2M参数, 257.8 GFLOPs)
YOLOv9-E 在更少参数下提升1.7% AP
2. 信息瓶颈理论
2.1 深度网络中的信息损失
YOLOv9的核心创新基于对深度网络信息传递的理论分析。在深度网络中,信息在层间传递时会不可避免地发生损失:
数据处理不等式(Data Processing Inequality):
I ( X ; Y ) ≥ I ( X ; f θ ( Y ) ) I(X; Y) \geq I(X; f_\theta(Y)) I(X;Y)≥I(X;fθ(Y))
其中:
- I ( ⋅ ; ⋅ ) I(\cdot; \cdot) I(⋅;⋅) 表示互信息
- X X X 为原始输入数据
- Y Y Y 为某一层的特征
- f θ f_\theta fθ 为参数化变换
这意味着经过每一层变换,特征与原始输入之间的互信息只会减少或保持不变。
2.2 信息瓶颈的形成
信息瓶颈的数学表达:
对于 N N N 层网络,设第 i i i 层输出为 f i f_i fi:
I ( X ; f N ) ≤ I ( X ; f N − 1 ) ≤ ⋯ ≤ I ( X ; f 1 ) ≤ I ( X ; X ) = H ( X ) I(X; f_N) \leq I(X; f_{N-1}) \leq \cdots \leq I(X; f_1) \leq I(X; X) = H(X) I(X;fN)≤I(X;fN−1)≤⋯≤I(X;f1)≤I(X;X)=H(X)
当网络变深时, I ( X ; f N ) I(X; f_N) I(X;fN) 可能趋近于零,导致:
∂ L ∂ W i ≈ 0 \frac{\partial \mathcal{L}}{\partial W_i} \approx 0 ∂Wi∂L≈0
即梯度消失,网络无法有效学习。
2.3 可逆函数的理论基础
为了解决信息瓶颈问题,YOLOv9引入可逆函数的概念:
定义:如果变换 r : X → Y r: X \rightarrow Y r:X→Y 存在逆变换 v : Y → X v: Y \rightarrow X v:Y→X,使得 v ( r ( X ) ) = X v(r(X)) = X v(r(X))=X,则称 r r r 为可逆函数。
性质:对于可逆变换,有:
I ( X ; r ( X ) ) = I ( X ; X ) = H ( X ) I(X; r(X)) = I(X; X) = H(X) I(X;r(X))=I(X;X)=H(X)
即信息完全保留,不存在信息损失。
3. 可编程梯度信息(PGI)
3.1 PGI架构设计
PGI的核心思想是通过额外的可逆分支来提供完整的梯度信息,指导主网络的训练:
3.2 辅助可逆分支
辅助可逆分支的设计确保信息的完整传递:
可逆块设计:
class ReversibleBlock(nn.Module):
"""可逆残差块"""
def __init__(self, channels):
super().__init__()
self.F = nn.Sequential(
nn.Conv2d(channels // 2, channels // 2, 3, padding=1),
nn.BatchNorm2d(channels // 2),
nn.SiLU(),
nn.Conv2d(channels // 2, channels // 2, 3, padding=1),
nn.BatchNorm2d(channels // 2),
)
self.G = nn.Sequential(
nn.Conv2d(channels // 2, channels // 2, 3, padding=1),
nn.BatchNorm2d(channels // 2),
nn.SiLU(),
nn.Conv2d(channels // 2, channels // 2, 3, padding=1),
nn.BatchNorm2d(channels // 2),
)
def forward(self, x):
x1, x2 = x.chunk(2, dim=1)
y1 = x1 + self.F(x2)
y2 = x2 + self.G(y1)
return torch.cat([y1, y2], dim=1)
def inverse(self, y):
y1, y2 = y.chunk(2, dim=1)
x2 = y2 - self.G(y1)
x1 = y1 - self.F(x2)
return torch.cat([x1, x2], dim=1)
3.3 可逆性的数学证明
对于上述可逆块,设输入为 ( x 1 , x 2 ) (x_1, x_2) (x1,x2),输出为 ( y 1 , y 2 ) (y_1, y_2) (y1,y2):
前向传播:
y 1 = x 1 + F ( x 2 ) y_1 = x_1 + F(x_2) y1=x1+F(x2)
y 2 = x 2 + G ( y 1 ) y_2 = x_2 + G(y_1) y2=x2+G(y1)
逆向传播:
x 2 = y 2 − G ( y 1 ) x_2 = y_2 - G(y_1) x2=y2−G(y1)
x 1 = y 1 − F ( x 2 ) x_1 = y_1 - F(x_2) x1=y1−F(x2)
验证可逆性:
x 1 = y 1 − F ( x 2 ) = y 1 − F ( y 2 − G ( y 1 ) ) x_1 = y_1 - F(x_2) = y_1 - F(y_2 - G(y_1)) x1=y1−F(x2)=y1−F(y2−G(y1))
代入前向公式可证明逆向传播能精确恢复原始输入。
3.4 梯度信息的程序化控制
PGI通过以下方式实现梯度的"可编程"控制:
多级辅助信息:
class PGI(nn.Module):
"""可编程梯度信息模块"""
def __init__(self, main_branch, aux_branch, fusion_layers):
super().__init__()
self.main_branch = main_branch
self.aux_branch = aux_branch # 可逆分支
self.fusion_layers = fusion_layers
def forward(self, x):
# 主分支特征
main_features = self.main_branch(x)
if self.training:
# 辅助分支提供完整梯度信息
aux_features = self.aux_branch(x)
# 梯度信息融合
for i, (main_f, aux_f) in enumerate(zip(main_features, aux_features)):
# 辅助分支的梯度指导主分支
main_features[i] = main_f + self.fusion_layers[i](aux_f)
return main_features
3.5 损失函数设计
PGI的总损失函数包含主损失和辅助损失:
L t o t a l = L m a i n + λ ⋅ L a u x \mathcal{L}_{total} = \mathcal{L}_{main} + \lambda \cdot \mathcal{L}_{aux} Ltotal=Lmain+λ⋅Laux
其中:
L m a i n = L b o x + L c l s + L d f l \mathcal{L}_{main} = \mathcal{L}_{box} + \mathcal{L}_{cls} + \mathcal{L}_{dfl} Lmain=Lbox+Lcls+Ldfl
L a u x = L b o x a u x + L c l s a u x \mathcal{L}_{aux} = \mathcal{L}_{box}^{aux} + \mathcal{L}_{cls}^{aux} Laux=Lboxaux+Lclsaux
辅助损失只在训练时计算,推理时辅助分支被移除。
4. 广义高效层聚合网络(GELAN)
4.1 GELAN设计理念
GELAN是对CSPNet和ELAN的泛化,旨在实现更灵活高效的特征聚合:
4.2 与现有架构的关系
GELAN可以统一表示多种经典架构:
| 架构 | GELAN表示 |
|---|---|
| CSPNet | 分割比例=0.5,单计算单元 |
| ELAN | 等分割,多并行计算单元 |
| VoVNet | 全通道参与,密集连接 |
| ResNet | 分割比例=1,单计算单元+残差 |
4.3 GELAN Block实现
class GELANBlock(nn.Module):
"""广义高效层聚合块"""
def __init__(self, in_channels, out_channels, num_blocks=2,
split_ratio=0.5, block_type='conv'):
super().__init__()
hidden_channels = int(in_channels * split_ratio)
# 通道分割
self.split_channels = hidden_channels
# 计算块列表
self.blocks = nn.ModuleList()
for i in range(num_blocks):
if block_type == 'conv':
block = ConvBlock(hidden_channels, hidden_channels)
elif block_type == 'repconv':
block = RepConvBlock(hidden_channels, hidden_channels)
elif block_type == 'csp':
block = CSPBlock(hidden_channels, hidden_channels)
self.blocks.append(block)
# 过渡层:聚合所有分支
concat_channels = hidden_channels * (num_blocks + 1)
self.transition = nn.Sequential(
nn.Conv2d(concat_channels, out_channels, 1),
nn.BatchNorm2d(out_channels),
nn.SiLU()
)
def forward(self, x):
# 通道分割
x1 = x[:, :self.split_channels, :, :]
x2 = x[:, self.split_channels:, :, :]
# 收集所有分支输出
outputs = [x1]
current = x2
for block in self.blocks:
current = block(current)
outputs.append(current)
# 特征聚合
concat = torch.cat(outputs, dim=1)
out = self.transition(concat)
return out
class ConvBlock(nn.Module):
"""基础卷积块"""
def __init__(self, in_channels, out_channels, kernel_size=3):
super().__init__()
self.conv = nn.Sequential(
nn.Conv2d(in_channels, out_channels, kernel_size,
padding=kernel_size//2),
nn.BatchNorm2d(out_channels),
nn.SiLU()
)
def forward(self, x):
return self.conv(x)
4.4 GELAN的计算效率分析
设输入通道数为 C C C,分割比例为 α \alpha α,计算块数为 N N N:
参数量:
P = α C ⋅ k 2 ⋅ N + ( N + 1 ) α C ⋅ C o u t P = \alpha C \cdot k^2 \cdot N + (N+1)\alpha C \cdot C_{out} P=αC⋅k2⋅N+(N+1)αC⋅Cout
计算量:
F L O P s = α C ⋅ k 2 ⋅ H ⋅ W ⋅ N + ( N + 1 ) α C ⋅ C o u t ⋅ H ⋅ W FLOPs = \alpha C \cdot k^2 \cdot H \cdot W \cdot N + (N+1)\alpha C \cdot C_{out} \cdot H \cdot W FLOPs=αC⋅k2⋅H⋅W⋅N+(N+1)αC⋅Cout⋅H⋅W
通过调整 α \alpha α 和 N N N,可以灵活控制计算效率与特征表达能力的平衡。
5. YOLOv9网络架构
5.1 整体架构
5.2 Backbone配置
# YOLOv9 Backbone配置
backbone_config = {
'yolov9-s': {
'depth_multiple': 0.33,
'width_multiple': 0.25,
'stages': [
# [out_channels, num_blocks, block_type]
[64, 1, 'gelan'],
[128, 2, 'gelan'],
[256, 2, 'gelan'],
[512, 1, 'gelan'],
]
},
'yolov9-m': {
'depth_multiple': 0.67,
'width_multiple': 0.50,
'stages': [
[64, 2, 'gelan'],
[128, 4, 'gelan'],
[256, 4, 'gelan'],
[512, 2, 'gelan'],
]
},
'yolov9-c': {
'depth_multiple': 1.0,
'width_multiple': 0.75,
'stages': [
[64, 3, 'gelan'],
[128, 6, 'gelan'],
[256, 6, 'gelan'],
[512, 3, 'gelan'],
]
},
'yolov9-e': {
'depth_multiple': 1.0,
'width_multiple': 1.0,
'stages': [
[64, 3, 'gelan'],
[128, 6, 'gelan'],
[256, 6, 'gelan'],
[512, 3, 'gelan'],
]
}
}
5.3 完整网络实现
class YOLOv9(nn.Module):
"""YOLOv9检测模型"""
def __init__(self, num_classes=80, model_size='yolov9-c',
use_pgi=True):
super().__init__()
self.num_classes = num_classes
self.use_pgi = use_pgi
config = backbone_config[model_size]
dm = config['depth_multiple']
wm = config['width_multiple']
# Stem
self.stem = nn.Sequential(
nn.Conv2d(3, int(64 * wm), 3, 2, 1),
nn.BatchNorm2d(int(64 * wm)),
nn.SiLU()
)
# Backbone stages
self.stages = nn.ModuleList()
in_ch = int(64 * wm)
for out_ch, num_blocks, block_type in config['stages']:
out_ch = int(out_ch * wm)
num_blocks = max(1, int(num_blocks * dm))
self.stages.append(
self._make_stage(in_ch, out_ch, num_blocks, block_type)
)
in_ch = out_ch
# Neck: PANet
self.neck = PANet(
in_channels=[int(128*wm), int(256*wm), int(512*wm)],
out_channels=int(256*wm)
)
# Detection head
self.head = DetectionHead(
in_channels=[int(256*wm)] * 3,
num_classes=num_classes
)
# PGI辅助分支(可选)
if use_pgi:
self.aux_branch = self._build_aux_branch(wm, dm)
self.aux_head = DetectionHead(
in_channels=[int(256*wm)] * 3,
num_classes=num_classes
)
def _make_stage(self, in_ch, out_ch, num_blocks, block_type):
layers = [
nn.Conv2d(in_ch, out_ch, 3, 2, 1),
nn.BatchNorm2d(out_ch),
nn.SiLU()
]
for _ in range(num_blocks):
layers.append(GELANBlock(out_ch, out_ch))
return nn.Sequential(*layers)
def _build_aux_branch(self, wm, dm):
"""构建辅助可逆分支"""
return ReversibleBranch(
channels=[int(64*wm), int(128*wm), int(256*wm), int(512*wm)]
)
def forward(self, x):
# Stem
x = self.stem(x)
# Backbone
features = []
for i, stage in enumerate(self.stages):
x = stage(x)
if i >= 1: # 保存P3, P4, P5特征
features.append(x)
# Neck
neck_features = self.neck(features)
# Main head
outputs = self.head(neck_features)
if self.training and self.use_pgi:
# 辅助分支
aux_features = self.aux_branch(features)
aux_outputs = self.aux_head(aux_features)
return outputs, aux_outputs
return outputs
6. 关键模块详解
6.1 RepNCSPELAN4
YOLOv9中的核心特征提取模块:
class RepNCSPELAN4(nn.Module):
"""Rep-NCSP-ELAN4模块"""
def __init__(self, c1, c2, c3, c4, n=1):
super().__init__()
self.c = c3 // 2
self.cv1 = Conv(c1, c3, 1, 1)
self.cv2 = nn.Sequential(
RepNCSP(c3 // 2, c4, n),
Conv(c4, c4, 3, 1)
)
self.cv3 = nn.Sequential(
RepNCSP(c4, c4, n),
Conv(c4, c4, 3, 1)
)
self.cv4 = Conv(c3 + 2 * c4, c2, 1, 1)
def forward(self, x):
y = list(self.cv1(x).chunk(2, 1))
y.extend([self.cv2(y[-1]), self.cv3(y[-1])])
return self.cv4(torch.cat(y, 1))
class RepNCSP(nn.Module):
"""重参数化NCSP模块"""
def __init__(self, c1, c2, n=1, shortcut=True, e=0.5):
super().__init__()
c_ = int(c2 * e)
self.cv1 = Conv(c1, c_, 1, 1)
self.cv2 = Conv(c1, c_, 1, 1)
self.cv3 = Conv(2 * c_, c2, 1)
self.m = nn.Sequential(
*[RepNBottleneck(c_, c_, shortcut, e=1.0) for _ in range(n)]
)
def forward(self, x):
return self.cv3(torch.cat((self.m(self.cv1(x)), self.cv2(x)), 1))
class RepNBottleneck(nn.Module):
"""重参数化N-Bottleneck"""
def __init__(self, c1, c2, shortcut=True, e=0.5):
super().__init__()
c_ = int(c2 * e)
self.cv1 = RepConvN(c1, c_, 3, 1)
self.cv2 = Conv(c_, c2, 3, 1)
self.add = shortcut and c1 == c2
def forward(self, x):
return x + self.cv2(self.cv1(x)) if self.add else self.cv2(self.cv1(x))
6.2 ADown下采样模块
class ADown(nn.Module):
"""高效下采样模块"""
def __init__(self, c1, c2):
super().__init__()
self.c = c2 // 2
self.cv1 = Conv(c1 // 2, self.c, 3, 2, 1)
self.cv2 = Conv(c1 // 2, self.c, 1, 1, 0)
def forward(self, x):
x = torch.nn.functional.avg_pool2d(x, 2, 1, 0, False, True)
x1, x2 = x.chunk(2, 1)
x1 = self.cv1(x1)
x2 = torch.nn.functional.max_pool2d(x2, 3, 2, 1)
x2 = self.cv2(x2)
return torch.cat((x1, x2), 1)
6.3 SPPELAN模块
class SPPELAN(nn.Module):
"""SPP-ELAN模块"""
def __init__(self, c1, c2, c3, k=5):
super().__init__()
self.c = c3
self.cv1 = Conv(c1, c3, 1, 1)
self.cv2 = nn.MaxPool2d(kernel_size=k, stride=1, padding=k // 2)
self.cv3 = nn.MaxPool2d(kernel_size=k, stride=1, padding=k // 2)
self.cv4 = nn.MaxPool2d(kernel_size=k, stride=1, padding=k // 2)
self.cv5 = Conv(4 * c3, c2, 1, 1)
def forward(self, x):
y = [self.cv1(x)]
y.extend([self.cv2(y[-1]), self.cv3(y[-1]), self.cv4(y[-1])])
return self.cv5(torch.cat(y, 1))
7. 训练策略
7.1 PGI训练流程
class YOLOv9Trainer:
"""YOLOv9训练器"""
def __init__(self, model, train_loader, val_loader, config):
self.model = model
self.train_loader = train_loader
self.val_loader = val_loader
self.config = config
self.optimizer = optim.SGD(
model.parameters(),
lr=config['lr'],
momentum=0.937,
weight_decay=5e-4
)
self.scheduler = CosineAnnealingLR(
self.optimizer,
T_max=config['epochs']
)
# 主损失和辅助损失权重
self.aux_weight = config.get('aux_weight', 0.25)
def train_epoch(self, epoch):
self.model.train()
total_loss = 0
for batch_idx, (images, targets) in enumerate(self.train_loader):
images = images.cuda()
targets = targets.cuda()
self.optimizer.zero_grad()
# 前向传播
if self.model.use_pgi:
main_outputs, aux_outputs = self.model(images)
# 计算主损失
main_loss = self.compute_loss(main_outputs, targets)
# 计算辅助损失
aux_loss = self.compute_loss(aux_outputs, targets)
# 总损失
loss = main_loss + self.aux_weight * aux_loss
else:
outputs = self.model(images)
loss = self.compute_loss(outputs, targets)
loss.backward()
self.optimizer.step()
total_loss += loss.item()
return total_loss / len(self.train_loader)
def compute_loss(self, outputs, targets):
"""计算检测损失"""
box_loss = compute_box_loss(outputs, targets)
cls_loss = compute_cls_loss(outputs, targets)
dfl_loss = compute_dfl_loss(outputs, targets)
return box_loss + cls_loss + dfl_loss
7.2 数据增强策略
# YOLOv9数据增强配置
augmentation_config = {
# Mosaic增强
'mosaic': 1.0,
'mosaic_scale': (0.1, 2.0),
# MixUp增强
'mixup': 0.15,
# Copy-Paste增强
'copy_paste': 0.3,
# 几何变换
'degrees': 0.0,
'translate': 0.1,
'scale': 0.9,
'shear': 0.0,
'perspective': 0.0,
# 颜色增强
'hsv_h': 0.015,
'hsv_s': 0.7,
'hsv_v': 0.4,
# 翻转
'flipud': 0.0,
'fliplr': 0.5,
}
7.3 辅助分支移除
推理时需要移除辅助分支以提高效率:
def remove_aux_branch(model):
"""移除辅助分支,用于推理"""
if hasattr(model, 'aux_branch'):
delattr(model, 'aux_branch')
if hasattr(model, 'aux_head'):
delattr(model, 'aux_head')
model.use_pgi = False
return model
# 使用示例
model = YOLOv9(num_classes=80, use_pgi=True)
# 训练...
# 推理前移除辅助分支
model = remove_aux_branch(model)
model.eval()
8. 实验与性能分析
8.1 COCO数据集结果
| 模型 | 输入尺寸 | AP | AP50 | AP75 | 参数量 | FLOPs |
|---|---|---|---|---|---|---|
| YOLOv9-S | 640 | 46.8% | 63.4% | 50.7% | 7.2M | 26.7G |
| YOLOv9-M | 640 | 51.4% | 68.1% | 56.1% | 20.1M | 76.8G |
| YOLOv9-C | 640 | 53.0% | 70.2% | 57.8% | 25.5M | 102.8G |
| YOLOv9-E | 640 | 55.6% | 72.8% | 60.6% | 58.1M | 192.5G |
8.2 与其他模型对比
参数效率对比(相同AP水平):
YOLOv9-C vs YOLOv7:
- AP: 53.0% vs 51.4%
- 参数: 25.5M vs 36.9M(减少31%)
- FLOPs: 102.8G vs 104.7G(减少2%)
YOLOv9-E vs YOLOv8-X:
- AP: 55.6% vs 53.9%(提升1.7%)
- 参数: 58.1M vs 68.2M(减少15%)
- FLOPs: 192.5G vs 257.8G(减少25%)
8.3 消融实验
PGI效果验证:
| 配置 | AP | AP50 | 说明 |
|---|---|---|---|
| Baseline | 51.2% | 67.8% | 无PGI |
| + 辅助损失 | 52.1% | 68.5% | 普通辅助分支 |
| + 可逆分支 | 52.8% | 69.2% | 可逆辅助分支 |
| + PGI完整 | 53.0% | 70.2% | 完整PGI |
GELAN效果验证:
| 架构 | AP | 参数量 | FLOPs |
|---|---|---|---|
| CSPDarknet | 51.8% | 28.2M | 115.6G |
| ELAN | 52.4% | 26.8M | 108.2G |
| GELAN | 53.0% | 25.5M | 102.8G |
9. 代码使用示例
9.1 模型加载与推理
import torch
from yolov9 import YOLOv9
# 加载模型
model = YOLOv9(num_classes=80, model_size='yolov9-c', use_pgi=False)
model.load_state_dict(torch.load('yolov9-c.pt'))
model.eval()
model.cuda()
# 推理
image = preprocess_image('test.jpg')
with torch.no_grad():
outputs = model(image.cuda())
# 后处理
results = postprocess(outputs, conf_thres=0.25, iou_thres=0.45)
9.2 使用官方代码
# 克隆官方仓库
git clone https://github.com/WongKinYiu/yolov9
cd yolov9
# 安装依赖
pip install -r requirements.txt
# 检测
python detect.py --weights yolov9-c.pt --source test.jpg
# 训练
python train.py --batch 16 --epochs 300 --data coco.yaml \
--weights '' --cfg yolov9-c.yaml --device 0
# 验证
python val.py --data coco.yaml --weights yolov9-c.pt --batch 32
10. 总结
10.1 YOLOv9核心创新
| 创新点 | 技术细节 | 作用 |
|---|---|---|
| 信息瓶颈分析 | 数据处理不等式,互信息分析 | 理论指导 |
| PGI | 可逆分支,梯度信息编程 | 解决梯度退化 |
| GELAN | 泛化的层聚合架构 | 高效特征提取 |
| 辅助分支 | 训练时辅助,推理时移除 | 无推理开销 |
10.2 设计理念
YOLOv9从信息论角度重新审视深度网络的设计,通过:
- 理论分析:揭示信息瓶颈问题的本质
- PGI机制:提供完整的梯度信息
- GELAN架构:实现高效的特征聚合
- 可逆设计:保证信息的无损传递
10.3 适用场景
- 高精度目标检测任务
- 计算资源受限的边缘部署
- 需要平衡精度与效率的应用
- 研究深度网络信息传递机制
系列导航:
- 上一篇:YOLO系列10:YOLOv8详解
- 下一篇:YOLO系列12:YOLOv10详解
- 返回目录
更多推荐
所有评论(0)