-
Notifications
You must be signed in to change notification settings - Fork 40
feat: held-out validation during training #77
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -35,6 +35,9 @@ class TrainingRequest(BaseModel): | |
| dataset_revision: str | None = None | ||
| dataset_root: str | None = None | ||
| dataset_episodes: list[int] | None = None | ||
| # Fraction of episodes held out for validation (0 disables). lerobot | ||
| # requires eval_split > 0 whenever eval_steps > 0. | ||
| dataset_eval_split: float = 0.0 | ||
|
|
||
| # Policy configuration | ||
| policy_type: str = "act" | ||
|
|
@@ -71,6 +74,10 @@ class TrainingRequest(BaseModel): | |
| eval_n_episodes: int = 10 | ||
| eval_batch_size: int = 50 | ||
| eval_use_async_envs: bool = False | ||
| # Compute eval loss on the held-out split every N steps (0 disables). | ||
| eval_steps: int = 0 | ||
| # Cap on total eval samples (0 = use all held-out data). | ||
| max_eval_samples: int = 0 | ||
|
|
||
| # Policy-specific | ||
| policy_device: str | None = "cuda" | ||
|
|
@@ -118,6 +125,8 @@ def build_training_command( | |
| cmd.extend(["--dataset.root", request.dataset_root]) | ||
| if request.dataset_episodes: | ||
| cmd.extend(["--dataset.episodes"] + [str(ep) for ep in request.dataset_episodes]) | ||
| if request.dataset_eval_split > 0: | ||
| cmd.extend(["--dataset.eval_split", str(request.dataset_eval_split)]) | ||
|
Comment on lines
+128
to
+129
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is the half of the pairing lerobot does not enforce, and it is the half that fails silently.
I hit this by calling |
||
|
|
||
| # Policy | ||
| cmd.extend(["--policy.type", request.policy_type]) | ||
|
|
@@ -184,6 +193,10 @@ def build_training_command( | |
| cmd.extend(["--eval.n_episodes", str(request.eval_n_episodes)]) | ||
| cmd.extend(["--eval.batch_size", str(request.eval_batch_size)]) | ||
| cmd.extend(["--eval.use_async_envs", "true" if request.eval_use_async_envs else "false"]) | ||
| if request.eval_steps > 0: | ||
| cmd.extend(["--eval_steps", str(request.eval_steps)]) | ||
| if request.max_eval_samples > 0: | ||
| cmd.extend(["--max_eval_samples", str(request.max_eval_samples)]) | ||
|
|
||
| # Optimizer | ||
| if request.optimizer_type: | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unbounded. lerobot validates this as
0.0 <= x < 1.0(configs/default.py:55), but the request model does not, sodataset_eval_split=1.5is accepted here, the job spawns, and it dies insidemake_train_eval_datasetsabout a minute later with the reason buried in the training log.Field(ge=0.0, lt=1.0)makes it a 422 on the request, before anything starts.