easylearning commited on
Commit
64b9802
·
verified ·
1 Parent(s): baa2b36

Add files using upload-large-folder tool

Browse files
Files changed (45) hide show
  1. bridge/models/ordinary200/config.json +30 -0
  2. bridge/models/ordinary200/generation_config.json +6 -0
  3. bridge/preprocessing/action_ranges.pth +3 -0
  4. code/THIRD_PARTY_NOTICES.md +9 -0
  5. code/pyproject.toml +16 -0
  6. code/src/futureworlds/__init__.py +2 -0
  7. code/src/futureworlds/batch.py +9 -0
  8. code/src/futureworlds/checkpoints.py +76 -0
  9. code/src/futureworlds/decoding.py +81 -0
  10. code/src/futureworlds/memory.py +41 -0
  11. code/src/futureworlds/motion_reward.py +72 -0
  12. code/src/futureworlds/objective.py +203 -0
  13. code/src/futureworlds/ordinary_search.py +71 -0
  14. code/src/futureworlds/reward_core.py +98 -0
  15. code/src/futureworlds/rewards.py +48 -0
  16. code/src/futureworlds/search.py +72 -0
  17. code/src/futureworlds/text_conditioning.py +73 -0
  18. robocasa/README.md +50 -0
  19. robocasa/codec/config.json +40 -0
  20. robocasa/codec/diffusion_pytorch_model.safetensors +3 -0
  21. robocasa/futureworlds_config.json +77 -0
  22. robocasa/models/grpo200/config.json +30 -0
  23. robocasa/models/grpo200/generation_config.json +6 -0
  24. robocasa/models/grpo200/model.safetensors +3 -0
  25. robocasa/models/grpo200/text_adapters.safetensors +3 -0
  26. robocasa/models/main/config.json +30 -0
  27. robocasa/models/main/generation_config.json +6 -0
  28. robocasa/models/main/model.safetensors +3 -0
  29. robocasa/models/main/text_adapters.safetensors +3 -0
  30. robocasa/models/memspo200/config.json +30 -0
  31. robocasa/models/memspo200/generation_config.json +6 -0
  32. robocasa/models/memspo200/model.safetensors +3 -0
  33. robocasa/models/memspo200/text_adapters.safetensors +3 -0
  34. robocasa/models/ordinary200/config.json +30 -0
  35. robocasa/models/ordinary200/generation_config.json +6 -0
  36. robocasa/models/ordinary200/model.safetensors +3 -0
  37. robocasa/models/ordinary200/text_adapters.safetensors +3 -0
  38. robocasa/models/sft/config.json +30 -0
  39. robocasa/models/sft/generation_config.json +6 -0
  40. robocasa/models/sft/model.safetensors +3 -0
  41. robocasa/models/sft/text_adapters.safetensors +3 -0
  42. robocasa/preprocessing/action_ranges.pt +3 -0
  43. robocasa/training_recipe.json +23 -0
  44. rt1/models/main/text_adapters.safetensors +3 -0
  45. rt1/models/sft/text_adapters.safetensors +3 -0
