MilesCranmer commited on
Commit
35b5720
1 Parent(s): c2c1511

Introduce perturbation factor

Browse files
Files changed (3) hide show
  1. eureqa.jl +10 -21
  2. eureqa.py +6 -1
  3. hyperparamopt.py +5 -4
eureqa.jl CHANGED
@@ -208,7 +208,7 @@ function mutateConstant(
208
  end
209
 
210
  bottom = 0.1f0
211
- maxChange = T + 1.0f0 + bottom
212
  factor = maxChange^Float32(rand())
213
  makeConstBigger = rand() > 0.5
214
 
@@ -490,10 +490,7 @@ end
490
 
491
  # Go through one simulated annealing mutation cycle
492
  # exp(-delta/T) defines probability of accepting a change
493
- function iterate(
494
- tree::Node, T::Float32;
495
- annealing::Bool=true
496
- )::Node
497
  prev = tree
498
  tree = copyNode(tree)
499
 
@@ -592,13 +589,9 @@ function bestSubPop(pop::Population; topn::Integer=10)::Population
592
  end
593
 
594
  # Mutate the best sampled member of the population
595
- function iterateSample(
596
- pop::Population, T::Float32;
597
- annealing::Bool=true)::PopMember
598
  allstar = bestOfSample(pop)
599
- new = iterate(
600
- allstar.tree, T,
601
- annealing=annealing)
602
  allstar.tree = new
603
  allstar.score = scoreFunc(new)
604
  allstar.birth = getTime()
@@ -607,11 +600,9 @@ end
607
 
608
  # Pass through the population several times, replacing the oldest
609
  # with the fittest of a small subsample
610
- function regEvolCycle(
611
- pop::Population, T::Float32;
612
- annealing::Bool=true)::Population
613
  for i=1:round(Integer, pop.n/ns)
614
- baby = iterateSample(pop, T, annealing=annealing)
615
  #printTree(baby.tree)
616
  oldest = argmin([pop.members[member].birth for member=1:pop.n])
617
  pop.members[oldest] = baby
@@ -623,17 +614,16 @@ end
623
  # printing the fittest equation every 10% through
624
  function run(
625
  pop::Population,
626
- ncycles::Integer,
627
- annealing::Bool=false;
628
  verbosity::Integer=0
629
  )::Population
630
 
631
  allT = LinRange(1.0f0, 0.0f0, ncycles)
632
  for iT in 1:size(allT)[1]
633
  if annealing
634
- pop = regEvolCycle(pop, allT[iT], annealing=true)
635
  else
636
- pop = regEvolCycle(pop, 1.0f0, annealing=true)
637
  end
638
 
639
  if verbosity > 0 && (iT % verbosity == 0)
@@ -721,7 +711,6 @@ end
721
 
722
  function fullRun(niterations::Integer;
723
  npop::Integer=300,
724
- annealing::Bool=true,
725
  ncyclesperiteration::Integer=3000,
726
  fractionReplaced::Float32=0.1f0,
727
  verbosity::Integer=0,
@@ -738,7 +727,7 @@ function fullRun(niterations::Integer;
738
  for k=1:niterations
739
  # Spawn threads to run indepdent evolutions, then gather them
740
  @inbounds Threads.@threads for i=1:nthreads
741
- allPops[i] = run(allPops[i], ncyclesperiteration, annealing, verbosity=verbosity)
742
  bestSubPops[i] = bestSubPop(allPops[i], topn=topn)
743
  for j=1:bestSubPops[i].n
744
  bestSubPops[i].members[j].tree = simplifyTree(bestSubPops[i].members[j].tree)
 
208
  end
209
 
210
  bottom = 0.1f0
211
+ maxChange = perturbationFactor * T + 1.0f0 + bottom
212
  factor = maxChange^Float32(rand())
213
  makeConstBigger = rand() > 0.5
214
 
 
490
 
491
  # Go through one simulated annealing mutation cycle
492
  # exp(-delta/T) defines probability of accepting a change
493
+ function iterate(tree::Node, T::Float32)::Node
 
 
 
494
  prev = tree
495
  tree = copyNode(tree)
496
 
 
589
  end
590
 
591
  # Mutate the best sampled member of the population
592
+ function iterateSample(pop::Population, T::Float32)::PopMember
 
 
593
  allstar = bestOfSample(pop)
594
+ new = iterate(allstar.tree, T)
 
 
595
  allstar.tree = new
596
  allstar.score = scoreFunc(new)
597
  allstar.birth = getTime()
 
600
 
601
  # Pass through the population several times, replacing the oldest
602
  # with the fittest of a small subsample
603
+ function regEvolCycle(pop::Population, T::Float32)::Population
 
 
604
  for i=1:round(Integer, pop.n/ns)
605
+ baby = iterateSample(pop, T)
606
  #printTree(baby.tree)
607
  oldest = argmin([pop.members[member].birth for member=1:pop.n])
608
  pop.members[oldest] = baby
 
614
  # printing the fittest equation every 10% through
615
  function run(
616
  pop::Population,
617
+ ncycles::Integer;
 
618
  verbosity::Integer=0
619
  )::Population
620
 
621
  allT = LinRange(1.0f0, 0.0f0, ncycles)
622
  for iT in 1:size(allT)[1]
623
  if annealing
624
+ pop = regEvolCycle(pop, allT[iT])
625
  else
626
+ pop = regEvolCycle(pop, 1.0f0)
627
  end
628
 
629
  if verbosity > 0 && (iT % verbosity == 0)
 
711
 
712
  function fullRun(niterations::Integer;
713
  npop::Integer=300,
 
714
  ncyclesperiteration::Integer=3000,
715
  fractionReplaced::Float32=0.1f0,
716
  verbosity::Integer=0,
 
727
  for k=1:niterations
728
  # Spawn threads to run indepdent evolutions, then gather them
729
  @inbounds Threads.@threads for i=1:nthreads
730
+ allPops[i] = run(allPops[i], ncyclesperiteration, verbosity=verbosity)
731
  bestSubPops[i] = bestSubPop(allPops[i], topn=topn)
732
  for j=1:bestSubPops[i].n
733
  bestSubPops[i].members[j].tree = simplifyTree(bestSubPops[i].members[j].tree)
eureqa.py CHANGED
@@ -21,6 +21,7 @@ default_weightDoNothing = 1
21
  default_result = 1
22
  default_topn = 10
23
  default_parsimony = 0.0
 
24
 
25
 
26
  def eureqa(X=None, y=None, threads=4,
@@ -46,6 +47,7 @@ def eureqa(X=None, y=None, threads=4,
46
  weightMutateOperator=default_weightMutateOperator,
47
  weightRandomize=default_weightRandomize,
48
  weightSimplify=default_weightSimplify,
 
49
  timeout=None,
50
  equation_file='hall_of_fame.csv',
51
  test='simple1',
@@ -138,6 +140,8 @@ const fractionReplacedHof = {fractionReplacedHof}f0
138
  const shouldOptimizeConstants = {'true' if shouldOptimizeConstants else 'false'}
139
  const hofFile = "{equation_file}"
140
  const nthreads = {threads:d}
 
 
141
  const mutationWeights = [
142
  {weightMutateConstant:f},
143
  {weightMutateOperator:f},
@@ -175,7 +179,7 @@ const y = convert(Array{Float32, 1}, """f"{y_str})""""
175
  'julia -O3',
176
  f'--threads {threads}',
177
  '-e',
178
- f'\'include(".hyperparams_{rand_string}.jl"); include(".dataset_{rand_string}.jl"); include("eureqa.jl"); fullRun({niterations:d}, npop={npop:d}, annealing={"true" if annealing else "false"}, ncyclesperiteration={ncyclesperiteration:d}, fractionReplaced={fractionReplaced:f}f0, verbosity=round(Int32, {verbosity:f}), topn={topn:d})\'',
179
  ]
180
  if timeout is not None:
181
  command = [f'timeout {timeout}'] + command
@@ -203,6 +207,7 @@ if __name__ == "__main__":
203
  parser.add_argument("--npop", type=int, default=int(default_npop), help="Number of members per population")
204
  parser.add_argument("--ncyclesperiteration", type=int, default=10000, help="Number of evolutionary cycles per migration")
205
  parser.add_argument("--topn", type=int, default=int(default_topn), help="How many best species to distribute from each population")
 
206
  parser.add_argument("--fractionReplacedHof", type=float, default=default_fractionReplacedHof, help="Fraction of population to replace with hall of fame")
207
  parser.add_argument("--fractionReplaced", type=float, default=default_fractionReplaced, help="Fraction of population to replace with best from other populations")
208
  parser.add_argument("--weightAddNode", type=float, default=default_weightAddNode)
 
21
  default_result = 1
22
  default_topn = 10
23
  default_parsimony = 0.0
24
+ default_perturbationFactor = 1.0
25
 
26
 
27
  def eureqa(X=None, y=None, threads=4,
 
47
  weightMutateOperator=default_weightMutateOperator,
48
  weightRandomize=default_weightRandomize,
49
  weightSimplify=default_weightSimplify,
50
+ perturbationFactor=default_perturbationFactor,
51
  timeout=None,
52
  equation_file='hall_of_fame.csv',
53
  test='simple1',
 
140
  const shouldOptimizeConstants = {'true' if shouldOptimizeConstants else 'false'}
141
  const hofFile = "{equation_file}"
142
  const nthreads = {threads:d}
143
+ const perturbationFactor = {perturbationFactor:f}f0
144
+ const annealing = {"true" if annealing else "false"}
145
  const mutationWeights = [
146
  {weightMutateConstant:f},
147
  {weightMutateOperator:f},
 
179
  'julia -O3',
180
  f'--threads {threads}',
181
  '-e',
182
+ f'\'include(".hyperparams_{rand_string}.jl"); include(".dataset_{rand_string}.jl"); include("eureqa.jl"); fullRun({niterations:d}, npop={npop:d}, ncyclesperiteration={ncyclesperiteration:d}, fractionReplaced={fractionReplaced:f}f0, verbosity=round(Int32, {verbosity:f}), topn={topn:d})\'',
183
  ]
184
  if timeout is not None:
185
  command = [f'timeout {timeout}'] + command
 
207
  parser.add_argument("--npop", type=int, default=int(default_npop), help="Number of members per population")
208
  parser.add_argument("--ncyclesperiteration", type=int, default=10000, help="Number of evolutionary cycles per migration")
209
  parser.add_argument("--topn", type=int, default=int(default_topn), help="How many best species to distribute from each population")
210
+ parser.add_argument("--perturbationFactor", type=float, default=default_perturbationFactor)
211
  parser.add_argument("--fractionReplacedHof", type=float, default=default_fractionReplacedHof, help="Fraction of population to replace with hall of fame")
212
  parser.add_argument("--fractionReplaced", type=float, default=default_fractionReplaced, help="Fraction of population to replace with best from other populations")
213
  parser.add_argument("--weightAddNode", type=float, default=default_weightAddNode)
hyperparamopt.py CHANGED
@@ -38,7 +38,7 @@ def run_trial(args):
38
  args[key] = int(args[key])
39
 
40
 
41
- total_steps = 20*100*5000
42
  niterations = args['niterations']
43
  npop = args['npop']
44
  if niterations == 0 or npop == 0:
@@ -57,7 +57,7 @@ def run_trial(args):
57
 
58
  args['weightDoNothing'] = 1.0
59
 
60
- maxTime = 3*60
61
  ntrials = 2
62
  equation_file = f'.hall_of_fame_{np.random.rand():f}.csv'
63
 
@@ -73,13 +73,13 @@ def run_trial(args):
73
  print(f"Starting", str(args))
74
  try:
75
  trials = []
76
- for i in range(1, 6):
77
  print(f"Starting test {i}")
78
  for j in range(ntrials):
79
  print(f"Starting trial {j}")
80
  trial = eureqa.eureqa(
81
  test=f"simple{i}",
82
- threads=8,
83
  binary_operators=["plus", "mult", "pow", "div"],
84
  unary_operators=["cos", "exp", "sin", "loga", "abs"],
85
  equation_file=equation_file,
@@ -114,6 +114,7 @@ space = {
114
  'alpha': hp.lognormal('alpha', np.log(10.0), 1.0),
115
  'fractionReplacedHof': hp.lognormal('fractionReplacedHof', np.log(0.1), 1.0),
116
  'fractionReplaced': hp.lognormal('fractionReplaced', np.log(0.1), 1.0),
 
117
  'weightMutateConstant': hp.lognormal('weightMutateConstant', np.log(4.0), 1.0),
118
  'weightMutateOperator': hp.lognormal('weightMutateOperator', np.log(0.5), 1.0),
119
  'weightAddNode': hp.lognormal('weightAddNode', np.log(0.5), 1.0),
 
38
  args[key] = int(args[key])
39
 
40
 
41
+ total_steps = 10*100*1000
42
  niterations = args['niterations']
43
  npop = args['npop']
44
  if niterations == 0 or npop == 0:
 
57
 
58
  args['weightDoNothing'] = 1.0
59
 
60
+ maxTime = 30
61
  ntrials = 2
62
  equation_file = f'.hall_of_fame_{np.random.rand():f}.csv'
63
 
 
73
  print(f"Starting", str(args))
74
  try:
75
  trials = []
76
+ for i in range(3, 6):
77
  print(f"Starting test {i}")
78
  for j in range(ntrials):
79
  print(f"Starting trial {j}")
80
  trial = eureqa.eureqa(
81
  test=f"simple{i}",
82
+ threads=4,
83
  binary_operators=["plus", "mult", "pow", "div"],
84
  unary_operators=["cos", "exp", "sin", "loga", "abs"],
85
  equation_file=equation_file,
 
114
  'alpha': hp.lognormal('alpha', np.log(10.0), 1.0),
115
  'fractionReplacedHof': hp.lognormal('fractionReplacedHof', np.log(0.1), 1.0),
116
  'fractionReplaced': hp.lognormal('fractionReplaced', np.log(0.1), 1.0),
117
+ 'perturbationFactor': hp.lognormal('perturbationFactor', np.log(1.0), 1.0),
118
  'weightMutateConstant': hp.lognormal('weightMutateConstant', np.log(4.0), 1.0),
119
  'weightMutateOperator': hp.lognormal('weightMutateOperator', np.log(0.5), 1.0),
120
  'weightAddNode': hp.lognormal('weightAddNode', np.log(0.5), 1.0),