Skip to content

Commit 6b4748d

Browse files
author
Han Wang
committed
fix performance issue when type_one_side == False
1 parent 115ec93 commit 6b4748d

1 file changed

Lines changed: 40 additions & 23 deletions

File tree

deepmd/dpmodel/descriptor/se_e2_a.py

Lines changed: 40 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -453,30 +453,47 @@ def call(
453453
rr = xp.reshape(rr, (nf * nloc, nnei, 4))
454454
rr = xp.astype(rr, self.dstd.dtype)
455455

456-
if not self.type_one_side:
457-
# nf x nloc -> (nf * nloc)
456+
if self.type_one_side:
457+
for tt in range(self.ntypes):
458+
mm = exclude_mask[:, sec[tt] : sec[tt + 1]]
459+
tr = rr[:, sec[tt] : sec[tt + 1], :]
460+
tr = tr * xp.astype(mm[:, :, None], tr.dtype)
461+
ss = tr[..., 0:1]
462+
gg = self.cal_g(ss, (tt,))
463+
gr += xp.sum(gg[:, :, :, None] * tr[:, :, None, :], axis=1)
464+
else:
465+
# Sort atoms by center type so each type forms a contiguous block.
466+
# Slice indexing (arr[s:e]) is array-api compatible and lets us
467+
# run cal_g only on atoms of the matching center type, keeping the
468+
# same O(nf*nloc) total embedding cost as the original numpy code.
458469
atype_loc = xp.reshape(atype_ext[:, :nloc], (nf * nloc,))
459-
460-
for embedding_idx in itertools.product(
461-
range(self.ntypes), repeat=self.embeddings.ndim
462-
):
463-
if self.type_one_side:
464-
(tt,) = embedding_idx
465-
else:
466-
ti, tt = embedding_idx
467-
mm = exclude_mask[:, sec[tt] : sec[tt + 1]]
468-
tr = rr[:, sec[tt] : sec[tt + 1], :]
469-
tr = tr * xp.astype(mm[:, :, None], tr.dtype)
470-
ss = tr[..., 0:1]
471-
gg = self.cal_g(ss, embedding_idx)
472-
gr_tmp = xp.sum(gg[:, :, :, None] * tr[:, :, None, :], axis=1)
473-
if not self.type_one_side:
474-
# (nf * nloc) x 1 x 1
475-
ti_mask = xp.astype(
476-
xp.reshape(atype_loc == ti, (nf * nloc, 1, 1)), gr_tmp.dtype
477-
)
478-
gr_tmp = gr_tmp * ti_mask
479-
gr += gr_tmp
470+
sort_idx = xp.argsort(atype_loc)
471+
unsort_idx = xp.argsort(sort_idx)
472+
rr_s = xp.take(rr, sort_idx, axis=0)
473+
mask_s = xp.take(exclude_mask, sort_idx, axis=0)
474+
dev = array_api_compat.device(coord_ext)
475+
gr_s = xp.zeros([nf * nloc, ng, 4], dtype=input_dtype, device=dev)
476+
# Per-type boundaries in sorted order
477+
type_ends = []
478+
offset = 0
479+
for ti in range(self.ntypes):
480+
offset += int(xp.sum(xp.astype(atype_loc == ti, xp.int32)))
481+
type_ends.append(offset)
482+
type_starts = [0, *type_ends[:-1]]
483+
for ti in range(self.ntypes):
484+
s, e = type_starts[ti], type_ends[ti]
485+
if s == e:
486+
continue
487+
for tt in range(self.ntypes):
488+
mm = mask_s[s:e, sec[tt] : sec[tt + 1]]
489+
tr = rr_s[s:e, sec[tt] : sec[tt + 1], :]
490+
tr = tr * xp.astype(mm[:, :, None], tr.dtype)
491+
ss = tr[..., 0:1]
492+
gg = self.cal_g(ss, (ti, tt))
493+
gr_s[s:e] = gr_s[s:e] + xp.sum(
494+
gg[:, :, :, None] * tr[:, :, None, :], axis=1
495+
)
496+
gr = xp.take(gr_s, unsort_idx, axis=0)
480497
gr = xp.reshape(gr, (nf, nloc, ng, 4))
481498
# nf x nloc x ng x 4
482499
gr /= self.nnei

0 commit comments

Comments
 (0)