Spaces:
Running
Running
MilesCranmer
commited on
Commit
•
009d206
1
Parent(s):
a8f4864
Implement DaemonMode for fast startup
Browse files- Project.toml +1 -0
- pysr/sr.py +65 -14
Project.toml
CHANGED
@@ -1,4 +1,5 @@
|
|
1 |
[deps]
|
|
|
2 |
SymbolicRegression = "8254be44-1295-4e6a-a16d-46603ac705cb"
|
3 |
|
4 |
[compat]
|
|
|
1 |
[deps]
|
2 |
+
DaemonMode = "d749ddd5-2b29-4920-8305-6ff5a704e36e"
|
3 |
SymbolicRegression = "8254be44-1295-4e6a-a16d-46603ac705cb"
|
4 |
|
5 |
[compat]
|
pysr/sr.py
CHANGED
@@ -13,6 +13,8 @@ import shutil
|
|
13 |
from pathlib import Path
|
14 |
from datetime import datetime
|
15 |
import warnings
|
|
|
|
|
16 |
|
17 |
global_state = dict(
|
18 |
equation_file="hall_of_fame.csv",
|
@@ -26,6 +28,7 @@ global_state = dict(
|
|
26 |
multioutput=False,
|
27 |
nout=1,
|
28 |
selection=None,
|
|
|
29 |
)
|
30 |
|
31 |
sympy_mappings = {
|
@@ -132,6 +135,7 @@ def pysr(
|
|
132 |
tournament_selection_p=1.0,
|
133 |
denoise=False,
|
134 |
Xresampled=None,
|
|
|
135 |
):
|
136 |
"""Run symbolic regression to fit f(X[i, :]) ~ y[i] for all i.
|
137 |
Note: most default parameters have been tuned over several example
|
@@ -248,6 +252,10 @@ def pysr(
|
|
248 |
:type tournament_selection_p: float
|
249 |
:param denoise: Whether to use a Gaussian Process to denoise the data before inputting to PySR. Can help PySR fit noisy data.
|
250 |
:type denoise: bool
|
|
|
|
|
|
|
|
|
251 |
:returns: Results dataframe, giving complexity, MSE, and equations (as strings), as well as functional forms. If list, each element corresponds to a dataframe of equations for each output.
|
252 |
:type: pd.DataFrame/list
|
253 |
"""
|
@@ -410,6 +418,7 @@ def pysr(
|
|
410 |
tournament_selection_n=tournament_selection_n,
|
411 |
tournament_selection_p=tournament_selection_p,
|
412 |
denoise=denoise,
|
|
|
413 |
)
|
414 |
|
415 |
kwargs = {**_set_paths(tempdir), **kwargs}
|
@@ -467,12 +476,53 @@ def _set_globals(X, **kwargs):
|
|
467 |
global_state[key] = value
|
468 |
|
469 |
|
470 |
-
def
|
471 |
-
|
472 |
-
|
473 |
-
|
474 |
-
|
475 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
476 |
if timeout is not None:
|
477 |
command = ["timeout", f"{timeout}"] + command
|
478 |
_cmd_runner(command, **kwargs)
|
@@ -523,6 +573,7 @@ def _create_julia_files(
|
|
523 |
pkg_directory,
|
524 |
need_install,
|
525 |
update,
|
|
|
526 |
**kwargs,
|
527 |
):
|
528 |
with open(hyperparam_filename, "w") as f:
|
@@ -534,14 +585,14 @@ def _create_julia_files(
|
|
534 |
julia_project = pkg_directory
|
535 |
else:
|
536 |
julia_project = Path(julia_project)
|
537 |
-
|
538 |
-
|
539 |
-
|
540 |
-
|
541 |
-
|
542 |
-
|
543 |
-
|
544 |
-
|
545 |
print(f"using SymbolicRegression", file=f)
|
546 |
print(f'include("{_escape_filename(hyperparam_filename)}")', file=f)
|
547 |
print(f'include("{_escape_filename(dataset_filename)}")', file=f)
|
|
|
13 |
from pathlib import Path
|
14 |
from datetime import datetime
|
15 |
import warnings
|
16 |
+
import shlex
|
17 |
+
import time
|
18 |
|
19 |
global_state = dict(
|
20 |
equation_file="hall_of_fame.csv",
|
|
|
28 |
multioutput=False,
|
29 |
nout=1,
|
30 |
selection=None,
|
31 |
+
daemon=None,
|
32 |
)
|
33 |
|
34 |
sympy_mappings = {
|
|
|
135 |
tournament_selection_p=1.0,
|
136 |
denoise=False,
|
137 |
Xresampled=None,
|
138 |
+
daemon_mode=False,
|
139 |
):
|
140 |
"""Run symbolic regression to fit f(X[i, :]) ~ y[i] for all i.
|
141 |
Note: most default parameters have been tuned over several example
|
|
|
252 |
:type tournament_selection_p: float
|
253 |
:param denoise: Whether to use a Gaussian Process to denoise the data before inputting to PySR. Can help PySR fit noisy data.
|
254 |
:type denoise: bool
|
255 |
+
:param Xresampled:
|
256 |
+
:type Xresampled: np.ndarray/None
|
257 |
+
:param daemon_mode: Whether to use DaemonMode.jl for Julia. This will let you quickly restart PySR between calls.
|
258 |
+
:type daemon_mode: bool
|
259 |
:returns: Results dataframe, giving complexity, MSE, and equations (as strings), as well as functional forms. If list, each element corresponds to a dataframe of equations for each output.
|
260 |
:type: pd.DataFrame/list
|
261 |
"""
|
|
|
418 |
tournament_selection_n=tournament_selection_n,
|
419 |
tournament_selection_p=tournament_selection_p,
|
420 |
denoise=denoise,
|
421 |
+
daemon_mode=daemon_mode,
|
422 |
)
|
423 |
|
424 |
kwargs = {**_set_paths(tempdir), **kwargs}
|
|
|
476 |
global_state[key] = value
|
477 |
|
478 |
|
479 |
+
def _start_julia_daemon(
|
480 |
+
julia_optimization, julia_project, need_install, update, **kwargs
|
481 |
+
):
|
482 |
+
global global_state
|
483 |
+
if global_state["daemon"] is not None:
|
484 |
+
return
|
485 |
+
|
486 |
+
s = "import Pkg;"
|
487 |
+
if need_install:
|
488 |
+
s += "Pkg.instantiate();"
|
489 |
+
s += "Pkg.update();"
|
490 |
+
s += "Pkg.precompile();"
|
491 |
+
elif update:
|
492 |
+
s += "Pkg.update();"
|
493 |
+
command = shlex.split(
|
494 |
+
f"julia --startup-file=no -O{julia_optimization:d} --project={julia_project} -e"
|
495 |
+
f" '{s}using DaemonMode; println(\"Julia server starting!\"); serve(3000, true)'"
|
496 |
+
)
|
497 |
+
print("Running on", " ".join(command))
|
498 |
+
process = subprocess.Popen(command, stdout=subprocess.PIPE, bufsize=-1)
|
499 |
+
while True:
|
500 |
+
line = process.stdout.readline()
|
501 |
+
if not line:
|
502 |
+
break
|
503 |
+
decoded_line = line.decode("utf-8")
|
504 |
+
print(decoded_line, end="")
|
505 |
+
if "Julia server starting!" in decoded_line:
|
506 |
+
break
|
507 |
+
|
508 |
+
time.sleep(5)
|
509 |
+
print("Finished starting Julia daemon.")
|
510 |
+
global_state["daemon"] = process
|
511 |
+
|
512 |
+
|
513 |
+
def _final_pysr_process(
|
514 |
+
julia_optimization, julia_project, runfile_filename, timeout, daemon_mode, **kwargs
|
515 |
+
):
|
516 |
+
if daemon_mode:
|
517 |
+
_start_julia_daemon(
|
518 |
+
julia_optimization=julia_optimization, julia_project=julia_project, **kwargs
|
519 |
+
)
|
520 |
+
command = shlex.split(
|
521 |
+
f"julia --startup-file=no --project={julia_project}"
|
522 |
+
f" -e 'using DaemonMode; runargs()' {runfile_filename}"
|
523 |
+
)
|
524 |
+
else:
|
525 |
+
command = shlex.split(f"julia -O{julia_optimization:d} {runfile_filename}")
|
526 |
if timeout is not None:
|
527 |
command = ["timeout", f"{timeout}"] + command
|
528 |
_cmd_runner(command, **kwargs)
|
|
|
573 |
pkg_directory,
|
574 |
need_install,
|
575 |
update,
|
576 |
+
daemon_mode,
|
577 |
**kwargs,
|
578 |
):
|
579 |
with open(hyperparam_filename, "w") as f:
|
|
|
585 |
julia_project = pkg_directory
|
586 |
else:
|
587 |
julia_project = Path(julia_project)
|
588 |
+
if not daemon_mode:
|
589 |
+
print(f"import Pkg", file=f)
|
590 |
+
if need_install:
|
591 |
+
print(f"Pkg.instantiate()", file=f)
|
592 |
+
print("Pkg.update()", file=f)
|
593 |
+
print("Pkg.precompile()", file=f)
|
594 |
+
elif update:
|
595 |
+
print(f"Pkg.update()", file=f)
|
596 |
print(f"using SymbolicRegression", file=f)
|
597 |
print(f'include("{_escape_filename(hyperparam_filename)}")', file=f)
|
598 |
print(f'include("{_escape_filename(dataset_filename)}")', file=f)
|