AdrianLlopart commited on
Commit
2c919d6
·
verified ·
1 Parent(s): bb7601a

docs: HF model card for OpenRAL/rskill-sam2_1-any-grasped_object_mask-bf16 v0.1.0

Browse files
Files changed (1) hide show
  1. README.md +262 -0
README.md ADDED
@@ -0,0 +1,262 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ language:
3
+ - en
4
+ license: apache-2.0
5
+ pipeline_tag: mask-generation
6
+ tags:
7
+ - OpenRAL
8
+ - rskill
9
+ - segmenter
10
+ - mask-generation
11
+ - promptable-segmentation
12
+ - any
13
+ - sam2
14
+ - attachment-evidence
15
+ - grasped-object
16
+ inference: false
17
+ base_model:
18
+ - facebook/sam2.1-hiera-small
19
+ ---
20
+
21
+ # rskill-sam2_1-any-grasped_object_mask-bf16
22
+
23
+ > **OpenRAL rSkill** — SAM 2.1 (Hiera-small) packaged as an Apache-2.0
24
+ > **promptable segmenter** (`kind: segmenter`). It answers one geometric
25
+ > question — "which pixels of this wrist frame belong to the object in the
26
+ > jaws?" — so the HAL's vision attachment-evidence producer can bound a grasped
27
+ > payload from real depth instead of simulator ground truth. One shot per
28
+ > attach / detach / regrasp event. **No actuators.**
29
+
30
+ This package wraps `hf://facebook/sam2.1-hiera-small` with a `rskill.yaml`
31
+ manifest that adds capability checking, license surfacing, latency budgets, and
32
+ local registry integration. It does **not** copy model weights.
33
+
34
+ ## Preview
35
+
36
+ Real model output on two real in-tree frames (not synthetic), rendered by the
37
+ same CPU inference path the tests run. Yellow ring = the point prompt; tint =
38
+ the model's own best-scoring mask.
39
+
40
+ | Wrist view — good case | Third-person view — the failure case |
41
+ | :---: | :---: |
42
+ | ![wrist](media/wrist_eraser_mask.png) | ![front](media/front_tablecloth_mask.png) |
43
+ | score **0.842**, 5.4% of frame — isolates the eraser, excludes the jaws | score **0.978**, 59.8% of frame — the entire tablecloth |
44
+
45
+ The right-hand frame is why nothing downstream is allowed to trust the model's
46
+ confidence. See [Quality probe](#quality-probe--and-the-result-that-drives-the-safety-design).
47
+
48
+ ## What this skill does
49
+
50
+ Given a camera frame and a **point** in it, returns the binary mask of whatever
51
+ object that point lands on. There is no label vocabulary and no class: the skill
52
+ never says *what* the pixels are, only *which* pixels belong to the prompted
53
+ thing.
54
+
55
+ Its consumer is the HAL's vision attachment-evidence producer. At a grasp event
56
+ the producer projects the tool center point into the wrist camera, asks this
57
+ skill for the mask, intersects the mask with the same frame's depth channel, and
58
+ fits the ≤16 bounded primitives of an `AttachedCollisionObject` so the safety
59
+ kernel plans around the carried payload. It replaces MuJoCo introspection, which
60
+ gives perfect answers in simulation and does not exist on real hardware.
61
+
62
+ | Field | Value |
63
+ | --- | --- |
64
+ | Actions | `detect` |
65
+ | Objects | grasped object (whatever is in the jaws — no vocabulary) |
66
+ | Scenes | tabletop, kitchen, indoor, household |
67
+ | Embodiment | embodiment-agnostic (any wrist RGB camera ≥ 320×240) |
68
+
69
+ ## How it works
70
+
71
+ SAM 2.1 is a first-class `transformers` architecture (`Sam2Model` +
72
+ `Sam2Processor`), so it runs **in-process** via the
73
+ [`Sam2Segmenter`](../../python/runner/src/openral_runner/backends/gstreamer/sam2_segmenter.py)
74
+ backend (`engine: sam2_hf`) — no sidecar venv, no ZMQ, no quantization beyond
75
+ the bf16 compute dtype. The HAL stays torch-free and reaches it over the
76
+ `openral_msgs/srv/SegmentInView` service.
77
+
78
+ The prompt crosses that service boundary as a **3-D point**, not a pixel, so
79
+ camera intrinsics stay entirely on the perception side. The masks come back as
80
+ raw `mono8` `sensor_msgs/Image[]` — see the `.srv` header for why raw and not
81
+ run-length encoded.
82
+
83
+ `multimask: true` returns SAM 2's three nested hypotheses (subpart / part /
84
+ whole), and **all** of them cross the service boundary. This skill deliberately
85
+ does **not** pick between them: it has no depth, and only geometry — containment
86
+ between the jaws, payload extent, depth validity — can say which hypothesis is
87
+ the payload. The backend orders them by **area ascending** and the HAL producer,
88
+ which holds the wrist depth frame, selects among them.
89
+
90
+ ### Observation → mask contract
91
+
92
+ | Direction | Key | Shape | Notes |
93
+ | --- | --- | --- | --- |
94
+ | in | wrist RGB camera | `(H, W, 3)` BGR `uint8` | latest frame; min 320×240 |
95
+ | in | prompt point(s) | `(u, v)` pixels | positive at the TCP; optional negatives at the jaw tips |
96
+ | out | masks | ≤3 × `(H, W)` bool | at the source frame's own resolution, area ascending |
97
+ | out | `mask_scores_advisory` | float, one per mask | recorded in the trace, **never** thresholded or used to select |
98
+
99
+ ## Measured numbers
100
+
101
+ Measured on an **RTX 4070 Laptop 8 GB** (transformers 5.5.4, torch 2.9.1+cu128,
102
+ bf16, 512² input, ~3.5 GiB already resident from a co-loaded VLA), by
103
+ `torch.cuda.max_memory_allocated` deltas against a pre-load baseline:
104
+
105
+ | Metric | SAM 2.1 hiera-small | (SAM 3, for comparison) |
106
+ | --- | --- | --- |
107
+ | Weights | **74 MiB** | 1645 MiB |
108
+ | Peak allocated | **297 MiB** | 2037 MiB |
109
+ | Torch reserved | 448 MiB | 2262 MiB |
110
+ | Warm median | **53 ms** | 418 ms |
111
+ | First call (cold) | 742 ms | 970 ms |
112
+
113
+ Latency is **flat across input resolution** (46–52 ms from 224² to 1024²)
114
+ because `Sam2Processor` always resizes to 1024² internally. Wrist camera
115
+ resolution is not a lever for this model.
116
+
117
+ At 297 MiB the segmenter co-resides trivially with a ~3.5 GiB VLA and a
118
+ simulator on an 8 GB card, so it is held resident and warmed at node activate
119
+ rather than loaded on demand — the 742 ms first call would not fit inside the
120
+ HAL's ~100 ms deferred-ack barrier, but the 53 ms warm call fits with room to
121
+ spare.
122
+
123
+ ### Quality probe — and the result that drives the safety design
124
+
125
+ Two real in-tree frames, prompted with a point at `(0.52·W, 0.68·H)` (a stand-in
126
+ for the projected TCP):
127
+
128
+ | Frame | Best-candidate IoU score | Mask coverage | Verdict |
129
+ | --- | --- | --- | --- |
130
+ | SO-101 wrist, holding an eraser (320×240) | 0.842 | 5.4% of frame | cleanly isolates the eraser, **excludes the jaws** |
131
+ | SO-101 third-person, fruit scene (640×480) | **0.978** | **59.8% of frame** | essentially the entire tablecloth |
132
+
133
+ The second row is the load-bearing finding for this whole package. A mis-aimed
134
+ or out-of-context point prompt returned a mask covering most of the image at the
135
+ model's **highest** confidence. The model's own score cannot detect that it is
136
+ wrong.
137
+
138
+ **Therefore every fail-closed gate in the consumer is geometric** — containment
139
+ between the jaws, a payload extent cap, a depth-validity fraction — and **never**
140
+ the mask score. `mask_scores_advisory` is named to say so. Both frames are
141
+ regression-tested in `tests/unit/test_vision_attachment_evidence.py`.
142
+
143
+ ## Upstream model and training
144
+
145
+ A thin wrapper around the upstream Apache-2.0 SAM 2.1 checkpoint; weights live
146
+ upstream and are not copied here.
147
+
148
+ | Field | Value |
149
+ | --- | --- |
150
+ | Source repo | [`facebook/sam2.1-hiera-small`](https://huggingface.co/facebook/sam2.1-hiera-small) |
151
+ | Base model | SAM 2.1, Hiera-small backbone |
152
+ | Paper | [arxiv:2408.00714](https://arxiv.org/abs/2408.00714) — *SAM 2: Segment Anything in Images and Videos* |
153
+ | License | apache-2.0 (commercial use permitted) |
154
+ | Parameters | ~46 M |
155
+ | Training data | upstream: SA-V and the SAM 2 training mixture per the Meta release |
156
+
157
+ The checkpoint's config declares `sam2_video`; loading it into the image-only
158
+ `Sam2Model` is the supported subset path and emits a `transformers` notice to
159
+ that effect. The image path is all this rSkill uses — there is no video/tracker
160
+ state, because segmentation is one-shot at an event, not a per-frame track.
161
+
162
+ ## Supported robots
163
+
164
+ Embodiment-agnostic — the only requirement is a wrist RGB camera. The consumer
165
+ additionally needs registered depth on the same frame, but that is the HAL
166
+ producer's requirement, not this model's.
167
+
168
+ | Robot | Embodiment tag | Status | Notes |
169
+ | --- | --- | --- | --- |
170
+ | any with a wrist RGB-D camera | `any` | ⚡ experimental | validated against SO-101 wrist frames |
171
+
172
+ ## Sensors required
173
+
174
+ Mirrors `rskill.yaml::sensors_required`.
175
+
176
+ | Key | Modality | Min resolution | Format |
177
+ | --- | --- | --- | --- |
178
+ | wrist RGB camera | RGB | 320 × 240 | `uint8` BGR frame |
179
+
180
+ ## Manifest summary
181
+
182
+ | Field | Value |
183
+ | --- | --- |
184
+ | `name` | `OpenRAL/rskill-sam2_1-any-grasped_object_mask-bf16` |
185
+ | `version` | `0.1.0` |
186
+ | `license` | `apache-2.0` |
187
+ | `role` / `kind` | `s1` / `segmenter` |
188
+ | `runtime` / `quantization.dtype` | `pytorch` / `bf16` |
189
+ | `segmenter.engine` | `sam2_hf` |
190
+ | `segmenter.multimask` / `max_prompt_points` / `min_mask_area_px` | `true` / `8` / `64` |
191
+ | `weights_uri` | `hf://facebook/sam2.1-hiera-small` |
192
+ | `latency_budget.per_chunk_ms` | 100 ms (measured warm: 53 ms) |
193
+ | `commercial_use_allowed` | yes (Apache-2.0 weights) |
194
+
195
+ Full schema: [`openral_core.schemas.RSkillManifest`](../../python/core/src/openral_core/schemas.py).
196
+
197
+ ## Quick start
198
+
199
+ ```bash
200
+ just sync --group sam2 # torch + transformers + pillow for the in-process backend
201
+ ```
202
+
203
+ ```python
204
+ from openral_core.schemas import RSkillManifest, SegmenterEngine
205
+
206
+ manifest = RSkillManifest.from_yaml(
207
+ "rskills/rskill-sam2_1-any-grasped_object_mask-bf16/rskill.yaml"
208
+ )
209
+ assert manifest.segmenter.engine is SegmenterEngine.SAM2_HF
210
+ ```
211
+
212
+ ## Reproduction
213
+
214
+ Packaging-only wrapper — no trained numbers to reproduce. The measured latency
215
+ and VRAM figures above need the reference GPU; the quality probe and the
216
+ geometric-gate regressions run on CPU:
217
+
218
+ ```bash
219
+ just sync --group sam2
220
+ uv run pytest tests/unit/test_sam2_segmenter.py tests/unit/test_vision_attachment_evidence.py
221
+ ```
222
+
223
+ ## Evaluation
224
+
225
+ No benchmarks shipped — packaging-only wrapper; a promptable segmenter has no
226
+ task success rate. The quality probe above is the honest substitute.
227
+
228
+ ## Known limitations
229
+
230
+ Inherited from the design and **not** fixed by this skill:
231
+
232
+ - **Articulated objects.** Vision gives geometry, not kinematic class. A drawer
233
+ handle would mask as a free box. The consumer is scoped to free objects.
234
+ - **Transparent / thin objects.** Expected to fail the consumer's
235
+ depth-validity gate and degrade to the conservative fallback box.
236
+ - **Self-occlusion.** The far side of the object is never observed; only
237
+ partially mitigated by the consumer's view-ray inflation margin.
238
+ - **Mass / centre of mass / inertia.** Not estimable from vision; they stay
239
+ `None` on real hardware, unlike the simulator producer.
240
+ - **Deformable objects and multi-object grasps.** Not addressed — a single
241
+ positive point means a single object.
242
+ - **Support contact.** This skill establishes what is *attached*, never what is
243
+ *resting on* something.
244
+
245
+ ## License
246
+
247
+ This rSkill package (`rskill.yaml`, `README.md`) is **apache-2.0**. The wrapped
248
+ weights at `hf://facebook/sam2.1-hiera-small` are also **apache-2.0**, so the
249
+ segmenter is fully commercial-safe (CLAUDE.md §1.9).
250
+
251
+ ## See also
252
+
253
+ - [`packages/msgs/srv/SegmentInView.srv`](../../packages/msgs/srv/SegmentInView.srv)
254
+ — the typed HAL↔segmenter boundary, with the mono8-vs-RLE rationale.
255
+ - [`python/hal/src/openral_hal/_vision_attachment_evidence.py`](../../python/hal/src/openral_hal/_vision_attachment_evidence.py)
256
+ — the consumer: geometric gates, primitive fit, and the conservative fallback.
257
+ - [`python/hal/src/openral_hal/_sim_attachment_evidence.py`](../../python/hal/src/openral_hal/_sim_attachment_evidence.py)
258
+ — the simulator counterpart this transfers to real hardware, emitting the
259
+ identical `AttachedCollisionObject` contract.
260
+ - [`rskills/omdet-turbo-locator/`](../omdet-turbo-locator/) — the *semantic*
261
+ perception sibling ("find object X"), for contrast.
262
+ - [CLAUDE.md §6.4](../../CLAUDE.md) — rSkill packaging contract.