pymc-devs / pymc-devs/pytensor-ml

require_unique_state_names misses a duplicate name that is only read

Open
#122 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

enhancement optimizer
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

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.