T5-DA3-#2: eval README, source bundles, and the DA3 eval-input builder
Browse files- T5-DA3-#2/README.md +154 -0
- T5-DA3-#2/code/b1k_code.tgz +3 -0
- T5-DA3-#2/code/b1k_support.tgz +3 -0
- T5-DA3-#2/code/da3_eval_inputs.py +88 -0
- T5-DA3-#2/code/da3_geostack.tgz +3 -0
T5-DA3-#2/README.md
ADDED
|
@@ -0,0 +1,154 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# T5-DA3-#2 — BEHAVIOR-1K task 5 (`setting_mousetraps`), pi0.5 + DA3 spatial injection
|
| 2 |
+
|
| 3 |
+
Terminal checkpoint, **step 32999 of 33000**. Final training `action_loss` ≈ **0.022**.
|
| 4 |
+
|
| 5 |
+
Fine-tuned from the 100-task meta checkpoint (`meta100-1epoch/step35000`) on task 5 only, with a
|
| 6 |
+
frozen DA3-GIANT-1.1 backbone supplying per-patch geometry features that are cross-attended into the
|
| 7 |
+
last 6 blocks of the action expert.
|
| 8 |
+
|
| 9 |
+
---
|
| 10 |
+
|
| 11 |
+
## ⚠ Read this first
|
| 12 |
+
|
| 13 |
+
**The stock eval path does not support DA3.** `grep -rn "da3\|DA3" src/b1k/policies/ src/b1k/shared/`
|
| 14 |
+
returns nothing. If you serve this checkpoint through `scripts/serve_b1k.py` unchanged:
|
| 15 |
+
|
| 16 |
+
- `observation.da3_features` is `None`
|
| 17 |
+
- `PiBehavior._compute_banks` returns `None` (`src/b1k/models/pi_behavior.py:372`)
|
| 18 |
+
- the spatial injection is skipped **silently — no error, no warning**
|
| 19 |
+
|
| 20 |
+
You get a policy running without the branch it was trained with. Use `code/da3_eval_inputs.py`
|
| 21 |
+
(included here) to build the missing fields.
|
| 22 |
+
|
| 23 |
+
**The architecture flags are not stored in the checkpoint.** They come from environment variables
|
| 24 |
+
read at model-construction time. If they don't match, the parameter tree won't match either — some
|
| 25 |
+
mismatches raise, others load partially. Export the block below before building the model.
|
| 26 |
+
|
| 27 |
+
---
|
| 28 |
+
|
| 29 |
+
## 1. Environment (required, exact)
|
| 30 |
+
|
| 31 |
+
```bash
|
| 32 |
+
# --- architecture: these DEFINE the parameter tree, not just behaviour ---
|
| 33 |
+
export USE_DA3_FULL=1 B1K_USE_GT_DEPTH=1 B1K_GRASP_AUX=0
|
| 34 |
+
export DA3_MODEL_NAME=depth-anything/DA3-GIANT-1.1
|
| 35 |
+
export DA3_OUT_LAYERS=19,27,33,39 DA3_CHANNELS=1536
|
| 36 |
+
export DA3_GRID_H=16 DA3_GRID_W=16 DA3_BACKBONE_ONLY=1
|
| 37 |
+
export DA3_USE_PERCEIVER=0 DA3_LANG_DEPTH=0
|
| 38 |
+
export DA3_SPATIAL_VEC=1 DA3_SPATIAL_FILM=1 DA3_SPATIAL_USE_DA3=1
|
| 39 |
+
export DA3_FOURIER_BANDS=10 DA3_BANK_TOKEN_EMBED=1 DA3_BANK_CENTER=0
|
| 40 |
+
export DA3_QK_NORM=1 DA3_LOGIT_GAIN=1 DA3_LOGIT_GAIN_INIT=3.0 DA3_INJ_GAIN_MAX=8.0
|
| 41 |
+
export DA3_INIT_STD=0.01 DA3_SCALE=1.0 DA3_EMBED_GROUP=0
|
| 42 |
+
|
| 43 |
+
# --- this run's architecture changes vs the earlier DA3-#1 checkpoints ---
|
| 44 |
+
export DA3_SAMPLE_TOKEN_CENTER=1 # per-sample token centering on the final bank
|
| 45 |
+
export DA3_FEAT_INPUT_NORM=1 # LayerNorm the raw DA3 taps before projection
|
| 46 |
+
export DA3_TAP_TOKEN_CENTER=1 # per-tap token centering before layer_fuse
|
| 47 |
+
export DA3_TAP_GAIN=1 # learnable per-tap scalar gain
|
| 48 |
+
export DA3_CENTER_FUSED=1 # strip the latent DC inside SpatialConditioner
|
| 49 |
+
export DA3_FILM_INIT_STD=0.01 # FiLM gamma/beta non-zero init
|
| 50 |
+
export DA3_S1=1 # merge_proj reads the ATTENTION OUTPUTS
|
| 51 |
+
export DA3_INJ_NO_BIAS=1 # no bias on merge_proj / out_proj
|
| 52 |
+
export DA3_INJECT_DROPOUT=0.0 # inference: always 0
|
| 53 |
+
|
| 54 |
+
# --- task / assets ---
|
| 55 |
+
export B1K_ACTIVITIES=setting_mousetraps B1K_TASK_SPACE=100
|
| 56 |
+
export B1K_ASSETS_BASE=<dir containing assets/ from this repo folder>
|
| 57 |
+
export DA3_LANG_CACHE=<path>/modernbert_b1k_tasks.pkl
|
| 58 |
+
export B1K_TASK_DATA_JSON=<path>/task_data.json
|
| 59 |
+
export DA3_FREEZE_BASE_HARD=0 DA3_LR_GROUPS=1 DA3_TASK5_STAGED=1
|
| 60 |
+
```
|
| 61 |
+
|
| 62 |
+
`DA3_S1=1` and `DA3_INJ_NO_BIAS=1` change the *shape* of the injection block. Loading this checkpoint
|
| 63 |
+
with `DA3_S1=0` will not reproduce the trained function even if it loads.
|
| 64 |
+
|
| 65 |
+
## 2. Files in this folder
|
| 66 |
+
|
| 67 |
+
| path | what |
|
| 68 |
+
|---|---|
|
| 69 |
+
| `params/` | orbax params (13 GB). This is what you load. |
|
| 70 |
+
| `assets/IliaLarchenko/behavior_224_rgb/norm_stats.json` | action/state normalization + the correlated-noise matrix |
|
| 71 |
+
| `_CHECKPOINT_METADATA` | orbax metadata |
|
| 72 |
+
| `code/b1k_code.tgz` | the full training/serving source at the exact commit state this was trained with (`src/`, `scripts/`, `openpi/src/`) |
|
| 73 |
+
| `code/da3_geostack.tgz` | `da3_for_geostack.py`, the DA3-GIANT wrapper the extractor loads |
|
| 74 |
+
| `code/b1k_support.tgz` | `modernbert_b1k_tasks.pkl` (task language features), `task_data.json` |
|
| 75 |
+
| `code/da3_eval_inputs.py` | **the missing piece** — builds the DA3 observation fields at eval time |
|
| 76 |
+
|
| 77 |
+
`train_state/` was deliberately not uploaded (another ~34 GB). Ask if you need to resume training.
|
| 78 |
+
|
| 79 |
+
## 3. Inputs the model expects
|
| 80 |
+
|
| 81 |
+
Standard b1k fields, built by the existing wrapper:
|
| 82 |
+
|
| 83 |
+
| field | shape | notes |
|
| 84 |
+
|---|---|---|
|
| 85 |
+
| `image` | 3 × `[224,224,3]` uint8 | `base_0_rgb` (head/zed), `left_wrist_0_rgb`, `right_wrist_0_rgb` |
|
| 86 |
+
| `state` | `[23]` | `extract_state_2026` of the 61-d proprio: base_qvel(3), trunk(4), left arm(7), left grip(1), right arm(7), right grip(1) |
|
| 87 |
+
| `tokenized_prompt` | `[2]` | `[task_id, stage_id]`; task 5 = `setting_mousetraps`, in the 100-task space |
|
| 88 |
+
|
| 89 |
+
DA3 fields — **you must add these** (see `code/da3_eval_inputs.py`):
|
| 90 |
+
|
| 91 |
+
| field | shape | notes |
|
| 92 |
+
|---|---|---|
|
| 93 |
+
| `da3_features` | `[B,4,3,1536,16,16]` **uint16** | bf16 *bits*, not floats. The model bitcasts them back. taps 19/27/33/39, 3 views, 16×16 patch grid |
|
| 94 |
+
| `da3_ray` | `[B,3,3,16,16]` f32 | unit camera rays through exact patch centres, from the intrinsics |
|
| 95 |
+
| `da3_depth` | `[B,3,1,16,16]` f32 | metric **metres**, area-averaged over each patch's 14×14 pixel footprint |
|
| 96 |
+
| `camera_extrinsics` | `[B,3,4,4]` f32 | robot→cam OpenCV, from `pose7_to_robot2cam` |
|
| 97 |
+
| `lang_feat` / `lang_mask` | `[B,32,1024]` / `[B,32]` | ModernBERT features for the task string, from the pickle |
|
| 98 |
+
|
| 99 |
+
View order is fixed everywhere: **head, left wrist, right wrist**. Depth must be *simulator/GT* depth
|
| 100 |
+
at native camera resolution before the 16×16 area-average — the model was never trained on DA3's own
|
| 101 |
+
predicted depth (`DA3_BACKBONE_ONLY=1` skips that head entirely). **Enable `depth_linear` on all three
|
| 102 |
+
cameras in your OmniGibson env config**; without it this checkpoint cannot be evaluated faithfully.
|
| 103 |
+
|
| 104 |
+
Intrinsics are derived, not measured: `fx = fy = (17.0/20.995) · 224`, `cx = cy = 112`.
|
| 105 |
+
|
| 106 |
+
## 4. Output and how to decode it
|
| 107 |
+
|
| 108 |
+
The model returns an action chunk of shape `[B, 30, 32]` in **normalized** space:
|
| 109 |
+
|
| 110 |
+
1. Only the **first 23 dims are real**; 23–31 are padding and are unconstrained by the loss — discard them.
|
| 111 |
+
2. Unnormalize with `assets/.../norm_stats.json` (`actions` block). Training used quantile
|
| 112 |
+
normalization; use the same path the existing b1k eval wrapper uses — do not hand-roll it.
|
| 113 |
+
3. Field order matches the state: `base_qvel(3) | trunk(4) | left_arm(7) | left_gripper(1) | right_arm(7) | right_gripper(1)` = 23.
|
| 114 |
+
4. Gripper dims are normalized against `MAX_GRIPPER_WIDTH = 0.1`.
|
| 115 |
+
|
| 116 |
+
Sampling is flow-matching: `sample_actions(rng, obs, num_steps=10)` (10 denoising steps is what the
|
| 117 |
+
probes used; the trainer used 15 flow samples for the loss, which is unrelated). It returns
|
| 118 |
+
`(actions, subtask_logits)` — take `[0]`.
|
| 119 |
+
|
| 120 |
+
## 5. Minimal loading sketch
|
| 121 |
+
|
| 122 |
+
```python
|
| 123 |
+
config = build_config() # scripts/train_2026_da3_task5.py, with the env above set
|
| 124 |
+
model = config.model.create(jax.random.key(0))
|
| 125 |
+
loaded = config.weight_loader.load(jax.tree.map(np.asarray, nnx.state(model).to_pure_dict()))
|
| 126 |
+
gd, st = nnx.split(model); st.replace_by_pure_dict(loaded); model = nnx.merge(gd, st)
|
| 127 |
+
|
| 128 |
+
raw = json.load(open(f"{ASSETS}/norm_stats.json"))["norm_stats"]["actions"]
|
| 129 |
+
model.load_correlation_matrix({"actions": {k: np.asarray(v, np.float32) if isinstance(v, list) else v
|
| 130 |
+
for k, v in raw.items()}})
|
| 131 |
+
```
|
| 132 |
+
Point `B1K_INIT_PARAMS` at this folder's `params/`. `config.weight_loader` is
|
| 133 |
+
`PiBehaviorWeightLoader`, which reads it directly.
|
| 134 |
+
|
| 135 |
+
Sanity check before trusting any eval number: run one batch and confirm the injection is live —
|
| 136 |
+
`model._compute_banks(obs)` must return a dict of three `[B,256,1024]` banks, **not None**. If it
|
| 137 |
+
returns None, `da3_features` didn't reach the model and you are evaluating a different model.
|
| 138 |
+
|
| 139 |
+
## 6. What changed vs DA3-#1 (context for interpreting results)
|
| 140 |
+
|
| 141 |
+
DA3-#1 was trained with `init_std=0.05`, no token centering, and the original merge wiring. Measured
|
| 142 |
+
problems, all fixed here:
|
| 143 |
+
|
| 144 |
+
- its bank was **71–80% a fixed DC vector** (the same vector for ~98% of samples), so the injection
|
| 145 |
+
attention had almost nothing to discriminate on;
|
| 146 |
+
- the injection had a **bank-free path** — `left_branch`/`right_branch`/`merge_proj` composed into a
|
| 147 |
+
learned linear map of the action stream that never touched the geometry, so ablating the branch
|
| 148 |
+
looked catastrophic while shuffling the geometry looked free;
|
| 149 |
+
- the 0.05 init multiplied the residual stream by ~2× at step 0, costing ~7–8k steps of repair.
|
| 150 |
+
|
| 151 |
+
At checkpoint 10000 of this run, shuffling geometry across the batch costs **3× more** than removing
|
| 152 |
+
the injection entirely (+2.30% vs +0.78%) — i.e. the model reads per-sample geometry, and giving it
|
| 153 |
+
the *wrong* scene is worse than giving it none. That is the property that makes correct DA3 inputs at
|
| 154 |
+
eval time matter.
|
T5-DA3-#2/code/b1k_code.tgz
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:3b7d355b1c1ae58974f9b6b5a3226099742bad7f3a8361baa8daf0505ecdab34
|
| 3 |
+
size 306781
|
T5-DA3-#2/code/b1k_support.tgz
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:7c2ee4d9227042448097ba134143803a97e047696b86e80df1add41f20a33d26
|
| 3 |
+
size 6113864
|
T5-DA3-#2/code/da3_eval_inputs.py
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Build the DA3 observation fields at EVAL time for T5-DA3-#2.
|
| 2 |
+
|
| 3 |
+
The stock b1k serving path (`scripts/serve_b1k.py` -> `b1k.shared.eval_b1k_wrapper`) has NO DA3
|
| 4 |
+
support: `grep -r da3 src/b1k/policies src/b1k/shared` is empty. If you run this checkpoint through
|
| 5 |
+
it unchanged, `observation.da3_features` is None, `PiBehavior._compute_banks` returns None, and the
|
| 6 |
+
spatial injection is skipped **silently** -- you get a degraded policy and no error. This module
|
| 7 |
+
fills that gap by reproducing the training-time inputs exactly.
|
| 8 |
+
|
| 9 |
+
Use:
|
| 10 |
+
|
| 11 |
+
from da3_eval_inputs import DA3EvalInputs
|
| 12 |
+
da3 = DA3EvalInputs(lang_cache="support/behavior1k/modernbert_b1k_tasks.pkl",
|
| 13 |
+
task_name="setting_mousetraps", device="cuda:0")
|
| 14 |
+
|
| 15 |
+
extra = da3(rgb224=[head, left_wrist, right_wrist], # 3x [224,224,3] uint8, VIEW_ORDER
|
| 16 |
+
depth_m=[d_head, d_left, d_right], # 3x [H,W] float32 METRES, native res
|
| 17 |
+
pose7=[p_head, p_left, p_right]) # 3x [7] cam-in-robot, [xyz, quat wxyz]
|
| 18 |
+
# -> dict with da3_features, da3_ray, da3_depth, camera_extrinsics, lang_feat, lang_mask
|
| 19 |
+
# merge into the Observation you pass to the policy (batch axis added for you).
|
| 20 |
+
|
| 21 |
+
Order is fixed: head (zed), left wrist (left realsense), right wrist (right realsense). Getting it
|
| 22 |
+
wrong silently mispairs geometry with pixels.
|
| 23 |
+
"""
|
| 24 |
+
from __future__ import annotations
|
| 25 |
+
|
| 26 |
+
import pickle
|
| 27 |
+
|
| 28 |
+
import numpy as np
|
| 29 |
+
|
| 30 |
+
FOCAL_RATIO = 17.0 / 20.995 # OmniGibson VisionSensor default; fx = fy = FOCAL_RATIO * width
|
| 31 |
+
GRID = 16 # 224 / patch 14
|
| 32 |
+
DA3_HW = (224, 224)
|
| 33 |
+
OUT_LAYERS = (19, 27, 33, 39)
|
| 34 |
+
MODEL_NAME = "depth-anything/DA3-GIANT-1.1"
|
| 35 |
+
|
| 36 |
+
|
| 37 |
+
class DA3EvalInputs:
|
| 38 |
+
def __init__(self, lang_cache: str, task_name: str, device: str = "cuda:0",
|
| 39 |
+
model_name: str = MODEL_NAME, forward_chunk: int = 8):
|
| 40 |
+
from b1k.training.da3_extractor import DA3InlineExtractor
|
| 41 |
+
|
| 42 |
+
self.ex = DA3InlineExtractor(
|
| 43 |
+
model_name=model_name, out_layers=OUT_LAYERS, da3_hw=DA3_HW,
|
| 44 |
+
devices=[device], forward_chunk=forward_chunk,
|
| 45 |
+
backbone_only=True, # DA3's own depth head is unused: we feed GT/sim depth
|
| 46 |
+
out_views=3, # only the current frame's 3 cameras are read out
|
| 47 |
+
)
|
| 48 |
+
with open(lang_cache, "rb") as f:
|
| 49 |
+
lang = pickle.load(f)
|
| 50 |
+
feat, mask = lang[task_name]
|
| 51 |
+
self.lang_feat = np.asarray(feat, np.float32)
|
| 52 |
+
self.lang_mask = np.asarray(mask, bool)
|
| 53 |
+
k = np.array([[FOCAL_RATIO * DA3_HW[1], 0.0, DA3_HW[1] / 2.0],
|
| 54 |
+
[0.0, FOCAL_RATIO * DA3_HW[0], DA3_HW[0] / 2.0],
|
| 55 |
+
[0.0, 0.0, 1.0]], np.float32)
|
| 56 |
+
self.intr = np.tile(k, (3, 1, 1))
|
| 57 |
+
|
| 58 |
+
@staticmethod
|
| 59 |
+
def _depth_grid(depth_m: np.ndarray) -> np.ndarray:
|
| 60 |
+
"""Native metric depth -> [1,16,16], area-averaged over each patch's pixel footprint.
|
| 61 |
+
|
| 62 |
+
INTER_AREA is a box mean, matching training (`b1k_da3._decode_gt_depth`). Depth and RGB share
|
| 63 |
+
the camera raster and FOV, so cell (i,j) covers exactly the pixels of patch token (i,j).
|
| 64 |
+
"""
|
| 65 |
+
import cv2
|
| 66 |
+
d = np.asarray(depth_m, np.float32)
|
| 67 |
+
if d.ndim == 3:
|
| 68 |
+
d = d[..., 0]
|
| 69 |
+
return cv2.resize(d, (GRID, GRID), interpolation=cv2.INTER_AREA)[None]
|
| 70 |
+
|
| 71 |
+
def __call__(self, rgb224, depth_m, pose7) -> dict:
|
| 72 |
+
from b1k.training.b1k_da3 import pose7_to_robot2cam
|
| 73 |
+
|
| 74 |
+
assert len(rgb224) == len(depth_m) == len(pose7) == 3, "expect 3 views in VIEW_ORDER"
|
| 75 |
+
imgs = np.stack([np.asarray(x, np.uint8) for x in rgb224], 0) # [3,224,224,3]
|
| 76 |
+
assert imgs.shape[1:3] == DA3_HW, f"pass the SAME 224x224 images the VLM gets, got {imgs.shape}"
|
| 77 |
+
extr = np.stack([pose7_to_robot2cam(np.asarray(p, np.float32)) for p in pose7], 0) # [3,4,4]
|
| 78 |
+
depth = np.stack([self._depth_grid(d) for d in depth_m], 0).astype(np.float32) # [3,1,16,16]
|
| 79 |
+
|
| 80 |
+
feats, ray, _ = self.ex.extract(imgs[None], extr[None], self.intr[None])
|
| 81 |
+
return {
|
| 82 |
+
"da3_features": feats, # uint16 = bf16 BITS, [1,4,3,1536,16,16]
|
| 83 |
+
"da3_ray": np.asarray(ray, np.float32), # [1,3,3,16,16] unit rays at patch centres
|
| 84 |
+
"da3_depth": depth[None], # [1,3,1,16,16] metric metres
|
| 85 |
+
"camera_extrinsics": extr[None], # [1,3,4,4] robot->cam OpenCV
|
| 86 |
+
"lang_feat": self.lang_feat[None], # [1,32,1024] ModernBERT, per task
|
| 87 |
+
"lang_mask": self.lang_mask[None], # [1,32]
|
| 88 |
+
}
|
T5-DA3-#2/code/da3_geostack.tgz
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:48fade1ccebe10f2195530702eb259b6fc843e0e16be4ea87fc9aba87577e5a2
|
| 3 |
+
size 9022
|