The model changed its own buffers while being traced.
An exported package is a pure function of its inputs: whatever the buffers held is written into it as constants. A model that updates a buffer as it runs — a counter, a cache, a running statistic — keeps accumulating in eager and stops the moment it is exported.
The first call still agrees, because the constants were read after
the trace, which is what makes this worth refusing rather than
warning about: verify runs one prediction and passes.
Examples
>>> import shutil, tempfile
>>> import lucid, lucid.nn as nn, lucid.coreml as cml
>>> class Counts(nn.Module):
... def __init__(self):
... super().__init__()
... self.register_buffer("total", lucid.zeros(1, 4))
... def forward(self, x):
... self.total += x
... return self.total + x
>>> room = tempfile.mkdtemp()
>>> try:
... cml.export(Counts().eval(), lucid.ones(1, 4), f"{room}/m.mlpackage")
... except cml.StatefulModel as refusal:
... print(refusal)
lucid.coreml: tracing changed total, so this model is not a pure function ...
>>> shutil.rmtree(room)