You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
feat(dpa4): so3_readout across pt + dpmodel/pt_expt backends (#5561)
## What
Adds the DPA4/SeZM `so3_readout` option (`"none"` / `"glu"` / `"mlp"`)
**across all backends** (pt + dpmodel + pt_expt), making it
cross-backend consistent.
Builds on **#5556** (@OutisLi): its pt `so3_readout` commit
(`refactor(dpa4): output ffn`) is included here with original authorship
preserved; this PR adds the missing **dpmodel** counterpart so the
shared DPA4 serialize format round-trips across backends. (The unrelated
`nv_nlist`/compiler-check fixes from #5556 are intentionally left to
#5556.)
## Why
`so3_readout` is implemented by configuring the final output FFN —
`"glu"`/`"mlp"` turn on the SO(3)-grid FFN (`ffn_so3_grid`, `grid_mlp`).
On its own (pt-only, as in #5556) it breaks DPA4 cross-backend
consistency: pt `serialize()` emits `so3_readout` but dpmodel
`DescrptDPA4` couldn't round-trip it →
`source/tests/consistent/descriptor/test_dpa4.py::...::test_pt_consistent_with_ref`
failed on every Test Python shard.
This is now feasible and small because **#5555** already ported
`ffn_so3_grid` + the SO(3)-grid machinery
(`SO3GridNet`/`GridMLP`/`GridProduct`) into the dpmodel
`EquivariantFFN`. So the dpmodel `so3_readout` is just: accept the
param, configure `output_ffn` exactly like pt, wire the readout (l=0
slice for `"none"`; full `(N,D,1,C)` fold for `"glu"`/`"mlp"` then slice
l=0), and serialize the key. pt_expt auto-wraps.
## Changes
- **pt** (from #5556): `so3_readout` in `DescrptSeZM` + argcheck +
`examples/water/dpa4/input.json`.
- **dpmodel** `descriptor/dpa4.py`: `so3_readout` param + validation;
`output_ffn` configured (`lmax=node_l_schedule[-1]`, `kmax=min(kmax,
readout_lmax)`, `ffn_so3_grid`, `grid_mlp`, `grid_branch=0`); readout
forward mirrors pt; serialize the key.
- **pt_expt**: auto-wrapped (no explicit change).
## Validation
- `test_dpa4.py` cross-backend consistency rows for `so3_readout ∈
{none, glu, mlp}` (pt vs dpmodel vs pt_expt, mixed_types) — green;
`test_pt_consistent_with_ref` now passes.
- Full-descriptor pt→dpmodel parity (weight-copied, `glu`+`mlp`) —
**~7e-15 abs** (gate 1e-10), proving serialize interop.
- dpa4 suite: 611 passed; ruff clean.
## Notes
- Depends on #5555 (merged) for the dpmodel SO(3)-grid FFN.
- `so3_readout` no longer "(Supported Backend: PyTorch)" — now
multi-backend.
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
## Release Notes
* **New Features**
* Added a configurable `so3_readout` option to the DPA4 and SeZM
descriptors (modes: `"none"`, `"glu"`, `"mlp"`), controlling how the
final SO(3) readout is computed.
* The setting is included in descriptor configuration
serialization/deserialization to support round-tripping.
* Updated the water DPA4 example to use `so3_readout: "mlp"`.
* **Tests**
* Added tests covering multiple readout modes, backend parity between
implementations, and correct behavior for edge-free scenarios.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
---------
Co-authored-by: OutisLi <LTC201806070316@gmail.com>
Co-authored-by: Han Wang <wang_han@iapcm.ac.cn>
0 commit comments