Skip to content

Commit b16dc7f

Browse files
iProzdChiahsinChu
authored andcommitted
feat(pt/pd): add size option to dp show (deepmodeling#4783)
<!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - **New Features** - Added the ability to display model parameter counts using the "size" attribute in the "show" command. - Users can now view detailed parameter counts for descriptor, fitting-net, and total parameters for both single-task and multi-task models. - **Tests** - Updated tests to verify correct output of model parameter counts when using the new "size" attribute. - **Documentation** - Added new documentation for the "show" command detailing usage and output for various model attributes, including the new "size" attribute. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
1 parent 5369e80 commit b16dc7f

8 files changed

Lines changed: 188 additions & 25 deletions

File tree

deepmd/entrypoints/show.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,3 +63,9 @@ def show(
6363
else:
6464
fitting_net = model_params["fitting_net"]
6565
log.info(f"The fitting_net parameter is {fitting_net}")
66+
if "size" in ATTRIBUTES:
67+
size_dict = model.get_model_size()
68+
log_prefix = " for a single branch model" if model_is_multi_task else ""
69+
log.info(f"Parameter counts{log_prefix}:")
70+
for k in sorted(size_dict):
71+
log.info(f"Parameters in {k}: {size_dict[k]:,}")

deepmd/infer/deep_eval.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -291,6 +291,10 @@ def get_model_def_script(self) -> dict:
291291
"""Get model definition script."""
292292
raise NotImplementedError("Not implemented in this backend.")
293293

294+
def get_model_size(self) -> dict:
295+
"""Get model parameter count."""
296+
raise NotImplementedError("Not implemented in this backend.")
297+
294298

295299
class DeepEval(ABC):
296300
"""High-level Deep Evaluator interface.
@@ -560,3 +564,7 @@ def get_ntypes_spin(self) -> int:
560564
def get_model_def_script(self) -> dict:
561565
"""Get model definition script."""
562566
return self.deep_eval.get_model_def_script()
567+
568+
def get_model_size(self) -> dict:
569+
"""Get model parameter count."""
570+
return self.deep_eval.get_model_size()

deepmd/main.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -851,7 +851,7 @@ def main_parser() -> argparse.ArgumentParser:
851851
)
852852
parser_show.add_argument(
853853
"ATTRIBUTES",
854-
choices=["model-branch", "type-map", "descriptor", "fitting-net"],
854+
choices=["model-branch", "type-map", "descriptor", "fitting-net", "size"],
855855
nargs="+",
856856
)
857857
return parser

deepmd/pd/infer/deep_eval.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -482,6 +482,30 @@ def get_model_def_script(self) -> str:
482482
"""Get model definition script."""
483483
return self.model_def_script
484484

485+
def get_model_size(self) -> dict:
486+
"""Get model parameter count.
487+
488+
Returns
489+
-------
490+
dict
491+
A dictionary containing the number of parameters in the model.
492+
The keys are 'descriptor', 'fitting_net', and 'total'.
493+
"""
494+
params_dict = dict(self.dp.named_parameters())
495+
sum_param_des = sum(
496+
params_dict[k].numel() for k in params_dict.keys() if "descriptor" in k
497+
)
498+
sum_param_fit = sum(
499+
params_dict[k].numel()
500+
for k in params_dict.keys()
501+
if "fitting" in k and "_networks" not in k
502+
)
503+
return {
504+
"descriptor": sum_param_des,
505+
"fitting-net": sum_param_fit,
506+
"total": sum_param_des + sum_param_fit,
507+
}
508+
485509
def eval_descriptor(
486510
self,
487511
coords: np.ndarray,

deepmd/pt/infer/deep_eval.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -624,6 +624,30 @@ def get_model_def_script(self) -> str:
624624
"""Get model definition script."""
625625
return self.model_def_script
626626

627+
def get_model_size(self) -> dict:
628+
"""Get model parameter count.
629+
630+
Returns
631+
-------
632+
dict
633+
A dictionary containing the number of parameters in the model.
634+
The keys are 'descriptor', 'fitting_net', and 'total'.
635+
"""
636+
params_dict = dict(self.dp.named_parameters())
637+
sum_param_des = sum(
638+
params_dict[k].numel() for k in params_dict.keys() if "descriptor" in k
639+
)
640+
sum_param_fit = sum(
641+
params_dict[k].numel()
642+
for k in params_dict.keys()
643+
if "fitting" in k and "_networks" not in k
644+
)
645+
return {
646+
"descriptor": sum_param_des,
647+
"fitting-net": sum_param_fit,
648+
"total": sum_param_des + sum_param_fit,
649+
}
650+
627651
def eval_descriptor(
628652
self,
629653
coords: np.ndarray,

doc/model/index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,3 +28,4 @@ Model
2828
pairtab
2929
change-bias
3030
precision
31+
show-model-info

doc/model/show-model-info.md

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
# Use `dp show` to show the model information
2+
3+
The `dp show` command is designed to display essential information about a trained model checkpoint or frozen model file.
4+
This utility helps to understand the model's architecture, configuration, and parameter statistics in both single-task and multi-task settings.
5+
6+
## Command Syntax
7+
8+
```bash
9+
dp --pt show <INPUT> <ATTRIBUTES...>
10+
```
11+
12+
- `<INPUT>`: Path to the model checkpoint file or frozen model file.
13+
- `<ATTRIBUTES>`: One or more information categories to display. Supported values are:
14+
15+
- `model-branch`: Shows available branches for multi-task models.
16+
- `type-map`: Shows the type mapping used by the model.
17+
- `descriptor`: Displays the model descriptor parameters.
18+
- `fitting-net`: Displays parameters of the fitting network.
19+
- `size`: (Supported Backends: PyTorch and PaddlePaddle) Shows the parameter counts for various components.
20+
21+
## Example Usage
22+
23+
```bash
24+
# For a multi-task model (model.pt)
25+
dp show model.pt model-branch type-map descriptor fitting-net size
26+
27+
# For a single-task frozen model (frozen_model.pth)
28+
dp show frozen_model.pth type-map descriptor fitting-net size
29+
```
30+
31+
## Output Description
32+
33+
Depending on the provided attributes and the model type, the output includes:
34+
35+
- **Model Type**
36+
37+
- Logs whether the loaded model is a _singletask_ or _multitask_ model.
38+
39+
- **model-branch**
40+
41+
- _Only available for multitask models._
42+
- Lists all available model branches and the special `"RANDOM"` branch, which refers to a randomly initialized fitting net.
43+
44+
- **type-map**
45+
46+
- For multitask models: Shows the type map for each branch.
47+
- For singletask models: Shows the model's type map.
48+
49+
- **descriptor**
50+
51+
- For multitask models: Displays the descriptor parameter for each branch.
52+
- For singletask models: Displays the descriptor parameter.
53+
54+
- **fitting-net**
55+
56+
- For multitask models: Shows the fitting network parameters for each branch.
57+
- For singletask models: Shows the fitting network parameters.
58+
59+
- **size**
60+
61+
- Prints the number of parameters for each component (`descriptor`, `fitting-net`, etc.), as well as the total parameter count.
62+
63+
## Example Output
64+
65+
For a singletask model, the output might look like:
66+
67+
```
68+
This is a singletask model
69+
The type_map is ['O', 'H', 'Au']
70+
The descriptor parameter is {'type': 'se_e2_a', 'sel': [46, 92, 4], 'rcut': 4.0}
71+
The fitting_net parameter is {'neuron': [24, 24, 24], 'resnet_dt': True, 'seed': 1}
72+
Parameter counts:
73+
Parameters in descriptor: 19,350
74+
Parameters in fitting-net: 119,091
75+
Parameters in total: 138,441
76+
```
77+
78+
For a multitask model, if `model-branch` is selected, it will additionally display available branches:
79+
80+
```
81+
This is a multitask model
82+
Available model branches are ['branch1', 'branch2', 'RANDOM'], where 'RANDOM' means using a randomly initialized fitting net.
83+
...
84+
```

source/tests/pt/test_dp_show.py

Lines changed: 40 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -47,35 +47,43 @@ def setUp(self) -> None:
4747

4848
def test_checkpoint(self) -> None:
4949
INPUT = "model.pt"
50-
ATTRIBUTES = "type-map descriptor fitting-net"
50+
ATTRIBUTES = "type-map descriptor fitting-net size"
5151
with redirect_stderr(io.StringIO()) as f:
5252
run_dp(f"dp --pt show {INPUT} {ATTRIBUTES}")
5353
results = f.getvalue().split("\n")[:-1]
54-
assert "This is a singletask model" in results[-4]
55-
assert "The type_map is ['O', 'H', 'Au']" in results[-3]
54+
assert "This is a singletask model" in results[-8]
55+
assert "The type_map is ['O', 'H', 'Au']" in results[-7]
5656
assert (
5757
"{'type': 'se_e2_a'" and "'sel': [46, 92, 4]" and "'rcut': 4.0"
58-
) in results[-2]
58+
) in results[-6]
5959
assert (
6060
"The fitting_net parameter is {'neuron': [24, 24, 24], 'resnet_dt': True, 'seed': 1}"
61-
in results[-1]
61+
in results[-5]
6262
)
63+
assert "Parameter counts:" in results[-4]
64+
assert "Parameters in descriptor: 19,350" in results[-3]
65+
assert "Parameters in fitting-net: 119,091" in results[-2]
66+
assert "Parameters in total: 138,441" in results[-1]
6367

6468
def test_frozen_model(self) -> None:
6569
INPUT = "frozen_model.pth"
66-
ATTRIBUTES = "type-map descriptor fitting-net"
70+
ATTRIBUTES = "type-map descriptor fitting-net size"
6771
with redirect_stderr(io.StringIO()) as f:
6872
run_dp(f"dp --pt show {INPUT} {ATTRIBUTES}")
6973
results = f.getvalue().split("\n")[:-1]
70-
assert "This is a singletask model" in results[-4]
71-
assert "The type_map is ['O', 'H', 'Au']" in results[-3]
74+
assert "This is a singletask model" in results[-8]
75+
assert "The type_map is ['O', 'H', 'Au']" in results[-7]
7276
assert (
7377
"{'type': 'se_e2_a'" and "'sel': [46, 92, 4]" and "'rcut': 4.0"
74-
) in results[-2]
78+
) in results[-6]
7579
assert (
7680
"The fitting_net parameter is {'neuron': [24, 24, 24], 'resnet_dt': True, 'seed': 1}"
77-
in results[-1]
81+
in results[-5]
7882
)
83+
assert "Parameter counts:" in results[-4]
84+
assert "Parameters in descriptor: 19,350" in results[-3]
85+
assert "Parameters in fitting-net: 119,091" in results[-2]
86+
assert "Parameters in total: 138,441" in results[-1]
7987

8088
def test_checkpoint_error(self) -> None:
8189
INPUT = "model.pt"
@@ -144,54 +152,62 @@ def setUp(self) -> None:
144152

145153
def test_checkpoint(self) -> None:
146154
INPUT = "model.ckpt.pt"
147-
ATTRIBUTES = "model-branch type-map descriptor fitting-net"
155+
ATTRIBUTES = "model-branch type-map descriptor fitting-net size"
148156
with redirect_stderr(io.StringIO()) as f:
149157
run_dp(f"dp --pt show {INPUT} {ATTRIBUTES}")
150158
results = f.getvalue().split("\n")[:-1]
151-
assert "This is a multitask model" in results[-8]
159+
assert "This is a multitask model" in results[-12]
152160
assert (
153161
"Available model branches are ['model_1', 'model_2', 'RANDOM'], "
154162
"where 'RANDOM' means using a randomly initialized fitting net."
155-
in results[-7]
163+
in results[-11]
156164
)
157-
assert "The type_map of branch model_1 is ['O', 'H', 'B']" in results[-6]
158-
assert "The type_map of branch model_2 is ['O', 'H', 'B']" in results[-5]
165+
assert "The type_map of branch model_1 is ['O', 'H', 'B']" in results[-10]
166+
assert "The type_map of branch model_2 is ['O', 'H', 'B']" in results[-9]
159167
assert (
160168
"model_1"
161169
and "'type': 'se_e2_a'"
162170
and "'sel': [46, 92, 4]"
163171
and "'rcut_smth': 0.5"
164-
) in results[-4]
172+
) in results[-8]
165173
assert (
166174
"model_2"
167175
and "'type': 'se_e2_a'"
168176
and "'sel': [46, 92, 4]"
169177
and "'rcut_smth': 0.5"
170-
) in results[-3]
178+
) in results[-7]
171179
assert (
172180
"The fitting_net parameter of branch model_1 is {'neuron': [1, 2, 3], 'seed': 678}"
173-
in results[-2]
181+
in results[-6]
174182
)
175183
assert (
176184
"The fitting_net parameter of branch model_2 is {'neuron': [9, 8, 7], 'seed': 1111}"
177-
in results[-1]
185+
in results[-5]
178186
)
187+
assert "Parameter counts for a single branch model:" in results[-4]
188+
assert "Parameters in descriptor: 19,350" in results[-3]
189+
assert "Parameters in fitting-net: 4,860" in results[-2]
190+
assert "Parameters in total: 24,210" in results[-1]
179191

180192
def test_frozen_model(self) -> None:
181193
INPUT = "frozen_model.pth"
182-
ATTRIBUTES = "type-map descriptor fitting-net"
194+
ATTRIBUTES = "type-map descriptor fitting-net size"
183195
with redirect_stderr(io.StringIO()) as f:
184196
run_dp(f"dp --pt show {INPUT} {ATTRIBUTES}")
185197
results = f.getvalue().split("\n")[:-1]
186-
assert "This is a singletask model" in results[-4]
187-
assert "The type_map is ['O', 'H', 'B']" in results[-3]
198+
assert "This is a singletask model" in results[-8]
199+
assert "The type_map is ['O', 'H', 'B']" in results[-7]
188200
assert (
189201
"'type': 'se_e2_a'" and "'sel': [46, 92, 4]" and "'rcut_smth': 0.5"
190-
) in results[-2]
202+
) in results[-6]
191203
assert (
192204
"The fitting_net parameter is {'neuron': [1, 2, 3], 'seed': 678}"
193-
in results[-1]
205+
in results[-5]
194206
)
207+
assert "Parameter counts:" in results[-4]
208+
assert "Parameters in descriptor: 19,350" in results[-3]
209+
assert "Parameters in fitting-net: 4,860" in results[-2]
210+
assert "Parameters in total: 24,210" in results[-1]
195211

196212
def tearDown(self) -> None:
197213
for f in os.listdir("."):

0 commit comments

Comments
 (0)