|
|
|
""" |
|
Block modules |
|
""" |
|
|
|
import torch |
|
import torch.nn as nn |
|
from timm.models.layers import DropPath |
|
|
|
from .conv import Conv |
|
|
|
|
|
__all__ = ('C2f', 'Bottleneck',) |
|
|
|
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, drop_path=None): |
|
super().__init__() |
|
if drop_path is None: |
|
drop_path = [0.0] * n |
|
|
|
self.c = int(c2 * e) |
|
self.cv1 = Conv(c1, 2 * self.c, 1, 1) |
|
self.cv2 = Conv((2 + n) * self.c, c2, 1) |
|
self.m = nn.ModuleList(Bottleneck(self.c, self.c, shortcut, g, k=((3, 3), (3, 3)), e=1.0, drop_path=drop_path[i]) for i 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)) |
|
|
|
|
|
class Bottleneck(nn.Module): |
|
"""Standard bottleneck.""" |
|
|
|
def __init__(self, c1, c2, shortcut=True, g=1, k=(3, 3), e=0.5, drop_path=0.0): |
|
super().__init__() |
|
c_ = int(c2 * e) |
|
self.cv1 = Conv(c1, c_, k[0], 1) |
|
self.cv2 = Conv(c_, c2, k[1], 1, g=g) |
|
self.add = shortcut and c1 == c2 |
|
self.drop_path1 = DropPath(drop_path) if drop_path > 0. else nn.Identity() |
|
|
|
def forward(self, x): |
|
"""'forward()' applies the YOLOv5 FPN to input data.""" |
|
return x + self.drop_path1(self.cv2(self.cv1(x))) if self.add else self.cv2(self.cv1(x)) |
|
|