diff --git a/train.py b/train.py index c08224ed4..26df91057 100644 --- a/train.py +++ b/train.py @@ -42,7 +42,7 @@ hyp = {'lr0': 0.01, # initial learning rate (SGD=1E-2, Adam=1E-3) def train(hyp, opt, device, tb_writer=None): print(f'Hyperparameters {hyp}') - log_dir = tb_writer.log_dir if tb_writer else 'runs/evolution' # run directory + log_dir = tb_writer.log_dir if tb_writer else 'runs/evolve' # run directory wdir = str(Path(log_dir) / 'weights') + os.sep # weights directory os.makedirs(wdir, exist_ok=True) last = wdir + 'last.pt' @@ -491,6 +491,7 @@ if __name__ == '__main__': assert opt.local_rank == -1, 'DDP mode not implemented for --evolve' opt.notest, opt.nosave = True, True # only test/save final epoch # ei = [isinstance(x, (int, float)) for x in hyp.values()] # evolvable indices + yaml_file = Path('runs/evolve/hyp_evolved.yaml') # save best result here if opt.bucket: os.system('gsutil cp gs://%s/evolve.txt .' % opt.bucket) # download evolve.txt if exists @@ -518,17 +519,21 @@ if __name__ == '__main__': while all(v == 1): # mutate until a change occurs (prevent duplicates) v = (g * (npr.random(ng) < mp) * npr.randn(ng) * npr.random() * s + 1).clip(0.3, 3.0) for i, k in enumerate(hyp.keys()): # plt.hist(v.ravel(), 300) - hyp[k] = x[i + 7] * v[i] # mutate + hyp[k] = float(x[i + 7] * v[i]) # mutate - # Clip to limits + # Constrain to limits for k, v in meta.items(): - hyp[k] = np.clip(hyp[k], v[1], v[2]) + hyp[k] = max(hyp[k], v[1]) # lower limit + hyp[k] = min(hyp[k], v[2]) # upper limit + hyp[k] = round(hyp[k], 5) # significant digits # Train mutation results = train(hyp.copy(), opt, device) # Write mutation results - print_mutation(hyp, results, opt.bucket) + print_mutation(hyp.copy(), results, yaml_file, opt.bucket) - # Plot results - # plot_evolution_results(hyp) + # Plot results + plot_evolution_results(yaml_file) + print('Hyperparameter evolution complete. Best results saved as: %s\nCommand to train a new model with these ' + 'hyperparameters: $ python train.py --hyp %s' % (f, f)) diff --git a/utils/utils.py b/utils/utils.py index 184e8dc25..146383471 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -818,11 +818,11 @@ def kmean_anchors(path='./data/coco128.yaml', n=9, img_size=640, thr=4.0, gen=10 return print_results(k) -def print_mutation(hyp, results, bucket=''): +def print_mutation(hyp, results, yaml_file='hyp_evolved.yaml', bucket=''): # Print mutation results to evolve.txt (for use with train.py --evolve) a = '%10s' * len(hyp) % tuple(hyp.keys()) # hyperparam keys b = '%10.3g' * len(hyp) % tuple(hyp.values()) # hyperparam values - c = '%10.4g' * len(results) % results # results (P, R, mAP, F1, test_loss) + c = '%10.4g' * len(results) % results # results (P, R, mAP@0.5, mAP@0.5:0.95, val_losses x 3) print('\n%s\n%s\nEvolved fitness: %s\n' % (a, b, c)) if bucket: @@ -831,11 +831,19 @@ def print_mutation(hyp, results, bucket=''): with open('evolve.txt', 'a') as f: # append result f.write(c + b + '\n') x = np.unique(np.loadtxt('evolve.txt', ndmin=2), axis=0) # load unique rows - np.savetxt('evolve.txt', x[np.argsort(-fitness(x))], '%10.3g') # save sort by fitness + x = x[np.argsort(-fitness(x))] # sort + np.savetxt('evolve.txt', x, '%10.3g') # save sort by fitness if bucket: os.system('gsutil cp evolve.txt gs://%s' % bucket) # upload evolve.txt + # Save yaml + for i, k in enumerate(hyp.keys()): + hyp[k] = float(x[0, i + 7]) + with open(yaml_file, 'w') as f: + f.write('# Hyperparameter Evolution Results\n# Generations: %g\n# Metrics: ' % len(x) + c + '\n\n') + yaml.dump(hyp, f, sort_keys=False) + def apply_classifier(x, model, img, im0): # applies a second stage classifier to yolo outputs @@ -1146,23 +1154,26 @@ def plot_labels(labels, save_dir=''): plt.close() -def plot_evolution_results(hyp): # from utils.utils import *; plot_evolution_results(hyp) +def plot_evolution_results(yaml_file='hyp_evolved.yaml'): # from utils.utils import *; plot_evolution_results() # Plot hyperparameter evolution results in evolve.txt + with open(yaml_file) as f: + hyp = yaml.load(f, Loader=yaml.FullLoader) x = np.loadtxt('evolve.txt', ndmin=2) f = fitness(x) # weights = (f - f.min()) ** 2 # for weighted results - plt.figure(figsize=(12, 10), tight_layout=True) + plt.figure(figsize=(14, 10), tight_layout=True) matplotlib.rc('font', **{'size': 8}) for i, (k, v) in enumerate(hyp.items()): y = x[:, i + 7] # mu = (y * weights).sum() / weights.sum() # best weighted result mu = y[f.argmax()] # best single result - plt.subplot(4, 5, i + 1) + plt.subplot(4, 6, i + 1) plt.plot(mu, f.max(), 'o', markersize=10) plt.plot(y, f, '.') plt.title('%s = %.3g' % (k, mu), fontdict={'size': 9}) # limit to 40 characters print('%15s: %.3g' % (k, mu)) plt.savefig('evolve.png', dpi=200) + print('\nPlot saved as evolve.png') def plot_results_overlay(start=0, stop=0): # from utils.utils import *; plot_results_overlay()