Skip to content

Commit ab8172d

Browse files
committed
Enable per-agent advantage normalization
The feature is not implemented in BenchMARL yet. It's opened under this PR: facebookresearch/BenchMARL#256
1 parent c2a642a commit ab8172d

1 file changed

Lines changed: 64 additions & 3 deletions

File tree

examples/python/pettingzoo_learning.py

Lines changed: 64 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,9 @@ def _evaluation_metrics(self, rollouts):
219219
# Actions are (time, n_agents, n_factors)
220220
per_agent = torch.cat(
221221
[
222-
rollout.get((group, "action"))[:, agent_index].reshape(-1, len(self._factor_sizes)).long()
222+
rollout.get((group, "action"))[:, agent_index]
223+
.reshape(-1, len(self._factor_sizes))
224+
.long()
223225
for rollout in rollouts
224226
]
225227
)
@@ -352,7 +354,9 @@ def _get_policy_for_loss(self, group, model_config, continuous, _orig=original):
352354

353355
n_agents = len(self.group_map[group])
354356
actor_module = model_config.get_model(
355-
input_spec=_Composite({group: self.observation_spec[group].clone().to(self.device)}),
357+
input_spec=_Composite(
358+
{group: self.observation_spec[group].clone().to(self.device)}
359+
),
356360
output_spec=_Composite(
357361
{
358362
group: _Composite(
@@ -395,6 +399,51 @@ def _get_policy_for_loss(self, group, model_config, continuous, _orig=original):
395399
_ADVANTAGE_AGENT_DIM = -2
396400

397401

402+
def _enable_per_agent_advantage_normalization(
403+
loss_module, group: str, n_agents: int
404+
) -> None:
405+
"""
406+
BenchMARL hardcodes `normalize_advantage=False` and doesn't expose it on the config,
407+
which deviates loss_obj from entropy bonus.
408+
409+
`normalize_advantage_exclude_dims` (in TorchRL) is what we want, but it's not implemented in BenchMARL.
410+
The flag will be added in this PR: https://github.com/facebookresearch/BenchMARL/pull/256.
411+
"""
412+
for attribute in ("normalize_advantage", "normalize_advantage_exclude_dims"):
413+
if not hasattr(loss_module, attribute):
414+
raise RuntimeError(
415+
f"{type(loss_module).__name__} has no {attribute!r}. Check TorchRL version"
416+
)
417+
418+
loss_module.normalize_advantage = True
419+
loss_module.normalize_advantage_exclude_dims = (_ADVANTAGE_AGENT_DIM,)
420+
421+
# check -2 is agent dimension
422+
advantage_key = loss_module.tensor_keys.advantage
423+
inner_forward = loss_module.forward
424+
state = {"verified": False}
425+
426+
def forward(tensordict, *args, **kwargs):
427+
if not state["verified"]:
428+
advantage = tensordict.get(advantage_key, None)
429+
if advantage is None:
430+
raise RuntimeError(
431+
f"[{group}] {advantage_key} absent before the loss forward"
432+
)
433+
shape = tuple(advantage.shape)
434+
if advantage.ndim < 3 or shape[-1] != 1 or shape[-2] != n_agents:
435+
raise RuntimeError(
436+
f"[{group}] expected advantage of shape (..., {n_agents}, 1) so "
437+
f"that dim {_ADVANTAGE_AGENT_DIM} holds agents, got {shape}."
438+
)
439+
print(
440+
f"[adv-norm] {group}: (advantage {shape}, agent dim {_ADVANTAGE_AGENT_DIM}, {n_agents} agents)",
441+
flush=True,
442+
)
443+
state["verified"] = True
444+
return inner_forward(tensordict, *args, **kwargs)
445+
446+
loss_module.forward = forward
398447

399448

400449
class VizdoomExperiment(Experiment):
@@ -404,8 +453,18 @@ class VizdoomExperiment(Experiment):
404453
- job_type : algorithm name
405454
- group : "<environment>/<task>"
406455
- id / name : "<algo>_<task>_<N>agents_seed<S>_<timestamp>"
456+
457+
and turns on per-agent advantage normalization.
407458
"""
408459

460+
def _setup_algorithm(self):
461+
super()._setup_algorithm()
462+
for group, loss_module in self.losses.items():
463+
if hasattr(loss_module, "normalize_advantage"):
464+
_enable_per_agent_advantage_normalization(
465+
loss_module, group, len(self.group_map[group])
466+
)
467+
409468
def _setup_logger(self):
410469
num_agents = sum(len(v) for v in self.group_map.values())
411470
run_id = self.task.config.get("run_id")
@@ -423,7 +482,9 @@ def _setup_logger(self):
423482
"name": run_id,
424483
}
425484

426-
action_spec = self.test_env.input_spec["full_action_spec", next(iter(self.group_map)), "action"]
485+
action_spec = self.test_env.input_spec[
486+
"full_action_spec", next(iter(self.group_map)), "action"
487+
]
427488
original = self.config.wandb_extra_kwargs
428489
self.config.wandb_extra_kwargs = {**original, **extra}
429490
try:

0 commit comments

Comments
 (0)