# -*- coding: utf-8 -*- __author__ = "S.X.Zhang" import torch import numpy as np import cv2 import torch.nn as nn from torch.autograd import Variable def normalize_adj(A, type="AD"): if type == "DAD": A = A + np.eye(A.shape[0]) # A=A+I d = np.sum(A, axis=0) d_inv = np.power(d, -0.5).flatten() d_inv[np.isinf(d_inv)] = 0.0 d_inv = np.diag(d_inv) G = A.dot(d_inv).transpose().dot(d_inv) # L = D^-1/2 A D^-1/2 G = torch.from_numpy(G) elif type == "AD": A = A + np.eye(A.shape[0]) # A=A+I A = torch.from_numpy(A) D = A.sum(1, keepdim=True) G = A.div(D) # L= A/D else: A = A + np.eye(A.shape[0]) # A=A+I D = A.sum(1, keepdim=True) D = np.diag(D) G = torch.from_numpy(D - A) # L = D-A return G def np_to_variable(x, is_cuda=True, dtype=torch.FloatTensor): v = Variable(torch.from_numpy(x).type(dtype)) if is_cuda: v = v.cuda() return v def set_trainable(model, requires_grad): for param in model.parameters(): param.requires_grad = requires_grad def weights_normal_init(model, dev=0.01): if isinstance(model, list): for m in model: weights_normal_init(m, dev) else: for m in model.modules(): if isinstance(m, nn.Conv2d): m.weight.data.normal_(0.0, dev) elif isinstance(m, nn.Linear): m.weight.data.normal_(0.0, dev) def clip_gradient(model, clip_norm): """Computes a gradient clipping coefficient based on gradient norm.""" totalnorm = 0 for p in model.parameters(): if p.requires_grad: modulenorm = p.grad.data.norm() totalnorm += modulenorm ** 2 totalnorm = np.sqrt(totalnorm) norm = clip_norm / max(totalnorm, clip_norm) for p in model.parameters(): if p.requires_grad: p.grad.mul_(norm) def EuclideanDistances(A, B): BT = B.transpose() vecProd = np.dot(A,BT) SqA = A**2 sumSqA = np.matrix(np.sum(SqA, axis=1)) sumSqAEx = np.tile(sumSqA.transpose(), (1, vecProd.shape[1])) SqB = B**2 sumSqB = np.sum(SqB, axis=1) sumSqBEx = np.tile(sumSqB, (vecProd.shape[0], 1)) SqED = sumSqBEx + sumSqAEx - 2*vecProd SqED[SqED<0]=0.0 ED = np.sqrt(SqED) return ED def get_center_feature(cnn_feature, img_poly, ind, h, w): batch_size = cnn_feature.size(0) for i in range(batch_size): poly = img_poly[ind == i].cpu().numpy() mask = np.zeros((h, w), dtype=np.uint8) cv2.fillPoly(mask, poly.astype(np.int32), color=(1,)) return None def get_node_feature(cnn_feature, img_poly, ind, h, w): img_poly = img_poly.clone().float() img_poly[..., 0] = img_poly[..., 0] / (w / 2.) - 1 img_poly[..., 1] = img_poly[..., 1] / (h / 2.) - 1 batch_size = cnn_feature.size(0) gcn_feature = torch.zeros([img_poly.size(0), cnn_feature.size(1), img_poly.size(1)]).to(img_poly.device) for i in range(batch_size): poly = img_poly[ind == i].unsqueeze(0) gcn_feature[ind == i] = torch.nn.functional.grid_sample(cnn_feature[i:i + 1], poly)[0].permute(1, 0, 2) return gcn_feature def get_adj_mat(n_adj, n_nodes): a = np.zeros([n_nodes, n_nodes], dtype=np.float) for i in range(n_nodes): for j in range(-n_adj // 2, n_adj // 2 + 1): if j != 0: a[i][(i + j) % n_nodes] = 1 a[(i + j) % n_nodes][i] = 1 return a def get_adj_ind(n_adj, n_nodes, device): ind = torch.tensor([i for i in range(-n_adj // 2, n_adj // 2 + 1) if i != 0]).long() ind = (torch.arange(n_nodes)[:, None] + ind[None]) % n_nodes return ind.to(device) def coord_embedding(b, w, h, device): x_range = torch.linspace(0, 1, w, device=device) y_range = torch.linspace(0, 1, h, device=device) y, x = torch.meshgrid(y_range, x_range) y = y.expand([b, 1, -1, -1]) x = x.expand([b, 1, -1, -1]) coord_map = torch.cat([x, y], 1) return coord_map def img_poly_to_can_poly(img_poly): if len(img_poly) == 0: return torch.zeros_like(img_poly) x_min = torch.min(img_poly[..., 0], dim=-1)[0] y_min = torch.min(img_poly[..., 1], dim=-1)[0] can_poly = img_poly.clone() can_poly[..., 0] = can_poly[..., 0] - x_min[..., None] can_poly[..., 1] = can_poly[..., 1] - y_min[..., None] # x_max = torch.max(img_poly[..., 0], dim=-1)[0] # y_max = torch.max(img_poly[..., 1], dim=-1)[0] # h, w = y_max - y_min + 1, x_max - x_min + 1 # long_side = torch.max(h, w) # can_poly = can_poly / long_side[..., None, None] return can_poly