MCPcopy Create free account
hub / github.com/SpatialVLA/SpatialVLA / chunk_act_obs

Function chunk_act_obs

data/traj_transforms.py:12–74  ·  view source on GitHub ↗

Chunks actions and observations into the given window_size. "observation" keys are given a new axis (at index 1) of size `window_size` containing `window_size - 1` observations from the past and the current observation. "action" is given a new axis (at index 1) of size `window_size

(
    traj: Dict,
    backward_windows_size: int = 0,
    backward_delta: int = 1,
    forward_window_size: int = 0,
)

Source from the content-addressed store, hash-verified

10import tensorflow as tf
11
12def chunk_act_obs(
13 traj: Dict,
14 backward_windows_size: int = 0,
15 backward_delta: int = 1,
16 forward_window_size: int = 0,
17) -> Dict:
18 """
19 Chunks actions and observations into the given window_size.
20
21 "observation" keys are given a new axis (at index 1) of size `window_size` containing `window_size - 1`
22 observations from the past and the current observation. "action" is given a new axis (at index 1) of size
23 `window_size + future_action_window_size` containing `window_size - 1` actions from the past, the current
24 action, and `future_action_window_size` actions from the future. "pad_mask" is added to "observation" and
25 indicates whether an observation should be considered padding (i.e. if it had come from a timestep
26 before the start of the trajectory).
27 """
28 traj_len = tf.shape(traj["action"])[0]
29 action_dim = traj["action"].shape[-1]
30 chunk_indices = tf.broadcast_to(tf.range(-backward_windows_size, 1) * backward_delta, [traj_len, backward_windows_size + 1]) + tf.broadcast_to(
31 tf.range(traj_len)[:, None], [traj_len, backward_windows_size + 1]
32 )
33
34 action_chunk_indices = tf.broadcast_to(
35 tf.range(0, 1 + forward_window_size),
36 [traj_len, 1 + forward_window_size],
37 ) + tf.broadcast_to(
38 tf.range(traj_len)[:, None],
39 [traj_len, 1 + forward_window_size],
40 )
41
42 floored_chunk_indices = tf.maximum(chunk_indices, 0)
43
44 if "timestep" in traj["task"]:
45 goal_timestep = traj["task"]["timestep"]
46 else:
47 goal_timestep = tf.fill([traj_len], traj_len - 1)
48
49 floored_action_chunk_indices = tf.minimum(tf.maximum(action_chunk_indices, 0), goal_timestep[:, None])
50
51 traj["observation"] = tf.nest.map_structure(lambda x: tf.gather(x, floored_chunk_indices), traj["observation"])
52 traj["action"] = tf.gather(traj["action"], floored_action_chunk_indices)
53
54 # indicates whether an entire observation is padding
55 traj["observation"]["pad_mask"] = chunk_indices >= 0
56
57 # if no absolute_action_mask was provided, assume all actions are relative
58 if "absolute_action_mask" not in traj and forward_window_size > 0:
59 logging.warning(
60 "future_action_window_size > 0 but no absolute_action_mask was provided. "
61 "Assuming all actions are relative for the purpose of making neutral actions."
62 )
63 absolute_action_mask = traj.get("absolute_action_mask", tf.zeros([traj_len, action_dim], dtype=tf.bool))
64 neutral_actions = tf.where(
65 absolute_action_mask[:, None, :],
66 traj["action"], # absolute actions are repeated (already done during chunking)
67 tf.zeros_like(traj["action"]), # relative actions are zeroed
68 )
69

Callers

nothing calls this directly

Calls

no outgoing calls

Tested by

no test coverage detected