From cb725a85a23316f8bd7d24eae4e61a194f9063c8 Mon Sep 17 00:00:00 2001 From: iamhankai Date: Mon, 5 Dec 2022 23:03:58 +0800 Subject: [PATCH 01/11] add ViG models --- .gitignore | 3 + timm/models/__init__.py | 1 + timm/models/layers/__init__.py | 1 + timm/models/layers/gnn_layers.py | 274 ++++++++++++++++++++++++++++++ timm/models/vision_gnn.py | 280 +++++++++++++++++++++++++++++++ 5 files changed, 559 insertions(+) create mode 100755 timm/models/layers/gnn_layers.py create mode 100755 timm/models/vision_gnn.py diff --git a/.gitignore b/.gitignore index e5142b32eb..e95c81bfd8 100644 --- a/.gitignore +++ b/.gitignore @@ -109,3 +109,6 @@ output/ *.gz Untitled.ipynb Testing notebook.ipynb + +# MacOS +*.DS_Store diff --git a/timm/models/__init__.py b/timm/models/__init__.py index 5ff79595d8..bec521e762 100644 --- a/timm/models/__init__.py +++ b/timm/models/__init__.py @@ -55,6 +55,7 @@ from .twins import * from .vgg import * from .visformer import * +from .vision_gnn import * from .vision_transformer import * from .vision_transformer_hybrid import * from .vision_transformer_relpos import * diff --git a/timm/models/layers/__init__.py b/timm/models/layers/__init__.py index 21c641b6c3..f398502b86 100644 --- a/timm/models/layers/__init__.py +++ b/timm/models/layers/__init__.py @@ -21,6 +21,7 @@ from .filter_response_norm import FilterResponseNormTlu2d, FilterResponseNormAct2d from .gather_excite import GatherExcite from .global_context import GlobalContext +from .gnn_layers import Grapher from .helpers import to_ntuple, to_2tuple, to_3tuple, to_4tuple, make_divisible, extend_tuple from .inplace_abn import InplaceAbn from .linear import Linear diff --git a/timm/models/layers/gnn_layers.py b/timm/models/layers/gnn_layers.py new file mode 100755 index 0000000000..d830cba3bb --- /dev/null +++ b/timm/models/layers/gnn_layers.py @@ -0,0 +1,274 @@ +# Layers for GNN model +# Reference: https://github.com/lightaime/deep_gcns_torch +import numpy as np +import torch +from torch import nn +import torch.nn.functional as F +from .drop import DropPath +from .pos_embed import build_sincos2d_pos_embed + + +def pairwise_distance(x, y): + """ + Compute pairwise distance of a point cloud + """ + with torch.no_grad(): + xy_inner = -2*torch.matmul(x, y.transpose(2, 1)) + x_square = torch.sum(torch.mul(x, x), dim=-1, keepdim=True) + y_square = torch.sum(torch.mul(y, y), dim=-1, keepdim=True) + return x_square + xy_inner + y_square.transpose(2, 1) + + +def dense_knn_matrix(x, y, k=16, relative_pos=None): + """Get KNN based on the pairwise distance + """ + with torch.no_grad(): + x = x.transpose(2, 1).squeeze(-1) + y = y.transpose(2, 1).squeeze(-1) + batch_size, n_points, n_dims = x.shape + dist = pairwise_distance(x.detach(), y.detach()) + if relative_pos is not None: + dist += relative_pos + _, nn_idx = torch.topk(-dist, k=k) + center_idx = torch.arange(0, n_points, device=x.device).repeat(batch_size, k, 1).transpose(2, 1) + return torch.stack((nn_idx, center_idx), dim=0) + + +class DenseDilated(nn.Module): + """ + Find dilated neighbor from neighbor list + """ + def __init__(self, k=9, dilation=1, stochastic=False, epsilon=0.0): + super(DenseDilated, self).__init__() + self.dilation = dilation + self.stochastic = stochastic + self.epsilon = epsilon + self.k = k + + def forward(self, edge_index): + if self.stochastic: + if torch.rand(1) < self.epsilon and self.training: + num = self.k * self.dilation + randnum = torch.randperm(num)[:self.k] + edge_index = edge_index[:, :, :, randnum] + else: + edge_index = edge_index[:, :, :, ::self.dilation] + else: + edge_index = edge_index[:, :, :, ::self.dilation] + return edge_index + + +class DenseDilatedKnnGraph(nn.Module): + """ + Find the neighbors' indices based on dilated knn + """ + def __init__(self, k=9, dilation=1, stochastic=False, epsilon=0.0): + super(DenseDilatedKnnGraph, self).__init__() + self.dilation = dilation + self.k = k + self._dilated = DenseDilated(k, dilation, stochastic, epsilon) + + def forward(self, x, y=None, relative_pos=None): + x = F.normalize(x, p=2.0, dim=1) + if y is not None: + y = F.normalize(y, p=2.0, dim=1) + edge_index = dense_knn_matrix(x, y, self.k * self.dilation, relative_pos) + else: + edge_index = dense_knn_matrix(x, x, self.k * self.dilation, relative_pos) + return self._dilated(edge_index) + + +def batched_index_select(x, idx): + # fetches neighbors features from a given neighbor idx + batch_size, num_dims, num_vertices_reduced = x.shape[:3] + _, num_vertices, k = idx.shape + idx_base = torch.arange(0, batch_size, device=idx.device).view(-1, 1, 1) * num_vertices_reduced + idx = idx + idx_base + idx = idx.contiguous().view(-1) + + x = x.transpose(2, 1) + feature = x.contiguous().view(batch_size * num_vertices_reduced, -1)[idx, :] + feature = feature.view(batch_size, num_vertices, k, num_dims).permute(0, 3, 1, 2).contiguous() + return feature + + +def norm_layer(norm, nc): + # normalization layer 2d + norm = norm.lower() + if norm == 'batch': + layer = nn.BatchNorm2d(nc, affine=True) + elif norm == 'instance': + layer = nn.InstanceNorm2d(nc, affine=False) + else: + raise NotImplementedError('normalization layer [%s] is not found' % norm) + return layer + + +class MRConv2d(nn.Module): + """ + Max-Relative Graph Convolution (Paper: https://arxiv.org/abs/1904.03751) for dense data type + """ + def __init__(self, in_channels, out_channels, act_layer=nn.GELU, norm=None, bias=True): + super(MRConv2d, self).__init__() + # self.nn = BasicConv([in_channels*2, out_channels], act_layer, norm, bias) + self.nn = nn.Sequential( + nn.Conv2d(in_channels*2, out_channels, 1, bias=bias, groups=4), + norm_layer(norm, out_channels), + act_layer(), + ) + + self.init_weights() + + def init_weights(self): + for m in self.modules(): + if isinstance(m, nn.Conv2d): + nn.init.kaiming_normal_(m.weight) + if m.bias is not None: + nn.init.zeros_(m.bias) + elif isinstance(m, nn.BatchNorm2d) or isinstance(m, nn.InstanceNorm2d): + m.weight.data.fill_(1) + m.bias.data.zero_() + + def forward(self, x, edge_index, y=None): + x_i = batched_index_select(x, edge_index[1]) + if y is not None: + x_j = batched_index_select(y, edge_index[0]) + else: + x_j = batched_index_select(x, edge_index[0]) + x_j, _ = torch.max(x_j - x_i, -1, keepdim=True) + b, c, n, _ = x.shape + x = torch.cat([x.unsqueeze(2), x_j.unsqueeze(2)], dim=2).reshape(b, 2 * c, n, _) + return self.nn(x) + + +class EdgeConv2d(nn.Module): + """ + Edge convolution layer (with activation, batch normalization) for dense data type + """ + def __init__(self, in_channels, out_channels, act_layer=nn.GELU, norm=None, bias=True): + super(EdgeConv2d, self).__init__() + self.nn = nn.Sequential( + nn.Conv2d(in_channels*2, out_channels, 1, bias=bias, groups=4), + norm_layer(norm, out_channels), + act_layer(), + ) + + self.init_weights() + + def init_weights(self): + for m in self.modules(): + if isinstance(m, nn.Conv2d): + nn.init.kaiming_normal_(m.weight) + if m.bias is not None: + nn.init.zeros_(m.bias) + elif isinstance(m, nn.BatchNorm2d) or isinstance(m, nn.InstanceNorm2d): + m.weight.data.fill_(1) + m.bias.data.zero_() + + def forward(self, x, edge_index, y=None): + x_i = batched_index_select(x, edge_index[1]) + if y is not None: + x_j = batched_index_select(y, edge_index[0]) + else: + x_j = batched_index_select(x, edge_index[0]) + max_value, _ = torch.max(self.nn(torch.cat([x_i, x_j - x_i], dim=1)), -1, keepdim=True) + return max_value + + +class GraphConv2d(nn.Module): + """ + Static graph convolution layer + """ + def __init__(self, in_channels, out_channels, conv='mr', act_layer=nn.GELU, norm=None, bias=True): + super(GraphConv2d, self).__init__() + if conv == 'edge': + self.gconv = EdgeConv2d(in_channels, out_channels, act_layer, norm, bias) + elif conv == 'mr': + self.gconv = MRConv2d(in_channels, out_channels, act_layer, norm, bias) + else: + raise NotImplementedError('conv:{} is not supported'.format(conv)) + + def forward(self, x, edge_index, y=None): + return self.gconv(x, edge_index, y) + + +class DyGraphConv2d(GraphConv2d): + """ + Dynamic graph convolution layer + """ + def __init__(self, in_channels, out_channels, kernel_size=9, dilation=1, conv='mr', act_layer=nn.GELU, + norm=None, bias=True, stochastic=False, epsilon=0.0, r=1): + super(DyGraphConv2d, self).__init__(in_channels, out_channels, conv, act_layer, norm, bias) + self.k = kernel_size + self.d = dilation + self.r = r + self.dilated_knn_graph = DenseDilatedKnnGraph(kernel_size, dilation, stochastic, epsilon) + + def forward(self, x, relative_pos=None): + B, C, H, W = x.shape + y = None + if self.r > 1: + y = F.avg_pool2d(x, self.r, self.r) + y = y.reshape(B, C, -1, 1).contiguous() + x = x.reshape(B, C, -1, 1).contiguous() + edge_index = self.dilated_knn_graph(x, y, relative_pos) + x = super(DyGraphConv2d, self).forward(x, edge_index, y) + return x.reshape(B, -1, H, W).contiguous() + + +def get_2d_relative_pos_embed(embed_dim, grid_size): + """ + relative position embedding + References: https://arxiv.org/abs/2009.13658 + """ + pos_embed = build_sincos2d_pos_embed([grid_size, grid_size], embed_dim) + relative_pos = 2 * torch.matmul(pos_embed, pos_embed.transpose(0, 1)) / pos_embed.shape[1] + return relative_pos + + +class Grapher(nn.Module): + """ + Grapher module with graph convolution and fc layers + """ + def __init__(self, in_channels, kernel_size=9, dilation=1, conv='mr', act_layer=nn.GELU, norm=None, + bias=True, stochastic=False, epsilon=0.0, r=1, n=196, drop_path=0.0, relative_pos=False): + super(Grapher, self).__init__() + self.channels = in_channels + self.n = n + self.r = r + self.fc1 = nn.Sequential( + nn.Conv2d(in_channels, in_channels, 1, stride=1, padding=0), + nn.BatchNorm2d(in_channels), + ) + self.graph_conv = DyGraphConv2d(in_channels, in_channels * 2, kernel_size, dilation, conv, + act_layer, norm, bias, stochastic, epsilon, r) + self.fc2 = nn.Sequential( + nn.Conv2d(in_channels * 2, in_channels, 1, stride=1, padding=0), + nn.BatchNorm2d(in_channels), + ) + self.drop_path = DropPath(drop_path) if drop_path > 0. else nn.Identity() + self.relative_pos = None + if relative_pos: + relative_pos_tensor = get_2d_relative_pos_embed(in_channels, + int(n**0.5)).unsqueeze(0).unsqueeze(1) + relative_pos_tensor = F.interpolate( + relative_pos_tensor, size=(n, n//(r*r)), mode='bicubic', align_corners=False) + self.relative_pos = nn.Parameter(-relative_pos_tensor.squeeze(1), requires_grad=False) + + def _get_relative_pos(self, relative_pos, H, W): + if relative_pos is None or H * W == self.n: + return relative_pos + else: + N = H * W + N_reduced = N // (self.r * self.r) + return F.interpolate(relative_pos.unsqueeze(0), size=(N, N_reduced), mode="bicubic").squeeze(0) + + def forward(self, x): + _tmp = x + x = self.fc1(x) + B, C, H, W = x.shape + relative_pos = self._get_relative_pos(self.relative_pos, H, W) + x = self.graph_conv(x, relative_pos) + x = self.fc2(x) + x = self.drop_path(x) + _tmp + return x diff --git a/timm/models/vision_gnn.py b/timm/models/vision_gnn.py new file mode 100755 index 0000000000..5e48ef9d61 --- /dev/null +++ b/timm/models/vision_gnn.py @@ -0,0 +1,280 @@ +""" +An implementation of ViG Model as defined in: +Vision GNN: An Image is Worth Graph of Nodes. +https://arxiv.org/abs/2206.00272 +""" +import math +import torch +import torch.nn as nn +import torch.nn.functional as F +from torch.nn import Sequential as Seq + +from timm.data import IMAGENET_DEFAULT_MEAN, IMAGENET_DEFAULT_STD +from .helpers import load_pretrained, build_model_with_cfg +from .layers import DropPath, Grapher +from .registry import register_model + + +def _cfg(url='', **kwargs): + return { + 'url': url, + 'num_classes': 1000, 'input_size': (3, 224, 224), 'pool_size': None, + 'crop_pct': .9, 'interpolation': 'bicubic', + 'mean': IMAGENET_DEFAULT_MEAN, 'std': IMAGENET_DEFAULT_STD, + 'first_conv': 'patch_embed.proj', 'classifier': 'head', + **kwargs + } + + +default_cfgs = { + 'pvig_ti_224_gelu': _cfg( + mean=(0.5, 0.5, 0.5), std=(0.5, 0.5, 0.5), + url='https://github.com/huawei-noah/Efficient-AI-Backbones/releases/download/pyramid-vig/pvig_ti_78.5.pth.tar', + ), + 'pvig_s_224_gelu': _cfg( + mean=(0.5, 0.5, 0.5), std=(0.5, 0.5, 0.5), + url='https://github.com/huawei-noah/Efficient-AI-Backbones/releases/download/pyramid-vig/pvig_s_82.1.pth.tar', + ), + 'pvig_m_224_gelu': _cfg( + mean=(0.5, 0.5, 0.5), std=(0.5, 0.5, 0.5), + url='https://github.com/huawei-noah/Efficient-AI-Backbones/releases/download/pyramid-vig/pvig_m_83.1.pth.tar', + ), + 'pvig_b_224_gelu': _cfg( + crop_pct=0.95, mean=(0.5, 0.5, 0.5), std=(0.5, 0.5, 0.5), + url='https://github.com/huawei-noah/Efficient-AI-Backbones/releases/download/pyramid-vig/pvig_b_83.66.pth.tar', + ), +} + + +class FFN(nn.Module): + def __init__(self, in_features, hidden_features=None, out_features=None, + act_layer=nn.GELU, drop_path=0.0): + super().__init__() + out_features = out_features or in_features + hidden_features = hidden_features or in_features + self.fc1 = nn.Sequential( + nn.Conv2d(in_features, hidden_features, 1, stride=1, padding=0), + nn.BatchNorm2d(hidden_features), + ) + self.act = act_layer() + self.fc2 = nn.Sequential( + nn.Conv2d(hidden_features, out_features, 1, stride=1, padding=0), + nn.BatchNorm2d(out_features), + ) + self.drop_path = DropPath(drop_path) if drop_path > 0. else nn.Identity() + + def forward(self, x): + shortcut = x + x = self.fc1(x) + x = self.act(x) + x = self.fc2(x) + x = self.drop_path(x) + shortcut + return x + + +class Stem(nn.Module): + """ Image to Visual Embedding + Overlap: https://arxiv.org/pdf/2106.13797.pdf + """ + def __init__(self, img_size=224, in_dim=3, out_dim=768, act_layer=nn.GELU): + super().__init__() + self.convs = nn.Sequential( + nn.Conv2d(in_dim, out_dim//2, 3, stride=2, padding=1), + nn.BatchNorm2d(out_dim//2), + act_layer(), + nn.Conv2d(out_dim//2, out_dim, 3, stride=2, padding=1), + nn.BatchNorm2d(out_dim), + act_layer(), + nn.Conv2d(out_dim, out_dim, 3, stride=1, padding=1), + nn.BatchNorm2d(out_dim), + ) + + def forward(self, x): + x = self.convs(x) + return x + + +class Downsample(nn.Module): + """ Convolution-based downsample + """ + def __init__(self, in_dim=3, out_dim=768): + super().__init__() + self.conv = nn.Sequential( + nn.Conv2d(in_dim, out_dim, 3, stride=2, padding=1), + nn.BatchNorm2d(out_dim), + ) + + def forward(self, x): + x = self.conv(x) + return x + + +class DeepGCN(torch.nn.Module): + def __init__(self, opt, num_classes=1000, in_chans=3): + super(DeepGCN, self).__init__() + self.num_classes = num_classes + self.in_chans = in_chans + print(opt) + k = opt.k + act_layer = nn.GELU + norm = opt.norm + bias = opt.bias + epsilon = opt.epsilon + stochastic = opt.use_stochastic + conv = opt.conv + drop_path = opt.drop_path + + blocks = opt.blocks + self.n_blocks = sum(blocks) + channels = opt.channels + reduce_ratios = [4, 2, 1, 1] + dpr = [x.item() for x in torch.linspace(0, drop_path, self.n_blocks)] # stochastic depth decay + num_knn = [int(x.item()) for x in torch.linspace(k, k, self.n_blocks)] # number of knn's k + max_dilation = 49 // max(num_knn) + + self.stem = Stem(in_dim=in_chans, out_dim=channels[0], act_layer=act_layer) + self.pos_embed = nn.Parameter(torch.zeros(1, channels[0], 224//4, 224//4)) + HW = 224 // 4 * 224 // 4 + + self.backbone = nn.ModuleList([]) + idx = 0 + for i in range(len(blocks)): + if i > 0: + self.backbone.append(Downsample(channels[i-1], channels[i])) + HW = HW // 4 + for j in range(blocks[i]): + self.backbone += [ + Seq(Grapher(channels[i], num_knn[idx], min(idx // 4 + 1, max_dilation), conv, act_layer, + norm, bias, stochastic, epsilon, reduce_ratios[i], n=HW, drop_path=dpr[idx], + relative_pos=True), + FFN(channels[i], channels[i] * 4, act_layer=act_layer, drop_path=dpr[idx]) + )] + idx += 1 + self.backbone = Seq(*self.backbone) + + self.prediction = Seq(nn.Conv2d(channels[-1], 1024, 1, bias=True), + nn.BatchNorm2d(1024), + act_layer(), + nn.Dropout(opt.dropout), + nn.Conv2d(1024, num_classes, 1, bias=True)) + self.model_init() + + def model_init(self): + for m in self.modules(): + if isinstance(m, torch.nn.Conv2d): + torch.nn.init.kaiming_normal_(m.weight) + m.weight.requires_grad = True + if m.bias is not None: + m.bias.data.zero_() + m.bias.requires_grad = True + + def forward(self, inputs): + x = self.stem(inputs) + self.pos_embed + B, C, H, W = x.shape + for i in range(len(self.backbone)): + x = self.backbone[i](x) + + x = F.adaptive_avg_pool2d(x, 1) + return self.prediction(x).squeeze(-1).squeeze(-1) + + +def _create_pvig(variant, opt, pretrained=False, **kwargs): + """ + Constructs a GhostNet model + """ + model_kwargs = dict( + opt=opt, + **kwargs, + ) + return build_model_with_cfg( + DeepGCN, variant, pretrained, + feature_cfg=dict(flatten_sequential=True), + **model_kwargs) + + +@register_model +def pvig_ti_224_gelu(pretrained=False, **kwargs): + class OptInit: + def __init__(self, drop_path_rate=0.0, **kwargs): + self.k = 9 # neighbor num (default:9) + self.conv = 'mr' # graph conv layer {edge, mr} + self.norm = 'batch' # batch or instance normalization {batch, instance} + self.bias = True # bias of conv layer True or False + self.dropout = 0.0 # dropout rate + self.use_dilation = True # use dilated knn or not + self.epsilon = 0.2 # stochastic epsilon for gcn + self.use_stochastic = False # stochastic for gcn, True or False + self.drop_path = drop_path_rate + self.blocks = [2, 2, 6, 2] # number of basic blocks in the backbone + self.channels = [48, 96, 240, 384] # number of channels of deep features + + opt = OptInit(**kwargs) + model = _create_pvig('pvig_ti_224_gelu', opt, pretrained) + model.default_cfg = default_cfgs['pvig_ti_224_gelu'] + return model + + +@register_model +def pvig_s_224_gelu(pretrained=False, **kwargs): + class OptInit: + def __init__(self, drop_path_rate=0.0, **kwargs): + self.k = 9 # neighbor num (default:9) + self.conv = 'mr' # graph conv layer {edge, mr} + self.norm = 'batch' # batch or instance normalization {batch, instance} + self.bias = True # bias of conv layer True or False + self.dropout = 0.0 # dropout rate + self.use_dilation = True # use dilated knn or not + self.epsilon = 0.2 # stochastic epsilon for gcn + self.use_stochastic = False # stochastic for gcn, True or False + self.drop_path = drop_path_rate + self.blocks = [2, 2, 6, 2] # number of basic blocks in the backbone + self.channels = [80, 160, 400, 640] # number of channels of deep features + + opt = OptInit(**kwargs) + model = _create_pvig('pvig_s_224_gelu', opt, pretrained) + model.default_cfg = default_cfgs['pvig_s_224_gelu'] + return model + + +@register_model +def pvig_m_224_gelu(pretrained=False, **kwargs): + class OptInit: + def __init__(self, drop_path_rate=0.0, **kwargs): + self.k = 9 # neighbor num (default:9) + self.conv = 'mr' # graph conv layer {edge, mr} + self.norm = 'batch' # batch or instance normalization {batch, instance} + self.bias = True # bias of conv layer True or False + self.dropout = 0.0 # dropout rate + self.use_dilation = True # use dilated knn or not + self.epsilon = 0.2 # stochastic epsilon for gcn + self.use_stochastic = False # stochastic for gcn, True or False + self.drop_path = drop_path_rate + self.blocks = [2,2,16,2] # number of basic blocks in the backbone + self.channels = [96, 192, 384, 768] # number of channels of deep features + + opt = OptInit(**kwargs) + model = _create_pvig('pvig_m_224_gelu', opt, pretrained) + model.default_cfg = default_cfgs['pvig_m_224_gelu'] + return model + + +@register_model +def pvig_b_224_gelu(pretrained=False, **kwargs): + class OptInit: + def __init__(self, drop_path_rate=0.0, **kwargs): + self.k = 9 # neighbor num (default:9) + self.conv = 'mr' # graph conv layer {edge, mr} + self.norm = 'batch' # batch or instance normalization {batch, instance} + self.bias = True # bias of conv layer True or False + self.dropout = 0.0 # dropout rate + self.use_dilation = True # use dilated knn or not + self.epsilon = 0.2 # stochastic epsilon for gcn + self.use_stochastic = False # stochastic for gcn, True or False + self.drop_path = drop_path_rate + self.blocks = [2,2,18,2] # number of basic blocks in the backbone + self.channels = [128, 256, 512, 1024] # number of channels of deep features + + opt = OptInit(**kwargs) + model = _create_pvig('pvig_b_224_gelu', opt, pretrained) + model.default_cfg = default_cfgs['pvig_b_224_gelu'] + return model From f080f1b8c9c1de58477e4b94939989d2a68663d6 Mon Sep 17 00:00:00 2001 From: iamhankai Date: Tue, 6 Dec 2022 12:18:50 +0800 Subject: [PATCH 02/11] update ViG models --- tests/test_models.py | 2 +- timm/models/vision_gnn.py | 10 ++++++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/tests/test_models.py b/tests/test_models.py index d007d65afa..1d619c6269 100644 --- a/tests/test_models.py +++ b/tests/test_models.py @@ -28,7 +28,7 @@ 'vit_*', 'tnt_*', 'pit_*', 'swin_*', 'coat_*', 'cait_*', '*mixer_*', 'gmlp_*', 'resmlp_*', 'twins_*', 'convit_*', 'levit*', 'visformer*', 'deit*', 'jx_nest_*', 'nest_*', 'xcit_*', 'crossvit_*', 'beit*', 'poolformer_*', 'volo_*', 'sequencer2d_*', 'swinv2_*', 'pvt_v2*', 'mvitv2*', 'gcvit*', 'efficientformer*', - 'coatnet*', 'coatnext*', 'maxvit*', 'maxxvit*', + 'coatnet*', 'coatnext*', 'maxvit*', 'maxxvit*', 'pvig_*', ] NUM_NON_STD = len(NON_STD_FILTERS) diff --git a/timm/models/vision_gnn.py b/timm/models/vision_gnn.py index 5e48ef9d61..4fe4a8f66d 100755 --- a/timm/models/vision_gnn.py +++ b/timm/models/vision_gnn.py @@ -114,7 +114,6 @@ def __init__(self, opt, num_classes=1000, in_chans=3): super(DeepGCN, self).__init__() self.num_classes = num_classes self.in_chans = in_chans - print(opt) k = opt.k act_layer = nn.GELU norm = opt.norm @@ -168,9 +167,16 @@ def model_init(self): m.bias.data.zero_() m.bias.requires_grad = True + def _get_pos_embed(self, pos_embed, H, W): + if pos_embed is None or (H == pos_embed.size(-2) and W == pos_embed.size(-1)): + return pos_embed + else: + return F.interpolate(pos_embed, size=(H, W), mode="bicubic") + def forward(self, inputs): - x = self.stem(inputs) + self.pos_embed + x = self.stem(inputs) B, C, H, W = x.shape + x = x + self._get_pos_embed(self.pos_embed, H, W) for i in range(len(self.backbone)): x = self.backbone[i](x) From 1d81cd55f532aced08702ad609e3d58844552784 Mon Sep 17 00:00:00 2001 From: Kai Han Date: Tue, 6 Dec 2022 16:15:02 +0800 Subject: [PATCH 03/11] fix error of min input size --- timm/models/vision_gnn.py | 1 + 1 file changed, 1 insertion(+) diff --git a/timm/models/vision_gnn.py b/timm/models/vision_gnn.py index 4fe4a8f66d..e49351e60c 100755 --- a/timm/models/vision_gnn.py +++ b/timm/models/vision_gnn.py @@ -22,6 +22,7 @@ def _cfg(url='', **kwargs): 'crop_pct': .9, 'interpolation': 'bicubic', 'mean': IMAGENET_DEFAULT_MEAN, 'std': IMAGENET_DEFAULT_STD, 'first_conv': 'patch_embed.proj', 'classifier': 'head', + 'min_input_size': (3, 224, 224), **kwargs } From 38a908bf542f7b5cffa884e0c27587f10eb27ea9 Mon Sep 17 00:00:00 2001 From: iamhankai Date: Tue, 6 Dec 2022 22:21:00 +0800 Subject: [PATCH 04/11] fix test errors --- tests/test_models.py | 2 +- timm/models/layers/gnn_layers.py | 6 ++-- timm/models/vision_gnn.py | 47 +++++++++++++++++++++++--------- 3 files changed, 39 insertions(+), 16 deletions(-) diff --git a/tests/test_models.py b/tests/test_models.py index 1d619c6269..f5e5cab3a1 100644 --- a/tests/test_models.py +++ b/tests/test_models.py @@ -270,7 +270,7 @@ def test_model_features_pretrained(model_name, batch_size): EXCLUDE_JIT_FILTERS = [ '*iabn*', 'tresnet*', # models using inplace abn unlikely to ever be scriptable - 'dla*', 'hrnet*', 'ghostnet*', # hopefully fix at some point + 'dla*', 'hrnet*', 'ghostnet*', 'pvig*', # hopefully fix at some point 'vit_large_*', 'vit_huge_*', 'vit_gi*', ] diff --git a/timm/models/layers/gnn_layers.py b/timm/models/layers/gnn_layers.py index d830cba3bb..ca453e735a 100755 --- a/timm/models/layers/gnn_layers.py +++ b/timm/models/layers/gnn_layers.py @@ -247,13 +247,15 @@ def __init__(self, in_channels, kernel_size=9, dilation=1, conv='mr', act_layer= nn.BatchNorm2d(in_channels), ) self.drop_path = DropPath(drop_path) if drop_path > 0. else nn.Identity() - self.relative_pos = None if relative_pos: relative_pos_tensor = get_2d_relative_pos_embed(in_channels, int(n**0.5)).unsqueeze(0).unsqueeze(1) relative_pos_tensor = F.interpolate( relative_pos_tensor, size=(n, n//(r*r)), mode='bicubic', align_corners=False) - self.relative_pos = nn.Parameter(-relative_pos_tensor.squeeze(1), requires_grad=False) + # self.relative_pos = nn.Parameter(-relative_pos_tensor.squeeze(1)) + self.register_buffer('relative_pos', -relative_pos_tensor.squeeze(1)) + else: + self.relative_pos = None def _get_relative_pos(self, relative_pos, H, W): if relative_pos is None or H * W == self.n: diff --git a/timm/models/vision_gnn.py b/timm/models/vision_gnn.py index e49351e60c..fa8b0d72e8 100755 --- a/timm/models/vision_gnn.py +++ b/timm/models/vision_gnn.py @@ -21,7 +21,7 @@ def _cfg(url='', **kwargs): 'num_classes': 1000, 'input_size': (3, 224, 224), 'pool_size': None, 'crop_pct': .9, 'interpolation': 'bicubic', 'mean': IMAGENET_DEFAULT_MEAN, 'std': IMAGENET_DEFAULT_STD, - 'first_conv': 'patch_embed.proj', 'classifier': 'head', + 'first_conv': 'stem.convs.0', 'classifier': 'prediction.4', 'min_input_size': (3, 224, 224), **kwargs } @@ -123,10 +123,11 @@ def __init__(self, opt, num_classes=1000, in_chans=3): stochastic = opt.use_stochastic conv = opt.conv drop_path = opt.drop_path + channels = opt.channels + self.num_features = channels[-1] # num_features for consistency with other models blocks = opt.blocks self.n_blocks = sum(blocks) - channels = opt.channels reduce_ratios = [4, 2, 1, 1] dpr = [x.item() for x in torch.linspace(0, drop_path, self.n_blocks)] # stochastic depth decay num_knn = [int(x.item()) for x in torch.linspace(k, k, self.n_blocks)] # number of knn's k @@ -152,11 +153,14 @@ def __init__(self, opt, num_classes=1000, in_chans=3): idx += 1 self.backbone = Seq(*self.backbone) - self.prediction = Seq(nn.Conv2d(channels[-1], 1024, 1, bias=True), + if num_classes > 0: + self.prediction = Seq(nn.Conv2d(self.num_features, 1024, 1, bias=True), nn.BatchNorm2d(1024), act_layer(), nn.Dropout(opt.dropout), nn.Conv2d(1024, num_classes, 1, bias=True)) + else: + self.prediction = nn.Identity() self.model_init() def model_init(self): @@ -174,13 +178,30 @@ def _get_pos_embed(self, pos_embed, H, W): else: return F.interpolate(pos_embed, size=(H, W), mode="bicubic") - def forward(self, inputs): - x = self.stem(inputs) + def reset_classifier(self, num_classes: int, global_pool=None): + self.num_classes = num_classes + if global_pool is not None: + assert global_pool in ('', 'avg', 'token') + self.global_pool = global_pool + if num_classes > 0: + self.prediction = Seq(nn.Conv2d(self.num_features, 1024, 1, bias=True), + nn.BatchNorm2d(1024), + act_layer(), + nn.Dropout(opt.dropout), + nn.Conv2d(1024, num_classes, 1, bias=True)) + else: + self.prediction = nn.Identity() + + def forward_features(self, x): + x = self.stem(x) B, C, H, W = x.shape x = x + self._get_pos_embed(self.pos_embed, H, W) for i in range(len(self.backbone)): x = self.backbone[i](x) + return x + def forward(self, x): + x = self.forward_features(x) x = F.adaptive_avg_pool2d(x, 1) return self.prediction(x).squeeze(-1).squeeze(-1) @@ -200,7 +221,7 @@ def _create_pvig(variant, opt, pretrained=False, **kwargs): @register_model -def pvig_ti_224_gelu(pretrained=False, **kwargs): +def pvig_ti_224_gelu(pretrained=False, num_classes=1000, **kwargs): class OptInit: def __init__(self, drop_path_rate=0.0, **kwargs): self.k = 9 # neighbor num (default:9) @@ -216,13 +237,13 @@ def __init__(self, drop_path_rate=0.0, **kwargs): self.channels = [48, 96, 240, 384] # number of channels of deep features opt = OptInit(**kwargs) - model = _create_pvig('pvig_ti_224_gelu', opt, pretrained) + model = _create_pvig('pvig_ti_224_gelu', opt, pretrained, num_classes=num_classes) model.default_cfg = default_cfgs['pvig_ti_224_gelu'] return model @register_model -def pvig_s_224_gelu(pretrained=False, **kwargs): +def pvig_s_224_gelu(pretrained=False, num_classes=1000, **kwargs): class OptInit: def __init__(self, drop_path_rate=0.0, **kwargs): self.k = 9 # neighbor num (default:9) @@ -238,13 +259,13 @@ def __init__(self, drop_path_rate=0.0, **kwargs): self.channels = [80, 160, 400, 640] # number of channels of deep features opt = OptInit(**kwargs) - model = _create_pvig('pvig_s_224_gelu', opt, pretrained) + model = _create_pvig('pvig_s_224_gelu', opt, pretrained, num_classes=num_classes) model.default_cfg = default_cfgs['pvig_s_224_gelu'] return model @register_model -def pvig_m_224_gelu(pretrained=False, **kwargs): +def pvig_m_224_gelu(pretrained=False, num_classes=1000, **kwargs): class OptInit: def __init__(self, drop_path_rate=0.0, **kwargs): self.k = 9 # neighbor num (default:9) @@ -260,13 +281,13 @@ def __init__(self, drop_path_rate=0.0, **kwargs): self.channels = [96, 192, 384, 768] # number of channels of deep features opt = OptInit(**kwargs) - model = _create_pvig('pvig_m_224_gelu', opt, pretrained) + model = _create_pvig('pvig_m_224_gelu', opt, pretrained, num_classes=num_classes) model.default_cfg = default_cfgs['pvig_m_224_gelu'] return model @register_model -def pvig_b_224_gelu(pretrained=False, **kwargs): +def pvig_b_224_gelu(pretrained=False, num_classes=1000, **kwargs): class OptInit: def __init__(self, drop_path_rate=0.0, **kwargs): self.k = 9 # neighbor num (default:9) @@ -282,6 +303,6 @@ def __init__(self, drop_path_rate=0.0, **kwargs): self.channels = [128, 256, 512, 1024] # number of channels of deep features opt = OptInit(**kwargs) - model = _create_pvig('pvig_b_224_gelu', opt, pretrained) + model = _create_pvig('pvig_b_224_gelu', opt, pretrained, num_classes=num_classes) model.default_cfg = default_cfgs['pvig_b_224_gelu'] return model From 00101f9789f58db643d2b10b96d955241649c822 Mon Sep 17 00:00:00 2001 From: Kai Han Date: Wed, 7 Dec 2022 18:41:33 +0800 Subject: [PATCH 05/11] Update vision_gnn.py --- timm/models/vision_gnn.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/timm/models/vision_gnn.py b/timm/models/vision_gnn.py index fa8b0d72e8..85a01a577a 100755 --- a/timm/models/vision_gnn.py +++ b/timm/models/vision_gnn.py @@ -13,6 +13,7 @@ from .helpers import load_pretrained, build_model_with_cfg from .layers import DropPath, Grapher from .registry import register_model +from .fx_features import register_notrace_function def _cfg(url='', **kwargs): @@ -172,6 +173,7 @@ def model_init(self): m.bias.data.zero_() m.bias.requires_grad = True + @register_notrace_function # reason: int argument is a Proxy def _get_pos_embed(self, pos_embed, H, W): if pos_embed is None or (H == pos_embed.size(-2) and W == pos_embed.size(-1)): return pos_embed From 33c6d8e9a931dbbbfbac393ba36e2f3e2b24c215 Mon Sep 17 00:00:00 2001 From: Kai Han Date: Wed, 7 Dec 2022 18:43:16 +0800 Subject: [PATCH 06/11] Update gnn_layers.py --- timm/models/layers/gnn_layers.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/timm/models/layers/gnn_layers.py b/timm/models/layers/gnn_layers.py index ca453e735a..a26220e47e 100755 --- a/timm/models/layers/gnn_layers.py +++ b/timm/models/layers/gnn_layers.py @@ -6,6 +6,7 @@ import torch.nn.functional as F from .drop import DropPath from .pos_embed import build_sincos2d_pos_embed +from .fx_features import register_notrace_module def pairwise_distance(x, y): @@ -226,6 +227,7 @@ def get_2d_relative_pos_embed(embed_dim, grid_size): return relative_pos +@register_notrace_module # reason: FX can't symbolically trace control flow in forward method class Grapher(nn.Module): """ Grapher module with graph convolution and fc layers From df75883615caaaa6c52dfa4a2185c766ab690bd6 Mon Sep 17 00:00:00 2001 From: Kai Han Date: Wed, 7 Dec 2022 21:57:47 +0800 Subject: [PATCH 07/11] Update gnn_layers.py --- timm/models/layers/gnn_layers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/timm/models/layers/gnn_layers.py b/timm/models/layers/gnn_layers.py index a26220e47e..4275cb3c24 100755 --- a/timm/models/layers/gnn_layers.py +++ b/timm/models/layers/gnn_layers.py @@ -4,9 +4,9 @@ import torch from torch import nn import torch.nn.functional as F +from timm.models.fx_features import register_notrace_module from .drop import DropPath from .pos_embed import build_sincos2d_pos_embed -from .fx_features import register_notrace_module def pairwise_distance(x, y): From 7e71058c88feea9dafa8f3fb9c6102eeb10913e3 Mon Sep 17 00:00:00 2001 From: iamhankai Date: Wed, 7 Dec 2022 22:13:26 +0800 Subject: [PATCH 08/11] fix test errors --- timm/models/layers/__init__.py | 2 +- timm/models/layers/gnn_layers.py | 63 ------------------------------ timm/models/vision_gnn.py | 67 +++++++++++++++++++++++++++++++- 3 files changed, 66 insertions(+), 66 deletions(-) diff --git a/timm/models/layers/__init__.py b/timm/models/layers/__init__.py index f398502b86..db5033be6b 100644 --- a/timm/models/layers/__init__.py +++ b/timm/models/layers/__init__.py @@ -21,7 +21,7 @@ from .filter_response_norm import FilterResponseNormTlu2d, FilterResponseNormAct2d from .gather_excite import GatherExcite from .global_context import GlobalContext -from .gnn_layers import Grapher +from .gnn_layers import DyGraphConv2d from .helpers import to_ntuple, to_2tuple, to_3tuple, to_4tuple, make_divisible, extend_tuple from .inplace_abn import InplaceAbn from .linear import Linear diff --git a/timm/models/layers/gnn_layers.py b/timm/models/layers/gnn_layers.py index 4275cb3c24..b264527127 100755 --- a/timm/models/layers/gnn_layers.py +++ b/timm/models/layers/gnn_layers.py @@ -4,9 +4,7 @@ import torch from torch import nn import torch.nn.functional as F -from timm.models.fx_features import register_notrace_module from .drop import DropPath -from .pos_embed import build_sincos2d_pos_embed def pairwise_distance(x, y): @@ -215,64 +213,3 @@ def forward(self, x, relative_pos=None): edge_index = self.dilated_knn_graph(x, y, relative_pos) x = super(DyGraphConv2d, self).forward(x, edge_index, y) return x.reshape(B, -1, H, W).contiguous() - - -def get_2d_relative_pos_embed(embed_dim, grid_size): - """ - relative position embedding - References: https://arxiv.org/abs/2009.13658 - """ - pos_embed = build_sincos2d_pos_embed([grid_size, grid_size], embed_dim) - relative_pos = 2 * torch.matmul(pos_embed, pos_embed.transpose(0, 1)) / pos_embed.shape[1] - return relative_pos - - -@register_notrace_module # reason: FX can't symbolically trace control flow in forward method -class Grapher(nn.Module): - """ - Grapher module with graph convolution and fc layers - """ - def __init__(self, in_channels, kernel_size=9, dilation=1, conv='mr', act_layer=nn.GELU, norm=None, - bias=True, stochastic=False, epsilon=0.0, r=1, n=196, drop_path=0.0, relative_pos=False): - super(Grapher, self).__init__() - self.channels = in_channels - self.n = n - self.r = r - self.fc1 = nn.Sequential( - nn.Conv2d(in_channels, in_channels, 1, stride=1, padding=0), - nn.BatchNorm2d(in_channels), - ) - self.graph_conv = DyGraphConv2d(in_channels, in_channels * 2, kernel_size, dilation, conv, - act_layer, norm, bias, stochastic, epsilon, r) - self.fc2 = nn.Sequential( - nn.Conv2d(in_channels * 2, in_channels, 1, stride=1, padding=0), - nn.BatchNorm2d(in_channels), - ) - self.drop_path = DropPath(drop_path) if drop_path > 0. else nn.Identity() - if relative_pos: - relative_pos_tensor = get_2d_relative_pos_embed(in_channels, - int(n**0.5)).unsqueeze(0).unsqueeze(1) - relative_pos_tensor = F.interpolate( - relative_pos_tensor, size=(n, n//(r*r)), mode='bicubic', align_corners=False) - # self.relative_pos = nn.Parameter(-relative_pos_tensor.squeeze(1)) - self.register_buffer('relative_pos', -relative_pos_tensor.squeeze(1)) - else: - self.relative_pos = None - - def _get_relative_pos(self, relative_pos, H, W): - if relative_pos is None or H * W == self.n: - return relative_pos - else: - N = H * W - N_reduced = N // (self.r * self.r) - return F.interpolate(relative_pos.unsqueeze(0), size=(N, N_reduced), mode="bicubic").squeeze(0) - - def forward(self, x): - _tmp = x - x = self.fc1(x) - B, C, H, W = x.shape - relative_pos = self._get_relative_pos(self.relative_pos, H, W) - x = self.graph_conv(x, relative_pos) - x = self.fc2(x) - x = self.drop_path(x) + _tmp - return x diff --git a/timm/models/vision_gnn.py b/timm/models/vision_gnn.py index 85a01a577a..50f9baf465 100755 --- a/timm/models/vision_gnn.py +++ b/timm/models/vision_gnn.py @@ -11,9 +11,10 @@ from timm.data import IMAGENET_DEFAULT_MEAN, IMAGENET_DEFAULT_STD from .helpers import load_pretrained, build_model_with_cfg -from .layers import DropPath, Grapher +from .layers import DropPath, DyGraphConv2d +from .layers.pos_embed import build_sincos2d_pos_embed from .registry import register_model -from .fx_features import register_notrace_function +from .fx_features import register_notrace_function, register_notrace_module def _cfg(url='', **kwargs): @@ -48,6 +49,68 @@ def _cfg(url='', **kwargs): } + +def get_2d_relative_pos_embed(embed_dim, grid_size): + """ + relative position embedding + References: https://arxiv.org/abs/2009.13658 + """ + pos_embed = build_sincos2d_pos_embed([grid_size, grid_size], embed_dim) + relative_pos = 2 * torch.matmul(pos_embed, pos_embed.transpose(0, 1)) / pos_embed.shape[1] + return relative_pos + + +@register_notrace_module # reason: FX can't symbolically trace control flow in forward method +class Grapher(nn.Module): + """ + Grapher module with graph convolution and fc layers + """ + def __init__(self, in_channels, kernel_size=9, dilation=1, conv='mr', act_layer=nn.GELU, norm=None, + bias=True, stochastic=False, epsilon=0.0, r=1, n=196, drop_path=0.0, relative_pos=False): + super(Grapher, self).__init__() + self.channels = in_channels + self.n = n + self.r = r + self.fc1 = nn.Sequential( + nn.Conv2d(in_channels, in_channels, 1, stride=1, padding=0), + nn.BatchNorm2d(in_channels), + ) + self.graph_conv = DyGraphConv2d(in_channels, in_channels * 2, kernel_size, dilation, conv, + act_layer, norm, bias, stochastic, epsilon, r) + self.fc2 = nn.Sequential( + nn.Conv2d(in_channels * 2, in_channels, 1, stride=1, padding=0), + nn.BatchNorm2d(in_channels), + ) + self.drop_path = DropPath(drop_path) if drop_path > 0. else nn.Identity() + if relative_pos: + relative_pos_tensor = get_2d_relative_pos_embed(in_channels, + int(n**0.5)).unsqueeze(0).unsqueeze(1) + relative_pos_tensor = F.interpolate( + relative_pos_tensor, size=(n, n//(r*r)), mode='bicubic', align_corners=False) + self.register_buffer('relative_pos', -relative_pos_tensor.squeeze(1)) + else: + self.relative_pos = None + + @register_notrace_function # reason: int argument is a Proxy + def _get_relative_pos(self, relative_pos, H, W): + if relative_pos is None or H * W == self.n: + return relative_pos + else: + N = H * W + N_reduced = N // (self.r * self.r) + return F.interpolate(relative_pos.unsqueeze(0), size=(N, N_reduced), mode="bicubic").squeeze(0) + + def forward(self, x): + _tmp = x + x = self.fc1(x) + B, C, H, W = x.shape + relative_pos = self._get_relative_pos(self.relative_pos, H, W) + x = self.graph_conv(x, relative_pos) + x = self.fc2(x) + x = self.drop_path(x) + _tmp + return x + + class FFN(nn.Module): def __init__(self, in_features, hidden_features=None, out_features=None, act_layer=nn.GELU, drop_path=0.0): From 3f46747d6ecd47f4e8a29f7cc387184aa1989685 Mon Sep 17 00:00:00 2001 From: iamhankai Date: Wed, 29 Mar 2023 22:46:37 +0800 Subject: [PATCH 09/11] add im21k pretrained weights --- timm/layers/__init__.py | 1 + timm/{models => }/layers/gnn_layers.py | 0 timm/models/vision_gnn.py | 8 +++++--- 3 files changed, 6 insertions(+), 3 deletions(-) rename timm/{models => }/layers/gnn_layers.py (100%) diff --git a/timm/layers/__init__.py b/timm/layers/__init__.py index d4eab66002..a1cb597741 100644 --- a/timm/layers/__init__.py +++ b/timm/layers/__init__.py @@ -23,6 +23,7 @@ from .format import Format, get_channel_dim, get_spatial_dim, nchw_to, nhwc_to from .gather_excite import GatherExcite from .global_context import GlobalContext +from .gnn_layers import DyGraphConv2d from .helpers import to_ntuple, to_2tuple, to_3tuple, to_4tuple, make_divisible, extend_tuple from .inplace_abn import InplaceAbn from .linear import Linear diff --git a/timm/models/layers/gnn_layers.py b/timm/layers/gnn_layers.py similarity index 100% rename from timm/models/layers/gnn_layers.py rename to timm/layers/gnn_layers.py diff --git a/timm/models/vision_gnn.py b/timm/models/vision_gnn.py index 50f9baf465..79dcd90005 100755 --- a/timm/models/vision_gnn.py +++ b/timm/models/vision_gnn.py @@ -2,6 +2,8 @@ An implementation of ViG Model as defined in: Vision GNN: An Image is Worth Graph of Nodes. https://arxiv.org/abs/2206.00272 +The imagenet-21k pretrained weights: +https://github.com/huawei-noah/Efficient-AI-Backbones/releases/download/pyramid-vig/pvig_m_im21k_90e.pth """ import math import torch @@ -10,9 +12,9 @@ from torch.nn import Sequential as Seq from timm.data import IMAGENET_DEFAULT_MEAN, IMAGENET_DEFAULT_STD -from .helpers import load_pretrained, build_model_with_cfg -from .layers import DropPath, DyGraphConv2d -from .layers.pos_embed import build_sincos2d_pos_embed +from timm.layers import DropPath, DyGraphConv2d +from timm.layers.pos_embed import build_sincos2d_pos_embed +from .helpers import load_pretrained, build_model_with_cfgx from .registry import register_model from .fx_features import register_notrace_function, register_notrace_module From 1daf56d1dfaa2b7720b86d84d6f3a11c350131a8 Mon Sep 17 00:00:00 2001 From: Kai Han Date: Fri, 31 Mar 2023 14:00:39 +0800 Subject: [PATCH 10/11] Update vision_gnn.py --- timm/models/vision_gnn.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/timm/models/vision_gnn.py b/timm/models/vision_gnn.py index 79dcd90005..ba91696ebc 100755 --- a/timm/models/vision_gnn.py +++ b/timm/models/vision_gnn.py @@ -13,7 +13,7 @@ from timm.data import IMAGENET_DEFAULT_MEAN, IMAGENET_DEFAULT_STD from timm.layers import DropPath, DyGraphConv2d -from timm.layers.pos_embed import build_sincos2d_pos_embed +from timm.layers.pos_embed_sincos import build_sincos2d_pos_embed from .helpers import load_pretrained, build_model_with_cfgx from .registry import register_model from .fx_features import register_notrace_function, register_notrace_module From 95106819e28f61f59db2b1b173a215aa6688f8c0 Mon Sep 17 00:00:00 2001 From: Kai Han Date: Mon, 3 Apr 2023 09:55:08 +0800 Subject: [PATCH 11/11] fix typo --- timm/models/vision_gnn.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/timm/models/vision_gnn.py b/timm/models/vision_gnn.py index ba91696ebc..f7490fcff9 100755 --- a/timm/models/vision_gnn.py +++ b/timm/models/vision_gnn.py @@ -14,7 +14,7 @@ from timm.data import IMAGENET_DEFAULT_MEAN, IMAGENET_DEFAULT_STD from timm.layers import DropPath, DyGraphConv2d from timm.layers.pos_embed_sincos import build_sincos2d_pos_embed -from .helpers import load_pretrained, build_model_with_cfgx +from .helpers import load_pretrained, build_model_with_cfg from .registry import register_model from .fx_features import register_notrace_function, register_notrace_module