| import os |
| import torch |
| import logging |
| import re |
| import pandas as pd |
| import numpy as np |
| from matplotlib import pyplot as plt |
| import copy |
|
|
| def snapshot(dir_path, run_name, state,logger): |
| snapshot_file = os.path.join(dir_path, |
| run_name + '-model_best.pth') |
| |
| |
| torch.save(state, snapshot_file) |
| logger.info("Snapshot saved to {}\n".format(snapshot_file)) |
|
|
| class Log_parser(object): |
| def __init__(self,log_path,val_split_line=False,use_line_as_valtest=1): |
| |
| self.val_split_line = val_split_line |
| self.use_line_as_valtest = use_line_as_valtest |
| if os.path.exists(log_path): |
| with open(log_path,'r') as f: |
| log_file = f.readlines() |
| f.close() |
| |
| log_file = np.array([line.strip() for line in log_file]) |
| else: |
| print('log path error !') |
| self.log_file = log_file |
| |
| |
| |
| |
| self.epoch_line_matcher = r"\s.* epoch (\d{1,4}).*" |
| self.start_val_line_matcher = r"\s*.* start validation .*\s*" |
| self.match_logging_time = r"\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2},\d{3} -" |
| self.match_percentage = r"\s*\d{1,6} /\s*\d{1,6}\s*\((\d|\.){,6}%\):" |
| |
| self.match_sub_verbose = lambda x : r"\s*%s:\s*(?P<%s>(-|\d|\.|e|){,40})"%(x,x) |
| |
| |
| self.train_verbose_finder = self.match_logging_time + self.match_percentage |
| |
| |
| self.extract_training_verbose_data() |
| self.extract_val_verbose_data() |
| |
| def lines_to_json(self, line, sett): |
| remove_time = line.split('%):')[1].split() if sett=='train' else line.split(' - \t ')[1].split() |
| line_json = {metrics.split(':')[0]:metrics.split(':')[1] for metrics in remove_time} |
| return line_json |
| |
| def lines_matching(self,matcher): |
| """ |
| return lines that can match certain syntax |
| """ |
| return [line for line in self.log_file if re.match(matcher,line) is not None] |
| |
| def position_matching(self,matcher): |
| """ |
| return position of the line that can match certain syntax |
| """ |
| return [i for i,line in enumerate(self.log_file) if re.match(matcher,line) is not None] |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| def extract_training_verbose_data(self): |
| """ |
| regular expression to match the printed metric during training and save to pd.DataFrame |
| """ |
| self.train_verbose_lines = self.lines_matching(self.train_verbose_finder) |
| |
| self.train_verbose_dict = [self.lines_to_json(line,'train') for line in self.train_verbose_lines] |
| |
| self.train_metric = list(self.train_verbose_dict[0].keys()) |
| |
| self.train_verbose_DF = pd.json_normalize(self.train_verbose_dict).astype(float) |
| |
| |
| |
| def extract_val_verbose_data(self): |
| """ |
| regular expression to match the printed metric during training and save to pd.DataFrame |
| """ |
| self.start_val_posi = self.position_matching(self.start_val_line_matcher) |
| val_verbose_posi = np.array(self.start_val_posi) +1 |
| self.val_verbose_posi = val_verbose_posi[val_verbose_posi < len(self.log_file)] |
| self.val_verbose_lines = self.log_file[self.val_verbose_posi] |
| if self.val_split_line: |
| self.val_verbose_lines = ["\t".join(self.log_file[[posi,posi+1,posi+2,posi+3,posi+4]]) for posi in self.val_verbose_posi] |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| self.val_verbose_dict = [self.lines_to_json(line, 'val') for line in self.val_verbose_lines] |
| self.val_metric = list(self.val_verbose_dict[0].keys()) |
| |
| |
| |
| |
| |
| |
| self.val_verbose_DF = pd.json_normalize(self.val_verbose_dict).astype(float) |
| |
| |
| |
| def plot_val_metric(self,fig=None,dataset='val'): |
| DF = self.val_verbose_DF if dataset == 'val' else self.train_verbose_DF |
| metrics = self.val_metric if dataset == 'val' else self.train_metric |
| n = len(metrics) |
| |
| if fig is None: |
| fig = plt.figure(figsize=(18,5*np.ceil(n/3))) |
| if n <=3: |
| axs = fig.subplots(1,n) |
| for i in range(n): |
| axs[i].plot(DF[metrics[i]].values) |
| axs[i].set_title(dataset.capitalize()+" "+metrics[i]) |
| else: |
| axs = fig.add_subplot(n//3+1,n,1+i) |
| |
|
|
| def plot_a_exp_set(log_list,log_name_ls,dataset='val',fig=None,layout=None,check_time=10,start_from=0,mean_of_train=None,define_order=None,esubset=None, cycle_train=False,**kwargs): |
| all_metric = [logg.__getattribute__(dataset+"_metric") for logg in log_list] |
| share_metric = [all_metric[0]] |
| for logg_metric in all_metric[1:]: |
| share_metric = np.intersect1d(share_metric,logg_metric) |
| if define_order is not None: |
| assert set(define_order) == set(share_metric) |
| |
| n = len(share_metric) + 1 |
| fig = plt.figure(figsize=(20,5)) if fig is None else fig |
|
|
| |
| if layout is None: |
| axs = fig.subplots(1,n); |
| else: |
| row,column = layout |
| axs = fig.subplots(row,column).flatten() |
| |
| |
| for i,metric in enumerate(share_metric): |
| |
| |
| ax = axs[i] |
| for st,log in enumerate(log_list): |
| DF = log.__getattribute__(dataset+"_verbose_DF") |
| |
| if (dataset == 'train') & (type(mean_of_train)==int): |
| DF = mean_of(mean_of_train,DF) |
| elif (dataset == 'train') & (type(esubset)==slice): |
| DF = subset_of(esubset,DF) |
| X = np.arange(DF.shape[0])*check_time if dataset == 'val' else np.arange(DF.shape[0]) |
| ax.plot(X[start_from:],DF[metric].values[start_from:],**kwargs) |
| ax.set_title(" ".join([dataset.capitalize(),metric])) |
| for st,log in enumerate(log_list): |
| axs[-1].plot(0,0,label=log_name_ls[st]) |
| axs[-1].axis('off') |
| axs[-1].legend() |
| |
| def plot_cycle_exp_set(log_ls,log_name,dataset='val',**kwargs): |
| interval = 2 if dataset=='val' else 6 |
| new_log_ls = [] |
| new_log_name = [] |
| for i in range(len(log_ls)): |
| log = log_ls[i] |
| DF = log.__getattribute__(dataset+"_verbose_DF") |
| ds1_index = [i for i in range(DF.shape[0]) if i//interval%2 ==0] |
| ds2_index = [i for i in range(DF.shape[0]) if i//interval%2 ==1] |
| DF1 = DF.iloc[ds1_index] |
| DF2 = DF.iloc[ds2_index] |
| log1 = copy.deepcopy(log) |
| log2 = copy.deepcopy(log) |
| |
| log1.__setattr__(dataset+'_verbose_DF', DF1) |
| log2.__setattr__(dataset+'_verbose_DF', DF2) |
| |
| new_log_ls.append(log1) |
| new_log_ls.append(log2) |
| |
| new_log_name.append(log_name[i]+"_ds1") |
| new_log_name.append(log_name[i]+"_ds2") |
| |
| plot_a_exp_set(new_log_ls, new_log_name, **kwargs) |
| |
| |
| def subset_of(x,DF): |
| |
| values = DF.values |
| mean_ls = [] |
| |
| for i in range(0,values.shape[0],x.stop): |
| |
| mean_ls.append(values[i:i+x.stop][x]) |
| |
| mean_ls = np.concatenate(mean_ls,axis=0) |
| mean_DF = pd.DataFrame(mean_ls,columns=DF.columns) |
| |
| return mean_DF |
|
|
| def mean_of(x,DF): |
| |
| values = DF.values |
| mean_ls = [] |
| |
| for i in range(0,values.shape[0],x): |
| |
| mean_ls.append(np.mean(values[i:i+x,:],axis=0)) |
| |
| mean_ls = np.stack(mean_ls) |
| mean_DF = pd.DataFrame(mean_ls,columns=DF.columns) |
| |
| return mean_DF |
|
|
| def read_log_of_a_dir(log_dir): |
| """ |
| ...log_dir : abs path of log dir |
| """ |
| file_ls = [file for file in os.listdir(log_dir) if ".log" in file] |
| log_path = [os.path.join(log_dir,file) for file in file_ls] |
| log_name = [file.replace('.log','') for file in file_ls] |
| log_ls = [Log_parser(file) for file in log_path] |
| return log_ls,log_name |