DL-Art-School/codes/models/archs/ChainedEmbeddingGen.py

188 lines
10 KiB
Python
Raw Normal View History

2020-10-21 17:07:45 +00:00
import os
2020-10-16 05:18:08 +00:00
import torch
2020-10-21 17:07:45 +00:00
import torchvision
2020-10-16 05:18:08 +00:00
from torch import nn
2020-10-17 02:44:36 +00:00
from models.archs.SPSR_arch import ImageGradientNoPadding
2020-10-16 05:18:08 +00:00
from models.archs.arch_util import ConvGnLelu, ExpansionBlock2, ConvGnSilu, ConjoinBlock, MultiConvBlock, \
2020-10-17 14:40:28 +00:00
FinalUpsampleBlock2x, ReferenceJoinBlock
2020-10-16 05:18:08 +00:00
from models.archs.spinenet_arch import SpineNet
from utils.util import checkpoint
class BasicEmbeddingPyramid(nn.Module):
def __init__(self, use_norms=True):
super(BasicEmbeddingPyramid, self).__init__()
self.initial_process = ConvGnLelu(64, 64, kernel_size=1, bias=True, activation=True, norm=False)
self.reducers = nn.ModuleList([ConvGnLelu(64, 128, stride=2, kernel_size=1, bias=False, activation=True, norm=False),
ConvGnLelu(128, 128, kernel_size=3, bias=False, activation=True, norm=use_norms),
ConvGnLelu(128, 256, stride=2, kernel_size=1, bias=False, activation=True, norm=False),
ConvGnLelu(256, 256, kernel_size=3, bias=False, activation=True, norm=use_norms)])
self.expanders = nn.ModuleList([ExpansionBlock2(256, 128, block=ConvGnLelu),
ExpansionBlock2(128, 64, block=ConvGnLelu)])
self.embedding_processor1 = ConvGnSilu(256, 128, kernel_size=1, bias=True, activation=True, norm=False)
self.embedding_joiner1 = ConjoinBlock(128, block=ConvGnLelu, norm=use_norms)
self.embedding_processor2 = ConvGnSilu(256, 256, kernel_size=1, bias=True, activation=True, norm=False)
self.embedding_joiner2 = ConjoinBlock(256, block=ConvGnLelu, norm=use_norms)
self.final_process = nn.Sequential(ConvGnLelu(128, 96, kernel_size=1, bias=False, activation=False, norm=False,
weight_init_factor=.1),
ConvGnLelu(96, 64, kernel_size=1, bias=False, activation=False, norm=False,
weight_init_factor=.1),
ConvGnLelu(64, 64, kernel_size=1, bias=False, activation=False, norm=False,
weight_init_factor=.1),
ConvGnLelu(64, 64, kernel_size=1, bias=False, activation=False, norm=False,
weight_init_factor=.1))
def forward(self, x, *embeddings):
p = self.initial_process(x)
identities = []
for i in range(2):
identities.append(p)
p = self.reducers[i*2](p)
p = self.reducers[i*2+1](p)
if i == 0:
p = self.embedding_joiner1(p, self.embedding_processor1(embeddings[0]))
elif i == 1:
p = self.embedding_joiner2(p, self.embedding_processor2(embeddings[1]))
for i in range(2):
p = self.expanders[i](p, identities[-(i+1)])
x = self.final_process(torch.cat([x, p], dim=1))
2020-10-21 17:07:45 +00:00
return x, p
2020-10-16 05:18:08 +00:00
class ChainedEmbeddingGen(nn.Module):
2020-10-17 02:44:36 +00:00
def __init__(self, depth=10):
2020-10-16 05:18:08 +00:00
super(ChainedEmbeddingGen, self).__init__()
self.initial_conv = ConvGnLelu(3, 64, kernel_size=7, bias=True, norm=False, activation=False)
self.spine = SpineNet(arch='49', output_level=[3, 4], double_reduce_early=False)
2020-10-17 02:44:36 +00:00
self.blocks = nn.ModuleList([BasicEmbeddingPyramid() for i in range(depth)])
2020-10-16 05:18:08 +00:00
self.upsample = FinalUpsampleBlock2x(64)
def forward(self, x):
fea = self.initial_conv(x)
emb = checkpoint(self.spine, fea)
2020-10-16 05:18:08 +00:00
for block in self.blocks:
2020-10-21 17:07:45 +00:00
fea = fea + checkpoint(block, fea, *emb)[0]
2020-10-16 05:18:08 +00:00
return checkpoint(self.upsample, fea),
2020-10-17 02:44:36 +00:00
class ChainedEmbeddingGenWithStructure(nn.Module):
2020-10-18 04:54:12 +00:00
def __init__(self, depth=10, recurrent=False, recurrent_nf=3, recurrent_stride=2):
2020-10-17 02:44:36 +00:00
super(ChainedEmbeddingGenWithStructure, self).__init__()
self.recurrent = recurrent
2020-10-17 14:40:28 +00:00
self.initial_conv = ConvGnLelu(3, 64, kernel_size=7, bias=True, norm=False, activation=False)
if recurrent:
self.recurrent_nf = recurrent_nf
self.recurrent_stride = recurrent_stride
2020-10-18 04:54:12 +00:00
self.recurrent_process = ConvGnLelu(recurrent_nf, 64, kernel_size=3, stride=recurrent_stride, norm=False, bias=True, activation=False)
2020-10-17 14:40:28 +00:00
self.recurrent_join = ReferenceJoinBlock(64, residual_weight_init_factor=.01, final_norm=False, kernel_size=1, depth=3, join=False)
2020-10-17 02:44:36 +00:00
self.spine = SpineNet(arch='49', output_level=[3, 4], double_reduce_early=False)
self.blocks = nn.ModuleList([BasicEmbeddingPyramid() for i in range(depth)])
self.structure_joins = nn.ModuleList([ConjoinBlock(64) for i in range(3)])
self.structure_blocks = nn.ModuleList([ConvGnLelu(64, 64, kernel_size=3, bias=False, norm=False, activation=False, weight_init_factor=.1) for i in range(3)])
self.structure_upsample = FinalUpsampleBlock2x(64)
self.grad_extract = ImageGradientNoPadding()
self.upsample = FinalUpsampleBlock2x(64)
2020-10-18 04:54:12 +00:00
self.ref_join_std = 0
2020-10-17 02:44:36 +00:00
2020-10-17 14:35:46 +00:00
def forward(self, x, recurrent=None):
2020-10-17 14:40:28 +00:00
fea = self.initial_conv(x)
if self.recurrent:
2020-10-18 04:54:12 +00:00
if recurrent is None:
if self.recurrent_nf == 3:
recurrent = torch.zeros_like(x)
if self.recurrent_stride != 1:
recurrent = torch.nn.functional.interpolate(recurrent, scale_factor=self.recurrent_stride, mode='nearest')
else:
recurrent = torch.zeros_like(fea)
2020-10-17 14:40:28 +00:00
rec = self.recurrent_process(recurrent)
2020-10-18 04:54:12 +00:00
fea, recstd = self.recurrent_join(fea, rec)
self.ref_join_std = recstd.item()
emb = checkpoint(self.spine, fea)
2020-10-17 02:44:36 +00:00
grad = fea
for i, block in enumerate(self.blocks):
2020-10-21 17:07:45 +00:00
fea = fea + checkpoint(block, fea, *emb)[0]
2020-10-17 02:44:36 +00:00
if i < 3:
structure_br = checkpoint(self.structure_joins[i], grad, fea)
grad = grad + checkpoint(self.structure_blocks[i], structure_br)
out = checkpoint(self.upsample, fea)
2020-10-18 04:54:12 +00:00
return out, self.grad_extract(checkpoint(self.structure_upsample, grad)), self.grad_extract(out), fea
def get_debug_values(self, step, net_name):
return { 'ref_join_std': self.ref_join_std }
2020-10-21 17:07:45 +00:00
# This is a structural block that learns to mute regions of a residual transformation given a signal.
class OptionalPassthroughBlock(nn.Module):
def __init__(self, nf, initial_bias=10):
super(OptionalPassthroughBlock, self).__init__()
self.switch_process = nn.Sequential(ConvGnLelu(nf, nf // 2, 1, activation=False, norm=False, bias=False),
ConvGnLelu(nf // 2, nf // 4, 1, activation=False, norm=False, bias=False),
ConvGnLelu(nf // 4, 1, 1, activation=False, norm=False, bias=False))
self.bias = nn.Parameter(torch.tensor(initial_bias, dtype=torch.float), requires_grad=True)
self.activation = nn.Sigmoid()
def forward(self, x, switch_signal):
switch = self.switch_process(switch_signal)
bypass_map = self.activation(self.bias + switch)
return x * bypass_map, bypass_map
class StructuredChainedEmbeddingGenWithBypass(nn.Module):
def __init__(self, depth=10, recurrent=False, recurrent_nf=3, recurrent_stride=2, bypass_bias=10):
super(StructuredChainedEmbeddingGenWithBypass, self).__init__()
self.recurrent = recurrent
self.initial_conv = ConvGnLelu(3, 64, kernel_size=7, bias=True, norm=False, activation=False)
if recurrent:
self.recurrent_nf = recurrent_nf
self.recurrent_stride = recurrent_stride
self.recurrent_process = ConvGnLelu(recurrent_nf, 64, kernel_size=3, stride=recurrent_stride, norm=False, bias=True, activation=False)
self.recurrent_join = ReferenceJoinBlock(64, residual_weight_init_factor=.01, final_norm=False, kernel_size=1, depth=3, join=False)
self.spine = SpineNet(arch='49', output_level=[3, 4], double_reduce_early=False)
self.blocks = nn.ModuleList([BasicEmbeddingPyramid() for i in range(depth)])
self.bypasses = nn.ModuleList([OptionalPassthroughBlock(64, initial_bias=bypass_bias) for i in range(depth)])
self.structure_joins = nn.ModuleList([ConjoinBlock(64) for i in range(3)])
self.structure_blocks = nn.ModuleList([ConvGnLelu(64, 64, kernel_size=3, bias=False, norm=False, activation=False, weight_init_factor=.1) for i in range(3)])
self.structure_upsample = FinalUpsampleBlock2x(64)
self.grad_extract = ImageGradientNoPadding()
self.upsample = FinalUpsampleBlock2x(64)
self.ref_join_std = 0
self.bypass_maps = []
def forward(self, x, recurrent=None):
fea = self.initial_conv(x)
if self.recurrent:
if recurrent is None:
if self.recurrent_nf == 3:
recurrent = torch.zeros_like(x)
if self.recurrent_stride != 1:
recurrent = torch.nn.functional.interpolate(recurrent, scale_factor=self.recurrent_stride, mode='nearest')
else:
recurrent = torch.zeros_like(fea)
rec = self.recurrent_process(recurrent)
fea, recstd = self.recurrent_join(fea, rec)
self.ref_join_std = recstd.item()
emb = checkpoint(self.spine, fea)
grad = fea
self.bypass_maps = []
for i, block in enumerate(self.blocks):
residual, context = checkpoint(block, fea, *emb)
residual, bypass_map = checkpoint(self.bypasses[i], residual, context)
fea = fea + residual
self.bypass_maps.append(bypass_map.detach())
if i < 3:
structure_br = checkpoint(self.structure_joins[i], grad, fea)
grad = grad + checkpoint(self.structure_blocks[i], structure_br)
out = checkpoint(self.upsample, fea)
return out, self.grad_extract(checkpoint(self.structure_upsample, grad)), self.grad_extract(out), fea
def visual_dbg(self, step, path):
for i, bm in enumerate(self.bypass_maps):
torchvision.utils.save_image(bm.cpu(), os.path.join(path, "%i_bypass_%i.png" % (step, i+1)))
def get_debug_values(self, step, net_name):
biases = [b.bias.item() for b in self.bypasses]
return { 'ref_join_std': self.ref_join_std, 'bypass_biases': sum(biases) / len(biases) }