stable-baselines3 2.9.0a2__tar.gz → 2.9.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (109) hide show
  1. {stable_baselines3-2.9.0a2 → stable_baselines3-2.9.2}/NOTICE +1 -1
  2. {stable_baselines3-2.9.0a2/stable_baselines3.egg-info → stable_baselines3-2.9.2}/PKG-INFO +4 -6
  3. {stable_baselines3-2.9.0a2 → stable_baselines3-2.9.2}/README.md +14 -9
  4. {stable_baselines3-2.9.0a2 → stable_baselines3-2.9.2}/pyproject.toml +7 -4
  5. {stable_baselines3-2.9.0a2 → stable_baselines3-2.9.2}/setup.py +3 -5
  6. {stable_baselines3-2.9.0a2 → stable_baselines3-2.9.2}/stable_baselines3/common/envs/__init__.py +0 -1
  7. {stable_baselines3-2.9.0a2 → stable_baselines3-2.9.2}/stable_baselines3/common/logger.py +1 -0
  8. {stable_baselines3-2.9.0a2 → stable_baselines3-2.9.2}/stable_baselines3/common/monitor.py +3 -3
  9. {stable_baselines3-2.9.0a2 → stable_baselines3-2.9.2}/stable_baselines3/common/noise.py +1 -1
  10. {stable_baselines3-2.9.0a2 → stable_baselines3-2.9.2}/stable_baselines3/common/off_policy_algorithm.py +12 -0
  11. {stable_baselines3-2.9.0a2 → stable_baselines3-2.9.2}/stable_baselines3/common/policies.py +3 -3
  12. {stable_baselines3-2.9.0a2 → stable_baselines3-2.9.2}/stable_baselines3/common/sb2_compat/rmsprop_tf_like.py +1 -1
  13. {stable_baselines3-2.9.0a2 → stable_baselines3-2.9.2}/stable_baselines3/common/vec_env/base_vec_env.py +2 -2
  14. {stable_baselines3-2.9.0a2 → stable_baselines3-2.9.2}/stable_baselines3/common/vec_env/subproc_vec_env.py +6 -0
  15. {stable_baselines3-2.9.0a2 → stable_baselines3-2.9.2}/stable_baselines3/ddpg/ddpg.py +4 -1
  16. {stable_baselines3-2.9.0a2 → stable_baselines3-2.9.2}/stable_baselines3/dqn/dqn.py +3 -0
  17. {stable_baselines3-2.9.0a2 → stable_baselines3-2.9.2}/stable_baselines3/ppo/ppo.py +1 -1
  18. {stable_baselines3-2.9.0a2 → stable_baselines3-2.9.2}/stable_baselines3/sac/sac.py +3 -0
  19. {stable_baselines3-2.9.0a2 → stable_baselines3-2.9.2}/stable_baselines3/td3/td3.py +3 -0
  20. stable_baselines3-2.9.2/stable_baselines3/version.txt +1 -0
  21. {stable_baselines3-2.9.0a2 → stable_baselines3-2.9.2/stable_baselines3.egg-info}/PKG-INFO +4 -6
  22. {stable_baselines3-2.9.0a2 → stable_baselines3-2.9.2}/stable_baselines3.egg-info/requires.txt +2 -4
  23. {stable_baselines3-2.9.0a2 → stable_baselines3-2.9.2}/tests/test_cnn.py +10 -3
  24. {stable_baselines3-2.9.0a2 → stable_baselines3-2.9.2}/tests/test_logger.py +8 -2
  25. {stable_baselines3-2.9.0a2 → stable_baselines3-2.9.2}/tests/test_n_step_replay.py +46 -1
  26. {stable_baselines3-2.9.0a2 → stable_baselines3-2.9.2}/tests/test_save_load.py +31 -0
  27. {stable_baselines3-2.9.0a2 → stable_baselines3-2.9.2}/tests/test_spaces.py +16 -1
  28. {stable_baselines3-2.9.0a2 → stable_baselines3-2.9.2}/tests/test_utils.py +56 -0
  29. {stable_baselines3-2.9.0a2 → stable_baselines3-2.9.2}/tests/test_vec_envs.py +1 -1
  30. stable_baselines3-2.9.0a2/stable_baselines3/version.txt +0 -1
  31. {stable_baselines3-2.9.0a2 → stable_baselines3-2.9.2}/LICENSE +0 -0
  32. {stable_baselines3-2.9.0a2 → stable_baselines3-2.9.2}/setup.cfg +0 -0
  33. {stable_baselines3-2.9.0a2 → stable_baselines3-2.9.2}/stable_baselines3/__init__.py +0 -0
  34. {stable_baselines3-2.9.0a2 → stable_baselines3-2.9.2}/stable_baselines3/a2c/__init__.py +0 -0
  35. {stable_baselines3-2.9.0a2 → stable_baselines3-2.9.2}/stable_baselines3/a2c/a2c.py +0 -0
  36. {stable_baselines3-2.9.0a2 → stable_baselines3-2.9.2}/stable_baselines3/a2c/policies.py +0 -0
  37. {stable_baselines3-2.9.0a2 → stable_baselines3-2.9.2}/stable_baselines3/common/__init__.py +0 -0
  38. {stable_baselines3-2.9.0a2 → stable_baselines3-2.9.2}/stable_baselines3/common/atari_wrappers.py +0 -0
  39. {stable_baselines3-2.9.0a2 → stable_baselines3-2.9.2}/stable_baselines3/common/base_class.py +0 -0
  40. {stable_baselines3-2.9.0a2 → stable_baselines3-2.9.2}/stable_baselines3/common/buffers.py +0 -0
  41. {stable_baselines3-2.9.0a2 → stable_baselines3-2.9.2}/stable_baselines3/common/callbacks.py +0 -0
  42. {stable_baselines3-2.9.0a2 → stable_baselines3-2.9.2}/stable_baselines3/common/distributions.py +0 -0
  43. {stable_baselines3-2.9.0a2 → stable_baselines3-2.9.2}/stable_baselines3/common/env_checker.py +0 -0
  44. {stable_baselines3-2.9.0a2 → stable_baselines3-2.9.2}/stable_baselines3/common/env_util.py +0 -0
  45. {stable_baselines3-2.9.0a2 → stable_baselines3-2.9.2}/stable_baselines3/common/envs/bit_flipping_env.py +0 -0
  46. {stable_baselines3-2.9.0a2 → stable_baselines3-2.9.2}/stable_baselines3/common/envs/identity_env.py +0 -0
  47. {stable_baselines3-2.9.0a2 → stable_baselines3-2.9.2}/stable_baselines3/common/envs/multi_input_envs.py +0 -0
  48. {stable_baselines3-2.9.0a2 → stable_baselines3-2.9.2}/stable_baselines3/common/evaluation.py +0 -0
  49. {stable_baselines3-2.9.0a2 → stable_baselines3-2.9.2}/stable_baselines3/common/on_policy_algorithm.py +0 -0
  50. {stable_baselines3-2.9.0a2 → stable_baselines3-2.9.2}/stable_baselines3/common/preprocessing.py +0 -0
  51. {stable_baselines3-2.9.0a2 → stable_baselines3-2.9.2}/stable_baselines3/common/results_plotter.py +0 -0
  52. {stable_baselines3-2.9.0a2 → stable_baselines3-2.9.2}/stable_baselines3/common/running_mean_std.py +0 -0
  53. {stable_baselines3-2.9.0a2 → stable_baselines3-2.9.2}/stable_baselines3/common/save_util.py +0 -0
  54. {stable_baselines3-2.9.0a2 → stable_baselines3-2.9.2}/stable_baselines3/common/sb2_compat/__init__.py +0 -0
  55. {stable_baselines3-2.9.0a2 → stable_baselines3-2.9.2}/stable_baselines3/common/torch_layers.py +0 -0
  56. {stable_baselines3-2.9.0a2 → stable_baselines3-2.9.2}/stable_baselines3/common/type_aliases.py +0 -0
  57. {stable_baselines3-2.9.0a2 → stable_baselines3-2.9.2}/stable_baselines3/common/utils.py +0 -0
  58. {stable_baselines3-2.9.0a2 → stable_baselines3-2.9.2}/stable_baselines3/common/vec_env/__init__.py +0 -0
  59. {stable_baselines3-2.9.0a2 → stable_baselines3-2.9.2}/stable_baselines3/common/vec_env/dummy_vec_env.py +0 -0
  60. {stable_baselines3-2.9.0a2 → stable_baselines3-2.9.2}/stable_baselines3/common/vec_env/patch_gym.py +0 -0
  61. {stable_baselines3-2.9.0a2 → stable_baselines3-2.9.2}/stable_baselines3/common/vec_env/stacked_observations.py +0 -0
  62. {stable_baselines3-2.9.0a2 → stable_baselines3-2.9.2}/stable_baselines3/common/vec_env/util.py +0 -0
  63. {stable_baselines3-2.9.0a2 → stable_baselines3-2.9.2}/stable_baselines3/common/vec_env/vec_check_nan.py +0 -0
  64. {stable_baselines3-2.9.0a2 → stable_baselines3-2.9.2}/stable_baselines3/common/vec_env/vec_extract_dict_obs.py +0 -0
  65. {stable_baselines3-2.9.0a2 → stable_baselines3-2.9.2}/stable_baselines3/common/vec_env/vec_frame_stack.py +0 -0
  66. {stable_baselines3-2.9.0a2 → stable_baselines3-2.9.2}/stable_baselines3/common/vec_env/vec_monitor.py +0 -0
  67. {stable_baselines3-2.9.0a2 → stable_baselines3-2.9.2}/stable_baselines3/common/vec_env/vec_normalize.py +0 -0
  68. {stable_baselines3-2.9.0a2 → stable_baselines3-2.9.2}/stable_baselines3/common/vec_env/vec_transpose.py +0 -0
  69. {stable_baselines3-2.9.0a2 → stable_baselines3-2.9.2}/stable_baselines3/common/vec_env/vec_video_recorder.py +0 -0
  70. {stable_baselines3-2.9.0a2 → stable_baselines3-2.9.2}/stable_baselines3/ddpg/__init__.py +0 -0
  71. {stable_baselines3-2.9.0a2 → stable_baselines3-2.9.2}/stable_baselines3/ddpg/policies.py +0 -0
  72. {stable_baselines3-2.9.0a2 → stable_baselines3-2.9.2}/stable_baselines3/dqn/__init__.py +0 -0
  73. {stable_baselines3-2.9.0a2 → stable_baselines3-2.9.2}/stable_baselines3/dqn/policies.py +0 -0
  74. {stable_baselines3-2.9.0a2 → stable_baselines3-2.9.2}/stable_baselines3/her/__init__.py +0 -0
  75. {stable_baselines3-2.9.0a2 → stable_baselines3-2.9.2}/stable_baselines3/her/goal_selection_strategy.py +0 -0
  76. {stable_baselines3-2.9.0a2 → stable_baselines3-2.9.2}/stable_baselines3/her/her_replay_buffer.py +0 -0
  77. {stable_baselines3-2.9.0a2 → stable_baselines3-2.9.2}/stable_baselines3/ppo/__init__.py +0 -0
  78. {stable_baselines3-2.9.0a2 → stable_baselines3-2.9.2}/stable_baselines3/ppo/policies.py +0 -0
  79. {stable_baselines3-2.9.0a2 → stable_baselines3-2.9.2}/stable_baselines3/py.typed +0 -0
  80. {stable_baselines3-2.9.0a2 → stable_baselines3-2.9.2}/stable_baselines3/sac/__init__.py +0 -0
  81. {stable_baselines3-2.9.0a2 → stable_baselines3-2.9.2}/stable_baselines3/sac/policies.py +0 -0
  82. {stable_baselines3-2.9.0a2 → stable_baselines3-2.9.2}/stable_baselines3/td3/__init__.py +0 -0
  83. {stable_baselines3-2.9.0a2 → stable_baselines3-2.9.2}/stable_baselines3/td3/policies.py +0 -0
  84. {stable_baselines3-2.9.0a2 → stable_baselines3-2.9.2}/stable_baselines3.egg-info/SOURCES.txt +0 -0
  85. {stable_baselines3-2.9.0a2 → stable_baselines3-2.9.2}/stable_baselines3.egg-info/dependency_links.txt +0 -0
  86. {stable_baselines3-2.9.0a2 → stable_baselines3-2.9.2}/stable_baselines3.egg-info/top_level.txt +0 -0
  87. {stable_baselines3-2.9.0a2 → stable_baselines3-2.9.2}/tests/test_buffers.py +0 -0
  88. {stable_baselines3-2.9.0a2 → stable_baselines3-2.9.2}/tests/test_callbacks.py +0 -0
  89. {stable_baselines3-2.9.0a2 → stable_baselines3-2.9.2}/tests/test_custom_policy.py +0 -0
  90. {stable_baselines3-2.9.0a2 → stable_baselines3-2.9.2}/tests/test_deterministic.py +0 -0
  91. {stable_baselines3-2.9.0a2 → stable_baselines3-2.9.2}/tests/test_dict_env.py +0 -0
  92. {stable_baselines3-2.9.0a2 → stable_baselines3-2.9.2}/tests/test_distributions.py +0 -0
  93. {stable_baselines3-2.9.0a2 → stable_baselines3-2.9.2}/tests/test_env_checker.py +0 -0
  94. {stable_baselines3-2.9.0a2 → stable_baselines3-2.9.2}/tests/test_envs.py +0 -0
  95. {stable_baselines3-2.9.0a2 → stable_baselines3-2.9.2}/tests/test_gae.py +0 -0
  96. {stable_baselines3-2.9.0a2 → stable_baselines3-2.9.2}/tests/test_her.py +0 -0
  97. {stable_baselines3-2.9.0a2 → stable_baselines3-2.9.2}/tests/test_identity.py +0 -0
  98. {stable_baselines3-2.9.0a2 → stable_baselines3-2.9.2}/tests/test_monitor.py +0 -0
  99. {stable_baselines3-2.9.0a2 → stable_baselines3-2.9.2}/tests/test_predict.py +0 -0
  100. {stable_baselines3-2.9.0a2 → stable_baselines3-2.9.2}/tests/test_preprocessing.py +0 -0
  101. {stable_baselines3-2.9.0a2 → stable_baselines3-2.9.2}/tests/test_run.py +0 -0
  102. {stable_baselines3-2.9.0a2 → stable_baselines3-2.9.2}/tests/test_sde.py +0 -0
  103. {stable_baselines3-2.9.0a2 → stable_baselines3-2.9.2}/tests/test_tensorboard.py +0 -0
  104. {stable_baselines3-2.9.0a2 → stable_baselines3-2.9.2}/tests/test_train_eval_mode.py +0 -0
  105. {stable_baselines3-2.9.0a2 → stable_baselines3-2.9.2}/tests/test_vec_check_nan.py +0 -0
  106. {stable_baselines3-2.9.0a2 → stable_baselines3-2.9.2}/tests/test_vec_extract_dict_obs.py +0 -0
  107. {stable_baselines3-2.9.0a2 → stable_baselines3-2.9.2}/tests/test_vec_monitor.py +0 -0
  108. {stable_baselines3-2.9.0a2 → stable_baselines3-2.9.2}/tests/test_vec_normalize.py +0 -0
  109. {stable_baselines3-2.9.0a2 → stable_baselines3-2.9.2}/tests/test_vec_stacked_obs.py +0 -0
@@ -2,7 +2,7 @@ Large portion of the code of Stable-Baselines3 (in `common/`) were ported from S
2
2
  both licensed under the MIT License:
3
3
 
4
4
  before the fork (June 2018):
5
- Copyright (c) 2017 OpenAI (http://openai.com)
5
+ Copyright (c) 2017 OpenAI (https://openai.com)
6
6
 
7
7
  after the fork (June 2018):
8
8
  Copyright (c) 2018-2019 Stable-Baselines Team
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: stable_baselines3
3
- Version: 2.9.0a2
3
+ Version: 2.9.2
4
4
  Summary: Pytorch version of Stable Baselines, implementations of reinforcement learning algorithms.
5
5
  Home-page: https://github.com/DLR-RM/stable-baselines3
6
6
  Author: Antonin Raffin
@@ -24,14 +24,12 @@ License-File: LICENSE
24
24
  License-File: NOTICE
25
25
  Requires-Dist: gymnasium<2.0,>=0.29.1
26
26
  Requires-Dist: numpy<3.0,>=1.20
27
- Requires-Dist: torch<3.0,>=2.3
27
+ Requires-Dist: torch<3.0,>=2.8
28
28
  Requires-Dist: cloudpickle
29
29
  Provides-Extra: tests
30
30
  Requires-Dist: pytest; extra == "tests"
31
31
  Requires-Dist: pytest-cov; extra == "tests"
32
- Requires-Dist: pytest-env; extra == "tests"
33
- Requires-Dist: pytest-xdist; extra == "tests"
34
- Requires-Dist: mypy<2,>=1.9.0; extra == "tests"
32
+ Requires-Dist: mypy<3,>=1.9.0; extra == "tests"
35
33
  Requires-Dist: ruff>=0.5.6; extra == "tests"
36
34
  Requires-Dist: black<27,>=26.1.0; extra == "tests"
37
35
  Provides-Extra: docs
@@ -116,7 +114,7 @@ vec_env = model.get_env()
116
114
  obs = vec_env.reset()
117
115
  for i in range(1000):
118
116
  action, _states = model.predict(obs, deterministic=True)
119
- obs, reward, done, info = vec_env.step(action)
117
+ obs, rewards, dones, info = vec_env.step(action)
120
118
  vec_env.render()
121
119
  # VecEnv resets automatically
122
120
  # if done:
@@ -100,7 +100,7 @@ It provides a minimal number of features compared to SB3 but can be much faster
100
100
 
101
101
  ## Installation
102
102
 
103
- **Note:** Stable-Baselines3 supports PyTorch >= 2.3
103
+ **Note:** Stable-Baselines3 supports PyTorch >= 2.8
104
104
 
105
105
  ### Prerequisites
106
106
  Stable Baselines3 requires Python 3.10+.
@@ -142,8 +142,8 @@ model.learn(total_timesteps=10_000)
142
142
  vec_env = model.get_env()
143
143
  obs = vec_env.reset()
144
144
  for i in range(1000):
145
- action, _states = model.predict(obs, deterministic=True)
146
- obs, reward, done, info = vec_env.step(action)
145
+ actions, _states = model.predict(obs, deterministic=True)
146
+ obs, rewards, dones, info = vec_env.step(actions)
147
147
  vec_env.render()
148
148
  # VecEnv resets automatically
149
149
  # if done:
@@ -182,23 +182,28 @@ All the following examples can be executed online using Google Colab notebooks:
182
182
 
183
183
  | **Name** | **Recurrent** | `Box` | `Discrete` | `MultiDiscrete` | `MultiBinary` | **Multi Processing** |
184
184
  | ------------------- | ------------------ | ------------------ | ------------------ | ------------------- | ------------------ | --------------------------------- |
185
- | ARS<sup>[1](#f1)</sup> | :x: | :heavy_check_mark: | :heavy_check_mark: | :x: | :x: | :heavy_check_mark: |
186
185
  | A2C | :x: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
187
- | CrossQ<sup>[1](#f1)</sup> | :x: | :heavy_check_mark: | :x: | :x: | :x: | :heavy_check_mark: |
186
+ | ARS<sup>[1](#f1)</sup> | :x: | :heavy_check_mark: | :heavy_check_mark: | :x: | :x: | :heavy_check_mark: |
187
+ | CrossQ<sup>[1](#f1)[2](#f2)</sup> | :x: | :heavy_check_mark: | :x: | :x: | :x: | :heavy_check_mark: |
188
188
  | DDPG | :x: | :heavy_check_mark: | :x: | :x: | :x: | :heavy_check_mark: |
189
189
  | DQN | :x: | :x: | :heavy_check_mark: | :x: | :x: | :heavy_check_mark: |
190
+ | DroQ<sup>[2](#f2)</sup> | :x: | :heavy_check_mark: | :x: | :x: | :x: | :heavy_check_mark: |
190
191
  | HER | :x: | :heavy_check_mark: | :heavy_check_mark: | :x: | :x: | :heavy_check_mark: |
192
+ | Maskable PPO<sup>[1](#f1)</sup> | :x: | :x: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
191
193
  | PPO | :x: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
192
194
  | QR-DQN<sup>[1](#f1)</sup> | :x: | :x: | :heavy_check_mark: | :x: | :x: | :heavy_check_mark: |
193
195
  | RecurrentPPO<sup>[1](#f1)</sup> | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
194
196
  | SAC | :x: | :heavy_check_mark: | :x: | :x: | :x: | :heavy_check_mark: |
197
+ | SAC-N<sup>[2](#f2)</sup> | :x: | :heavy_check_mark: | :x: | :x: | :x: | :heavy_check_mark: |
198
+ | SimBa<sup>[2](#f2)</sup> | :x: | :heavy_check_mark: | :x: | :x: | :x: | :heavy_check_mark: |
195
199
  | TD3 | :x: | :heavy_check_mark: | :x: | :x: | :x: | :heavy_check_mark: |
196
200
  | TQC<sup>[1](#f1)</sup> | :x: | :heavy_check_mark: | :x: | :x: | :x: | :heavy_check_mark: |
197
201
  | TRPO<sup>[1](#f1)</sup> | :x: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
198
- | Maskable PPO<sup>[1](#f1)</sup> | :x: | :x: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
199
202
 
200
203
  <b id="f1">1</b>: Implemented in [SB3 Contrib](https://github.com/Stable-Baselines-Team/stable-baselines3-contrib) GitHub repository.
201
204
 
205
+ <b id="f2">2</b>: Implemented in [SBX (SB3 + Jax)](https://github.com/araffin/sbx)
206
+
202
207
  Actions `gymnasium.spaces`:
203
208
  * `Box`: A N-dimensional box that contains every point in the action space.
204
209
  * `Discrete`: A list of possible actions, where only one action can be used per timestep.
@@ -256,7 +261,7 @@ To cite this repository in publications:
256
261
  volume = {22},
257
262
  number = {268},
258
263
  pages = {1-8},
259
- url = {http://jmlr.org/papers/v22/20-1364.html}
264
+ url = {https://jmlr.org/papers/v22/20-1364.html}
260
265
  }
261
266
  ```
262
267
 
@@ -264,7 +269,7 @@ Note: If you need to refer to a specific version of SB3, you can also use the [Z
264
269
 
265
270
  ## Maintainers
266
271
 
267
- Stable-Baselines3 is currently maintained by [Ashley Hill](https://github.com/hill-a) (aka @hill-a), [Antonin Raffin](https://araffin.github.io/) (aka [@araffin](https://github.com/araffin)), [Maximilian Ernestus](https://github.com/ernestum) (aka @ernestum), [Adam Gleave](https://github.com/adamgleave) (@AdamGleave), [Anssi Kanervisto](https://github.com/Miffyli) (@Miffyli) and [Quentin Gallouédec](https://gallouedec.com/) (@qgallouedec).
272
+ Stable-Baselines3 is currently maintained by [Ashley Hill](https://github.com/hill-a) (aka @hill-a), [Antonin Raffin](https://araffin.github.io/) (aka [@araffin](https://github.com/araffin)), [Maximilian Ernestus](https://github.com/ernestum) (aka @ernestum), [Adam Gleave](https://github.com/adamgleave) (@AdamGleave), [Anssi Kanervisto](https://github.com/Miffyli) (@Miffyli) and [Quentin Gallouédec](https://github.com/qgallouedec) (@qgallouedec).
268
273
 
269
274
  **Important Note: We do not provide technical support, or consulting** and do not answer personal questions via email.
270
275
  Please post your question on the [RL Discord](https://discord.com/invite/xhfNqQv), [Reddit](https://www.reddit.com/r/reinforcementlearning/), or [Stack Overflow](https://stackoverflow.com/) in that case.
@@ -279,7 +284,7 @@ If you want to contribute, please read [**CONTRIBUTING.md**](./CONTRIBUTING.md)
279
284
 
280
285
  The initial work to develop Stable Baselines3 was partially funded by the project *Reduced Complexity Models* from the *Helmholtz-Gemeinschaft Deutscher Forschungszentren*, and by the EU Horizon 2020 Research and Innovation Programme under grant number 951992 ([VeriDream](https://www.veridream.eu/)).
281
286
 
282
- The original version, Stable Baselines, was created in the [robotics lab U2IS](http://u2is.ensta-paristech.fr/index.php?lang=en) ([INRIA Flowers](https://flowers.inria.fr/) team) at [ENSTA ParisTech](http://www.ensta-paristech.fr/en).
287
+ The original version, Stable Baselines, was created in the [robotics lab U2IS](http://u2is.ensta-paris.fr/?lang=en) ([INRIA Flowers](https://flowers.inria.fr/) team) at [ENSTA ParisTech](https://www.ensta.fr/en).
283
288
 
284
289
 
285
290
  Logo credits: [L.M. Tenkes](https://www.instagram.com/lucillehue/)
@@ -36,20 +36,23 @@ exclude = """(?x)(
36
36
 
37
37
  [tool.pytest.ini_options]
38
38
  # Deterministic ordering for tests; useful for pytest-xdist.
39
- env = ["PYTHONHASHSEED=0"]
39
+ # env = ["PYTHONHASHSEED=0"]
40
40
 
41
41
  filterwarnings = [
42
+ # multiprocessing and fork method, use of fork may lead to deadlocks
43
+ "ignore::DeprecationWarning:multiprocessing.popen_fork",
42
44
  # A2C/PPO on GPU
43
45
  "ignore:You are trying to run (PPO|A2C) on the GPU",
44
46
  # Tensorboard warnings
45
47
  "ignore::DeprecationWarning:tensorboard",
48
+ # Torch tensorboard numpy newshape deprecation
49
+ "ignore:`newshape` keyword argument is deprecated:DeprecationWarning:torch.utils.tensorboard._utils",
46
50
  # Gymnasium warnings
47
51
  "ignore::UserWarning:gymnasium",
52
+ # Taxi-v3 and CliffWalking-v0
53
+ "ignore::DeprecationWarning:gymnasium.envs.registration",
48
54
  # tqdm warning about rich being experimental
49
55
  "ignore:rich is experimental",
50
- # Pygame warnings about pkg_resources
51
- "ignore:pkg_resources is deprecated",
52
- "ignore:Deprecated call to `pkg_resources",
53
56
  ]
54
57
  markers = [
55
58
  "expensive: marks tests as expensive (deselect with '-m \"not expensive\"')",
@@ -55,7 +55,7 @@ vec_env = model.get_env()
55
55
  obs = vec_env.reset()
56
56
  for i in range(1000):
57
57
  action, _states = model.predict(obs, deterministic=True)
58
- obs, reward, done, info = vec_env.step(action)
58
+ obs, rewards, dones, info = vec_env.step(action)
59
59
  vec_env.render()
60
60
  # VecEnv resets automatically
61
61
  # if done:
@@ -81,7 +81,7 @@ setup(
81
81
  install_requires=[
82
82
  "gymnasium>=0.29.1,<2.0",
83
83
  "numpy>=1.20,<3.0",
84
- "torch>=2.3,<3.0",
84
+ "torch>=2.8,<3.0",
85
85
  # For saving models
86
86
  "cloudpickle",
87
87
  ],
@@ -90,10 +90,8 @@ setup(
90
90
  # Run tests and coverage
91
91
  "pytest",
92
92
  "pytest-cov",
93
- "pytest-env",
94
- "pytest-xdist",
95
93
  # Type check
96
- "mypy>=1.9.0,<2",
94
+ "mypy>=1.9.0,<3",
97
95
  # Lint code and sort imports (flake8 and isort replacement)
98
96
  "ruff>=0.5.6",
99
97
  # Reformat
@@ -16,5 +16,4 @@ __all__ = [
16
16
  "IdentityEnvMultiBinary",
17
17
  "IdentityEnvMultiDiscrete",
18
18
  "SimpleMultiObsEnv",
19
- "SimpleMultiObsEnv",
20
19
  ]
@@ -428,6 +428,7 @@ class TensorBoardOutputFormat(KVWriter):
428
428
  self.writer.add_image(key, value.image, step, dataformats=value.dataformats)
429
429
 
430
430
  if isinstance(value, HParam):
431
+ assert self.writer.file_writer is not None
431
432
  # we don't use `self.writer.add_hparams` to have control over the log_dir
432
433
  experiment, session_start_info, session_end_info = hparams(value.hparam_dict, metric_dict=value.metric_dict)
433
434
  self.writer.file_writer.add_summary(experiment)
@@ -262,10 +262,10 @@ def load_results(path: str) -> "pandas.DataFrame":
262
262
  # Only empty monitor files, return empty df
263
263
  empty_df = pandas.DataFrame(columns=["r", "l", "t"])
264
264
  # Create index to have the same columns
265
- empty_df.reset_index(inplace=True)
265
+ empty_df = empty_df.reset_index()
266
266
  return empty_df
267
267
  data_frame = pandas.concat(data_frames)
268
- data_frame.sort_values("t", inplace=True)
269
- data_frame.reset_index(inplace=True)
268
+ data_frame = data_frame.sort_values("t")
269
+ data_frame = data_frame.reset_index()
270
270
  data_frame["t"] -= min(header["t_start"] for header in headers)
271
271
  return data_frame
@@ -51,7 +51,7 @@ class OrnsteinUhlenbeckActionNoise(ActionNoise):
51
51
  """
52
52
  An Ornstein Uhlenbeck action noise, this is designed to approximate Brownian motion with friction.
53
53
 
54
- Based on http://math.stackexchange.com/questions/1287634/implementing-ornstein-uhlenbeck-in-matlab
54
+ Based on https://math.stackexchange.com/questions/1287634/implementing-ornstein-uhlenbeck-in-matlab
55
55
 
56
56
  :param mean: Mean of the noise
57
57
  :param sigma: Scale of the noise
@@ -52,6 +52,9 @@ class OffPolicyAlgorithm(BaseAlgorithm):
52
52
  at a cost of more complexity.
53
53
  See https://github.com/DLR-RM/stable-baselines3/issues/37#issuecomment-637501195
54
54
  :param n_steps: When n_step > 1, uses n-step return (with the NStepReplayBuffer) when updating the Q-value network.
55
+ Note: it is only used when ``replay_buffer_class`` is ``None``, and is not supported for Dict
56
+ observation spaces yet. When passing a custom ``replay_buffer_class``, configure it directly
57
+ with ``replay_buffer_kwargs={"n_steps": ..., "gamma": ...}`` instead.
55
58
  :param policy_kwargs: Additional arguments to be passed to the policy on creation
56
59
  :param stats_window_size: Window size for the rollout logging, specifying the number of episodes to average
57
60
  the reported success rate, mean episode length, and mean reward over
@@ -175,6 +178,15 @@ class OffPolicyAlgorithm(BaseAlgorithm):
175
178
  self._setup_lr_schedule()
176
179
  self.set_random_seed(self.seed)
177
180
 
181
+ if self.n_steps > 1 and self.replay_buffer_class is not None:
182
+ warnings.warn(
183
+ f"`n_steps={self.n_steps}` is ignored because a custom `replay_buffer_class` "
184
+ f"(`{self.replay_buffer_class.__name__}`) was passed: n-step returns are only set up "
185
+ "automatically when `replay_buffer_class` is `None`. "
186
+ "To use n-step returns with a custom replay buffer, configure it explicitly, e.g. "
187
+ f'`replay_buffer_kwargs={{"n_steps": {self.n_steps}, "gamma": {self.gamma}}}`.'
188
+ )
189
+
178
190
  if self.replay_buffer_class is None:
179
191
  if isinstance(self.observation_space, spaces.Dict):
180
192
  self.replay_buffer_class = DictReplayBuffer
@@ -257,7 +257,7 @@ class BaseModel(nn.Module):
257
257
  obs_ = np.array(obs)
258
258
  vectorized_env = vectorized_env or is_vectorized_observation(obs_, obs_space)
259
259
  # Add batch dimension if needed
260
- observation[key] = obs_.reshape((-1, *self.observation_space[key].shape)) # type: ignore[misc]
260
+ observation[key] = obs_.reshape((-1, *self.observation_space[key].shape)) # type: ignore[misc, arg-type]
261
261
 
262
262
  elif is_image_space(self.observation_space):
263
263
  # Handle the different cases for images
@@ -271,7 +271,7 @@ class BaseModel(nn.Module):
271
271
  # Dict obs need to be handled separately
272
272
  vectorized_env = is_vectorized_observation(observation, self.observation_space)
273
273
  # Add batch dimension if needed
274
- observation = observation.reshape((-1, *self.observation_space.shape)) # type: ignore[misc]
274
+ observation = observation.reshape((-1, *self.observation_space.shape)) # type: ignore[misc, arg-type]
275
275
 
276
276
  obs_tensor = obs_as_tensor(observation, self.device)
277
277
  return obs_tensor, vectorized_env
@@ -367,7 +367,7 @@ class BasePolicy(BaseModel, ABC):
367
367
  with th.no_grad():
368
368
  actions = self._predict(obs_tensor, deterministic=deterministic)
369
369
  # Convert to numpy, and reshape to the original action shape
370
- actions = actions.cpu().numpy().reshape((-1, *self.action_space.shape)) # type: ignore[misc, assignment]
370
+ actions = actions.cpu().numpy().reshape((-1, *self.action_space.shape)) # type: ignore[misc, assignment, arg-type]
371
371
 
372
372
  if isinstance(self.action_space, spaces.Box):
373
373
  if self.squash_output:
@@ -20,7 +20,7 @@ class RMSpropTFLike(Optimizer):
20
20
  - Initialize squared gradient to ones rather than zeros
21
21
 
22
22
  Proposed by G. Hinton in his
23
- `course <http://www.cs.toronto.edu/~tijmen/csc321/slides/lecture_slides_lec6.pdf>`_.
23
+ `course <https://www.cs.toronto.edu/~tijmen/csc321/slides/lecture_slides_lec6.pdf>`_.
24
24
 
25
25
  The centered version first appears in `Generating Sequences
26
26
  With Recurrent Neural Networks <https://arxiv.org/pdf/1308.0850v5.pdf>`_.
@@ -289,7 +289,7 @@ class VecEnv(ABC):
289
289
  self.env_method("render")
290
290
  return None
291
291
 
292
- def seed(self, seed: int | None = None) -> Sequence[None | int]:
292
+ def seed(self, seed: int | None = None) -> Sequence[int | None]:
293
293
  """
294
294
  Sets the random seeds for all environments, based on a given seed.
295
295
  Each individual environment will still get its own seed, by incrementing the given seed.
@@ -392,7 +392,7 @@ class VecEnvWrapper(VecEnv):
392
392
  def step_wait(self) -> VecEnvStepReturn:
393
393
  pass
394
394
 
395
- def seed(self, seed: int | None = None) -> Sequence[None | int]:
395
+ def seed(self, seed: int | None = None) -> Sequence[int | None]:
396
396
  return self.venv.seed(seed)
397
397
 
398
398
  def set_options(self, options: list[dict] | dict | None = None) -> None:
@@ -159,6 +159,12 @@ class SubprocVecEnv(VecEnv):
159
159
  remote.send(("close", None))
160
160
  for process in self.processes:
161
161
  process.join()
162
+ # Close the parent side of the pipes: otherwise the sockets stay open
163
+ # until this instance (and its ``remotes``) is garbage collected,
164
+ # which can exhaust the file-descriptor limit (``Too many open files``)
165
+ # in long-running loops (e.g. hyperparameter optimization).
166
+ for remote in self.remotes:
167
+ remote.close()
162
168
  self.closed = True
163
169
 
164
170
  def get_images(self) -> Sequence[np.ndarray | None]:
@@ -15,7 +15,7 @@ class DDPG(TD3):
15
15
  """
16
16
  Deep Deterministic Policy Gradient (DDPG).
17
17
 
18
- Deterministic Policy Gradient: http://proceedings.mlr.press/v32/silver14.pdf
18
+ Deterministic Policy Gradient: https://proceedings.mlr.press/v32/silver14.pdf
19
19
  DDPG Paper: https://arxiv.org/abs/1509.02971
20
20
  Introduction to DDPG: https://spinningup.openai.com/en/latest/algorithms/ddpg.html
21
21
 
@@ -45,6 +45,9 @@ class DDPG(TD3):
45
45
  at a cost of more complexity.
46
46
  See https://github.com/DLR-RM/stable-baselines3/issues/37#issuecomment-637501195
47
47
  :param n_steps: When n_step > 1, uses n-step return (with the NStepReplayBuffer) when updating the Q-value network.
48
+ Note: it is only used when ``replay_buffer_class`` is ``None``, and is not supported for Dict
49
+ observation spaces yet. When passing a custom ``replay_buffer_class``, configure it directly
50
+ with ``replay_buffer_kwargs={"n_steps": ..., "gamma": ...}`` instead.
48
51
  :param policy_kwargs: additional arguments to be passed to the policy on creation. See :ref:`ddpg_policies`
49
52
  :param verbose: Verbosity level: 0 for no output, 1 for info messages (such as device or wrappers used), 2 for
50
53
  debug messages
@@ -45,6 +45,9 @@ class DQN(OffPolicyAlgorithm):
45
45
  at a cost of more complexity.
46
46
  See https://github.com/DLR-RM/stable-baselines3/issues/37#issuecomment-637501195
47
47
  :param n_steps: When n_step > 1, uses n-step return (with the NStepReplayBuffer) when updating the Q-value network.
48
+ Note: it is only used when ``replay_buffer_class`` is ``None``, and is not supported for Dict
49
+ observation spaces yet. When passing a custom ``replay_buffer_class``, configure it directly
50
+ with ``replay_buffer_kwargs={"n_steps": ..., "gamma": ...}`` instead.
48
51
  :param target_update_interval: update the target network every ``target_update_interval``
49
52
  environment steps.
50
53
  :param exploration_fraction: fraction of entire training period over which the exploration rate is reduced
@@ -88,7 +88,7 @@ class PPO(OnPolicyAlgorithm):
88
88
  gamma: float = 0.99,
89
89
  gae_lambda: float = 0.95,
90
90
  clip_range: float | Schedule = 0.2,
91
- clip_range_vf: None | float | Schedule = None,
91
+ clip_range_vf: float | Schedule | None = None,
92
92
  normalize_advantage: bool = True,
93
93
  ent_coef: float = 0.0,
94
94
  vf_coef: float = 0.5,
@@ -54,6 +54,9 @@ class SAC(OffPolicyAlgorithm):
54
54
  at a cost of more complexity.
55
55
  See https://github.com/DLR-RM/stable-baselines3/issues/37#issuecomment-637501195
56
56
  :param n_steps: When n_step > 1, uses n-step return (with the NStepReplayBuffer) when updating the Q-value network.
57
+ Note: it is only used when ``replay_buffer_class`` is ``None``, and is not supported for Dict
58
+ observation spaces yet. When passing a custom ``replay_buffer_class``, configure it directly
59
+ with ``replay_buffer_kwargs={"n_steps": ..., "gamma": ...}`` instead.
57
60
  :param ent_coef: Entropy regularization coefficient. (Equivalent to
58
61
  inverse of reward scale in the original SAC paper.) Controlling exploration/exploitation trade-off.
59
62
  Set it to 'auto' to learn it automatically (and 'auto_0.1' for using 0.1 as initial value)
@@ -49,6 +49,9 @@ class TD3(OffPolicyAlgorithm):
49
49
  at a cost of more complexity.
50
50
  See https://github.com/DLR-RM/stable-baselines3/issues/37#issuecomment-637501195
51
51
  :param n_steps: When n_step > 1, uses n-step return (with the NStepReplayBuffer) when updating the Q-value network.
52
+ Note: it is only used when ``replay_buffer_class`` is ``None``, and is not supported for Dict
53
+ observation spaces yet. When passing a custom ``replay_buffer_class``, configure it directly
54
+ with ``replay_buffer_kwargs={"n_steps": ..., "gamma": ...}`` instead.
52
55
  :param policy_delay: Policy and target networks will only be updated once every policy_delay steps
53
56
  per training steps. The Q values will be updated policy_delay more often (update every training step).
54
57
  :param target_policy_noise: Standard deviation of Gaussian noise added to target policy
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: stable_baselines3
3
- Version: 2.9.0a2
3
+ Version: 2.9.2
4
4
  Summary: Pytorch version of Stable Baselines, implementations of reinforcement learning algorithms.
5
5
  Home-page: https://github.com/DLR-RM/stable-baselines3
6
6
  Author: Antonin Raffin
@@ -24,14 +24,12 @@ License-File: LICENSE
24
24
  License-File: NOTICE
25
25
  Requires-Dist: gymnasium<2.0,>=0.29.1
26
26
  Requires-Dist: numpy<3.0,>=1.20
27
- Requires-Dist: torch<3.0,>=2.3
27
+ Requires-Dist: torch<3.0,>=2.8
28
28
  Requires-Dist: cloudpickle
29
29
  Provides-Extra: tests
30
30
  Requires-Dist: pytest; extra == "tests"
31
31
  Requires-Dist: pytest-cov; extra == "tests"
32
- Requires-Dist: pytest-env; extra == "tests"
33
- Requires-Dist: pytest-xdist; extra == "tests"
34
- Requires-Dist: mypy<2,>=1.9.0; extra == "tests"
32
+ Requires-Dist: mypy<3,>=1.9.0; extra == "tests"
35
33
  Requires-Dist: ruff>=0.5.6; extra == "tests"
36
34
  Requires-Dist: black<27,>=26.1.0; extra == "tests"
37
35
  Provides-Extra: docs
@@ -116,7 +114,7 @@ vec_env = model.get_env()
116
114
  obs = vec_env.reset()
117
115
  for i in range(1000):
118
116
  action, _states = model.predict(obs, deterministic=True)
119
- obs, reward, done, info = vec_env.step(action)
117
+ obs, rewards, dones, info = vec_env.step(action)
120
118
  vec_env.render()
121
119
  # VecEnv resets automatically
122
120
  # if done:
@@ -1,6 +1,6 @@
1
1
  gymnasium<2.0,>=0.29.1
2
2
  numpy<3.0,>=1.20
3
- torch<3.0,>=2.3
3
+ torch<3.0,>=2.8
4
4
  cloudpickle
5
5
 
6
6
  [docs]
@@ -26,8 +26,6 @@ matplotlib
26
26
  [tests]
27
27
  pytest
28
28
  pytest-cov
29
- pytest-env
30
- pytest-xdist
31
- mypy<2,>=1.9.0
29
+ mypy<3,>=1.9.0
32
30
  ruff>=0.5.6
33
31
  black<27,>=26.1.0
@@ -133,12 +133,19 @@ def test_features_extractor_target_net(model_class, share_features_extractor):
133
133
  if model_class == DQN and share_features_extractor:
134
134
  pytest.skip()
135
135
 
136
- env = FakeImageEnv(screen_height=40, screen_width=40, n_channels=1, discrete=model_class not in {SAC, TD3})
136
+ env = FakeImageEnv(screen_height=36, screen_width=36, n_channels=1, discrete=model_class not in {SAC, TD3})
137
137
  # Avoid memory error when using replay buffer
138
138
  # Reduce the size of the features
139
- kwargs = dict(buffer_size=250, learning_starts=100, policy_kwargs=dict(features_extractor_kwargs=dict(features_dim=32)))
139
+ kwargs = dict(
140
+ buffer_size=100,
141
+ learning_starts=50,
142
+ policy_kwargs=dict(features_extractor_kwargs=dict(features_dim=8)),
143
+ learning_rate=1e-3,
144
+ )
140
145
  if model_class != DQN:
141
146
  kwargs["policy_kwargs"]["share_features_extractor"] = share_features_extractor
147
+ else:
148
+ kwargs["target_update_interval"] = 10
142
149
 
143
150
  # No delay for TD3 (changes when the actor and polyak update take place)
144
151
  if model_class == TD3:
@@ -172,7 +179,7 @@ def test_features_extractor_target_net(model_class, share_features_extractor):
172
179
  if model_class == TD3:
173
180
  params_should_match(model.actor.parameters(), model.actor_target.parameters())
174
181
 
175
- model.learn(200)
182
+ model.learn(100)
176
183
 
177
184
  # Critic and target should differ
178
185
  params_should_differ(model.critic.parameters(), model.critic_target.parameters())
@@ -1,4 +1,3 @@
1
- import importlib.util
2
1
  import json
3
2
  import os
4
3
  import sys
@@ -273,7 +272,14 @@ def test_report_video_to_tensorboard(tmp_path, read_log, capsys):
273
272
 
274
273
 
275
274
  def is_moviepy_installed():
276
- return importlib.util.find_spec("moviepy") is not None
275
+ try:
276
+ import moviepy
277
+
278
+ # PyTorch doesn't support moviepy >= 2.0
279
+ # See: https://github.com/pytorch/pytorch/issues/147317
280
+ return moviepy.__version__ < "2.0"
281
+ except (ImportError, AttributeError):
282
+ return False
277
283
 
278
284
 
279
285
  @pytest.mark.parametrize("unsupported_format", ["stdout", "log", "json", "csv"])
@@ -1,10 +1,14 @@
1
+ import warnings
2
+
1
3
  import gymnasium as gym
2
4
  import numpy as np
3
5
  import pytest
4
6
 
5
7
  from stable_baselines3 import DQN, SAC, TD3
6
- from stable_baselines3.common.buffers import NStepReplayBuffer, ReplayBuffer
8
+ from stable_baselines3.common.buffers import DictReplayBuffer, NStepReplayBuffer, ReplayBuffer
7
9
  from stable_baselines3.common.env_util import make_vec_env
10
+ from stable_baselines3.common.envs import BitFlippingEnv
11
+ from stable_baselines3.her import HerReplayBuffer
8
12
 
9
13
 
10
14
  @pytest.mark.parametrize("model_class", [SAC, DQN, TD3])
@@ -30,6 +34,47 @@ def test_run(model_class):
30
34
  model.learn(total_timesteps=150)
31
35
 
32
36
 
37
+ @pytest.mark.parametrize("replay_buffer_class", [ReplayBuffer, NStepReplayBuffer])
38
+ def test_n_steps_warns_with_custom_replay_buffer_class(replay_buffer_class):
39
+ """`n_steps > 1` is ignored when the buffer class is user-provided, so it must warn."""
40
+ with pytest.warns(UserWarning, match="n_steps=3"):
41
+ model = SAC("MlpPolicy", "Pendulum-v1", n_steps=3, buffer_size=200, replay_buffer_class=replay_buffer_class)
42
+ # The buffer is built from the user-provided class, untouched by `n_steps`
43
+ assert type(model.replay_buffer) is replay_buffer_class
44
+
45
+
46
+ @pytest.mark.parametrize("replay_buffer_class", [None, DictReplayBuffer, HerReplayBuffer])
47
+ def test_n_steps_with_dict_obs(replay_buffer_class):
48
+ """Dict observation spaces do not support n-step returns: assert on the default path, warn otherwise."""
49
+ env = BitFlippingEnv(n_bits=4, continuous=True)
50
+ if replay_buffer_class is None:
51
+ with pytest.raises(AssertionError, match="Dict observation spaces"):
52
+ SAC("MultiInputPolicy", env, n_steps=3, buffer_size=200)
53
+ else:
54
+ with pytest.warns(UserWarning, match="n_steps=3"):
55
+ SAC("MultiInputPolicy", env, n_steps=3, buffer_size=200, replay_buffer_class=replay_buffer_class)
56
+
57
+
58
+ def test_n_steps_custom_class_no_warnings():
59
+ with warnings.catch_warnings():
60
+ warnings.simplefilter("error")
61
+ # Note: values must differ from ``NStepReplayBuffer`` defaults (n_steps=3, gamma=0.99)
62
+ # otherwise the assertions below would pass even if nothing was applied.
63
+ model = SAC(
64
+ "MlpPolicy",
65
+ "Pendulum-v1",
66
+ buffer_size=200,
67
+ replay_buffer_class=NStepReplayBuffer,
68
+ replay_buffer_kwargs={"n_steps": 4, "gamma": 0.95},
69
+ )
70
+ assert isinstance(model.replay_buffer, NStepReplayBuffer)
71
+ assert model.replay_buffer.n_steps == 4
72
+ assert model.replay_buffer.gamma == 0.95
73
+
74
+ # Default n-steps
75
+ SAC("MlpPolicy", "Pendulum-v1", buffer_size=200, replay_buffer_class=ReplayBuffer)
76
+
77
+
33
78
  def create_buffer(buffer_size=10, n_steps=3, gamma=0.99, n_envs=1):
34
79
  obs_space = gym.spaces.Box(low=0, high=1, shape=(4,), dtype=np.float32)
35
80
  act_space = gym.spaces.Box(low=0, high=1, shape=(2,), dtype=np.float32)
@@ -891,3 +891,34 @@ def test_save_load_clip_range_portable(tmp_path, model_class):
891
891
  assert isinstance(model.clip_range, FloatSchedule)
892
892
  assert isinstance(model.clip_range.value_schedule, ConstantSchedule)
893
893
  assert model.clip_range.value_schedule.val == 0.2
894
+
895
+
896
+ def test_load_bad_zip(tmp_path):
897
+ """Test that loading a non-zip file raises a ValueError."""
898
+ # Write a plain text file to the path
899
+ bad_path = tmp_path / "not_a_zip.zip"
900
+ bad_path.write_text("this is not a zip file")
901
+
902
+ with pytest.raises(ValueError, match="wasn't a zip-file"):
903
+ PPO.load(str(bad_path))
904
+
905
+
906
+ @pytest.mark.filterwarnings("error::ResourceWarning")
907
+ def test_open_path_directory_and_missing_parent(tmp_path):
908
+ """Test IsADirectoryError and FileNotFoundError handling in open_path."""
909
+ # Test IsADirectoryError: path already has the suffix and is a folder
910
+ dir_path = tmp_path / "is_a_folder.pkl"
911
+ dir_path.mkdir()
912
+ with warnings.catch_warnings(record=True) as record:
913
+ open_path(dir_path, "w", suffix="pkl").close()
914
+ assert any("is a folder" in str(warning.message) for warning in record)
915
+ # Verify the fallback file was created
916
+ assert (tmp_path / "is_a_folder.pkl_2").exists()
917
+
918
+ # Test FileNotFoundError: parent folder doesn't exist
919
+ missing_parent_path = tmp_path / "nonexistent_parent" / "sub" / "file"
920
+ with warnings.catch_warnings(record=True) as record:
921
+ open_path(missing_parent_path, "w", suffix="pkl").close()
922
+ assert any("does not exist" in str(warning.message) for warning in record)
923
+ # Verify the parent was created and file was written
924
+ assert (tmp_path / "nonexistent_parent" / "sub" / "file.pkl").exists()
@@ -123,7 +123,8 @@ def test_sde_multi_dim():
123
123
  @pytest.mark.parametrize("model_class", [A2C, PPO, DQN])
124
124
  @pytest.mark.parametrize("env", ["Taxi-v3"])
125
125
  def test_discrete_obs_space(model_class, env):
126
- env = make_vec_env(env, n_envs=2, seed=0)
126
+
127
+ env = _make_env_safe(env, n_envs=2, seed=0)
127
128
  kwargs = {}
128
129
  if model_class == DQN:
129
130
  kwargs = dict(buffer_size=1000, learning_starts=100)
@@ -173,3 +174,17 @@ def test_multidim_binary_not_supported():
173
174
  env = DummyEnv(BOX_SPACE_FLOAT32, spaces.MultiBinary([2, 3]))
174
175
  with pytest.raises(AssertionError, match=r"Multi-dimensional MultiBinary\(.*\) action space is not supported"):
175
176
  A2C("MlpPolicy", env)
177
+
178
+
179
+ def _make_env_safe(env_id, **kwargs):
180
+ try:
181
+ return make_vec_env(env_id, **kwargs)
182
+ except gym.error.DeprecatedEnv:
183
+ # map deprecated to new (better extendability for this)
184
+ fallback_map = {
185
+ # as of gymnasium 1.3.0 Taxi-v3 is deprecated
186
+ "Taxi-v3": "Taxi-v4",
187
+ }
188
+ if env_id in fallback_map:
189
+ return make_vec_env(fallback_map[env_id], **kwargs)
190
+ raise
@@ -1,4 +1,5 @@
1
1
  import os
2
+ import pickle
2
3
  import shutil
3
4
 
4
5
  import ale_py
@@ -15,6 +16,7 @@ from stable_baselines3.common.env_util import is_wrapped, make_atari_env, make_v
15
16
  from stable_baselines3.common.evaluation import evaluate_policy
16
17
  from stable_baselines3.common.monitor import Monitor
17
18
  from stable_baselines3.common.noise import OrnsteinUhlenbeckActionNoise, VectorizedActionNoise
19
+ from stable_baselines3.common.sb2_compat.rmsprop_tf_like import RMSpropTFLike
18
20
  from stable_baselines3.common.utils import (
19
21
  ConstantSchedule,
20
22
  FloatSchedule,
@@ -628,3 +630,57 @@ def test_deprecated_schedules():
628
630
  assert np.allclose(fn(0.5), schedule(0.5))
629
631
  assert np.allclose(fn(0.5), float_schedule(0.5))
630
632
  assert np.allclose(fn(0.5), float_schedule_2(0.5))
633
+
634
+
635
+ class TestRMSpropTFLike:
636
+ """Tests for the RMSpropTFLike optimizer (sb2_compat)."""
637
+
638
+ def test_invalid_params(self):
639
+ """Test that invalid optimizer parameters raise ValueError."""
640
+ param = th.nn.Parameter(th.zeros(2))
641
+ with pytest.raises(ValueError, match="Invalid learning rate"):
642
+ RMSpropTFLike([param], lr=-1.0)
643
+ with pytest.raises(ValueError, match="Invalid epsilon"):
644
+ RMSpropTFLike([param], eps=-1.0)
645
+ with pytest.raises(ValueError, match="Invalid momentum"):
646
+ RMSpropTFLike([param], momentum=-1.0)
647
+ with pytest.raises(ValueError, match="Invalid weight_decay"):
648
+ RMSpropTFLike([param], weight_decay=-1.0)
649
+ with pytest.raises(ValueError, match="Invalid alpha"):
650
+ RMSpropTFLike([param], alpha=-1.0)
651
+
652
+ def test_centered_momentum_weight_decay(self):
653
+ """Test centered=True, momentum>0, weight_decay>0 branches in step()."""
654
+ param = th.nn.Parameter(th.tensor([1.0, 2.0]))
655
+ opt = RMSpropTFLike(
656
+ [param],
657
+ lr=0.1,
658
+ momentum=0.9,
659
+ alpha=0.99,
660
+ eps=1e-8,
661
+ centered=True,
662
+ weight_decay=0.01,
663
+ )
664
+ # Compute gradient
665
+ loss = (param**2).sum()
666
+ loss.backward()
667
+
668
+ # Run step with closure (covers closure branch)
669
+ def closure():
670
+ param.grad.zero_()
671
+ return float((param**2).sum().detach())
672
+
673
+ opt.step(closure=closure)
674
+ # Check state keys exist (covers centered + momentum init)
675
+ state = opt.state[param]
676
+ assert "grad_avg" in state # centered=True
677
+ assert "momentum_buffer" in state # momentum > 0
678
+
679
+ def test_pickle_roundtrip(self):
680
+ """Test that optimizer survives pickle roundtrip (covers __setstate__)."""
681
+ param = th.nn.Parameter(th.tensor([1.0, 2.0]))
682
+ opt = RMSpropTFLike([param], lr=0.1, momentum=0.5, centered=True)
683
+ opt2 = pickle.loads(pickle.dumps(opt))
684
+ assert opt2.param_groups[0]["lr"] == 0.1
685
+ assert opt2.param_groups[0]["momentum"] == 0.5
686
+ assert opt2.param_groups[0]["centered"] is True
@@ -317,7 +317,7 @@ def check_vecenv_obs(obs, space):
317
317
  assert space.contains(value)
318
318
 
319
319
 
320
- @pytest.mark.parametrize("vec_env_class,space", itertools.product(VEC_ENV_CLASSES, SPACES.values()))
320
+ @pytest.mark.parametrize("vec_env_class,space", list(itertools.product(VEC_ENV_CLASSES, SPACES.values())))
321
321
  def test_vecenv_single_space(vec_env_class, space):
322
322
  def obs_assert(obs):
323
323
  return check_vecenv_obs(obs, space)
@@ -1 +0,0 @@
1
- 2.9.0a2