jbilcke-hf commited on
Commit
74cf591
Β·
verified Β·
1 Parent(s): 0c5ee34

Upload opentrack.ipynb

Browse files
Files changed (1) hide show
  1. samples/opentrack.ipynb +148 -38
samples/opentrack.ipynb CHANGED
@@ -33,7 +33,19 @@
33
  "import threading\n",
34
  "import queue\n",
35
  "\n",
36
- "print(\"Environment setup complete!\")"
 
 
 
 
 
 
 
 
 
 
 
 
37
  ]
38
  },
39
  {
@@ -50,14 +62,19 @@
50
  "outputs": [],
51
  "source": [
52
  "# Clone the repository if not already cloned\n",
53
- "if not os.path.exists('OpenTrack'):\n",
54
- " !git clone https://github.com/GalaxyGeneralRobotics/OpenTrack.git\n",
 
 
 
 
55
  " print(\"βœ“ Repository cloned successfully\")\n",
56
  "else:\n",
57
- " print(\"βœ“ Repository already exists\")\n",
58
  "\n",
59
- "os.chdir('OpenTrack')\n",
60
- "print(f\"Current directory: {os.getcwd()}\")"
 
61
  ]
62
  },
63
  {
@@ -100,23 +117,23 @@
100
  "source": [
101
  "from huggingface_hub import snapshot_download\n",
102
  "\n",
103
- "# Create directory structure\n",
104
- "mocap_dir = Path(\"data/mocap/lafan1/UnitreeG1\")\n",
105
  "mocap_dir.mkdir(parents=True, exist_ok=True)\n",
106
  "\n",
107
  "repo_id = \"robfiras/loco-mujoco-datasets\"\n",
108
  "\n",
109
  "print(\"Downloading all mocap data from Lafan1/mocap/UnitreeG1...\")\n",
 
110
  "print(\"This will download all .npz files concurrently.\\n\")\n",
111
  "\n",
112
  "try:\n",
113
  " # Use snapshot_download with allow_patterns to download only the files we need\n",
114
- " # This is much more efficient than downloading files one by one\n",
115
  " snapshot_path = snapshot_download(\n",
116
  " repo_id=repo_id,\n",
117
  " repo_type=\"dataset\",\n",
118
  " allow_patterns=\"Lafan1/mocap/UnitreeG1/*.npz\",\n",
119
- " local_dir=\".\",\n",
120
  " local_dir_use_symlinks=False\n",
121
  " )\n",
122
  " \n",
@@ -133,6 +150,22 @@
133
  " if len(npz_files) > 10:\n",
134
  " print(f\" ... and {len(npz_files) - 10} more files\")\n",
135
  " \n",
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
136
  "except Exception as e:\n",
137
  " print(f\"⚠ Error downloading mocap data: {e}\")\n",
138
  " print(\"\\nYou may need to download manually from:\")\n",
@@ -190,38 +223,76 @@
190
  " \"\"\"\n",
191
  " Find the latest experiment folder matching the pattern\n",
192
  " \"\"\"\n",
193
- " logs_dir = Path(\"logs\")\n",
194
- " if not logs_dir.exists():\n",
195
- " return None\n",
196
  " \n",
197
- " # Find all matching experiments\n",
198
- " experiments = sorted(\n",
199
- " [d for d in logs_dir.iterdir() if d.is_dir() and exp_name_pattern in d.name],\n",
200
- " key=lambda x: x.stat().st_mtime,\n",
201
- " reverse=True\n",
202
- " )\n",
 
 
 
 
 
 
 
 
203
  " \n",
204
- " return experiments[0].name if experiments else None\n",
 
 
205
  "\n",
206
  "\n",
207
- "def find_generated_videos(output_dir=\"videos\"):\n",
208
  " \"\"\"\n",
209
  " Find all generated video files\n",
210
  " \"\"\"\n",
211
- " video_dir = Path(output_dir)\n",
212
- " if not video_dir.exists():\n",
 
 
 
 
 
 
 
 
 
213
  " # Try alternative locations\n",
214
- " alternative_dirs = [\".\", \"logs\", \"outputs\"]\n",
215
  " for alt_dir in alternative_dirs:\n",
216
- " alt_path = Path(alt_dir)\n",
217
- " videos = list(alt_path.glob(\"**/*.mp4\")) + list(alt_path.glob(\"**/*.gif\"))\n",
218
- " if videos:\n",
219
- " return sorted(videos, key=lambda x: x.stat().st_mtime, reverse=True)\n",
220
- " return []\n",
221
  " \n",
222
- " videos = list(video_dir.glob(\"*.mp4\")) + list(video_dir.glob(\"*.gif\"))\n",
223
  " return sorted(videos, key=lambda x: x.stat().st_mtime, reverse=True)\n",
224
  "\n",
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
225
  "print(\"βœ“ Helper functions loaded\")"
226
  ]
227
  },
