snr_bias / code /models /LPPNL.py
cangyeone's picture
Upload GRL reproducibility package
7170296 verified
Raw
History Blame Contribute Delete
5.12 kB
import torch
import torch.nn as nn
import torch.nn.functional as F
from torch.quantization import QuantStub, DeQuantStub, fuse_modules
class ConvBNReLU(nn.Sequential):
"""
三个层在计算过程中应当进行融合
使用ReLU作为激活函数可以限制
数值范围,从而有利于量化处理。
"""
def __init__(self, n_in, n_out,
kernel_size=3, stride=1,
groups=1, norm_layer=nn.BatchNorm2d):
# padding为same时两边添加(K-1)/2个0
padding = (kernel_size - 1) // 2
# 本层构建三个层,即0:卷积,1:批标准化,2:ReLU
super(ConvBNReLU, self).__init__(
nn.Conv2d(n_in, n_out, [1, kernel_size],
stride, [0, padding], groups=groups,
bias=False),
nn.BatchNorm2d(n_out),
nn.ReLU(inplace=True)
)
class QInvertedResidual(nn.Module):
"""
本个模块为MobileNetV2中的可分离卷积层
中间带有扩张部分,如图10-2所示
"""
def __init__(self, n_in, n_out,
stride, expand_ratio, norm_layer=nn.BatchNorm2d):
super().__init__()
self.stride = stride
self.conv = ConvBNReLU(n_in, n_out, 5, stride=stride)
if n_in == n_out and stride==1:
self.use_res = True
else:
self.use_res = False
def forward(self, x):
if self.use_res:
return x + self.conv(x)
else:
return self.conv(x)
class ConvTBNReLU(nn.Sequential):
"""
三个层在计算过程中应当进行融合
使用ReLU作为激活函数可以限制
数值范围,从而有利于量化处理。
"""
def __init__(self, n_in, n_out,
kernel_size=3, stride=1, padding=1, output_padding=1, bias=True, dilation=1,
groups=1, norm_layer=nn.BatchNorm2d):
# padding为same时两边添加(K-1)/2个0
# 本层构建三个层,即0:卷积,1:批标准化,2:ReLU
super(ConvTBNReLU, self).__init__(
nn.UpsamplingNearest2d(scale_factor=tuple(stride)),
QInvertedResidual(n_in, n_out, 1, 2),
)
class Model(nn.Module):
def __init__(self, n_stride=8):
super().__init__()
self.n_stride = n_stride # 总步长
F = 16
self.layers = nn.Sequential(
ConvBNReLU(3, F*2**0),
QInvertedResidual(F*2**0, F*2**1, 2, 2),
QInvertedResidual(F*2**1, F*2**1, 1, 2),
QInvertedResidual(F*2**1, F*2**2, 2, 2),
QInvertedResidual(F*2**2, F*2**2, 1, 2),
QInvertedResidual(F*2**2, F*2**3, 2, 2),
QInvertedResidual(F*2**3, F*2**3, 1, 2)
)
self.class_encoder = nn.Sequential(
QInvertedResidual(F*2**3, F*2**3, 2, 2),
QInvertedResidual(F*2**3, F*2**3, 2, 2),
QInvertedResidual(F*2**3, F*2**3, 2, 2),
ConvTBNReLU(F*2**3, F*2**3, [1, 5], stride=[1, 2], padding=[
0, 2], output_padding=[0, 1], bias=False, dilation=1),
ConvTBNReLU(F*2**3, F*2**3, [1, 5], stride=[1, 2], padding=[
0, 2], output_padding=[0, 1], bias=False, dilation=1),
ConvTBNReLU(F*2**3, F*2**3, [1, 5], stride=[1, 2], padding=[
0, 2], output_padding=[0, 1], bias=False, dilation=1),
)
self.cl = nn.Conv2d(F * 2 ** 3 * 2, 3, 1)
self.tm = nn.Conv2d(F * 2 ** 3 * 2, 1, 1)
self.quant = torch.quantization.QuantStub()
self.dequant = torch.quantization.DeQuantStub()
self.qfunc = nn.quantized.FloatFunctional()
def fuse_model(self):
for m in self.modules():
if type(m) == ConvBNReLU:
fuse_modules(m, ['0', '1', '2'], inplace=True)
#if type(m) == ConvTBNReLU:
# fuse_modules(m, ['1', '2', '3'], inplace=True)
#if type(m) == QInvertedResidual:
# m.fuse_model()
def forward(self, x):
x = x.unsqueeze(2)
x1 = self.layers(x)
x2 = self.class_encoder(x1)
x = torch.cat([x1, x2], dim=1)
out_class = self.cl(x).squeeze(dim=2)
out_time = self.tm(x)
out_time = out_time.sigmoid().squeeze() * self.n_stride
if self.training:
return out_class, out_time
else:
out_class = F.softmax(out_class, dim=1)
return out_class, out_time
class Loss(nn.Module):
"""损失函数"""
def __init__(self):
super().__init__()
self.mse = nn.MSELoss(reduction="none")
# 加权
self.ce = nn.CrossEntropyLoss(reduction="sum", ignore_index=-1)
def forward(self, pred, label):
pclass, ptime = pred
dclass = label[:, 0, :].long()
dtime = label[:, 1, :].float()
loss_class = self.ce(pclass, dclass)
loss_time_none = self.mse(ptime, dtime) * (dclass).clamp(0, 1).float()
loss_time = loss_time_none.sum()
loss = loss_class + loss_time / 10
return loss