Polyp_Detection / model.py
Harshith Reddy
Multi-model support: config paths, lazy load by name, query param validation, response model field
07a087d
Raw
History Blame Contribute Delete
5.87 kB
import torch
import torch.nn as nn
from resnet import resnet50
import numpy as np
import cv2
def save_feats_mean(x, size=(256, 256)):
b, c, h, w = x.shape
with torch.no_grad():
x = x.detach().cpu().numpy()
x = np.transpose(x[0], (1, 2, 0))
x = np.mean(x, axis=-1)
x = x/np.max(x)
x = x * 255.0
x = x.astype(np.uint8)
if h != size[1]:
x = cv2.resize(x, size)
x = cv2.applyColorMap(x, cv2.COLORMAP_JET)
x = np.array(x, dtype=np.uint8)
return x
def get_mean_attention_map(x):
x = torch.mean(x, axis=1)
x = torch.unsqueeze(x, 1)
x = x / torch.max(x)
return x
class ResidualBlock(nn.Module):
def __init__(self, in_c, out_c):
super().__init__()
self.relu = nn.ReLU()
self.conv = nn.Sequential(
nn.Conv2d(in_c, out_c, kernel_size=3, padding=1),
nn.BatchNorm2d(out_c),
nn.ReLU(),
nn.Conv2d(out_c, out_c, kernel_size=3, padding=1),
nn.BatchNorm2d(out_c)
)
self.shortcut = nn.Sequential(
nn.Conv2d(in_c, out_c, kernel_size=1, padding=0),
nn.BatchNorm2d(out_c)
)
def forward(self, inputs):
x1 = self.conv(inputs)
x2 = self.shortcut(inputs)
x = self.relu(x1 + x2)
return x
class DilatedConv(nn.Module):
def __init__(self, in_c, out_c):
super().__init__()
self.c1 = nn.Sequential(
nn.Conv2d(in_c, out_c, kernel_size=3, padding=1, dilation=1),
nn.BatchNorm2d(out_c),
nn.ReLU()
)
self.c2 = nn.Sequential(
nn.Conv2d(in_c, out_c, kernel_size=3, padding=3, dilation=3),
nn.BatchNorm2d(out_c),
nn.ReLU()
)
self.c3 = nn.Sequential(
nn.Conv2d(in_c, out_c, kernel_size=3, padding=6, dilation=6),
nn.BatchNorm2d(out_c),
nn.ReLU()
)
self.c4 = nn.Sequential(
nn.Conv2d(in_c, out_c, kernel_size=3, padding=9, dilation=9),
nn.BatchNorm2d(out_c),
nn.ReLU()
)
self.c5 = nn.Sequential(
nn.Conv2d(out_c*4, out_c, kernel_size=1, padding=0),
nn.BatchNorm2d(out_c),
nn.ReLU()
)
def forward(self, inputs):
x1 = self.c1(inputs)
x2 = self.c2(inputs)
x3 = self.c3(inputs)
x4 = self.c4(inputs)
x = torch.cat([x1, x2, x3, x4], axis=1)
x = self.c5(x)
return x
class ChannelAttention(nn.Module):
def __init__(self, in_planes, ratio=16):
super(ChannelAttention, self).__init__()
self.avg_pool = nn.AdaptiveAvgPool2d(1)
self.max_pool = nn.AdaptiveMaxPool2d(1)
self.fc1 = nn.Conv2d(in_planes, in_planes // 16, 1, bias=False)
self.relu1 = nn.ReLU()
self.fc2 = nn.Conv2d(in_planes // 16, in_planes, 1, bias=False)
self.sigmoid = nn.Sigmoid()
def forward(self, x):
x0 = x
avg_out = self.fc2(self.relu1(self.fc1(self.avg_pool(x))))
max_out = self.fc2(self.relu1(self.fc1(self.max_pool(x))))
out = avg_out + max_out
return x0 * self.sigmoid(out)
class SpatialAttention(nn.Module):
def __init__(self, kernel_size=7):
super(SpatialAttention, self).__init__()
assert kernel_size in (3, 7), 'kernel size must be 3 or 7'
padding = 3 if kernel_size == 7 else 1
self.conv1 = nn.Conv2d(2, 1, kernel_size, padding=padding, bias=False)
self.sigmoid = nn.Sigmoid()
def forward(self, x):
x0 = x
avg_out = torch.mean(x, dim=1, keepdim=True)
max_out, _ = torch.max(x, dim=1, keepdim=True)
x = torch.cat([avg_out, max_out], dim=1)
x = self.conv1(x)
return x0 * self.sigmoid(x)
class DecoderBlock(nn.Module):
def __init__(self, in_c, out_c):
super().__init__()
self.up = nn.Upsample(scale_factor=2, mode="bilinear", align_corners=True)
self.r1 = ResidualBlock(in_c[0]+in_c[1], out_c)
self.r2 = ResidualBlock(out_c, out_c)
self.ca = ChannelAttention(out_c)
self.sa = SpatialAttention()
def forward(self, x, s):
x = self.up(x)
x = torch.cat([x, s], axis=1)
x = self.r1(x)
x = self.r2(x)
x = self.ca(x)
x = self.sa(x)
return x
class RUPNet(nn.Module):
def __init__(self):
super().__init__()
backbone = resnet50(pretrained=False)
self.layer0 = nn.Sequential(backbone.conv1, backbone.bn1, backbone.relu)
self.layer1 = nn.Sequential(backbone.maxpool, backbone.layer1)
self.layer2 = backbone.layer2
self.layer3 = backbone.layer3
self.r1 = nn.Sequential(DilatedConv(64, 64), nn.MaxPool2d((8, 8)))
self.r2 = nn.Sequential(DilatedConv(256, 64), nn.MaxPool2d((4, 4)))
self.r3 = nn.Sequential(DilatedConv(512, 64), nn.MaxPool2d((2, 2)))
self.r4 = DilatedConv(1024, 64)
self.d1 = DecoderBlock([256, 512], 256)
self.d2 = DecoderBlock([256, 256], 128)
self.d3 = DecoderBlock([128, 64], 64)
self.d4 = DecoderBlock([64, 3], 32)
self.y = nn.Conv2d(32, 1, kernel_size=1, padding=0)
def forward(self, x, heatmap=None):
s0 = x
s1 = self.layer0(s0)
s2 = self.layer1(s1)
s3 = self.layer2(s2)
s4 = self.layer3(s3)
r1 = self.r1(s1)
r2 = self.r2(s2)
r3 = self.r3(s3)
r4 = self.r4(s4)
rx = torch.cat([r1, r2, r3, r4], axis=1)
d1 = self.d1(rx, s3)
d2 = self.d2(d1, s2)
d3 = self.d3(d2, s1)
d4 = self.d4(d3, s0)
y = self.y(d4)
if heatmap is not None:
hmap = save_feats_mean(d4)
return hmap, y
else:
return y