MilesCranmer commited on
Commit
78cf882
1 Parent(s): 81463ee

Clean up API; make const optimization random

Browse files
Files changed (2) hide show
  1. julia/sr.jl +18 -14
  2. pysr/sr.py +18 -33
julia/sr.jl CHANGED
@@ -684,18 +684,20 @@ function optimizeConstants(member::PopMember)::PopMember
684
  x0 = getConstants(member.tree)
685
  f(x::Array{Float32,1})::Float32 = optFunc(x, member.tree)
686
  if size(x0)[1] == 1
687
- result = Optim.optimize(f, x0, Optim.Newton(), Optim.Options(iterations=20))
688
  else
689
- result = Optim.optimize(f, x0, Optim.NelderMead(), Optim.Options(iterations=100))
 
690
 
691
- # Try other initial conditions:
692
- for i=1:5
693
- tmpresult = Optim.optimize(f, x0 .* (1f0 .+ 5f-1*randn(Float32, size(x0)[1])), Optim.NelderMead(), Optim.Options(iterations=100))
694
- if tmpresult.minimum < result.minimum
695
- result = tmpresult
696
- end
697
  end
698
  end
 
699
  if Optim.converged(result)
700
  setConstants(member.tree, result.minimizer)
701
  member.score = convert(Float32, result.minimum)
