how does theano.scan's updates work?
ML System Design practice on Codemia
Design recommenders, ranking systems and training pipelines the way ML interviews actually ask for them, with worked solutions.
Introduction
theano.scan is Theano's way to build loop-like behavior inside a symbolic computation graph. The part that confuses many people is the updates object returned by scan. The short version is that updates is not how you pass state from one iteration to the next. It is how Theano records changes that should be applied to shared variables after the compiled function runs.
What scan Returns
A basic scan call returns two things:
- the symbolic outputs produced across iterations
- an updates mapping that must be passed to
theano.functionif you want those shared-variable updates to happen
A simplified shape looks like this:
In this example, updates is usually empty because the loop state is carried through outputs_info, not through shared-variable mutation.
State Between Iterations Uses outputs_info
This is the key idea: if you want one iteration to influence the next, use recurrent outputs and outputs_info.
In the previous example, running_sum is the state being threaded through the loop. Each iteration returns a new value, and scan feeds it into the next step automatically.
That is different from shared-variable updates. Shared-variable updates are not the normal mechanism for per-step recurrence inside scan.
What updates Is Actually For
updates matters when the computation touches shared state that should change across calls to the compiled function. A common case is random number generation, where internal random state needs to advance after execution.
Here, the updates returned by scan advance the random stream state so the next outer function call produces new samples. If you ignore the returned updates, the behavior is wrong or stale because the shared RNG state is not updated properly.
Shared Variables Outside the Loop
You can also combine scan results with explicit shared-variable updates at the outer function level.
In this example, the loop itself is simple, but the compiled function also updates a shared counter after computing the result.
Timing Matters
Another source of confusion is timing. The updates mapping is attached to the compiled function call, not applied as ordinary Python side effects while you define the graph. Theano builds a symbolic description first. The actual shared-variable mutation happens when the compiled function executes.
That means updates is part of the runtime execution plan, not an immediate assignment.
The Practical Rule
Use outputs_info when the loop needs recurrent state between timesteps.
Use updates when shared variables or random streams must be advanced across calls to the compiled function.
If you mix those ideas up, you usually end up with code that either fails to propagate state correctly or mutates shared variables in places where a recurrent output would have been clearer.
Common Pitfalls
The most common mistake is trying to use shared-variable updates to carry state from one scan iteration to the next. That is what recurrent outputs and outputs_info are for.
Another mistake is ignoring the updates returned by scan, especially when random streams are involved. If you do not pass those updates into theano.function, the symbolic graph does not maintain the expected state.
Developers also sometimes expect updates to happen immediately at graph-construction time. Theano does not work that way. The updates are applied only when the compiled function runs.
Finally, do not assume updates will be non-empty for every scan. Many scans use pure symbolic recurrence and return no meaningful shared-variable updates at all.
Summary
- '
scanreturns both outputs and an updates mapping.' - Use
outputs_infofor state that flows from one iteration to the next. - Use
updatesfor shared-variable changes that should occur when the compiled function executes. - Random streams are a common reason
scanreturns important updates. - Pass the returned updates into
theano.functionwhen they matter.
Related reading
- How does WEKA treat nominal attributes v/s numerical attributes?
- How exactly does LSTMCell from TensorFlow operates?
- How generate an artificial data set through a simple simulation model for Classification analysis with Binary Response and 4-5 features?
- How good can Nearest Neighbor, Naive Bayes and a Decision Tree classifier solve the given classification problem?
- How does this input work with the Python 'any' function?
- How does ThreadPoolExecutor.map differ from ThreadPoolExecutor.submit?
- How GridSearchCV in sklearn choose the cross-validation sets?
- How inverting the dropout compensates the effect of dropout and keeps expected values unchanged?
.png&w=3840&q=75)
Tackling System Design Interview Problems
A short course that equips you with the skills to approach system design interviews methodically.
Start the free courseTrack what you have practised
A free account saves your progress, solutions and study plan across every problem on Codemia.
ML System Design practice on Codemia
Design recommenders, ranking systems and training pipelines the way ML interviews actually ask for them, with worked solutions.