Skip to content

Commit 19df985

Browse files
author
Han Wang
committed
fix issues
1 parent b67accc commit 19df985

3 files changed

Lines changed: 179 additions & 51 deletions

File tree

deepmd/pt_expt/model/ener_model.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -122,8 +122,8 @@ def forward_lower(
122122
-------
123123
torch.nn.Module
124124
A traced module whose ``forward`` accepts
125-
``(extended_coord, extended_atype, nlist, mapping)`` and
126-
returns a dict with the same keys as ``_forward_lower``.
125+
``(extended_coord, extended_atype, nlist, mapping, fparam, aparam)``
126+
and returns a dict with the same keys as ``_forward_lower``.
127127
"""
128128
model = self
129129

@@ -132,6 +132,8 @@ def fn(
132132
extended_atype: torch.Tensor,
133133
nlist: torch.Tensor,
134134
mapping: torch.Tensor | None,
135+
fparam: torch.Tensor | None,
136+
aparam: torch.Tensor | None,
135137
) -> dict[str, torch.Tensor]:
136138
extended_coord = extended_coord.detach().requires_grad_(True)
137139
return model._forward_lower(
@@ -144,4 +146,6 @@ def fn(
144146
do_atomic_virial=do_atomic_virial,
145147
)
146148

147-
return make_fx(fn)(extended_coord, extended_atype, nlist, mapping)
149+
return make_fx(fn)(
150+
extended_coord, extended_atype, nlist, mapping, fparam, aparam
151+
)

source/tests/consistent/model/test_ener.py

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,6 @@ def data(self) -> dict:
123123
pd_class = EnergyModelPD
124124
pt_expt_class = EnergyModelPTExpt
125125
jax_class = EnergyModelJAX
126-
pd_class = EnergyModelPD
127126
args = model_args()
128127

129128
def get_reference_backend(self):
@@ -979,7 +978,6 @@ def test_get_default_fparam(self) -> None:
979978
def test_change_out_bias(self) -> None:
980979
"""change_out_bias should produce consistent bias on dp and pt."""
981980
nframes = 2
982-
nloc = 6
983981
# Use realistic coords (from setUp, tiled for 2 frames)
984982
coords_2f = np.tile(self.coords, (nframes, 1, 1)) # (2, 6, 3)
985983
atype_2f = np.array([[0, 0, 1, 1, 1, 1], [0, 1, 1, 0, 1, 1]], dtype=np.int32)
@@ -1182,7 +1180,6 @@ def test_compute_or_load_out_stat(self) -> None:
11821180
)
11831181

11841182
nframes = 2
1185-
nloc = 6
11861183
coords_2f = np.tile(self.coords, (nframes, 1, 1))
11871184
atype_2f = np.array([[0, 0, 1, 1, 1, 1], [0, 1, 1, 0, 1, 1]], dtype=np.int32)
11881185
box_2f = np.tile(self.box.reshape(1, 3, 3), (nframes, 1, 1))

source/tests/pt_expt/model/test_ener_model.py

Lines changed: 172 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,11 @@ def setUp(self) -> None:
6060
[[0, 0, 0, 1, 1]], dtype=torch.int64, device=self.device
6161
)
6262

63-
def _make_model(self) -> EnergyModel:
63+
def _make_model(
64+
self,
65+
numb_fparam: int = 0,
66+
numb_aparam: int = 0,
67+
) -> EnergyModel:
6468
ds = DescrptSeA(
6569
self.rcut,
6670
self.rcut_smth,
@@ -71,6 +75,8 @@ def _make_model(self) -> EnergyModel:
7175
self.nt,
7276
ds.get_dim_out(),
7377
1,
78+
numb_fparam=numb_fparam,
79+
numb_aparam=numb_aparam,
7480
mixed_types=ds.mixed_types(),
7581
seed=GLOBAL_SEED,
7682
).to(self.device)
@@ -98,17 +104,8 @@ def test_output_shapes(self) -> None:
98104
self.assertEqual(ret["force"].shape, (1, self.natoms, 3))
99105
self.assertEqual(ret["virial"].shape, (1, 9))
100106

101-
def test_forward_lower_exportable(self) -> None:
102-
"""Test that EnergyModel.forward_lower returns an exportable module.
103-
104-
forward_lower() uses make_fx to trace through torch.autograd.grad,
105-
decomposing the backward pass into primitive ops. The returned module
106-
can be passed directly to torch.export.export.
107-
"""
108-
md = self._make_model()
109-
md.eval()
110-
111-
# Prepare extended coords and neighbor list using dpmodel utilities
107+
def _prepare_lower_inputs(self):
108+
"""Build extended coords, atype, nlist, mapping as torch tensors."""
112109
coord_np = self.coord.detach().cpu().numpy()
113110
atype_np = self.atype.detach().cpu().numpy()
114111
cell_np = self.cell.reshape(1, 9).detach().cpu().numpy()
@@ -131,8 +128,6 @@ def test_forward_lower_exportable(self) -> None:
131128
distinguish_types=True,
132129
)
133130
extended_coord = extended_coord.reshape(1, -1, 3)
134-
135-
# Convert to torch tensors
136131
ext_coord = torch.tensor(
137132
extended_coord,
138133
dtype=torch.float64,
@@ -145,63 +140,195 @@ def test_forward_lower_exportable(self) -> None:
145140
)
146141
nlist_t = torch.tensor(nlist, dtype=torch.int64, device=self.device)
147142
mapping_t = torch.tensor(mapping, dtype=torch.int64, device=self.device)
143+
return ext_coord, ext_atype, nlist_t, mapping_t
144+
145+
def test_forward_lower_exportable(self) -> None:
146+
"""Test that EnergyModel.forward_lower returns an exportable module.
147+
148+
forward_lower() uses make_fx to trace through torch.autograd.grad,
149+
decomposing the backward pass into primitive ops. The returned module
150+
can be passed directly to torch.export.export.
151+
152+
The test builds a model with numb_fparam > 0 and numb_aparam > 0 and
153+
verifies that:
154+
1. The traced / exported module reproduces eager results (zero params).
155+
2. The traced / exported module reproduces eager results with non-zero
156+
fparam and aparam (ruling out baked-in constants).
157+
3. Changing fparam or aparam at runtime actually changes the output.
158+
"""
159+
numb_fparam = 2
160+
numb_aparam = 3
161+
md = self._make_model(
162+
numb_fparam=numb_fparam,
163+
numb_aparam=numb_aparam,
164+
)
165+
md.eval()
148166

149-
# Eager reference via _forward_lower
150-
ret0 = md._forward_lower(
167+
ext_coord, ext_atype, nlist_t, mapping_t = self._prepare_lower_inputs()
168+
nframes = ext_coord.shape[0]
169+
nloc = self.natoms
170+
output_keys = ("energy", "extended_force", "virial", "extended_virial")
171+
172+
fparam_zero = torch.zeros(
173+
nframes,
174+
numb_fparam,
175+
dtype=torch.float64,
176+
device=self.device,
177+
)
178+
aparam_zero = torch.zeros(
179+
nframes,
180+
nloc,
181+
numb_aparam,
182+
dtype=torch.float64,
183+
device=self.device,
184+
)
185+
186+
# --- eager reference with zero params ---
187+
ret_eager_zero = md._forward_lower(
151188
ext_coord.requires_grad_(True),
152189
ext_atype,
153190
nlist_t,
154191
mapping_t,
192+
fparam=fparam_zero,
193+
aparam=aparam_zero,
155194
do_atomic_virial=True,
156195
)
157-
self.assertIn("energy", ret0)
158-
self.assertIn("extended_force", ret0)
159-
self.assertIn("virial", ret0)
160-
self.assertIn("extended_virial", ret0)
196+
for key in output_keys:
197+
self.assertIn(key, ret_eager_zero)
161198

162-
# forward_lower returns a traced module
199+
# --- trace and export ---
163200
traced = md.forward_lower(
164201
ext_coord,
165202
ext_atype,
166203
nlist_t,
167204
mapping_t,
205+
fparam=fparam_zero,
206+
aparam=aparam_zero,
168207
do_atomic_virial=True,
169208
)
170209
self.assertIsInstance(traced, torch.nn.Module)
171210

172-
# The traced module should be directly exportable
173211
exported = torch.export.export(
174212
traced,
175-
(ext_coord, ext_atype, nlist_t, mapping_t),
213+
(ext_coord, ext_atype, nlist_t, mapping_t, fparam_zero, aparam_zero),
176214
strict=False,
177215
)
178216
self.assertIsNotNone(exported)
179217

180-
# Verify exported model produces same output
181-
ret1 = exported.module()(ext_coord, ext_atype, nlist_t, mapping_t)
182-
np.testing.assert_allclose(
183-
ret0["energy"].detach().cpu().numpy(),
184-
ret1["energy"].detach().cpu().numpy(),
185-
rtol=1e-10,
186-
atol=1e-10,
218+
# --- verify traced/exported match eager (zero params) ---
219+
ret_traced_zero = traced(
220+
ext_coord,
221+
ext_atype,
222+
nlist_t,
223+
mapping_t,
224+
fparam_zero,
225+
aparam_zero,
187226
)
188-
np.testing.assert_allclose(
189-
ret0["extended_force"].detach().cpu().numpy(),
190-
ret1["extended_force"].detach().cpu().numpy(),
191-
rtol=1e-10,
192-
atol=1e-10,
227+
ret_exported_zero = exported.module()(
228+
ext_coord,
229+
ext_atype,
230+
nlist_t,
231+
mapping_t,
232+
fparam_zero,
233+
aparam_zero,
193234
)
194-
np.testing.assert_allclose(
195-
ret0["virial"].detach().cpu().numpy(),
196-
ret1["virial"].detach().cpu().numpy(),
197-
rtol=1e-10,
198-
atol=1e-10,
235+
for key in output_keys:
236+
np.testing.assert_allclose(
237+
ret_eager_zero[key].detach().cpu().numpy(),
238+
ret_traced_zero[key].detach().cpu().numpy(),
239+
rtol=1e-10,
240+
atol=1e-10,
241+
err_msg=f"traced vs eager (zero params): {key}",
242+
)
243+
np.testing.assert_allclose(
244+
ret_eager_zero[key].detach().cpu().numpy(),
245+
ret_exported_zero[key].detach().cpu().numpy(),
246+
rtol=1e-10,
247+
atol=1e-10,
248+
err_msg=f"exported vs eager (zero params): {key}",
249+
)
250+
251+
# --- verify traced/exported match eager (non-zero params) ---
252+
fparam_nz = torch.ones(
253+
nframes,
254+
numb_fparam,
255+
dtype=torch.float64,
256+
device=self.device,
199257
)
200-
np.testing.assert_allclose(
201-
ret0["extended_virial"].detach().cpu().numpy(),
202-
ret1["extended_virial"].detach().cpu().numpy(),
203-
rtol=1e-10,
204-
atol=1e-10,
258+
aparam_nz = torch.ones(
259+
nframes,
260+
nloc,
261+
numb_aparam,
262+
dtype=torch.float64,
263+
device=self.device,
264+
)
265+
ret_eager_nz = md._forward_lower(
266+
ext_coord.requires_grad_(True),
267+
ext_atype,
268+
nlist_t,
269+
mapping_t,
270+
fparam=fparam_nz,
271+
aparam=aparam_nz,
272+
do_atomic_virial=True,
273+
)
274+
ret_traced_nz = traced(
275+
ext_coord,
276+
ext_atype,
277+
nlist_t,
278+
mapping_t,
279+
fparam_nz,
280+
aparam_nz,
281+
)
282+
ret_exported_nz = exported.module()(
283+
ext_coord,
284+
ext_atype,
285+
nlist_t,
286+
mapping_t,
287+
fparam_nz,
288+
aparam_nz,
289+
)
290+
for key in output_keys:
291+
np.testing.assert_allclose(
292+
ret_eager_nz[key].detach().cpu().numpy(),
293+
ret_traced_nz[key].detach().cpu().numpy(),
294+
rtol=1e-10,
295+
atol=1e-10,
296+
err_msg=f"traced vs eager (non-zero params): {key}",
297+
)
298+
np.testing.assert_allclose(
299+
ret_eager_nz[key].detach().cpu().numpy(),
300+
ret_exported_nz[key].detach().cpu().numpy(),
301+
rtol=1e-10,
302+
atol=1e-10,
303+
err_msg=f"exported vs eager (non-zero params): {key}",
304+
)
305+
306+
# --- verify fparam is dynamic (changing it changes the output) ---
307+
self.assertFalse(
308+
np.allclose(
309+
ret_traced_zero["energy"].detach().cpu().numpy(),
310+
ret_traced_nz["energy"].detach().cpu().numpy(),
311+
),
312+
"Changing fparam did not change output — "
313+
"fparam may be baked in as a constant",
314+
)
315+
316+
# --- verify aparam is dynamic (changing it changes the output) ---
317+
ret_traced_ap = traced(
318+
ext_coord,
319+
ext_atype,
320+
nlist_t,
321+
mapping_t,
322+
fparam_zero,
323+
aparam_nz,
324+
)
325+
self.assertFalse(
326+
np.allclose(
327+
ret_traced_zero["energy"].detach().cpu().numpy(),
328+
ret_traced_ap["energy"].detach().cpu().numpy(),
329+
),
330+
"Changing aparam did not change output — "
331+
"aparam may be baked in as a constant",
205332
)
206333

207334
def test_dp_consistency(self) -> None:

0 commit comments

Comments
 (0)