def validation(self, dataloader, use_cuda, verbose=True, prob=1.0, accuracy=False, parameters=None): """ Compute the avaraged loss per event of a generalized Hawkes process given observed sequences and current model :param dataloader: a pytorch batch-based data loader :param use_cuda: use cuda (true) or not (false) """ device = torch.device('cuda:0' if use_cuda else 'cpu') self.lambda_model_validation.to(device) self.lambda_model_validation.eval() Cs = torch.LongTensor( list(range(len(dataloader.dataset.database['type2idx'])))) Cs = Cs.view(-1, 1) Cs = Cs.to(device) if dataloader.dataset.database['event_features'] is not None: all_event_feature = torch.from_numpy( dataloader.dataset.database['event_features']) FCs = all_event_feature.type(torch.FloatTensor) FCs = torch.t(FCs) # (num_type, dim_features) FCs = FCs.to(device) else: FCs = None if not accuracy: start = time.time() loss = 0 prob = np.array([prob]) prob_tensor = torch.from_numpy(prob).type(torch.FloatTensor) with torch.no_grad(): for batch_idx, samples in enumerate(dataloader): ci, batch_dict = samples2dict(samples, device, Cs, FCs) lambda_t, Lambda_t = self.lambda_model_validation( batch_dict) lambda_t /= prob_tensor Lambda_t /= prob_tensor loss += self.loss_function(lambda_t, Lambda_t, ci) # display training processes if verbose: if batch_idx % 100 == 0: logger.info( 'Validation [{}/{} ({:.0f}%)]\t Time={:.2f}sec.' .format(batch_idx * ci.size(0), len(dataloader.dataset), 100. * batch_idx / len(dataloader), time.time() - start)) return loss / len(dataloader.dataset) else: with torch.no_grad(): loss = np.linalg.norm( list(self.lambda_model_validation.parameters()) [1].data.numpy() - parameters) / self.num_type**2 return loss
def validation(self, dataloader, use_cuda): """ Compute the avaraged loss per event of a generalized Hawkes process given observed sequences and current model :param dataloader: a pytorch batch-based data loader :param use_cuda: use cuda (true) or not (false) """ device = torch.device('cuda:0' if use_cuda else 'cpu') self.lambda_model.to(device) self.lambda_model.eval() Cs = torch.LongTensor( list(range(len(dataloader.dataset.database['type2idx'])))) Cs = Cs.view(-1, 1) Cs = Cs.to(device) if dataloader.dataset.database['event_features'] is not None: all_event_feature = torch.from_numpy( dataloader.dataset.database['event_features']) FCs = all_event_feature.type(torch.FloatTensor) FCs = torch.t(FCs) # (num_type, dim_features) FCs = FCs.to(device) else: FCs = None start = time.time() loss = 0 for batch_idx, samples in enumerate(dataloader): ci, batch_dict = samples2dict(samples, device, Cs, FCs) loss = 0 for m in range(self.num_cluster): weight = self.responsibility[batch_dict['sn'][:, 0], m] # (batch_size, ) lambda_t, Lambda_t = self.lambda_model[m](batch_dict) loss_m = self.loss_function(lambda_t, Lambda_t, ci) # (batch_size, ) loss += (weight * loss_m).sum() / loss_m.size(0) # display training processes if batch_idx % 100 == 0: logger.info( 'Validation [{}/{} ({:.0f}%)]\t Time={:.2f}sec.'.format( batch_idx * ci.size(0), len(dataloader.dataset), 100. * batch_idx / len(dataloader), time.time() - start)) return loss / len(dataloader.dataset)
def fit_ot(self, dataloader, optimizer, epochs: int, trans: torch.Tensor, mu_t: torch.Tensor, A_t: torch.Tensor, p_s: torch.Tensor, p_t: torch.Tensor, sample_dict1, sample_dict2, gamma, alpha, scheduler=None, sparsity: float=None, nonnegative=None, use_cuda: bool=False, validation_set=None): """ Learn parameters of a generalized Hawkes process given observed sequences :param dataloader: a pytorch batch-based data loader :param optimizer: the sgd optimization method defined by PyTorch :param epochs: the number of training epochs :param trans: fixed optimal transport :param mu_t: base intensity of target Hawkes process :param A_t: infectivity of target Hawkes process :param p_s: the distribution of event types in source Hawkes process :param p_t: the distribution of event types in target Hawkes process :param scheduler: the method adjusting the learning rate of SGD defined by PyTorch :param sparsity: None or a float weight of L1 regularizer :param nonnegative: None or a float lower bound, typically the lower bound = 0 :param use_cuda: use cuda (true) or not (false) :param validation_set: None or a validation dataloader """ device = torch.device('cuda:0' if use_cuda else 'cpu') self.lambda_model.to(device) best_model = None self.lambda_model.train() if nonnegative is not None: clipper = LowerBoundClipper(nonnegative) Cs = torch.LongTensor(list(range(len(dataloader.dataset.database['type2idx'])))) Cs = Cs.view(-1, 1) Cs = Cs.to(device) if dataloader.dataset.database['event_features'] is not None: all_event_feature = torch.from_numpy(dataloader.dataset.database['event_features']) FCs = all_event_feature.type(torch.FloatTensor) FCs = torch.t(FCs) # (num_type, dim_features) FCs = FCs.to(device) else: FCs = None if validation_set is not None: validation_loss = self.validation(validation_set, use_cuda) logger.info('In the beginning, validation loss per event: {:.6f}.\n'.format(validation_loss)) best_loss = validation_loss else: best_loss = np.inf for epoch in range(epochs): if scheduler is not None: scheduler.step() start = time.time() for batch_idx, samples in enumerate(dataloader): ci, batch_dict = samples2dict(samples, device, Cs, FCs) optimizer.zero_grad() lambda_t, Lambda_t = self.lambda_model(batch_dict) loss = self.loss_function(lambda_t, Lambda_t, ci) / lambda_t.size(0) reg = 0 if sparsity is not None: for parameter in self.lambda_model.parameters(): reg += sparsity * torch.sum(torch.abs(parameter)) base_intensity = self.lambda_model.exogenous_intensity.intensity(sample_dict1) infectivity = self.lambda_model.endogenous_intensity.granger_causality(sample_dict2).squeeze(2) d_gw = self.dgw(infectivity, A_t, trans, p_s, p_t) d_w = self.dw(base_intensity, mu_t, trans, p_s, p_t) loss_total = loss + reg + gamma * (alpha*d_w + (1-alpha)*d_gw) loss_total.backward() optimizer.step() if nonnegative is not None: self.lambda_model.apply(clipper) # display training processes if batch_idx % 100 == 0: logger.info('Train Epoch: {} [{}/{} ({:.0f}%)]'.format( epoch, batch_idx * ci.size(0), len(dataloader.dataset), 100. * batch_idx / len(dataloader))) if sparsity is not None: logger.info('Loss per event: {:.6f}, Regularizer: {:.6f} Time={:.2f}sec'.format( loss.data, reg.data, time.time() - start)) else: logger.info('Loss per event: {:.6f}, Regularizer: {:.6f} Time={:.2f}sec'.format( loss.data, 0, time.time() - start)) if validation_set is not None: validation_loss = self.validation(validation_set, use_cuda) logger.info('After Epoch: {}, validation loss per event: {:.6f}.\n'.format(epoch, validation_loss)) if validation_loss < best_loss: best_model = copy.deepcopy(self.lambda_model) best_loss = validation_loss if best_model is not None: self.lambda_model = copy.deepcopy(best_model)
def fit(self, dataloader, optimizer, epochs: int, scheduler=None, sparsity: float = None, nonnegative=None, use_cuda: bool = False, validation_set=None, verbose=True, prob: float = 1.0, accuracy=False, parameters=None): """ Learn parameters of a generalized Hawkes process given observed sequences :param dataloader: a pytorch batch-based data loader :param optimizer: the sgd optimization method defined by PyTorch :param epochs: the number of training epochs :param scheduler: the method adjusting the learning rate of SGD defined by PyTorch :param sparsity: None or a float weight of L1 regularizer :param nonnegative: None or a float lower bound, typically the lower bound = 0 :param use_cuda: use cuda (true) or not (false) :param validation_set: None or a validation dataloader """ device = torch.device('cuda:0' if use_cuda else 'cpu') self.lambda_model.to(device) best_model = None self.lambda_model.train() self.mu_path.append( copy.deepcopy(list(self.lambda_model.parameters())[0].data)) self.alpha_path.append( copy.deepcopy(list(self.lambda_model.parameters())[1].data)) if nonnegative is not None: clipper = LowerBoundClipper(nonnegative) Cs = torch.LongTensor( list(range(len(dataloader.dataset.database['type2idx'])))) Cs = Cs.view(-1, 1) Cs = Cs.to(device) if dataloader.dataset.database['event_features'] is not None: all_event_feature = torch.from_numpy( dataloader.dataset.database['event_features']) FCs = all_event_feature.type(torch.FloatTensor) FCs = torch.t(FCs) # (num_type, dim_features) FCs = FCs.to(device) else: FCs = None if validation_set is not None: validation_loss = self.validation(validation_set, use_cuda, verbose, prob, accuracy, parameters) logger.info( 'In the beginning, validation loss per event: {:.6f}.\n'. format(validation_loss)) best_loss = validation_loss self.learning_path.append(validation_loss) else: best_loss = np.inf start0 = time.time() self.training_time.append(time.time() - start0) for epoch in range(epochs): if scheduler is not None: scheduler.step() start = time.time() for batch_idx, samples in enumerate(dataloader): ci, batch_dict = samples2dict(samples, device, Cs, FCs) optimizer.zero_grad() lambda_t, Lambda_t = self.lambda_model(batch_dict) loss = self.loss_function(lambda_t, Lambda_t, ci) / lambda_t.size(0) reg = 0 if sparsity is not None: for parameter in self.lambda_model.parameters(): reg += sparsity * torch.sum(torch.abs(parameter)) loss_total = loss + reg loss_total.backward() optimizer.step() if nonnegative is not None: self.lambda_model.apply(clipper) if validation_set is not None: validation_loss = self.validation(validation_set, use_cuda, verbose, prob, accuracy, parameters) if verbose: logger.info( 'After Epoch: {}, validation loss per event: {:.6f}.\n' .format(epoch, validation_loss)) if validation_loss < best_loss: best_model = copy.deepcopy(self.lambda_model) best_loss = validation_loss esti_loss = loss_total.data # display training processes if verbose: if batch_idx % 100 == 0: logger.info('Train Epoch: {} [{}/{} ({:.0f}%)]'.format( epoch, batch_idx * ci.size(0), len(dataloader.dataset), 100. * batch_idx / len(dataloader))) if sparsity is not None: logger.info( 'Loss per event: {:.3f}, Regularizer: {:.3f}, Validate Loss: {:.3f}, Time={:.2f}sec' .format(esti_loss.data, reg.data, validation_loss, time.time() - start)) else: logger.info( 'Loss per event: {:.3f}, Regularizer: {:.3f}, Loss: {:.6f}, Time={:.2f}sec' .format(esti_loss.data, 0, validation_loss, time.time() - start)) self.learning_path.append(loss_total) self.validation_path.append(validation_loss) self.training_time.append(time.time() - start0) self.mu_path.append( copy.deepcopy( list(self.lambda_model.parameters())[0].data)) self.alpha_path.append( copy.deepcopy( list(self.lambda_model.parameters())[1].data)) self.lambda_path.append(lambda_t) self.Lambda_path.append(Lambda_t) logger.info( 'Epoch : {}/{}, Used time: {: .2f} min, Estimated Time to finish: {: .2f} min, train loss: {: .3f}, validation loss: {: .3f}' .format((epoch + 1), epochs, self.training_time[-1] / 60, self.training_time[-1] / 60 / (epoch + 1) * (epochs - epoch - 1), loss_total, validation_loss)) if best_model is not None: self.lambda_model = copy.deepcopy(best_model)
def fit(self, dataloader, optimizer, epochs: int, scheduler=None, sparsity: float = None, nonnegative=None, use_cuda: bool = False, validation_set=None, track_diagnostics=False): """ Learn parameters of a generalized Hawkes process given observed sequences :param dataloader: a pytorch batch-based data loader :param optimizer: the sgd optimization method defined by PyTorch :param epochs: the number of training epochs :param scheduler: the method adjusting the learning rate of SGD defined by PyTorch :param sparsity: None or a float weight of L1 regularizer :param nonnegative: None or a float lower bound, typically the lower bound = 0 :param use_cuda: use cuda (true) or not (false) :param validation_set: None or a validation dataloader :param track_diagnostics: Set to True to return historical loss values and weights. """ device = torch.device('cuda:0' if use_cuda else 'cpu') self.lambda_model.to(device) best_model = None self.lambda_model.train() if nonnegative is not None: clipper = LowerBoundClipper(nonnegative) Cs = torch.LongTensor( list(range(len(dataloader.dataset.database['type2idx'])))) Cs = Cs.view(-1, 1) Cs = Cs.to(device) if dataloader.dataset.database['event_features'] is not None: all_event_feature = torch.from_numpy( dataloader.dataset.database['event_features']) FCs = all_event_feature.type(torch.FloatTensor) FCs = torch.t(FCs) # (num_type, dim_features) FCs = FCs.to(device) else: FCs = None if validation_set is not None: validation_loss = self.validation(validation_set, use_cuda) logger.info( 'In the beginning, validation loss per event: {:.6f}.\n'. format(validation_loss)) best_loss = validation_loss else: best_loss = np.inf if track_diagnostics: self.diagnostics = Diagnostics() for epoch in range(epochs): if scheduler is not None: scheduler.step() start = time.time() for batch_idx, samples in enumerate(dataloader): ci, batch_dict = samples2dict(samples, device, Cs, FCs) optimizer.zero_grad() lambda_t, Lambda_t = self.lambda_model(batch_dict) loss = self.loss_function(lambda_t, Lambda_t, ci) / lambda_t.size(0) reg = 0 if sparsity is not None: for parameter in self.lambda_model.parameters(): reg += sparsity * torch.sum(torch.abs(parameter)) loss_total = loss + reg loss_total.backward() optimizer.step() if nonnegative is not None: self.lambda_model.apply(clipper) if track_diagnostics: self.diagnostics.loss.append(loss.data.item()) self.diagnostics.mu.append( self.lambda_model.exogenous_intensity.emb.weight. squeeze().tolist()) self.diagnostics.alpha.append( self.lambda_model.endogenous_intensity.basis[0].weight. squeeze().tolist()) # display training processes if batch_idx % 100 == 0: logger.info('Train Epoch: {} [{}/{} ({:.0f}%)]'.format( epoch, batch_idx * ci.size(0), len(dataloader.dataset), 100. * batch_idx / len(dataloader))) if sparsity is not None: logger.info( 'Loss per event: {:.6f}, Regularizer: {:.6f} Time={:.2f}sec' .format(loss.data, reg.data, time.time() - start)) else: logger.info( 'Loss per event: {:.6f}, Regularizer: {:.6f} Time={:.2f}sec' .format(loss.data, 0, time.time() - start)) if validation_set is not None: validation_loss = self.validation(validation_set, use_cuda) logger.info( 'After Epoch: {}, validation loss per event: {:.6f}.\n'. format(epoch, validation_loss)) if validation_loss < best_loss: best_model = copy.deepcopy(self.lambda_model) best_loss = validation_loss if best_model is not None: self.lambda_model = copy.deepcopy(best_model)
def fit(self, dataloader, optimizer, epochs: int, scheduler=None, sparsity: float = None, nonnegative=None, use_cuda: bool = False, validation_set=None): """ Learn parameters of a generalized Hawkes process given observed sequences :param dataloader: a pytorch batch-based data loader :param optimizer: the sgd optimization method :param epochs: the number of training epochs :param scheduler: the method adjusting the learning rate of SGD :param sparsity: None or a float weight of L1 regularizer :param nonnegative: None or a float lower bound :param use_cuda: use cuda (true) or not (false) :param validation_set: None or a validation dataloader """ device = torch.device('cuda:0' if use_cuda else 'cpu') self.lambda_model.to(device) self.responsibility = self.responsibility.to(device) self.prob_cluster = self.prob_cluster.to(device) best_model = None self.lambda_model.train() if nonnegative is not None: clipper = LowerBoundClipper(nonnegative) Cs = torch.LongTensor( list(range(len(dataloader.dataset.database['type2idx'])))) Cs = Cs.view(-1, 1) Cs = Cs.to(device) if dataloader.dataset.database['event_features'] is not None: all_event_feature = torch.from_numpy( dataloader.dataset.database['event_features']) FCs = all_event_feature.type(torch.FloatTensor) FCs = torch.t(FCs) # (num_type, dim_features) FCs = FCs.to(device) else: FCs = None if validation_set is not None: validation_loss = self.validation(validation_set, use_cuda) logger.info( 'In the beginning, validation loss per event: {:.6f}.\n'. format(validation_loss)) best_loss = validation_loss else: best_loss = np.inf # EM algorithm for epoch in range(epochs): if scheduler is not None: scheduler.step() start = time.time() log_weight = self.prob_cluster.log().view(1, self.num_cluster).repeat( self.num_sequence, 1) log_responsibility = 0 * self.responsibility num_responsibllity = 0 * self.responsibility log_responsibility = log_responsibility.to(device) num_responsibllity = num_responsibllity.to(device) for batch_idx, samples in enumerate(dataloader): ci, batch_dict = samples2dict(samples, device, Cs, FCs) optimizer.zero_grad() loss = 0 for m in range(self.num_cluster): weight = self.responsibility[batch_dict['sn'][:, 0], m] # (batch_size, ) lambda_t, Lambda_t = self.lambda_model[m](batch_dict) loss_m = self.loss_function(lambda_t, Lambda_t, ci) # (batch_size, ) loss += (weight * loss_m).sum() / loss_m.size(0) for i in range(loss_m.size(0)): sn = batch_dict['sn'][i, 0] log_responsibility[sn, m] += loss_m.data[i] num_responsibllity[sn, m] += 1 reg = 0 if sparsity is not None: for parameter in self.lambda_model.parameters(): reg += sparsity * torch.sum(torch.abs(parameter)) loss_total = loss + reg loss_total.backward() optimizer.step() if nonnegative is not None: self.lambda_model.apply(clipper) # display training processes if batch_idx % 100 == 0: logger.info('Train Epoch: {} [{}/{} ({:.0f}%)]'.format( epoch, batch_idx * ci.size(0), len(dataloader.dataset), 100. * batch_idx / len(dataloader))) if sparsity is not None: logger.info( 'Loss per event: {:.6f}, Regularizer: {:.6f} Time={:.2f}sec' .format(loss.data, reg.data, time.time() - start)) else: logger.info( 'Loss per event: {:.6f}, Regularizer: {:.6f} Time={:.2f}sec' .format(loss.data, 0, time.time() - start)) logger.info('Distribution of clusters') for m in range(self.num_cluster): logger.info('Cluster {}, prob={:.6f}'.format( m, self.prob_cluster[m])) # update responsibility log_responsibility /= (num_responsibllity + 1e-7) self.responsibility = F.softmax(log_responsibility + log_weight, dim=1) self.prob_cluster = self.responsibility.sum(0) self.prob_cluster = self.prob_cluster / self.prob_cluster.sum() if validation_set is not None: validation_loss = self.validation(validation_set, use_cuda) logger.info( 'After Epoch: {}, validation loss per event: {:.6f}.\n'. format(epoch, validation_loss)) if validation_loss < best_loss: best_model = copy.deepcopy(self.lambda_model) best_loss = validation_loss if best_model is not None: self.lambda_model = copy.deepcopy(best_model)