class Actor(): """ Create an agent and set it up for Proximal Policy Optimization """ maxGradientNormilization = 0.5 clipParameter = 0.1 bufferSize = 2500 batchSize = 128 epoch = 10 def __init__(self, outputModel, inputModel, discount=0.99, framesPerState=8, trainingMode=False, hwDevice='cpu'): """ The actor constructor Parameters ------- outputModel : string the path to where the output model should be saved, excluding the file extension. inputModel : string the path, including file extension to the input model. discount : float The discount factor. framesPerState : int Number of frames per state. trainingMode: : boolean Whether this Actor is used for training or predicting. hwDevice : string, CPU or CUDA (whether to offload to GPU or use the CPU). """ self.hardwareDevice = hwDevice self.trainingMode = trainingMode self.inputPath = inputModel self.outputPath = outputModel self.discount = discount self.transition = np.dtype([ ('s', np.float64, (framesPerState, 96, 96)), ('matrix_a', np.float64, (3, )), ('coefficient', np.float64), ('slice_to_concat', np.float64), ('index_exp ', np.float64, (framesPerState, 96, 96)) ]) self.nn = NN().double().to(self.hardwareDevice) self.buffer = np.empty(self.bufferSize, dtype=self.transition) self.optimizer = optim.Adam(self.nn.parameters(), lr=1e-3) self.trainingStep = 0 self.counter = 0 def saveModel(self): """ Save a model to a pytorch PKL file Raises ------- AssertionError Raised if the output path hasn't been provided Notes ------- `self.outputPath` has to be provided WITHOUT a file extension. """ assert self.outputPath != None, "You haven't given an output path!" path = f"{self.outputPath}" while (True): if (not os.path.exists(f'{path}.pkl')): filename = f'{self.outputPath}.pkl' torch.save(self.nn.state_dict(), filename) break else: path = f'{path}-new' def loadModel(self): """ Load a model from a pytorch PKL file Raises ------- AssertionError Raised if the given model path doesn't exist in the filesystem Notes: ------- `self.inputPath` is a path to a model file INCLUDING it's file extension (usually `.pkl`) """ if not self.inputPath: print( 'No input model argument was given, starting point is now set to untrained.' ) return assert os.path.exists( self.inputPath), "The given model path doesn't exist!" self.nn.load_state_dict(torch.load(self.inputPath)) def chooseAction(self, state): """ Choose an action to perform on the track Parameters ------- state: The current state of the car. Returns ------- action : np.ndarray An action for the network to run on the track Notes ------- This function is only called when the --train flag is NOT provided. """ state = torch.from_numpy(state).double().to( self.hardwareDevice).unsqueeze(0) with torch.no_grad(): alpha, beta = self.nn(state)[0] action = alpha / (alpha + beta) return action.squeeze().cpu().numpy() def chooseActionTrain(self, state): """ Choose an action during training mode Parameters ------- state: The current state of the car. Returns ------- action : np.ndarray The actions to run on the track coefficient : float The logarithmic probability for an action Notes ------- This function is only called when the --train flag IS provided. """ state = torch.from_numpy(state).double().to( self.hardwareDevice).unsqueeze(0) with torch.no_grad(): alpha, beta = self.nn(state)[0] dist = Beta(alpha, beta) action = dist.sample() coefficient = dist.log_prob(action).sum(dim=1) action = action.squeeze().cpu().numpy() coefficient = coefficient.item() return action, coefficient def storeInBuffer(self, transition): """ Store a transition in a buffer Parameters ------- transition : dtype=self.transition A transition element which is saved to the internal memory buffer Returns ------- Boolean A boolean representing whether the buffer was SUCCESFULLY stored and didn't overflow. """ self.buffer[self.counter] = transition self.counter += 1 if not self.bufferSize == self.counter: return False self.counter = 0 return True def update(self): """ Run an update on the network """ self.trainingStep += 1 sliceToConcat = torch.tensor(self.buffer['slice_to_concat'], dtype=torch.double).to( self.hardwareDevice).view(-1, 1) matrixA = torch.tensor(self.buffer['matrix_a'], dtype=torch.double).to(self.hardwareDevice) indexExp = torch.tensor(self.buffer['index_exp'], dtype=torch.double).to(self.hardwareDevice) s = torch.tensor(self.buffer['s'], dtype=torch.double).to(self.hardwareDevice) old_coefficient = torch.tensor(self.buffer['coefficient'], dtype=torch.double).to( self.hardwareDevice).view(-1, 1) with torch.no_grad(): target = sliceToConcat + self.discount * self.nn(indexExp)[1] advantage = target - self.nn(s)[1] for _ in range(self.epoch): for index in BatchSampler( SubsetRandomSampler(range(self.bufferSize)), self.batchSize, False): alpha, beta = self.nn(s[index])[0] distance = Beta(alpha, beta) coefficient = distance.log_prob(matrixA[index]).sum( dim=1, keepdim=True) relativeAdvantage = torch.exp(coefficient - old_coefficient[index]) s1 = relativeAdvantage * advantage[index] s2 = torch.clamp(ratio, 1.0 - self.clipParameter, 1.0 + self.clipParameter) * advantage[index] # Loss on an action aLoss = -torch.min(s1, s2).mean() # Loss on the value vLoss = F.smooth_l1_loss(self.nn(s[index])[1], target[index]) # Total loss calculation loss = aLoss + (vLoss * 2.0) self.optimizer.zero_grad() loss.backward() self.optimizer.step()
def train(fold_ind, dataset_dir, type_name, setting_symbol, device_id=None): if device_id is not None: device_ind = device_id else: device_ind = (fold_ind - 1) % 4 device = torch.device( f'cuda:{device_ind}' if torch.cuda.is_available() else 'cpu') print(device) # loss if args.classifier == "nn": crit = nn.NLLLoss() elif args.classifier == "dm" or args.classifier == "ip": crit = nn.BCELoss() # read dataset dataset = torch.load( os.path.join(dataset_dir, f'dataset_fold_{fold_ind}.pt')) num_node_features = dataset.num_node_features dataset = dataset.to(device) print(dataset) # read train and test with open( os.path.join(dataset_dir, f"train_test_split_fold_{fold_ind}.pkl"), "rb") as f: positive_train, positive_test = pickle.load(f) with open( os.path.join( dataset_dir, f"../10/negative_train_test_split_fold_{fold_ind}.pkl"), "rb") as f: negative_train, negative_test = pickle.load(f) # generate data loader if args.classifier == "nn": train_loader, test_loader = read_train_test_nn(positive_train, positive_test, negative_train, negative_test, args.bs) elif args.classifier == "dm" or args.classifier == "ip": train_loader, test_loader = read_train_test_dm(positive_train, positive_test, negative_train, negative_test, args.bs) # read omim and test (use for eval_all) with open(f"preprocess/edgelist_result/union_omim_gene_list.pkl", "rb") as f: omim_list, gene_list = pickle.load(f) with open(os.path.join(dataset_dir, f"id_conversion_fold_{fold_ind}.pkl"), "rb") as f: node_name_to_contiguous_id, contiguous_id_to_node_name = pickle.load(f) refine_gene_list = [] for gene in gene_list: if gene in node_name_to_contiguous_id: refine_gene_list.append(node_name_to_contiguous_id[gene]) else: refine_gene_list.append(-1) add_links = [] if "S" in type_name: sc_add_name = "sc_add_topall20.txt" with open( os.path.join("preprocess/edgelist_result/disease_gene/", sc_add_name), "r") as f: for line in f.read().strip().split("\n"): d, g = line.strip().split("\t") d, g = "omim:" + str(d), "gene:" + str(g) if d in omim_list and g in gene_list: add_links.append([ node_name_to_contiguous_id[d], node_name_to_contiguous_id[g] ]) # embedding gcn gcn = GCN_EMB(num_node_features, args.gcn_dim, args.conv_type, args.dropout_ratio).to(device) # classifier if args.classifier == "nn": classifier = NN(args.nn_dim, device).to(device) elif args.classifier == "dm": classifier = DM(args.dm_dim).to(device) elif args.classifier == "ip": classifier = IP().to(device) params = list(gcn.parameters()) + list(classifier.parameters()) optimizer = torch.optim.SGD(params, lr=args.lr, momentum=0.9, weight_decay=5e-4) scheduler = torch.optim.lr_scheduler.MultiStepLR(optimizer, milestones=args.milestone, gamma=0.1) # train best_auc = 0.0 tqdm_train = tqdm(range(args.epoch_num)) for epoch in tqdm_train: t1 = time.time() gcn.train() classifier.train() epoch_loss = 0.0 count = 0 # calculate loss based on train and test split delta_time = 0.0 for batch_ind, batch_target in train_loader: optimizer.zero_grad() batch_target = batch_target.to(device) # forward emb = gcn(dataset) # distmult batch_output = classifier(emb, batch_ind) # loss loss = crit(batch_output, batch_target) epoch_loss += loss.item() * batch_target.size(0) count += batch_target.size(0) loss.backward() optimizer.step() epoch_loss /= count # eval acc if args.classifier == "nn": acc, test_loss, roc_auc = eval_test_nn(gcn, classifier, test_loader, device, dataset, crit) elif args.classifier == "dm" or args.classifier == "ip": acc, test_loss, roc_auc = eval_test_dm(gcn, classifier, test_loader, device, dataset, crit) tqdm_train.set_description( f"fold {fold_ind}, epoch {epoch+1}, average loss: {round(epoch_loss, 4)}, test accuracy: {round(acc, 4)} , roc auc: {round(roc_auc, 4)} , test loss: {round(test_loss, 4)}" ) if roc_auc >= best_auc: best_auc = roc_auc torch.save( gcn.state_dict(), f"best_auc_gcn_{type_name}_{setting_symbol}_fold_{fold_ind}.pth" ) torch.save( classifier.state_dict(), f"best_auc_classifier_{type_name}_{setting_symbol}_fold_{fold_ind}.pth" ) scheduler.step() # final evaluation # eval on last if args.classifier == "nn": mean_auc, mean_rank, fpr_list, tpr_list = eval_all_nn( gcn, classifier, device, dataset, refine_gene_list, positive_train + add_links, positive_test, negative_train) elif args.classifier == "dm" or args.classifier == "ip": mean_auc, mean_rank, fpr_list, tpr_list = eval_all_dm( gcn, classifier, device, dataset, refine_gene_list, positive_train + add_links, positive_test, negative_train) print( f"====== \n {type_name}_{setting_symbol}, fold {fold_ind}, eval on last \n mean auc is: {round(mean_auc, 4)} \n mean rank is: {round(mean_rank, 4)} \n======" ) torch.save(gcn.state_dict(), f"last_gcn_{type_name}_{setting_symbol}_fold_{fold_ind}.pth") torch.save( classifier.state_dict(), f"last_classifier_{type_name}_{setting_symbol}_fold_{fold_ind}.pth") # save fold result each_mean_auc_on_last[fold_ind - 1].append(mean_auc) each_mean_rank_on_last[fold_ind - 1].append(mean_rank) each_fpr_list_on_last[fold_ind - 1].extend(fpr_list) each_tpr_list_on_last[fold_ind - 1].extend(tpr_list) # eval on best auc gcn.load_state_dict( torch.load( f"best_auc_gcn_{type_name}_{setting_symbol}_fold_{fold_ind}.pth")) classifier.load_state_dict( torch.load( f"best_auc_classifier_{type_name}_{setting_symbol}_fold_{fold_ind}.pth" )) if args.classifier == "nn": mean_auc, mean_rank, fpr_list, tpr_list = eval_all_nn( gcn, classifier, device, dataset, refine_gene_list, positive_train + add_links, positive_test, negative_train) elif args.classifier == "dm" or args.classifier == "ip": mean_auc, mean_rank, fpr_list, tpr_list = eval_all_dm( gcn, classifier, device, dataset, refine_gene_list, positive_train + add_links, positive_test, negative_train) print( f"====== \n {type_name}_{setting_symbol}, fold {fold_ind}, eval on best auc \n mean auc is: {round(mean_auc, 4)} \n mean rank is: {round(mean_rank, 4)} \n======" ) # save fold result each_mean_auc[fold_ind - 1].append(mean_auc) each_mean_rank[fold_ind - 1].append(mean_rank) each_fpr_list[fold_ind - 1].extend(fpr_list) each_tpr_list[fold_ind - 1].extend(tpr_list)
dataset,loader,test_dataset,test_loader = loadDatasets(args.train_dataset, args.test_dataset,args.window_size,args.batch_size,shuffle=True,vocab_size=args.vocab_size,compute_dicts = args.embeddings_path is None) print("Number of training examples / test examples: {} / {}".format(len(dataset),len(test_dataset))) if args.embeddings_path is not None: embLoader = EmbeddingsLoader(args.embeddings_path) print("Embeddings loaded, vocab size: {} embedding dims: {}".format(embLoader.get_dimensions()[0],embLoader.get_dimensions()[1])) args.vocab_size,args.embedding_size = embLoader.get_dimensions() model = NN(vocab_size=args.vocab_size,number_tags=dataset.get_num_tags(), batch_size=args.batch_size,gpu=args.gpu,window_size=args.window_size, include_cap=args.capitalization,number_suffix=dataset.get_num_suffix(), embedding_dim=args.embedding_size,activation=args.activation) model.load_state_dict(torch.load(args.trained_model)) if args.gpu and torch.cuda.is_available(): model.cuda() tagged_file = open(args.output_file,"w") if args.embeddings_path is not None: word_to_index = embLoader.word_to_index else: word_to_index = dataset.word_to_index for i,(words_input,tags) in enumerate(test_loader): input_tensor,target_tensor,cap_tensor,suf_tensor = model.get_train_tensors(words_input,tags, word_to_index,dataset.tag_to_index,suffix2id=dataset.suffix_to_index) output = model(Variable(input_tensor),Variable(cap_tensor),Variable(suf_tensor))