使用Stable Baselines3创建自定义Gym环境模型时报TypeError错误
问题根因
你遇到的报错来自两处实现问题,第一处直接触发当前类型错误,第二处会在第一处修复后触发网络形状不匹配错误:
- 第一处:
MultiBinary观测空间初始化参数错误
Gym的MultiBinary空间对初始化参数有要求:你传入的是列表[field_size[0], field_size[1]],会导致空间实例的n属性被赋值为这个列表。Stable Baselines3(下称SB3)解析观测空间时,只要检测到空间存在n属性就会默认它是一维离散空间,尝试执行int(observation_space.n),自然会因为传入的是列表触发类型错误。
多维MultiBinary初始化必须传入元组作为形状参数:# 错误写法 self.observation_space = MultiBinary([field_size[0], field_size[1]]) # 正确写法 self.observation_space = MultiBinary((field_size[0], field_size[1])) - 第二处:观测形状不符合CnnPolicy输入要求
修复上面的问题后依然会报错:SB3的CnnPolicy是为图像输入设计的,要求观测必须带通道维度,也就是形状至少为3维,支持通道优先(通道数, 高度, 宽度)和通道最后(高度, 宽度, 通道数)两种格式。你当前的观测是2维(20,10),没有通道维度,CNN卷积层无法处理。
你的场地只有0(空)、1(有方块)两种值,属于单通道二值图,需要同步调整观测空间和返回的观测数组形状:- 先导入numpy:
import numpy as np - 修改观测空间定义,使用通道优先格式(SB3对该格式兼容性最好):
self.observation_space = MultiBinary((1, self.height, self.width)) - 修改
step方法的返回值,给观测增加通道维度:# 替换原有的 return self.game.field, reward, done, {} obs = np.expand_dims(self.game.field, axis=0) return obs, reward, done, {} - 修改
reset方法的返回值,同步增加通道维度:# 替换原有的 return self.game.field obs = np.expand_dims(self.game.field, axis=0) return obs
- 先导入numpy:
可选调整方案
如果你不想使用CNN,也可以换用MlpPolicy,此时不需要保留二维结构,只需要把场地展平为一维向量即可:
# __init__里修改观测空间为一维,长度为场地总格子数 self.observation_space = MultiBinary(self.height * self.width) # step和reset返回观测时展平数组 obs = self.game.field.flatten()
注意MlpPolicy对二维网格的空间特征提取能力弱于CNN,训练到同等效果需要更多采样样本。
额外训练建议
- 你当前的奖励函数过于稀疏,仅在消行和存活时给奖励,智能体收敛速度会很慢,可以加入落地后空洞数惩罚、场地平整度奖励等塑形奖励,加快收敛。
- 当前动作空间设置为单步移动/旋转,每个episode需要决策的步数过多,训练效率极低。常规俄罗斯方块RL环境会把动作定义为「当前方块旋转N次+移动到X列直接落地」,可以把单episode决策步数从几千降到几十,大幅提升训练速度。
- 如果你使用SB3 2.0以上版本,建议把旧版
gym替换为gymnasium,避免API不兼容导致的隐性问题。
内容的提问来源于stack exchange,提问作者UnknownInnocent
相关产品推荐
相关产品推荐

