flockgo commited on
Commit
5076c35
·
verified ·
1 Parent(s): 92a5d1d

Upload folder using huggingface_hub

Browse files
README.md ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ Self-contained SigLIP2-base Robotics VLA policy for task 23.
2
+ The adapter loads only the bundled local backbone and action head.
action_head.pt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:30acb580f4bb5273216286eecb0ad380fb52a037c14e4a0df36988969a51f932
3
+ size 2878413
backbone/config.json ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "architectures": [
3
+ "Siglip2Model"
4
+ ],
5
+ "initializer_factor": 1.0,
6
+ "model_type": "siglip2",
7
+ "text_config": {
8
+ "model_type": "siglip2_text_model",
9
+ "vocab_size": 256000
10
+ },
11
+ "torch_dtype": "float32",
12
+ "transformers_version": "4.49.0.dev0",
13
+ "vision_config": {
14
+ "model_type": "siglip2_vision_model"
15
+ }
16
+ }
backbone/model.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:ac5f28bbdf92c0c1696ccbd3ce716426049cd67ad8045b66d0d938b0f9c8bbec
3
+ size 1500985224
backbone/preprocessor_config.json ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "do_convert_rgb": null,
3
+ "do_normalize": true,
4
+ "do_rescale": true,
5
+ "do_resize": true,
6
+ "image_mean": [
7
+ 0.5,
8
+ 0.5,
9
+ 0.5
10
+ ],
11
+ "image_processor_type": "Siglip2ImageProcessorFast",
12
+ "image_std": [
13
+ 0.5,
14
+ 0.5,
15
+ 0.5
16
+ ],
17
+ "max_num_patches": 256,
18
+ "patch_size": 16,
19
+ "processor_class": "Siglip2Processor",
20
+ "resample": 2,
21
+ "rescale_factor": 0.00392156862745098
22
+ }
flock_robotics_adapter.py ADDED
@@ -0,0 +1,119 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from __future__ import annotations
2
+ import hashlib
3
+ import json
4
+ import math
5
+ import re
6
+ from pathlib import Path
7
+ import numpy as np
8
+ import torch
9
+ import torch.nn as nn
10
+
11
+ class SigLIPActionHead(nn.Module):
12
+ def __init__(self, config):
13
+ super().__init__()
14
+ self.chunk = int(config["chunk"])
15
+ self.proprio = nn.Sequential(nn.Linear(32, 128), nn.LayerNorm(128), nn.SiLU())
16
+ self.text = nn.Sequential(nn.Linear(128, 128), nn.LayerNorm(128), nn.SiLU())
17
+ self.task = nn.Embedding(int(config["task_count"]), 32)
18
+ self.difficulty = nn.Embedding(int(config["difficulty_count"]), 16)
19
+ self.head = nn.Sequential(
20
+ nn.Linear(768 + 128 + 128 + 32 + 16, 512),
21
+ nn.LayerNorm(512), nn.SiLU(), nn.Dropout(0.10),
22
+ nn.Linear(512, 256), nn.SiLU(), nn.Linear(256, self.chunk * 7)
23
+ )
24
+ def forward(self, features, proprio, text, task_id, difficulty_id):
25
+ fused = torch.cat([
26
+ features.float(), self.proprio(proprio.float()), self.text(text.float()),
27
+ self.task(task_id.clamp(0, self.task.num_embeddings - 1)),
28
+ self.difficulty(difficulty_id.clamp(0, self.difficulty.num_embeddings - 1)),
29
+ ], dim=-1)
30
+ return torch.tanh(self.head(fused)).reshape(-1, self.chunk, 7)
31
+
32
+ def _text_vector(text, dim):
33
+ result = np.zeros(dim, dtype=np.float32)
34
+ for token in re.findall(r"[a-z0-9_]+", str(text).lower()):
35
+ value = int.from_bytes(hashlib.blake2b(token.encode("utf-8"), digest_size=8).digest(), "little")
36
+ result[value % dim] += 1.0 if value & 1 else -1.0
37
+ norm = float(np.linalg.norm(result))
38
+ return result / norm if norm else result
39
+
40
+ def _proprio(obs, config):
41
+ value = np.asarray(obs.get("proprio", np.zeros(25, dtype=np.float32)), dtype=np.float32).reshape(-1)
42
+ if value.size == 21:
43
+ value = np.pad(value, (0, 4))
44
+ if value.size != 25:
45
+ raise ValueError(f"proprio must have 25 values, got {value.size}")
46
+ step = float(obs.get("step", 0))
47
+ horizon = float(obs.get("horizon", 320) or 320)
48
+ value = np.concatenate([value, np.asarray([step / max(horizon, 1.0)], dtype=np.float32)])
49
+ value = np.pad(value, (0, max(0, int(config["proprio_dim"]) - value.size)))
50
+ value = value[: int(config["proprio_dim"])]
51
+ mean = np.asarray(config["proprio_mean"], dtype=np.float32)
52
+ std = np.asarray(config["proprio_std"], dtype=np.float32)
53
+ return ((value - mean) / np.maximum(std, 1e-4)).astype(np.float32)
54
+
55
+ class Policy:
56
+ def __init__(self, backbone, processor, head, config, device):
57
+ self.backbone, self.processor = backbone, processor
58
+ self.head, self.config, self.device = head, config, device
59
+ self.chunk = int(config["chunk"])
60
+ self.last_step, self.last_action = None, np.zeros(7, dtype=np.float32)
61
+ self.chunks = {}
62
+ self.task_to_id, self.difficulty_to_id = config["task_to_id"], config["difficulty_to_id"]
63
+ @torch.inference_mode()
64
+ def act(self, obs):
65
+ image = np.asarray(obs.get("image", np.zeros((224, 224, 3), dtype=np.uint8)))
66
+ if image.ndim == 2:
67
+ image = np.repeat(image[..., None], 3, axis=-1)
68
+ if image.shape[-1] == 4:
69
+ image = image[..., :3]
70
+ if image.shape[-1] != 3:
71
+ raise ValueError("image must have 3 or 4 channels")
72
+ step = int(obs.get("step", 0))
73
+ if self.last_step is None or step == 0 or step != self.last_step + 1:
74
+ self.chunks = {}
75
+ if step == self.last_step:
76
+ return self.last_action.copy()
77
+ inputs = self.processor(images=image, return_tensors="pt")
78
+ inputs = {key: value.to(self.device) for key, value in inputs.items()}
79
+ result = self.backbone.get_image_features(**inputs)
80
+ features = result.pooler_output if hasattr(result, "pooler_output") else result.last_hidden_state.mean(dim=1)
81
+ task = str(obs.get("task", ""))
82
+ difficulty = str(obs.get("difficulty", "") or "")
83
+ text = f"task {task} difficulty {difficulty} instruction {obs.get('instruction', '')}"
84
+ raw = self.head(
85
+ features, torch.from_numpy(_proprio(obs, self.config)).unsqueeze(0).to(self.device),
86
+ torch.from_numpy(_text_vector(text, 128)).unsqueeze(0).to(self.device),
87
+ torch.tensor([self.task_to_id.get(task, len(self.task_to_id))], device=self.device),
88
+ torch.tensor([self.difficulty_to_id.get(difficulty, len(self.difficulty_to_id))], device=self.device),
89
+ )[0].float().cpu().numpy()
90
+ self.chunks[step] = raw
91
+ candidates, weights = [], []
92
+ for start, chunk in list(self.chunks.items()):
93
+ offset = step - start
94
+ if 0 <= offset < self.chunk:
95
+ candidates.append(chunk[offset])
96
+ weights.append(math.exp(-0.55 * offset))
97
+ else:
98
+ del self.chunks[start]
99
+ action = np.average(np.asarray(candidates), axis=0, weights=np.asarray(weights))
100
+ action = np.clip(action, -1.0, 1.0).astype(np.float32)
101
+ if action[6] > 0.12:
102
+ action[6] = 1.0
103
+ elif action[6] < -0.12:
104
+ action[6] = -1.0
105
+ self.last_step, self.last_action = step, action.copy()
106
+ return action
107
+
108
+ def load_policy(model_dir: str, device: str, dtype: str):
109
+ from transformers import AutoImageProcessor, AutoModel
110
+ root = Path(model_dir)
111
+ config = json.loads((root / "vla_config.json").read_text())
112
+ selected = torch.device(device if str(device).startswith("cuda") and torch.cuda.is_available() else "cpu")
113
+ processor = AutoImageProcessor.from_pretrained(root / "backbone", local_files_only=True)
114
+ backbone = AutoModel.from_pretrained(root / "backbone", local_files_only=True).to(selected).eval()
115
+ head = SigLIPActionHead(config).to(selected)
116
+ state = torch.load(root / "action_head.pt", map_location=selected, weights_only=True)
117
+ head.load_state_dict(state["state_dict"], strict=True)
118
+ head.eval()
119
+ return Policy(backbone, processor, head, config, selected)
vla_config.json ADDED
@@ -0,0 +1,110 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "schema_version": "task23_siglip2_self_contained_v1",
3
+ "model_type": "siglip2_frozen_vision_action_chunk",
4
+ "backbone": "google/siglip2-base-patch16-naflex",
5
+ "chunk": 8,
6
+ "feature_dim": 768,
7
+ "text_dim": 128,
8
+ "proprio_dim": 32,
9
+ "task_count": 14,
10
+ "difficulty_count": 5,
11
+ "proprio_mean": [
12
+ -0.01592460460960865,
13
+ 0.7428314685821533,
14
+ 0.010429546236991882,
15
+ -1.932236671447754,
16
+ 0.024123214185237885,
17
+ 2.8178389072418213,
18
+ 0.7557806372642517,
19
+ 0.02269606851041317,
20
+ 0.05282147601246834,
21
+ 0.00876456405967474,
22
+ 0.07294361293315887,
23
+ -0.021329032257199287,
24
+ -0.015278438106179237,
25
+ 0.04549413174390793,
26
+ 0.07919428497552872,
27
+ -0.06642947345972061,
28
+ 0.9300205707550049,
29
+ 0.9961889982223511,
30
+ -0.004495386034250259,
31
+ 0.0756562203168869,
32
+ -0.005136882420629263,
33
+ 0.03150780126452446,
34
+ -0.03062213398516178,
35
+ 0.0001331703970208764,
36
+ 3.20150975312572e-05,
37
+ 0.4979763627052307,
38
+ 0.0,
39
+ 0.0,
40
+ 0.0,
41
+ 0.0,
42
+ 0.0,
43
+ 0.0
44
+ ],
45
+ "proprio_std": [
46
+ 0.1833081692457199,
47
+ 0.2757302522659302,
48
+ 0.0830760970711708,
49
+ 0.40317803621292114,
50
+ 0.1892702728509903,
51
+ 0.21985791623592377,
52
+ 0.3677351772785187,
53
+ 0.09155969321727753,
54
+ 0.24703823029994965,
55
+ 0.07063839584589005,
56
+ 0.27435028553009033,
57
+ 0.12254507839679718,
58
+ 0.17527462542057037,
59
+ 0.2087806612253189,
60
+ 0.09155305474996567,
61
+ 0.16622483730316162,
62
+ 0.07347064465284348,
63
+ 0.004743508528918028,
64
+ 0.020507004112005234,
65
+ 0.03240346908569336,
66
+ 0.01718319021165371,
67
+ 0.00835738331079483,
68
+ 0.009069605730473995,
69
+ 0.014785450883209705,
70
+ 0.012382089160382748,
71
+ 0.2886733412742615,
72
+ 1.0,
73
+ 1.0,
74
+ 1.0,
75
+ 1.0,
76
+ 1.0,
77
+ 1.0
78
+ ],
79
+ "task_to_id": {
80
+ "lift_cube": 0,
81
+ "pick_place_can": 1,
82
+ "pick_place_milk": 2,
83
+ "pick_place_bread": 3,
84
+ "pick_place_cereal": 4,
85
+ "pick_place_clutter": 5,
86
+ "stack_blocks": 6,
87
+ "open_door": 7,
88
+ "nut_assembly": 8,
89
+ "nut_assembly_square": 9,
90
+ "nut_assembly_round": 10,
91
+ "wipe_table": 11,
92
+ "tool_hang": 12
93
+ },
94
+ "difficulty_to_id": {
95
+ "low": 0,
96
+ "medium": 1,
97
+ "hard": 2,
98
+ "very_high": 3
99
+ },
100
+ "local_files_only": true,
101
+ "adapter_inputs": [
102
+ "image",
103
+ "instruction",
104
+ "proprio",
105
+ "task",
106
+ "step",
107
+ "difficulty",
108
+ "horizon"
109
+ ]
110
+ }