解决 Stable Baselines 'MIN_LEVEL' 报错: Gym 版本冲突与方案
2025-04-23 12:57:19
踩坑指南:解决 Stable Baselines 运行报错 module 'gym.logger' has no attribute 'MIN_LEVEL'
写强化学习代码的时候,用 stable-baselines
这个库还挺顺手的。但有时候,冷不丁就会遇到一些奇奇怪怪的报错,比如这个 'gym.logger' has no attribute 'MIN_LEVEL'
。今天咱们就来盘一盘这个错误,看看它到底是何方神圣,又该怎么解决。
问题在哪?
当你兴致勃勃地想用 stable-baselines
跑个 PPO 或者 DDPG 之类的算法时,可能刚初始化模型,比如像下面这样:
import gym
from stable_baselines.common.policies import MlpPolicy
from stable_baselines.common import make_vec_env
from stable_baselines import PPO2 # 或者其他算法,比如 A2C, DDPG 等
# 创建环境,这里用 CartPole 做例子
env = make_vec_env('CartPole-v1', n_envs=4)
# 初始化模型,问题通常就出在这!
model = PPO2(MlpPolicy, env, verbose=1)
# 下面的学习、保存、加载代码暂时还跑不到
# model.learn(total_timesteps=25000)
# model.save("ppo2_cartpole")
# ...
啪!程序就可能给你甩来一脸错误信息,关键部分长这样:
Traceback (most recent call last):
... # 中间一堆调用栈信息
File "~/miniconda3/envs/tf15/lib/python3.7/site-packages/stable_baselines/common/base_class.py", line 1129, in __enter__
self.gym_level = gym.logger.MIN_LEVEL
AttributeError: module 'gym.logger' has no attribute 'MIN_LEVEL'
看到 AttributeError
就头大,意思是 gym.logger
这个模块下面,根本就没有 MIN_LEVEL
这个属性或者变量。这就奇怪了,stable-baselines
官方示例代码都可能出错,难道是打开方式不对?
为啥会出现这个错误?(原因分析)
这问题十有八九是 库版本冲突 造成的,特别是 stable-baselines
和 gym
这两个库之间的爱恨情仇。
咱们来捋一捋:
-
stable-baselines
的年代: 你遇到的这个stable-baselines
(注意,不是stable-baselines3
) 是一个相对较老的库。它主要设计用来和 TensorFlow 1.x 配合使用(就像问题里提到的 TF 1.15.0)。这个库在开发的时候,依赖的是当时主流的gym
版本。 -
gym
的变迁: OpenAI 的gym
库也在不断发展。在某个版本(具体来说是 0.21.0 版本 左右)之后,gym
进行了一次比较大的 API 更新和内部结构调整。其中就包括了日志(logging)系统的修改。在旧版本的gym
中,gym.logger
下面确实有一个叫做MIN_LEVEL
的东西,用来控制日志输出的级别。 -
冲突点:
stable-baselines
的代码(特别是内部用于控制日志输出详细程度的SetVerbosity
类)是按照旧版gym
的 API 来写的。它期望能找到gym.logger.MIN_LEVEL
。但是,如果你环境里安装的gym
是一个比较新的版本 (比如 >= 0.21.0),那么这个MIN_LEVEL
可能已经被移除或者改名了。这就导致了AttributeError
—— 你想找的东西,在新版gym
里已经没了!
简单说就是:老库(stable-baselines
)想用老接口(gym.logger.MIN_LEVEL
),但你装了个新库(新版 gym
),新库把老接口给改了。卒。
特别是当你使用 Conda 或 Pip 安装 stable-baselines
时,包管理器可能会自动帮你安装最新版本的 gym
作为依赖,这就很容易触发这个版本不兼容的问题。
怎么解决?(解决方案)
知道了原因,解决起来就有方向了。主要是围绕着让 stable-baselines
和 gym
的版本匹配起来。
方案一:降低 Gym 版本(推荐)
这是最直接也通常是最稳妥的方法。既然 stable-baselines
需要旧版的 gym
API,那咱们就给它装个旧版的 gym
。
-
原理:
安装一个与你使用的stable-baselines
版本兼容的gym
版本(通常是 0.21.0 之前的版本,比如 0.20.0 或更早)。这样stable-baselines
代码就能找到它需要的gym.logger.MIN_LEVEL
了。 -
操作步骤:
-
卸载当前 Gym:
在你的 Conda 环境(或虚拟环境)中,先卸载掉可能存在的新版本gym
。pip uninstall gym gymnasium # gymnasium 也可能装了,顺手卸了 # 或者如果用 conda 安装的 # conda remove gym gymnasium
-
安装指定版本的 Gym:
安装一个明确的、较旧的版本。0.20.0
是一个比较常见的选择,通常能与stable-baselines
配合良好。pip install gym==0.20.0
或者尝试安装明确小于 0.21.0 的版本约束:
pip install "gym<0.21.0"
你可以先试试
0.20.0
,如果不行再尝试更早的版本,比如0.19.0
。 -
验证安装:
可以检查一下gym
的版本是否确实降级成功了。pip show gym
输出信息里应该显示
Version: 0.20.0
(或者你安装的其他旧版本)。
-
-
代码示例:
完成上述降级操作后,你之前报错的代码应该就能正常运行了:import gym from stable_baselines.common.policies import MlpPolicy from stable_baselines.common import make_vec_env from stable_baselines import PPO2 print(f"Using Gym version: {gym.__version__}") # 可以加一行打印确认版本 # 现在这步应该不会报错了 env = make_vec_env('CartPole-v1', n_envs=4) model = PPO2(MlpPolicy, env, verbose=1) print("Model initialized successfully!") # 后续代码... # model.learn(total_timesteps=1000) # 缩短点时间,快速验证 # model.save("ppo2_cartpole_fixed")
-
安全建议:
使用较旧版本的库理论上可能错过一些安全补丁。不过,对于gym
这样一个主要用于模拟环境的库,且版本回退不算太久远(比如到 0.20.0),在隔离的开发环境(如 Conda 环境)中使用,风险通常较低。关键是确保你的训练环境和生产环境的网络隔离。 -
进阶使用技巧:
为了保证环境的可复现性,强烈建议将项目的所有依赖(包括明确指定的gym
版本)固定下来。可以使用pip freeze > requirements.txt
命令生成依赖列表文件,或者在 Conda 环境中使用conda env export > environment.yml
。下次创建环境时,可以直接从这些文件安装,确保所有依赖版本一致。
方案二:迁移到 Stable-Baselines3
如果你的项目不是非得用 TensorFlow 1.x 和旧版的 stable-baselines
,那么升级到 stable-baselines3
是一个更现代、更推荐的选择。
-
原理:
stable-baselines3
是stable-baselines
的精神续作,基于 PyTorch (也间接支持 TensorFlow 2.x via Tianshou 或其他库封装),并且被积极维护。它设计时就考虑了与较新版本gym
(甚至包括后来的gymnasium
)的兼容性。迁移到 SB3 可以一劳永逸地解决旧库版本兼容性的问题。 -
操作步骤:
-
卸载旧库 (可选但推荐):
如果确认不再需要旧版stable-baselines
,可以先卸载它。pip uninstall stable-baselines
-
安装 Stable-Baselines3:
安装stable-baselines3
。它默认使用 PyTorch。pip install stable-baselines3[extra] # [extra] 会包含常用依赖,如 atari 环境支持
同时,确保你的
gym
版本较新,或者使用gymnasium
(推荐,gym
0.26 后更名为gymnasium
):pip install gymnasium # 安装 gymnasium # 或者更新 gym 到较新版 # pip install --upgrade gym
注意:
stable-baselines3
目前推荐使用gymnasium
。 -
修改代码:
stable-baselines3
的 API 和旧版stable-baselines
有些不同。你需要相应地修改你的导入语句和模型初始化等代码。
-
-
代码示例 (使用 SB3 和 Gymnasium):
原来的 PPO2 示例用 SB3 和 Gymnasium 实现大致如下:import gymnasium as gym # 注意导入 gymnasium # from stable_baselines3.common.env_util import make_vec_env # SB3 用自己的 make_vec_env # 注意:SB3 更推荐使用 SubprocVecEnv 或 DummyVecEnv 手动创建向量化环境 from stable_baselines3.common.vec_env import DummyVecEnv, SubprocVecEnv from stable_baselines3 import PPO # 算法名字可能简化了,没有 '2' from stable_baselines3.common.env_util import make_vec_env # 也可以用这个助手函数 # 使用 SB3 的 make_vec_env (推荐) # 这个函数会自动处理环境创建和向量化 env = make_vec_env('CartPole-v1', n_envs=4) # 或者手动创建 VecEnv # def make_env(rank: int, seed: int = 0): # """Helper function to create environment""" # def _init(): # env = gym.make('CartPole-v1') # # Deprecated in gymnasium # # env.seed(seed + rank) # # Use reset with seed instead for Gymnasium >= 0.26 # # env.reset(seed=seed+rank) # return env # # set_global_seeds(seed) # deprecated in SB3 >= 2.0 # return _init # num_cpu = 4 # env = SubprocVecEnv([make_env(i) for i in range(num_cpu)]) # 初始化模型,注意 API 变化 # policy='MlpPolicy' 是默认的,也可以显式指定 model = PPO('MlpPolicy', env, verbose=1) print("SB3 Model initialized successfully!") # 学习、保存、加载 model.learn(total_timesteps=25000) model.save("ppo_cartpole_sb3") del model # remove to demonstrate saving and loading model = PPO.load("ppo_cartpole_sb3") # 享受训练好的智能体 (Gymnasium API) vec_env = model.get_env() obs = vec_env.reset() while True: action, _states = model.predict(obs, deterministic=True) obs, rewards, terminated, truncated, info = vec_env.step(action) # 注意返回值的变化 dones = terminated | truncated # 在 SB3 和 Gymnasium 中,通常这样组合 done 信号 vec_env.render("human") # 如果所有环境都结束了,可以考虑重置(VecEnv 会自动处理) if dones.any(): pass # VecEnv handles auto-resetting by default
-
优势:
- 使用最新的、被积极维护的库。
- 享受 PyTorch 生态(或者 TensorFlow 2.x,如果通过其他方式集成)。
- 与最新的
gym
/gymnasium
兼容,可以使用更多新环境和特性。 - 通常有更好的性能和更多的算法选择。
-
注意事项:
- 需要修改现有代码以适应
stable-baselines3
的 API。 - 如果项目强制要求 TensorFlow 1.x,则此方案不适用。
- 需要熟悉 PyTorch 的基本概念(如果选用 PyTorch 后端)。
- 需要修改现有代码以适应
总结一下
遇到 stable_baselines
报 AttributeError: module 'gym.logger' has no attribute 'MIN_LEVEL'
这个错误,基本可以断定是 stable-baselines
(旧版) 和 gym
(新版) 之间的版本不兼容导致的。
- 最快修复: 降级
gym
到0.20.0
或更早版本 (pip install gym==0.20.0
)。 - 长远之计: 如果条件允许,迁移到
stable-baselines3
,并使用gymnasium
。这能让你跟上技术发展的步伐,并避免未来可能出现的类似兼容性问题。
选择哪种方案取决于你的项目需求、时间以及对 TensorFlow 1.x 的依赖程度。希望这篇分析能帮你顺利解决这个拦路虎!