Spaces:
Sleeping
Sleeping
Merge pull request #208 from MilesCranmer/update-backend
Browse files- pysr/sr.py +50 -35
- pysr/version.py +2 -2
- test/test.py +4 -1
pysr/sr.py
CHANGED
|
@@ -476,6 +476,11 @@ class PySRRegressor(MultiOutputMixin, RegressorMixin, BaseEstimator):
|
|
| 476 |
algorithm than regularized evolution, but does cycles 15%
|
| 477 |
faster. May be algorithmically less efficient.
|
| 478 |
Default is `False`.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 479 |
precision : int
|
| 480 |
What precision to use for the data. By default this is `32`
|
| 481 |
(float32), but you can select `64` or `16` as well, giving
|
|
@@ -692,6 +697,7 @@ class PySRRegressor(MultiOutputMixin, RegressorMixin, BaseEstimator):
|
|
| 692 |
batching=False,
|
| 693 |
batch_size=50,
|
| 694 |
fast_cycle=False,
|
|
|
|
| 695 |
precision=32,
|
| 696 |
random_state=None,
|
| 697 |
deterministic=False,
|
|
@@ -779,6 +785,7 @@ class PySRRegressor(MultiOutputMixin, RegressorMixin, BaseEstimator):
|
|
| 779 |
self.batching = batching
|
| 780 |
self.batch_size = batch_size
|
| 781 |
self.fast_cycle = fast_cycle
|
|
|
|
| 782 |
self.precision = precision
|
| 783 |
self.random_state = random_state
|
| 784 |
self.deterministic = deterministic
|
|
@@ -1518,25 +1525,22 @@ class PySRRegressor(MultiOutputMixin, RegressorMixin, BaseEstimator):
|
|
| 1518 |
str(self.early_stop_condition) if self.early_stop_condition else None
|
| 1519 |
)
|
| 1520 |
|
| 1521 |
-
mutation_weights =
|
| 1522 |
-
|
| 1523 |
-
|
| 1524 |
-
|
| 1525 |
-
|
| 1526 |
-
|
| 1527 |
-
|
| 1528 |
-
|
| 1529 |
-
|
| 1530 |
-
self.weight_do_nothing,
|
| 1531 |
-
],
|
| 1532 |
-
dtype=float,
|
| 1533 |
)
|
| 1534 |
|
| 1535 |
# Call to Julia backend.
|
| 1536 |
# See https://github.com/MilesCranmer/SymbolicRegression.jl/blob/master/src/OptionsStruct.jl
|
| 1537 |
options = SymbolicRegression.Options(
|
| 1538 |
-
binary_operators=Main.eval(str(
|
| 1539 |
-
unary_operators=Main.eval(str(
|
| 1540 |
bin_constraints=bin_constraints,
|
| 1541 |
una_constraints=una_constraints,
|
| 1542 |
complexity_of_operators=complexity_of_operators,
|
|
@@ -1545,45 +1549,47 @@ class PySRRegressor(MultiOutputMixin, RegressorMixin, BaseEstimator):
|
|
| 1545 |
nested_constraints=nested_constraints,
|
| 1546 |
loss=custom_loss,
|
| 1547 |
maxsize=int(self.maxsize),
|
| 1548 |
-
|
| 1549 |
npopulations=int(self.populations),
|
| 1550 |
batching=self.batching,
|
| 1551 |
-
|
| 1552 |
-
|
| 1553 |
-
|
| 1554 |
-
|
| 1555 |
# These have the same name:
|
| 1556 |
parsimony=self.parsimony,
|
| 1557 |
alpha=self.alpha,
|
| 1558 |
maxdepth=maxdepth,
|
| 1559 |
fast_cycle=self.fast_cycle,
|
|
|
|
| 1560 |
migration=self.migration,
|
| 1561 |
-
|
| 1562 |
-
|
| 1563 |
-
|
| 1564 |
-
|
| 1565 |
-
|
| 1566 |
-
|
| 1567 |
npop=self.population_size,
|
| 1568 |
-
|
| 1569 |
-
|
| 1570 |
topn=self.topn,
|
| 1571 |
verbosity=self.verbosity,
|
| 1572 |
optimizer_algorithm=self.optimizer_algorithm,
|
| 1573 |
optimizer_nrestarts=self.optimizer_nrestarts,
|
| 1574 |
-
|
| 1575 |
optimizer_iterations=self.optimizer_iterations,
|
| 1576 |
-
|
| 1577 |
annealing=self.annealing,
|
| 1578 |
-
|
| 1579 |
progress=progress,
|
| 1580 |
timeout_in_seconds=self.timeout_in_seconds,
|
| 1581 |
-
|
| 1582 |
skip_mutation_failures=self.skip_mutation_failures,
|
| 1583 |
max_evals=self.max_evals,
|
| 1584 |
-
|
| 1585 |
seed=seed,
|
| 1586 |
deterministic=self.deterministic,
|
|
|
|
| 1587 |
)
|
| 1588 |
|
| 1589 |
# Convert data to desired precision
|
|
@@ -1603,7 +1609,16 @@ class PySRRegressor(MultiOutputMixin, RegressorMixin, BaseEstimator):
|
|
| 1603 |
else:
|
| 1604 |
Main.weights = None
|
| 1605 |
|
| 1606 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1607 |
|
| 1608 |
# Call to Julia backend.
|
| 1609 |
# See https://github.com/MilesCranmer/SymbolicRegression.jl/blob/master/src/SymbolicRegression.jl
|
|
@@ -1614,8 +1629,8 @@ class PySRRegressor(MultiOutputMixin, RegressorMixin, BaseEstimator):
|
|
| 1614 |
niterations=int(self.niterations),
|
| 1615 |
varMap=self.feature_names_in_.tolist(),
|
| 1616 |
options=options,
|
| 1617 |
-
numprocs=
|
| 1618 |
-
|
| 1619 |
saved_state=self.raw_julia_state_,
|
| 1620 |
addprocs_function=cluster_manager,
|
| 1621 |
)
|
|
|
|
| 476 |
algorithm than regularized evolution, but does cycles 15%
|
| 477 |
faster. May be algorithmically less efficient.
|
| 478 |
Default is `False`.
|
| 479 |
+
turbo: bool
|
| 480 |
+
(Experimental) Whether to use LoopVectorization.jl to speed up the
|
| 481 |
+
search evaluation. Certain operators may not be supported.
|
| 482 |
+
Does not support 16-bit precision floats.
|
| 483 |
+
Default is `False`.
|
| 484 |
precision : int
|
| 485 |
What precision to use for the data. By default this is `32`
|
| 486 |
(float32), but you can select `64` or `16` as well, giving
|
|
|
|
| 697 |
batching=False,
|
| 698 |
batch_size=50,
|
| 699 |
fast_cycle=False,
|
| 700 |
+
turbo=False,
|
| 701 |
precision=32,
|
| 702 |
random_state=None,
|
| 703 |
deterministic=False,
|
|
|
|
| 785 |
self.batching = batching
|
| 786 |
self.batch_size = batch_size
|
| 787 |
self.fast_cycle = fast_cycle
|
| 788 |
+
self.turbo = turbo
|
| 789 |
self.precision = precision
|
| 790 |
self.random_state = random_state
|
| 791 |
self.deterministic = deterministic
|
|
|
|
| 1525 |
str(self.early_stop_condition) if self.early_stop_condition else None
|
| 1526 |
)
|
| 1527 |
|
| 1528 |
+
mutation_weights = SymbolicRegression.MutationWeights(
|
| 1529 |
+
mutate_constant=self.weight_mutate_constant,
|
| 1530 |
+
mutate_operator=self.weight_mutate_operator,
|
| 1531 |
+
add_node=self.weight_add_node,
|
| 1532 |
+
insert_node=self.weight_insert_node,
|
| 1533 |
+
delete_node=self.weight_delete_node,
|
| 1534 |
+
simplify=self.weight_simplify,
|
| 1535 |
+
randomize=self.weight_randomize,
|
| 1536 |
+
do_nothing=self.weight_do_nothing,
|
|
|
|
|
|
|
|
|
|
| 1537 |
)
|
| 1538 |
|
| 1539 |
# Call to Julia backend.
|
| 1540 |
# See https://github.com/MilesCranmer/SymbolicRegression.jl/blob/master/src/OptionsStruct.jl
|
| 1541 |
options = SymbolicRegression.Options(
|
| 1542 |
+
binary_operators=Main.eval(str(binary_operators).replace("'", "")),
|
| 1543 |
+
unary_operators=Main.eval(str(unary_operators).replace("'", "")),
|
| 1544 |
bin_constraints=bin_constraints,
|
| 1545 |
una_constraints=una_constraints,
|
| 1546 |
complexity_of_operators=complexity_of_operators,
|
|
|
|
| 1549 |
nested_constraints=nested_constraints,
|
| 1550 |
loss=custom_loss,
|
| 1551 |
maxsize=int(self.maxsize),
|
| 1552 |
+
output_file=_escape_filename(self.equation_file_),
|
| 1553 |
npopulations=int(self.populations),
|
| 1554 |
batching=self.batching,
|
| 1555 |
+
batch_size=int(min([batch_size, len(X)]) if self.batching else len(X)),
|
| 1556 |
+
mutation_weights=mutation_weights,
|
| 1557 |
+
tournament_selection_p=self.tournament_selection_p,
|
| 1558 |
+
tournament_selection_n=self.tournament_selection_n,
|
| 1559 |
# These have the same name:
|
| 1560 |
parsimony=self.parsimony,
|
| 1561 |
alpha=self.alpha,
|
| 1562 |
maxdepth=maxdepth,
|
| 1563 |
fast_cycle=self.fast_cycle,
|
| 1564 |
+
turbo=self.turbo,
|
| 1565 |
migration=self.migration,
|
| 1566 |
+
hof_migration=self.hof_migration,
|
| 1567 |
+
fraction_replaced_hof=self.fraction_replaced_hof,
|
| 1568 |
+
should_optimize_constants=self.should_optimize_constants,
|
| 1569 |
+
warmup_maxsize_by=self.warmup_maxsize_by,
|
| 1570 |
+
use_frequency=self.use_frequency,
|
| 1571 |
+
use_frequency_in_tournament=self.use_frequency_in_tournament,
|
| 1572 |
npop=self.population_size,
|
| 1573 |
+
ncycles_per_iteration=self.ncyclesperiteration,
|
| 1574 |
+
fraction_replaced=self.fraction_replaced,
|
| 1575 |
topn=self.topn,
|
| 1576 |
verbosity=self.verbosity,
|
| 1577 |
optimizer_algorithm=self.optimizer_algorithm,
|
| 1578 |
optimizer_nrestarts=self.optimizer_nrestarts,
|
| 1579 |
+
optimizer_probability=self.optimize_probability,
|
| 1580 |
optimizer_iterations=self.optimizer_iterations,
|
| 1581 |
+
perturbation_factor=self.perturbation_factor,
|
| 1582 |
annealing=self.annealing,
|
| 1583 |
+
return_state=True, # Required for state saving.
|
| 1584 |
progress=progress,
|
| 1585 |
timeout_in_seconds=self.timeout_in_seconds,
|
| 1586 |
+
crossover_probability=self.crossover_probability,
|
| 1587 |
skip_mutation_failures=self.skip_mutation_failures,
|
| 1588 |
max_evals=self.max_evals,
|
| 1589 |
+
early_stop_condition=early_stop_condition,
|
| 1590 |
seed=seed,
|
| 1591 |
deterministic=self.deterministic,
|
| 1592 |
+
define_helper_functions=False,
|
| 1593 |
)
|
| 1594 |
|
| 1595 |
# Convert data to desired precision
|
|
|
|
| 1609 |
else:
|
| 1610 |
Main.weights = None
|
| 1611 |
|
| 1612 |
+
if self.procs == 0 and not multithreading:
|
| 1613 |
+
parallelism = "serial"
|
| 1614 |
+
elif multithreading:
|
| 1615 |
+
parallelism = "multithreading"
|
| 1616 |
+
else:
|
| 1617 |
+
parallelism = "multiprocessing"
|
| 1618 |
+
|
| 1619 |
+
cprocs = (
|
| 1620 |
+
None if parallelism in ["serial", "multithreading"] else int(self.procs)
|
| 1621 |
+
)
|
| 1622 |
|
| 1623 |
# Call to Julia backend.
|
| 1624 |
# See https://github.com/MilesCranmer/SymbolicRegression.jl/blob/master/src/SymbolicRegression.jl
|
|
|
|
| 1629 |
niterations=int(self.niterations),
|
| 1630 |
varMap=self.feature_names_in_.tolist(),
|
| 1631 |
options=options,
|
| 1632 |
+
numprocs=cprocs,
|
| 1633 |
+
parallelism=parallelism,
|
| 1634 |
saved_state=self.raw_julia_state_,
|
| 1635 |
addprocs_function=cluster_manager,
|
| 1636 |
)
|
pysr/version.py
CHANGED
|
@@ -1,2 +1,2 @@
|
|
| 1 |
-
__version__ = "0.11.
|
| 2 |
-
__symbolic_regression_jl_version__ = "0.
|
|
|
|
| 1 |
+
__version__ = "0.11.6"
|
| 2 |
+
__symbolic_regression_jl_version__ = "0.14.0"
|
test/test.py
CHANGED
|
@@ -70,12 +70,13 @@ class TestPipeline(unittest.TestCase):
|
|
| 70 |
print(model.equations_)
|
| 71 |
self.assertLessEqual(model.get_best()["loss"], 1e-4)
|
| 72 |
|
| 73 |
-
def
|
| 74 |
y = self.X[:, 0]
|
| 75 |
model = PySRRegressor(
|
| 76 |
**self.default_test_kwargs,
|
| 77 |
procs=2,
|
| 78 |
multithreading=False,
|
|
|
|
| 79 |
early_stop_condition="stop_if(loss, complexity) = loss < 1e-4 && complexity == 1",
|
| 80 |
)
|
| 81 |
model.fit(self.X, y)
|
|
@@ -108,6 +109,8 @@ class TestPipeline(unittest.TestCase):
|
|
| 108 |
verbosity=0,
|
| 109 |
**self.default_test_kwargs,
|
| 110 |
procs=0,
|
|
|
|
|
|
|
| 111 |
# Test custom operators with constraints:
|
| 112 |
nested_constraints={"square_op": {"square_op": 3}},
|
| 113 |
constraints={"square_op": 10},
|
|
|
|
| 70 |
print(model.equations_)
|
| 71 |
self.assertLessEqual(model.get_best()["loss"], 1e-4)
|
| 72 |
|
| 73 |
+
def test_multiprocessing_turbo(self):
|
| 74 |
y = self.X[:, 0]
|
| 75 |
model = PySRRegressor(
|
| 76 |
**self.default_test_kwargs,
|
| 77 |
procs=2,
|
| 78 |
multithreading=False,
|
| 79 |
+
turbo=True,
|
| 80 |
early_stop_condition="stop_if(loss, complexity) = loss < 1e-4 && complexity == 1",
|
| 81 |
)
|
| 82 |
model.fit(self.X, y)
|
|
|
|
| 109 |
verbosity=0,
|
| 110 |
**self.default_test_kwargs,
|
| 111 |
procs=0,
|
| 112 |
+
# Test custom operators with turbo:
|
| 113 |
+
turbo=True,
|
| 114 |
# Test custom operators with constraints:
|
| 115 |
nested_constraints={"square_op": {"square_op": 3}},
|
| 116 |
constraints={"square_op": 10},
|