poke-env environments provide observations as dictionaries containing "observation" and "action_mask" keys. To prevent a reinforcement learning agent from selecting illegal moves, you must implement a custom policy in Stable-Baselines3 that applies this mask to the action logits.
- Custom Features Extractor: Create a
BaseFeaturesExtractor that pulls the "observation" tensor from the dictionary. - Masked Policy: Subclass
ActorCriticPolicy (or similar) to intercept the "action_mask" and apply it as -inf to the action logits in _get_action_dist_from_latent. This ensures illegal actions have a probability of zero.
class MaskedActorCriticPolicy(ActorCriticPolicy):
def __init__(self, *args, **kwargs):
super().__init__(
*args,
**kwargs,
net_arch=[64, 64],
features_extractor_class=FeaturesExtractor,
)
def forward(self, obs, deterministic=False):
self._mask = obs["action_mask"]
return super().forward(obs, deterministic)
def evaluate_actions(self, obs, actions):
self._mask = obs["action_mask"]
return super().evaluate_actions(obs, actions)
def _get_action_dist_from_latent(self, latent_pi):
action_logits = self.action_net(latent_pi)
mask = torch.where(self._mask == 1, 0, float("-inf"))
return self.action_dist.proba_distribution(action_logits + mask)