snr_bias / code /models /LPPNT.py
cangyeone's picture
Upload GRL reproducibility package
7170296 verified
Raw
History Blame Contribute Delete
6.67 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 InvertedResidual(nn.Module):
"""
本个模块为MobileNetV2中的可分离卷积层
中间带有扩张部分,如图10-2所示
"""
def __init__(self, n_in, n_out,
stride, expand_ratio, norm_layer=nn.BatchNorm2d):
super().__init__()
self.stride = stride
# 隐藏层需要进行特征拓张,以防止信息损失
hidden_dim = int(round(n_in * expand_ratio))
# 当输出和输出维度相同时,使用残差结构
self.use_res = self.stride == 1 and n_in == n_out
# 构建多层
layers = []
if expand_ratio != 1:
# 逐点卷积,增加通道数
layers.append(
ConvBNReLU(n_in, hidden_dim, kernel_size=1,
norm_layer=norm_layer))
layers.extend([
# 逐层卷积,提取特征。当groups=输入通道数时为逐层卷积
ConvBNReLU(
hidden_dim, hidden_dim,
stride=stride, groups=hidden_dim, norm_layer=norm_layer),
# 逐点卷积,本层不加激活函数
nn.Conv2d(hidden_dim, n_out, 1, 1, 0, bias=False),
nn.BatchNorm2d(n_out),
])
# 定义多个层
self.conv = nn.Sequential(*layers)
def forward(self, x):
if self.use_res:
return x + self.conv(x)
else:
return self.conv(x)
class QInvertedResidual(InvertedResidual):
"""量化模型修改"""
def __init__(self, *args, **kwargs):
super(QInvertedResidual, self).__init__(*args, **kwargs)
# 量化模型应当使用量化计算方法
self.skip_add = nn.quantized.FloatFunctional()
def forward(self, x):
if self.use_res:
# 量化加法
#return self.skip_add.add(x, self.conv(x))
return x + self.conv(x)
else:
return self.conv(x)
def fuse_model(self):
# 模型融合
for idx in range(len(self.conv)):
if type(self.conv[idx]) == nn.Conv2d:
# 将本个模块最后的卷积层和BN层融合
fuse_modules(
self.conv,
[str(idx), str(idx + 1)], inplace=True)
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 = 4
self.layers = nn.Sequential(
ConvBNReLU(3, F*1),
QInvertedResidual(F*1, F*2, 2, 2),
QInvertedResidual(F*2, F*2, 1, 2),
QInvertedResidual(F*2, F*3, 2, 2),
QInvertedResidual(F*3, F*3, 1, 2),
QInvertedResidual(F*3, F*4, 2, 2),
QInvertedResidual(F*4, F*4, 1, 2)
)
self.class_encoder = nn.Sequential(
QInvertedResidual(F*4, F*4, 2, 2),
QInvertedResidual(F*4, F*4, 2, 2),
QInvertedResidual(F*4, F*4, 2, 2),
ConvTBNReLU(F*4, F*4, [1, 5], stride=[1, 2], padding=[
0, 2], output_padding=[0, 1], bias=False, dilation=1),
ConvTBNReLU(F*4, F*4, [1, 5], stride=[1, 2], padding=[
0, 2], output_padding=[0, 1], bias=False, dilation=1),
ConvTBNReLU(F*4, F*4, [1, 5], stride=[1, 2], padding=[
0, 2], output_padding=[0, 1], bias=False, dilation=1),
)
self.cl = nn.Conv2d(F * 4 * 2, 3, 1)
self.tm = nn.Conv2d(F * 4 * 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