open-mmlab/mmyolo

The network structure of the C2f module in YOLOv8 has a minor issue

Latitude9527 opened this issue · 4 comments

Prerequisite

🐞 Describe the bug

在我阅读yolov8源码后发现红圈所示的通道似乎不应该存在,代码中并没有关于这个通道的描述,而在图的最下面的Concat操作后时,似乎也没有算上这条通道(假设n为1,按照公式输出通道数应该只有1.5c,而按照图中如果算上红圈所示输出通道应该有2c个)
1
下面是yoloV8源码中关于C2F模块的定义:
class C2f(nn.Module):
"""Faster Implementation of CSP Bottleneck with 2 convolutions."""

def __init__(self, c1, c2, n=1, shortcut=False, g=1, e=0.5):
    """Initialize CSP bottleneck layer with two convolutions with arguments ch_in, ch_out, number, shortcut, groups,
    expansion.
    """
    super().__init__()
    self.c = int(c2 * e)  # hidden channels
    self.cv1 = Conv(c1, 2 * self.c, 1, 1)
    self.cv2 = Conv((2 + n) * self.c, c2, 1)  # optional act=FReLU(c2)
    self.m = nn.ModuleList(Bottleneck(self.c, self.c, shortcut, g, k=((3, 3), (3, 3)), e=1.0) for _ in range(n))

def forward(self, x):
    """Forward pass through C2f layer."""
    y = list(self.cv1(x).chunk(2, 1))
    y.extend(m(y[-1]) for m in self.m)
    return self.cv2(torch.cat(y, 1))

def forward_split(self, x):
    """Forward pass using split() instead of chunk()."""
    y = list(self.cv1(x).split((self.c, self.c), 1))
    y.extend(m(y[-1]) for m in self.m)
    return self.cv2(torch.cat(y, 1))

如果我的想法是错误的,请告诉我红圈的那条通道是如何产生的,谢谢

Environment

我并没有运行代码,只是在结合结构图阅读代码时产生了疑问

Additional information

No response

我认为那一条线是存在的,不过位置不对,应该在split下面
你看下面的代码

def forward(self, x):
    """Forward pass through C2f layer."""
    y = list(self.cv1(x).chunk(2, 1))       # 这一行的结果y包含了split的2个结果,2个分支都被保存
    y.extend(m(y[-1]) for m in self.m)
    return self.cv2(torch.cat(y, 1))

那一条线应该移动到下图的红色直线位置
yolov8

我还查看了自己导出的yolov8的onnx,concat是有2条split的输出的,所以证明是有那一条分支的,不过位置画错了,但是netron只画出了一条,那应该是软件bug
yolov8-1

我认为那一条线是存在的,不过位置不对,应该在split下面 你看下面的代码

def forward(self, x):
    """Forward pass through C2f layer."""
    y = list(self.cv1(x).chunk(2, 1))       # 这一行的结果y包含了split的2个结果,2个分支都被保存
    y.extend(m(y[-1]) for m in self.m)
    return self.cv2(torch.cat(y, 1))

那一条线应该移动到下图的红色直线位置 yolov8

我还查看了自己导出的yolov8的onnx,concat是有2条split的输出的,所以证明是有那一条分支的,不过位置画错了,但是netron只画出了一条,那应该是软件bug yolov8-1

但是这样一来最下面Concat算出来的通道数又不对了,而且split模块左边已经有一条线是你所说的功能了,而这段代码我的理解是:
def forward(self, x):
"""Forward pass through C2f layer."""
y = list(self.cv1(x).chunk(2, 1)) # 对输入变量x进行1×1卷积后仅从chunk分块操作,并将结构储存在列表y中,所以y是一个含两个张量的列表
y.extend(m(y[-1]) for m in self.m) # 对列表中最后一个元素通过Bottleneck模块进行处理并将结构添加到在y中,处理几次,存储几次
return self.cv2(torch.cat(y, 1)) #将列表y中的每个张量拼接在一起再进行1×1的卷积 ,然后输出
所以我认为红圈那条线直接删掉就可以了

我看了一下最新的图 https://github.com/open-mmlab/mmyolo/tree/main/configs/yolov8 ,发现相比你发的图片删除了一个分支,就是最下面的DarknetBottleneck左侧的分支被删除了,删除了这个分支再加上我上面说的红色分支,最后的concat结果就是对的了。

下图中蓝圈内的分支在新的图片中已经删除了
yolov8-2

我看了一下最新的图 https://github.com/open-mmlab/mmyolo/tree/main/configs/yolov8 ,发现相比你发的图片删除了一个分支,就是最下面的DarknetBottleneck左侧的分支被删除了,删除了这个分支再加上我上面说的红色分支,最后的concat结果就是对的了。

下图中蓝圈内的分支在新的图片中已经删除了 yolov8-2

好的,十分感谢