Files
chaojie-ComfyUI_StreamingT2V/thirdparty/modelscope/models/cv/tinynas_classfication/basic_blocks.py
T
2024-04-08 06:24:30 +08:00

1311 lines
43 KiB
Python

# These codes are copied from modelscope revision c58451baead80d83281f063d12fb377fad415257
# Copyright (c) Alibaba, Inc. and its affiliates.
# The ZenNAS implementation is also open-sourced by the authors, and available at https://github.com/idstcv/ZenNAS.
import uuid
import numpy as np
import torch
import torch.nn.functional as F
from torch import nn
from .global_utils import (create_netblock_list_from_str_inner,
get_right_parentheses_index)
class PlainNetBasicBlockClass(nn.Module):
def __init__(self,
in_channels=None,
out_channels=None,
stride=1,
no_create=False,
block_name=None,
**kwargs):
super(PlainNetBasicBlockClass, self).__init__(**kwargs)
self.in_channels = in_channels
self.out_channels = out_channels
self.stride = stride
self.no_create = no_create
self.block_name = block_name
if self.block_name is None:
self.block_name = 'uuid{}'.format(uuid.uuid4().hex)
def forward(self, x):
raise RuntimeError('Not implemented')
def __str__(self):
return type(self).__name__ + '({},{},{})'.format(
self.in_channels, self.out_channels, self.stride)
def __repr__(self):
return type(self).__name__ + '({}|{},{},{})'.format(
self.block_name, self.in_channels, self.out_channels, self.stride)
def get_output_resolution(self, input_resolution):
raise RuntimeError('Not implemented')
@classmethod
def create_from_str(cls, s, no_create=False, **kwargs):
assert PlainNetBasicBlockClass.is_instance_from_str(s)
idx = get_right_parentheses_index(s)
assert idx is not None
param_str = s[len(cls.__name__ + '('):idx]
tmp_idx = param_str.find('|')
if tmp_idx < 0:
tmp_block_name = 'uuid{}'.format(uuid.uuid4().hex)
else:
tmp_block_name = param_str[0:tmp_idx]
param_str = param_str[tmp_idx + 1:]
param_str_split = param_str.split(',')
in_channels = int(param_str_split[0])
out_channels = int(param_str_split[1])
stride = int(param_str_split[2])
return cls(
in_channels=in_channels,
out_channels=out_channels,
stride=stride,
block_name=tmp_block_name,
no_create=no_create), s[idx + 1:]
@classmethod
def is_instance_from_str(cls, s):
if s.startswith(cls.__name__ + '(') and s[-1] == ')':
return True
else:
return False
class AdaptiveAvgPool(PlainNetBasicBlockClass):
def __init__(self, out_channels, output_size, no_create=False, **kwargs):
super(AdaptiveAvgPool, self).__init__(**kwargs)
self.in_channels = out_channels
self.out_channels = out_channels
self.output_size = output_size
self.no_create = no_create
if not no_create:
self.netblock = nn.AdaptiveAvgPool2d(
output_size=(self.output_size, self.output_size))
def forward(self, x):
return self.netblock(x)
def __str__(self):
return type(self).__name__ + '({},{})'.format(
self.out_channels // self.output_size**2, self.output_size)
def __repr__(self):
return type(self).__name__ + '({}|{},{})'.format(
self.block_name, self.out_channels // self.output_size**2,
self.output_size)
def get_output_resolution(self, input_resolution):
return self.output_size
@classmethod
def create_from_str(cls, s, no_create=False, **kwargs):
assert AdaptiveAvgPool.is_instance_from_str(s)
idx = get_right_parentheses_index(s)
assert idx is not None
param_str = s[len('AdaptiveAvgPool('):idx]
tmp_idx = param_str.find('|')
if tmp_idx < 0:
tmp_block_name = 'uuid{}'.format(uuid.uuid4().hex)
else:
tmp_block_name = param_str[0:tmp_idx]
param_str = param_str[tmp_idx + 1:]
param_str_split = param_str.split(',')
out_channels = int(param_str_split[0])
output_size = int(param_str_split[1])
return AdaptiveAvgPool(
out_channels=out_channels,
output_size=output_size,
block_name=tmp_block_name,
no_create=no_create), s[idx + 1:]
class BN(PlainNetBasicBlockClass):
def __init__(self,
out_channels=None,
copy_from=None,
no_create=False,
**kwargs):
super(BN, self).__init__(**kwargs)
self.no_create = no_create
if copy_from is not None:
assert isinstance(copy_from, nn.BatchNorm2d)
self.in_channels = copy_from.weight.shape[0]
self.out_channels = copy_from.weight.shape[0]
assert out_channels is None or out_channels == self.out_channels
self.netblock = copy_from
else:
self.in_channels = out_channels
self.out_channels = out_channels
if no_create:
return
else:
self.netblock = nn.BatchNorm2d(num_features=self.out_channels)
def forward(self, x):
return self.netblock(x)
def __str__(self):
return 'BN({})'.format(self.out_channels)
def __repr__(self):
return 'BN({}|{})'.format(self.block_name, self.out_channels)
def get_output_resolution(self, input_resolution):
return input_resolution
@classmethod
def create_from_str(cls, s, no_create=False, **kwargs):
assert BN.is_instance_from_str(s)
idx = get_right_parentheses_index(s)
assert idx is not None
param_str = s[len('BN('):idx]
tmp_idx = param_str.find('|')
if tmp_idx < 0:
tmp_block_name = 'uuid{}'.format(uuid.uuid4().hex)
else:
tmp_block_name = param_str[0:tmp_idx]
param_str = param_str[tmp_idx + 1:]
out_channels = int(param_str)
return BN(
out_channels=out_channels,
block_name=tmp_block_name,
no_create=no_create), s[idx + 1:]
class ConvKX(PlainNetBasicBlockClass):
def __init__(self,
in_channels=None,
out_channels=None,
kernel_size=None,
stride=None,
groups=1,
copy_from=None,
no_create=False,
**kwargs):
super(ConvKX, self).__init__(**kwargs)
self.no_create = no_create
if copy_from is not None:
assert isinstance(copy_from, nn.Conv2d)
self.in_channels = copy_from.in_channels
self.out_channels = copy_from.out_channels
self.kernel_size = copy_from.kernel_size[0]
self.stride = copy_from.stride[0]
self.groups = copy_from.groups
assert in_channels is None or in_channels == self.in_channels
assert out_channels is None or out_channels == self.out_channels
assert kernel_size is None or kernel_size == self.kernel_size
assert stride is None or stride == self.stride
self.netblock = copy_from
else:
self.in_channels = in_channels
self.out_channels = out_channels
self.stride = stride
self.groups = groups
self.kernel_size = kernel_size
self.padding = (self.kernel_size - 1) // 2
if no_create or self.in_channels == 0 or self.out_channels == 0 or self.kernel_size == 0 \
or self.stride == 0:
return
else:
self.netblock = nn.Conv2d(
in_channels=self.in_channels,
out_channels=self.out_channels,
kernel_size=self.kernel_size,
stride=self.stride,
padding=self.padding,
bias=False,
groups=self.groups)
def forward(self, x):
return self.netblock(x)
def __str__(self):
return type(self).__name__ + '({},{},{},{})'.format(
self.in_channels, self.out_channels, self.kernel_size, self.stride)
def __repr__(self):
return type(self).__name__ + '({}|{},{},{},{})'.format(
self.block_name, self.in_channels, self.out_channels,
self.kernel_size, self.stride)
def get_output_resolution(self, input_resolution):
return input_resolution // self.stride
@classmethod
def create_from_str(cls, s, no_create=False, **kwargs):
assert cls.is_instance_from_str(s)
idx = get_right_parentheses_index(s)
assert idx is not None
param_str = s[len(cls.__name__ + '('):idx]
tmp_idx = param_str.find('|')
if tmp_idx < 0:
tmp_block_name = 'uuid{}'.format(uuid.uuid4().hex)
else:
tmp_block_name = param_str[0:tmp_idx]
param_str = param_str[tmp_idx + 1:]
split_str = param_str.split(',')
in_channels = int(split_str[0])
out_channels = int(split_str[1])
kernel_size = int(split_str[2])
stride = int(split_str[3])
return cls(
in_channels=in_channels,
out_channels=out_channels,
kernel_size=kernel_size,
stride=stride,
no_create=no_create,
block_name=tmp_block_name), s[idx + 1:]
class ConvDW(PlainNetBasicBlockClass):
def __init__(self,
out_channels=None,
kernel_size=None,
stride=None,
copy_from=None,
no_create=False,
**kwargs):
super(ConvDW, self).__init__(**kwargs)
self.no_create = no_create
if copy_from is not None:
assert isinstance(copy_from, nn.Conv2d)
self.in_channels = copy_from.in_channels
self.out_channels = copy_from.out_channels
self.kernel_size = copy_from.kernel_size[0]
self.stride = copy_from.stride[0]
assert self.in_channels == self.out_channels
assert out_channels is None or out_channels == self.out_channels
assert kernel_size is None or kernel_size == self.kernel_size
assert stride is None or stride == self.stride
self.netblock = copy_from
else:
self.in_channels = out_channels
self.out_channels = out_channels
self.stride = stride
self.kernel_size = kernel_size
self.padding = (self.kernel_size - 1) // 2
if no_create or self.in_channels == 0 or self.out_channels == 0 or self.kernel_size == 0 \
or self.stride == 0:
return
else:
self.netblock = nn.Conv2d(
in_channels=self.in_channels,
out_channels=self.out_channels,
kernel_size=self.kernel_size,
stride=self.stride,
padding=self.padding,
bias=False,
groups=self.in_channels)
def forward(self, x):
return self.netblock(x)
def __str__(self):
return 'ConvDW({},{},{})'.format(self.out_channels, self.kernel_size,
self.stride)
def __repr__(self):
return 'ConvDW({}|{},{},{})'.format(self.block_name, self.out_channels,
self.kernel_size, self.stride)
def get_output_resolution(self, input_resolution):
return input_resolution // self.stride
@classmethod
def create_from_str(cls, s, no_create=False, **kwargs):
assert ConvDW.is_instance_from_str(s)
idx = get_right_parentheses_index(s)
assert idx is not None
param_str = s[len('ConvDW('):idx]
tmp_idx = param_str.find('|')
if tmp_idx < 0:
tmp_block_name = 'uuid{}'.format(uuid.uuid4().hex)
else:
tmp_block_name = param_str[0:tmp_idx]
param_str = param_str[tmp_idx + 1:]
split_str = param_str.split(',')
out_channels = int(split_str[0])
kernel_size = int(split_str[1])
stride = int(split_str[2])
return ConvDW(
out_channels=out_channels,
kernel_size=kernel_size,
stride=stride,
no_create=no_create,
block_name=tmp_block_name), s[idx + 1:]
class ConvKXG2(ConvKX):
def __init__(self,
in_channels=None,
out_channels=None,
kernel_size=None,
stride=None,
copy_from=None,
no_create=False,
**kwargs):
super(ConvKXG2, self).__init__(
in_channels=in_channels,
out_channels=out_channels,
kernel_size=kernel_size,
stride=stride,
copy_from=copy_from,
no_create=no_create,
groups=2,
**kwargs)
class ConvKXG4(ConvKX):
def __init__(self,
in_channels=None,
out_channels=None,
kernel_size=None,
stride=None,
copy_from=None,
no_create=False,
**kwargs):
super(ConvKXG4, self).__init__(
in_channels=in_channels,
out_channels=out_channels,
kernel_size=kernel_size,
stride=stride,
copy_from=copy_from,
no_create=no_create,
groups=4,
**kwargs)
class ConvKXG8(ConvKX):
def __init__(self,
in_channels=None,
out_channels=None,
kernel_size=None,
stride=None,
copy_from=None,
no_create=False,
**kwargs):
super(ConvKXG8, self).__init__(
in_channels=in_channels,
out_channels=out_channels,
kernel_size=kernel_size,
stride=stride,
copy_from=copy_from,
no_create=no_create,
groups=8,
**kwargs)
class ConvKXG16(ConvKX):
def __init__(self,
in_channels=None,
out_channels=None,
kernel_size=None,
stride=None,
copy_from=None,
no_create=False,
**kwargs):
super(ConvKXG16, self).__init__(
in_channels=in_channels,
out_channels=out_channels,
kernel_size=kernel_size,
stride=stride,
copy_from=copy_from,
no_create=no_create,
groups=16,
**kwargs)
class ConvKXG32(ConvKX):
def __init__(self,
in_channels=None,
out_channels=None,
kernel_size=None,
stride=None,
copy_from=None,
no_create=False,
**kwargs):
super(ConvKXG32, self).__init__(
in_channels=in_channels,
out_channels=out_channels,
kernel_size=kernel_size,
stride=stride,
copy_from=copy_from,
no_create=no_create,
groups=32,
**kwargs)
class Flatten(PlainNetBasicBlockClass):
def __init__(self, out_channels, no_create=False, **kwargs):
super(Flatten, self).__init__(**kwargs)
self.in_channels = out_channels
self.out_channels = out_channels
self.no_create = no_create
def forward(self, x):
return torch.flatten(x, 1)
def __str__(self):
return 'Flatten({})'.format(self.out_channels)
def __repr__(self):
return 'Flatten({}|{})'.format(self.block_name, self.out_channels)
def get_output_resolution(self, input_resolution):
return 1
@classmethod
def create_from_str(cls, s, no_create=False, **kwargs):
assert Flatten.is_instance_from_str(s)
idx = get_right_parentheses_index(s)
assert idx is not None
param_str = s[len('Flatten('):idx]
tmp_idx = param_str.find('|')
if tmp_idx < 0:
tmp_block_name = 'uuid{}'.format(uuid.uuid4().hex)
else:
tmp_block_name = param_str[0:tmp_idx]
param_str = param_str[tmp_idx + 1:]
out_channels = int(param_str)
return Flatten(
out_channels=out_channels,
no_create=no_create,
block_name=tmp_block_name), s[idx + 1:]
class Linear(PlainNetBasicBlockClass):
def __init__(self,
in_channels=None,
out_channels=None,
bias=True,
copy_from=None,
no_create=False,
**kwargs):
super(Linear, self).__init__(**kwargs)
self.no_create = no_create
if copy_from is not None:
assert isinstance(copy_from, nn.Linear)
self.in_channels = copy_from.weight.shape[1]
self.out_channels = copy_from.weight.shape[0]
self.use_bias = copy_from.bias is not None
assert in_channels is None or in_channels == self.in_channels
assert out_channels is None or out_channels == self.out_channels
self.netblock = copy_from
else:
self.in_channels = in_channels
self.out_channels = out_channels
self.use_bias = bias
if not no_create:
self.netblock = nn.Linear(
self.in_channels, self.out_channels, bias=self.use_bias)
def forward(self, x):
return self.netblock(x)
def __str__(self):
return 'Linear({},{},{})'.format(self.in_channels, self.out_channels,
int(self.use_bias))
def __repr__(self):
return 'Linear({}|{},{},{})'.format(self.block_name, self.in_channels,
self.out_channels,
int(self.use_bias))
def get_output_resolution(self, input_resolution):
assert input_resolution == 1
return 1
@classmethod
def create_from_str(cls, s, no_create=False, **kwargs):
assert Linear.is_instance_from_str(s)
idx = get_right_parentheses_index(s)
assert idx is not None
param_str = s[len('Linear('):idx]
tmp_idx = param_str.find('|')
if tmp_idx < 0:
tmp_block_name = 'uuid{}'.format(uuid.uuid4().hex)
else:
tmp_block_name = param_str[0:tmp_idx]
param_str = param_str[tmp_idx + 1:]
split_str = param_str.split(',')
in_channels = int(split_str[0])
out_channels = int(split_str[1])
use_bias = int(split_str[2])
return Linear(
in_channels=in_channels,
out_channels=out_channels,
bias=use_bias == 1,
block_name=tmp_block_name,
no_create=no_create), s[idx + 1:]
class MaxPool(PlainNetBasicBlockClass):
def __init__(self,
out_channels,
kernel_size,
stride,
no_create=False,
**kwargs):
super(MaxPool, self).__init__(**kwargs)
self.in_channels = out_channels
self.out_channels = out_channels
self.kernel_size = kernel_size
self.stride = stride
self.padding = (kernel_size - 1) // 2
self.no_create = no_create
if not no_create:
self.netblock = nn.MaxPool2d(
kernel_size=self.kernel_size,
stride=self.stride,
padding=self.padding)
def forward(self, x):
return self.netblock(x)
def __str__(self):
return 'MaxPool({},{},{})'.format(self.out_channels, self.kernel_size,
self.stride)
def __repr__(self):
return 'MaxPool({}|{},{},{})'.format(self.block_name,
self.out_channels,
self.kernel_size, self.stride)
def get_output_resolution(self, input_resolution):
return input_resolution // self.stride
@classmethod
def create_from_str(cls, s, no_create=False, **kwargs):
assert MaxPool.is_instance_from_str(s)
idx = get_right_parentheses_index(s)
assert idx is not None
param_str = s[len('MaxPool('):idx]
tmp_idx = param_str.find('|')
if tmp_idx < 0:
tmp_block_name = 'uuid{}'.format(uuid.uuid4().hex)
else:
tmp_block_name = param_str[0:tmp_idx]
param_str = param_str[tmp_idx + 1:]
param_str_split = param_str.split(',')
out_channels = int(param_str_split[0])
kernel_size = int(param_str_split[1])
stride = int(param_str_split[2])
return MaxPool(
out_channels=out_channels,
kernel_size=kernel_size,
stride=stride,
no_create=no_create,
block_name=tmp_block_name), s[idx + 1:]
class Sequential(PlainNetBasicBlockClass):
def __init__(self, block_list, no_create=False, **kwargs):
super(Sequential, self).__init__(**kwargs)
self.block_list = block_list
if not no_create:
self.module_list = nn.ModuleList(block_list)
self.in_channels = block_list[0].in_channels
self.out_channels = block_list[-1].out_channels
self.no_create = no_create
res = 1024
for block in self.block_list:
res = block.get_output_resolution(res)
self.stride = 1024 // res
def forward(self, x):
output = x
for inner_block in self.block_list:
output = inner_block(output)
return output
def __str__(self):
s = 'Sequential('
for inner_block in self.block_list:
s += str(inner_block)
s += ')'
return s
def __repr__(self):
return str(self)
def get_output_resolution(self, input_resolution):
the_res = input_resolution
for the_block in self.block_list:
the_res = the_block.get_output_resolution(the_res)
return the_res
@classmethod
def create_from_str(cls, s, no_create=False, **kwargs):
assert Sequential.is_instance_from_str(s)
the_right_paraen_idx = get_right_parentheses_index(s)
param_str = s[len('Sequential(') + 1:the_right_paraen_idx]
tmp_idx = param_str.find('|')
if tmp_idx < 0:
tmp_block_name = 'uuid{}'.format(uuid.uuid4().hex)
else:
tmp_block_name = param_str[0:tmp_idx]
param_str = param_str[tmp_idx + 1:]
the_block_list, remaining_s = create_netblock_list_from_str_inner(
param_str, netblocks_dict=bottom_basic_dict, no_create=no_create)
assert len(remaining_s) == 0
if the_block_list is None or len(the_block_list) == 0:
return None, ''
return Sequential(
block_list=the_block_list,
no_create=no_create,
block_name=tmp_block_name), ''
class MultiSumBlock(PlainNetBasicBlockClass):
def __init__(self, block_list, no_create=False, **kwargs):
super(MultiSumBlock, self).__init__(**kwargs)
self.block_list = block_list
if not no_create:
self.module_list = nn.ModuleList(block_list)
self.in_channels = np.max([x.in_channels for x in block_list])
self.out_channels = np.max([x.out_channels for x in block_list])
self.no_create = no_create
res = 1024
res = self.block_list[0].get_output_resolution(res)
self.stride = 1024 // res
def forward(self, x):
output = self.block_list[0](x)
for inner_block in self.block_list[1:]:
output2 = inner_block(x)
output = output + output2
return output
def __str__(self):
s = 'MultiSumBlock({}|'.format(self.block_name)
for inner_block in self.block_list:
s += str(inner_block) + ';'
s = s[:-1]
s += ')'
return s
def __repr__(self):
return str(self)
def get_output_resolution(self, input_resolution):
the_res = self.block_list[0].get_output_resolution(input_resolution)
for the_block in self.block_list:
assert the_res == the_block.get_output_resolution(input_resolution)
return the_res
@classmethod
def create_from_str(cls, s, no_create=False, **kwargs):
assert MultiSumBlock.is_instance_from_str(s)
idx = get_right_parentheses_index(s)
assert idx is not None
param_str = s[len('MultiSumBlock('):idx]
tmp_idx = param_str.find('|')
if tmp_idx < 0:
tmp_block_name = 'uuid{}'.format(uuid.uuid4().hex)
else:
tmp_block_name = param_str[0:tmp_idx]
param_str = param_str[tmp_idx + 1:]
the_s = param_str
the_block_list = []
while len(the_s) > 0:
tmp_block_list, remaining_s = create_netblock_list_from_str_inner(
the_s, netblocks_dict=bottom_basic_dict, no_create=no_create)
the_s = remaining_s
if tmp_block_list is None:
pass
elif len(tmp_block_list) == 1:
the_block_list.append(tmp_block_list[0])
else:
the_block_list.append(
Sequential(block_list=tmp_block_list, no_create=no_create))
pass
if len(the_block_list) == 0:
return None, s[idx + 1:]
return MultiSumBlock(
block_list=the_block_list,
block_name=tmp_block_name,
no_create=no_create), s[idx + 1:]
class MultiCatBlock(PlainNetBasicBlockClass):
def __init__(self, block_list, no_create=False, **kwargs):
super(MultiCatBlock, self).__init__(**kwargs)
self.block_list = block_list
if not no_create:
self.module_list = nn.ModuleList(block_list)
self.in_channels = np.max([x.in_channels for x in block_list])
self.out_channels = np.sum([x.out_channels for x in block_list])
self.no_create = no_create
res = 1024
res = self.block_list[0].get_output_resolution(res)
self.stride = 1024 // res
def forward(self, x):
output_list = []
for inner_block in self.block_list:
output = inner_block(x)
output_list.append(output)
return torch.cat(output_list, dim=1)
def __str__(self):
s = 'MultiCatBlock({}|'.format(self.block_name)
for inner_block in self.block_list:
s += str(inner_block) + ';'
s = s[:-1]
s += ')'
return s
def __repr__(self):
return str(self)
def get_output_resolution(self, input_resolution):
the_res = self.block_list[0].get_output_resolution(input_resolution)
for the_block in self.block_list:
assert the_res == the_block.get_output_resolution(input_resolution)
return the_res
@classmethod
def create_from_str(cls, s, no_create=False, **kwargs):
assert MultiCatBlock.is_instance_from_str(s)
idx = get_right_parentheses_index(s)
assert idx is not None
param_str = s[len('MultiCatBlock('):idx]
tmp_idx = param_str.find('|')
if tmp_idx < 0:
tmp_block_name = 'uuid{}'.format(uuid.uuid4().hex)
else:
tmp_block_name = param_str[0:tmp_idx]
param_str = param_str[tmp_idx + 1:]
the_s = param_str
the_block_list = []
while len(the_s) > 0:
tmp_block_list, remaining_s = create_netblock_list_from_str_inner(
the_s, netblocks_dict=bottom_basic_dict, no_create=no_create)
the_s = remaining_s
if tmp_block_list is None:
pass
elif len(tmp_block_list) == 1:
the_block_list.append(tmp_block_list[0])
else:
the_block_list.append(
Sequential(block_list=tmp_block_list, no_create=no_create))
if len(the_block_list) == 0:
return None, s[idx + 1:]
return MultiCatBlock(
block_list=the_block_list,
block_name=tmp_block_name,
no_create=no_create), s[idx + 1:]
class RELU(PlainNetBasicBlockClass):
def __init__(self, out_channels, no_create=False, **kwargs):
super(RELU, self).__init__(**kwargs)
self.in_channels = out_channels
self.out_channels = out_channels
self.no_create = no_create
def forward(self, x):
return F.relu(x)
def __str__(self):
return 'RELU({})'.format(self.out_channels)
def __repr__(self):
return 'RELU({}|{})'.format(self.block_name, self.out_channels)
def get_output_resolution(self, input_resolution):
return input_resolution
@classmethod
def create_from_str(cls, s, no_create=False, **kwargs):
assert RELU.is_instance_from_str(s)
idx = get_right_parentheses_index(s)
assert idx is not None
param_str = s[len('RELU('):idx]
tmp_idx = param_str.find('|')
if tmp_idx < 0:
tmp_block_name = 'uuid{}'.format(uuid.uuid4().hex)
else:
tmp_block_name = param_str[0:tmp_idx]
param_str = param_str[tmp_idx + 1:]
out_channels = int(param_str)
return RELU(
out_channels=out_channels,
no_create=no_create,
block_name=tmp_block_name), s[idx + 1:]
class ResBlock(PlainNetBasicBlockClass):
"""
ResBlock(in_channles, inner_blocks_str). If in_channels is missing, use block_list[0].in_channels as in_channels
"""
def __init__(self,
block_list,
in_channels=None,
stride=None,
no_create=False,
**kwargs):
super(ResBlock, self).__init__(**kwargs)
self.block_list = block_list
self.stride = stride
self.no_create = no_create
if not no_create:
self.module_list = nn.ModuleList(block_list)
if in_channels is None:
self.in_channels = block_list[0].in_channels
else:
self.in_channels = in_channels
self.out_channels = block_list[-1].out_channels
if self.stride is None:
tmp_input_res = 1024
tmp_output_res = self.get_output_resolution(tmp_input_res)
self.stride = tmp_input_res // tmp_output_res
self.proj = None
if self.stride > 1 or self.in_channels != self.out_channels:
self.proj = nn.Sequential(
nn.Conv2d(self.in_channels, self.out_channels, 1, self.stride),
nn.BatchNorm2d(self.out_channels),
)
def forward(self, x):
if len(self.block_list) == 0:
return x
output = x
for inner_block in self.block_list:
output = inner_block(output)
if self.proj is not None:
output = output + self.proj(x)
else:
output = output + x
return output
def __str__(self):
s = 'ResBlock({},{},'.format(self.in_channels, self.stride)
for inner_block in self.block_list:
s += str(inner_block)
s += ')'
return s
def __repr__(self):
s = 'ResBlock({}|{},{},'.format(self.block_name, self.in_channels,
self.stride)
for inner_block in self.block_list:
s += str(inner_block)
s += ')'
return s
def get_output_resolution(self, input_resolution):
the_res = input_resolution
for the_block in self.block_list:
the_res = the_block.get_output_resolution(the_res)
return the_res
@classmethod
def create_from_str(cls, s, no_create=False, **kwargs):
assert ResBlock.is_instance_from_str(s)
idx = get_right_parentheses_index(s)
assert idx is not None
the_stride = None
param_str = s[len('ResBlock('):idx]
tmp_idx = param_str.find('|')
if tmp_idx < 0:
tmp_block_name = 'uuid{}'.format(uuid.uuid4().hex)
else:
tmp_block_name = param_str[0:tmp_idx]
param_str = param_str[tmp_idx + 1:]
first_comma_index = param_str.find(',')
if first_comma_index < 0 or not param_str[0:first_comma_index].isdigit(
):
in_channels = None
the_block_list, remaining_s = create_netblock_list_from_str_inner(
param_str,
netblocks_dict=bottom_basic_dict,
no_create=no_create)
else:
in_channels = int(param_str[0:first_comma_index])
param_str = param_str[first_comma_index + 1:]
second_comma_index = param_str.find(',')
if second_comma_index < 0 or not param_str[
0:second_comma_index].isdigit():
the_block_list, remaining_s = create_netblock_list_from_str_inner(
param_str,
netblocks_dict=bottom_basic_dict,
no_create=no_create)
else:
the_stride = int(param_str[0:second_comma_index])
param_str = param_str[second_comma_index + 1:]
the_block_list, remaining_s = create_netblock_list_from_str_inner(
param_str,
netblocks_dict=bottom_basic_dict,
no_create=no_create)
pass
pass
assert len(remaining_s) == 0
if the_block_list is None or len(the_block_list) == 0:
return None, s[idx + 1:]
return ResBlock(
block_list=the_block_list,
in_channels=in_channels,
stride=the_stride,
no_create=no_create,
block_name=tmp_block_name), s[idx + 1:]
class ResBlockProj(PlainNetBasicBlockClass):
"""
ResBlockProj(in_channles, inner_blocks_str). If in_channels is missing, use block_list[0].in_channels as in_channels
"""
def __init__(self,
block_list,
in_channels=None,
stride=None,
no_create=False,
**kwargs):
super(ResBlockProj, self).__init__(**kwargs)
self.block_list = block_list
self.stride = stride
self.no_create = no_create
if not no_create:
self.module_list = nn.ModuleList(block_list)
if in_channels is None:
self.in_channels = block_list[0].in_channels
else:
self.in_channels = in_channels
self.out_channels = block_list[-1].out_channels
if self.stride is None:
tmp_input_res = 1024
tmp_output_res = self.get_output_resolution(tmp_input_res)
self.stride = tmp_input_res // tmp_output_res
self.proj = nn.Sequential(
nn.Conv2d(self.in_channels, self.out_channels, 1, self.stride),
nn.BatchNorm2d(self.out_channels),
)
def forward(self, x):
if len(self.block_list) == 0:
return x
output = x
for inner_block in self.block_list:
output = inner_block(output)
output = output + self.proj(x)
return output
def __str__(self):
s = 'ResBlockProj({},{},'.format(self.in_channels, self.stride)
for inner_block in self.block_list:
s += str(inner_block)
s += ')'
return s
def __repr__(self):
s = 'ResBlockProj({}|{},{},'.format(self.block_name, self.in_channels,
self.stride)
for inner_block in self.block_list:
s += str(inner_block)
s += ')'
return s
def get_output_resolution(self, input_resolution):
the_res = input_resolution
for the_block in self.block_list:
the_res = the_block.get_output_resolution(the_res)
return the_res
@classmethod
def create_from_str(cls, s, no_create=False, **kwargs):
assert ResBlockProj.is_instance_from_str(s)
idx = get_right_parentheses_index(s)
assert idx is not None
the_stride = None
param_str = s[len('ResBlockProj('):idx]
tmp_idx = param_str.find('|')
if tmp_idx < 0:
tmp_block_name = 'uuid{}'.format(uuid.uuid4().hex)
else:
tmp_block_name = param_str[0:tmp_idx]
param_str = param_str[tmp_idx + 1:]
first_comma_index = param_str.find(',')
if first_comma_index < 0 or not param_str[0:first_comma_index].isdigit(
):
in_channels = None
the_block_list, remaining_s = create_netblock_list_from_str_inner(
param_str,
netblocks_dict=bottom_basic_dict,
no_create=no_create)
else:
in_channels = int(param_str[0:first_comma_index])
param_str = param_str[first_comma_index + 1:]
second_comma_index = param_str.find(',')
if second_comma_index < 0 or not param_str[
0:second_comma_index].isdigit():
the_block_list, remaining_s = create_netblock_list_from_str_inner(
param_str,
netblocks_dict=bottom_basic_dict,
no_create=no_create)
else:
the_stride = int(param_str[0:second_comma_index])
param_str = param_str[second_comma_index + 1:]
the_block_list, remaining_s = create_netblock_list_from_str_inner(
param_str,
netblocks_dict=bottom_basic_dict,
no_create=no_create)
pass
pass
assert len(remaining_s) == 0
if the_block_list is None or len(the_block_list) == 0:
return None, s[idx + 1:]
return ResBlockProj(
block_list=the_block_list,
in_channels=in_channels,
stride=the_stride,
no_create=no_create,
block_name=tmp_block_name), s[idx + 1:]
class SE(PlainNetBasicBlockClass):
def __init__(self,
out_channels=None,
copy_from=None,
no_create=False,
**kwargs):
super(SE, self).__init__(**kwargs)
self.no_create = no_create
if copy_from is not None:
raise RuntimeError('Not implemented')
else:
self.in_channels = out_channels
self.out_channels = out_channels
self.se_ratio = 0.25
self.se_channels = max(
1, int(round(self.out_channels * self.se_ratio)))
if no_create or self.out_channels == 0:
return
else:
self.netblock = nn.Sequential(
nn.AdaptiveAvgPool2d((1, 1)),
nn.Conv2d(
in_channels=self.out_channels,
out_channels=self.se_channels,
kernel_size=1,
stride=1,
padding=0,
bias=False), nn.BatchNorm2d(self.se_channels),
nn.ReLU(),
nn.Conv2d(
in_channels=self.se_channels,
out_channels=self.out_channels,
kernel_size=1,
stride=1,
padding=0,
bias=False), nn.BatchNorm2d(self.out_channels),
nn.Sigmoid())
def forward(self, x):
se_x = self.netblock(x)
return se_x * x
def __str__(self):
return 'SE({})'.format(self.out_channels)
def __repr__(self):
return 'SE({}|{})'.format(self.block_name, self.out_channels)
def get_output_resolution(self, input_resolution):
return input_resolution
@classmethod
def create_from_str(cls, s, no_create=False, **kwargs):
assert SE.is_instance_from_str(s)
idx = get_right_parentheses_index(s)
assert idx is not None
param_str = s[len('SE('):idx]
tmp_idx = param_str.find('|')
if tmp_idx < 0:
tmp_block_name = 'uuid{}'.format(uuid.uuid4().hex)
else:
tmp_block_name = param_str[0:tmp_idx]
param_str = param_str[tmp_idx + 1:]
out_channels = int(param_str)
return SE(
out_channels=out_channels,
no_create=no_create,
block_name=tmp_block_name), s[idx + 1:]
class SwishImplementation(torch.autograd.Function):
@staticmethod
def forward(ctx, i):
result = i * torch.sigmoid(i)
ctx.save_for_backward(i)
return result
@staticmethod
def backward(ctx, grad_output):
i = ctx.saved_variables[0]
sigmoid_i = torch.sigmoid(i)
return grad_output * (sigmoid_i * (1 + i * (1 - sigmoid_i)))
class Swish(PlainNetBasicBlockClass):
def __init__(self,
out_channels=None,
copy_from=None,
no_create=False,
**kwargs):
super(Swish, self).__init__(**kwargs)
self.no_create = no_create
if copy_from is not None:
raise RuntimeError('Not implemented')
else:
self.in_channels = out_channels
self.out_channels = out_channels
def forward(self, x):
return SwishImplementation.apply(x)
def __str__(self):
return 'Swish({})'.format(self.out_channels)
def __repr__(self):
return 'Swish({}|{})'.format(self.block_name, self.out_channels)
def get_output_resolution(self, input_resolution):
return input_resolution
@classmethod
def create_from_str(cls, s, no_create=False, **kwargs):
assert Swish.is_instance_from_str(s)
idx = get_right_parentheses_index(s)
assert idx is not None
param_str = s[len('Swish('):idx]
tmp_idx = param_str.find('|')
if tmp_idx < 0:
tmp_block_name = 'uuid{}'.format(uuid.uuid4().hex)
else:
tmp_block_name = param_str[0:tmp_idx]
param_str = param_str[tmp_idx + 1:]
out_channels = int(param_str)
return Swish(
out_channels=out_channels,
no_create=no_create,
block_name=tmp_block_name), s[idx + 1:]
bottom_basic_dict = {
'AdaptiveAvgPool': AdaptiveAvgPool,
'BN': BN,
'ConvDW': ConvDW,
'ConvKX': ConvKX,
'ConvKXG2': ConvKXG2,
'ConvKXG4': ConvKXG4,
'ConvKXG8': ConvKXG8,
'ConvKXG16': ConvKXG16,
'ConvKXG32': ConvKXG32,
'Flatten': Flatten,
'Linear': Linear,
'MaxPool': MaxPool,
'PlainNetBasicBlockClass': PlainNetBasicBlockClass,
'RELU': RELU,
'SE': SE,
'Swish': Swish,
}
def register_netblocks_dict(netblocks_dict: dict):
this_py_file_netblocks_dict = {
'MultiSumBlock': MultiSumBlock,
'MultiCatBlock': MultiCatBlock,
'ResBlock': ResBlock,
'ResBlockProj': ResBlockProj,
'Sequential': Sequential,
}
netblocks_dict.update(this_py_file_netblocks_dict)
netblocks_dict.update(bottom_basic_dict)
return netblocks_dict