yolo.py目录
m __init__(self, nc=80, anchors=(), ch=(), inplace=True)
m _make_grid(self, nx=20, ny=20, i=0, torch_1_10=check_version(torch.__version__, '1.10.0'))
m __init__(self, nc=80, anchors=(), nm=32, npr=256, ch=(), inplace=True)
m forward(self, x, profile=False, visualize=False)
m _forward_once(self, x, profile=False, visualize=False)
m _profile_one_layer(self, m, x, dt)
m info(self, verbose=False, img_size=640)
m __init__(self, cfg='yolov5s.yaml', ch=3, nc=None, anchors=None)
m forward(self, x, augment=False, profile=False, visualize=False)
m _descale_pred(self, p, flips, scale, img_size)
m _initialize_biases(self, cf=None)
c SegmentationModel(DetectionModel)
m __init__(self, cfg='yolov5s-seg.yaml', ch=3, nc=None, anchors=None)
c ClassificationModel(BaseModel)
m __init__(self, cfg=None, model=None, nc=1000, cutoff=10)
common.py
class SPPF(nn.Module):
# Spatial Pyramid Pooling - Fast (SPPF) layer for YOLOv5 by Glenn Jocher实现空间金字塔池化
def __init__(self, c1, c2, k=5): # equivalent to SPP(k=(5, 9, 13))
super().__init__()
c_ = c1 // 2 # hidden channels
self.cv1 = Conv(c1, c_, 1, 1)
self.cv2 = Conv(c_ * 4, c2, 1, 1)
self.m = nn.MaxPool2d(kernel_size=k, stride=1, padding=k // 2)
def forward(self, x):
x = self.cv1(x)
with warnings.catch_warnings():
warnings.simplefilter('ignore') # suppress torch 1.9.0 max_pool2d() warning
y1 = self.m(x)
y2 = self.m(y1)
return self.cv2(torch.cat((x, y1, y2, self.m(y2)), 1))
这个类具有两个主要部分:初始化函数__init__
和前向传播函数forward
。
在__init__
函数中,首先计算了隐藏通道数c_
,然后初始化了两个卷积层(cv1
和cv2
),最后定义了一个最大池化层self.m
。
在forward
函数中,输入x
首先通过cv1
卷积层处理,然后经过两次池化操作(self.m(x)
和self.m(y1)
),最后将结果拼接起来并通过cv2
卷积层处理。
代码中用到了警告处理,用于忽略特定类型的警告,这里是PyTorch 1.9.0版本的中max_pool2d()函数的警告。
总的来说,这个SPPF类是为了在YOLOv5中实现空间金字塔池化(Spatial Pyramid Pooling)。这种池化方式可以在不同尺度上提取特征,从而使模型能够更好地理解和处理输入数据的多样性。
class Focus(nn.Module):
# Focus wh information into c-space
def __init__(self, c1, c2, k=1, s=1, p=None, g=1, act=True): # ch_in, ch_out, kernel, stride, padding, groups
super().__init__()
self.conv = Conv(c1 * 4, c2, k, s, p, g, act=act)
# self.contract = Contract(gain=2)
def forward(self, x): # x(b,c,w,h) -> y(b,4c,w/2,h/2)
return self.conv(torch.cat((x[..., ::2, ::2], x[..., 1::2, ::2], x[..., ::2, 1::2], x[..., 1::2, 1::2]), 1))
# return self.conv(self.contract(x))
init函数接受7个参数(c1,c2,k,s,p,g,act)(输入通道数、输出通道数、核数、步长、是否填充、组数、是否使用激活函数),并且这些参数可以用于配置Conv函数。
前向传播函数定义了输入数据x通过网络时的前向传播过程。它对输入的四分之三的空间信息用torch.cat进行连接,然后通过卷积层进行运算。
class GhostConv(nn.Module):
# Ghost Convolution https://github.com/huawei-noah/ghostnet
def __init__(self, c1, c2, k=1, s=1, g=1, act=True): # ch_in, ch_out, kernel, stride, groups
super().__init__()
c_ = c2 // 2 # hidden channels
self.cv1 = Conv(c1, c_, k, s, None, g, act=act)
self.cv2 = Conv(c_, c_, 5, 1, None, c_, act=act)
def forward(self, x):
y = self.cv1(x)
return torch.cat((y, self.cv2(y)), 1)
隐藏通道数为c2的一半,forward前向传播函数先进行一次卷积,再将卷积结果进行第二次卷积,并将两次的卷积结果通过torch.cat 拼接。提高网络性能和模型精度的轻量级卷积方法。
class GhostBottleneck(nn.Module):
# Ghost Bottleneck https://github.com/huawei-noah/ghostnet
def __init__(self, c1, c2, k=3, s=1): # ch_in, ch_out, kernel, stride
super().__init__()
c_ = c2 // 2
self.conv = nn.Sequential(
GhostConv(c1, c_, 1, 1), # pw
DWConv(c_, c_, k, s, act=False) if s == 2 else nn.Identity(), # dw
GhostConv(c_, c2, 1, 1, act=False)) # pw-linear
self.shortcut = nn.Sequential(DWConv(c1, c1, k, s, act=False), Conv(c1, c2, 1, 1,
act=False)) if s == 2 else nn.Identity()
def forward(self, x):
return self.conv(x) + self.shortcut(x)
定义了一个名为'conv'的序列,它包括以下三个部分:
- 一个GhostConv层,作为第一个部分,它输入的通道数为'c1',输出的通道数为'c_',卷积核大小和步长都为1。
- 一个DWConv层或一个Identity,作为第二个部分。如果步长为2,就使用DWConv层,否则使用Identity。这个层的输入通道数为'c_',输出的通道数也为'c_',卷积核大小和步长分别为给定的'k'和's'。如果步长为2,这个部分之后还有一个GhostConv层,输入的通道数为'c_',输出的通道数为'c2',卷积核大小和步长都为1。
所有这些部分通过nn.Sequential连接起来。
接下来,定义了一个名为'shortcut'的序列,如果步长为2,它包括一个DWConv层和一个Conv层,否则它只包括一个Identity。
最后,在'forward'方法中,模块的前向传播被定义。输入数据'x'首先通过'conv'序列进行计算,然后与通过'shortcut'序列计算的输出相加。
class Contract(nn.Module):
# Contract width-height into channels, i.e. x(1,64,80,80) to x(1,256,40,40)
def __init__(self, gain=2):
super().__init__()
self.gain = gain
def forward(self, x):
b, c, h, w = x.size() # assert (h / s == 0) and (W / s == 0), 'Indivisible gain'
s = self.gain
x = x.view(b, c, h // s, s, w // s, s) # x(1,64,40,2,40,2)
x = x.permute(0, 3, 5, 1, 2, 4).contiguous() # x(1,2,2,64,40,40)
return x.view(b, c * s * s, h // s, w // s) # x(1,256,40,40)
gain参数指定了宽高缩放的比例。这个比例将被用于将输入的张量'x'的宽度和高度进行缩小,并将通道数增加为原来的gain的平方倍。
前向传播函数forward :使用view将(b,c,h,w)变为(b,c,h//s,s,w//s,s),再使用permute将其顺序改变,最后使用view输出(b,c,c*s*s,h//s,w//s)
class Expand(nn.Module):
# Expand channels into width-height, i.e. x(1,64,80,80) to x(1,16,160,160)
def __init__(self, gain=2):
super().__init__()
self.gain = gain
def forward(self, x):
b, c, h, w = x.size() # assert C / s ** 2 == 0, 'Indivisible gain'
s = self.gain
x = x.view(b, s, s, c // s ** 2, h, w) # x(1,2,2,16,80,80)
x = x.permute(0, 3, 4, 1, 5, 2).contiguous() # x(1,16,80,2,80,2)
return x.view(b, c // s ** 2, h * s, w * s) # x(1,16,160,160)
gain参数指定了增益,即宽度和高度将增加原来的gain的平方倍,通道数将减少到原来的1/s的平方倍。
这个模块的主要作用就是将输入的张量进行宽度和高度增加,并减少通道数。
class Concat(nn.Module):
# Concatenate a list of tensors along dimension
def __init__(self, dimension=1):
super().__init__()
self.d = dimension
def forward(self, x):
return torch.cat(x, self.d)
init函数有一个参数'dimension',默认值为1。这个参数用于指定连接张量列表时的维度。
前向传播函数forward,接收一个参数'x',这是一个张量列表。然后使用PyTorch的'torch.cat'函数将这个列表中的所有张量沿着指定的维度(self.d)连接起来。
这个'Concat'类可以沿着指定的维度连接一个张量列表。