Repository navigation
6d: continuous rotation representation, bimanual layouts, shared norm helpers - #653
Conversation
|
| ) -> torch.Tensor: | ||
| """Normalize with per-key stats (zscore, or [-1, 1] for minmax/quantile).""" | ||
| center, scale = _norm_center_scale(stats, norm_mode, tensor) | ||
| return (tensor - center) / (scale + _eps(norm_mode)) |
There was a problem hiding this comment.
Normalization changes constant channels
For minmax and quantile normalization, the centered formula does not match the previous 2 * (x - lo) / (hi - lo + 1e-6) - 1. When a channel is constant and its sample equals the bound, it now normalizes to 0 instead of -1. The dataset uses this helper for training, including the configured quantile mode, so this refactor changes model inputs. Please preserve the previous offset.
| def _like_input(out: np.ndarray, is_tensor: bool): | ||
| return torch.from_numpy(out) if is_tensor else out |
There was a problem hiding this comment.
Tensor output loses its device
If either new transform receives a CUDA tensor, _as_array moves it to CPU and this conversion returns a CPU tensor. Code that then combines the result with CUDA tensors will encounter a device mismatch. Preserve the input device on the returned tensor, or make the transforms' CPU-only contract explicit.
768af57 to
78794c5
Compare
3ce0cef to
1a00f2a
Compare
1a00f2a to
f885a7d
Compare
… helpers Groundwork for the 6D action pipeline, with no behavior change anywhere. pose_utils gains _ypr_to_rot6d / _rot6d_to_ypr (numpy, ZYX euler <-> the first two columns of the rotation matrix, Gram-Schmidt on the way back so a non-orthonormal model prediction still yields a proper rotation), matching the column convention of the torch helpers in action_utils. BIMANUAL_CARTESIAN_LAYOUTS maps a vector width (12/14 ypr, 18/20 6D) to its xyz / rot / grip channel indices; the norm-stat bounds check and the eval metrics both consume it to know which channel is which. action_chunk_transforms gains CartesianYPRToRot6D / CartesianRot6DToYPR, which convert a bimanual cartesian vector between xyz+ypr(+gripper) and xyz+rot6d(+gripper) while preserving the numpy/tensor type of the input. action_utils extracts the normalization math that was inlined in MultiDataset._apply_norm_one / ._apply_unnorm_one into module-level _apply_norm_one / _apply_unnorm_one, over a shared _norm_center_scale. _eps preserves the historical denominators exactly (std + 1e-6 for zscore, (hi - lo) + 1e-6 for minmax/quantile, i.e. half_range + 0.5e-6), so the three norm modes are numerically identical to before; MultiDataset now delegates. Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
f885a7d to
61ad3a5
Compare

Groundwork for the 6D action pipeline, with no behavior change anywhere.
pose_utils gains _ypr_to_rot6d / _rot6d_to_ypr (numpy, ZYX euler <-> the first
two columns of the rotation matrix, Gram-Schmidt on the way back so a
non-orthonormal model prediction still yields a proper rotation), matching the
column convention of the torch helpers in action_utils. BIMANUAL_CARTESIAN_LAYOUTS
maps a vector width (12/14 ypr, 18/20 6D) to its xyz / rot / grip channel
indices; the norm-stat bounds check and the eval metrics both consume it to know
which channel is which.
action_chunk_transforms gains CartesianYPRToRot6D / CartesianRot6DToYPR, which
convert a bimanual cartesian vector between xyz+ypr(+gripper) and
xyz+rot6d(+gripper) while preserving the numpy/tensor type of the input.
action_utils extracts the normalization math that was inlined in
MultiDataset._apply_norm_one / ._apply_unnorm_one into module-level
_apply_norm_one / _apply_unnorm_one, over a shared _norm_center_scale. _eps
preserves the historical denominators exactly (std + 1e-6 for zscore,
(hi - lo) + 1e-6 for minmax/quantile, i.e. half_range + 0.5e-6), so the three
norm modes are numerically identical to before; MultiDataset now delegates.
Co-Authored-By: Claude Opus 5 (1M context) [email protected]
🤖 Generated with Claude Code