Reinforcement Learning
stable-baselines3
PyTorch
English
Korean
deep-reinforcement-learning
ppo
proximal-policy-optimization
cartpole-v1
gymnasium
openai-gym
classic-control
robotics
physical-ai
sim-to-real
zero-shot-transfer
domain-randomization
inverted-pendulum
optimal-control
lqr-control
control-theory
interactive-demo
Eval Results (legacy)
Instructions to use hwihwalab/cartpole-v1-ppo with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- stable-baselines3
How to use hwihwalab/cartpole-v1-ppo with stable-baselines3:
from huggingface_sb3 import load_from_hub checkpoint = load_from_hub( repo_id="hwihwalab/cartpole-v1-ppo", filename="{MODEL FILENAME}.zip", ) - Notebooks
- Google Colab
- Kaggle
Hwihwa_Lab
feat: upgrade replay.mp4 to 1:1 square (720x720) close-up viewport for HF video preview widget
e780fe4 Download record_replay_mp4.py from hwihwalab/cartpole-v1-ppo: direct link, hf CLI and curl.
- Browser
- Download file 4.35 kB
-
https://huggingface.co/hwihwalab/cartpole-v1-ppo/resolve/main/record_replay_mp4.py
- Command line
-
hf download hf://hwihwalab/cartpole-v1-ppo/record_replay_mp4.py
-
curl -L -o record_replay_mp4.py https://huggingface.co/hwihwalab/cartpole-v1-ppo/resolve/main/record_replay_mp4.py
4.35 kB
| # -*- coding: utf-8 -*- | |
| """ | |
| HWIHWA LAB // Ultra-High-Definition 1:1 Square (720x720) Replay Video Generator | |
| Optimized specifically for Hugging Face Model Hub's Video Preview Sidebar Widget. | |
| - 1:1 Square Aspect Ratio (720x720) | |
| - Huge, bold Cart & Pole dynamics centered in the viewport | |
| - Big shock impulse laser & particle physics | |
| - Clean HUD overlay (Active force, score, shock banner) | |
| - Ultra-sharp H.264 (CRF 17, 25 FPS) | |
| """ | |
| import time | |
| import io | |
| from pathlib import Path | |
| import numpy as np | |
| from PIL import Image | |
| import imageio | |
| from playwright.sync_api import sync_playwright | |
| def generate_square_canvas_replay(): | |
| current_dir = Path(__file__).resolve().parent | |
| html_url = f"file:///{current_dir.as_posix()}/index.html" | |
| output_mp4 = current_dir / "replay.mp4" | |
| raw_frames = [] | |
| print("๐ Launching Headless Chromium to record 1:1 SQUARE (720x720) CartPole Dynamics...") | |
| with sync_playwright() as p: | |
| browser = p.chromium.launch(headless=True) | |
| # 720x720 Square Viewport with device_scale_factor=1 | |
| context = browser.new_context(viewport={"width": 720, "height": 720}, device_scale_factor=1) | |
| page = context.new_page() | |
| page.goto(html_url) | |
| page.wait_for_timeout(1000) # Wait for weights & chart initialization | |
| # Maximize Stage to 100% of 720x720 viewport | |
| page.evaluate("""() => { | |
| const header = document.querySelector('.header-bar'); | |
| if (header) header.style.display = 'none'; | |
| const bento = document.querySelector('.bento-deck-golden'); | |
| if (bento) bento.style.display = 'none'; | |
| const labMain = document.querySelector('.lab-main'); | |
| if (labMain) { | |
| labMain.style.padding = '0'; | |
| labMain.style.height = '100vh'; | |
| } | |
| const stageSec = document.querySelector('.stage-section'); | |
| if (stageSec) stageSec.style.height = '100vh'; | |
| const area = document.querySelector('.canvas-viewport-area'); | |
| if (area) { | |
| area.style.height = '100vh'; | |
| area.style.borderRadius = '0'; | |
| area.style.border = 'none'; | |
| } | |
| window.dispatchEvent(new Event('resize')); | |
| }""") | |
| page.wait_for_timeout(300) | |
| stage = page.locator(".canvas-viewport-area") | |
| box = stage.bounding_box() | |
| if not box: | |
| stage = page.locator("#simCanvas") | |
| box = stage.bounding_box() | |
| cx = 360 | |
| cy = 360 | |
| print(f" ๐ฏ Stage Bounding Box: Width={box['width']}, Height={box['height']}") | |
| total_frames = 110 # ~4.4 seconds @ 25 FPS | |
| for i in range(total_frames): | |
| # Apply dynamic mouse disturbance impulse | |
| if i == 25: | |
| page.mouse.move(cx - 20, cy + 50) | |
| page.mouse.down() | |
| elif i == 30: | |
| page.mouse.move(cx + 140, cy - 40) | |
| elif i == 35: | |
| page.mouse.up() | |
| # Optional second gentle tap at frame 70 | |
| if i == 70: | |
| page.mouse.move(cx + 20, cy + 40) | |
| page.mouse.down() | |
| elif i == 74: | |
| page.mouse.move(cx - 80, cy - 30) | |
| elif i == 78: | |
| page.mouse.up() | |
| screenshot_bytes = stage.screenshot(type="png") | |
| img = Image.open(io.BytesIO(screenshot_bytes)) | |
| # Resize precisely to 720x720 if slight pixel sub-pixel rounding occurs | |
| if img.width != 720 or img.height != 720: | |
| img = img.resize((720, 720), Image.Resampling.LANCZOS) | |
| raw_frames.append(np.array(img.convert("RGB"))) | |
| time.sleep(0.035) | |
| browser.close() | |
| print(f"๐ฌ Encoding {len(raw_frames)} square frames (720x720) to H.264 replay.mp4...") | |
| writer = imageio.get_writer( | |
| str(output_mp4), | |
| fps=25, | |
| codec="libx264", | |
| pixelformat="yuv420p", | |
| ffmpeg_params=["-crf", "17", "-preset", "slow"] | |
| ) | |
| for f in raw_frames: | |
| writer.append_data(f) | |
| writer.close() | |
| size_kb = round(output_mp4.stat().st_size / 1024, 1) | |
| print(f"[โ] SUCCESS: 1:1 Square (720x720) Replay saved to: {output_mp4} ({size_kb} KB)") | |
| return output_mp4 | |
| if __name__ == "__main__": | |
| generate_square_canvas_replay() | |