f3a8a38acd
web-platform-ci / Standalone decision service (no cloud credentials) (push) Has been cancelled
web-platform-ci / TypeScript, lint, unit, build (push) Has been cancelled
web-platform-ci / Playwright E2E (push) Has been cancelled
lekiwi-compatibility / cpu-compatibility (push) Has been cancelled
web-platform-ci / Standalone decision service (no cloud credentials) (pull_request) Has been cancelled
web-platform-ci / TypeScript, lint, unit, build (pull_request) Has been cancelled
web-platform-ci / Playwright E2E (pull_request) Has been cancelled
lekiwi-compatibility / cpu-compatibility (pull_request) Has been cancelled
集成同源 BYOK 会话隔离、精简模型设置、官方订阅入口和 HTTPS 发布运维;保留本地训练/调参与控制能力。同步 npm 版本及 CHANGELOG,记录公网真实 API 验收仍待用户凭据。
85 lines
3.1 KiB
Python
85 lines
3.1 KiB
Python
"""Optional navigation-only behavior-cloning initialization, followed by PPO.
|
|
|
|
The teacher is used ONLY to collect training data. Export contains the trained MLP,
|
|
not a hidden scripted navigation fallback. Later stages never use this initializer.
|
|
"""
|
|
|
|
import math
|
|
|
|
import mujoco
|
|
import numpy as np
|
|
import torch
|
|
|
|
from .env import MobileManipulatorEnv
|
|
from .kernel import TASK, navigation_error
|
|
|
|
|
|
def navigation_teacher(state):
|
|
_, yaw = navigation_error(state)
|
|
x = state[37] - TASK["navigationOffset"][0] - state[0]
|
|
y = state[38] - TASK["navigationOffset"][1] - state[1]
|
|
action = np.zeros(TASK["actionSize"], dtype=np.float32)
|
|
action[0] = 8 * (math.cos(yaw) * x + math.sin(yaw) * y)
|
|
action[1] = 8 * (-math.sin(yaw) * x + math.cos(yaw) * y)
|
|
action[2] = -4 * yaw
|
|
return np.clip(action, -1, 1)
|
|
|
|
|
|
def bootstrap_navigation(agent, package, params, reset_options, seed):
|
|
steps = params["navigationBootstrapSteps"]
|
|
if not steps:
|
|
return
|
|
print(f"Navigation BC initialization: {steps} simulated teacher steps, then PPO", flush=True)
|
|
env = MobileManipulatorEnv(
|
|
package,
|
|
stage="navigate",
|
|
reset_options=reset_options,
|
|
position_jitter=params["positionJitter"],
|
|
)
|
|
rng = np.random.default_rng(seed)
|
|
observations, actions = [], []
|
|
|
|
def reset():
|
|
env.reset()
|
|
# Cover heading errors rather than cloning only a straight, zero-yaw path.
|
|
yaw = rng.uniform(-0.6, 0.6)
|
|
env.data.qpos[env.base_q + 3 : env.base_q + 7] = [
|
|
math.cos(yaw / 2),
|
|
0,
|
|
0,
|
|
math.sin(yaw / 2),
|
|
]
|
|
mujoco.mj_forward(env.model, env.data)
|
|
env.hold()
|
|
return env.observe().copy()
|
|
|
|
try:
|
|
env.reset(seed=seed)
|
|
observation = reset()
|
|
for _ in range(steps):
|
|
action = navigation_teacher(env.state)
|
|
observations.append(observation.copy())
|
|
actions.append(action)
|
|
# Cover nearby off-teacher states without teleportation or privileged deployment inputs.
|
|
noisy = action.copy()
|
|
noisy[:3] += rng.normal(0, 0.2, 3)
|
|
observation, _, terminated, truncated, _ = env.step(noisy)
|
|
if terminated or truncated:
|
|
observation = reset()
|
|
finally:
|
|
env.close()
|
|
x = torch.as_tensor(np.asarray(observations), device=agent.device)
|
|
y = torch.as_tensor(np.asarray(actions), device=agent.device)
|
|
policy = agent.policy
|
|
optimizer = torch.optim.Adam(policy.parameters(), lr=1e-3)
|
|
for _ in range(30):
|
|
for batch in torch.randperm(steps, device=agent.device).split(256):
|
|
features = policy.extract_features(x[batch])
|
|
predicted = policy.action_net(policy.mlp_extractor.forward_actor(features))
|
|
loss = torch.nn.functional.mse_loss(predicted, y[batch])
|
|
optimizer.zero_grad()
|
|
loss.backward()
|
|
torch.nn.utils.clip_grad_norm_(policy.parameters(), 1)
|
|
optimizer.step()
|
|
print(f"Navigation BC initialization finished; final batch MSE={loss.item():.6g}", flush=True)
|