anhtld commited on
Commit
b56cdca
·
verified ·
1 Parent(s): dd9b9f1

Auto-sync: 2026-06-25 23:02:08 (part 2)

Browse files
Files changed (1) hide show
  1. scripts/merge_task_datasets.py +143 -0
scripts/merge_task_datasets.py ADDED
@@ -0,0 +1,143 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ """
3
+ Merge multiple task-specific h=16 datasets into single training-ready dataset.
4
+ Creates unified manifest and symlinks to shards.
5
+ """
6
+ import json
7
+ import shutil
8
+ from pathlib import Path
9
+ import argparse
10
+
11
+ def merge_datasets(task_dirs, output_dir):
12
+ """Merge multiple CIL datasets into one."""
13
+ output_dir = Path(output_dir)
14
+ output_dir.mkdir(parents=True, exist_ok=True)
15
+
16
+ # Collect all manifests
17
+ all_groups = []
18
+ all_group_index = []
19
+ all_record_index = []
20
+ total_records = 0
21
+ shard_counter = 0
22
+
23
+ for task_dir in task_dirs:
24
+ task_path = Path(task_dir)
25
+ manifest_path = task_path / "manifest.json"
26
+
27
+ if not manifest_path.exists():
28
+ print(f"⚠️ Skipping {task_path.name} (no manifest)")
29
+ continue
30
+
31
+ print(f"Processing {task_path.name}...")
32
+ manifest = json.loads(manifest_path.read_text())
33
+
34
+ # Copy shard files (rename to .jsonl for compatibility)
35
+ for shard_info in manifest.get("shards", []):
36
+ shard_file = task_path / shard_info["path"]
37
+ if shard_file.exists():
38
+ dest = output_dir / f"shard_{shard_counter:04d}.jsonl"
39
+ shutil.copy2(shard_file, dest)
40
+ shard_counter += 1
41
+
42
+ # Fallback: glob for .shard files if shards key missing
43
+ if not manifest.get("shards"):
44
+ for shard_file in task_path.glob("*.shard"):
45
+ dest = output_dir / f"shard_{shard_counter:04d}.jsonl"
46
+ shutil.copy2(shard_file, dest)
47
+ shard_counter += 1
48
+
49
+ # Read and merge group index
50
+ group_index_path = task_path / manifest.get("group_index_path", "group_index.jsonl")
51
+ if group_index_path.exists():
52
+ with open(group_index_path) as f:
53
+ for line in f:
54
+ if line.strip():
55
+ entry = json.loads(line)
56
+ all_groups.append(entry["group_id"])
57
+ all_group_index.append(entry)
58
+
59
+ # Read and merge record index
60
+ record_index_path = task_path / manifest.get("record_index_path", "record_index.jsonl")
61
+ if record_index_path.exists():
62
+ with open(record_index_path) as f:
63
+ for line in f:
64
+ if line.strip():
65
+ all_record_index.append(json.loads(line))
66
+
67
+ # Accumulate metadata
68
+ total_records += manifest["record_count"]
69
+
70
+ print(f" ✅ {manifest['group_count']} groups, {manifest['record_count']} records")
71
+
72
+ # Write merged indexes
73
+ group_index_out = output_dir / "group_index.jsonl"
74
+ with open(group_index_out, 'w') as f:
75
+ for entry in all_group_index:
76
+ f.write(json.dumps(entry) + '\n')
77
+
78
+ record_index_out = output_dir / "record_index.jsonl"
79
+ with open(record_index_out, 'w') as f:
80
+ for entry in all_record_index:
81
+ f.write(json.dumps(entry) + '\n')
82
+
83
+ # Create unified manifest
84
+ shard_list = [{"path": f"shard_{i:04d}.jsonl"} for i in range(shard_counter)]
85
+
86
+ merged_manifest = {
87
+ "backend": "maniskill",
88
+ "created_at": Path(task_dirs[0]).joinpath("manifest.json").stat().st_mtime if task_dirs else 0,
89
+ "dataset_name": "cil_h16_merged",
90
+ "format": "dovla_cil",
91
+ "group_count": len(all_groups),
92
+ "group_index_path": "group_index.jsonl",
93
+ "index_format": "jsonl",
94
+ "k": 16,
95
+ "num_groups": len(all_groups),
96
+ "num_records": total_records,
97
+ "record_count": total_records,
98
+ "record_index_path": "record_index.jsonl",
99
+ "schema_version": "0.1",
100
+ "shard_count": shard_counter,
101
+ "shard_format": "jsonl",
102
+ "shards": shard_list,
103
+ "horizon": 16,
104
+ "tasks": [Path(d).name for d in task_dirs if (Path(d) / "manifest.json").exists()]
105
+ }
106
+
107
+ manifest_out = output_dir / "manifest.json"
108
+ manifest_out.write_text(json.dumps(merged_manifest, indent=2))
109
+
110
+ print("\n" + "="*60)
111
+ print(f"✅ Merged dataset created: {output_dir}")
112
+ print(f" Total groups: {merged_manifest['group_count']}")
113
+ print(f" Total records: {merged_manifest['record_count']}")
114
+ print(f" Shards: {merged_manifest['shard_count']}")
115
+ print(f" Tasks: {', '.join(merged_manifest['tasks'])}")
116
+ print("="*60)
117
+
118
+ return merged_manifest
119
+
120
+ def main():
121
+ parser = argparse.ArgumentParser()
122
+ parser.add_argument("--input", required=True, help="Parent dir containing task subdirs")
123
+ parser.add_argument("--output", required=True, help="Output merged dataset dir")
124
+ args = parser.parse_args()
125
+
126
+ input_path = Path(args.input)
127
+ task_dirs = [d for d in input_path.iterdir() if d.is_dir() and (d / "manifest.json").exists()]
128
+
129
+ if not task_dirs:
130
+ print(f"❌ No valid task directories found in {input_path}")
131
+ return 1
132
+
133
+ print(f"Found {len(task_dirs)} tasks to merge:")
134
+ for d in task_dirs:
135
+ print(f" - {d.name}")
136
+ print()
137
+
138
+ merge_datasets(task_dirs, args.output)
139
+ return 0
140
+
141
+ if __name__ == "__main__":
142
+ import sys
143
+ sys.exit(main())