Skip to content

Choose the acquisition function with the scientist instead of defaulting to expected improvement - #56

Merged
MarcusMNoack merged 4 commits into
lbl-camera:masterfrom
ronpandolfi:skills/acquisition-function-guidance
Jul 29, 2026
Merged

Choose the acquisition function with the scientist instead of defaulting to expected improvement#56
MarcusMNoack merged 4 commits into
lbl-camera:masterfrom
ronpandolfi:skills/acquisition-function-guidance

Conversation

@ronpandolfi

Copy link
Copy Markdown
Contributor

Why

The skills presented the acquisition function as a lookup rather than a decision, and every path through them landed on "expected improvement":

  • experiment-designer Step 1 asked a binary — "Exploration? Optimization? Both?" — whose optimization branch listed EI first. Scientists nearly always say "find the peak."
  • EI had the broadest "Best for" cell in the built-in table ("Optimization (find max)"), while UCB's read like a knob you had to understand first.
  • No skill listed a single EI failure mode, and none told the agent to involve the scientist in the choice.
  • EI is the most-cited acquisition in the BO literature, so an LLM defaults to it. Silence was enough.

What changed

acquisition-functions/SKILL.md is restructured around choosing with the scientist: a decision table keyed on what they want to learn, an "Avoid when" column on the built-in table, and a caveats section for gpCAM-specific behavior the skills never mentioned:

  • (a) EI clips improvement before forming z (surrogate_model.py:260), so wherever the posterior mean is below the incumbent it collapses to 0.3989·σ — identical in ranking to "variance". Measured: 193/200 grid candidates on a 15-point sin(x) fit, ratio exactly 0.398942. Filed separately as expected improvement clips improvement before forming z, degenerating to a scaled variance acquisition #55.
  • (b) EI, PI, UCB, "maximum", KG, and NEI are all maximization-only and fail silently for minimization.
  • (c) Plain EI/PI anchor to np.max(y_data), a noisy observation — which is what NEI exists to fix.
  • (d) Multi-task plain EI sums stds across tasks and compares to a scalar max(y_data); KG/NEI scalarize the same objective correctly via _scalarized_blocks.
  • (e) ask(n>1) silently rewrites string acquisitions to "total correlation".
  • (f) "ucb"/"lcb" hardcode beta=3.0. Measured: implied β exactly 3.0000. This also corrects experiment-designer, which claimed the string exposed a tunable beta.
  • (g) KG/NEI are the expensive built-ins — joint posterior per evaluation, KG loops per candidate.

Adds a radical_gradient recipe — sqrt(‖∇m‖)·σ — for mapping change through parameter space. Softening the gradient term lets uncertainty carry relatively more weight, so sampling spreads across every changing region instead of piling onto the steepest ridge. Built-in "gradient" stays the pick when there's one dominant transition.

Adds references/choosing-an-acquisition-function.md with a worked example per archetype: peak finding, mapping, change mapping, threshold, target value, minimization, batch, multi-task, cost-constrained.

Also registers the new troubleshooting and uncertainty-calibration skills in docs/source/claude-skills.md — they were added to CLAUDE.md but missed the docs table.

Verification

Claims (a) and (f) were measured against a live GP, and the radical_gradient recipe was run end-to-end through ask(). KG/NEI guidance is source-read only — I couldn't exercise it locally (installed fvgp is 4.6.5; the current code needs ~=4.8.1).

No library code is touched — docs and skills only.

🤖 Generated with Claude Code

https://claude.ai/code/session_01G3DENMtUbk58gb5yVwEBBY

ronpandolfi and others added 4 commits July 28, 2026 15:13
Diagnoses why the skills funnel users to "expected improvement" and
records the agreed redesign.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01G3DENMtUbk58gb5yVwEBBY
The skills presented the acquisition function as a lookup rather than a
decision, and every path through them landed on EI: experiment-designer
asked a binary exploration/optimization question whose optimization branch
listed EI first, and EI had the broadest "Best for" cell in the built-in
table. Nothing anywhere listed a failure mode.

