OpenAI-Gym结合Keras-RL实现DQN时模型输出维度不匹配报错求助
报错根因
- 直接触发原因:DQNAgent的
nb_actions参数要求传入整数,代表所有可选离散动作的总数量,但你传入的是env.action_space.shape也就是元组(3,),类型和含义都不符合要求。 - 底层逻辑错误:
- Keras-RL原生DQN仅支持单维度离散动作空间(即
Discrete类型),你当前使用Box类型定义3个整数动作属于用法错误,Box是用于连续动作的空间类型。 - 你的模型输出维度为3,不符合DQN的设计逻辑:DQN的输出层维度必须等于所有可选动作的总数量,每个输出值对应一个动作的Q值,你当前的3个输出仅对应动作的3个维度,并非独立动作的Q值。
- 额外隐含bug:自定义环境的观测空间下限第一个值为20,但reset方法初始化state_1为0,会直接导致状态越界,后续训练也会出错。
- Keras-RL原生DQN仅支持单维度离散动作空间(即
解决方案
提供两种可行方案,按需选择:
方案1:适配原生Keras-RL DQN,扁平化动作空间
如果必须使用Keras-RL框架,把3个离散动作组合扁平化转为单维度离散动作:
- 修改环境动作空间定义:
# 原来的Box定义删掉,替换为 self.action_space = Discrete(11 * 21 * 28) # 三个动作的取值数量乘积:0-10共11个,0-20共21个,0-27共28个
- 新增动作解码工具函数,把DQN输出的单个动作id拆分为3个维度的动作值:
def decode_action(action_id): a0 = action_id % 11 rem = action_id // 11 a1 = rem % 21 a2 = rem //21 return [a0, a1, a2]
- 修改step方法,先解码再执行状态更新:
def step(self, action ): # 新增解码逻辑 action = decode_action(action) # 后面原有逻辑保持不变
- 修改模型构建和Agent初始化参数:
# 动作总个数直接定义为整数 nb_actions = 11 * 21 * 28 def build_model(states, nb_actions): model = Sequential() model.add(Dense(24, activation='relu', input_shape=states)) model.add(Dense(24, activation='relu')) model.add(Dense(nb_actions , activation='linear')) # 输出维度改为动作总个数 return model # 初始化Agent时传入整数nb_actions def build_agent (model, nb_actions): policy = BoltzmannQPolicy() memory = SequentialMemory(limit = 50000, window_length=1) dqn = DQNAgent (model = model, memory = memory, policy=policy, nb_actions=nb_actions, nb_steps_warmup=10, target_model_update= 1e-2) return dqn
- 修复reset的状态越界问题,把初始化的state_1、state_2、state_3调整到观测空间的取值范围内。
方案2:换用支持多离散动作的RL框架(更推荐)
Keras-RL已经停止维护,推荐换用Stable Baselines3,其DQN直接支持MultiDiscrete类型的多离散动作空间,无需扁平化:
- 首先修改环境动作空间定义:
from gym.spaces import MultiDiscrete # 替换原来的Box定义 self.action_space = MultiDiscrete([11, 21, 28]) # 每个维度的动作取值数量
- 安装Stable Baselines3后直接调用其DQN接口即可,无需手动修改模型输出层,框架会自动适配多离散动作的Q值输出。
内容的提问来源于stack exchange,提问作者PeterBe
相关产品推荐
相关产品推荐

