glenn-jocher commited on
Commit
e32abb5
1 Parent(s): 8056fe2

hyperparameter evolution bug fix (#566)

Browse files
Files changed (2) hide show
  1. train.py +12 -7
  2. utils/utils.py +17 -6
train.py CHANGED
@@ -42,7 +42,7 @@ hyp = {'lr0': 0.01, # initial learning rate (SGD=1E-2, Adam=1E-3)
42
 
43
  def train(hyp, opt, device, tb_writer=None):
44
  print(f'Hyperparameters {hyp}')
45
- log_dir = tb_writer.log_dir if tb_writer else 'runs/evolution' # run directory
46
  wdir = str(Path(log_dir) / 'weights') + os.sep # weights directory
47
  os.makedirs(wdir, exist_ok=True)
48
  last = wdir + 'last.pt'
@@ -491,6 +491,7 @@ if __name__ == '__main__':
491
  assert opt.local_rank == -1, 'DDP mode not implemented for --evolve'
492
  opt.notest, opt.nosave = True, True # only test/save final epoch
493
  # ei = [isinstance(x, (int, float)) for x in hyp.values()] # evolvable indices
 
494
  if opt.bucket:
495
  os.system('gsutil cp gs://%s/evolve.txt .' % opt.bucket) # download evolve.txt if exists
496
 
@@ -518,17 +519,21 @@ if __name__ == '__main__':
518
  while all(v == 1): # mutate until a change occurs (prevent duplicates)
519
  v = (g * (npr.random(ng) < mp) * npr.randn(ng) * npr.random() * s + 1).clip(0.3, 3.0)
520
  for i, k in enumerate(hyp.keys()): # plt.hist(v.ravel(), 300)
521
- hyp[k] = x[i + 7] * v[i] # mutate
522
 
523
- # Clip to limits
524
  for k, v in meta.items():
525
- hyp[k] = np.clip(hyp[k], v[1], v[2])
 
 
526
 
527
  # Train mutation
528
  results = train(hyp.copy(), opt, device)
529
 
530
  # Write mutation results
531
- print_mutation(hyp, results, opt.bucket)
532
 
533
- # Plot results
534
- # plot_evolution_results(hyp)
 
 
 
42
 
43
  def train(hyp, opt, device, tb_writer=None):
44
  print(f'Hyperparameters {hyp}')
45
+ log_dir = tb_writer.log_dir if tb_writer else 'runs/evolve' # run directory
46
  wdir = str(Path(log_dir) / 'weights') + os.sep # weights directory
47
  os.makedirs(wdir, exist_ok=True)
48
  last = wdir + 'last.pt'
 
491
  assert opt.local_rank == -1, 'DDP mode not implemented for --evolve'
492
  opt.notest, opt.nosave = True, True # only test/save final epoch
493
  # ei = [isinstance(x, (int, float)) for x in hyp.values()] # evolvable indices
494
+ yaml_file = Path('runs/evolve/hyp_evolved.yaml') # save best result here
495
  if opt.bucket:
496
  os.system('gsutil cp gs://%s/evolve.txt .' % opt.bucket) # download evolve.txt if exists
497
 
 
519
  while all(v == 1): # mutate until a change occurs (prevent duplicates)
520
  v = (g * (npr.random(ng) < mp) * npr.randn(ng) * npr.random() * s + 1).clip(0.3, 3.0)
521
  for i, k in enumerate(hyp.keys()): # plt.hist(v.ravel(), 300)
522
+ hyp[k] = float(x[i + 7] * v[i]) # mutate
523
 
524
+ # Constrain to limits
525
  for k, v in meta.items():
526
+ hyp[k] = max(hyp[k], v[1]) # lower limit
527
+ hyp[k] = min(hyp[k], v[2]) # upper limit
528
+ hyp[k] = round(hyp[k], 5) # significant digits
529
 
530
  # Train mutation
531
  results = train(hyp.copy(), opt, device)
532
 
533
  # Write mutation results
534
+ print_mutation(hyp.copy(), results, yaml_file, opt.bucket)
535
 
536
+ # Plot results
537
+ plot_evolution_results(yaml_file)
538
+ print('Hyperparameter evolution complete. Best results saved as: %s\nCommand to train a new model with these '
539
+ 'hyperparameters: $ python train.py --hyp %s' % (f, f))
utils/utils.py CHANGED
@@ -818,11 +818,11 @@ def kmean_anchors(path='./data/coco128.yaml', n=9, img_size=640, thr=4.0, gen=10
818
  return print_results(k)
819
 
820
 
821
- def print_mutation(hyp, results, bucket=''):
822
  # Print mutation results to evolve.txt (for use with train.py --evolve)
823
  a = '%10s' * len(hyp) % tuple(hyp.keys()) # hyperparam keys
824
  b = '%10.3g' * len(hyp) % tuple(hyp.values()) # hyperparam values
825
- c = '%10.4g' * len(results) % results # results (P, R, mAP, F1, test_loss)
826
  print('\n%s\n%s\nEvolved fitness: %s\n' % (a, b, c))
827
 
828
  if bucket:
@@ -831,11 +831,19 @@ def print_mutation(hyp, results, bucket=''):
831
  with open('evolve.txt', 'a') as f: # append result
832
  f.write(c + b + '\n')
833
  x = np.unique(np.loadtxt('evolve.txt', ndmin=2), axis=0) # load unique rows
834
- np.savetxt('evolve.txt', x[np.argsort(-fitness(x))], '%10.3g') # save sort by fitness
 
835
 
836
  if bucket:
837
  os.system('gsutil cp evolve.txt gs://%s' % bucket) # upload evolve.txt
838
 
 
 
 
 
 
 
 
839
 
840
  def apply_classifier(x, model, img, im0):
841
  # applies a second stage classifier to yolo outputs
@@ -1146,23 +1154,26 @@ def plot_labels(labels, save_dir=''):
1146
  plt.close()
1147
 
1148
 
1149
- def plot_evolution_results(hyp): # from utils.utils import *; plot_evolution_results(hyp)
1150
  # Plot hyperparameter evolution results in evolve.txt
 
 
1151
  x = np.loadtxt('evolve.txt', ndmin=2)
1152
  f = fitness(x)
1153
  # weights = (f - f.min()) ** 2 # for weighted results
1154
- plt.figure(figsize=(12, 10), tight_layout=True)
1155
  matplotlib.rc('font', **{'size': 8})
1156
  for i, (k, v) in enumerate(hyp.items()):
1157
  y = x[:, i + 7]
1158
  # mu = (y * weights).sum() / weights.sum() # best weighted result
1159
  mu = y[f.argmax()] # best single result
1160
- plt.subplot(4, 5, i + 1)
1161
  plt.plot(mu, f.max(), 'o', markersize=10)
1162
  plt.plot(y, f, '.')
1163
  plt.title('%s = %.3g' % (k, mu), fontdict={'size': 9}) # limit to 40 characters
1164
  print('%15s: %.3g' % (k, mu))
1165
  plt.savefig('evolve.png', dpi=200)
 
1166
 
1167
 
1168
  def plot_results_overlay(start=0, stop=0): # from utils.utils import *; plot_results_overlay()
 
818
  return print_results(k)
819
 
820
 
821
+ def print_mutation(hyp, results, yaml_file='hyp_evolved.yaml', bucket=''):
822
  # Print mutation results to evolve.txt (for use with train.py --evolve)
823
  a = '%10s' * len(hyp) % tuple(hyp.keys()) # hyperparam keys
824
  b = '%10.3g' * len(hyp) % tuple(hyp.values()) # hyperparam values
825
+ c = '%10.4g' * len(results) % results # results (P, R, mAP@0.5, mAP@0.5:0.95, val_losses x 3)
826
  print('\n%s\n%s\nEvolved fitness: %s\n' % (a, b, c))
827
 
828
  if bucket:
 
831
  with open('evolve.txt', 'a') as f: # append result
832
  f.write(c + b + '\n')
833
  x = np.unique(np.loadtxt('evolve.txt', ndmin=2), axis=0) # load unique rows
834
+ x = x[np.argsort(-fitness(x))] # sort
835
+ np.savetxt('evolve.txt', x, '%10.3g') # save sort by fitness
836
 
837
  if bucket:
838
  os.system('gsutil cp evolve.txt gs://%s' % bucket) # upload evolve.txt
839
 
840
+ # Save yaml
841
+ for i, k in enumerate(hyp.keys()):
842
+ hyp[k] = float(x[0, i + 7])
843
+ with open(yaml_file, 'w') as f:
844
+ f.write('# Hyperparameter Evolution Results\n# Generations: %g\n# Metrics: ' % len(x) + c + '\n\n')
845
+ yaml.dump(hyp, f, sort_keys=False)
846
+
847
 
848
  def apply_classifier(x, model, img, im0):
849
  # applies a second stage classifier to yolo outputs
 
1154
  plt.close()
1155
 
1156
 
1157
+ def plot_evolution_results(yaml_file='hyp_evolved.yaml'): # from utils.utils import *; plot_evolution_results()
1158
  # Plot hyperparameter evolution results in evolve.txt
1159
+ with open(yaml_file) as f:
1160
+ hyp = yaml.load(f, Loader=yaml.FullLoader)
1161
  x = np.loadtxt('evolve.txt', ndmin=2)
1162
  f = fitness(x)
1163
  # weights = (f - f.min()) ** 2 # for weighted results
1164
+ plt.figure(figsize=(14, 10), tight_layout=True)
1165
  matplotlib.rc('font', **{'size': 8})
1166
  for i, (k, v) in enumerate(hyp.items()):
1167
  y = x[:, i + 7]
1168
  # mu = (y * weights).sum() / weights.sum() # best weighted result
1169
  mu = y[f.argmax()] # best single result
1170
+ plt.subplot(4, 6, i + 1)
1171
  plt.plot(mu, f.max(), 'o', markersize=10)
1172
  plt.plot(y, f, '.')
1173
  plt.title('%s = %.3g' % (k, mu), fontdict={'size': 9}) # limit to 40 characters
1174
  print('%15s: %.3g' % (k, mu))
1175
  plt.savefig('evolve.png', dpi=200)
1176
+ print('\nPlot saved as evolve.png')
1177
 
1178
 
1179
  def plot_results_overlay(start=0, stop=0): # from utils.utils import *; plot_results_overlay()