pymc-devs / pymc-devs/pytensor-ml
require_unique_state_names misses a duplicate name that is only read
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 9
- Forks
- 7
- Avg merge
- 6h 55m
- Merged PRs (30d)
- 40
Description
scalar_state and counter allocate a fresh shared variable on every call outside a reuses_state frame — the name is for the serialization boundary, not for lookup. Building the plateau scale the way the docstring reads, once for the policy and once for the rate, therefore produces two distinct variables under one name. The policy cuts its copy and the rate multiplies the other one. require_unique_state_names walks only the keys of the updates dict, and the rate-side copy is read but never written, so the guard cannot see it either.
import numpy as np
import pytensor.tensor as pt
from pytensor_ml.optim import adam, compile_train, reduce_on_plateau, scalar_state
from pytensor_ml.params import trainable
target = pt.scalar("target")
w = trainable(np.zeros(3), name="w")
loss = ((w - target) ** 2).sum() # starts at its minimum, so it never improves
rule = reduce_on_plateau(
adam(learning_rate=scalar_state("plateau/scale", fill_value=1.0) * 1e-3),
scalar_state("plateau/scale", fill_value=1.0),
patience=1,
factor=0.1,
)
step = compile_train(loss, rule, inputs=[target])
for _ in range(8):
step(0.0)
print([v.get_value() for v in step.get_shared() if v.name == "plateau/scale"])
# [array(1.), array(1.e-07)]
# the policy drove its copy to 1e-7; the one adam reads is still 1.0, and the rate never changed
reduce_on_plateau(adam(1e-3), some_scale) — where the scale was never wired into the rate at all — is likewise a silent no-op. Checking that the scale is an ancestor of the rule's update expressions would catch both.
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start at require_unique_state_names and the reduce_on_plateau entry point, then run the provided reproduction to inspect the shared variables and update expressions. Trace how scalar_state values are collected and how rule updates are formed. Done means the validation catches duplicate names even when one copy is only read, and catches a scale that is not an ancestor of the rule's updates.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- machine-learning
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 72/100