-
Notifications
You must be signed in to change notification settings - Fork 350
This issue was moved to a discussion.
You can continue the conversation there. Go to discussion →
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Caching robustness and determinism #3259
Comments
For more determinism guarantees, see experimental strict mode: https://github.com/marimo-team/marimo/releases/tag/0.6.20
Not really, because execution path is really the fallback.
Yep, that's the primary hashing check. Caching does the best it can by relying on the contents of the variables it uses, and only falls back on execution mode if it is unable to hash the variable contents. It is possible to have an unhashable datatype that mutates between executions- but then your notebook is not deterministic regardless of As long as the variable data is hashable, then cache should be deterministic. If execution path is utilized- then as a limitation of python it is not possible to guarantee determinism, since file state and hidden memory can accumulate in ways that marimo cannot detect. You can mitigate against this by using strict mode- which requires a deep copy between each cell execution, and also has some other scheduling guarantees. But this of course is flawed in terms of performance. There's potential for a COW (copy on write mode), that might be an intermediate here- but I think this might be a little tricky to properly implement.
|
I do like your latter suggestion of tracking file contents. |
Could you please point to the place in code that does this? Between these lines in Lines 357 to 386 in 1a1db27
And Lines 453 to 482 in 1a1db27
I don't see how what you are saying takes place. Moreover, |
A remark here is that even if the notebook is knowingly non-deterministic, e.g., it involves LLM generations with non-zero temperature that are used as inputs in downstream cells, it's still good to definitely know at the marimo level (and figure-outable across sudden runtime shutdowns, restarts, etc.) whether these non-deterministic cells are consistent with each other, i.e., whether they "resulted (or could have resulted) from a blank-slate notebook run top-to-bottom, without using cache". |
|
Just a little further down: Line 399 in 1a1db27
You can refer to the unit tests for edge cases if you are concerned: https://github.com/marimo-team/marimo/blob/1a1db277543da001fe8f1b0c84b7a9632c4645bd/tests/_save/test_hash.py Re the proposed bug IIRC, execution_refs in collect_for_content_hash are for Excited if you can think of a non-deterministic case! We did spend a fair bit of time thinking through edge cases
The hash mechanism is denoted as a prefix to the hash (e.g.
That is a good observation, I believe that I'll read over the docs again, but they shouldn't sound like caching is totally bullet proof. I'm fairly certain we call out randomness, network-requests and file system concerns |
How it's not a certainty that the
|
Re your simple example: Cell 2 will not run unless Cell 1 has, so I am unsure of the issue. In normal marimo, Cell 2 can be run manually if Cell 1 has failed (note a cache mechanism failure results in rerun)- but this behavior can be disabled with the before mentioned strict mode. Your example can also be written in a way such that there is no issue: @dataclass
class NotContentAddressable:
text: str
@app.cell
def one():
with mo.persistent_cache("llm_call") as cache:
a = NotContentAddressable(text=llm.prompt("blah", temperature=1))
@app.cell
def two():
text = a.text
with mo.persistent_cache("llm_feed") as cache:
_ = llm.prompt("do something with " + text) # Will now be content hash vs execution hash since text is 'primitive'
assert cache.cache_type == "ContentAddressed" If your LLM is non-deterministic, then maybe consider utilizing a seed. Caching and non-determinism do not mix well. From your feature specs it seems like you would like something more like an archive with quick retrieval, which I am not certain falls under the current scope of the caching feature. Re robustness- I appreciate your concern, but I do think it's a little misplaced unless you can provide concrete examples of where the hashing mechanism fails barring cases with side effects. I'm moving this over to "discussion" since it seems that better documentation/ communication is required for caching- but I just made an issue for incorporating tracked files into cache (#3258). But feel free to keep the discussion going ! |
This issue was moved to a discussion.
You can continue the conversation there. Go to discussion →
Hashing strategy for "execution path" refs could lead to inconsistent notebook state
If automatic cell re-run is off, and an upstream cell is non-deterministic, then upon re-running the upstream cell the notebook is in inconsistent state and if at this moment the notebook is closed, then upon restart there would be no way to know for Marimo runtime that the cache result for the downstream cell are invalid.
Although
BlockHasher
's doc mentions this (albeit this isn't even a part of user-facing docs!), the phrase "sources of non-determinism are not accounted for in this implementation, and are left to the user" is not helpful. The core of Marimo's caching logic is exactly the place to deal with this, at least in a good fraction of cases.If the upstream cell is cached persistently (most likely because all cells are cached persistently, i.e., via #3054), then cached content hashing is vital for correctness and corruption prevention (see #3176). Then, if the upstream cell has been run in the current marimo notebook runtime (either forcefully, or because its own dependencies are invalidated), its results (i.e., "content") have also been serialised and cached, and thus the content hash for these latest results has also been recorded.
This means that we can include upstream execution path's content hash along with its module hash in the calculation of the block hash cheaply and at the same handle non-determinism much better.
File inputs
For even better handling of non-determinism, "file inputs" to cells should be tracked and also being part of the block hash (#3258). Thus, if the non-deterministic cell writes out different contents to these non-python files but has the same "content", the downstream cells would still record a cache miss and re-run.
The text was updated successfully, but these errors were encountered: