RLlib训练时打印动作分布报错求助:多智能体剪刀石头布场景
解决RLLib多智能体环境中Episode结束后打印动作分布的报错问题
你想在每个Episode结束后打印动作分布来观察智能体行为的思路是对的,但代码里有几个关键问题导致了输入形状不匹配的错误,我来帮你拆解一下:
错误原因分析
你遇到的ValueError: Input 0 of layer fc_value_1 is incompatible with the layer: expected axis -1 of input shape to have value 3 but received input with shape [1, 6],核心问题是你错误地定义了观测空间:
- 在原RockPaperScissors多智能体环境中,每个智能体的观测空间是
Discrete(3)(观测内容是对手上一轮的动作),而不是你写的Tuple((Discrete(3),Discrete(3)))。 - 你手动创建的预处理器基于错误的观测空间,把输入处理成了6维(两个3维离散空间拼接),但训练好的模型是基于3维观测构建的,自然会出现形状不匹配。
除此之外,代码还有几个不规范/错误的地方:
- 直接访问
episode._policies是访问私有属性,RLLib推荐用公开API获取策略; - 手动创建预处理器没必要,应该用策略自带的预处理器来处理观测,保证和训练时的预处理逻辑一致;
- 构造的
curr_state = (0,1)不符合单个智能体的观测格式,应该是单个0-2的整数。
修正后的代码示例
下面是调整后的on_episode_end回调函数,你可以直接替换原代码:
import numpy as np from ray.rllib.policy.sample_batch import SampleBatch def on_episode_end(info): episode = info["episode"] # 通过智能体ID获取对应的策略(比如"player1"是使用learned策略的智能体) policy = episode.policy_for("player1") # 构造符合观测空间的测试状态:比如对手上一轮出了动作0(石头) test_obs = 0 # 使用策略自带的预处理器处理观测,和训练时逻辑一致 processed_obs = policy.preprocessors[SampleBatch.OBS].transform([test_obs]) # 获取模型的logits输出 logits, _ = policy.model.from_batch({SampleBatch.OBS: np.array(processed_obs)}) # 创建分布对象 dist = policy.dist_class(logits, policy.model) # 打印动作分布的概率、采样结果和指定动作的log概率 print(f"动作概率分布: {dist.prob_numpy()}") print(f"采样动作: {dist.sample().numpy()}") print(f"动作0的log概率: {dist.logp([0]).numpy()}")
关键调整点说明
- 正确获取策略:用
episode.policy_for("player1")替代私有属性访问,更稳定且符合RLLib的API规范; - 使用策略自带的预处理器:
policy.preprocessors[SampleBatch.OBS]是训练时用的预处理器,保证观测处理逻辑和训练完全一致; - 构造正确的观测格式:单个
Discrete(3)类型的观测是0-2的整数,而不是元组; - 打印更直观的分布信息:新增了打印动作概率分布的代码,比只打印log概率更便于观察智能体的行为倾向。
内容的提问来源于stack exchange,提问作者Charlie Hou
相关产品推荐
相关产品推荐

