Custom loss with partial derivatives for 2 inputs and 2 outputs function. #1174
Replies: 2 comments 8 replies
-
|
I think you could try doing this with TemplateExpressionSpec and I'll do some digging for relevant issues... (@MilesCranmerBot can you please read through discussions/issues over the past year and point to the most relevant ones? Ideally it would be nice if you could find a discussion that shows how to use |
Beta Was this translation helpful? Give feedback.
-
|
So this is what I have: d = np.linspace(5, 1400, 500)
T = np.linspace(refprop.T_min, 450, 500)
D, T_grid = np.meshgrid(d, T)
p, h = ph_dt(D, T_grid)
pp = p[~np.isnan(p) & ~np.isnan(h)]
hh = h[~np.isnan(p) & ~np.isnan(h)]
DD = D[~np.isnan(p) & ~np.isnan(h)]
TT = T_grid[~np.isnan(p) & ~np.isnan(h)]
X = np.column_stack((pp.ravel(), hh.ravel(), DD.ravel(), TT.ravel()))
dummy_y = np.zeros(X.shape[0])
from pysr import jl, PySRRegressor, TemplateExpressionSpec
jl.seval("using Zygote") # For gradient calculations
template = TemplateExpressionSpec(
variable_names=["p", "h", "d", "T"],
expressions=["f1", "f2"],
combine="abs(d - f1(p,h)) + abs(T - f2(p,h)) + abs(D(f1,1)(p,h)*D(f2,2)(p,h) - D(f1,2)(p,h)*D(f2,1)(p,h))",
# L1 loss for d and T + det(Jacobian) noteq 0
)
model = PySRRegressor(
unary_operators=["log", "exp"],
nested_constraints={
"log": {"log": 0, "exp": 0},
"exp": {"exp": 0, "log": 0},
},
maxsize=35,
weight_optimize=0.001,
batching=True, # Enable mini-batch training
batch_size=1024, # Recommended batch size (adjust as needed)
niterations=100, # Number of iterations (adjust for complexity)
binary_operators=["+", "-", "*", "/", "^"], # Operators
constraints={"^": (-1,1)}, # Allow the model to fit the exponent "a"
populations=100, # Number of populations (influences exploration)
population_size=100, # Number of individuals in each population
ncycles_per_iteration=100, # Number of total mutations to run, per 10 samples of the population, per iteration
model_selection="best", # Keep the best-performing model
parsimony=1e-5, # parsimony (times complexity) added to the loss
maxdepth=7, # Max depth of the equation
progress=True, # Display training progress
verbosity=1, # Show intermediate output
expression_spec=template,
elementwise_loss="(pred, targ) -> pred"
)
model.fit(X, dummy_y, variable_names = ["p", "h", "d", "T"])And it seems to work so thank you ! Howeve, I encountered a different issue and I suspect it has to do with the derivatives: None of the variables contain negative values and this wasn't happening before. I suspect something is going on with the derivatives but I have no idea why. To go around this issue I modified the model like that, using safe version of log and pow: extra_sympy_mappings={
"slog": sympy.log,
"spow": lambda x, y: x**y
},
model = PySRRegressor(
unary_operators=["exp", "slog(x) = x > 0 ? log(x) : typeof(x)(NaN)"],
nested_constraints={
"slog": {"slog": 0, "exp": 0},
"exp": {"exp": 0, "slog": 0},
},
binary_operators=["+", "-", "*", "/", "spow(x, y) = x > 0 ? x^y : typeof(x)(NaN)"],
constraints={"spow": (-1,1)},
extra_sympy_mappings=extra_sympy_mappings,But I don't know what changed and if the log of negative values is a bug or not. |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
Hi everyone,
I am currently trying to use PySR for finding an approximant for the inverse of a function. I apologize if there is something trivial that I missed but I haven't been able to find a discussion or an issue for something similar.
I want to find two functions, f1 and f2, such that:
I also have a custom condition on their partial derivatives that I want to enforce during the optimization process:
My hope is that this condition will help steer the algorithm toward solutions that are physically meaningful.
I have X and y of shape (241127, 2), where:
X contains the inputs [P, h]
y contains the targets [d, T]
I used a custom loss function in PySR to combine the standard MSE loss with the derivative condition.
When I tried to implement the custom loss, I got a BoundsError:
BoundsError: attempt to access 2×241127 Matrix{Float32} at index [1:2, 1, 2]This suggests that eval_grad_tree_array only returns a (2, N) matrix (2 variables × N data points), not the full Jacobian for both outputs.
My attempts to extract four derivatives
(df1/dP, df1/dh, df2/dP, df2/dh)failed because PySR appears to call the loss function separately for each output (or at least it's my guess).Is it possible to enforce such a condition in PySR with a single loss function for two outputs?
If not, is there a recommended way to achieve this ?
Beta Was this translation helpful? Give feedback.
All reactions