MilesCranmer / PySR

High-Performance Symbolic Regression in Python and Julia
https://astroautomata.com/PySR
Apache License 2.0
2.24k stars 209 forks source link

[BUG]: PySRRegressor.from_file throws AttributeError #700

Open tbuckworth opened 3 weeks ago

tbuckworth commented 3 weeks ago

What happened?

When loading a saved model with from_file, an AttributeError is thrown:

AttributeError: 'PySRRegressor' object has no attribute 'dimensionless_constants_only'

I am using version 0.18.4 and it is possible that the model I am loading was saved under an older version (0.17.2 maybe) - could that be the problem?

Version

0.18.4

Operating System

Linux

Package Manager

pip

Interface

Script (i.e., python my_script.py)

Relevant log output

msg_model = PySRRegressor.from_file(pickle_filename, extra_torch_mappings=get_extra_torch_mappings())
Checking if logs/train/cartpole/2024-07-11__04-48-25__seed_6033/symbreg/2024-07-22__04-36-52/msg/2024-07-22__04-36-55/symb_reg.pkl exists...
Loading model from logs/train/cartpole/2024-07-11__04-48-25__seed_6033/symbreg/2024-07-22__04-36-52/msg/2024-07-22__04-36-55/symb_reg.pkl
Traceback (most recent call last):
  File "/home/titus/PycharmProjects/train-procgen-pytorch/venv/lib/python3.8/site-packages/IPython/core/interactiveshell.py", line 3508, in run_code
    exec(code_obj, self.user_global_ns, self.user_ns)
  File "<ipython-input-7-fec4b34b7d62>", line 1, in <module>
    msg_model = PySRRegressor.from_file(pickle_filename, extra_torch_mappings=get_extra_torch_mappings())
  File "/home/titus/PycharmProjects/train-procgen-pytorch/venv/lib/python3.8/site-packages/pysr/sr.py", line 969, in from_file
    model.set_params(**pysr_kwargs)
  File "/home/titus/PycharmProjects/train-procgen-pytorch/venv/lib/python3.8/site-packages/sklearn/base.py", line 223, in set_params
    valid_params = self.get_params(deep=True)
  File "/home/titus/PycharmProjects/train-procgen-pytorch/venv/lib/python3.8/site-packages/sklearn/base.py", line 195, in get_params
    value = getattr(self, key)
AttributeError: 'PySRRegressor' object has no attribute 'dimensionless_constants_only'

Extra Info

No response

MilesCranmer commented 3 weeks ago

I am using version 0.18.4 and it is possible that the model I am loading was saved under an older version (0.17.2 maybe) - could that be the problem?

Yes this seems to be the cause. That variable was only introduced more recently. However this seems like it would be a common enough issue with pickle so I’m assuming there’s some sort of easy workaround we can use?

MilesCranmer commented 3 weeks ago

I guess maybe the error is inevitable. Though it would be nicer if PySR could print a nicer error, maybe by saving the PySR version used to create the pickle file.

tbuckworth commented 3 weeks ago

I have found a workaround by inspecting the error a bit closer.

The problem is in sklearn.BaseEstimator. In the get_params method, _get_param_names gets all the parameter names from the (current) constructor and then uses value = getattr(self, key) for each key in the parameters. When it reaches dimensionless_constants_only, it throws the error.

So a workaround is in the from_file method, to have it call in all the parameters and their default values from the constructor and then add any missing attributes to the model before calling set_params.

# Get constructor parameters and default values
params = inspect.signature(model.__init__).parameters

# Filter for missing parameters excluding kwargs
missing_params = {k:v for k,v in params.items() if k not in model.__dict__.keys() and  v.name != "self" and v.kind != v.VAR_KEYWORD}

# Assign missing attributes
for k, v in missing_params.items():
    setattr(model, k, v)

model.set_params(**pysr_kwargs)

This then no longer throws the error. Should I try to suggest it in the code?

tbuckworth commented 3 weeks ago

I've created a pull request, but maybe you want to add a warning when missing_params is not empty, as it could effect the behaviour of the model.