blanchon's picture
Update
3ed0796
# Ultralytics YOLO πŸš€, AGPL-3.0 license
"""
Convolution modules
"""
import math
import numpy as np
import torch
import torch.nn as nn
__all__ = ('Conv', 'LightConv', 'DWConv', 'DWConvTranspose2d', 'ConvTranspose', 'Focus', 'GhostConv',
'ChannelAttention', 'SpatialAttention', 'CBAM', 'Concat', 'RepConv')
def autopad(k, p=None, d=1): # kernel, padding, dilation
"""Pad to 'same' shape outputs."""
if d > 1:
k = d * (k - 1) + 1 if isinstance(k, int) else [d * (x - 1) + 1 for x in k] # actual kernel-size
if p is None:
p = k // 2 if isinstance(k, int) else [x // 2 for x in k] # auto-pad
return p
# Pavlo's implementation with switch to deploy
class Conv(nn.Module):
default_act = nn.SiLU() # default activation
def __init__(self, a, b, kernel_size=1, stride=1, padding=None, g=1, dilation=1, bn_weight_init=1, bias=False, act=True):
super().__init__()
self.conv = torch.nn.Conv2d(a, b, kernel_size, stride, autopad(kernel_size, padding, dilation), dilation, g, bias=False)
if 1:
self.bn = torch.nn.BatchNorm2d(b)
torch.nn.init.constant_(self.bn.weight, bn_weight_init)
torch.nn.init.constant_(self.bn.bias, 0)
self.act = self.default_act if act is True else act if isinstance(act, nn.Module) else nn.Identity()
def forward(self,x):
x = self.conv(x)
x = self.bn(x)
x = self.act(x)
return x
@torch.no_grad()
def switch_to_deploy(self):
if not isinstance(self.bn, nn.Identity):
# return 1
c, bn = self.conv, self.bn
w = bn.weight / (bn.running_var + bn.eps) ** 0.5
w = c.weight * w[:, None, None, None]
b = bn.bias - bn.running_mean * bn.weight / \
(bn.running_var + bn.eps)**0.5
# m = torch.nn.Conv2d(w.size(1) * c.groups,
# w.size(0),
# w.shape[2:],
# stride=c.stride,
# padding=c.padding,
# dilation=c.dilation,
# groups=c.groups)
self.conv.weight.data.copy_(w)
self.conv.bias = nn.Parameter(b)
# self.conv.bias.data.copy_(b)
# self.conv = m.to(c.weight.device)
self.bn = nn.Identity()