@@ -240,6 +311,11 @@
240
  "metadata": {},
241
  "outputs": [],
242
  "source": [
 
 
 
 
 
243
  "# Run quick training\n",
244
  "cmd = [\n",
245
  " 'python', 'train_policy.py',\n",
@@ -253,6 +329,7 @@
253
  "exp_folder = find_latest_experiment('debug')\n",
254
  "if exp_folder:\n",
255
  " print(f\"\\nβœ“ Training completed! Experiment: {exp_folder}\")\n",
 
256
  "else:\n",
257
  " print(\"\\n⚠ Could not find experiment folder\")"
258
  ]
@@ -306,6 +383,7 @@
306
  "\n",
307
  "if exp_folder:\n",
308
  " print(f\"Generating videos for: {exp_folder}\")\n",
 
309
  " \n",
310
  " # Use --use_renderer for headless video generation (NOT --use_viewer)\n",
311
  " cmd = [\n",
@@ -327,14 +405,28 @@
327
  " # Find generated videos\n",
328
  " videos = find_generated_videos()\n",
329
  " \n",
 
 
 
 
 
 
 
 
 
 
 
 
 
 
330
  " if videos:\n",
331
- " print(f\"\\nβœ“ Found {len(videos)} video(s):\")\n",
332
  " for video in videos:\n",
333
  " print(f\" - {video}\")\n",
334
  " else:\n",
335
  " print(\"\\n⚠ No videos found. Checking alternative locations...\")\n",
336
  " # Search more broadly\n",
337
- " all_videos = list(Path(\".\").rglob(\"*.mp4\")) + list(Path(\".\").rglob(\"*.gif\"))\n",
338
  " if all_videos:\n",
339
  " print(f\"Found {len(all_videos)} video(s) in project:\")\n",
340
  " for video in all_videos[:10]: # Show first 10\n",
@@ -356,19 +448,20 @@
356
  "metadata": {},
357
  "outputs": [],
358
  "source": [
359
- "# Find and display all generated videos\n",
360
  "videos = find_generated_videos()\n",
361
  "\n",
362
  "if not videos:\n",
363
- " # Try alternative search\n",
364
- " videos = list(Path(\".\").rglob(\"*.mp4\")) + list(Path(\".\").rglob(\"*.gif\"))\n",
365
  "\n",
366
  "if videos:\n",
367
- " print(f\"Displaying {len(videos)} video(s):\\n\")\n",
368
  " \n",
369
  " for i, video_path in enumerate(videos[:5]): # Display first 5 videos\n",
370
  " print(f\"\\n{'='*60}\")\n",
371
  " print(f\"Video {i+1}: {video_path.name}\")\n",
 
372
  " print(f\"{'='*60}\")\n",
373
  " \n",
374
  " try:\n",
@@ -456,16 +549,33 @@
456
  "4. βœ… Generating videos using headless MuJoCo renderer\n",
457
  "5. βœ… Displaying videos in the notebook\n",
458
  "\n",
 
 
 
 
 
 
 
 
 
 
 
 
 
 
459
  "**Next Steps:**\n",
460
- "- Download more mocap files for better training\n",
461
  "- Run full training with GPU support\n",
462
  "- Test on rough terrain\n",
463
  "- Experiment with reference motion playback\n",
 
 
464
  "\n",
465
  "**Troubleshooting:**\n",
466
  "- If videos aren't generated, check that `--use_renderer` flag is used (not `--use_viewer`)\n",
467
  "- Ensure MuJoCo can run headless (may need `xvfb` on some systems)\n",
468
- "- Check `logs/` directory for experiment outputs"
 
469
  ]
470
  }
471
  ],
 
33
  "import threading\n",
34
  "import queue\n",
35
  "\n",
36
+ "# Define project directory structure\n",
37
+ "PROJECT_BASE = Path(\"/data/workspaces/opentrack\")\n",
38
+ "DATASETS_DIR = PROJECT_BASE / \"datasets\"\n",
39
+ "MODELS_DIR = PROJECT_BASE / \"models\"\n",
40
+ "VIDEOS_DIR = PROJECT_BASE / \"videos\"\n",
41
+ "REPO_DIR = PROJECT_BASE / \"OpenTrack\"\n",
42
+ "\n",
43
+ "# Create directories\n",
44
+ "for dir_path in [PROJECT_BASE, DATASETS_DIR, MODELS_DIR, VIDEOS_DIR]:\n",
45
+ " dir_path.mkdir(parents=True, exist_ok=True)\n",
46
+ " print(f\"βœ“ {dir_path}\")\n",
47
+ "\n",
48
+ "print(\"\\nβœ“ Environment setup complete!\")"
49
  ]
