Mask Generation
sam2
English
OpenRAL
rskill
segmenter
promptable-segmentation
any
attachment-evidence
grasped-object
Instructions to use OpenRAL/rskill-sam2_1-any-grasped_object_mask-bf16 with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- sam2
How to use OpenRAL/rskill-sam2_1-any-grasped_object_mask-bf16 with sam2:
# Use SAM2 with images import torch from sam2.sam2_image_predictor import SAM2ImagePredictor predictor = SAM2ImagePredictor.from_pretrained("OpenRAL/rskill-sam2_1-any-grasped_object_mask-bf16") with torch.inference_mode(), torch.autocast("cuda", dtype=torch.bfloat16): predictor.set_image(<your_image>) masks, _, _ = predictor.predict(<input_prompts>)# Use SAM2 with videos import torch from sam2.sam2_video_predictor import SAM2VideoPredictor predictor = SAM2VideoPredictor.from_pretrained("OpenRAL/rskill-sam2_1-any-grasped_object_mask-bf16") with torch.inference_mode(), torch.autocast("cuda", dtype=torch.bfloat16): state = predictor.init_state(<your_video>) # add new prompts and instantly get the output on the same frame frame_idx, object_ids, masks = predictor.add_new_points(state, <your_prompts>) # propagate the prompts to get masklets throughout the video for frame_idx, object_ids, masks in predictor.propagate_in_video(state): ... - Notebooks
- Google Colab
- Kaggle
docs: HF model card for OpenRAL/rskill-sam2_1-any-grasped_object_mask-bf16 v0.1.0
Browse files
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 |
+
|  |  |
|
| 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.
|