Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Custom loss functions - v0.5.0 #28

Merged
merged 5 commits into from
Feb 12, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@
SymbolicRegression = "8254be44-1295-4e6a-a16d-46603ac705cb"

[compat]
SymbolicRegression = "0.4.2 - 0.4.9, 0.4.11"
julia = "1.4"
SymbolicRegression = "0.5.0"
julia = "1.5"
9 changes: 9 additions & 0 deletions docs/options.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ may find useful include:
- `variable_names` (or pandas input)
- Constraining operator complexity
- LaTeX, SymPy, and callable equation output
- `loss`

These are described below

Expand Down Expand Up @@ -158,3 +159,11 @@ for the best equation, using the `score` column to sort equations.
`best_latex()` returns the LaTeX form of this, and `best_callable()`
returns a callable function.

## `loss`

The default loss is mean-square error, and weighted mean-square error.
One can pass an arbitrary Julia string to define a custom loss, using,
e.g., `loss="myloss(x, y) = abs(x - y)^1.5"`. For more details,
see the
[Losses](https://milescranmer.github.io/SymbolicRegression.jl/dev/losses/)
page for SymbolicRegression.jl.
4 changes: 3 additions & 1 deletion example.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@
binary_operators=["plus", "mult"],
unary_operators=[
"cos", "exp", "sin", #Pre-defined library of operators (see https://pysr.readthedocs.io/en/latest/docs/operators/)
"inv(x) = 1/x"]) # Define your own operator! (Julia syntax)
"inv(x) = 1/x"],
loss='L1DistLoss()',
julia_project="../SymbolicRegression.jl") # Define your own operator! (Julia syntax)

...# (you can use ctl-c to exit early)

Expand Down
43 changes: 36 additions & 7 deletions pysr/sr.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,12 +57,13 @@
}

def pysr(X=None, y=None, weights=None,
binary_operators=["plus", "mult"],
unary_operators=["cos", "exp", "sin"],
procs=4,
loss='L2DistLoss()',
populations=None,
niterations=100,
ncyclesperiteration=300,
binary_operators=["plus", "mult"],
unary_operators=["cos", "exp", "sin"],
alpha=0.1,
annealing=True,
fractionReplaced=0.10,
Expand Down Expand Up @@ -116,16 +117,42 @@ def pysr(X=None, y=None, weights=None,
:param y: np.ndarray, 1D array. Rows are examples.
:param weights: np.ndarray, 1D array. Each row is how to weight the
mean-square-error loss on weights.
:param binary_operators: list, List of strings giving the binary operators
in Julia's Base.
:param unary_operators: list, Same but for operators taking a single scalar.
:param procs: int, Number of processes (=number of populations running).
:param loss: str, String of Julia code specifying the loss function.
Can either be a loss from LossFunctions.jl, or your own
loss written as a function. Examples of custom written losses
include: `myloss(x, y) = abs(x-y)` for non-weighted, or
`myloss(x, y, w) = w*abs(x-y)` for weighted.
Among the included losses, these are:
Regression:
- `LPDistLoss{P}()`,
- `L1DistLoss()`,
- `L2DistLoss()` (mean square),
- `LogitDistLoss()`,
- `HuberLoss(d)`,
- `L1EpsilonInsLoss(ϵ)`,
- `L2EpsilonInsLoss(ϵ)`,
- `PeriodicLoss(c)`,
- `QuantileLoss(τ)`,
Classification:
- `ZeroOneLoss()`,
- `PerceptronLoss()`,
- `L1HingeLoss()`,
- `SmoothedL1HingeLoss(γ)`,
- `ModifiedHuberLoss()`,
- `L2MarginLoss()`,
- `ExpLoss()`,
- `SigmoidLoss()`,
- `DWDMarginLoss(q)`.
:param populations: int, Number of populations running; by default=procs.
:param niterations: int, Number of iterations of the algorithm to run. The best
equations are printed, and migrate between populations, at the
end of each.
:param ncyclesperiteration: int, Number of total mutations to run, per 10
samples of the population, per iteration.
:param binary_operators: list, List of strings giving the binary operators
in Julia's Base, or in `operator.jl`.
:param unary_operators: list, Same but for operators taking a single `Float32`.
:param alpha: float, Initial temperature.
:param annealing: bool, Whether to use annealing. You should (and it is default).
:param fractionReplaced: float, How much of population to replace with migrating
Expand Down Expand Up @@ -262,7 +289,7 @@ def pysr(X=None, y=None, weights=None,
weightSimplify=weightSimplify,
constraints=constraints,
extra_sympy_mappings=extra_sympy_mappings,
julia_project=julia_project)
julia_project=julia_project, loss=loss)

kwargs = {**_set_paths(tempdir), **kwargs}

Expand Down Expand Up @@ -383,7 +410,7 @@ def _make_hyperparams_julia_str(X, alpha, annealing, batchSize, batching, binary
parsimony, perturbationFactor, populations, procs, shouldOptimizeConstants,
unary_operators, useFrequency, use_custom_variable_names,
variable_names, warmupMaxsize, weightAddNode,
ncyclesperiteration, fractionReplaced, topn, verbosity,
ncyclesperiteration, fractionReplaced, topn, verbosity, loss,
weightDeleteNode, weightDoNothing, weightInsertNode, weightMutateConstant,
weightMutateOperator, weightRandomize, weightSimplify, weights, **kwargs):
def tuple_fix(ops):
Expand Down Expand Up @@ -411,11 +438,13 @@ def tuple_fix(ops):
relu=SymbolicRegression.relu
logical_or=SymbolicRegression.logical_or
logical_and=SymbolicRegression.logical_and
_custom_loss = {loss}

options = SymbolicRegression.Options(binary_operators={'(' + tuple_fix(binary_operators) + ')'},
unary_operators={'(' + tuple_fix(unary_operators) + ')'},
{constraints_str}
parsimony={parsimony:f}f0,
loss=_custom_loss,
alpha={alpha:f}f0,
maxsize={maxsize:d},
maxdepth={maxdepth:d},
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

setuptools.setup(
name="pysr", # Replace with your own username
version="0.4.11",
version="0.5.0",
author="Miles Cranmer",
author_email="[email protected]",
description="Simple and efficient symbolic regression",
Expand Down