-
-
Notifications
You must be signed in to change notification settings - Fork 43
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
make env optional arg while creating from buffers #137
make env optional arg while creating from buffers #137
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for your work on this so far. I requested changes in two places. I also think there should be a new test which creates a dataset without providing an env
argument, and makes sure that everything still works as intended. Once that is all done, I will review again.
b115336
to
28403a7
Compare
raise error if obs space or action space not provided when env is none remove unnecessary if conditions as obs & action space can't be none
Thanks for your work on this; it looks almost ready! I think it would be good to add a test to test_dataset_creation where a dataset is created from buffers without the env being set, and then also tries to load that dataset after it is created. Additionally, it looks like pre-commit is failing. Once those two things are done, it should be ready to merge. |
minari/utils.py
Outdated
dataset.spec.env_spec.max_episode_steps for dataset in datasets_to_combine | ||
dataset.spec.env_spec.max_episode_steps | ||
for dataset in datasets_to_combine # pyright: ignore[reportGeneralTypeIssues] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually, since now the datasets can have a env_spec=None, we should address also this case.
You can create the list of env_spec and filter out None values
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As of now, I'm raising an error if any of the datasets to be combined have no env_spec. Please do let me know if you'd prefer some other specific action instead of this.
minari/utils.py
Outdated
if observation_space is None: | ||
observation_space = env.observation_space | ||
observation_space = ( | ||
env.observation_space # pyright: ignore[reportOptionalMemberAccess] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why do you need this? There is no way reaching here when env is None; do you got errors from the pre-commit?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I got errors from pre-commit.
1a61d32
to
5824961
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I had to play around a bit to understand how to solve so I just pushed the code to your branch; now should be good.
Last thing before merging, can you add a test for combining datasets without env_spec?
@younik Okay, so using assert you could handle the pyright optional member access issue! Thanks a lot for helping with that! I see that the "validate_datasets_to_combine" has the check "Tests if the datasets were created with the same environment" at L184-186 in utils.py removed. Is this intentional? Don't we need to compare if all the datasets have exactly the same env_spec? Am I missing something here? |
minari/utils.py
Outdated
env_spec = dataset.spec.env_spec | ||
if env_spec is not None: | ||
assert ( | ||
common_env_spec is not None |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh my bad, you are right, thanks! Can you fix it? You cannot simply assert check env_spec == common_env_spec tho, as max_episode_steps may differ.
Would be nice to also add a test on combining with different env_spec then (an error is expected)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
okay, sure. I'll add the fix and the test as well.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've added the fix. Please verify if this is fine. Also, I wanted to know if we could use assert in non-testing code as I have read that assert statements are unsafe in production environments could be disabled in python interpreters during optimization (quoting one source here). They recommend using assert only in testing and debugging code, but I've continued to use assert here as our repo already has many asserts in non-testing code.
The test case and pyright issue is still work in progress though I've done some refactoring to make use of the dataset generation with no env in the combining dataset test cass too.
Edit: Just noticed that we need a separate for loop statement for updating the max_episode_steps after line 186. I missed that. Will correct it. But please do advise me on the assert statement.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the fix! I left a couple of comments.
You are right about the assert, the difference is: when you believe something cannot happen you can use assert (e.g. asserts on line 401 and 404 of utils.py, as there is the check above). When it is something that can happen, but you want to let the user that it is not allowed, you should raise an error.
Unfortunately, in Minari we often use asserts as exceptions. I would be happy to merge another PR that addresses it.
Edit: Just noticed that we need a separate for loop statement for updating the max_episode_steps after line 186. I missed that. Will correct it. But please do advise me on the assert statement.
What do you mean? I don't see it.
tests/common.py
Outdated
if dataset.env_spec is None: | ||
raise ValueError("Recovering environment is not possible when env_spec is None") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this it is not necessary I believe, as recover_environment
will throw an error itself if env_spec is None
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
removed the redundant raise error
minari/utils.py
Outdated
env_spec = dataset.spec.env_spec | ||
if env_spec is not None: | ||
assert ( | ||
common_env_spec is not None |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the fix! I left a couple of comments.
You are right about the assert, the difference is: when you believe something cannot happen you can use assert (e.g. asserts on line 401 and 404 of utils.py, as there is the check above). When it is something that can happen, but you want to let the user that it is not allowed, you should raise an error.
Unfortunately, in Minari we often use asserts as exceptions. I would be happy to merge another PR that addresses it.
Edit: Just noticed that we need a separate for loop statement for updating the max_episode_steps after line 186. I missed that. Will correct it. But please do advise me on the assert statement.
What do you mean? I don't see it.
@younik I'm currently working on the merge conflicts with the eval_env changes that got merged yesterday. I had one question regarding this. Could there be a scenario where there is an eval_env even when env is None? I mean, can a user provide a eval_env for a dataset generated with buffers without an env? |
Thank you, good point. I don't see any common case when this would happen, but also no reason to constraint it. I would simply do what is easier in code, which is no constraint I guess. |
minari/utils.py
Outdated
if isinstance(env, (str, EnvSpec, type(None))) and (observation_space is None or action_space is None): | ||
raise ValueError("Both observation space and action space must be provided, if env is str|EnvSpec|None") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm assuming here that action_space and observation_space cannot be extracted unless it is of type gym.Env
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Uhm, if it is str or EnvSpec, you can recover the environment with gym.make
; I would do that
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So, if it is a str or EnvSpec, there would be 2 steps to extract the action_space and observation_space?
- recover env as gym.Env with gym.make;
- recover action_space and observation_space from this gym.Env.
Is this correct?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, exactly
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
implemented the above logic
minari/utils.py
Outdated
), "The datasets to be combined have different values for `env_spec` attribute." | ||
# checking equivalence of all datasets with an env | ||
for dataset in datasets_to_combine: | ||
if dataset.spec.env_spec is not None: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
They are required to be not None, it shouldn't be possible to combine datasets with some None env_spec and some None.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
okay, I think this answers my question in the previous comment.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
updated
minari/utils.py
Outdated
env_spec_copy = copy.deepcopy(dataset.spec.env_spec) | ||
env_spec_copy.max_episode_steps = common_env_spec.max_episode_steps | ||
if env_spec_copy != common_env_spec: | ||
raise ValueError( | ||
"The datasets to be combined have different values for `env_spec` attribute." | ||
) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can you just move this check in the other for loop and remove this one?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
minari/utils.py
Outdated
if eval_env is None: | ||
warnings.warn( | ||
f"`eval_env` is set to None. If another environment is intended to be used for evaluation please specify corresponding Gymnasium environment (gym.Env | gym.envs.registration.EnvSpec).\ | ||
if env_spec is not None: | ||
warnings.warn( | ||
f"`eval_env` is set to None. If another environment is intended to be used for evaluation please specify corresponding Gymnasium environment (gym.Env | gym.envs.registration.EnvSpec).\ | ||
If None the environment used to collect the data (`env={env_spec}`) will be used for this purpose.", | ||
UserWarning, | ||
) | ||
UserWarning, | ||
) | ||
else: | ||
warnings.warn( | ||
"Since both `eval_env` and `env` used to collect the data are None, no environment can be used for evaluation", | ||
UserWarning, | ||
) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would simplify this by having two independent checks. One for env_spec with a warning stating if you didn't declare it, and the other for eval_env (without checking what env_spec is).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
made the 2 checks independent
minari/utils.py
Outdated
eval_env (Optional[str|gym.Env|EnvSpec]): Gymnasium environment(gym.Env)/environment id(str)/environment spec(EnvSpec) to use for evaluation with the dataset. After loading the dataset, the environment can be recovered as follows: `MinariDataset.recover_environment(eval_env=True). | ||
If None the `env` used to collect the buffer data should be used for evaluation. | ||
If None, and if the `env` used to collect the buffer data is available, latter should be used for evaluation. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not related to your PR, but should
-> will
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
updated
…during metadata creation
raise error when some datasets have env_spec, and others don't combine two for-loops that check equality & update episodes for common_env_spec into one
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM; thanks for implementing this!
Actually, can you fix pre-commit @avjmachine Looks like you should use |
In line 524, we are overwriting the env variable if its just a string, using "env = gym.make(env)". So, will this work or is there a risk of env not having an observation_space or action_space attribute even after using gym.make? |
Yes, it is
No, there isn't; however, pyright is not able to infer it and throws an error. |
Done. I didn't get this pyright error on my local env. Hence, got confused. |
Description
Make the env argument as optional in the create_dataset_from_buffers() function in utils
Fixes # (issue), Depends on # (pull request)
Type of change
Screenshots
Checklist:
pre-commit
checks withpre-commit run --all-files
(seeCONTRIBUTING.md
instructions to set it up)pytest -v
and no errors are present.pytest -v
has generated that are related to my code to the best of my knowledge.