Skip to content

Commit 1fba6f1

Browse files
committed
Compile UMA energy output operations
> The current end-to-end validation uses UMA-S-1p2 with energy/forces/stress, > `external_graph_gen=False`, `internal_graph_gen_version=3`, `merge_mole=True`, > `execution_mode="umas_fast_gpu"`, and `compile_dynamic_shapes=False`. Energy > output processing is downstream of graph construction and is executed for this > checkpoint, so removing its explicit compile disable applies unchanged and removes > one graph break from this internal-graph configuration. `compute_energy` carried an unconditional compile disable around the float64 per-system reduction. The disable was added for an older float64 `index_add` accuracy issue, but current Inductor matches eager forward and backward results at strict tolerance. Keeping it now guarantees a boundary on every inference: ``` @torch.compiler.disable def compute_energy(...): ... ``` Remove the decorator after adding a regression test for the production-like float32 node-energy to float64 system-reduction path. The test checks compiled forward and backward results at strict tolerance. **Activation** No independent flag enables this fix. Energy output processing remains in the captured graph whenever UMA inference is compiled. ```python settings = InferenceSettings(compile=True) ``` The current benchmark additionally uses `merge_mole=True`, `external_graph_gen=False`, and `execution_mode="umas_fast_gpu"`, but those settings are not required for this output-processing fix. Test Plan: ``` PYTHONPATH=$PWD/src:$PYTHONPATH pytest -q tests/core/models/uma/test_outputs.py -k float64_compile ruff check src/fairchem/core/models/uma/outputs.py ``` Authored with assistance from Codex. ghstack-source-id: 19b9ddf Pull Request resolved: #2125
1 parent ebc706c commit 1fba6f1

2 files changed

Lines changed: 51 additions & 2 deletions

File tree

src/fairchem/core/models/uma/outputs.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,8 +81,6 @@ def reduce_node_to_system(
8181
return reduced, system_values
8282

8383

84-
# Compile produces the wrong values using index_add with float64 precision :(
85-
@torch.compiler.disable
8684
def compute_energy(
8785
emb: dict[str, torch.Tensor],
8886
energy_block: torch.nn.Module,

tests/core/models/uma/test_outputs.py

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,57 @@ def test_energy_part_for_gradients(self):
256256
assert node_embedding.grad is not None
257257
assert torch.allclose(node_embedding.grad, torch.ones_like(node_embedding))
258258

259+
@pytest.mark.gpu()
260+
@pytest.mark.compile_gpu()
261+
@pytest.mark.parametrize("dynamic", [False, True])
262+
def test_float64_compile_index_add_regression(self, compile_reset_state, dynamic):
263+
# Regression for pytorch/pytorch#108963.
264+
def fn():
265+
value = torch.zeros(1, dtype=torch.float64, device="cuda")
266+
index = torch.tensor([0], dtype=torch.long, device="cuda")
267+
source = torch.rand(1, dtype=torch.float64, device="cuda")
268+
return source, value.index_add(0, index, source, alpha=2.0) / 2
269+
270+
torch.manual_seed(0)
271+
source, output = torch.compile(fn, fullgraph=True, dynamic=dynamic)()
272+
273+
assert torch.equal(
274+
output.contiguous().view(torch.uint8),
275+
source.contiguous().view(torch.uint8),
276+
)
277+
278+
@pytest.mark.gpu()
279+
@pytest.mark.compile_gpu()
280+
@pytest.mark.parametrize("dynamic", [False, True])
281+
def test_float64_compile(self, compile_reset_state, dynamic):
282+
energy_block = nn.Linear(8, 1).cuda()
283+
284+
def fn(node_embedding, batch):
285+
return compute_energy(
286+
{"node_embedding": node_embedding}, energy_block, batch, num_systems=4
287+
)
288+
289+
node_embedding = torch.randn(
290+
257, 9, 8, device="cuda", dtype=torch.float32, requires_grad=True
291+
)
292+
batch = torch.arange(257, device="cuda") % 4
293+
expected = fn(node_embedding, batch)
294+
actual = torch.compile(fn, fullgraph=True, dynamic=dynamic)(
295+
node_embedding, batch
296+
)
297+
298+
for actual_output, expected_output in zip(actual, expected):
299+
assert torch.equal(
300+
actual_output.contiguous().view(torch.uint8),
301+
expected_output.contiguous().view(torch.uint8),
302+
)
303+
expected_grad = torch.autograd.grad(expected[1].sum(), node_embedding)[0]
304+
actual_grad = torch.autograd.grad(actual[1].sum(), node_embedding)[0]
305+
assert torch.equal(
306+
actual_grad.contiguous().view(torch.uint8),
307+
expected_grad.contiguous().view(torch.uint8),
308+
)
309+
259310
def test_reduce_mean(self):
260311
"""Test that reduce='mean' divides energy by natoms per system."""
261312
emb, energy_block = _make_emb_and_block(

0 commit comments

Comments
 (0)