Skip to content

Add openarm-mjlab-eval: measure a policy's success rate - #10

Merged
k1000dai merged 2 commits into
enactic:mainfrom
Manas-arumalla:feat/eval-harness
Oct 5, 2026
Merged

k1000dai merged 2 commits into
enactic:mainfrom
Manas-arumalla:feat/eval-harness

Conversation

@Manas-arumalla

Copy link
Copy Markdown
Contributor

Every task in this repo reports a success rate, and there's currently no shared way to reproduce one. train and play exist, but nothing answers what fraction of episodes actually succeed, so each number has to be taken on trust or re-derived with a script. This adds one command that does it for any registered task, with no task-specific code.

uv run openarm-mjlab-eval OpenArm-PickPlace

It reports the fraction of episodes reaching the task's success termination, alongside the rate of every other termination term and the episode-length distribution. Defaults to the latest checkpoint and 256 episodes.

Things it gets right that are easy to get wrong by hand:

Success is read from a named termination term, not done & !time_out. On any task with a failure termination a dropped cube, a puck knocked off the table the coarser test counts those failures as successes.

Each environment is scored once. After it terminates it stops updating, so an environment that succeeds, resets and succeeds again inside one rollout can't be counted twice.

The episode budget comes from the config as episode_length_s / (decimation * timestep), rather than a hardcoded step count that silently truncates whenever a task's episode length changes.

Choosing which termination term means success is the one step whose failure is silent a wrong choice prints a plausible number that means something else. So resolve_success_term prefers an explicit --success-term, then a term named success, then the sole remaining term once clock and failure terms are set aside, and raises rather than guessing when that's ambiguous.

@k1000dai

Copy link
Copy Markdown
Contributor

@Manas-arumalla Before adding eval or a new feature, I am planning to refactor the codebase a bit and update the README for more usability. Is it ok?

@Manas-arumalla

Copy link
Copy Markdown
Contributor Author

@k1000dai Sure, go ahead. I'll update #10, #11, #12 and #13 once your refactor lands. I also have a new tool ready that checks whether a task's successes are honest; I'll open it after your refactor so it doesn't get in the way.

@Manas-arumalla

Copy link
Copy Markdown
Contributor Author

@k1000dai If any help is needed in making the README please do let me know

@k1000dai

Copy link
Copy Markdown
Contributor

@Manas-arumalla Thanks! I will let you know after I create the PR for the README. Please review and tell me your thoughts!

Every task here reports a success rate and there was no shared way to
reproduce one. train and play exist; nothing answers what fraction of
episodes actually succeed, so each number had to be taken on trust or
re-derived with a throwaway script.

This adds one command that works for any registered task with no
task-specific code, and encodes four things that are easy to get wrong
when writing that script by hand:

Success is read from a named termination term rather than
`done & !time_out`. On any task with a failure termination -- a dropped
cube, a puck knocked off the table -- the coarser test counts those
failures as successes.

Each environment is scored once. After it terminates it stops updating,
so an environment that succeeds, resets and succeeds again inside one
rollout cannot be counted twice.

The episode budget is derived from the config as
episode_length_s / (decimation * timestep). A hardcoded step count
silently truncates or over-runs whenever a task's episode length changes.

Observation corruption is disabled, since training noise is a regularizer
and leaving it on measures the policy plus the noise.

Choosing the success term is the one step whose failure is silent: a wrong
choice prints a plausible number that means something else. So
resolve_success_term prefers an explicit --success-term, then a term named
success, then the sole remaining term once clock and failure terms are set
aside, and raises rather than guessing when that is ambiguous. Seven tests
pin those rules, including that puck_fell is never inferred as success.
For the same reason the returned rates are nested under "terms" rather
than flattened: a task may have a termination term literally named
success, and a flat layout would collide with it.

Verified on three tasks. Reach reports 1.000 with the success term
inferred correctly. Door reports 1.000 for the policy trained after the
handle geometry fix and 0.000 for the one trained before it, which is the
mismatch this is meant to surface.
@k1000dai

k1000dai commented Oct 2, 2026

Copy link
Copy Markdown
Contributor

@Manas-arumalla works well on my side.
Just a small comment here.
Please exclude block_fell from success-term. Currently, openarm-mjlab-eval OpenArm-Lift fails without --success-term because both lifted_target and block_fell remain candidates.

OpenArm-Lift's block_fell is a failure termination, so without
--success-term both it and lifted_target were candidates and the tool
refused to guess. Add it to the failure terms, and test that every
registered task resolves to exactly one success term on its own.
@Manas-arumalla

Copy link
Copy Markdown
Contributor Author

@k1000dai did the changes please check i forgot to let you know

@k1000dai

k1000dai commented Oct 5, 2026

Copy link
Copy Markdown
Contributor

(Thank you for letting me know)
LGTM.

@k1000dai
k1000dai merged commit 8f8f3e0 into enactic:main Oct 5, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants