the backend (my_compiler in the example above) provided, but the one
speedup that is important in this section is caching. Caching
itself is not a direct speedup but a critical enablement that prevents
recompilation. We dig a hole with dynamo, and caching allows us to get
out. It enables us to hold perf neutrality while then enabling
backends - the true source of our speedups.
With even a pass-through no-op backend provided:
def my_compiler(gm: torch.fx.GraphModule, example_inputs: List[torch.Tensor]):
       return gm.forward
We can see TorchDynamo speeding up Python execution even on regular
Python, not just PyTorch.
Caching and Guards Overview
TorchDynamo operates through caching transformed (by TorchDynamo) user
bytecode. When TorchDynamo receives a frame for evaluation, it checks
if the objects referenced in the frame have changed in certain
ways, and if not, TorchDynamo reads the previously transformed user