What happens
extract_normalization_stats in src/lerobot/processor/migrate_policy_normalization.py derives a feature name from a checkpoint buffer name with an unconditional replace("_", ".") (:112). A feature whose own name contains an underscore is mangled, so its migrated statistics land under a key the runtime never looks up.
observation.environment_state (OBS_ENV_STATE, used by ACT, TDMPC and gaussian_actor) is the concrete case:
import torch
from lerobot.processor.migrate_policy_normalization import extract_normalization_stats
state_dict = {
"normalize_inputs.buffer_observation_environment_state.mean": torch.tensor([1.0]),
"normalize_inputs.buffer_observation_environment_state.std": torch.tensor([2.0]),
}
print(sorted(extract_normalization_stats(state_dict)))
['observation.environment.state'] # expected: ['observation.environment_state']
Why it matters
This hits plain single-dataset checkpoints — no multi-dataset prefix involved. The statistics are extracted and written to the migrated processor config, but under observation.environment.state, so at runtime the normalizer never finds them for observation.environment_state and the feature silently goes unnormalized.
Why it is not a one-line fix
The mangling is not reversible from the string alone. buffer_observation_environment_state could be observation.environment_state or observation.environment.state, and nothing in the key distinguishes them. Resolving it needs the policy's declared feature keys as the authority, rather than more string splitting.
Related
Raised by @takashi-jp while reviewing #4441, which fixes a different defect in the same function (dataset-prefixed keys being dropped entirely). Filed separately because the two need different fixes, and #4441 deliberately leaves this one alone.
What happens
extract_normalization_statsinsrc/lerobot/processor/migrate_policy_normalization.pyderives a feature name from a checkpoint buffer name with an unconditionalreplace("_", ".")(:112). A feature whose own name contains an underscore is mangled, so its migrated statistics land under a key the runtime never looks up.observation.environment_state(OBS_ENV_STATE, used by ACT, TDMPC and gaussian_actor) is the concrete case:Why it matters
This hits plain single-dataset checkpoints — no multi-dataset prefix involved. The statistics are extracted and written to the migrated processor config, but under
observation.environment.state, so at runtime the normalizer never finds them forobservation.environment_stateand the feature silently goes unnormalized.Why it is not a one-line fix
The mangling is not reversible from the string alone.
buffer_observation_environment_statecould beobservation.environment_stateorobservation.environment.state, and nothing in the key distinguishes them. Resolving it needs the policy's declared feature keys as the authority, rather than more string splitting.Related
Raised by @takashi-jp while reviewing #4441, which fixes a different defect in the same function (dataset-prefixed keys being dropped entirely). Filed separately because the two need different fixes, and #4441 deliberately leaves this one alone.