From c681e3cb0a521d10cec905dee8ad78ca1dd88939 Mon Sep 17 00:00:00 2001 From: Gao Enhao Date: Mon, 21 Nov 2022 22:42:07 +0800 Subject: [PATCH] update basic_model.py and related part in other files --- abducer/abducer_base.py | 3 +- example.py | 4 +- framework.py | 10 ++- models/basic_model.py | 135 ++++++++++++++++++---------------------- utils/plog.py | 36 +++++------ 5 files changed, 84 insertions(+), 104 deletions(-) diff --git a/abducer/abducer_base.py b/abducer/abducer_base.py index b26c88a..54380ec 100644 --- a/abducer/abducer_base.py +++ b/abducer/abducer_base.py @@ -11,8 +11,7 @@ #================================================================# import abc -from kb import add_KB, hwf_KB -# from abducer.kb import add_KB, hwf_KB +from abducer.kb import add_KB, hwf_KB import numpy as np from itertools import product, combinations diff --git a/example.py b/example.py index d63185c..dad33f7 100644 --- a/example.py +++ b/example.py @@ -43,11 +43,11 @@ def run_test(): optimizer = torch.optim.Adam(cls.parameters(), lr=0.001, betas=(0.9, 0.99)) device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu") - base_model = BasicModel(cls, criterion, optimizer, device, recorder=recorder) + base_model = BasicModel(cls, criterion, optimizer, device, save_interval=1, save_dir=recorder.save_dir, num_epochs=1, recorder=recorder) model = WABLBasicModel(base_model, kb.pseudo_label_list) res = framework.train(model, abducer, train_X, train_Z, train_Y, sample_num = 10000, verbose = 1) - print(res) + recorder.print("abl_acc is ", res) recorder.dump() return True diff --git a/framework.py b/framework.py index a37483b..4f84694 100644 --- a/framework.py +++ b/framework.py @@ -123,7 +123,7 @@ def is_all_sublabel_exist(labels, std_label_list): def pretrain(model, X, Z): pass -def train(model, abducer, X, Z, Y, epochs = 10, sample_num = -1, verbose = -1): +def train(model, abducer, X, Z, Y, epochs = 5, sample_num = -1, verbose = -1): # Set default parameters if sample_num == -1: sample_num = len(X) @@ -138,10 +138,7 @@ def train(model, abducer, X, Z, Y, epochs = 10, sample_num = -1, verbose = -1): predict_func = clocker(model.predict) train_func = clocker(model.train) - abduce_func = clocker(abducer.batch_abduce) - - epochs = 50 # Abductive learning train process for epoch_idx in range(epochs): @@ -153,12 +150,13 @@ def train(model, abducer, X, Z, Y, epochs = 10, sample_num = -1, verbose = -1): if(char_acc_flag): ori_char_acc = get_char_acc(Z, preds_res['cls']) abd_char_acc = get_char_acc(abduced_Z, preds_res['cls']) - print('epoch_idx:', epoch_idx, ' abl_acc:', abl_acc, ' ori_char_acc:', ori_char_acc, ' abd_char_acc:', abd_char_acc) + INFO('epoch_idx:', epoch_idx, ' abl_acc:', abl_acc, ' ori_char_acc:', ori_char_acc, ' abd_char_acc:', abd_char_acc) else: - print('epoch_idx:', epoch_idx, ' abl_acc:', abl_acc) + INFO('epoch_idx:', epoch_idx, ' abl_acc:', abl_acc) finetune_X, finetune_Z = filter_data(X, abduced_Z) if len(finetune_X) > 0: + # model.valid(finetune_X, finetune_Z) train_func(finetune_X, finetune_Z) else: INFO("lack of data, all abduced failed", len(finetune_X)) diff --git a/models/basic_model.py b/models/basic_model.py index 00efd30..11063a8 100644 --- a/models/basic_model.py +++ b/models/basic_model.py @@ -55,7 +55,7 @@ class BasicModel(): optimizer, device, batch_size = 1, - num_epochs = 10, + num_epochs = 1, stop_loss = 0.01, num_workers = 0, save_interval = None, @@ -89,15 +89,15 @@ class BasicModel(): recorder = self.recorder recorder.print("model fitting") - min_loss = 999999999 + min_loss = 1e10 for epoch in range(n_epoch): loss_value = self.train_epoch(data_loader) recorder.print(f"{epoch}/{n_epoch} model training loss is {loss_value}") - if loss_value < min_loss: + if min_loss < 0 or loss_value < min_loss: min_loss = loss_value - if epoch > 0 and self.save_interval is not None and epoch % self.save_interval == 0: + if self.save_interval is not None and (epoch + 1) % self.save_interval == 0: assert self.save_dir is not None - self.save(self.save_dir) + self.save(epoch + 1, self.save_dir) if stop_loss is not None and loss_value < stop_loss: break recorder.print("Model fitted, minimal loss is ", min_loss) @@ -107,14 +107,7 @@ class BasicModel(): X = None, y = None): if data_loader is None: - collate_fn = self.collate_fn - transform = self.transform - - train_dataset = XYDataset(X, y, transform=transform) - sampler = None - data_loader = torch.utils.data.DataLoader(train_dataset, batch_size=self.batch_size, \ - shuffle=True, sampler=sampler, num_workers=int(self.num_workers), \ - collate_fn=collate_fn) + data_loader = self._data_loader(X, y) return self._fit(data_loader, self.num_epochs, self.stop_loss) def train_epoch(self, data_loader): @@ -136,6 +129,7 @@ class BasicModel(): optimizer.step() total_loss += loss.item() * data.size(0) + total_num += data.size(0) return total_loss / total_num @@ -149,107 +143,98 @@ class BasicModel(): results = [] for data, _ in data_loader: data = data.to(device) - pred_Y = model(data) - results.append(pred_Y) + out = model(data) + results.append(out) return torch.cat(results, axis=0) def predict(self, data_loader = None, X = None, print_prefix = ""): - if data_loader is None: - collate_fn = self.collate_fn - transform = self.transform - - Y = [0] * len(X) - val_dataset = XYDataset(X, Y, transform=transform) - sampler = None - data_loader = torch.utils.data.DataLoader(val_dataset, batch_size=self.batch_size, \ - shuffle=False, sampler=sampler, num_workers=int(self.num_workers), \ - collate_fn=collate_fn) - recorder = self.recorder - recorder.print('Start Predict ', print_prefix) - Y = self._predict(data_loader).argmax(axis=1) - return [int(y) for y in Y] + recorder.print('Start Predict Class ', print_prefix) - def predict_proba(self, data_loader = None, X = None, print_prefix = ""): if data_loader is None: - collate_fn = self.collate_fn - transform = self.transform - - Y = [0] * len(X) - val_dataset = XYDataset(X, Y, transform=transform) - sampler = None - data_loader = torch.utils.data.DataLoader(val_dataset, batch_size=self.batch_size, \ - shuffle=False, sampler=sampler, num_workers=int(self.num_workers), \ - collate_fn=collate_fn) + data_loader = self._data_loader(X) + return self._predict(data_loader).argmax(axis=1).cpu().numpy() + def predict_proba(self, data_loader = None, X = None, print_prefix = ""): recorder = self.recorder - recorder.print('Start Predict ', print_prefix) - return torch.softmax(self._predict(data_loader), axis=1).cpu().numpy() + recorder.print('Start Predict Probability ', print_prefix) - def _val(self, data_loader, print_prefix): + if data_loader is None: + data_loader = self._data_loader(X) + return self._predict(data_loader).softmax(axis=1).cpu().numpy() + + def _val(self, data_loader): model = self.model criterion = self.criterion - recorder = self.recorder device = self.device - recorder.print('Start val ', print_prefix) model.eval() - - n_correct = 0 - pred_num = 0 - loss_value = 0 + + total_correct_num, total_num, total_loss = 0, 0, 0.0 + with torch.no_grad(): - for _, data in enumerate(data_loader): - X = data[0].to(device) - Y = data[1].to(device) + for data, target in data_loader: + data, target = data.to(device), target.to(device) - pred_Y = model(X) + out = model(data) - correct_num = sum(Y == pred_Y.argmax(axis=1)) - loss = criterion(pred_Y, Y) - loss_value += loss.item() + correct_num = sum(target == out.argmax(axis=1)).item() + loss = criterion(out, target) + total_loss += loss.item() * data.size(0) - n_correct += correct_num - pred_num += len(X) + total_correct_num += correct_num + total_num += data.size(0) + + mean_loss = total_loss / total_num + accuracy = total_correct_num / total_num - accuracy = float(n_correct) / float(pred_num) - recorder.print('[%s] Val loss: %f, accuray: %f' % (print_prefix, loss_value, accuracy)) - return accuracy + return mean_loss, accuracy def val(self, data_loader = None, X = None, y = None, print_prefix = ""): - if data_loader is None: - collate_fn = self.collate_fn - transform = self.transform + recorder = self.recorder + recorder.print('Start val ', print_prefix) - val_dataset = XYDataset(X, y, transform=transform) - sampler = None - data_loader = torch.utils.data.DataLoader(val_dataset, batch_size=self.batch_size, \ - shuffle=True, sampler=sampler, num_workers=int(self.num_workers), \ - collate_fn=collate_fn) - return self._val(data_loader, print_prefix) + if data_loader is None: + data_loader = self._data_loader(X, y) + mean_loss, accuracy = self._val(data_loader) + recorder.print('[%s] Val loss: %f, accuray: %f' % (print_prefix, mean_loss, accuracy)) + return accuracy def score(self, data_loader = None, X = None, y = None, print_prefix = ""): return self.val(data_loader, X, y, print_prefix) - def save(self, save_dir): + def _data_loader(self, X, y = None): + collate_fn = self.collate_fn + transform = self.transform + + if y is None: + y = [0] * len(X) + dataset = XYDataset(X, y, transform=transform) + sampler = None + data_loader = torch.utils.data.DataLoader(dataset, batch_size=self.batch_size, \ + shuffle=False, sampler=sampler, num_workers=int(self.num_workers), \ + collate_fn=collate_fn) + return data_loader + + def save(self, epoch_id, save_dir): recorder = self.recorder if not os.path.exists(save_dir): os.mkdir(save_dir) recorder.print("Saving model and opter") - save_path = os.path.join(save_dir, "net.pth") + save_path = os.path.join(save_dir, str(epoch_id) + "_net.pth") torch.save(self.model.state_dict(), save_path) - save_path = os.path.join(save_dir, "opt.pth") + save_path = os.path.join(save_dir, str(epoch_id) + "_opt.pth") torch.save(self.optimizer.state_dict(), save_path) - def load(self, load_dir): + def load(self, epoch_id, load_dir): recorder = self.recorder recorder.print("Loading model and opter") - load_path = os.path.join(load_dir, "net.pth") + load_path = os.path.join(load_dir, str(epoch_id) + "_net.pth") self.model.load_state_dict(torch.load(load_path)) - load_path = os.path.join(load_dir, "opt.pth") + load_path = os.path.join(load_dir, str(epoch_id) + "_opt.pth") self.optimizer.load_state_dict(torch.load(load_path)) if __name__ == "__main__": diff --git a/utils/plog.py b/utils/plog.py index 4aee019..178b8b7 100644 --- a/utils/plog.py +++ b/utils/plog.py @@ -20,12 +20,11 @@ global recorder recorder = None class ResultRecorder: - def __init__(self, pk_dir = 'results', pk_filepath = None): - self.result = {} - + def __init__(self): logging.basicConfig(level=logging.DEBUG, filemode='a') - self.set_savefile(pk_dir, pk_filepath) + self.result = {} + self.set_savefile() logging.info("===========================================================") logging.info("============= Result Recorder Version: 0.03 ===============") @@ -33,20 +32,19 @@ class ResultRecorder: pass - def set_savefile(self, pk_dir = None, pk_filepath = None): - if pk_dir is None: - pk_dir = "results" - - if not os.path.exists(pk_dir): - os.makedirs(pk_dir) + def set_savefile(self): + local_time = time.strftime("%Y%m%d_%H_%M_%S", time.localtime()) - if pk_filepath is None: - local_time = time.strftime("%Y%m%d_%H_%M_%S", time.localtime()) - pk_filepath = os.path.join(pk_dir, local_time + ".pk") + save_dir = os.path.join("results", local_time) + save_file_path = os.path.join(save_dir, "result.pk") - self.save_file = pk_filepath + self.save_dir = save_dir + self.save_file_path = save_file_path + + if not os.path.exists(save_dir): + os.makedirs(save_dir) - filename = os.path.join(pk_dir, local_time + ".txt") + filename = os.path.join(save_dir, "log.txt") file_handler = logging.FileHandler(filename) file_handler.setLevel(logging.DEBUG) formatter = logging.Formatter('%(asctime)s - %(filename)s[line:%(lineno)d] - %(levelname)s: %(message)s') @@ -87,10 +85,10 @@ class ResultRecorder: #self.print_result(label + ":" + str(data)) self.store_kv(label, data) - def dump(self, save_file = None): - if save_file is None: - save_file = self.save_file - with open(save_file, 'wb') as f: + def dump(self, save_file_path = None): + if save_file_path is None: + save_file_path = self.save_file_path + with open(save_file_path, 'wb') as f: pk.dump(self.result, f) def clock(self, func):