SuperResolution / model.py
ckyrkou's picture
Upload 2 files
2dfda0f verified
Raw
History Blame Contribute Delete
25.6 kB
import torch
import torch.nn as nn
import torch.nn.init as init
import math
def pixact(x):
return (torch.tanh(x) + 1) / 2
#return x.sigmoid()
# class Net(nn.Module):
# def __init__(self, upscale_factor):
# super(Net, self).__init__()
#
# self.relu = nn.ReLU()
# self.conv1 = nn.Conv2d(3, 64, (5, 5), (1, 1), (2, 2))
# self.conv2 = nn.Conv2d(64, 64, (3, 3), (1, 1), (1, 1))
# self.conv3 = nn.Conv2d(64, 32, (3, 3), (1, 1), (1, 1))
# self.conv4 = nn.Conv2d(32, upscale_factor ** 2, (3, 3), (1, 1), (1, 1))
# self.pixel_shuffle = nn.PixelShuffle(upscale_factor)
#
# self._initialize_weights()
#
# def forward(self, x):
# x = self.relu(self.conv1(x))
# x = self.relu(self.conv2(x))
# x = self.relu(self.conv3(x))
# x = self.pixel_shuffle(self.conv4(x))
# return x
#
# def _initialize_weights(self):
# init.orthogonal_(self.conv1.weight, init.calculate_gain('relu'))
# init.orthogonal_(self.conv2.weight, init.calculate_gain('relu'))
# init.orthogonal_(self.conv3.weight, init.calculate_gain('relu'))
# init.orthogonal_(self.conv4.weight)
# class Net(nn.Module):
# def __init__(self, upscale_factor=1):
# super(Net, self).__init__()
#
# self.relu = nn.ReLU()
# self.conv1 = nn.Conv2d(3, 64, (5, 5), (1, 1), (2, 2))
# self.conv2 = nn.Conv2d(64, 64, (3, 3), (1, 1), (1, 1))
# self.conv3 = nn.Conv2d(64, 32, (3, 3), (1, 1), (1, 1))
# self.conv4 = nn.Conv2d(32, 3, (3, 3), (1, 1), (1, 1))
# #self.pixel_shuffle = nn.PixelShuffle(upscale_factor)
# self.upsample = nn.Upsample(scale_factor=2, mode='nearest')
#
# self._initialize_weights()
#
# def forward(self, x):
# x = self.relu(self.conv1(x))
# x = self.relu(self.conv2(x))
# x = self.upsample(self.relu(self.conv3(x)))
# x = self.relu(self.conv4(x))
# return x
#
# def _initialize_weights(self):
# init.orthogonal_(self.conv1.weight, init.calculate_gain('relu'))
# init.orthogonal_(self.conv2.weight, init.calculate_gain('relu'))
# init.orthogonal_(self.conv3.weight, init.calculate_gain('relu'))
# init.orthogonal_(self.conv4.weight)
# class Net(nn.Module):
# def __init__(self, upscale_factor=1):
# super(Net, self).__init__()
#
# self.relu = nn.ReLU()
# self.conv1 = nn.Conv2d(3, 64, (5, 5), (1, 1), (2, 2))
# self.conv2 = nn.Conv2d(64, 64, (3, 3), (1, 1), (1, 1))
# self.conv3 = nn.Conv2d(64, 128, (3, 3), (1, 1), (1, 1))
# self.conv4 = nn.Conv2d(128, 64, (3, 3), (1, 1), (1, 1))
# self.conv5 = nn.Conv2d(64, 32, (3, 3), (1, 1), (1, 1))
# self.conv6 = nn.Conv2d(32, 3, (3, 3), (1, 1), (1, 1))
# #self.pixel_shuffle = nn.PixelShuffle(upscale_factor)
# self.upsample = nn.Upsample(scale_factor=2, mode='nearest')
#
# self._initialize_weights()
#
#
# def forward(self, x):
# x = self.relu(self.conv1(x))
# x = self.relu(self.conv2(x))
# x = self.upsample(self.relu(self.conv3(x)))
# x = self.relu(self.conv4(x))
# x = self.upsample(self.relu(self.conv5(x)))
# x = self.relu(self.conv6(x))
# return x
#
# def _initialize_weights(self):
# init.orthogonal_(self.conv1.weight, init.calculate_gain('relu'))
# init.orthogonal_(self.conv2.weight, init.calculate_gain('relu'))
# init.orthogonal_(self.conv3.weight, init.calculate_gain('relu'))
# init.orthogonal_(self.conv4.weight, init.calculate_gain('relu'))
# init.orthogonal_(self.conv5.weight, init.calculate_gain('relu'))
# init.orthogonal_(self.conv6.weight, init.calculate_gain('relu'))
class ResidualBlockG(nn.Module):
def __init__(self, channels):
super(ResidualBlockG, self).__init__()
self.conv1 = dws_block(channels, channels, kernel_size=3, padding=1)
self.bn1 = nn.InstanceNorm2d(channels)
self.relu = nn.ReLU()
self.conv2 = dws_block(channels, channels, kernel_size=3, padding=1)
self.bn2 = nn.InstanceNorm2d(channels)
def forward(self, x):
residual = self.conv1(x)
residual = self.bn1(residual)
residual = self.relu(residual)
residual = self.conv2(residual)
residual = self.bn2(residual)
return x + residual
class UpsampleBlock(nn.Module):
def __init__(self, in_channels, up_scale):
super(UpsampleBlock, self).__init__()
self.conv = nn.Conv2d(in_channels, in_channels * up_scale ** 2,
kernel_size=3, padding=1)
self.pixel_shuffle = nn.PixelShuffle(up_scale)
self.prelu = nn.ReLU()
def forward(self, x):
x = self.conv(x)
x = self.pixel_shuffle(x)
x = self.prelu(x)
return x
class Generator(nn.Module):
def __init__(self, scale_factor):
super(Generator, self).__init__()
upsample_block_num = int(math.log(scale_factor, 2))
self.block1 = nn.Sequential(
nn.Conv2d(3, 64, kernel_size=9, padding=4),
nn.ReLU()
)
self.block2 = ResidualBlockG(64)
self.block3 = ResidualBlockG(64)
self.block4 = ResidualBlockG(64)
self.block5 = ResidualBlockG(64)
self.block6 = ResidualBlockG(64)
self.block7 = nn.Sequential(
nn.Conv2d(64, 64, kernel_size=3, padding=1),
nn.BatchNorm2d(64)
)
block8 = [UpsampleBlock(64, 2) for _ in range(upsample_block_num)]
block8.append(nn.Conv2d(64, 3, kernel_size=9, padding=4))
self.block8 = nn.Sequential(*block8)
def forward(self, x):
block1 = self.block1(x)
block2 = self.block2(block1)
block3 = self.block3(block2)
block4 = self.block4(block3)
block5 = self.block5(block4)
block6 = self.block6(block5)
block7 = self.block7(block6)
block8 = self.block8(block1 + block7)
return block8
class block(nn.Module):
def __init__(self,channels_in,channels_out,kernel,stride,pad):
super(block, self).__init__()
self.conv = nn.Conv2d(channels_in, channels_out, kernel, stride, pad)
self.act = nn.LeakyReLU(0.2)
#self.act = nn.ReLU()
#self.norm = nn.InstanceNorm2d(channels_out)
def forward(self, x):
x = self.conv(x)
#x = self.norm(x)
x = self.act(x)
return x
class SubPixelConvolutionalBlock(nn.Module):
"""
A subpixel convolutional block, comprising convolutional, pixel-shuffle, and PReLU activation layers.
"""
def __init__(self, kernel_size=3, n_channels=64, scaling_factor=2):
"""
:param kernel_size: kernel size of the convolution
:param n_channels: number of input and output channels
:param scaling_factor: factor to scale input images by (along both dimensions)
"""
super(SubPixelConvolutionalBlock, self).__init__()
# A convolutional layer that increases the number of channels by scaling factor^2, followed by pixel shuffle and PReLU
self.conv = nn.Conv2d(in_channels=n_channels, out_channels=n_channels * (scaling_factor ** 2),
kernel_size=kernel_size, padding=kernel_size // 2)
# These additional channels are shuffled to form additional pixels, upscaling each dimension by the scaling factor
self.pixel_shuffle = nn.PixelShuffle(upscale_factor=scaling_factor)
#self.lrelu = nn.ReLU()
self.lrelu = nn.LeakyReLU(0.2)
def forward(self, input):
"""
Forward propagation.
:param input: input images, a tensor of size (N, n_channels, w, h)
:return: scaled output images, a tensor of size (N, n_channels, w * scaling factor, h * scaling factor)
"""
output = self.conv(input) # (N, n_channels * scaling factor^2, w, h)
output = self.pixel_shuffle(output) # (N, n_channels, w * scaling factor, h * scaling factor)
output = self.lrelu(output) # (N, n_channels, w * scaling factor, h * scaling factor)
return output
class Net(nn.Module):
def __init__(self, upscale_factor=1):
super(Net, self).__init__()
self.conv1 = block(3, 64, (7, 7), (1, 1), (3, 3))
self.conv2 = block(64, 64, (5, 5), (1, 1), (2, 2))
self.conv3 = block(64, 128, (5, 5), (1, 1), (2, 2))
self.conv4 = block(128, 256, (5, 5), (1, 1), (2, 2))
self.conv4_1 = block(256, 256, (5, 5), (1, 1), (2, 2))
self.conv5 = block(256, 128, (5, 5), (1, 1), (2, 2))
self.conv6 = block(128, 64, (5, 5), (1, 1), (2, 2))
self.conv7 = block(64, 32, (3, 3), (1, 1), (1, 1))
self.conv7_1 = block(32, 16, (3, 3), (1, 1), (1, 1))
self.conv8 = nn.Conv2d(16, 3, (3, 3), (1, 1), (1, 1))
#self.pixel_shuffle = nn.PixelShuffle(upscale_factor)
#self.relu = nn.ReLU(inplace=True)
#self.upsample = nn.Upsample(scale_factor=2, mode='bicubic')
self.spc1 = SubPixelConvolutionalBlock( kernel_size=3, n_channels=128, scaling_factor=2)
#self.spc1 = nn.Upsample(scale_factor=2, mode='bicubic')
self.spc2 = SubPixelConvolutionalBlock( kernel_size=3, n_channels=128, scaling_factor=2)
#self.spc2 = nn.Upsample(scale_factor=2, mode='bicubic')
self.spc3 = SubPixelConvolutionalBlock(kernel_size=3, n_channels=128, scaling_factor=4)
#self._initialize_weights()
def forward(self, x):
x =self.conv1(x)
x = self.conv2(x)
x = self.conv3(x)
x = self.spc1(x)
x = self.conv4(x)
x = self.conv4_1(x)
x = self.conv5(x)
x = self.spc2(x)
x = self.conv6(x)
x = self.conv7(x)
x = self.conv7_1(x)
x = self.conv8(x)
return x
# def _initialize_weights(self):
# init.orthogonal_(self.conv1.weight, init.calculate_gain('relu'))
# init.orthogonal_(self.conv2.weight, init.calculate_gain('relu'))
# init.orthogonal_(self.conv3.weight, init.calculate_gain('relu'))
# init.orthogonal_(self.conv4.weight, init.calculate_gain('relu'))
# init.orthogonal_(self.conv4_1.weight, init.calculate_gain('relu'))
# init.orthogonal_(self.conv5.weight, init.calculate_gain('relu'))
# init.orthogonal_(self.conv6.weight, init.calculate_gain('relu'))
# init.orthogonal_(self.conv7.weight, init.calculate_gain('relu'))
# init.orthogonal_(self.conv7_1.weight, init.calculate_gain('relu'))
# init.orthogonal_(self.conv8.weight, init.calculate_gain('relu'))
def _initialize_weights(self):
for m in self.modules():
if isinstance(m, nn.Conv2d):
# n = m.kernel_size[0] * m.kernel_size[1] * m.out_channels
# m.weight.data.normal_(0, math.sqrt(2. / n))
# g = nn.init.calculate_gain('leaky_relu', 0.1)
m.weight.data.normal_(0, 0.01)
# nn.init.xavier_normal_(m.weight,gai=g)
if m.bias is not None:
m.bias.data.zero_()
elif isinstance(m, nn.BatchNorm2d) or isinstance(m, nn.InstanceNorm2d):
m.weight.data.fill_(1)
m.bias.data.zero_()
elif isinstance(m, nn.Linear):
m.weight.data.normal_(0, 0.01)
m.bias.data.zero_()
# self.sp.weight.data.normal_(0,0.01)
class dws_block(nn.Module):
def __init__(self, in_channels, out_channels, kernel_size=3, padding=1,stride = 1):
super(dws_block, self).__init__()
self.dc = nn.Conv2d(in_channels, in_channels, kernel_size=kernel_size, padding=padding, groups=in_channels,stride=stride)
self.pc = nn.Conv2d(in_channels, out_channels, kernel_size=1, padding=0)
def forward(self, x):
# Encoder
x = self.dc(x)
x = self.pc(x)
return x
class _Residual_Block(nn.Module):
def __init__(self):
super(_Residual_Block, self).__init__()
self.conv1 = nn.Conv2d(in_channels=64, out_channels=64, kernel_size=3, stride=1, padding=1, bias=False)
self.bn1 = nn.InstanceNorm2d(64)
self.relu = nn.LeakyReLU(0.2, inplace=True)
self.pad2 = nn.ReflectionPad2d(1)
self.conv2 = nn.Conv2d(in_channels=64, out_channels=64, kernel_size=3, stride=1, padding=1, bias=False)
self.bn2 = nn.InstanceNorm2d(64)
def forward(self, x):
identity_data = x
output = self.relu(self.bn1(self.conv1(x)))
output = self.bn2(self.conv2(x))
# add output of the ResBlock with its input with a skip connection
output = torch.add(output, identity_data)
return output
class UpscaleNet(nn.Module):
def __init__(self):
super(UpscaleNet, self).__init__()
# Input is 3 Channels => to 64 channels (kernel size 9 stride 1)
self.conv_input = nn.Conv2d(in_channels=3, out_channels=64, kernel_size=9, stride=1, padding=4, bias=False)
self.relu = nn.LeakyReLU(0.2, inplace=True)
# Running 16 resBlocks
self.residual = self.make_layer(_Residual_Block, 16)
# Position of the Network wise skip connection(transfering spatial information from the low dimension image)
self.conv_mid = nn.Conv2d(in_channels=64, out_channels=64, kernel_size=3, stride=1, padding=1, bias=False)
self.bn_mid = nn.InstanceNorm2d(64)
# Upscale module with PixelShuffle (Fractional Convolution)
self.upscale4x = nn.Sequential(
# using x2 two times to upscale by 4 times
nn.Conv2d(in_channels=64, out_channels=256, kernel_size=3, stride=1, padding=1, bias=False),
nn.PixelShuffle(2),
nn.LeakyReLU(0.2, inplace=True),
nn.Conv2d(in_channels=64, out_channels=256, kernel_size=3, stride=1, padding=1, bias=False),
nn.PixelShuffle(2),
nn.LeakyReLU(0.2, inplace=True),
)
# Final convolution to aleviate artifacts from the upsampling and colapsing channels from 64 to 3
self.conv_output = nn.Conv2d(in_channels=64, out_channels=3, kernel_size=9, stride=1, padding=4, bias=False)
for m in self.modules():
# Initialisation of conv layers
if isinstance(m, nn.Conv2d):
# init.orthogonal(m.weight, math.sqrt(2))
n = m.kernel_size[0] * m.kernel_size[1] * m.out_channels
m.weight.data.normal_(0, math.sqrt(2. / n))
if m.bias is not None:
m.bias.data.zero_()
def make_layer(self, block, num_of_layer):
# Generate the ResBlocks
layers = []
for _ in range(num_of_layer):
layers.append(block())
return nn.Sequential(*layers)
def forward(self, x):
# FeedForward
out = self.relu(self.conv_input(x))
# save input conv for skip connection
residual = out
# Apply ResBlocks
out = self.residual(out)
out = self.bn_mid(self.conv_mid(out))
# Apply skip connection
out = torch.add(out, residual)
# Upsclae
out = self.upscale4x(out)
# Generate output
out = self.conv_output(out)
return out
class UNet(nn.Module):
def __init__(self, in_channels, out_channels):
super(UNet, self).__init__()
# Encoder (contracting path)
self.encoder1 = self.contracting_block(in_channels, 64)
self.encoder2 = self.contracting_block(64, 128)
self.encoder3 = self.contracting_block(128, 256)
self.encoder4 = self.contracting_block(256, 512)
# Bottleneck
self.bottleneck = nn.Sequential(
dws_block(512, 1024, kernel_size=3, padding=1),
nn.ReLU(inplace=True),
dws_block(1024, 1024, kernel_size=3, padding=1),
nn.ReLU(inplace=True)
)
# Decoder (expansive path)
self.decoder1 = self.expansive_block(1024, 512)
self.decoder2 = self.expansive_block(512, 256)
self.decoder3 = self.expansive_block(256, 128)
self.decoder4 = self.expansive_block(128, 64)
self.decoder5 = self.expansive_block(32, 32)
self.decoder6 = self.expansive_block(16, 32)
# Output layer
self.final_conv = nn.Conv2d(16, out_channels, kernel_size=1)
def contracting_block(self, in_channels, out_channels):
return nn.Sequential(
dws_block(in_channels, out_channels, kernel_size=3, padding=1),
nn.ReLU(inplace=True),
dws_block(out_channels, out_channels, kernel_size=3, padding=1),
nn.ReLU(inplace=True),
nn.MaxPool2d(kernel_size=2, stride=2)
)
def expansive_block(self, in_channels, out_channels):
return nn.Sequential(
dws_block(in_channels, out_channels, kernel_size=3, padding=1),
nn.ReLU(inplace=True),
dws_block(out_channels, out_channels, kernel_size=3, padding=1),
nn.ReLU(inplace=True),
nn.ConvTranspose2d(out_channels, out_channels // 2, kernel_size=2, stride=2)
)
def forward(self, x):
# Encoder
enc1 = self.encoder1(x)
enc2 = self.encoder2(enc1)
enc3 = self.encoder3(enc2)
enc4 = self.encoder4(enc3)
# Bottleneck
bottleneck = self.bottleneck(enc4)
# Decoder
dec1 = self.decoder1(bottleneck)
dec2 = self.decoder2(torch.cat([dec1, enc3], dim=1))
dec3 = self.decoder3(torch.cat([dec2, enc2], dim=1))
dec4 = self.decoder4(torch.cat([dec3, enc1], dim=1))
dec5 = self.decoder5(dec4)
dec6 = self.decoder6(dec5)
# Output layer
output = self.final_conv(dec6)
return output
class ConvolutionalBlock(nn.Module):
"""
A convolutional block, comprising convolutional, BN, activation layers.
"""
def __init__(self, in_channels, out_channels, kernel_size, stride=1, batch_norm=False, activation=None):
"""
:param in_channels: number of input channels
:param out_channels: number of output channe;s
:param kernel_size: kernel size
:param stride: stride
:param batch_norm: include a BN layer?
:param activation: Type of activation; None if none
"""
super(ConvolutionalBlock, self).__init__()
if activation is not None:
activation = activation.lower()
assert activation in {'prelu', 'leakyrelu', 'tanh'}
# A container that will hold the layers in this convolutional block
layers = list()
# A convolutional layer
layers.append(
nn.Conv2d(in_channels=in_channels, out_channels=out_channels, kernel_size=kernel_size, stride=stride,
padding=kernel_size // 2))
# A batch normalization (BN) layer, if wanted
if batch_norm is True:
layers.append(nn.BatchNorm2d(num_features=out_channels))
# An activation layer, if wanted
if activation == 'prelu':
layers.append(nn.PReLU())
elif activation == 'leakyrelu':
layers.append(nn.LeakyReLU(0.2))
elif activation == 'tanh':
layers.append(nn.Tanh())
# Put together the convolutional block as a sequence of the layers in this container
self.conv_block = nn.Sequential(*layers)
def forward(self, input):
"""
Forward propagation.
:param input: input images, a tensor of size (N, in_channels, w, h)
:return: output images, a tensor of size (N, out_channels, w, h)
"""
output = self.conv_block(input) # (N, out_channels, w, h)
return output
class ResidualBlock(nn.Module):
"""
A residual block, comprising two convolutional blocks with a residual connection across them.
"""
def __init__(self, kernel_size=3, n_channels=64):
"""
:param kernel_size: kernel size
:param n_channels: number of input and output channels (same because the input must be added to the output)
"""
super(ResidualBlock, self).__init__()
# The first convolutional block
self.conv_block1 = ConvolutionalBlock(in_channels=n_channels, out_channels=n_channels, kernel_size=kernel_size,
batch_norm=True, activation='PReLu')
# The second convolutional block
self.conv_block2 = ConvolutionalBlock(in_channels=n_channels, out_channels=n_channels, kernel_size=kernel_size,
batch_norm=True, activation=None)
def forward(self, input):
"""
Forward propagation.
:param input: input images, a tensor of size (N, n_channels, w, h)
:return: output images, a tensor of size (N, n_channels, w, h)
"""
residual = input # (N, n_channels, w, h)
output = self.conv_block1(input) # (N, n_channels, w, h)
output = self.conv_block2(output) # (N, n_channels, w, h)
output = output + residual # (N, n_channels, w, h)
return output
class SRResNet(nn.Module):
"""
The SRResNet, as defined in the paper.
"""
def __init__(self, large_kernel_size=9, small_kernel_size=3, n_channels=64, n_blocks=16, scaling_factor=4):
"""
:param large_kernel_size: kernel size of the first and last convolutions which transform the inputs and outputs
:param small_kernel_size: kernel size of all convolutions in-between, i.e. those in the residual and subpixel convolutional blocks
:param n_channels: number of channels in-between, i.e. the input and output channels for the residual and subpixel convolutional blocks
:param n_blocks: number of residual blocks
:param scaling_factor: factor to scale input images by (along both dimensions) in the subpixel convolutional block
"""
super(SRResNet, self).__init__()
# Scaling factor must be 2, 4, or 8
scaling_factor = int(scaling_factor)
assert scaling_factor in {2, 4, 8}, "The scaling factor must be 2, 4, or 8!"
# The first convolutional block
self.conv_block1 = ConvolutionalBlock(in_channels=3, out_channels=n_channels, kernel_size=large_kernel_size,
batch_norm=False, activation='PReLu')
# A sequence of n_blocks residual blocks, each containing a skip-connection across the block
self.residual_blocks = nn.Sequential(
*[ResidualBlock(kernel_size=small_kernel_size, n_channels=n_channels) for i in range(n_blocks)])
# Another convolutional block
self.conv_block2 = ConvolutionalBlock(in_channels=n_channels, out_channels=n_channels,
kernel_size=small_kernel_size,
batch_norm=True, activation=None)
# Upscaling is done by sub-pixel convolution, with each such block upscaling by a factor of 2
n_subpixel_convolution_blocks = int(math.log2(scaling_factor))
self.subpixel_convolutional_blocks = nn.Sequential(
*[SubPixelConvolutionalBlock(kernel_size=small_kernel_size, n_channels=n_channels, scaling_factor=2) for i
in range(n_subpixel_convolution_blocks)])
# The last convolutional block
self.conv_block3 = ConvolutionalBlock(in_channels=n_channels, out_channels=3, kernel_size=large_kernel_size,
batch_norm=False, activation='Tanh')
def forward(self, lr_imgs):
"""
Forward prop.
:param lr_imgs: low-resolution input images, a tensor of size (N, 3, w, h)
:return: super-resolution output images, a tensor of size (N, 3, w * scaling factor, h * scaling factor)
"""
output = self.conv_block1(lr_imgs) # (N, 3, w, h)
residual = output # (N, n_channels, w, h)
output = self.residual_blocks(output) # (N, n_channels, w, h)
output = self.conv_block2(output) # (N, n_channels, w, h)
output = output + residual # (N, n_channels, w, h)
output = self.subpixel_convolutional_blocks(output) # (N, n_channels, w * scaling factor, h * scaling factor)
sr_imgs = self.conv_block3(output) # (N, 3, w * scaling factor, h * scaling factor)
return sr_imgs
class Discriminator(nn.Module):
def __init__(self):
super(Discriminator, self).__init__()
self.net = nn.Sequential(
dws_block(3, 64, kernel_size=3, padding=1),
nn.LeakyReLU(0.2),
dws_block(64, 64, kernel_size=3, stride=2, padding=1),
nn.BatchNorm2d(64),
nn.LeakyReLU(0.2),
dws_block(64, 128, kernel_size=3, padding=1),
nn.BatchNorm2d(128),
nn.LeakyReLU(0.2),
dws_block(128, 256, kernel_size=3, padding=1),
nn.BatchNorm2d(256),
nn.LeakyReLU(0.2),
dws_block(256, 256, kernel_size=3, stride=2, padding=1),
nn.BatchNorm2d(256),
nn.LeakyReLU(0.2),
dws_block(256, 512, kernel_size=3, padding=1),
nn.BatchNorm2d(512),
nn.LeakyReLU(0.2),
dws_block(512, 512, kernel_size=3, stride=2, padding=1),
nn.BatchNorm2d(512),
nn.LeakyReLU(0.2),
nn.AdaptiveAvgPool2d(1),
nn.Conv2d(512, 1024, kernel_size=1),
nn.LeakyReLU(0.2),
nn.Conv2d(1024, 1, kernel_size=1)
)
def forward(self, x):
batch_size=x.size()[0]
return torch.sigmoid(self.net(x).view(batch_size))