50
  },
51
  {
 
62
  "outputs": [],
63
  "source": [
64
  "# Clone the repository if not already cloned\n",
65
+ "if not REPO_DIR.exists():\n",
66
+ " print(f\"Cloning OpenTrack to {REPO_DIR}...\")\n",
67
+ " subprocess.run(\n",
68
+ " ['git', 'clone', 'https://github.com/GalaxyGeneralRobotics/OpenTrack.git', str(REPO_DIR)],\n",
69
+ " check=True\n",
70
+ " )\n",
71
  " print(\"βœ“ Repository cloned successfully\")\n",
72
  "else:\n",
73
+ " print(f\"βœ“ Repository already exists at {REPO_DIR}\")\n",
74
  "\n",
75
+ "# Change to repository directory\n",
76
+ "os.chdir(REPO_DIR)\n",
77
+ "print(f\"\\nβœ“ Working directory: {os.getcwd()}\")"
78
  ]
79
  },
80
  {
 
117
  "source": [
118
  "from huggingface_hub import snapshot_download\n",
119
  "\n",
120
+ "# Define mocap directory in our datasets folder\n",
121
+ "mocap_dir = DATASETS_DIR / \"lafan1\" / \"UnitreeG1\"\n",
122
  "mocap_dir.mkdir(parents=True, exist_ok=True)\n",
123
  "\n",
124
  "repo_id = \"robfiras/loco-mujoco-datasets\"\n",
125
  "\n",
126
  "print(\"Downloading all mocap data from Lafan1/mocap/UnitreeG1...\")\n",
127
+ "print(f\"Target directory: {mocap_dir}\")\n",
128
  "print(\"This will download all .npz files concurrently.\\n\")\n",
129
  "\n",
130
  "try:\n",
131
  " # Use snapshot_download with allow_patterns to download only the files we need\n",
 
132
  " snapshot_path = snapshot_download(\n",
133
  " repo_id=repo_id,\n",
134
  " repo_type=\"dataset\",\n",
135
  " allow_patterns=\"Lafan1/mocap/UnitreeG1/*.npz\",\n",
136
+ " local_dir=str(DATASETS_DIR),\n",
137
  " local_dir_use_symlinks=False\n",
138
  " )\n",
139
  " \n",
 
150
  " if len(npz_files) > 10:\n",
151
  " print(f\" ... and {len(npz_files) - 10} more files\")\n",
152
  " \n",
153
+ " # Create symlink from OpenTrack's expected data directory to our datasets\n",
154
+ " opentrack_data_dir = REPO_DIR / \"data\" / \"mocap\"\n",
155
+ " opentrack_data_dir.parent.mkdir(parents=True, exist_ok=True)\n",
156
+ " \n",
157
+ " # Remove old symlink/directory if it exists\n",
158
+ " if opentrack_data_dir.exists() or opentrack_data_dir.is_symlink():\n",
159
+ " if opentrack_data_dir.is_symlink():\n",
160
+ " opentrack_data_dir.unlink()\n",
161
+ " else:\n",
162
+ " import shutil\n",
163
+ " shutil.rmtree(opentrack_data_dir)\n",
164
+ " \n",
165
+ " # Create symlink\n",
166
+ " opentrack_data_dir.symlink_to(DATASETS_DIR, target_is_directory=True)\n",
167
+ " print(f\"\\nβœ“ Created symlink: {opentrack_data_dir} -> {DATASETS_DIR}\")\n",
168
+ " \n",
169
  "except Exception as e:\n",
170
  " print(f\"⚠ Error downloading mocap data: {e}\")\n",
171
  " print(\"\\nYou may need to download manually from:\")\n",
 
223
  " \"\"\"\n",
224
  " Find the latest experiment folder matching the pattern\n",
225
  " \"\"\"\n",
226
+ " # Check both MODELS_DIR and REPO_DIR/logs\n",
227
+ " search_dirs = [MODELS_DIR, REPO_DIR / \"logs\"]\n",
 
228
  " \n",
229
+ " all_experiments = []\n",
230
+ " for logs_dir in search_dirs:\n",
231
+ " if not logs_dir.exists():\n",
232
+ " continue\n",
233
+ " \n",
234
+ " # Find all matching experiments\n",
235
+ " experiments = [\n",
236
+ " d for d in logs_dir.iterdir() \n",
237
+ " if d.is_dir() and exp_name_pattern in d.name\n",
238
+ " ]\n",
239
+ " all_experiments.extend(experiments)\n",
240
+ " \n",
241
+ " if not all_experiments:\n",
242
+ " return None\n",
243
  " \n",
244
+ " # Sort by modification time and return latest\n",
245
+ " latest = sorted(all_experiments, key=lambda x: x.stat().st_mtime, reverse=True)[0]\n",
246
+ " return latest.name\n",
247
  "\n",
248
  "\n",
249
+ "def find_generated_videos(output_dir=None):\n",
250
  " \"\"\"\n",
251
  " Find all generated video files\n",
252
  " \"\"\"\n",
253
+ " if output_dir is None:\n",
254
+ " output_dir = VIDEOS_DIR\n",
255
+ " else:\n",
256
+ " output_dir = Path(output_dir)\n",
257
+ " \n",
258
+ " videos = []\n",
259
+ " \n",
260
+ " if output_dir.exists():\n",
261
+ " videos = list(output_dir.glob(\"*.mp4\")) + list(output_dir.glob(\"*.gif\"))\n",
262
+ " \n",
263
+ " if not videos:\n",
264
  " # Try alternative locations\n",
265
+ " alternative_dirs = [REPO_DIR, REPO_DIR / \"logs\", MODELS_DIR]\n",
266
  " for alt_dir in alternative_dirs:\n",
267
+ " if alt_dir.exists():\n",
268
+ " found = list(alt_dir.glob(\"**/*.mp4\")) + list(alt_dir.glob(\"**/*.gif\"))\n",
269
+ " videos.extend(found)\n",
 
 
270
  " \n",
 
271
  " return sorted(videos, key=lambda x: x.stat().st_mtime, reverse=True)\n",
272
  "\n",
273
+ "\n",
274
+ "def setup_model_output_symlink():\n",
275
+ " \"\"\"\n",
276
+ " Create symlink from OpenTrack's logs directory to our models directory\n",
277
+ " \"\"\"\n",
278
+ " opentrack_logs_dir = REPO_DIR / \"logs\"\n",
279
+ " \n",
280
+ " # Remove old symlink/directory if it exists\n",
281
+ " if opentrack_logs_dir.exists() or opentrack_logs_dir.is_symlink():\n",
282
+ " if opentrack_logs_dir.is_symlink():\n",
283
+ " opentrack_logs_dir.unlink()\n",
284
+ " else:\n",
285
+ " import shutil\n",
286
+ " # Move existing logs to MODELS_DIR first\n",
287
+ " if opentrack_logs_dir.is_dir():\n",
288
+ " for item in opentrack_logs_dir.iterdir():\n",
289
+ " shutil.move(str(item), str(MODELS_DIR))\n",
290
+ " shutil.rmtree(opentrack_logs_dir)\n",
291
+ " \n",
292
+ " # Create symlink\n",
293
+ " opentrack_logs_dir.symlink_to(MODELS_DIR, target_is_directory=True)\n",
294
+ " print(f\"βœ“ Created symlink: {opentrack_logs_dir} -> {MODELS_DIR}\")\n",
295
+ "\n",
296
  "print(\"βœ“ Helper functions loaded\")"
297
  ]
298
  },
 
