def __init__(self, num_units, adj_mx, max_diffusion_step, num_nodes, num_proj=None, activation=tf.nn.tanh, reuse=None, filter_type="laplacian", use_gc_for_ru=True): """ :param num_units: :param adj_mx: :param max_diffusion_step: :param num_nodes: :param input_size: :param num_proj: :param activation: :param reuse: :param filter_type: "laplacian", "random_walk", "dual_random_walk". :param use_gc_for_ru: whether to use Graph convolution to calculate the reset and update gates. """ super(DCGRUCell, self).__init__(_reuse=reuse) self._activation = activation self._num_nodes = num_nodes self._num_proj = num_proj self._num_units = num_units self._max_diffusion_step = max_diffusion_step self._supports = [] self._use_gc_for_ru = use_gc_for_ru supports = [] if filter_type == "laplacian": supports.append(utils.calculate_scaled_laplacian(adj_mx, lambda_max=None)) elif filter_type == "random_walk": supports.append(utils.calculate_random_walk_matrix(adj_mx).T) elif filter_type == "dual_random_walk": supports.append(utils.calculate_random_walk_matrix(adj_mx).T) supports.append(utils.calculate_random_walk_matrix(adj_mx.T).T) else: supports.append(utils.calculate_scaled_laplacian(adj_mx)) for support in supports: self._supports.append(self._build_sparse_matrix(support))
def __init__(self, num_units, adj_mx, max_diffusion_step, num_nodes, num_proj=None, activation=tf.nn.tanh, reuse=None, filter_type="laplacian", use_gc_for_ru=True, **kwargs): super(DCLSTMCell, self).__init__(**kwargs) self._activation = activation self._num_nodes = num_nodes self._num_proj = num_proj self._num_units = num_units self._max_diffusion_step = max_diffusion_step self._supports = [] self._use_gc_for_ru = use_gc_for_ru supports = [] if filter_type == "laplacian": supports.append( utils.calculate_scaled_laplacian(adj_mx, lambda_max=None)) elif filter_type == "random_walk": supports.append(utils.calculate_random_walk_matrix(adj_mx).T) elif filter_type == "dual_random_walk": supports.append(utils.calculate_random_walk_matrix(adj_mx).T) supports.append(utils.calculate_random_walk_matrix(adj_mx.T).T) else: supports.append(utils.calculate_scaled_laplacian(adj_mx)) for support in supports: self._supports.append(self._build_sparse_matrix(support))
def __init__(self, input_dim, num_units, adj_mat, max_diffusion_step, num_nodes, num_proj=None, activation=torch.tanh, use_gc_for_ru=True, filter_type='laplacian'): """ :param num_units: the hidden dim of rnn :param adj_mat: the (weighted) adjacency matrix of the graph, in numpy ndarray form :param max_diffusion_step: the max diffusion step :param num_nodes: :param num_proj: num of output dim, defaults to 1 (speed) :param activation: if None, don't do activation for cell state :param use_gc_for_ru: decide whether to use graph convolution inside rnn """ super(DCGRUCell, self).__init__() self._activation = activation self._num_nodes = num_nodes self._num_units = num_units self._max_diffusion_step = max_diffusion_step self._num_proj = num_proj self._use_gc_for_ru = use_gc_for_ru self._supports = [] supports = [] if filter_type == "laplacian": supports.append( utils.calculate_scaled_laplacian(adj_mat, lambda_max=None)) elif filter_type == "random_walk": supports.append(utils.calculate_random_walk_matrix(adj_mat).T) elif filter_type == "dual_random_walk": supports.append(utils.calculate_random_walk_matrix(adj_mat)) supports.append(utils.calculate_random_walk_matrix(adj_mat.T)) else: supports.append(utils.calculate_scaled_laplacian(adj_mat)) for support in supports: self._supports.append(self._build_sparse_matrix( support).cuda()) # to PyTorch sparse tensor # supports = utils.calculate_scaled_laplacian(adj_mat, lambda_max=None) # scipy coo matrix # self._supports = self._build_sparse_matrix(supports).cuda() # to pytorch sparse tensor self.dconv_gate = DiffusionGraphConv( supports=self._supports, input_dim=input_dim, hid_dim=num_units, num_nodes=num_nodes, max_diffusion_step=max_diffusion_step, output_dim=num_units * 2) self.dconv_candidate = DiffusionGraphConv( supports=self._supports, input_dim=input_dim, hid_dim=num_units, num_nodes=num_nodes, max_diffusion_step=max_diffusion_step, output_dim=num_units) if num_proj is not None: self.project = nn.Linear(self._num_units, self._num_proj)
def __init__(self, num_units, adj_mx, max_diffusion_step, num_nodes, batch_size, num_proj=None, activation=tf.nn.tanh, reuse=None, filter_type="laplacian", use_gc_for_ru=True): """ :param num_units: :param adj_mx: :param max_diffusion_step: :param num_nodes: :param input_size: :param num_proj: :param activation: :param reuse: :param filter_type: "laplacian", "random_walk", "dual_random_walk". :param use_gc_for_ru: whether to use Graph convolution to calculate the reset and update gates. """ super(DCLSTMCellAtt, self).__init__(_reuse=reuse) self._activation = activation self._num_nodes = num_nodes self._num_proj = num_proj self._num_units = num_units self._max_diffusion_step = max_diffusion_step self._supports = [] self._use_gc_for_ru = use_gc_for_ru supports = [] if filter_type == "laplacian": supports.append( utils.calculate_scaled_laplacian(adj_mx, lambda_max=None)) elif filter_type == "random_walk": supports.append(utils.calculate_random_walk_matrix(adj_mx).T) elif filter_type == "dual_random_walk": supports.append(utils.calculate_random_walk_matrix(adj_mx).T) supports.append(utils.calculate_random_walk_matrix(adj_mx.T).T) else: supports.append(utils.calculate_scaled_laplacian(adj_mx)) for support in supports: self._supports.append(self._build_sparse_matrix(support)) self._bias_mt = tf.convert_to_tensor(utils.adj_to_bias(np.expand_dims( adj_mx, axis=0), [self._num_nodes], nhood=1), dtype=tf.float32) _adj_mx = tf.convert_to_tensor(adj_mx) self._adj_mx_repeat = tf.tile(tf.expand_dims(_adj_mx, axis=0), [batch_size, 1, 1]) for support in self._supports: self._supports_dense.append(tf.sparse.to_dense(support))
def __init__(self, input_dim, num_units, adj_mat, max_diffusion_step, num_nodes, num_proj=None, activation=torch.tanh, use_gc_for_ru=True): """ :param num_units: the hidden dim of rnn :param adj_mat: the (weighted) adjacency matrix of the graph, in numpy ndarray form :param max_diffusion_step: the max diffusion step :param num_nodes: :param num_proj: num of output dim, defaults to 1 (speed) :param activation: if None, don't do activation for cell state :param use_gc_for_ru: decide whether to use graph convolution inside rnn """ super(DCGRUCell, self).__init__() self._activation = activation self._num_nodes = num_nodes self._num_units = num_units self._max_diffusion_step = max_diffusion_step self._num_proj = num_proj self._use_gc_for_ru = use_gc_for_ru supports = utils.calculate_scaled_laplacian(adj_mat, lambda_max=None) # scipy coo matrix self._supports = self._build_sparse_matrix(supports).cuda() # to pytorch sparse tensor # self.register_parameter('weight', None) # self.register_parameter('biases', None) # temp_inputs = torch.FloatTensor(torch.rand((batch_size, num_nodes * input_dim))) # temp_state = torch.FloatTensor(torch.rand((batch_size, num_nodes * num_units))) # self.forward(temp_inputs, temp_state) self.dconv_gate = DiffusionGraphConv(supports=self._supports, input_dim=input_dim, hid_dim=num_units, num_nodes=num_nodes, max_diffusion_step=max_diffusion_step, output_dim=num_units*2) self.dconv_candidate = DiffusionGraphConv(supports=self._supports, input_dim=input_dim, hid_dim=num_units, num_nodes=num_nodes, max_diffusion_step=max_diffusion_step, output_dim=num_units) if num_proj is not None: self.project = nn.Linear(self._num_units, self._num_proj)
def __init__(self, num_units, adj_mx, max_diffusion_step, num_nodes, network_type, graphEmbedFile, num_proj=None, activation=tf.nn.tanh, reuse=None, filter_type="laplacian"): """ :param num_units: :param adj_mx: :param max_diffusion_step: :param num_nodes: :param input_size: :param num_proj: :param activation: :param reuse: :param filter_type: "laplacian", "random_walk", "dual_random_walk". :param use_gc_for_ru: whether to use Graph convolution to calculate the reset and update gates. """ super(DCGRUCell, self).__init__(_reuse=reuse) self._activation = activation self._num_nodes = num_nodes self._num_proj = num_proj self._num_units = num_units # print(num_nodes, num_proj, num_units) # 207 None 64: when creating cell # 207 1 64: when creating cell_with_projection self._max_diffusion_step = max_diffusion_step self._supports = [] self._use_gc_for_ru = (network_type=='gconv') self._graphEmbedFile = graphEmbedFile supports = [] if filter_type == "laplacian": supports.append(utils.calculate_scaled_laplacian(adj_mx, lambda_max=None)) elif filter_type == "random_walk": supports.append(utils.calculate_random_walk_matrix(adj_mx).T) elif filter_type == "dual_random_walk": # supports have now two matrices for the two directions # all of them are of form D^{-1}W supports.append(utils.calculate_random_walk_matrix(adj_mx).T) supports.append(utils.calculate_random_walk_matrix(adj_mx.T).T) else: supports.append(utils.calculate_scaled_laplacian(adj_mx)) # print('This is the number of matrices: ', len(supports)) # 2 # There are 2 matrices for bi-directional random walk # Hence either one or two matrices will be in list of supports for support in supports: self._supports.append(self._build_sparse_matrix(support))
def __init__(self, num_units, adj_mx, max_diffusion_step, num_nodes, nonlinearity='tanh', filter_type="laplacian", use_gc_for_ru=True): """ :param num_units: :param adj_mx: :param max_diffusion_step: :param num_nodes: :param nonlinearity: :param filter_type: "laplacian", "random_walk", "dual_random_walk". :param use_gc_for_ru: whether to use Graph convolution to calculate the reset and update gates. """ super().__init__() self._activation = torch.tanh if nonlinearity == 'tanh' else torch.relu # support other nonlinearities up here? self._num_nodes = num_nodes self._num_units = num_units self._max_diffusion_step = max_diffusion_step self._supports = [] self._use_gc_for_ru = use_gc_for_ru self._mfd = PoincareManifold() supports = [] if filter_type == "laplacian": supports.append( utils.calculate_scaled_laplacian(adj_mx, lambda_max=None)) elif filter_type == "random_walk": supports.append(utils.calculate_random_walk_matrix(adj_mx).T) elif filter_type == "dual_random_walk": supports.append(utils.calculate_random_walk_matrix(adj_mx).T) supports.append(utils.calculate_random_walk_matrix(adj_mx.T).T) else: supports.append(utils.calculate_scaled_laplacian(adj_mx)) for support in supports: self._supports.append(self._build_sparse_matrix(support)) self._fc_params = LayerParams(self, 'fc') self._gconv_params = LayerParams(self, 'gconv')
def _valid_epoch(self, epoch): """ Validate after training an epoch :return: A log that contains information about validation Note: The validation metrics in log must have the key 'val_metrics'. """ self.model.eval() total_val_loss = 0 total_val_metrics = np.zeros(len(self.metrics)) with torch.no_grad(): for batch_idx, (data, target, adj_mat) in enumerate( self.valid_data_loader.get_iterator()): data = torch.FloatTensor(data) target = torch.FloatTensor(target) label = target[ ..., :self.model. output_dim] # (..., 1) supposed to be numpy array data, target = data.to(self.device), target.to(self.device) # construct the adj_mat here adj_mat = utils.calculate_scaled_laplacian( adj_mat, lambda_max=None) # scipy coo matrix adj_mat = self._build_sparse_matrix( adj_mat) # to PyTorch sparse tensor adj_mat = adj_mat.to(self.device) output = self.model(data, target, adj_mat, 0) output = torch.transpose( output.view(12, self.model.batch_size, self.model.num_nodes, self.model.output_dim), 0, 1) # back to (50, 12, 207, 1) loss = self.loss(output.cpu(), label) self.writer.set_step( (epoch - 1) * self.val_len_epoch + batch_idx, 'valid') self.writer.add_scalar('loss', loss.item()) total_val_loss += loss.item() total_val_metrics += self._eval_metrics( output.detach().numpy(), label.numpy()) # self.writer.add_image('input', make_grid(data.cpu(), nrow=8, normalize=True)) # add histogram of model parameters to the tensorboard for name, p in self.model.named_parameters(): self.writer.add_histogram(name, p, bins='auto') return { 'val_loss': total_val_loss / self.val_len_epoch, 'val_metrics': (total_val_metrics / self.val_len_epoch).tolist() }
def __init__(self, num_units, adj_mx, max_diffusion_step, num_nodes, num_proj=None, activation=tf.nn.tanh, reuse=None, filter_type="laplacian", use_gc_for_ru=True, output_activation=None, proximity_threshold=None): """ :param num_units: :param adj_mx: :param max_diffusion_step: :param num_nodes: :param input_size: :param num_proj: :param activation: :param reuse: :param filter_type: "laplacian", "random_walk", "dual_random_walk". :param use_gc_for_ru: whether to use Graph convolution to calculate the reset and update gates. """ super(DCGRUCell, self).__init__(_reuse=reuse) self._activation = activation self._output_activation = output_activation self._num_nodes = num_nodes self._num_proj = num_proj self._num_units = num_units self._max_diffusion_step = max_diffusion_step self._use_gc_for_ru = use_gc_for_ru self.id_mx = utils.calculate_identity(adj_mx) self._supports = [] supports = [] adj_mx[adj_mx < proximity_threshold] = 0 # adj_mx[adj_mx < proximity_threshold['end_proximity']] = 0 # self.proximity_threshold = proximity_threshold # self.pct_adj_mx = percentile_nd(adj_mx).astype(np.float32) if filter_type == "laplacian": supports.append( utils.calculate_scaled_laplacian(adj_mx, lambda_max=None)) elif filter_type == "laplacian_lambda_max_2": supports.append( utils.calculate_scaled_laplacian(adj_mx, lambda_max=2)) elif filter_type == "laplacian_lambda_max_1": supports.append( utils.calculate_scaled_laplacian(adj_mx, lambda_max=1)) elif filter_type == "random_walk": supports.append(utils.calculate_random_walk_matrix(adj_mx).T) elif filter_type == "dual_random_walk": supports.append(utils.calculate_random_walk_matrix(adj_mx).T) supports.append(utils.calculate_random_walk_matrix(adj_mx.T).T) elif filter_type == "ignore_spatial_dependency": supports.append(self.id_mx) else: raise ValueError("Invalid filter_type: {}".format(filter_type)) for support in supports: # support = np.asarray(support.todense()) # threshold = \ # linear_cosine_decay_start_end(start=self.proximity_threshold['start_proximity'], # end=self.proximity_threshold['end_proximity'], # global_step=tf.train.get_or_create_global_step(), # decay_steps=self.proximity_threshold['proximity_decay_steps'], # ) # support = thresholded_dense_to_sparse(support, self.pct_adj_mx, threshold=threshold) # # self._supports.append(support) self._supports.append(self._build_sparse_matrix(support))
def _train_epoch(self, epoch): """ Training logic for an epoch :param epoch: Current training epoch. :return: A log that contains all information you want to save. Note: If you have additional information to record, for example: > additional_log = {"x": x, "y": y} merge it with log before return. i.e. > log = {**log, **additional_log} > return log The metrics in log must have the key 'metrics'. """ self.model.train() total_loss = 0 total_metrics = np.zeros(len(self.metrics)) for batch_idx, (data, target, adj_mat) in enumerate(self.data_loader.get_iterator()): data = torch.FloatTensor(data) target = torch.FloatTensor(target) label = target[..., :self.model. output_dim] # (..., 1) supposed to be numpy array data, target = data.to(self.device), target.to(self.device) # construct the adj_mat here adj_mat = utils.calculate_scaled_laplacian( adj_mat, lambda_max=None) # scipy coo matrix adj_mat = self._build_sparse_matrix( adj_mat) # to PyTorch sparse tensor adj_mat = adj_mat.to(self.device) self.optimizer.zero_grad() # compute sampling ratio, which gradually decay to 0 during training global_step = (epoch - 1) * self.len_epoch + batch_idx teacher_forcing_ratio = self._compute_sampling_threshold( global_step, self.cl_decay_steps) output = self.model(data, target, adj_mat, teacher_forcing_ratio) output = torch.transpose( output.view(12, self.model.batch_size, self.model.num_nodes, self.model.output_dim), 0, 1) # back to (50, 12, 207, 1) loss = self.loss(output.cpu(), label) # loss is self-defined, need cpu input loss.backward() # add max grad clipping torch.nn.utils.clip_grad_norm_(self.model.parameters(), self.max_grad_norm) self.optimizer.step() self.writer.set_step((epoch - 1) * self.len_epoch + batch_idx) self.writer.add_scalar('loss', loss.item()) total_loss += loss.item() total_metrics += self._eval_metrics(output.detach().numpy(), label.numpy()) if batch_idx % self.log_step == 0: self.logger.debug('Train Epoch: {} {} Loss: {:.6f}'.format( epoch, self._progress(batch_idx), loss.item())) if batch_idx == self.len_epoch: break log = { 'loss': total_loss / self.len_epoch, 'metrics': (total_metrics / self.len_epoch).tolist() } if self.do_validation: val_log = self._valid_epoch(epoch) log.update(val_log) if self.lr_scheduler is not None: self.lr_scheduler.step() return log
def __init__(self, args, num_units, adj_mx, squeeze_and_excitation, se_activate, excitation_rate, r, diffusion_with_graph_kernel, graph_kernel_mode, cell_forward_mode, max_diffusion_step, num_nodes, num_proj=None, activation=tf.nn.tanh, reuse=None, filter_type="laplacian", use_gc_for_ru=True): """ :param num_units: :param adj_mx: :param max_diffusion_step: :param num_nodes: :param input_size: :param num_proj: :param activation: :param reuse: :param filter_type: "laplacian", "random_walk", "dual_random_walk". :param use_gc_for_ru: whether to use Graph convolution to calculate the reset and update gates. """ super(DCGRUCell, self).__init__(_reuse=reuse) self._activation = activation self._num_nodes = num_nodes #self._num_edges = np.sum(adj_mx!=0) self.mask_mx = adj_mx != 0 self._num_proj = num_proj self._num_units = num_units self._max_diffusion_step = max_diffusion_step self._supports = [] self._use_gc_for_ru = use_gc_for_ru self.squeeze_and_excitation = squeeze_and_excitation self.se_activate = se_activate self.excitation_rate = excitation_rate self.r = r self.cell_forward_mode = cell_forward_mode self.diffusion_channel_num = args.diffusion_channel_num self.diffusion_with_graph_kernel = diffusion_with_graph_kernel self.graph_kernel_mode = graph_kernel_mode supports = [] print('adj_mx: ', adj_mx.shape) if filter_type == "laplacian": supports.append( utils.calculate_scaled_laplacian(adj_mx, lambda_max=None)) elif filter_type == "random_walk": supports.append(utils.calculate_random_walk_matrix(adj_mx).T) elif filter_type == "dual_random_walk": supports.append(utils.calculate_random_walk_matrix(adj_mx).T) supports.append(utils.calculate_random_walk_matrix(adj_mx.T).T) else: supports.append(utils.calculate_scaled_laplacian(adj_mx)) for support in supports: self._supports.append(self._build_sparse_matrix(support)) self._kernel_inds = self.kernel_ind(supports) self.mask_mx_ind = self.mask_ind(supports)