lfhe commited on
Commit
17e2e27
·
verified ·
1 Parent(s): 1934d79
Files changed (5) hide show
  1. .gitattributes +1 -0
  2. flock_robotics_adapter.py +195 -0
  3. model.pt +3 -0
  4. training_report.json +167 -0
  5. vla_config.json +95 -0
.gitattributes ADDED
@@ -0,0 +1 @@
 
 
1
+ model.pt filter=lfs diff=lfs merge=lfs -text
flock_robotics_adapter.py ADDED
@@ -0,0 +1,195 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from __future__ import annotations
2
+
3
+ import hashlib
4
+ import json
5
+ import re
6
+ from pathlib import Path
7
+
8
+ import numpy as np
9
+ import torch
10
+ import torch.nn as nn
11
+ import torch.nn.functional as F
12
+
13
+
14
+ IMAGENET_MEAN = (0.485, 0.456, 0.406)
15
+ IMAGENET_STD = (0.229, 0.224, 0.225)
16
+
17
+
18
+ class EncoderVLAPolicyNet(nn.Module):
19
+ def __init__(
20
+ self,
21
+ encoder,
22
+ text_dim: int = 256,
23
+ proprio_dim: int = 32,
24
+ action_dim: int = 7,
25
+ image_size: int = 224,
26
+ vision_dim: int = 384,
27
+ modality_emb_dim: int = 256,
28
+ freeze_encoder: bool = True,
29
+ ):
30
+ super().__init__()
31
+ self.encoder = encoder
32
+ self.image_size = int(image_size)
33
+ self.freeze_encoder = bool(freeze_encoder)
34
+ if self.freeze_encoder:
35
+ for p in self.encoder.parameters():
36
+ p.requires_grad = False
37
+ self.vision_proj = nn.Sequential(
38
+ nn.Linear(vision_dim, 512),
39
+ nn.SiLU(),
40
+ nn.LayerNorm(512),
41
+ nn.Linear(512, 512),
42
+ nn.SiLU(),
43
+ )
44
+ self.proprio_encoder = nn.Sequential(
45
+ nn.Linear(proprio_dim, modality_emb_dim),
46
+ nn.SiLU(),
47
+ nn.LayerNorm(modality_emb_dim),
48
+ nn.Linear(modality_emb_dim, modality_emb_dim),
49
+ nn.SiLU(),
50
+ )
51
+ self.text_encoder = nn.Sequential(
52
+ nn.Linear(text_dim, modality_emb_dim),
53
+ nn.SiLU(),
54
+ nn.LayerNorm(modality_emb_dim),
55
+ nn.Linear(modality_emb_dim, modality_emb_dim),
56
+ nn.SiLU(),
57
+ )
58
+ fused = 512 + 2 * modality_emb_dim
59
+ self.action_head = nn.Sequential(
60
+ nn.Linear(fused, 1024),
61
+ nn.SiLU(),
62
+ nn.LayerNorm(1024),
63
+ nn.Dropout(0.05),
64
+ nn.Linear(1024, 512),
65
+ nn.SiLU(),
66
+ nn.LayerNorm(512),
67
+ nn.Linear(512, 256),
68
+ nn.SiLU(),
69
+ nn.Linear(256, action_dim),
70
+ nn.Tanh(),
71
+ )
72
+ self.register_buffer(
73
+ "img_mean",
74
+ torch.tensor(IMAGENET_MEAN, dtype=torch.float32).view(1, 3, 1, 1),
75
+ persistent=False,
76
+ )
77
+ self.register_buffer(
78
+ "img_std",
79
+ torch.tensor(IMAGENET_STD, dtype=torch.float32).view(1, 3, 1, 1),
80
+ persistent=False,
81
+ )
82
+
83
+ def _encode_images(self, images: torch.Tensor) -> torch.Tensor:
84
+ if images.ndim != 4:
85
+ raise ValueError(f"expected image batch [B,H,W,3] or [B,3,H,W], got {tuple(images.shape)}")
86
+ if images.shape[-1] == 3:
87
+ images = images.permute(0, 3, 1, 2)
88
+ images = images.float()
89
+ if images.max() > 2.0:
90
+ images = images / 255.0
91
+ target = (self.image_size, self.image_size)
92
+ if images.shape[-2:] != target:
93
+ images = F.interpolate(images, size=target, mode="bilinear", align_corners=False)
94
+ images = (images - self.img_mean) / self.img_std
95
+ if self.freeze_encoder:
96
+ with torch.no_grad():
97
+ out = self.encoder(pixel_values=images)
98
+ else:
99
+ out = self.encoder(pixel_values=images)
100
+ # CLS token
101
+ return out.last_hidden_state[:, 0]
102
+
103
+ def forward(self, images, proprio, text_features):
104
+ vision = self.vision_proj(self._encode_images(images))
105
+ proprio_emb = self.proprio_encoder(proprio.float())
106
+ text_emb = self.text_encoder(text_features.float())
107
+ return self.action_head(torch.cat([vision, proprio_emb, text_emb], dim=-1))
108
+
109
+
110
+ def _text_vector(text: str, dim: int) -> np.ndarray:
111
+ vec = np.zeros(dim, dtype=np.float32)
112
+ tokens = re.findall(r"[a-z0-9_]+", text.lower())
113
+ for token in tokens:
114
+ digest = hashlib.blake2b(token.encode("utf-8"), digest_size=8).digest()
115
+ value = int.from_bytes(digest, byteorder="little", signed=False)
116
+ vec[value % dim] += 1.0 if value & 1 else -1.0
117
+ norm = float(np.linalg.norm(vec))
118
+ if norm > 0:
119
+ vec /= norm
120
+ return vec
121
+
122
+
123
+ def _proprio_vector(obs: dict, dim: int) -> np.ndarray:
124
+ raw = np.asarray(obs.get("proprio", np.zeros(25, dtype=np.float32)), dtype=np.float32).reshape(-1)
125
+ step = float(obs.get("step", 0))
126
+ horizon = float(obs.get("horizon", 320) or 320)
127
+ step_feature = np.asarray([step / max(horizon, 1.0)], dtype=np.float32)
128
+ combined = np.concatenate([raw, step_feature], axis=0)
129
+ if combined.size < dim:
130
+ combined = np.pad(combined, (0, dim - combined.size))
131
+ return combined[:dim].astype(np.float32)
132
+
133
+
134
+ class EncoderVLAPolicy:
135
+ def __init__(self, model_dir: str, device: str, dtype: str):
136
+ from transformers import Dinov2Config, Dinov2Model
137
+
138
+ self.model_dir = Path(model_dir)
139
+ self.config = json.loads((self.model_dir / "vla_config.json").read_text())
140
+ if device == "cuda" and torch.cuda.is_available():
141
+ self.device = torch.device("cuda")
142
+ elif device == "mps" and hasattr(torch.backends, "mps") and torch.backends.mps.is_available():
143
+ self.device = torch.device("mps")
144
+ else:
145
+ self.device = torch.device("cpu")
146
+
147
+ enc_cfg = Dinov2Config.from_dict(self.config["encoder_config"])
148
+ encoder = Dinov2Model(enc_cfg)
149
+ image_size = self.config.get("image_size", [224, 224])
150
+ if isinstance(image_size, list):
151
+ image_size = int(image_size[0])
152
+ self.model = EncoderVLAPolicyNet(
153
+ encoder=encoder,
154
+ text_dim=int(self.config.get("text_dim", 256)),
155
+ proprio_dim=int(self.config.get("proprio_dim", 32)),
156
+ action_dim=int(self.config.get("action_dim", 7)),
157
+ image_size=int(image_size),
158
+ vision_dim=int(self.config.get("vision_dim", enc_cfg.hidden_size)),
159
+ modality_emb_dim=int(self.config.get("modality_emb_dim", 256)),
160
+ freeze_encoder=True,
161
+ ).to(self.device)
162
+ checkpoint = torch.load(self.model_dir / "model.pt", map_location=self.device, weights_only=True)
163
+ state_dict = checkpoint.get("state_dict", checkpoint)
164
+ self.model.load_state_dict(state_dict, strict=True)
165
+ self.model.eval()
166
+ for p in self.model.parameters():
167
+ p.requires_grad = False
168
+
169
+ def act(self, obs: dict) -> np.ndarray:
170
+ image_size = int(self.config.get("image_size", [224, 224])[0])
171
+ image = np.asarray(
172
+ obs.get("image", np.zeros((image_size, image_size, 3), dtype=np.uint8)),
173
+ dtype=np.uint8,
174
+ )
175
+ if image.ndim == 2:
176
+ image = np.repeat(image[..., None], 3, axis=-1)
177
+ if image.shape[-1] > 3:
178
+ image = image[..., :3]
179
+ task = str(obs.get("task", ""))
180
+ difficulty = str(obs.get("difficulty", ""))
181
+ instruction = str(obs.get("instruction", ""))
182
+ text = f"task {task} difficulty {difficulty} instruction {instruction}"
183
+ text_features = _text_vector(text, int(self.config.get("text_dim", 256)))
184
+ proprio = _proprio_vector(obs, int(self.config.get("proprio_dim", 32)))
185
+ with torch.no_grad():
186
+ action = self.model(
187
+ torch.from_numpy(image).unsqueeze(0).to(self.device),
188
+ torch.from_numpy(proprio).unsqueeze(0).to(self.device),
189
+ torch.from_numpy(text_features).unsqueeze(0).to(self.device),
190
+ )
191
+ return np.clip(action.squeeze(0).detach().cpu().numpy(), -1.0, 1.0).astype(np.float32)
192
+
193
+
194
+ def load_policy(model_dir: str, device: str, dtype: str):
195
+ return EncoderVLAPolicy(model_dir=model_dir, device=device, dtype=dtype)
model.pt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:8433d4893118995f0a3538134fe5faceb2ba2e8a9f5d0fa35df1b47581aba757
3
+ size 97821951
training_report.json ADDED
@@ -0,0 +1,167 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "samples": {
3
+ "trajectory_count": 103,
4
+ "loaded_frame_count": 25328,
5
+ "step_stride": 1,
6
+ "source": "random-sequence/flock-robotics-vla-training-v2"
7
+ },
8
+ "epochs": 25,
9
+ "batch_size": 64,
10
+ "learning_rate": 0.0003,
11
+ "weight_decay": 0.0001,
12
+ "device": "cuda",
13
+ "encoder_id": "facebook/dinov2-small",
14
+ "best_val_mse": 0.005434711876076663,
15
+ "history": [
16
+ {
17
+ "epoch": 1.0,
18
+ "train_mse": 0.052450973142346244,
19
+ "val_mse": 0.02464906360194864,
20
+ "lr": 0.0002988172051971717
21
+ },
22
+ {
23
+ "epoch": 2.0,
24
+ "train_mse": 0.015353698004698999,
25
+ "val_mse": 0.013575026146055304,
26
+ "lr": 0.0002952874741692947
27
+ },
28
+ {
29
+ "epoch": 3.0,
30
+ "train_mse": 0.012783010591259027,
31
+ "val_mse": 0.01241856964531621,
32
+ "lr": 0.0002894664728832377
33
+ },
34
+ {
35
+ "epoch": 4.0,
36
+ "train_mse": 0.010736383704168101,
37
+ "val_mse": 0.011335676267454738,
38
+ "lr": 0.00028144600200657956
39
+ },
40
+ {
41
+ "epoch": 5.0,
42
+ "train_mse": 0.0100194234388602,
43
+ "val_mse": 0.011257341734058625,
44
+ "lr": 0.00027135254915624217
45
+ },
46
+ {
47
+ "epoch": 6.0,
48
+ "train_mse": 0.009152803605718239,
49
+ "val_mse": 0.009612169949849847,
50
+ "lr": 0.0002593452941132118
51
+ },
52
+ {
53
+ "epoch": 7.0,
54
+ "train_mse": 0.00936236106123713,
55
+ "val_mse": 0.007432314051582962,
56
+ "lr": 0.00024561359846230347
57
+ },
58
+ {
59
+ "epoch": 8.0,
60
+ "train_mse": 0.008174229212043036,
61
+ "val_mse": 0.009825789436586142,
62
+ "lr": 0.0002303740192468495
63
+ },
64
+ {
65
+ "epoch": 9.0,
66
+ "train_mse": 0.008620002260551634,
67
+ "val_mse": 0.01041258188070491,
68
+ "lr": 0.0002138668937347609
69
+ },
70
+ {
71
+ "epoch": 10.0,
72
+ "train_mse": 0.007946362478426172,
73
+ "val_mse": 0.008026734568284587,
74
+ "lr": 0.0001963525491562421
75
+ },
76
+ {
77
+ "epoch": 11.0,
78
+ "train_mse": 0.007336850237303667,
79
+ "val_mse": 0.007538307731085432,
80
+ "lr": 0.00017810719718785873
81
+ },
82
+ {
83
+ "epoch": 12.0,
84
+ "train_mse": 0.00767612234281653,
85
+ "val_mse": 0.006661466446978822,
86
+ "lr": 0.00015941857792939703
87
+ },
88
+ {
89
+ "epoch": 13.0,
90
+ "train_mse": 0.00704610332234791,
91
+ "val_mse": 0.006911170980812155,
92
+ "lr": 0.00014058142207060302
93
+ },
94
+ {
95
+ "epoch": 14.0,
96
+ "train_mse": 0.006659559791542447,
97
+ "val_mse": 0.009048803709079564,
98
+ "lr": 0.00012189280281214133
99
+ },
100
+ {
101
+ "epoch": 15.0,
102
+ "train_mse": 0.006679477127921169,
103
+ "val_mse": 0.007556101494861581,
104
+ "lr": 0.00010364745084375795
105
+ },
106
+ {
107
+ "epoch": 16.0,
108
+ "train_mse": 0.006114454294127817,
109
+ "val_mse": 0.007176910378450843,
110
+ "lr": 8.61331062652391e-05
111
+ },
112
+ {
113
+ "epoch": 17.0,
114
+ "train_mse": 0.0062116264081053425,
115
+ "val_mse": 0.005434711876076663,
116
+ "lr": 6.962598075315047e-05
117
+ },
118
+ {
119
+ "epoch": 18.0,
120
+ "train_mse": 0.005705748372087895,
121
+ "val_mse": 0.006514828746489545,
122
+ "lr": 5.4386401537696536e-05
123
+ },
124
+ {
125
+ "epoch": 19.0,
126
+ "train_mse": 0.005474576261368675,
127
+ "val_mse": 0.005767398440657186,
128
+ "lr": 4.06547058867883e-05
129
+ },
130
+ {
131
+ "epoch": 20.0,
132
+ "train_mse": 0.0052186791698284486,
133
+ "val_mse": 0.006887162315010389,
134
+ "lr": 2.86474508437579e-05
135
+ },
136
+ {
137
+ "epoch": 21.0,
138
+ "train_mse": 0.004928951738128989,
139
+ "val_mse": 0.00600228262520844,
140
+ "lr": 1.8553997993420465e-05
141
+ },
142
+ {
143
+ "epoch": 22.0,
144
+ "train_mse": 0.004528539363558345,
145
+ "val_mse": 0.005473934499087845,
146
+ "lr": 1.05335271167623e-05
147
+ },
148
+ {
149
+ "epoch": 23.0,
150
+ "train_mse": 0.0043255689688378035,
151
+ "val_mse": 0.006198732651723034,
152
+ "lr": 4.712525830705356e-06
153
+ },
154
+ {
155
+ "epoch": 24.0,
156
+ "train_mse": 0.0040297096492367315,
157
+ "val_mse": 0.005554187416847895,
158
+ "lr": 1.1827948028283355e-06
159
+ },
160
+ {
161
+ "epoch": 25.0,
162
+ "train_mse": 0.0038712321390164763,
163
+ "val_mse": 0.005647414989951898,
164
+ "lr": 0.0
165
+ }
166
+ ]
167
+ }
vla_config.json ADDED
@@ -0,0 +1,95 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "schema_version": "robotics_vla_encoder_policy_v1",
3
+ "model_type": "dinov2_small_text_proprio_bc",
4
+ "encoder_id": "facebook/dinov2-small",
5
+ "encoder_config": {
6
+ "return_dict": true,
7
+ "output_hidden_states": false,
8
+ "dtype": "float32",
9
+ "chunk_size_feed_forward": 0,
10
+ "is_encoder_decoder": false,
11
+ "architectures": [
12
+ "Dinov2Model"
13
+ ],
14
+ "id2label": {
15
+ "0": "LABEL_0",
16
+ "1": "LABEL_1"
17
+ },
18
+ "label2id": {
19
+ "LABEL_0": 0,
20
+ "LABEL_1": 1
21
+ },
22
+ "problem_type": null,
23
+ "_name_or_path": "",
24
+ "transformers_version": "5.3.0",
25
+ "model_type": "dinov2",
26
+ "hidden_size": 384,
27
+ "num_hidden_layers": 12,
28
+ "num_attention_heads": 6,
29
+ "mlp_ratio": 4,
30
+ "hidden_act": "gelu",
31
+ "hidden_dropout_prob": 0.0,
32
+ "attention_probs_dropout_prob": 0.0,
33
+ "initializer_range": 0.02,
34
+ "layer_norm_eps": 1e-06,
35
+ "image_size": 518,
36
+ "patch_size": 14,
37
+ "num_channels": 3,
38
+ "qkv_bias": true,
39
+ "layerscale_value": 1.0,
40
+ "drop_path_rate": 0.0,
41
+ "use_swiglu_ffn": false,
42
+ "stage_names": [
43
+ "stem",
44
+ "stage1",
45
+ "stage2",
46
+ "stage3",
47
+ "stage4",
48
+ "stage5",
49
+ "stage6",
50
+ "stage7",
51
+ "stage8",
52
+ "stage9",
53
+ "stage10",
54
+ "stage11",
55
+ "stage12"
56
+ ],
57
+ "apply_layernorm": true,
58
+ "reshape_hidden_states": true,
59
+ "use_mask_token": true,
60
+ "output_attentions": false,
61
+ "out_features": [
62
+ "stage12"
63
+ ],
64
+ "out_indices": [
65
+ 12
66
+ ]
67
+ },
68
+ "text_dim": 256,
69
+ "proprio_dim": 32,
70
+ "action_dim": 7,
71
+ "image_size": [
72
+ 224,
73
+ 224
74
+ ],
75
+ "vision_dim": 384,
76
+ "modality_emb_dim": 256,
77
+ "parameter_count": 24434823,
78
+ "freeze_encoder": true,
79
+ "adapter_inputs": [
80
+ "image",
81
+ "proprio",
82
+ "instruction",
83
+ "task",
84
+ "difficulty",
85
+ "step",
86
+ "horizon"
87
+ ],
88
+ "forbidden_adapter_inputs": [
89
+ "raw_obs",
90
+ "object_state",
91
+ "sim_state",
92
+ "mujoco_data"
93
+ ],
94
+ "training_data": "hf:random-sequence/flock-robotics-vla-training-v2"
95
+ }