Yolov4 with MobileNet V2/V3 Backbone

shihyung
7 min readNov 9, 2020

--

* 目的:

這邊嘗試著以 MobileNet V2/V3 將 Yolov4 的 backbone 做替換來看看會有怎樣的訓練趨勢。

*Backbone 替換

* yaml 檔修改

原始的 Yolov4 yaml 檔案的 backbone:

修改後的 Yolov4_L_MobileNet_V2 yaml:

修改後的 Yolov4_L_MobileNet_V3_small yaml:

修改後的 Yolov4_L_MobileNet_V3_Large yaml:

* 程式修改 (以 Mobilenet_v3為例)

yolo.py, parse_model() 增加:

elif m is CBH:
c1=ch[f if f<0 else f+1]
c2=args[0]
args=[c1,c2,*args[1:]]
elif m is mb3Block:
c1=ch[f if f<0 else f+1]
c2=args[1]
args=[c1,*args]

if m is mb3Block:
m_=m(*args)

common.py 增加:

class hswish(nn.Module):
def forward(self, x):
out = x * nn.functional.relu6(x + 3, inplace=True) / 6
return out

class hsigmoid(nn.Module):
def forward(self, x):
out = nn.functional.relu6(x + 3, inplace=True) / 6
return out

class CBH(nn.Sequential):
def __init__(self, c1, c2, k=1, s=1): # ch_in, ch_out, kernel, stride, padding, groups
super(CBH, self).__init__()
self.conv = nn.Conv2d(c1, c2, k, s, autopad(k, None), bias=False)
self.bn = nn.BatchNorm2d(c2)
self.act = hswish()
def forward(self, x):
return self.act(self.bn(self.conv(x)))

class mb3SE(nn.Module):
def __init__(self, in_size, reduction=4):
super(mb3SE, self).__init__()
self.se = nn.Sequential(
nn.AdaptiveAvgPool2d(1),
nn.Conv2d(in_size, in_size // reduction, kernel_size=1, stride=1, padding=0, bias=False),
nn.ReLU(inplace=True),
nn.Conv2d(in_size // reduction, in_size, kernel_size=1, stride=1, padding=0, bias=False),
hsigmoid()
)
def forward(self, x):
return x * self.se(x)

class mb3Block(nn.Module):
def __init__(self, c1, cexp, c2, k=1, s=1, se=None, act='H'): #chin, ch_expansion, chout, stride, se, activation
super(mb3Block,self).__init__()
self.se=True if se=='S' else False
if self.se:
self.sem=mb3SE(c2)
self.stride=s
self.conv1 = nn.Conv2d(c1, cexp, kernel_size=1, stride=1, padding=0, bias=False)
self.bn1 = nn.BatchNorm2d(cexp)
self.act1 = hswish() if act=='H' else nn.ReLU(inplace=True)
self.conv2 = nn.Conv2d(cexp, cexp, kernel_size=k, stride=s, padding=k//2, groups=cexp, bias=False)
self.bn2 = nn.BatchNorm2d(cexp)
self.act2 = hswish() if act=='H' else nn.ReLU(inplace=True)
self.conv3 = nn.Conv2d(cexp, c2, kernel_size=1, stride=1, padding=0, bias=False)
self.bn3 = nn.BatchNorm2d(c2)

self.shortcut = nn.Sequential()
if s == 1 and c1 != c2:
self.shortcut = nn.Sequential(
nn.Conv2d(c1, c2, kernel_size=1, stride=1, padding=0, bias=False),
nn.BatchNorm2d(c2))

def forward(self, x):
out = self.act1(self.bn1(self.conv1(x)))
out = self.act2(self.bn2(self.conv2(out)))
out = self.bn3(self.conv3(out))
if self.se:
out = self.sem(out)
out = out + self.shortcut(x) if self.stride==1 else out
return out

* parameter 變化量

原始的 Yolov4_S:

原始的 Yolov4_L:

修改後的 Yolov4_MobileNet_v2:

修改後的 Yolov4_MobileNet_v3_small:

修改後的 Yolov4_MobileNet_v3_large:

* 測試結果

--

--

Responses (1)