311
  "metadata": {},
312
  "outputs": [],
313
  "source": [
314
+ "# Setup symlink for model outputs\n",
315
+ "setup_model_output_symlink()\n",
316
+ "\n",
317
+ "print(f\"\\nModels will be saved to: {MODELS_DIR}\\n\")\n",
318
+ "\n",
319
  "# Run quick training\n",
320
  "cmd = [\n",
321
  " 'python', 'train_policy.py',\n",
 
329
  "exp_folder = find_latest_experiment('debug')\n",
330
  "if exp_folder:\n",
331
  " print(f\"\\nβœ“ Training completed! Experiment: {exp_folder}\")\n",
332
+ " print(f\"βœ“ Model saved in: {MODELS_DIR / exp_folder}\")\n",
333
  "else:\n",
334
  " print(\"\\n⚠ Could not find experiment folder\")"
335
  ]
 
383
  "\n",
384
  "if exp_folder:\n",
385
  " print(f\"Generating videos for: {exp_folder}\")\n",
386
+ " print(f\"Videos will be saved to: {VIDEOS_DIR}\\n\")\n",
387
  " \n",
388
  " # Use --use_renderer for headless video generation (NOT --use_viewer)\n",
389
  " cmd = [\n",
 
405
  " # Find generated videos\n",