acquisition-functions/SKILL.md is restructured around choosing the function
*with* the scientist -- a decision table keyed on what they want to learn,
an "Avoid when" column, and a caveats section documenting five gpCAM
behaviors the skills never mentioned:

  a. EI clips improvement before forming gamma (surrogate_model.py:254), so
     wherever the posterior mean is below the incumbent it collapses to
     0.3989*sigma -- identical in ranking to "variance". Verified: on a
     15-point sin(x) fit, 193/200 grid candidates, ratio exactly 0.398942.
  b. EI/PI hardcode max(y_data) -- maximization only, fails silently.
  c. The incumbent is a noisy observation, not the posterior mean.
  d. Multi-task EI sums means and sums stds across tasks, then compares to
     a scalar max(y_data).
  e. ask(n>1) silently rewrites string acquisitions to "total correlation".
  f. "ucb"/"lcb" hardcode beta=3.0. Verified: implied beta exactly 3.0000.

Adds the radical_gradient recipe -- sqrt(||grad m||) * sigma, softening the
gradient weighting so uncertainty carries relatively more weight and
sampling spreads across every changing region instead of the steepest ridge.
Preferred for mapping change through parameter space; built-in "gradient"
remains good for one dominant transition.

Adds references/choosing-an-acquisition-function.md with a worked example
per archetype, and corrects experiment-designer's claim that the built-in
"ucb" string exposes a tunable beta.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01G3DENMtUbk58gb5yVwEBBY
… the skills

Upstream added "knowledge gradient" and "noisy expected improvement"
(b8d8bd0) plus a broad skills expansion. Reconciled against the
acquisition-choice restructuring on this branch, keeping both sides:

- acquisition-functions: KG/NEI folded into the goal-keyed decision table
  (noisy maximization -> NEI; stalled loop -> KG; multi-task optimization ->
  either) and into the built-in table's "Avoid when" column. Kept upstream's
  transformed-space note, fixed-scale normalization, and scale-aware
  threshold epsilon.
- Caveat (c) now points at NEI as the actual fix for the noisy-incumbent
  problem rather than suggesting a hand-written callable, and caveat (d)
  points at KG/NEI for multi-task optimization -- they scalarize the same
  task-summed objective but build the joint posterior properly.
- New caveat (g): KG/NEI are the expensive built-ins (joint posterior per
  evaluation, KG loops per candidate), with the reference-set knobs.
- Caveat (b) extended: KG/NEI are maximization-only too (np.max(mu_ref)),
  so the minimization warning now covers six built-ins, not four.
- Source line numbers refreshed for post-merge surrogate_model.py, and
  caveat (a) cross-references lbl-camera#55.
- experiment-designer/multi-task: upstream's KG/NEI routing merged into the
  "confirm with the scientist" framing rather than replacing it. Kept
  upstream's correction that the default prior mean is mean(y_data), not zero.
- docs: added the new troubleshooting and uncertainty-calibration skills to
  the skills table.

KG/NEI documentation is verified by source reading only -- the installed
fvgp is 4.6.5 and the merged code needs ~=4.8.1, so they could not be run
here. The EI claims were re-checked: the EI block differs from the version
actually executed only by a cosmetic .reshape(), so the measured
0.398942 ratio carries over unchanged.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01G3DENMtUbk58gb5yVwEBBY
docs/superpowers/specs/ is personal brainstorming-workflow output, not
project documentation. Its content now lives in the skill itself and in
lbl-camera#55.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01G3DENMtUbk58gb5yVwEBBY
@codecov

codecov Bot commented Jul 28, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 90.05%. Comparing base (3d576fa) to head (06bc0b6).

Additional details and impacted files
@@           Coverage Diff           @@
##           master      #56   +/-   ##
=======================================
  Coverage   90.05%   90.05%           
=======================================
  Files           9        9           
  Lines         945      945           
=======================================
  Hits          851      851           
  Misses         94       94           

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@ronpandolfi
ronpandolfi requested a review from MarcusMNoack July 28, 2026 22:52
@MarcusMNoack
MarcusMNoack merged commit d45db2c into lbl-camera:master Jul 29, 2026
6 checks passed
@ronpandolfi
ronpandolfi deleted the skills/acquisition-function-guidance branch July 29, 2026 01:22
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