bridge/models/ordinary200/config.json ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "architectures": [
3
+ "LlamaForCausalLM"
4
+ ],
5
+ "attention_bias": false,
6
+ "attention_dropout": 0.0,
7
+ "bos_token_id": 9006,
8
+ "dtype": "float32",
9
+ "eos_token_id": 9007,
10
+ "head_dim": 64,
11
+ "hidden_act": "silu",
12
+ "hidden_size": 768,
13
+ "initializer_range": 0.02,
14
+ "intermediate_size": 3072,
15
+ "max_length": null,
16
+ "max_position_embeddings": 8192,
17
+ "mlp_bias": false,
18
+ "model_type": "llama",
19
+ "num_attention_heads": 12,
20
+ "num_hidden_layers": 12,
21
+ "num_key_value_heads": 12,
22
+ "pretraining_tp": 1,
23
+ "rms_norm_eps": 1e-06,
24
+ "rope_scaling": null,
25
+ "rope_theta": 10000.0,
26
+ "tie_word_embeddings": false,
27
+ "transformers_version": "4.57.1",
28
+ "use_cache": true,
29
+ "vocab_size": 9008
30
+ }
bridge/models/ordinary200/generation_config.json ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ {
2
+ "_from_model_config": true,
3
+ "bos_token_id": 9006,
4
+ "eos_token_id": 9007,
5
+ "transformers_version": "4.57.1"
6
+ }
bridge/preprocessing/action_ranges.pth ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:4492b53758cea8b3d4cb01e01ddf32d9d4bf31095fb3ca768a2d3ff631be8b15
3
+ size 829
code/THIRD_PARTY_NOTICES.md ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ # Third-party provenance
2
+
3
+ This is a local research-code consolidation, not a public release.
4
+
5
+ - `objective.py` preserves the original ByteDance/Hugging Face Apache-2.0 header from the audited RLVR-World/verl-derived implementation.
6
+ - `reward_core.py` preserves its original upstream header. The audited upstream RLVR-World reference is commit `e1b8b6f40ca0696919ce9b8dbe965c4153bcf5f1`.
7
+ - Tokenizer and backbone loading in the archived trainers rely on iVideoGPT/RLVR-World components, Hugging Face Transformers and PyTorch. Those model assets and datasets are not included here.
8
+ - The local source manifest records file-level provenance. Before public distribution, consolidate the applicable full upstream licenses and choose the license for original additions; no blanket relicensing is implied here.
9
+
code/pyproject.toml ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ [build-system]
2
+ requires = ["setuptools>=68"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "futureworlds"
7
+ version = "0.1.0.dev0"
8
+ description = "Memory-conditioned search and post-training for robotic world models"
9
+ requires-python = ">=3.9"
10
+ dependencies = ["numpy", "torch>=2.1", "transformers>=4.45,<5", "safetensors"]
11
+
12
+ [project.optional-dependencies]
13
+ hub = ["huggingface_hub>=0.34"]
14
+
15
+ [tool.setuptools.packages.find]
16
+ where = ["src"]
code/src/futureworlds/__init__.py ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ """FutureWorlds research core. Training entry points are being consolidated."""
2
+ __version__ = "0.1.0.dev0"
code/src/futureworlds/batch.py ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ """Small tensor container for the upstream video reward's batch-only API."""
2
+ class TensorBatch:
3
+ def __init__(self,batch,meta_info=None):
4
+ self.batch=batch
5
+ self.meta_info=meta_info or {}
6
+ @classmethod
7
+ def from_single_dict(cls,batch,meta_info=None):return cls(batch,meta_info)
8
+ def __len__(self):return len(next(iter(self.batch.values())))
9
+ def __getitem__(self,index):return type(self)({k:v[index] for k,v in self.batch.items()},self.meta_info)
code/src/futureworlds/checkpoints.py ADDED
@@ -0,0 +1,76 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Load an explicit released world-model variant; never substitute adapters."""
2
+ import hashlib
3
+ import json
4
+ from pathlib import Path, PurePosixPath
5
+
6
+
7
+ def safe_path(root, relative):
8
+ rel = PurePosixPath(relative)
9
+ if rel.is_absolute() or not rel.parts or '..' in rel.parts or '\\' in relative:
10
+ raise ValueError(f'Invalid relative path: {relative!r}')
11
+ root = Path(root).resolve()
12
+ path = (root / relative).resolve()
13
+ if path != root and root not in path.parents:
14
+ raise ValueError('Path escapes bundle root')
15
+ return path
16
+
17
+
18
+ def file_sha256(path):
19
+ value = hashlib.sha256()
20
+ with Path(path).open('rb') as stream:
21
+ for block in iter(lambda: stream.read(8 * 1024 * 1024), b''):
22
+ value.update(block)
23
+ return value.hexdigest()
24
+
25
+
26
+ def verify_bundle(root):
27
+ root = Path(root)
28
+ manifest = json.loads((root / 'manifest.json').read_text())
29
+ if manifest.get('schema_version') != 1 or not manifest.get('files'):
30
+ raise ValueError('Unsupported or empty manifest')
31
+ seen = set()
32
+ for item in manifest['files']:
33
+ name = item['path']
34
+ if name in seen:
35
+ raise ValueError(f'Duplicate file: {name}')
36
+ seen.add(name)
37
+ path = safe_path(root, name)
38
+ if not path.is_file() or path.stat().st_size != item['bytes']:
39
+ raise ValueError(f'Missing file or wrong size: {name}')
40
+ if file_sha256(path) != item['sha256']:
41
+ raise ValueError(f'Checksum mismatch: {name}')
42
+ return manifest
43
+
44
+
45
+ def load_world_model(root, dataset, variant='main', device='cpu', verify=True):
46
+ """Load the predictor only. Codec/actions/T5 preprocessing are separate.
47
+
48
+ FP32 and SDPA match the audited loaders. Dataset/variant selection is
49
+ explicit; missing text adapters are an error, never silently zero-filled.
50
+ """
51
+ import torch
52
+ from safetensors.torch import load_file
53
+ from transformers import AutoConfig, AutoModelForCausalLM
54
+ from .text_conditioning import TextWorldModel
55
+
56
+ root = Path(root)
57
+ if verify:
58
+ verify_bundle(root)
59
+ settings = json.loads(safe_path(root, f'{dataset}/futureworlds_config.json').read_text())
60
+ if settings['dataset'] != dataset or variant not in settings['variants']:
61
+ raise ValueError('Dataset or variant does not match bundle configuration')
62
+ entry = settings['variants'][variant]
63
+ folder = safe_path(root, entry['path'])
64
+ cfg = AutoConfig.from_pretrained(folder, local_files_only=True, trust_remote_code=False)
65
+ core = AutoModelForCausalLM.from_config(cfg, torch_dtype=torch.float32, attn_implementation='sdpa', trust_remote_code=False)
66
+ core.load_state_dict(load_file(str(folder / 'model.safetensors')), strict=True)
67
+ if settings['text_conditioning']['enabled']:
68
+ tc = settings['text_conditioning']
69
+ model = TextWorldModel(core, text_width=tc['width'], layers=tc['layers'], inner=tc['inner'])
70
+ adapters = folder / 'text_adapters.safetensors'
71
+ if not adapters.is_file():
72
+ raise FileNotFoundError(f'Required trained text adapters missing: {adapters}')
73
+ model.adapters.load_state_dict(load_file(str(adapters)), strict=True)
74
+ else:
75
+ model = core
76
+ return model.to(device).eval()
code/src/futureworlds/decoding.py ADDED
@@ -0,0 +1,81 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Fixed-length, constrained HF beam search and independent numerical checks."""
2
+ import torch
3
+ from transformers import GenerationConfig, LogitsProcessor, LogitsProcessorList
4
+
5
+ class VisualTokensOnly(LogitsProcessor):
6
+ def __init__(self, valid_size):
7
+ self.valid_size = valid_size
8
+
9
+ def __call__(self, input_ids, scores):
10
+ scores = scores.clone()
11
+ scores[:, self.valid_size:] = -torch.inf
12
+ return scores
13
+
14
+ @torch.inference_mode()
15
+ def beam_decode(model, prefix, width=4, steps=80, valid_size=4375):
16
+ config = GenerationConfig(
17
+ do_sample=False, num_beams=width, num_return_sequences=width,
18
+ max_new_tokens=steps, min_new_tokens=steps,
19
+ eos_token_id=None, bos_token_id=None, pad_token_id=0,
20
+ length_penalty=0.0 if width > 1 else 1.0, early_stopping=False, renormalize_logits=True,
21
+ repetition_penalty=1.0, no_repeat_ngram_size=0,
22
+ use_cache=True, return_dict_in_generate=True, output_scores=True,
23
+ )
24
+ result = model.generate(
25
+ input_ids=prefix, attention_mask=torch.ones_like(prefix),
26
+ generation_config=config,
27
+ logits_processor=LogitsProcessorList([VisualTokensOnly(valid_size)]),
28
+ eos_token_id=None, bos_token_id=None,
29
+ forced_bos_token_id=None, forced_eos_token_id=None,
30
+ )
31
+ candidates = result.sequences[:, prefix.shape[1]:]
32
+ assert candidates.shape == (width,steps)
33
+ assert int(candidates.min()) >= 0 and int(candidates.max()) < valid_size
34
+ assert len({tuple(x) for x in candidates.tolist()}) == width
35
+ transitions = model.compute_transition_scores(
36
+ result.sequences, result.scores, getattr(result,'beam_indices',None),
37
+ normalize_logits=False,
38
+ )
39
+ assert transitions.shape == (width,steps) and torch.isfinite(transitions).all()
40
+ sums = transitions.sum(-1)
41
+ scores = result.sequences_scores if width > 1 else sums
42
+ error = float((sums-scores).abs().max())
43
+ assert torch.allclose(sums,scores,rtol=0,atol=2e-4), error
44
+ assert torch.all(scores[:-1] >= scores[1:])
45
+ return candidates, scores, {'beam_width':width,'tokens_per_frame':steps,
46
+ 'selected_index':0,'candidate_scores':scores.tolist(),
47
+ 'score_reconstruction_max_error':error,
48
+ 'score_definition':'Sum of log probabilities renormalized over valid visual tokens only; no length penalty or GT/image reward.'}
49
+
50
+ @torch.inference_mode()
51
+ def independent_check():
52
+ from transformers import LlamaConfig, LlamaForCausalLM
53
+ torch.manual_seed(3719)
54
+ model = LlamaForCausalLM(LlamaConfig(vocab_size=8,hidden_size=32,
55
+ intermediate_size=48,num_hidden_layers=2,num_attention_heads=4,
56
+ num_key_value_heads=4,max_position_embeddings=128,
57
+ eos_token_id=2,bos_token_id=1,pad_token_id=0,
58
+ attention_dropout=0.0)).float().eval()
59
+ prefix = torch.tensor([[6,1,3]],dtype=torch.long)
60
+ reports=[]
61
+ for width in [1,4]:
62
+ beams=[([],0.0)]
63
+ for _ in range(4):
64
+ expanded=[]
65
+ for seq,score in beams:
66
+ x=torch.tensor([prefix[0].tolist()+seq],dtype=torch.long)
67
+ probs=model(input_ids=x,use_cache=False).logits[0,-1,:5].log_softmax(-1)
68
+ expanded.extend((seq+[token],score+float(probs[token])) for token in range(5))
69
+ beams=sorted(expanded,key=lambda item:item[1],reverse=True)[:width]
70
+ ids,scores,meta=beam_decode(model,prefix,width=width,steps=4,valid_size=5)
71
+ expected=torch.tensor([seq for seq,_ in beams],dtype=torch.long)
72
+ expected_scores=torch.tensor([score for _,score in beams])
73
+ assert torch.equal(ids,expected),(width,ids,expected)
74
+ assert torch.allclose(scores,expected_scores,rtol=0,atol=2e-5)
75
+ reports.append({'width':width,'matches_independent_uncached_search':True,
76
+ 'max_score_error':float((scores-expected_scores).abs().max())})
77
+ return {'tests':reports,'eos_disabled':True,'valid_token_constraint_checked':True,'complete':True}
78
+
79
+ if __name__ == '__main__':
80
+ import json, transformers
81
+ print(json.dumps({'transformers':transformers.__version__,**independent_check()}))
code/src/futureworlds/memory.py ADDED
@@ -0,0 +1,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Causal ReCAP prompts shared by rollout and every policy log-probability pass."""
2
+ import torch
3
+
4
+ def retained(target,recent=6):
5
+ assert target>=2 and recent>=1
6
+ return [1]+list(range(max(2,target-recent),target))
7
+
8
+ def make_prefix(context,history,actions,target,recent=6):
9
+ kept=retained(target,recent)
10
+ assert max(kept)==target-1 and len(kept)==len(set(kept))
11
+ blocks=[context]
12
+ for t in kept:blocks += [history[t],actions[t].expand(context.shape[0],-1)]
13
+ return torch.cat(blocks,dim=1),kept
14
+
15
+ @torch.no_grad()
16
+ def rollout(model,context,anchor,actions,horizon,group,generator,visual=4375,width=80,temperature=1.0):
17
+ model.eval()
18
+ context=context.expand(group,-1);history={1:anchor.expand(group,-1)}
19
+ frames=[];traces=[]
20
+ for target in range(2,horizon+2):
21
+ prefix,kept=make_prefix(context,history,actions,target)
22
+ pending=prefix;kv=None;codes=[];lps=[]
23
+ for token in range(width):
24
+ out=model(input_ids=pending,past_key_values=kv,use_cache=True)
25
+ kv=out.past_key_values
26
+ logp=torch.log_softmax(out.logits[:,-1,:visual].float()/temperature,-1)
27
+ pending=torch.multinomial(logp.exp(),1,generator=generator)
28
+ codes.append(pending);lps.append(logp.gather(1,pending).squeeze(1))
29
+ response=torch.cat(codes,1)
30
+ frames.append({'prefix':prefix.detach(),'response':response.detach(),'sample_logp':torch.stack(lps,1).detach(),'target':target})
31
+ history[target]=response
32
+ traces.append({'target':target,'retained':kept,'prefix_length':prefix.shape[1],'positions_reset':True,'kv_reset':True,'future_observations':False})
33
+ return frames,traces
34
+
35
+ def frame_logp(model,prefix,response,visual=4375,temperature=1.0):
36
+ # Each target has its own rebased prefix. No discarded history is hidden in a cache.
37
+ ids=torch.cat([prefix,response[:,:-1]],1)
38
+ out=model(input_ids=ids,use_cache=False)
39
+ p=prefix.shape[1]
40
+ logits=out.logits[:,p-1:p+response.shape[1]-1,:visual].float()/temperature
41
+ return torch.log_softmax(logits,-1).gather(-1,response.unsqueeze(-1)).squeeze(-1)
code/src/futureworlds/motion_reward.py ADDED
@@ -0,0 +1,72 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """GT motion-proxy ROI and GT-referenced dynamics. No actor/search sees future GT."""
2
+ import torch
3
+ import torch.nn.functional as F
4
+ from .rewards import CodecWorker
5
+ from .batch import TensorBatch
6
+
7
+ @torch.no_grad()
8
+ def motion_regions(truth,previous):
9
+ """Shared across candidates: GT-derived, never shrinks after predicted disappearance."""
10
+ prev=torch.cat([previous[None],truth[:-1]],0)
11
+ motion=(truth-prev).abs().mean(1,keepdim=True)
12
+ thresholds=motion.flatten(1).quantile(.90,dim=1).clamp_min(.02)
13
+ masks=(motion>thresholds[:,None,None,None]).float()
14
+ masks=F.max_pool2d(masks,11,stride=1,padding=5)
15
+ fallback=masks.mean((1,2,3))<.01
16
+ masks[fallback]=1
17
+ crops=[];height,width=truth.shape[-2:]
18
+ for mask in masks:
19
+ y,x=torch.where(mask[0]>0)
20
+ y0,y1=int(y.min()),int(y.max())+1;x0,x1=int(x.min()),int(x.max())+1
21
+ cy=(y0+y1)//2;cx=(x0+x1)//2
22
+ h=max(64,y1-y0);w=max(64,x1-x0)
23
+ y0=max(0,min(cy-h//2,height-h));x0=max(0,min(cx-w//2,width-w))
24
+ crops.append((y0,min(height,y0+h),x0,min(width,x0+w)))
25
+ return masks,crops,fallback
26
+
27
+ class MotionReward:
28
+ def __init__(self,codec,perceptual,scales=None,alpha=.5,beta=.25):
29
+ self.worker=CodecWorker(codec,perceptual);self.perceptual=perceptual
30
+ self.scales=scales or dict(global_scale=1.,roi_scale=1.,delta_scale=1.)
31
+ self.alpha=alpha;self.beta=beta
32
+
33
+ @torch.no_grad()
34
+ def components(self,pred,pixels):
35
+ truth=pixels[0,2:];previous=pixels[0,1]
36
+ n,h=pred.shape[:2];real=truth[None].expand(n,-1,-1,-1,-1)
37
+ mae=(pred-real).abs().mean((2,3,4))
38
+ percept=self.worker.perceptual_loss(TensorBatch(dict(real=real,pred=pred))).batch['perceptual_loss']
39
+ masks,crops,fallback=motion_regions(truth,previous)
40
+ roi_mae=((pred-real).abs()*masks).sum((2,3,4))/(3*masks.sum((1,2,3)))[None]
41
+ roi_percept=torch.empty((n,h),device=pred.device)
42
+ for t,(y0,y1,x0,x1) in enumerate(crops):
43
+ r=truth[t:t+1,:,y0:y1,x0:x1]
44
+ for start in range(0,n,2):
45
+ pp=pred[start:start+2,t,:,y0:y1,x0:x1]
46
+ roi_percept[start:start+len(pp),t]=self.perceptual(pp*2-1,r.expand(len(pp),-1,-1,-1)*2-1).flatten()
47
+ pred_prev=torch.cat([previous[None,None].expand(n,1,-1,-1,-1),pred[:,:-1]],1)
48
+ true_prev=torch.cat([previous[None],truth[:-1]],0)
49
+ delta=((pred-pred_prev)-(truth-true_prev)[None]).abs().mean((2,3,4))
50
+ return dict(mae=mae,lpips=percept,global_loss=mae+percept,
51
+ roi_loss=roi_mae+roi_percept,roi_mae=roi_mae,roi_lpips=roi_percept,
52
+ delta_loss=delta,roi_fallback=fallback,roi_area=masks.mean((1,2,3)))
53
+
54
+ def combine(self,c):
55
+ s=self.scales
56
+ return -(c['global_loss']+self.alpha*s['global_scale']/s['roi_scale']*c['roi_loss']+
57
+ self.beta*s['global_scale']/s['delta_scale']*c['delta_loss']).mean(-1)
58
+
59
+ @torch.no_grad()
60
+ def decode(self,frames,context):
61
+ codes=torch.stack([f['response'] for f in frames],1)
62
+ assert codes.min()>=0 and codes.max()<4375
63
+ return self.worker.detokenize(TensorBatch(dict(tokens=codes,ctx_tokens=context.expand(len(codes),-1,-1))),None).batch['pixels'][:,1:]
64
+
65
+ @torch.no_grad()
66
+ def __call__(self,frames,context,actions,pixels):
67
+ c=self.components(self.decode(frames,context),pixels)
68
+ reward=self.combine(c)
69
+ assert torch.isfinite(reward).all()
70
+ metrics={'critic/recon_loss/mean':float(c['mae'].mean()),'critic/perceptual_loss/mean':float(c['lpips'].mean())}
71
+ metrics.update({k:float(v.float().mean()) for k,v in c.items()})
72
+ return reward,metrics
code/src/futureworlds/objective.py ADDED
@@ -0,0 +1,203 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright 2024 Bytedance Ltd. and/or its affiliates
2
+ # Copyright 2022 The HuggingFace Team. All rights reserved.
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+
16
+ import torch
17
+ import numpy as np
18
+ from collections import defaultdict
19
+ from types import SimpleNamespace
20
+
21
+ def masked_mean(values, mask, axis=None):
22
+ """Compute mean of tensor with a masked values."""
23
+ return (values * mask).sum(axis=axis) / (mask.sum(axis=axis) + 1e-8)
24
+
25
+ verl_F=SimpleNamespace(masked_mean=masked_mean)
26
+
27
+ def compute_grpo_outcome_advantage(token_level_rewards: torch.Tensor,
28
+ response_mask: torch.Tensor,
29
+ index: np.ndarray,
30
+ epsilon: float = 1e-6,
31
+ uniform_std=False):
32
+ """
33
+ Compute advantage for GRPO, operating only on Outcome reward
34
+ (with only one scalar reward for each response).
35
+ Args:
36
+ token_level_rewards: `(torch.Tensor)`
37
+ shape: (bs, response_length)
38
+ response_mask: `(torch.Tensor)`
39
+ shape: (bs, response_length)
40
+
41
+ Returns:
42
+ advantages: `(torch.Tensor)`
43
+ shape: (bs, response_length)
44
+ Returns: `(torch.Tensor)`
45
+ shape: (bs, response_length)
46
+ """
47
+ scores = token_level_rewards.sum(dim=-1)
48
+
49
+ id2score = defaultdict(list)
50
+ id2mean = {}
51
+ id2std = {}
52
+
53
+ with torch.no_grad():
54
+ bsz = scores.shape[0]
55
+ for i in range(bsz):
56
+ id2score[index[i]].append(scores[i])
57
+ for idx in id2score:
58
+ if len(id2score[idx]) == 1:
59
+ id2mean[idx] = torch.tensor(0.0)
60
+ id2std[idx] = torch.tensor(1.0)
61
+ elif len(id2score[idx]) > 1:
62
+ id2mean[idx] = torch.mean(torch.tensor(id2score[idx]))
63
+ id2std[idx] = torch.std(torch.tensor([id2score[idx]]))
64
+ else:
65
+ raise ValueError(f"no score in prompt index: {idx}")
66
+ if uniform_std:
67
+ std = torch.tensor(list(id2std.values())).mean()
68
+ for i in range(bsz):
69
+ scores[i] = (scores[i] - id2mean[index[i]]) / (std + epsilon)
70
+ else:
71
+ for i in range(bsz):
72
+ scores[i] = (scores[i] - id2mean[index[i]]) / (id2std[index[i]] + epsilon)
73
+ scores = scores.unsqueeze(-1) * response_mask
74
+
75
+ return scores, scores
76
+
77
+ def agg_loss(loss_mat: torch.Tensor, loss_mask: torch.Tensor, loss_agg_mode: str):
78
+ """
79
+ Aggregate the loss matrix into a scalar.
80
+ Args:
81
+ loss_mat: `(torch.Tensor)`
82
+ shape: (bs, response_length)
83
+ loss_mask: `(torch.Tensor)`
84
+ shape: (bs, response_length)
85
+ loss_agg_mode: (str) choices: "token-mean" / "seq-mean-token-sum" / "seq-mean-token-mean"
86
+ "token-mean" is the default behavior
87
+ Returns:
88
+ loss: `a scalar torch.Tensor`
89
+ aggregated loss
90
+ """
91
+ if loss_agg_mode == "token-mean":
92
+ loss = verl_F.masked_mean(loss_mat, loss_mask)
93
+ elif loss_agg_mode == "seq-mean-token-sum":
94
+ seq_losses = torch.sum(loss_mat * loss_mask, dim=-1) # token-sum
95
+ loss = torch.mean(seq_losses) # seq-mean
96
+ elif loss_agg_mode == "seq-mean-token-mean":
97
+ seq_losses = torch.sum(loss_mat * loss_mask, dim=-1) / torch.sum(loss_mask, dim=-1) # token-mean
98
+ loss = torch.mean(seq_losses) # seq-mean
99
+ else:
100
+ raise ValueError(f"Invalid loss_agg_mode: {loss_agg_mode}")
101
+
102
+ return loss
103
+
104
+ def compute_policy_loss(old_log_prob,
105
+ log_prob,
106
+ advantages,
107
+ response_mask,
108
+ cliprange=None,
109
+ cliprange_low=None,
110
+ cliprange_high=None,
111
+ clip_ratio_c=3.0,
112
+ loss_agg_mode="token-mean"):
113
+ """Adapted from https://github.com/huggingface/trl/blob/main/trl/trainer/ppo_trainer.py#L1122
114
+ Args:
115
+ old_log_prob: `(torch.Tensor)`
116
+ shape: (bs, response_length)
117
+ log_prob: `(torch.Tensor)`
118
+ shape: (bs, response_length)
119
+ advantages: `(torch.Tensor)`
120
+ shape: (bs, response_length)
121
+ response_mask: `(torch.Tensor)`
122
+ shape: (bs, response_length)
123
+ cliprange: (float)
124
+ The clip range used in PPO. See https://arxiv.org/abs/1707.06347
125
+ cliprange_low: (float)
126
+ The lower clip range used in PPO.
127
+ cliprange_high: (float)
128
+ The higher clip range used in PPO.
129
+ clip_ratio_c: (float) default: 3.0
130
+ The lower bound of the ratio for dual-clip PPO, See https://arxiv.org/pdf/1912.09729
131
+ loss_agg_mode: (str) choices: "token-mean" / "seq-mean-token-sum" / "seq-mean-token-mean"
132
+ "token-mean" is the default behavior
133
+
134
+ Returns:
135
+ pg_loss: `a scalar torch.Tensor`
136
+ policy gradient loss computed via PPO
137
+ pg_clipfrac: (float)
138
+ the fraction of policy gradient loss being clipped
139
+ ppo_kl: (float)
140
+ the estimated KL divergence between the latest updating policy and the old sampling policy
141
+ pg_clipfrac_lower: (float)
142
+ the fraction of policy gradient loss being clipped when the advantage is negative
143
+ """
144
+ assert clip_ratio_c > 1.0, f"The lower bound of the clip_ratio_c for dual-clip PPO should be greater than 1.0, but get the value: {clip_ratio_c}."
145
+
146
+ negative_approx_kl = log_prob - old_log_prob
147
+ ratio = torch.exp(negative_approx_kl)
148
+ ppo_kl = verl_F.masked_mean(-negative_approx_kl, response_mask)
149
+
150
+ pg_losses1 = -advantages * ratio
151
+ if cliprange_low is None:
152
+ cliprange_low = cliprange
153
+ if cliprange_high is None:
154
+ cliprange_high = cliprange
155
+ pg_losses2 = -advantages * torch.clamp(ratio, 1 - cliprange_low,
156
+ 1 + cliprange_high) # - clip(ratio, 1-cliprange, 1+cliprange) * A
157
+ clip_pg_losses1 = torch.maximum(pg_losses1,
158
+ pg_losses2) # max(-ratio * A, -clip(ratio, 1-cliprange, 1+cliprange) * A)
159
+ pg_clipfrac = verl_F.masked_mean(torch.gt(pg_losses2, pg_losses1).float(), response_mask)
160
+
161
+ pg_losses3 = -advantages * clip_ratio_c
162
+ clip_pg_losses2 = torch.min(pg_losses3, clip_pg_losses1)
163
+ pg_clipfrac_lower = verl_F.masked_mean(
164
+ torch.gt(clip_pg_losses2, pg_losses3) * (advantages < 0).float(), response_mask)
165
+
166
+ pg_losses = torch.where(advantages < 0, clip_pg_losses2, clip_pg_losses1)
167
+ pg_loss = agg_loss(loss_mat=pg_losses, loss_mask=response_mask, loss_agg_mode=loss_agg_mode)
168
+
169
+ return pg_loss, pg_clipfrac, ppo_kl, pg_clipfrac_lower
170
+
171
+ def kl_penalty(logprob: torch.FloatTensor, ref_logprob: torch.FloatTensor, kl_penalty) -> torch.FloatTensor:
172
+ """Compute KL divergence given logprob and ref_logprob.
173
+ Copied from https://github.com/huggingface/trl/blob/main/trl/trainer/ppo_trainer.py#L1104
174
+
175
+ Args:
176
+ logprob:
177
+ ref_logprob:
178
+
179
+ Returns:
180
+
181
+ """
182
+ if kl_penalty == "kl":
183
+ return logprob - ref_logprob
184
+
185
+ if kl_penalty == "abs":
186
+ return (logprob - ref_logprob).abs()
187
+
188
+ if kl_penalty == "mse":
189
+ return 0.5 * (logprob - ref_logprob).square()
190
+
191
+ # J. Schulman. Approximating kl divergence, 2020.
192
+ # # URL http://joschu.net/blog/kl-approx.html.
193
+ if kl_penalty == 'low_var_kl':
194
+ kl = ref_logprob - logprob
195
+ ratio = torch.exp(kl)
196
+ kld = (ratio - kl - 1).contiguous()
197
+ return torch.clamp(kld, min=-10, max=10)
198
+
199
+ if kl_penalty == "full":
200
+ # so, here logprob and ref_logprob should contain the logits for every token in vocabulary
201
+ raise NotImplementedError
202
+
203
+ raise NotImplementedError
code/src/futureworlds/ordinary_search.py ADDED
@@ -0,0 +1,71 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Global beam width 8; return top 4 by raw cumulative model score, no diversity penalty."""
2
+ import torch
3
+ from .memory import make_prefix
4
+
5
+ @torch.no_grad()
6
+ def rollout_ordinary_beam(model, context, anchor, actions, horizon, penalty,
7
+ groups=4, beams=2, visual=4375, width=80):
8
+ assert groups == 4 and beams == 2
9
+ groups, beams, penalty = 1, 8, 0.0
10
+ returned = 4
11
+ model.eval()
12
+ device=context.device; count=groups*beams
13
+ history={1:anchor.expand(count,-1)}; frames=[]; traces=[]
14
+ scores=torch.full((count,),float('-inf'),device=device,dtype=torch.float64)
15
+ scores[::beams]=0
16
+ raw=torch.zeros(count,device=device,dtype=torch.float64)
17
+ for target in range(2,horizon+2):
18
+ original,kept=make_prefix(context.expand(count,-1),history,actions,target)
19
+ ancestors=torch.arange(count,device=device)
20
+ codes=torch.empty((count,0),device=device,dtype=torch.long)
21
+ logs=torch.empty((count,0),device=device)
22
+ pending=original; cache=None
23
+ for token in range(width):
24
+ out=model(input_ids=pending,past_key_values=cache,use_cache=True)
25
+ lp=out.logits[:,-1,:visual].float().log_softmax(-1)
26
+ parents=[]; choices=[]; next_scores=[]
27
+ for g in range(groups):
28
+ start=g*beams
29
+ if g:
30
+ frequency=torch.bincount(torch.cat(choices),minlength=visual).double()/(g*beams)
31
+ else:
32
+ frequency=torch.zeros(visual,device=device,dtype=torch.float64)
33
+ totals=scores[start:start+beams,None]+lp[start:start+beams].double()-penalty*frequency
34
+ score,flat=totals.flatten().topk(beams,sorted=True)
35
+ parents.append(start+flat//visual);choices.append(flat%visual);next_scores.append(score)
36
+ parent=torch.cat(parents);chosen=torch.cat(choices)
37
+ assert torch.equal(parent//beams,torch.arange(count,device=device)//beams)
38
+ raw=raw[parent]+lp[parent,chosen].double()
39
+ scores=torch.cat(next_scores)
40
+ codes=torch.cat([codes[parent],chosen[:,None]],1)
41
+ logs=torch.cat([logs[parent],lp[parent,chosen,None]],1)
42
+ ancestors=ancestors[parent]
43
+ cache=out.past_key_values;cache.reorder_cache(parent)
44
+ pending=chosen[:,None]
45
+ for f in frames:
46
+ for key in ['prefix','response','model_logp']:f[key]=f[key][ancestors]
47
+ history={t:x[ancestors] for t,x in history.items()}
48
+ history[target]=codes
49
+ frames.append(dict(target=target,prefix=original[ancestors],response=codes,model_logp=logs))
50
+ traces.append(dict(target=target,retained=kept,prefix_length=original.shape[1],
51
+ frame_parent_indices=ancestors.tolist(),positions_reset=True,kv_reset=True,
52
+ future_observations=False,random_sampling=False))
53
+ selected=torch.arange(returned,device=device)
54
+ frames=[{k:(v[selected] if torch.is_tensor(v) else v) for k,v in f.items()} for f in frames]
55
+ history={t:x[selected] for t,x in history.items()}
56
+ for f in frames:
57
+ rebuilt,_=make_prefix(context.expand(returned,-1),history,actions,f['target'])
58
+ assert torch.equal(rebuilt,f['prefix'])
59
+ rebuilt=sum(f['model_logp'].double().sum(-1) for f in frames)
60
+ assert torch.allclose(rebuilt,raw[selected],atol=1e-7,rtol=0)
61
+ codes=torch.stack([f['response'] for f in frames],1)
62
+ pair=[float((codes[i]!=codes[j]).float().mean()) for i in range(returned) for j in range(i+1,returned)]
63
+ perframe=(codes!=codes[:1]).any(0).sum(-1).tolist()
64
+ return frames,dict(strategy='ordinary_global_beam8_top4_full_video',groups=groups,beams_per_group=beams,
65
+ active_paths=count,returned_trajectories=returned,penalty=penalty,
66
+ unique_trajectories=len({tuple(c.flatten().tolist()) for c in codes}),
67
+ mean_pairwise_token_difference_fraction=sum(pair)/len(pair),
68
+ pairwise_token_difference_fraction=pair,different_token_positions=sum(perframe),
69
+ different_positions_per_frame=perframe,model_log_scores=raw[selected].tolist(),
70
+ search_scores=scores[selected].tolist(),score_is_behavior_logprob=False,
71
+ on_policy_grpo=False,frames=traces)
code/src/futureworlds/reward_core.py ADDED
@@ -0,0 +1,98 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright 2024 Bytedance Ltd. and/or its affiliates
2
+ # Copyright 2022 The HuggingFace Team. All rights reserved.
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+
16
+ import torch
17
+ from .batch import TensorBatch as DataProto
18
+
19
+ def msp_reward_fn(self, batch: DataProto, pixels, return_reward_tensor=True, save_pred=False, pixels_before_repeat=None):
20
+ if pixels_before_repeat is None:
21
+ pixels_before_repeat = pixels
22
+
23
+ batch_size = batch.batch["responses"].shape[0]
24
+ segment_length = self.config.data.video.segment_length
25
+ tokens_per_frame = self.config.processor.tokens_per_frame
26
+ action_dim = self.config.processor.action_dim
27
+
28
+ output_tokens = batch.batch["responses"].reshape(batch_size, segment_length - 1, tokens_per_frame + action_dim)
29
+ output_tokens = output_tokens[:, :, :tokens_per_frame]
30
+ output_tokens = output_tokens.clamp(0, self.config.processor.visual_token_num - 1).long()
31
+
32
+ ctx_tokens = batch.batch["ctx_tokens"]
33
+ output_tokens = output_tokens.reshape(batch_size, segment_length - 1, tokens_per_frame)
34
+
35
+ detokenize_output = self.tokenizer_wg.detokenize(
36
+ DataProto.from_single_dict({"tokens": output_tokens, "ctx_tokens": ctx_tokens}),
37
+ # DataProto.from_single_dict({"real": pixels_before_repeat[:, 2:]}, meta_info={'lpips': True}),
38
+ DataProto.from_single_dict({"dummy": torch.zeros((batch_size, 1))}, meta_info={'lpips': True, 'recon': self.config.trainer.reward_fn}),
39
+ )
40
+
41
+ if 'recon_loss' in detokenize_output.batch.keys():
42
+ recon_loss = detokenize_output.batch['recon_loss']
43
+ else:
44
+ pred = detokenize_output.batch['pixels'].clamp(0.0, 1.0)[:, 1:]
45
+ real = pixels[:, 2:]
46
+ if self.config.trainer.reward_fn == 'mse':
47
+ recon_loss = torch.mean((real - pred)**2, dim=(2, 3, 4))
48
+ elif self.config.trainer.reward_fn == 'mae':
49
+ recon_loss = torch.mean(torch.abs(real - pred), dim=(2, 3, 4))
50
+ else:
51
+ raise NotImplementedError(f"Unsupported reward function: {self.config.trainer.reward_fn}")
52
+
53
+ if 'perceptual_loss' in detokenize_output.batch.keys():
54
+ perceptual_loss = detokenize_output.batch['perceptual_loss']
55
+ else:
56
+ perceptual_loss = self.tokenizer_wg.perceptual_loss(DataProto.from_single_dict({"real": real, "pred": pred}))
57
+ perceptual_loss = perceptual_loss.batch['perceptual_loss']
58
+
59
+ if self.config.trainer.msp_reward_aggregate == "mean":
60
+ loss = (recon_loss + perceptual_loss).mean(-1)
61
+ elif self.config.trainer.msp_reward_aggregate == "last":
62
+ loss = (recon_loss + perceptual_loss)[:, -1]
63
+ elif self.config.trainer.msp_reward_aggregate == "discount":
64
+ discount = 0.9
65
+ weight = discount ** torch.arange(recon_loss.shape[1], device=recon_loss.device)
66
+ loss = (recon_loss + perceptual_loss) * weight.unsqueeze(0)
67
+ loss = loss.sum(-1) / weight.sum()
68
+ if not return_reward_tensor:
69
+ return loss
70
+
71
+ print("loss", loss.mean().item(), flush=True)
72
+ print("recon_loss", recon_loss.mean().item(), flush=True)
73
+ print("perceptual_loss", perceptual_loss.mean().item(), flush=True)
74
+ if save_pred:
75
+ pred = detokenize_output.batch['pixels'].clamp(0.0, 1.0)[:, 1:]
76
+ real = pixels[:, 2:]
77
+ for i in range(1):
78
+ # for i in range(5):
79
+ real_traj = torch.cat([real[i:i+1, j] for j in range(real.shape[1])], dim=-1)
80
+ pred_traj = torch.cat([pred[i:i+1, j] for j in range(pred.shape[1])], dim=-1)
81
+ plot_img(torch.cat([
82
+ real_traj.float(),
83
+ pred_traj.float(),
84
+ torch.abs(real_traj-pred_traj).float(),
85
+ ], dim=-2), f"{self.config.trainer.experiment_name}-{i}")
86
+
87
+ reward_tensor = torch.zeros_like(batch.batch['responses'], dtype=torch.float32)
88
+ for i in range(len(batch)):
89
+ data_item = batch[i]
90
+ prompt_ids = data_item.batch['prompts']
91
+ prompt_length = prompt_ids.shape[-1]
92
+ valid_response_length = data_item.batch['attention_mask'][prompt_length:].sum().long().item()
93
+ reward_tensor[i, valid_response_length - 1] = -loss[i].item()
94
+
95
+ return reward_tensor, {
96
+ "critic/recon_loss/mean": recon_loss.mean().item(),
97
+ "critic/perceptual_loss/mean": perceptual_loss.mean().item(),
98
+ }
code/src/futureworlds/rewards.py ADDED
@@ -0,0 +1,48 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Use the upstream msp_reward_fn via a local frozen-tokenizer worker adapter."""
2
+ from types import SimpleNamespace as NS
3
+ import torch
4
+ from .batch import TensorBatch
5
+ from .reward_core import msp_reward_fn
6
+
7
+ class CodecWorker:
8
+ def __init__(self,codec,perceptual):self.codec=codec;self.perceptual=perceptual
9
+ @torch.no_grad()
10
+ def detokenize(self,batch,dummy):
11
+ codes=batch.batch['tokens'];ctx=batch.batch['ctx_tokens'];movies=[]
12
+ for b in range(codes.shape[0]):
13
+ parts=[];first=None
14
+ for start in range(0,codes.shape[1],2):
15
+ decoded=self.codec.detokenize(ctx[b:b+1],codes[b:b+1,start:start+2]).float().clamp(0,1)
16
+ if first is None:first=decoded[:,:1]
17
+ parts.append(decoded[:,1:])
18
+ movies.append(torch.cat([first]+parts,1))
19
+ return TensorBatch({'pixels':torch.cat(movies,0)})
20
+ @torch.no_grad()
21
+ def perceptual_loss(self,batch):
22
+ real,pred=batch.batch['real'],batch.batch['pred'];values=[]
23
+ for r,p in zip(real,pred):
24
+ pieces=[]
25
+ for i in range(0,len(p),2):pieces.append(self.perceptual(p[i:i+2]*2-1,r[i:i+2]*2-1).flatten())
26
+ values.append(torch.cat(pieces))
27
+ return TensorBatch({'perceptual_loss':torch.stack(values)})
28
+
29
+ class VideoReward:
30
+ msp_reward_fn=msp_reward_fn
31
+ def __init__(self,codec,perceptual,horizon):
32
+ self.config=NS(data=NS(video=NS(segment_length=horizon+1)),processor=NS(tokens_per_frame=80,action_dim=13,visual_token_num=4375),trainer=NS(reward_fn='mae',msp_reward_aggregate='mean'))
33
+ self.tokenizer_wg=CodecWorker(codec,perceptual)
34
+ @torch.no_grad()
35
+ def __call__(self,frames,context,actions,pixels):
36
+ # Only reward bookkeeping uses concatenated responses. Policy scoring uses actual per-frame prefixes.
37
+ codes=torch.stack([f['response'] for f in frames],1)
38
+ assert codes.min()>=0 and codes.max()<4375,'Illegal generated token; never hide it with upstream clamp'
39
+ group,horizon,_=codes.shape
40
+ act=actions[2:2+horizon].unsqueeze(0).expand(group,-1,-1)
41
+ responses=torch.cat([codes,act],-1).reshape(group,-1)
42
+ prompt=frames[0]['prefix']
43
+ batch=TensorBatch({'responses':responses,'prompts':prompt,'attention_mask':torch.ones(group,prompt.shape[1]+responses.shape[1],device=codes.device,dtype=torch.long),'ctx_tokens':context.expand(group,-1,-1)})
44
+ truth=pixels.expand(group,-1,-1,-1,-1)
45
+ tensor,metrics=self.msp_reward_fn(batch,truth)
46
+ reward=tensor.sum(-1)
47
+ assert torch.isfinite(reward).all()
48
+ return reward,metrics
code/src/futureworlds/search.py ADDED
@@ -0,0 +1,72 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Four disjoint beam groups, with unmodified policy scores for the RL surrogate.
2
+
3
+ Search penalties only affect proposal selection. Deterministic proposals do not
4
+ have on-policy sampling probabilities; the beam RL objective remains biased.
5
+ """
6
+ import torch
7
+ from .memory import make_prefix
8
+
9
+ @torch.no_grad()
10
+ def rollout_group_beam(model, context, anchor, actions, horizon, penalty,
11
+ groups=4, beams=2, visual=4375, width=80):
12
+ model.eval()
13
+ device=context.device; count=groups*beams
14
+ history={1:anchor.expand(count,-1)}; frames=[]; traces=[]
15
+ scores=torch.full((count,),float('-inf'),device=device,dtype=torch.float64)
16
+ scores[::beams]=0
17
+ raw=torch.zeros(count,device=device,dtype=torch.float64)
18
+ for target in range(2,horizon+2):
19
+ original,kept=make_prefix(context.expand(count,-1),history,actions,target)
20
+ ancestors=torch.arange(count,device=device)
21
+ codes=torch.empty((count,0),device=device,dtype=torch.long)
22
+ logs=torch.empty((count,0),device=device)
23
+ pending=original; cache=None
24
+ for token in range(width):
25
+ out=model(input_ids=pending,past_key_values=cache,use_cache=True)
26
+ lp=out.logits[:,-1,:visual].float().log_softmax(-1)
27
+ parents=[]; choices=[]; next_scores=[]
28
+ for g in range(groups):
29
+ start=g*beams
30
+ if g:
31
+ frequency=torch.bincount(torch.cat(choices),minlength=visual).double()/(g*beams)
32
+ else:
33
+ frequency=torch.zeros(visual,device=device,dtype=torch.float64)
34
+ totals=scores[start:start+beams,None]+lp[start:start+beams].double()-penalty*frequency
35
+ score,flat=totals.flatten().topk(beams,sorted=True)
36
+ parents.append(start+flat//visual);choices.append(flat%visual);next_scores.append(score)
37
+ parent=torch.cat(parents);chosen=torch.cat(choices)
38
+ assert torch.equal(parent//beams,torch.arange(count,device=device)//beams)
39
+ raw=raw[parent]+lp[parent,chosen].double()
40
+ scores=torch.cat(next_scores)
41
+ codes=torch.cat([codes[parent],chosen[:,None]],1)
42
+ logs=torch.cat([logs[parent],lp[parent,chosen,None]],1)
43
+ ancestors=ancestors[parent]
44
+ cache=out.past_key_values;cache.reorder_cache(parent)
45
+ pending=chosen[:,None]
46
+ for f in frames:
47
+ for key in ['prefix','response','model_logp']:f[key]=f[key][ancestors]
48
+ history={t:x[ancestors] for t,x in history.items()}
49
+ history[target]=codes
50
+ frames.append(dict(target=target,prefix=original[ancestors],response=codes,model_logp=logs))
51
+ traces.append(dict(target=target,retained=kept,prefix_length=original.shape[1],
52
+ frame_parent_indices=ancestors.tolist(),positions_reset=True,kv_reset=True,
53
+ future_observations=False,random_sampling=False))
54
+ selected=torch.arange(0,count,beams,device=device)
55
+ frames=[{k:(v[selected] if torch.is_tensor(v) else v) for k,v in f.items()} for f in frames]
56
+ history={t:x[selected] for t,x in history.items()}
57
+ for f in frames:
58
+ rebuilt,_=make_prefix(context.expand(groups,-1),history,actions,f['target'])
59
+ assert torch.equal(rebuilt,f['prefix'])
60
+ rebuilt=sum(f['model_logp'].double().sum(-1) for f in frames)
61
+ assert torch.allclose(rebuilt,raw[selected],atol=1e-7,rtol=0)
62
+ codes=torch.stack([f['response'] for f in frames],1)
63
+ pair=[float((codes[i]!=codes[j]).float().mean()) for i in range(groups) for j in range(i+1,groups)]
64
+ perframe=(codes!=codes[:1]).any(0).sum(-1).tolist()
65
+ return frames,dict(strategy='grouped_diverse_full_video_beam',groups=groups,beams_per_group=beams,
66
+ active_paths=count,returned_trajectories=groups,penalty=penalty,
67
+ unique_trajectories=len({tuple(c.flatten().tolist()) for c in codes}),
68
+ mean_pairwise_token_difference_fraction=sum(pair)/len(pair),
69
+ pairwise_token_difference_fraction=pair,different_token_positions=sum(perframe),
70
+ different_positions_per_frame=perframe,model_log_scores=raw[selected].tolist(),
71
+ search_scores=scores[selected].tolist(),score_is_behavior_logprob=False,
72
+ on_policy_grpo=False,frames=traces)
code/src/futureworlds/text_conditioning.py ADDED
@@ -0,0 +1,73 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Pretrained-text conditioning with zero-initialized residual cross-attention.
2
+
3
+ Frozen T5 features are inputs, not vocabulary IDs. Visual/action positions and
4
+ vocabulary stay unchanged. No-text requests bypass the added residual exactly.
5
+ """
6
+ import torch
7
+ _UNSET = object()
8
+ from torch import nn
9
+ import torch.nn.functional as F
10
+
11
+
12
+ class TextResidual(nn.Module):
13
+ def __init__(self, hidden=768, text_width=768, inner=256, heads=4):
14
+ super().__init__();self.heads=heads;self.inner=inner
15
+ self.query_norm=nn.LayerNorm(hidden)
16
+ self.text_norm=nn.LayerNorm(text_width)
17
+ self.q=nn.Linear(hidden,inner,bias=False)
18
+ self.k=nn.Linear(text_width,inner,bias=False)
19
+ self.v=nn.Linear(text_width,inner,bias=False)
20
+ self.out=nn.Linear(inner,hidden,bias=False)
21
+ nn.init.zeros_(self.out.weight)
22
+ def forward(self, hidden, text, mask):
23
+ b,t,_=hidden.shape
24
+ if text.shape[0]!=b:
25
+ assert text.shape[0]==1, 'Generation expansion is valid only within a single episode'
26
+ text=text.expand(b,-1,-1);mask=mask.expand(b,-1)
27
+ dim=self.inner//self.heads
28
+ q=self.q(self.query_norm(hidden)).view(b,t,self.heads,dim).transpose(1,2)
29
+ memory=self.text_norm(text)
30
+ k=self.k(memory).view(b,-1,self.heads,dim).transpose(1,2)
31
+ v=self.v(memory).view(b,-1,self.heads,dim).transpose(1,2)
32
+ value=F.scaled_dot_product_attention(q,k,v,attn_mask=mask[:,None,None,:].bool(),dropout_p=0.)
33
+ value=value.transpose(1,2).reshape(b,t,self.inner)
34
+ # Explicitly suppress all-padding / deliberately dropped instruction.
35
+ value=self.out(value)*mask.any(-1)[:,None,None].to(value.dtype)
36
+ return hidden+value.to(hidden.dtype)
37
+
38
+
39
+ class TextWorldModel(nn.Module):
40
+ def __init__(self, core, text_width=768, layers=(3,7,11), inner=256):
41
+ super().__init__();self.core=core;self.layers=list(layers)
42
+ self.adapters=nn.ModuleDict({str(i):TextResidual(core.config.hidden_size,text_width,inner) for i in layers})
43
+ self._text=None;self._mask=None;self._handles=[]
44
+ for i in layers:
45
+ self._handles.append(core.model.layers[i].register_forward_pre_hook(self._hook(i),with_kwargs=True))
46
+ def _hook(self,index):
47
+ def hook(module,args,kwargs):
48
+ if self._text is None:return args,kwargs
49
+ adapter=self.adapters[str(index)]
50
+ if args:
51
+ return (adapter(args[0],self._text,self._mask),)+args[1:],kwargs
52
+ kw=dict(kwargs);kw['hidden_states']=adapter(kw['hidden_states'],self._text,self._mask)
53
+ return args,kw
54
+ return hook
55
+ def set_text(self,text,mask):
56
+ assert (text is None)==(mask is None)
57
+ if text is not None:
58
+ assert text.ndim==3 and mask.shape==text.shape[:2]
59
+ assert torch.isfinite(text).all()
60
+ self._text=text;self._mask=mask
61
+ def forward(self,text_features=_UNSET,text_mask=_UNSET,**kwargs):
62
+ # Generation and selected-token scoring use the explicitly bound episode.
63
+ # No activation checkpointing: mutable conditioning cannot change during replay.
64
+ if text_features is not _UNSET:
65
+ assert text_mask is not _UNSET
66
+ self.set_text(text_features,text_mask)
67
+ else:
68
+ assert text_mask is _UNSET
69
+ return self.core(**kwargs)
70
+ def generate(self,*args,**kwargs):
71
+ # Caller sets the same episode instruction before every generated frame.
72
+ return self.core.generate(*args,**kwargs)
73
+ def compute_transition_scores(self,*args,**kwargs):return self.core.compute_transition_scores(*args,**kwargs)
robocasa/README.md ADDED
@@ -0,0 +1,50 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ language:
3
+ - en
4
+ tags:
5
+ - futureworlds
6
+ - world-model
7
+ - robotics
8
+ - video-prediction
9
+ - reinforcement-learning
10
+ ---
11
+ # FutureWorlds — RoboCasa
12
+
13
+ Local release candidate, not yet published. Model weights are verified by CPU SHA-256; end-to-end inference with the portable RGB pipeline is not yet validated.
14
+
15
+ ## Checkpoint variants
16
+
17
+ | Folder | Method | Updates | Use |
18
+ |---|---|---:|---|
19
+ | `models/main` | MemSPO (R0) | 400 | Paper main table |
20
+ | `models/sft` | SFT | 50,000 | Initialization/control |
21
+ | `models/memspo200` | MemSPO (R0) | 200 | Matched ablation |
22
+ | `models/grpo200` | GRPO (R0) | 200 | Matched ablation |
23
+ | `models/ordinary200` | Ordinary global beam8, top4 (R0) | 200 | Proposal-strategy ablation |
24
+
25
+ All post-training checkpoints start from their paired SFT checkpoint. `main` and `memspo200` must not be interchanged.
26
+
27
+ ## Main-table evaluation
28
+
29
+ 128 trajectories, 32 predicted frames, 2 initial observations, per-frame Beam4, anchor1 + recent6, no true-future refresh. Recorded split: held-out test; runtime: GPU FP32.
30
+
31
+ | PSNR ↑ | SSIM ↑ | LPIPS ↓ |
32
+ |---:|---:|---:|
33
+ | 18.4719 | 0.765948 | 0.183338 |
34
+
35
+ These are recorded paper results; staging weights does not constitute a fresh reproduction.
36
+
37
+ ## Required components
38
+
39
+ - Dataset-specific `codec/` and `preprocessing/` files, paired by the manifest.
40
+ - Trained text adapters in each checkpoint and frozen T5-base at revision `a9723ea7f1b39c1eae772870f3b547bf6ef7e6c1`; T5 is referenced, not duplicated.
41
+ - 52 action tokens per predicted frame. RoboCasa uses four ordered 13-dimensional control blocks; do not flatten time in a different order.
42
+ - Original FP32 safetensors; no post-hoc quantization or checkpoint merging.
43
+
44
+ ## Loading and scope
45
+
46
+ Use `futureworlds.checkpoints.load_world_model(bundle_root, "robocasa", variant="main")` for the predictor only. This does not decode RGB, prepare actions, or download T5 automatically. A complete RGB demo and clean-environment GPU equivalence run remain pending. These models are custom action-conditioned predictors, not generic `pipeline("text-to-video")` models.
47
+
48
+ ## Provenance and limitations
49
+
50
+ Core architecture and tokenizer derive from RLVR-World/iVideoGPT. Upstream license texts are included under `licenses/`; the license for original additions is not yet selected. The raw datasets and third-party baseline weights are not included. Learned-world feedback examples are qualitative generated trajectories, not independently verified physical task-success results.
robocasa/codec/config.json ADDED
@@ -0,0 +1,40 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "_class_name": "CompressiveVQModelFSQ",
3
+ "_diffusers_version": "0.35.2",
4
+ "act_fn": "silu",
5
+ "block_out_channels": [
6
+ 128,
7
+ 256,
8
+ 256,
9
+ 512
10
+ ],
11
+ "context_length": 1,
12
+ "down_block_types": [
13
+ "DownEncoderBlock2D",
14
+ "DownEncoderBlock2D",
15
+ "DownEncoderBlock2D",
16
+ "DownEncoderBlock2D"
17
+ ],
18
+ "dyn_fsq_levels": 12,
19
+ "force_upcast": true,
20
+ "in_channels": 3,
21
+ "latent_channels": 64,
22
+ "layers_per_block": 2,
23
+ "lookup_from_codebook": true,
24
+ "max_att_resolution": 32,
25
+ "mid_block_add_attention": false,
26
+ "norm_num_groups": 32,
27
+ "norm_type": "group",
28
+ "out_channels": 3,
29
+ "patch_size": 4,
30
+ "resolution": 256,
31
+ "sample_size": 32,
32
+ "scaling_factor": 0.18215,
33
+ "up_block_types": [
34
+ "UpDecoderBlock2D",
35
+ "UpDecoderBlock2D",
36
+ "UpDecoderBlock2D",
37
+ "UpDecoderBlock2D"
38
+ ],
39
+ "vq_fsq_levels": 12
40
+ }
robocasa/codec/diffusion_pytorch_model.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:4ea6133eae9d3deba4fc546ac7d0cb318363d0d79372b29a8e7d1a753023b77d
3
+ size 517850360
robocasa/futureworlds_config.json ADDED
@@ -0,0 +1,77 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "schema_version": 1,
3
+ "dataset": "robocasa",
4
+ "status": "staged_research_preview",
5
+ "codec": "robocasa/codec",
6
+ "action_ranges": "robocasa/preprocessing/action_ranges.pt",
7
+ "action_tokens_per_step": 52,
8
+ "text_conditioning": {
9
+ "enabled": true,
10
+ "repo_id": "google-t5/t5-base",
11
+ "revision": "a9723ea7f1b39c1eae772870f3b547bf6ef7e6c1",
12
+ "layers": [
13
+ 3,
14
+ 7,
15
+ 11
16
+ ],
17
+ "inner": 256,
18
+ "width": 768,
19
+ "max_tokens": 128,
20
+ "bundled": false
21
+ },
22
+ "initial_observations": 2,
23
+ "memory": {
24
+ "anchor_states": 1,
25
+ "recent_states": 6,
26
+ "ground_truth_refresh": false
27
+ },
28
+ "evaluation": {
29
+ "strategy": "per_frame_beam",
30
+ "beam_width": 4,
31
+ "horizon": 32,
32
+ "visual_tokens_per_frame": 80,
33
+ "valid_visual_vocab": 4375
34
+ },
35
+ "variants": {
36
+ "main": {
37
+ "path": "robocasa/models/main",
38
+ "method": "MemSPO",
39
+ "updates": 400,
40
+ "reward": "R0",
41
+ "purpose": "paper_main_table",
42
+ "text": true
43
+ },
44
+ "sft": {
45
+ "path": "robocasa/models/sft",
46
+ "method": "SFT",
47
+ "updates": 50000,
48
+ "reward": null,
49
+ "purpose": "matched_ablation",
50
+ "text": true
51
+ },
52
+ "memspo200": {
53
+ "path": "robocasa/models/memspo200",
54
+ "method": "MemSPO",
55
+ "updates": 200,
56
+ "reward": "R0",
57
+ "purpose": "matched_ablation",
58
+ "text": true
59
+ },
60
+ "grpo200": {
61
+ "path": "robocasa/models/grpo200",
62
+ "method": "GRPO",
63
+ "updates": 200,
64
+ "reward": "R0",
65
+ "purpose": "matched_ablation",
66
+ "text": true
67
+ },
68
+ "ordinary200": {
69
+ "path": "robocasa/models/ordinary200",
70
+ "method": "OrdinaryBeam",
71
+ "updates": 200,
72
+ "reward": "R0",
73
+ "purpose": "matched_ablation",
74
+ "text": true
75
+ }
76
+ }
77
+ }
robocasa/models/grpo200/config.json ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "architectures": [
3
+ "LlamaForCausalLM"
4
+ ],
5
+ "attention_bias": false,
6
+ "attention_dropout": 0.0,
7
+ "bos_token_id": 9006,
8
+ "dtype": "float32",
9
+ "eos_token_id": 9007,
10
+ "head_dim": 64,
11
+ "hidden_act": "silu",
12
+ "hidden_size": 768,
13
+ "initializer_range": 0.02,
14
+ "intermediate_size": 3072,
15
+ "max_length": null,
16
+ "max_position_embeddings": 8192,
17
+ "mlp_bias": false,
18
+ "model_type": "llama",
19
+ "num_attention_heads": 12,
20
+ "num_hidden_layers": 12,
21
+ "num_key_value_heads": 12,
22
+ "pretraining_tp": 1,
23
+ "rms_norm_eps": 1e-06,
24
+ "rope_scaling": null,
25
+ "rope_theta": 10000.0,
26
+ "tie_word_embeddings": false,
27
+ "transformers_version": "4.57.1",
28
+ "use_cache": true,
29
+ "vocab_size": 9008
30
+ }
robocasa/models/grpo200/generation_config.json ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ {
2
+ "_from_model_config": true,
3
+ "bos_token_id": 9006,
4
+ "eos_token_id": 9007,
5
+ "transformers_version": "4.57.1"
6
+ }
robocasa/models/grpo200/model.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:af36ba44677963a0de2753dcf933c46f616505792fe4d6668138adc2d8e59720
3
+ size 508419080
robocasa/models/grpo200/text_adapters.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:eba7ba8715d82c79f8909a8d65cf3ede5f1874b0963efcd3a351f2f8ca13633c
3
+ size 9476032
robocasa/models/main/config.json ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "architectures": [
3
+ "LlamaForCausalLM"
4
+ ],
5
+ "attention_bias": false,
6
+ "attention_dropout": 0.0,
7
+ "bos_token_id": 9006,
8
+ "dtype": "float32",
9
+ "eos_token_id": 9007,
10
+ "head_dim": 64,
11
+ "hidden_act": "silu",
12
+ "hidden_size": 768,
13
+ "initializer_range": 0.02,
14
+ "intermediate_size": 3072,
15
+ "max_length": null,
16
+ "max_position_embeddings": 8192,
17
+ "mlp_bias": false,
18
+ "model_type": "llama",
19
+ "num_attention_heads": 12,
20
+ "num_hidden_layers": 12,
21
+ "num_key_value_heads": 12,
22
+ "pretraining_tp": 1,
23
+ "rms_norm_eps": 1e-06,
24
+ "rope_scaling": null,
25
+ "rope_theta": 10000.0,
26
+ "tie_word_embeddings": false,
27
+ "transformers_version": "4.57.1",
28
+ "use_cache": true,
29
+ "vocab_size": 9008
30
+ }
robocasa/models/main/generation_config.json ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ {
2
+ "_from_model_config": true,
3
+ "bos_token_id": 9006,
4
+ "eos_token_id": 9007,
5
+ "transformers_version": "4.57.1"
6
+ }
robocasa/models/main/model.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:a0d4420b480f44f9f1f970edbfc96a95adb5e428dc6b49ca3d1b2c61fddb5807
3
+ size 508419080
robocasa/models/main/text_adapters.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:92ad8666771696ee22f6c7aaee12d9bd8bd6195569298defb1b89b3bcba11d1e
3
+ size 9476032
robocasa/models/memspo200/config.json ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "architectures": [
3
+ "LlamaForCausalLM"
4
+ ],
5
+ "attention_bias": false,
6
+ "attention_dropout": 0.0,
7
+ "bos_token_id": 9006,
8
+ "dtype": "float32",
9
+ "eos_token_id": 9007,
10
+ "head_dim": 64,
11
+ "hidden_act": "silu",
12
+ "hidden_size": 768,
13
+ "initializer_range": 0.02,
14
+ "intermediate_size": 3072,
15
+ "max_length": null,
16
+ "max_position_embeddings": 8192,
17
+ "mlp_bias": false,
18
+ "model_type": "llama",
19
+ "num_attention_heads": 12,
20
+ "num_hidden_layers": 12,
21
+ "num_key_value_heads": 12,
22
+ "pretraining_tp": 1,
23
+ "rms_norm_eps": 1e-06,
24
+ "rope_scaling": null,
25
+ "rope_theta": 10000.0,
26
+ "tie_word_embeddings": false,
27
+ "transformers_version": "4.57.1",
28
+ "use_cache": true,
29
+ "vocab_size": 9008
30
+ }
robocasa/models/memspo200/generation_config.json ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ {
2
+ "_from_model_config": true,
3
+ "bos_token_id": 9006,
4
+ "eos_token_id": 9007,
5
+ "transformers_version": "4.57.1"
6
+ }
robocasa/models/memspo200/model.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:6193281a747b6155cb32b7e4e3844f1ff05ac0e07d9df4cd3f11bba4c8711d92
3
+ size 508419080
robocasa/models/memspo200/text_adapters.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:2c9f8ac2cc6c128fc29305546a29effbd99250f47905e7711a8330a397bfd7c0
3
+ size 9476032
robocasa/models/ordinary200/config.json ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "architectures": [
3
+ "LlamaForCausalLM"
4
+ ],
5
+ "attention_bias": false,
6
+ "attention_dropout": 0.0,
7
+ "bos_token_id": 9006,
8
+ "dtype": "float32",
9
+ "eos_token_id": 9007,
10
+ "head_dim": 64,
11
+ "hidden_act": "silu",
12
+ "hidden_size": 768,
13
+ "initializer_range": 0.02,
14
+ "intermediate_size": 3072,
15
+ "max_length": null,
16
+ "max_position_embeddings": 8192,
17
+ "mlp_bias": false,
18
+ "model_type": "llama",
19
+ "num_attention_heads": 12,
20
+ "num_hidden_layers": 12,
21
+ "num_key_value_heads": 12,
22
+ "pretraining_tp": 1,
23
+ "rms_norm_eps": 1e-06,
24
+ "rope_scaling": null,
25
+ "rope_theta": 10000.0,
26
+ "tie_word_embeddings": false,
27
+ "transformers_version": "4.57.1",
28
+ "use_cache": true,
29
+ "vocab_size": 9008
30
+ }
robocasa/models/ordinary200/generation_config.json ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ {
2
+ "_from_model_config": true,
3
+ "bos_token_id": 9006,
4
+ "eos_token_id": 9007,
5
+ "transformers_version": "4.57.1"
6
+ }
robocasa/models/ordinary200/model.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:486a6c324466839121a4fb392450b1093e98d7482dbb9b6c794baf4ebb7b1519
3
+ size 508419080
robocasa/models/ordinary200/text_adapters.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:c4fc6d76fe21e5687fa7dd4cb2c82da0b3c52554490be6211e22aa4fabc85900
3
+ size 9476032
robocasa/models/sft/config.json ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "architectures": [
3
+ "LlamaForCausalLM"
4
+ ],
5
+ "attention_bias": false,
6
+ "attention_dropout": 0.0,
7
+ "bos_token_id": 9006,
8
+ "dtype": "float32",
9
+ "eos_token_id": 9007,
10
+ "head_dim": 64,
11
+ "hidden_act": "silu",
12
+ "hidden_size": 768,
13
+ "initializer_range": 0.02,
14
+ "intermediate_size": 3072,
15
+ "max_length": null,
16
+ "max_position_embeddings": 8192,
17
+ "mlp_bias": false,
18
+ "model_type": "llama",
19
+ "num_attention_heads": 12,
20
+ "num_hidden_layers": 12,
21
+ "num_key_value_heads": 12,
22
+ "pretraining_tp": 1,
23
+ "rms_norm_eps": 1e-06,
24
+ "rope_scaling": null,
25
+ "rope_theta": 10000.0,
26
+ "tie_word_embeddings": false,
27
+ "transformers_version": "4.57.1",
28
+ "use_cache": true,
29
+ "vocab_size": 9008
30
+ }
robocasa/models/sft/generation_config.json ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ {
2
+ "_from_model_config": true,
3
+ "bos_token_id": 9006,
4
+ "eos_token_id": 9007,
5
+ "transformers_version": "4.57.1"
6
+ }
robocasa/models/sft/model.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:a86d465e8b5c1cc824238b010aed477ea61d6d8307102135b886b32ca065463c
3
+ size 508419080
robocasa/models/sft/text_adapters.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:ef8a06e8ba6451ad1873d9476400c04ae581ce8e654ca77958f7cc56d9f6b380
3
+ size 9476032
robocasa/preprocessing/action_ranges.pt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:55531c0e5296d01b8eb78aa941b422bde30e80e458a24d362f874671f2dbfaf4
3
+ size 2003
robocasa/training_recipe.json ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "max_text_tokens": 128,
3
+ "text_layers": [
4
+ 3,
5
+ 7,
6
+ 11
7
+ ],
8
+ "text_inner": 256,
9
+ "seed": 20260918,
10
+ "sft_steps": 50000,
11
+ "sft_global_batch": 64,
12
+ "core_lr": 1e-05,
13
+ "adapter_lr": 0.0001,
14
+ "warmup_steps": 500,
15
+ "rl_steps": 500,
16
+ "rl_lr": 1e-06,
17
+ "kl_coef": 0.001,
18
+ "clip": 0.2,
19
+ "horizon": 10,
20
+ "groups": 4,
21
+ "beams_per_group": 2,
22
+ "diversity_penalty": 0.1
23
+ }
rt1/models/main/text_adapters.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:c426c478c690679230b613401b59f8d17bc7863b33450ba12964d42722b489cd
3
+ size 9476032
rt1/models/sft/text_adapters.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:006511fd5bbfdeb2f6975695415243b5cec4912517c7f187e65864a48ecfcf07
3
+ size 9476032