Skip to content

Commit

Permalink
fix rte-france#276 and rte-france#269
Browse files Browse the repository at this point in the history
  • Loading branch information
BDonnot committed Jan 18, 2022
1 parent 49854f8 commit 08e30b7
Show file tree
Hide file tree
Showing 7 changed files with 402 additions and 85 deletions.
4 changes: 3 additions & 1 deletion CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,9 @@ Change Log
`env.action_space.get_back_to_ref_state(obs)`
- [ADDED] a method of the action to store it in a grid2op independant fashion (using json and dictionaries), see `act.as_serializable_dict()`
- [IMPROVED] observation now raises `Grid2OpException` instead of `RuntimeError`

- [IMRPOVED] docs (and notebooks) for the "split_train_val" https://github.com/rte-france/Grid2Op/issues/269
- [IMRPOVED] the "split_train_val" function to also generate a test dataset see https://github.com/rte-france/Grid2Op/issues/276

[1.6.4] - 2021-11-08
---------------------
- [BREAKING] the name of the python files for the "agent" module are now lowercase (complient with PEP). If you
Expand Down
63 changes: 3 additions & 60 deletions docs/environment.rst
Original file line number Diff line number Diff line change
Expand Up @@ -550,11 +550,12 @@ This can be done with:
# extract 1% of the "chronics" to be used in the validation environment. The other 99% will
# be used for test
nm_env_train, nm_env_val = env.train_val_split_random(pct_val=1.)
nm_env_train, nm_env_val, nm_env_test = env.train_val_split_random(pct_val=1., pct_test=1.)
# and now you can use the training set only to train your agent:
print(f"The name of the training environment is \\"{nm_env_train}\\"")
print(f"The name of the validation environment is \\"{nm_env_val}\\"")
print(f"The name of the test environment is \\"{nm_env_test}\\"")
env_train = grid2op.make(nm_env_train)
You can then use, in the above case:
Expand All @@ -577,67 +578,9 @@ And then, at time of validation:
env_val = grid2op.make(env_name+"_val") # to only use the "validation chronics"
# do whatever you want with env_val
As of now, grid2op do not support "from the API" the possibility to split with convenient
names a environment a second times. If you want to do a "train / validation / test" split we recommend you to:
1. make a training / test split (see below)
2. split again the training set into training / validation (see below)
3. you will have locally an environment named "trainval" on your computer. This directory will not weight
more than a few kilobytes.
The example, not really convenient at the moment, please find a feature request if that is a problem for
you:
.. code-block:: python
import grid2op
import os
env_name = "l2rpn_case14_sandbox" # or any other...
env = grid2op.make(env_name)
# retrieve the names of the chronics:
full_path_data = env.chronics_handler.subpaths
chron_names = [os.path.split(el)[-1] for el in full_path_data]
# splitting into training / test, keeping the "last" 10 chronics to the test set
nm_env_trainval, nm_env_test = env.train_val_split(val_scen_id=chron_names[-10:],
add_for_val="test",
add_for_train="trainval")
# now splitting again the training set into training and validation, keeping the last 10 chronics
# of this environment for validation
env_trainval = grid2op.make(nm_env_trainval) # create the "trainval" environment
full_path_data = env_trainval.chronics_handler.subpaths
chron_names = [os.path.split(el)[-1] for el in full_path_data]
nm_env_train, nm_env_val = env_trainval.train_val_split(val_scen_id=chron_names[-10:],
remove_from_name="_trainval$")
And later on, you can do, if you followed the names above:
.. code-block:: python
import grid2op
import os
env_name = "l2rpn_case14_sandbox" # or any other...
env_train = grid2op.make(env_name+"_train")
env_val = grid2op.make(env_name+"_val")
# and of course
env_test = grid2op.make(env_name+"_test")
And you can also, if you want, delete the folder "l2rpn_case14_sandbox_trainval" from your machine:
.. code-block:: python
import grid2op
import os
env_name = "l2rpn_case14_sandbox" # or any other...
env_trainval = grid2op.make(env_name+"_trainval")
print(f"You can safely delete, if you want, the folder: \n\t\"{env_trainval.get_path_env()}\" \nnow useless.")
Customization
-------------
Expand Down
46 changes: 45 additions & 1 deletion getting_started/04_TrainingAnAgent.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,50 @@
"res"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 0) Good practice\n",
"\n",
"As in other machine learning tasks, we highly recommend, before even trying to train an agent, to split the \"chronics\" (ie the episode data) into 3 datasets:\n",
"- \"train\" use to train the agent\n",
"- \"val\" use to validate the hyper parameters\n",
"- \"test\" at which you would look only once to report the agent performance in a scientific paper (for example)\n",
"\n",
"Grid2op lets you do that with relative ease:\n",
"\n",
"```python\n",
"import grid2op\n",
"env_name = \"l2rpn_case14_sandbox\" # or any other...\n",
"env = grid2op.make(env_name)\n",
"\n",
"# extract 1% of the \"chronics\" to be used in the validation environment. The other 99% will\n",
"# be used for test\n",
"nm_env_train, nm_env_val, nm_env_test = env.train_val_split_random(pct_val=1., pct_test=1.)\n",
"\n",
"# and now you can use the training set only to train your agent:\n",
"print(f\"The name of the training environment is \\\\\"{nm_env_train}\\\\\"\")\n",
"print(f\"The name of the validation environment is \\\\\"{nm_env_val}\\\\\"\")\n",
"print(f\"The name of the test environment is \\\\\"{nm_env_test}\\\\\"\")\n",
"```"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"And now, you can use the training environment to train your agent:\n",
"\n",
"```python\n",
"import grid2op\n",
"env_name = \"l2rpn_case14_sandbox\"\n",
"env = grid2op.make(env_name+\"_train\")\n",
"```\n",
"\n",
"Be carefull, on windows you might run into issues. Don't hesitate to have a look at the documentation of this funciton if this the case (see https://grid2op.readthedocs.io/en/latest/environment.html#grid2op.Environment.Environment.train_val_split and https://grid2op.readthedocs.io/en/latest/environment.html#grid2op.Environment.Environment.train_val_split_random)"
]
},
{
"cell_type": "markdown",
"metadata": {},
Expand Down Expand Up @@ -1004,7 +1048,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.8.5"
"version": "3.8.10"
}
},
"nbformat": 4,
Expand Down
40 changes: 39 additions & 1 deletion getting_started/11_IntegrationWithExistingRLFrameworks.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,41 @@
"source": [
"## 0) Recommended initial steps\n",
"\n",
"\n",
"### Split the environment into training, validation and test\n",
"\n",
"As in other machine learning tasks, we highly recommend, before even trying to train an agent, to split the \"chronics\" (ie the episode data) into 3 datasets:\n",
"- \"train\" use to train the agent\n",
"- \"val\" use to validate the hyper parameters\n",
"- \"test\" at which you would look only once to report the agent performance in a scientific paper (for example)\n",
"\n",
"Grid2op lets you do that with relative ease:\n",
"\n",
"```python\n",
"import grid2op\n",
"env_name = \"l2rpn_case14_sandbox\" # or any other...\n",
"env = grid2op.make(env_name)\n",
"\n",
"# extract 1% of the \"chronics\" to be used in the validation environment. The other 99% will\n",
"# be used for test\n",
"nm_env_train, nm_env_val, nm_env_test = env.train_val_split_random(pct_val=1., pct_test=1.)\n",
"\n",
"# and now you can use the training set only to train your agent:\n",
"print(f\"The name of the training environment is \\\\\"{nm_env_train}\\\\\"\")\n",
"print(f\"The name of the validation environment is \\\\\"{nm_env_val}\\\\\"\")\n",
"print(f\"The name of the test environment is \\\\\"{nm_env_test}\\\\\"\")\n",
"```\n",
"\n",
"And now, you can use the training environment to train your agent:\n",
"\n",
"```python\n",
"import grid2op\n",
"env_name = \"l2rpn_case14_sandbox\"\n",
"env = grid2op.make(env_name+\"train\")\n",
"```\n",
"\n",
"Be carefull, on windows you might run into issues. Don't hesitate to have a look at the documentation of this funciton if this the case (see https://grid2op.readthedocs.io/en/latest/environment.html#grid2op.Environment.Environment.train_val_split and https://grid2op.readthedocs.io/en/latest/environment.html#grid2op.Environment.Environment.train_val_split_random)\n",
"\n",
"### Create a grid2op environment\n",
"\n",
"This is a rather standard step, with lots of inspiration drawn from openAI gym framework, and there is absolutely no specificity here."
Expand All @@ -108,7 +143,10 @@
"source": [
"import grid2op\n",
"env_name = \"l2rpn_case14_sandbox\"\n",
"env_glop = grid2op.make(env_name, test=True) # NOTE: do not set the flag \"test=True\" for a real usage !\n",
"env_glop = grid2op.make(env_name, test=True)\n",
"# NOTE: do not set the flag \"test=True\" for a real usage !\n",
"# NOTE: use grid2op.make(env_name+\"_train\", test=True) for a real usage (see paragraph above !)\n",
"\n",
"# This flag is here for testing purpose !!!\n",
"obs_glop = env_glop.reset()\n",
"obs_glop"
Expand Down
71 changes: 70 additions & 1 deletion grid2op/Chronics/fromNPY.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ class FromNPY(GridValue):
It is then much more flexible in its usage than the defaults chronics. But it is also much more error prone. For example, it does not check
the order of the loads / generators that you provide.
.. warnings::
.. warning::
It assume the order of the elements are consistent with the powergrid backend ! It will not attempt to reorder the columns of the dataset
.. note::
Expand Down Expand Up @@ -97,6 +97,14 @@ class FromNPY(GridValue):
obs = env.reset() # mandatory if you want the change to be taken into account
# obs.load_p is new_load_p[5] (or rather load_p[env.chronics_handler.real_data._i_start])
.. seealso::
More usage examples in:
- :func:`FromNPY.change_chronics`
- :func:`FromNPY.change_forecasts`
- :func:`FromNPY.change_i_start`
- :func:`FromNPY.change_i_end`
Attributes
----------
TODO
Expand Down Expand Up @@ -531,6 +539,36 @@ def change_i_start(self, new_i_start: Union[int, None]):
It has only an affect after "env.reset()" is called.
Examples
--------
.. code-block:: python
import grid2op
from grid2op.Chronics import FromNPY
# create an environment as in this class description (in short: )
load_p = ... # find somehow a suitable "load_p" array: rows represent time, columns the individual load
load_q = ...
prod_p = ...
prod_v = ...
# now create an environment with these chronics:
env = grid2op.make(env_name,
chronics_class=FromNPY,
data_feeding_kwargs={"load_p": load_p,
"load_q": load_q,
"prod_p": prod_p,
"prod_v": prod_v}
)
obs = env.reset() # obs.load_p is load_p[0] (or rather load_p[env.chronics_handler.real_data._i_start])
env.chronics_handler.real_data.change_i_start(10)
obs = env.reset() # obs.load_p is load_p[10]
# indeed `env.chronics_handler.real_data._i_start` has been changed to 10.
# to undo all changes (and use the defaults) you can:
# env.chronics_handler.real_data.change_i_start(None)
"""
if new_i_start is not None:
self.__new_istart = int(new_i_start)
Expand All @@ -546,6 +584,37 @@ def change_i_end(self, new_i_end: Union[int, None]):
It has only an affect after "env.reset()" is called.
Examples
--------
.. code-block:: python
import grid2op
from grid2op.Chronics import FromNPY
# create an environment as in this class description (in short: )
load_p = ... # find somehow a suitable "load_p" array: rows represent time, columns the individual load
load_q = ...
prod_p = ...
prod_v = ...
# now create an environment with these chronics:
env = grid2op.make(env_name,
chronics_class=FromNPY,
data_feeding_kwargs={"load_p": load_p,
"load_q": load_q,
"prod_p": prod_p,
"prod_v": prod_v}
)
obs = env.reset()
env.chronics_handler.real_data.change_i_end(150)
obs = env.reset()
# indeed `env.chronics_handler.real_data._i_end` has been changed to 10.
# scenario lenght will be at best 150 !
# to undo all changes (and use the defaults) you can:
# env.chronics_handler.real_data.change_i_end(None)
"""
if new_i_end is not None:
self.__new_iend = int(new_i_end)
Expand Down
2 changes: 1 addition & 1 deletion grid2op/Environment/BaseEnv.py
Original file line number Diff line number Diff line change
Expand Up @@ -2544,7 +2544,7 @@ def get_current_line_status(self):
@property
def parameters(self):
"""
return a deepcopy of the parameters used by the environment
Return a deepcopy of the parameters used by the environment
It is a deepcopy, so modifying it will have absolutely no effect.
Expand Down
Loading

0 comments on commit 08e30b7

Please sign in to comment.