Fix duplicate key error in HumanOutputFormat (#1079)

* Fix duplicate key error in HumanOutputFormat

* Update changelog

* Add test

* Update changelog.rst

Co-authored-by: Adam Gleave <adam@gleave.me>

Co-authored-by: Adam Gleave <adam@gleave.me>
This commit is contained in:
Juan Rocamonde 2022-09-28 12:06:07 +02:00 committed by GitHub
parent 432b3f876d
commit e22e372306
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 16 additions and 6 deletions

View file

@ -32,7 +32,7 @@ Bug Fixes:
- Fixed loading saved model with different number of envrionments
- Removed ``forward()`` abstract method declaration from ``common.policies.BaseModel`` (already defined in ``torch.nn.Module``) to fix type errors in subclasses (@Rocamonde)
- Fixed the return type of ``.load()`` and ``.learn()`` methods in ``BaseAlgorithm`` so that they now use ``TypeVar`` (@Rocamonde)
- Fixed an issue where keys with different tags but the same key raised an error in ``common.logger.HumanOutputFormat`` (@Rocamonde and @AdamGleave)
Deprecations:
^^^^^^^^^^^^^

View file

@ -193,30 +193,31 @@ class HumanOutputFormat(KVWriter, SeqWriter):
if key.find("/") > 0: # Find tag and add it to the dict
tag = key[: key.find("/") + 1]
key2str[self._truncate(tag)] = ""
key2str[(tag, self._truncate(tag))] = ""
# Remove tag from key
if tag is not None and tag in key:
key = str(" " + key[len(tag) :])
truncated_key = self._truncate(key)
if truncated_key in key2str:
if (tag, truncated_key) in key2str:
raise ValueError(
f"Key '{key}' truncated to '{truncated_key}' that already exists. Consider increasing `max_length`."
)
key2str[truncated_key] = self._truncate(value_str)
key2str[(tag, truncated_key)] = self._truncate(value_str)
# Find max widths
if len(key2str) == 0:
warnings.warn("Tried to write empty key-value dict")
return
else:
key_width = max(map(len, key2str.keys()))
tagless_keys = map(lambda x: x[1], key2str.keys())
key_width = max(map(len, tagless_keys))
val_width = max(map(len, key2str.values()))
# Write out the data
dashes = "-" * (key_width + val_width + 7)
lines = [dashes]
for key, value in key2str.items():
for (_, key), value in key2str.items():
key_space = " " * (key_width - len(key))
val_space = " " * (val_width - len(value))
lines.append(f"| {key}{key_space} | {value}{val_space} |")

View file

@ -1,4 +1,5 @@
import os
import sys
import time
from typing import Sequence
from unittest import mock
@ -409,3 +410,11 @@ def test_fps_no_div_zero(algo):
with mock.patch("time.time_ns", lambda: 42.0):
model = algo("MlpPolicy", "CartPole-v1")
model.learn(total_timesteps=100)
def test_human_output_format_no_crash_on_same_keys_different_tags():
o = HumanOutputFormat(sys.stdout, max_length=60)
o.write(
{"key1/foo": "value1", "key1/bar": "value2", "key2/bizz": "value3", "key2/foo": "value4"},
{"key1/foo": None, "key2/bizz": None, "key1/bar": None, "key2/foo": None},
)