406
  " videos = find_generated_videos()\n",
407
  " \n",
408
+ " # Move videos to VIDEOS_DIR if they're not already there\n",
409
+ " if videos:\n",
410
+ " import shutil\n",
411
+ " moved_videos = []\n",
412
+ " for video in videos:\n",
413
+ " if not video.is_relative_to(VIDEOS_DIR):\n",
414
+ " dest = VIDEOS_DIR / video.name\n",
415
+ " shutil.copy2(video, dest)\n",
416
+ " moved_videos.append(dest)\n",
417
+ " print(f\"Moved: {video.name} -> {dest}\")\n",
418
+ " else:\n",
419
+ " moved_videos.append(video)\n",
420
+ " videos = moved_videos\n",
421
+ " \n",
422
  " if videos:\n",
423
+ " print(f\"\\nβœ“ Found {len(videos)} video(s) in {VIDEOS_DIR}:\")\n",
424
  " for video in videos:\n",
425
  " print(f\" - {video}\")\n",
426
  " else:\n",
427
  " print(\"\\n⚠ No videos found. Checking alternative locations...\")\n",
428
  " # Search more broadly\n",
429
+ " all_videos = list(REPO_DIR.rglob(\"*.mp4\")) + list(REPO_DIR.rglob(\"*.gif\"))\n",
430
  " if all_videos:\n",
431
  " print(f\"Found {len(all_videos)} video(s) in project:\")\n",
432
  " for video in all_videos[:10]: # Show first 10\n",
 
448
  "metadata": {},
449
  "outputs": [],
450
  "source": [
451
+ "# Find and display all generated videos from our videos directory\n",
452
  "videos = find_generated_videos()\n",
453
  "\n",
454
  "if not videos:\n",
455
+ " # Try alternative search in the whole project\n",
456
+ " videos = list(REPO_DIR.rglob(\"*.mp4\")) + list(REPO_DIR.rglob(\"*.gif\"))\n",
457
  "\n",
458
  "if videos:\n",
459
+ " print(f\"Displaying {len(videos)} video(s) from {VIDEOS_DIR}:\\n\")\n",
460
  " \n",
461
  " for i, video_path in enumerate(videos[:5]): # Display first 5 videos\n",
462
  " print(f\"\\n{'='*60}\")\n",
463
  " print(f\"Video {i+1}: {video_path.name}\")\n",
464
+ " print(f\"Location: {video_path}\")\n",
465
  " print(f\"{'='*60}\")\n",
466
  " \n",
467
  " try:\n",
 
549
  "4. βœ… Generating videos using headless MuJoCo renderer\n",
550
  "5. βœ… Displaying videos in the notebook\n",
551
  "\n",
552
+ "**Project Structure:**\n",
553
+ "```\n",
554
+ "/data/workspaces/opentrack/\n",
555
+ "β”œβ”€β”€ datasets/ # Motion capture data (.npz files)\n",
556
+ "β”‚ └── lafan1/\n",
557
+ "β”‚ └── UnitreeG1/\n",
558
+ "β”œβ”€β”€ models/ # Trained models and checkpoints\n",
559
+ "β”‚ └── <timestamp>_<exp_name>/\n",
560
+ "β”œβ”€β”€ videos/ # Generated videos (.mp4, .gif)\n",
561
+ "└── OpenTrack/ # Cloned repository\n",
562
+ " β”œβ”€β”€ data/mocap -> ../datasets/ (symlink)\n",
563
+ " └── logs -> ../models/ (symlink)\n",
564
+ "```\n",
565
+ "\n",
566
  "**Next Steps:**\n",
567
+ "- All mocap data is in `/data/workspaces/opentrack/datasets/`\n",
568
  "- Run full training with GPU support\n",
569
  "- Test on rough terrain\n",
570
  "- Experiment with reference motion playback\n",
571
+ "- Trained models are saved in `/data/workspaces/opentrack/models/`\n",
572
+ "- Generated videos are in `/data/workspaces/opentrack/videos/`\n",
573
  "\n",
574
  "**Troubleshooting:**\n",
575
  "- If videos aren't generated, check that `--use_renderer` flag is used (not `--use_viewer`)\n",
576
  "- Ensure MuJoCo can run headless (may need `xvfb` on some systems)\n",
577
+ "- Check `/data/workspaces/opentrack/models/` directory for experiment outputs\n",
578
+ "- All data persists in `/data/workspaces/opentrack/` across notebook sessions"
579
  ]
580
  }
581
  ],