@@ -736,14 +738,16 @@ function fullRun(niterations::Integer;
736
  # Spawn threads to run indepdent evolutions, then gather them
737
  @inbounds Threads.@threads for i=1:nthreads
738
  allPops[i] = run(allPops[i], ncyclesperiteration, verbosity=verbosity)
739
- bestSubPops[i] = bestSubPop(allPops[i], topn=topn)
740
- for j=1:bestSubPops[i].n
741
- bestSubPops[i].members[j].tree = simplifyTree(bestSubPops[i].members[j].tree)
742
- bestSubPops[i].members[j].tree = combineOperators(bestSubPops[i].members[j].tree)
743
- if shouldOptimizeConstants
744
- bestSubPops[i].members[j] = optimizeConstants(bestSubPops[i].members[j])
 
745
  end
746
  end
 
747
  end
748
 
749
  # Get best 10 models from each evolution. Copy because we re-assign later.
 
684
  x0 = getConstants(member.tree)
685
  f(x::Array{Float32,1})::Float32 = optFunc(x, member.tree)
686
  if size(x0)[1] == 1
687
+ algorithm = Optim.Newton
688
  else
689
+ algorithm = Optim.NelderMead
690
+ end
691
 
692
+ result = Optim.optimize(f, x0, algorithm(), Optim.Options(iterations=100))
693
+ # Try other initial conditions:
694
+ for i=1:nrestarts
695
+ tmpresult = Optim.optimize(f, x0 .* (1f0 .+ 5f-1*randn(Float32, size(x0)[1])), algorithm(), Optim.Options(iterations=100))
696
+ if tmpresult.minimum < result.minimum
697
+ result = tmpresult
698
  end
699
  end
700
+
701
  if Optim.converged(result)
702
  setConstants(member.tree, result.minimizer)
703
  member.score = convert(Float32, result.minimum)
 
738
  # Spawn threads to run indepdent evolutions, then gather them
739
  @inbounds Threads.@threads for i=1:nthreads
740
  allPops[i] = run(allPops[i], ncyclesperiteration, verbosity=verbosity)
741
+ for j=1:allPops[i].n
742
+ if rand() < 0.1
743
+ allPops[i].members[j].tree = simplifyTree(allPops[i].members[j].tree)
744
+ allPops[i].members[j].tree = combineOperators(allPops[i].members[j].tree)
745
+ if shouldOptimizeConstants
746
+ allPops[i].members[j] = optimizeConstants(allPops[i].members[j])
747
+ end
748
  end
749
  end
750
+ bestSubPops[i] = bestSubPop(allPops[i], topn=topn)
751
  end
752
 
753
  # Get best 10 models from each evolution. Copy because we re-assign later.
pysr/sr.py CHANGED
@@ -5,48 +5,31 @@ import pathlib
5
  import numpy as np
6
  import pandas as pd
7
 
8
- # Dumped from hyperparam optimization
9
- default_alpha = 1.0#0.1
10
- default_fractionReplaced = 0.10
11
- default_fractionReplacedHof = 0.10
12
- default_npop = 1000
13
- default_weightAddNode = 1
14
- default_weightInsertNode = 3
15
- default_weightDeleteNode = 3
16
- default_weightMutateConstant = 10
17
- default_weightMutateOperator = 1
18
- default_weightRandomize = 1
19
- default_weightSimplify = 0.01
20
- default_weightDoNothing = 1
21
- default_result = 1
22
- default_topn = 10
23
- default_parsimony = 1e-4
24
- default_perturbationFactor = 1.0
25
-
26
  def pysr(X=None, y=None, threads=4,
27
  niterations=100,
28
  ncyclesperiteration=300,
29
  binary_operators=["plus", "mult"],
30
  unary_operators=["cos", "exp", "sin"],
31
- alpha=default_alpha,
32
  annealing=True,
33
- fractionReplaced=default_fractionReplaced,
34
- fractionReplacedHof=default_fractionReplacedHof,
35
- npop=int(default_npop),
36
- parsimony=default_parsimony,
37
  migration=True,
38
  hofMigration=True,
39
  shouldOptimizeConstants=True,
40
- topn=int(default_topn),
41
- weightAddNode=default_weightAddNode,
42
- weightInsertNode=default_weightInsertNode,
43
- weightDeleteNode=default_weightDeleteNode,
44
- weightDoNothing=default_weightDoNothing,
45
- weightMutateConstant=default_weightMutateConstant,
46
- weightMutateOperator=default_weightMutateOperator,
47
- weightRandomize=default_weightRandomize,
48
- weightSimplify=default_weightSimplify,
49
- perturbationFactor=default_perturbationFactor,
 
50
  timeout=None,
51
  equation_file='hall_of_fame.csv',
52
  test='simple1',
@@ -84,6 +67,7 @@ def pysr(X=None, y=None, threads=4,
84
  :param shouldOptimizeConstants: bool, Whether to numerically optimize
85
  constants (Nelder-Mead/Newton) at the end of each iteration.
86
  :param topn: int, How many top individuals migrate from each population.
 
87
  :param weightAddNode: float, Relative likelihood for mutation to add a node
88
  :param weightInsertNode: float, Relative likelihood for mutation to insert a node
89
  :param weightDeleteNode: float, Relative likelihood for mutation to delete a node
@@ -141,6 +125,7 @@ const fractionReplacedHof = {fractionReplacedHof}f0
141
  const shouldOptimizeConstants = {'true' if shouldOptimizeConstants else 'false'}
142
  const hofFile = "{equation_file}"
143
  const nthreads = {threads:d}
 
144
  const perturbationFactor = {perturbationFactor:f}f0
145
  const annealing = {"true" if annealing else "false"}
146
  const mutationWeights = [
 
5
  import numpy as np
6
  import pandas as pd
7
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8
  def pysr(X=None, y=None, threads=4,
9
  niterations=100,
10
  ncyclesperiteration=300,
11
  binary_operators=["plus", "mult"],
12
  unary_operators=["cos", "exp", "sin"],
13
+ alpha=0.1,
14
  annealing=True,
15
+ fractionReplaced=0.10,
16
+ fractionReplacedHof=0.10,
17
+ npop=1000,
18
+ parsimony=1e-4,
19
  migration=True,
20
  hofMigration=True,
21
  shouldOptimizeConstants=True,
22
+ topn=10,
23
+ weightAddNode=1,
24
+ weightInsertNode=3,
25
+ weightDeleteNode=3,
26
+ weightDoNothing=1,
27
+ weightMutateConstant=10,
28
+ weightMutateOperator=1,
29
+ weightRandomize=1,
30
+ weightSimplify=0.01,
31
+ perturbationFactor=1.0,
32
+ nrestarts=3,
33
  timeout=None,
34
  equation_file='hall_of_fame.csv',
35
  test='simple1',
 
67
  :param shouldOptimizeConstants: bool, Whether to numerically optimize
68
  constants (Nelder-Mead/Newton) at the end of each iteration.
69
  :param topn: int, How many top individuals migrate from each population.
70
+ :param nrestarts: int, Number of times to restart the constant optimizer
71
  :param weightAddNode: float, Relative likelihood for mutation to add a node
72
  :param weightInsertNode: float, Relative likelihood for mutation to insert a node
73
  :param weightDeleteNode: float, Relative likelihood for mutation to delete a node
 
125
  const shouldOptimizeConstants = {'true' if shouldOptimizeConstants else 'false'}
126
  const hofFile = "{equation_file}"
127
  const nthreads = {threads:d}
128
+ const nrestarts = {nrestarts:d}
129
  const perturbationFactor = {perturbationFactor:f}f0
130
  const annealing = {"true" if annealing else "false"}
131
  const mutationWeights = [