def visualize_attention_weights(self, epoch): """ Visualize attention of the model saved during an epoch :param epoch: The epoch """ #TODO: Add a node name mapping for easily readable visualization nodes = self._args.nodes assert len(nodes) == 2 src, trg = nodes utils.log( f"Generating attention weight visualization between source = {src} and target = {trg} nodes" ) self._load_best_model(best_epoch=epoch) batch = { "source_neighborhood": self._neighborhood[src].unsqueeze(0), "target_neighborhood": self._neighborhood[trg].unsqueeze(0), "source_mask": self._mask[src].unsqueeze(0), "target_mask": self._mask[trg].unsqueeze(0), } self._model(**utils.to(batch, self._device)) src_mask = self._mask[src] == 0 trg_mask = self._mask[trg] == 0 source_atn = self._model.source_atn.squeeze().detach().cpu().numpy( )[src_mask] target_atn = self._model.target_atn.squeeze().detach().cpu().numpy( )[trg_mask] source_nbh = batch["source_neighborhood"].squeeze()[src_mask] target_nbh = batch["source_neighborhood"].squeeze()[trg_mask] params = self._params data_dir = osp.join( params["root"], params["name"]) if "name" in params else params["root"] src_path = osp.join(data_dir, "results", f"source_atn_vis_{src}.html") trg_path = osp.join(data_dir, "results", f"target_atn_vis_{trg}.html") utils.visualize_attention_weights(path=src_path, neighborhood=source_nbh, weights=source_atn, node_id=src) utils.visualize_attention_weights(path=trg_path, neighborhood=target_nbh, weights=target_atn, node_id=trg)
def _fit(self, loader): """ Fits the GOAT model using data from a specified loader :param loader: The loader """ sources, targets, source_atn, target_atn, source_features, target_features = [], [], [], [], [], [] for bc, batch in self._test_loader: sources.append(batch["source"].cpu().numpy()) targets.append(batch["target"].cpu().numpy()) true_source_feature, true_target_feature, _, _ = self._model( **utils.to(batch, self._device)) source_atn.append( self._model.source_atn.squeeze().detach().cpu().numpy()) target_atn.append( self._model.target_atn.squeeze().detach().cpu().numpy()) source_features.append(true_source_feature.detach().cpu().numpy()) target_features.append(true_target_feature.detach().cpu().numpy()) sources = np.concatenate(sources) targets = np.concatenate(targets) source_atn = np.concatenate([ utils.expand_if(atn_v, 0, len(atn_v.shape) == 1) for atn_v in source_atn ]) target_atn = np.concatenate([ utils.expand_if(atn_v, 0, len(atn_v.shape) == 1) for atn_v in target_atn ]) true_source_feature = np.concatenate([ utils.expand_if(f, 0, len(f.shape) == 1) for f in source_features ]) true_target_feature = np.concatenate([ utils.expand_if(f, 0, len(f.shape) == 1) for f in target_features ]) return sources, targets, source_atn, target_atn, true_source_feature, true_target_feature
def _fit_false_pairs(self, num_false_samples=None): """ Inference using false pairs. Useful for validating and testing the quality of link prediction. :param num_false_samples: The number of false pairs. """ if num_false_samples: false_pairs = self._negative_pairs[:num_false_samples] else: false_pairs = self._negative_pairs num_false_samples = false_pairs.shape[0] source_features, target_features = [], [] batch_size = self._args.batch for i in range(0, num_false_samples, batch_size): end = i + batch_size if num_false_samples - batch_size > i else num_false_samples false_data = { "source_neighborhood": self._neighborhood[self._negative_pairs[i:end, 0]], "target_neighborhood": self._neighborhood[self._negative_pairs[i:end, 1]], "source_mask": self._mask[self._negative_pairs[i:end, 0]], "target_mask": self._mask[self._negative_pairs[i:end, 1]], } false_source_feature, false_target_feature, _, _ = self._model( **utils.to(false_data, self._device)) source_features.append(false_source_feature.detach().cpu().numpy()) target_features.append(false_target_feature.detach().cpu().numpy()) false_source_feature = np.concatenate([ utils.expand_if(f, 0, len(f.shape) == 1) for f in source_features ]) false_target_feature = np.concatenate([ utils.expand_if(f, 0, len(f.shape) == 1) for f in target_features ]) return false_source_feature, false_target_feature
# Higher level interface for interacting with specific classes of events import pyalm as alm import cleanup from utils import dictmapper, MappingRule as to ContributorBase = dictmapper( 'ContributorBase', { 'contributor_role': ['contributor_role'], 'first_author': to(['first_author'], cleanup._text_to_bool), 'given_name': ['given_name'], 'sequence': ['sequence'], 'surname': ['surname'] }) class Contributor(ContributorBase): def __repr__(self): return '<%s: %s%s>' % (type(self).__name__, self.given_name, self.surname) CrossrefBase = dictmapper( 'CrossrefBase', { 'article_title': ['event', 'article_title'], 'doi': ['event', 'doi'], 'fl_count': to(['event', 'fl_count'], cleanup._parse_numbers_to_int), 'issn': ['event', 'issn'], 'journal_abbreviation': ['event', 'journal_abbreviation'], 'journal_title': ['event', 'journal_title'], 'publication_type': ['event', 'publication_type'],
import requests from utils import dictmapper, MappingRule as to import cleanup import config BASE_HEADERS = {'Accept': 'application/json'} MetricsBase = dictmapper( 'MetricsBase', { 'citations': to(['citations'], cleanup._parse_numbers_to_int), 'comments': to(['comments'], cleanup._parse_numbers_to_int), 'html': to(['html'], cleanup._parse_numbers_to_int), 'likes': to(['likes'], cleanup._parse_numbers_to_int), 'pdf': to(['pdf'], cleanup._parse_numbers_to_int), 'readers': to(['readers'], cleanup._parse_numbers_to_int), 'shares': to(['shares'], cleanup._parse_numbers_to_int), 'total': to(['total'], cleanup._parse_numbers_to_int) }) class Metrics(MetricsBase): def __repr__(self): return """ <%s total:%s readers:%s pdf:%s html:%s comments:%s likes:%s> """ % (type(self).__name__, self.total, self.readers, self.pdf, self.html, self.comments, self.likes) SourceBase = dictmapper( 'SourceBase', { 'name': ['name'],
# Higher level interface for interacting with specific classes of events import pyalm as alm import cleanup from utils import dictmapper, MappingRule as to ContributorBase = dictmapper('ContributorBase', { 'contributor_role' : ['contributor_role'], 'first_author': to(['first_author'], cleanup._text_to_bool), 'given_name': ['given_name'], 'sequence': ['sequence'], 'surname': ['surname'] } ) class Contributor(ContributorBase): def __repr__(self): return '<%s: %s%s>' % (type(self).__name__, self.given_name, self.surname) CrossrefBase = dictmapper('CrossrefBase', { 'article_title' : ['event','article_title'], 'doi' : ['event','doi'], 'fl_count' : to(['event','fl_count'], cleanup._parse_numbers_to_int), 'issn' : ['event','issn'], 'journal_abbreviation' : ['event','journal_abbreviation'], 'journal_title' : ['event','journal_title'], 'publication_type' : ['event','publication_type'],
import requests from utils import dictmapper, MappingRule as to import cleanup import config BASE_HEADERS = {'Accept': 'application/json'} MetricsBase = dictmapper('MetricsBase', {'citations': to(['citations'], cleanup._parse_numbers_to_int), 'comments': to(['comments'], cleanup._parse_numbers_to_int), 'html': to(['html'], cleanup._parse_numbers_to_int), 'likes': to(['likes'], cleanup._parse_numbers_to_int), 'pdf': to(['pdf'], cleanup._parse_numbers_to_int), 'readers': to(['readers'], cleanup._parse_numbers_to_int), 'shares': to(['shares'], cleanup._parse_numbers_to_int), 'total': to(['total'], cleanup._parse_numbers_to_int) } ) class Metrics(MetricsBase): def __repr__(self): return """
# Higher level interface for interacting with specific classes of events import pyalm as alm import cleanup from utils import dictmapper, MappingRule as to ContributorBase = dictmapper('ContributorBase', { 'contributor_role' : ['contributor_role'], 'first_author': to(['first_author'], cleanup._text_to_bool), 'given_name': ['given_name'], 'sequence': ['sequence'], 'surname': ['surname'] } ) class Contributor(ContributorBase): def __repr__(self): return '<%s: %s%s>' % (type(self).__name__, self.given_name, self.surname) CitationBase = dictmapper('CitationBase', { 'article_title' : ['event','article_title'], 'doi' : ['event','doi'], 'fl_count' : to(['event','fl_count'], cleanup._parse_numbers_to_int), 'issn' : ['event','issn'], 'journal_abbreviation' : ['event','journal_abbreviation'], 'journal_title' : ['event','journal_title'], 'publication_type' : ['event','publication_type'],
import requests from utils import dictmapper, MappingRule as to import cleanup import config BASE_HEADERS = {'Accept': 'application/json'} MetricsBase = dictmapper('MetricsBase', {'citations': to(['citations'], cleanup._parse_numbers_to_int), 'comments': to(['comments'], cleanup._parse_numbers_to_int), 'groups': to(['groups'], cleanup._parse_numbers_to_int), 'likes': to(['likes'], cleanup._parse_numbers_to_int), 'pdf': to(['pdf'], cleanup._parse_numbers_to_int), 'shares': to(['shares'], cleanup._parse_numbers_to_int), 'total': to(['total'], cleanup._parse_numbers_to_int) } ) class Metrics(MetricsBase): def __repr__(self): return """ <%s total:%s shares:%s citations:%s comments:%s> """ % (type(self).__name__, self.total, self.shares, self.citations, self.comments)
def fit(self, trainloader, validloader, num_epochs=1000): # . . logs logs = {} # . . number of batches num_train_batch = len(trainloader) num_valid_batch = len(validloader) # . . register num batches to logs logs['num_train_batch'] = num_train_batch logs['num_valid_batch'] = num_valid_batch # . . # . . set the callback handler callback_handler = CallbackHandler(self.callbacks) # . . keep track of the losses train_losses = [] valid_losses = [] # . . call the callback function on_train_begin(): load the best model callback_handler.on_train_begin(logs=logs, model=self.model) for epoch in range(num_epochs): #scheduler.step() train_loss = 0. valid_loss = 0. # . . activate the training mode self.model.train() # . . get the next batch of training data for batch, (center, left, right) in enumerate(trainloader): # . . the training loss for the current batch batch_loss = 0. # . . send the batch to GPU center, left, right = utils.to(center, self.device), utils.to(left, self.device), utils.to(right, self.device) # . . zero the parameter gradients self.optimizer.zero_grad() # . . iterate over cameras cameras = [center, left, right] for camera in cameras: image, steering = camera # . . feed-forward network to predict the steering angle angle = self.model(image) #log_angle = torch.log10(1.0 + angle) # . . calculate the loss function loss = self.criterion(angle, steering.unsqueeze(1)) # . . backpropagate the loss #loss.backward() # . . backpropogate the scaled physics loss with amp.scale_loss(loss, self.optimizer) as scaled_loss: scaled_loss.backward() # . . update weights self.optimizer.step() # . . training loss for the current batch: accumulate over cameras batch_loss += loss.item() # . . accumulate the training loss train_loss += loss.item() # . . register the batch training loss logs['batch_loss'] = batch_loss # . . call the callback functions on_epoch_end() callback_handler.on_batch_end(batch, logs=logs, model=self.model) # . . activate the evaluation (validation) mode self.model.eval() # . . turn off the gradient for performance with torch.set_grad_enabled(False): # . . get the next batch of validation data for batch, (center, left, right) in enumerate(validloader): # . . send the batch to GPU center, left, right = utils.to(center, self.device), utils.to(left, self.device), utils.to(right, self.device) # . . iterate over cameras cameras = [center, left, right] for camera in cameras: image, steering = camera # . . feed-forward network to predict the steering angle angle = self.model(image) # . . calculate the loss function loss = self.criterion(angle, steering.unsqueeze(1)) # . . accumulate the training loss valid_loss += loss.item() # . . normalize the training and validation losses train_loss /= (num_train_batch*3) valid_loss /= (num_valid_batch*3) # . . on epoch end train_losses.append(train_loss) valid_losses.append(valid_loss) # . . update the epoch statistics (logs) logs["train_loss"] = train_loss logs["valid_loss"] = valid_loss # . . call the callback functions on_epoch_end() callback_handler.on_epoch_end(epoch, logs=logs, model=self.model) # . . check if the training should continue if self.model._stop_training: break # . . call the callback function on_train_end(): load the best model callback_handler.on_train_end(logs=logs, model=self.model) return train_losses, valid_losses