Upload folder using huggingface_hub
Browse files- .gitattributes +22 -10
- README.md +146 -0
- configuration.json +1 -0
- data/high_level_water.xyz +0 -0
- model/__init__.py +31 -0
- model/adapter.py +94 -0
- model/mattersim.py +201 -0
- scripts/batch_inference.py +32 -0
- scripts/finetune.py +74 -0
- scripts/finetune_config.yaml +44 -0
- scripts/md.py +27 -0
- scripts/relax.py +26 -0
- scripts/single_point.py +30 -0
- weight/mattersim-v1.0.0-1M.pth +3 -0
.gitattributes
CHANGED
|
@@ -1,35 +1,47 @@
|
|
| 1 |
*.7z filter=lfs diff=lfs merge=lfs -text
|
| 2 |
*.arrow filter=lfs diff=lfs merge=lfs -text
|
| 3 |
*.bin filter=lfs diff=lfs merge=lfs -text
|
|
|
|
| 4 |
*.bz2 filter=lfs diff=lfs merge=lfs -text
|
| 5 |
-
*.ckpt filter=lfs diff=lfs merge=lfs -text
|
| 6 |
*.ftz filter=lfs diff=lfs merge=lfs -text
|
| 7 |
*.gz filter=lfs diff=lfs merge=lfs -text
|
| 8 |
*.h5 filter=lfs diff=lfs merge=lfs -text
|
| 9 |
*.joblib filter=lfs diff=lfs merge=lfs -text
|
| 10 |
*.lfs.* filter=lfs diff=lfs merge=lfs -text
|
| 11 |
-
*.mlmodel filter=lfs diff=lfs merge=lfs -text
|
| 12 |
*.model filter=lfs diff=lfs merge=lfs -text
|
| 13 |
*.msgpack filter=lfs diff=lfs merge=lfs -text
|
| 14 |
-
*.npy filter=lfs diff=lfs merge=lfs -text
|
| 15 |
-
*.npz filter=lfs diff=lfs merge=lfs -text
|
| 16 |
*.onnx filter=lfs diff=lfs merge=lfs -text
|
| 17 |
*.ot filter=lfs diff=lfs merge=lfs -text
|
| 18 |
*.parquet filter=lfs diff=lfs merge=lfs -text
|
| 19 |
*.pb filter=lfs diff=lfs merge=lfs -text
|
| 20 |
-
*.pickle filter=lfs diff=lfs merge=lfs -text
|
| 21 |
-
*.pkl filter=lfs diff=lfs merge=lfs -text
|
| 22 |
*.pt filter=lfs diff=lfs merge=lfs -text
|
| 23 |
*.pth filter=lfs diff=lfs merge=lfs -text
|
| 24 |
*.rar filter=lfs diff=lfs merge=lfs -text
|
| 25 |
-
*.safetensors filter=lfs diff=lfs merge=lfs -text
|
| 26 |
saved_model/**/* filter=lfs diff=lfs merge=lfs -text
|
| 27 |
*.tar.* filter=lfs diff=lfs merge=lfs -text
|
| 28 |
-
*.tar filter=lfs diff=lfs merge=lfs -text
|
| 29 |
*.tflite filter=lfs diff=lfs merge=lfs -text
|
| 30 |
*.tgz filter=lfs diff=lfs merge=lfs -text
|
| 31 |
-
*.wasm filter=lfs diff=lfs merge=lfs -text
|
| 32 |
*.xz filter=lfs diff=lfs merge=lfs -text
|
| 33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
| 35 |
-
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
|
|
|
| 1 |
*.7z filter=lfs diff=lfs merge=lfs -text
|
| 2 |
*.arrow filter=lfs diff=lfs merge=lfs -text
|
| 3 |
*.bin filter=lfs diff=lfs merge=lfs -text
|
| 4 |
+
*.bin.* filter=lfs diff=lfs merge=lfs -text
|
| 5 |
*.bz2 filter=lfs diff=lfs merge=lfs -text
|
|
|
|
| 6 |
*.ftz filter=lfs diff=lfs merge=lfs -text
|
| 7 |
*.gz filter=lfs diff=lfs merge=lfs -text
|
| 8 |
*.h5 filter=lfs diff=lfs merge=lfs -text
|
| 9 |
*.joblib filter=lfs diff=lfs merge=lfs -text
|
| 10 |
*.lfs.* filter=lfs diff=lfs merge=lfs -text
|
|
|
|
| 11 |
*.model filter=lfs diff=lfs merge=lfs -text
|
| 12 |
*.msgpack filter=lfs diff=lfs merge=lfs -text
|
|
|
|
|
|
|
| 13 |
*.onnx filter=lfs diff=lfs merge=lfs -text
|
| 14 |
*.ot filter=lfs diff=lfs merge=lfs -text
|
| 15 |
*.parquet filter=lfs diff=lfs merge=lfs -text
|
| 16 |
*.pb filter=lfs diff=lfs merge=lfs -text
|
|
|
|
|
|
|
| 17 |
*.pt filter=lfs diff=lfs merge=lfs -text
|
| 18 |
*.pth filter=lfs diff=lfs merge=lfs -text
|
| 19 |
*.rar filter=lfs diff=lfs merge=lfs -text
|
|
|
|
| 20 |
saved_model/**/* filter=lfs diff=lfs merge=lfs -text
|
| 21 |
*.tar.* filter=lfs diff=lfs merge=lfs -text
|
|
|
|
| 22 |
*.tflite filter=lfs diff=lfs merge=lfs -text
|
| 23 |
*.tgz filter=lfs diff=lfs merge=lfs -text
|
|
|
|
| 24 |
*.xz filter=lfs diff=lfs merge=lfs -text
|
| 25 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
| 26 |
+
*.zstandard filter=lfs diff=lfs merge=lfs -text
|
| 27 |
+
*.tfevents* filter=lfs diff=lfs merge=lfs -text
|
| 28 |
+
*.db* filter=lfs diff=lfs merge=lfs -text
|
| 29 |
+
*.ark* filter=lfs diff=lfs merge=lfs -text
|
| 30 |
+
**/*ckpt*data* filter=lfs diff=lfs merge=lfs -text
|
| 31 |
+
**/*ckpt*.meta filter=lfs diff=lfs merge=lfs -text
|
| 32 |
+
**/*ckpt*.index filter=lfs diff=lfs merge=lfs -text
|
| 33 |
+
*.safetensors filter=lfs diff=lfs merge=lfs -text
|
| 34 |
+
*.ckpt filter=lfs diff=lfs merge=lfs -text
|
| 35 |
+
*.gguf* filter=lfs diff=lfs merge=lfs -text
|
| 36 |
+
*.ggml filter=lfs diff=lfs merge=lfs -text
|
| 37 |
+
*.llamafile* filter=lfs diff=lfs merge=lfs -text
|
| 38 |
+
*.pt2 filter=lfs diff=lfs merge=lfs -text
|
| 39 |
+
*.mlmodel filter=lfs diff=lfs merge=lfs -text
|
| 40 |
+
*.npy filter=lfs diff=lfs merge=lfs -text
|
| 41 |
+
*.npz filter=lfs diff=lfs merge=lfs -text
|
| 42 |
+
*.pickle filter=lfs diff=lfs merge=lfs -text
|
| 43 |
+
*.pkl filter=lfs diff=lfs merge=lfs -text
|
| 44 |
+
*.tar filter=lfs diff=lfs merge=lfs -text
|
| 45 |
+
*.wasm filter=lfs diff=lfs merge=lfs -text
|
| 46 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
| 47 |
+
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
README.md
ADDED
|
@@ -0,0 +1,146 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<p align="center">
|
| 2 |
+
<strong>
|
| 3 |
+
<span style="font-size: 30px;">MatterSim</span>
|
| 4 |
+
</strong>
|
| 5 |
+
</p>
|
| 6 |
+
|
| 7 |
+
# Model Introduction
|
| 8 |
+
|
| 9 |
+
MatterSim is a deep-learning interatomic potential model across elements, temperatures, and pressures proposed by Microsoft Research. It predicts energy and forces for inorganic materials, molecules, and periodic systems.
|
| 10 |
+
|
| 11 |
+
Paper: *MatterSim: A deep-learning atomistic model across elements, temperatures, and pressures*
|
| 12 |
+
Reference implementation: https://github.com/microsoft/mattersim
|
| 13 |
+
|
| 14 |
+
# Model Description
|
| 15 |
+
|
| 16 |
+
MatterSim is based on a deep-learning architecture and is trained on multiple materials and molecular datasets. It performs energy and force prediction, structure relaxation, molecular dynamics, and custom-dataset fine-tuning for inorganic materials, molecules, and periodic systems.
|
| 17 |
+
|
| 18 |
+
# Applicable Scenarios
|
| 19 |
+
|
| 20 |
+
| Scenario | Description |
|
| 21 |
+
| :---: | :--- |
|
| 22 |
+
| Single-point energy/force prediction | Quickly predict energy and atomic forces for a given atomic structure |
|
| 23 |
+
| Batch structure inference | Perform batch energy/force prediction for multiple structures |
|
| 24 |
+
| Structure relaxation | Optimize atomic positions and unit-cell shape using FIRE/BFGS |
|
| 25 |
+
| Molecular dynamics | Run short-range MD sampling under the NVT ensemble |
|
| 26 |
+
| Custom data fine-tuning | Fine-tune a pre-trained MatterSim model on your own dataset |
|
| 27 |
+
| Environment connectivity check | Use the single-point/relaxation scripts to check the OneScience matchem environment, model loading, and CUDA/DCU availability |
|
| 28 |
+
|
| 29 |
+
# Usage Instructions
|
| 30 |
+
|
| 31 |
+
## 1. Using OneCode
|
| 32 |
+
|
| 33 |
+
You can try out intelligent one-click AI4S programming in the OneCode online environment:
|
| 34 |
+
|
| 35 |
+
[Try intelligent one-click AI4S programming](https://web-2069360198568017922-iaaj.ksai.scnet.cn:58043/home)
|
| 36 |
+
|
| 37 |
+
## 2. Manual Installation and Usage
|
| 38 |
+
|
| 39 |
+
**Hardware Requirements**
|
| 40 |
+
|
| 41 |
+
- GPU or DCU is recommended.
|
| 42 |
+
- CPU can be used for import and small-configuration connectivity checks; full training and inference will be slow.
|
| 43 |
+
- DCU users need to install DTK in advance. DTK 25.04.2 or above, or the OneScience-recommended version matching the current cluster, is suggested.
|
| 44 |
+
|
| 45 |
+
### Download the Model Package
|
| 46 |
+
|
| 47 |
+
```bash
|
| 48 |
+
modelscope download --model OneScience/Mattersim --local_dir ./mattersim
|
| 49 |
+
cd mattersim
|
| 50 |
+
```
|
| 51 |
+
|
| 52 |
+
### Install the Runtime Environment
|
| 53 |
+
|
| 54 |
+
**DCU Environment**
|
| 55 |
+
|
| 56 |
+
```bash
|
| 57 |
+
# Please activate DTK and CONDA first
|
| 58 |
+
conda create -n onescience311 python=3.11 -y
|
| 59 |
+
conda activate onescience311
|
| 60 |
+
# uv installation is also supported
|
| 61 |
+
pip install onescience[matchem-dcu] -i http://mirrors.onescience.ai:3141/pypi/simple/ --trusted-host mirrors.onescience.ai
|
| 62 |
+
```
|
| 63 |
+
|
| 64 |
+
**GPU Environment**
|
| 65 |
+
|
| 66 |
+
```bash
|
| 67 |
+
# Please activate CONDA first
|
| 68 |
+
conda create -n onescience311 python=3.11 -y libstdcxx-ng=12 libgcc-ng=12 gcc_linux-64=12 gxx_linux-64=12
|
| 69 |
+
conda activate onescience311
|
| 70 |
+
# uv installation is also supported
|
| 71 |
+
pip install onescience[matchem-gpu] -i http://mirrors.onescience.ai:3141/pypi/simple/ --trusted-host mirrors.onescience.ai
|
| 72 |
+
```
|
| 73 |
+
|
| 74 |
+
|
| 75 |
+
### Training Data Description
|
| 76 |
+
|
| 77 |
+
By default, this repository only includes the example data file `high_level_water.xyz`, used for quickly verifying model loading, single-point inference, structure relaxation, molecular dynamics, and fine-tuning workflows. For other training data, please download it yourself and place it in the `data/` directory.
|
| 78 |
+
|
| 79 |
+
### Training Weights
|
| 80 |
+
|
| 81 |
+
The repository includes `weight/mattersim-v1.0.0-1M.pth`. All scripts also support specifying model weights via `--checkpoint`.
|
| 82 |
+
|
| 83 |
+
### Inference
|
| 84 |
+
|
| 85 |
+
```bash
|
| 86 |
+
cd scripts
|
| 87 |
+
python single_point.py --checkpoint ../weight/mattersim-v1.0.0-1M.pth
|
| 88 |
+
```
|
| 89 |
+
|
| 90 |
+
```bash
|
| 91 |
+
cd scripts
|
| 92 |
+
python batch_inference.py --checkpoint ../weight/mattersim-v1.0.0-1M.pth
|
| 93 |
+
```
|
| 94 |
+
|
| 95 |
+
**Structure Relaxation**
|
| 96 |
+
|
| 97 |
+
```bash
|
| 98 |
+
cd scripts
|
| 99 |
+
python relax.py --checkpoint ../weight/mattersim-v1.0.0-1M.pth --device cuda
|
| 100 |
+
```
|
| 101 |
+
|
| 102 |
+
> The default weight is `../weight/mattersim-v1.0.0-1M.pth`.
|
| 103 |
+
|
| 104 |
+
**Molecular Dynamics**
|
| 105 |
+
|
| 106 |
+
```bash
|
| 107 |
+
cd scripts
|
| 108 |
+
python md.py --checkpoint ../weight/mattersim-v1.0.0-1M.pth --device cuda
|
| 109 |
+
```
|
| 110 |
+
|
| 111 |
+
> The default weight is also `../weight/mattersim-v1.0.0-1M.pth`.
|
| 112 |
+
|
| 113 |
+
### Fine-tuning
|
| 114 |
+
|
| 115 |
+
Edit the paths and parameters in `scripts/finetune_config.yaml` directly (e.g., `train_data_path`, `checkpoint`, etc.):
|
| 116 |
+
|
| 117 |
+
```bash
|
| 118 |
+
cd scripts
|
| 119 |
+
# Edit fields such as train_data_path and checkpoint in finetune_config.yaml
|
| 120 |
+
```
|
| 121 |
+
|
| 122 |
+
Single-GPU:
|
| 123 |
+
|
| 124 |
+
```bash
|
| 125 |
+
python finetune.py --config finetune_config.yaml
|
| 126 |
+
```
|
| 127 |
+
|
| 128 |
+
Multi-GPU DDP:
|
| 129 |
+
|
| 130 |
+
```bash
|
| 131 |
+
torchrun --nproc_per_node=4 finetune.py --config finetune_config.yaml
|
| 132 |
+
```
|
| 133 |
+
|
| 134 |
+
# OneScience Official Information
|
| 135 |
+
|
| 136 |
+
| Platform | OneScience Main Repository | Skills Repository |
|
| 137 |
+
| --- | --- | --- |
|
| 138 |
+
| Gitee | https://gitee.com/onescience-ai/onescience | https://gitee.com/onescience-ai/oneskills |
|
| 139 |
+
| GitHub | https://github.com/onescience-ai/OneScience | https://github.com/onescience-ai/oneskills |
|
| 140 |
+
|
| 141 |
+
---
|
| 142 |
+
|
| 143 |
+
# Citation and License
|
| 144 |
+
|
| 145 |
+
- The MatterSim-related code comes from the matchem example implementation in the OneScience project and references the upstream MatterSim project (https://github.com/microsoft/mattersim). The upstream MatterSim code is released under the [MIT License](https://github.com/microsoft/mattersim/blob/main/LICENSE).
|
| 146 |
+
- If you use MatterSim training or inference results in scientific research, we recommend citing the original MatterSim paper, the relevant OneScience project information, and the sources of the datasets actually used.
|
configuration.json
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
{"framework":"Pytorch","task":"other"}
|
data/high_level_water.xyz
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
model/__init__.py
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""MatterSim model and integration entry points."""
|
| 2 |
+
|
| 3 |
+
MATTERSIM_SOURCE_VERSION = "1.2.3"
|
| 4 |
+
MATTERSIM_INTEGRATION_VERSION = "dcu2"
|
| 5 |
+
|
| 6 |
+
from .adapter import (
|
| 7 |
+
DEFAULT_CHECKPOINT,
|
| 8 |
+
load_calculator,
|
| 9 |
+
load_potential,
|
| 10 |
+
predict_structures,
|
| 11 |
+
resolve_checkpoint,
|
| 12 |
+
)
|
| 13 |
+
__all__ = [
|
| 14 |
+
"DEFAULT_CHECKPOINT",
|
| 15 |
+
"M3Gnet",
|
| 16 |
+
"MATTERSIM_INTEGRATION_VERSION",
|
| 17 |
+
"MATTERSIM_SOURCE_VERSION",
|
| 18 |
+
"MatterSim",
|
| 19 |
+
"load_calculator",
|
| 20 |
+
"load_potential",
|
| 21 |
+
"predict_structures",
|
| 22 |
+
"resolve_checkpoint",
|
| 23 |
+
]
|
| 24 |
+
|
| 25 |
+
|
| 26 |
+
def __getattr__(name):
|
| 27 |
+
if name in {"M3Gnet", "MatterSim"}:
|
| 28 |
+
from .mattersim import M3Gnet, MatterSim
|
| 29 |
+
|
| 30 |
+
return {"M3Gnet": M3Gnet, "MatterSim": MatterSim}[name]
|
| 31 |
+
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
|
model/adapter.py
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Checkpoint and model factories for the OneScience MatterSim integration."""
|
| 2 |
+
|
| 3 |
+
import os
|
| 4 |
+
from pathlib import Path
|
| 5 |
+
|
| 6 |
+
import torch
|
| 7 |
+
|
| 8 |
+
DEFAULT_CHECKPOINT = "mattersim-v1.0.0-1M.pth"
|
| 9 |
+
|
| 10 |
+
|
| 11 |
+
def resolve_checkpoint(checkpoint: str | os.PathLike | None = None) -> str:
|
| 12 |
+
"""Resolve a MatterSim checkpoint without changing its native format.
|
| 13 |
+
|
| 14 |
+
Explicit checkpoint values are passed through so MatterSim model aliases keep
|
| 15 |
+
working. When no value is supplied, the shared OneScience model store is
|
| 16 |
+
checked before falling back to MatterSim's native alias and download logic.
|
| 17 |
+
"""
|
| 18 |
+
if checkpoint is not None:
|
| 19 |
+
return str(Path(checkpoint).expanduser())
|
| 20 |
+
|
| 21 |
+
models_dir = os.environ.get("ONESCIENCE_MODELS_DIR")
|
| 22 |
+
if models_dir:
|
| 23 |
+
shared_checkpoint = Path(models_dir).expanduser() / "mattersim" / DEFAULT_CHECKPOINT
|
| 24 |
+
if shared_checkpoint.is_file():
|
| 25 |
+
return str(shared_checkpoint)
|
| 26 |
+
|
| 27 |
+
return DEFAULT_CHECKPOINT
|
| 28 |
+
|
| 29 |
+
|
| 30 |
+
def _device(device: str | None) -> str:
|
| 31 |
+
return device or ("cuda" if torch.cuda.is_available() else "cpu")
|
| 32 |
+
|
| 33 |
+
|
| 34 |
+
def load_potential(
|
| 35 |
+
checkpoint: str | os.PathLike | None = None,
|
| 36 |
+
device: str | None = None,
|
| 37 |
+
load_training_state: bool = False,
|
| 38 |
+
**kwargs,
|
| 39 |
+
):
|
| 40 |
+
"""Load a MatterSim ``Potential`` from a resolved checkpoint."""
|
| 41 |
+
from onescience.utils.mattersim.potential import Potential
|
| 42 |
+
|
| 43 |
+
return Potential.from_checkpoint(
|
| 44 |
+
load_path=resolve_checkpoint(checkpoint),
|
| 45 |
+
device=_device(device),
|
| 46 |
+
load_training_state=load_training_state,
|
| 47 |
+
**kwargs,
|
| 48 |
+
)
|
| 49 |
+
|
| 50 |
+
|
| 51 |
+
def load_calculator(
|
| 52 |
+
checkpoint: str | os.PathLike | None = None,
|
| 53 |
+
device: str | None = None,
|
| 54 |
+
**kwargs,
|
| 55 |
+
):
|
| 56 |
+
"""Create an ASE-compatible ``MatterSimCalculator``."""
|
| 57 |
+
from onescience.utils.mattersim.calculator import MatterSimCalculator
|
| 58 |
+
|
| 59 |
+
return MatterSimCalculator.from_checkpoint(
|
| 60 |
+
resolve_checkpoint(checkpoint), device=_device(device), **kwargs
|
| 61 |
+
)
|
| 62 |
+
|
| 63 |
+
|
| 64 |
+
def predict_structures(
|
| 65 |
+
atoms,
|
| 66 |
+
checkpoint: str | os.PathLike | None = None,
|
| 67 |
+
device: str | None = None,
|
| 68 |
+
batch_size: int = 16,
|
| 69 |
+
include_forces: bool = True,
|
| 70 |
+
include_stresses: bool = False,
|
| 71 |
+
cutoff: float = 5.0,
|
| 72 |
+
threebody_cutoff: float = 4.0,
|
| 73 |
+
):
|
| 74 |
+
"""Predict ASE structures with the MatterSim potential."""
|
| 75 |
+
from onescience.datapipes.materials.mattersim import build_dataloader
|
| 76 |
+
|
| 77 |
+
potential = load_potential(checkpoint=checkpoint, device=device)
|
| 78 |
+
dataloader = build_dataloader(
|
| 79 |
+
atoms=list(atoms),
|
| 80 |
+
batch_size=batch_size,
|
| 81 |
+
cutoff=cutoff,
|
| 82 |
+
threebody_cutoff=threebody_cutoff,
|
| 83 |
+
only_inference=True,
|
| 84 |
+
)
|
| 85 |
+
energies, forces, stresses = potential.predict_properties(
|
| 86 |
+
dataloader,
|
| 87 |
+
include_forces=include_forces,
|
| 88 |
+
include_stresses=include_stresses,
|
| 89 |
+
)
|
| 90 |
+
return {
|
| 91 |
+
"energies": energies,
|
| 92 |
+
"forces": forces,
|
| 93 |
+
"stresses": stresses,
|
| 94 |
+
}
|
model/mattersim.py
ADDED
|
@@ -0,0 +1,201 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# -*- coding: utf-8 -*-
|
| 2 |
+
from typing import Dict
|
| 3 |
+
|
| 4 |
+
import torch
|
| 5 |
+
import torch.nn as nn
|
| 6 |
+
import torch.nn.functional as F
|
| 7 |
+
from torch_runstats.scatter import scatter
|
| 8 |
+
|
| 9 |
+
from onescience.modules.block.mattersim_block import MainBlock
|
| 10 |
+
from onescience.modules.embedding.mattersim_embedding import (
|
| 11 |
+
SmoothBesselBasis,
|
| 12 |
+
SphericalBasisLayer,
|
| 13 |
+
)
|
| 14 |
+
from onescience.modules.func_utils.mattersim_jit import compile_mode
|
| 15 |
+
from onescience.modules.func_utils.mattersim_scaling import AtomScaling
|
| 16 |
+
from onescience.modules.layer.mattersim_layer import GatedMLP, MLP
|
| 17 |
+
|
| 18 |
+
|
| 19 |
+
@compile_mode("script")
|
| 20 |
+
class M3Gnet(nn.Module):
|
| 21 |
+
"""
|
| 22 |
+
M3Gnet
|
| 23 |
+
"""
|
| 24 |
+
|
| 25 |
+
def __init__(
|
| 26 |
+
self,
|
| 27 |
+
num_blocks: int = 4,
|
| 28 |
+
units: int = 128,
|
| 29 |
+
max_l: int = 4,
|
| 30 |
+
max_n: int = 4,
|
| 31 |
+
cutoff: float = 5.0,
|
| 32 |
+
device: str = "cuda" if torch.cuda.is_available() else "cpu",
|
| 33 |
+
max_z: int = 94,
|
| 34 |
+
threebody_cutoff: float = 4.0,
|
| 35 |
+
**kwargs,
|
| 36 |
+
):
|
| 37 |
+
super().__init__()
|
| 38 |
+
self.rbf = SmoothBesselBasis(r_max=cutoff, max_n=max_n)
|
| 39 |
+
self.sbf = SphericalBasisLayer(max_n=max_n, max_l=max_l, cutoff=cutoff)
|
| 40 |
+
self.edge_encoder = MLP(
|
| 41 |
+
in_dim=max_n, out_dims=[units], activation="swish", use_bias=False
|
| 42 |
+
)
|
| 43 |
+
module_list = [
|
| 44 |
+
MainBlock(max_n, max_l, cutoff, units, max_n, threebody_cutoff)
|
| 45 |
+
for i in range(num_blocks)
|
| 46 |
+
]
|
| 47 |
+
self.graph_conv = nn.ModuleList(module_list)
|
| 48 |
+
self.final = GatedMLP(
|
| 49 |
+
in_dim=units,
|
| 50 |
+
out_dims=[units, units, 1],
|
| 51 |
+
activation=["swish", "swish", None],
|
| 52 |
+
)
|
| 53 |
+
self.apply(self.init_weights)
|
| 54 |
+
self.atom_embedding = MLP(
|
| 55 |
+
in_dim=max_z + 1, out_dims=[units], activation=None, use_bias=False
|
| 56 |
+
)
|
| 57 |
+
self.atom_embedding.apply(self.init_weights_uniform)
|
| 58 |
+
self.normalizer = AtomScaling(verbose=False, max_z=max_z, device=device)
|
| 59 |
+
self.max_z = max_z
|
| 60 |
+
self.device = device
|
| 61 |
+
self.model_args = {
|
| 62 |
+
"num_blocks": num_blocks,
|
| 63 |
+
"units": units,
|
| 64 |
+
"max_l": max_l,
|
| 65 |
+
"max_n": max_n,
|
| 66 |
+
"cutoff": cutoff,
|
| 67 |
+
"max_z": max_z,
|
| 68 |
+
"threebody_cutoff": threebody_cutoff,
|
| 69 |
+
}
|
| 70 |
+
|
| 71 |
+
def forward(
|
| 72 |
+
self,
|
| 73 |
+
input: Dict[str, torch.Tensor],
|
| 74 |
+
dataset_idx: int = -1,
|
| 75 |
+
) -> torch.Tensor:
|
| 76 |
+
# Exact data from input_dictionary
|
| 77 |
+
pos = input["atom_pos"]
|
| 78 |
+
cell = input["cell"]
|
| 79 |
+
pbc_offsets = input["pbc_offsets"].float()
|
| 80 |
+
atom_attr = input["atom_attr"]
|
| 81 |
+
edge_index = input["edge_index"].long()
|
| 82 |
+
three_body_indices = input["three_body_indices"].long()
|
| 83 |
+
num_bonds = input["num_bonds"]
|
| 84 |
+
num_triple_ij = input["num_triple_ij"]
|
| 85 |
+
num_atoms = input["num_atoms"]
|
| 86 |
+
num_graphs = input["num_graphs"]
|
| 87 |
+
batch = input["batch"]
|
| 88 |
+
|
| 89 |
+
# Use precomputed values if available, otherwise compute on the fly
|
| 90 |
+
# (backward-compat for callers not using batch_to_dict)
|
| 91 |
+
total_num_atoms = input.get("total_num_atoms", int(num_atoms.sum()))
|
| 92 |
+
total_num_bonds = input.get("total_num_bonds", int(num_bonds.sum()))
|
| 93 |
+
|
| 94 |
+
bond_index_bias = input.get("bond_index_bias", None)
|
| 95 |
+
if bond_index_bias is None:
|
| 96 |
+
cumsum = torch.cumsum(num_bonds, dim=0) - num_bonds
|
| 97 |
+
bond_index_bias = torch.repeat_interleave(
|
| 98 |
+
cumsum, input["num_three_body"], dim=0
|
| 99 |
+
).unsqueeze(-1)
|
| 100 |
+
|
| 101 |
+
three_body_edge_map = input.get("three_body_edge_map", None)
|
| 102 |
+
|
| 103 |
+
# -------------------------------------------------------------#
|
| 104 |
+
three_body_indices = three_body_indices + bond_index_bias
|
| 105 |
+
|
| 106 |
+
# === Refer to the implementation of M3GNet, ===
|
| 107 |
+
# === we should re-compute the following attributes ===
|
| 108 |
+
# edge_length, edge_vector(optional), triple_edge_length, theta_jik
|
| 109 |
+
edge_batch = batch[edge_index[0]]
|
| 110 |
+
edge_vector = pos[edge_index[0]] - (
|
| 111 |
+
pos[edge_index[1]]
|
| 112 |
+
+ torch.einsum("bi, bij->bj", pbc_offsets, cell[edge_batch])
|
| 113 |
+
)
|
| 114 |
+
edge_length = torch.linalg.norm(edge_vector, dim=1)
|
| 115 |
+
vij = edge_vector[three_body_indices[:, 0].clone()]
|
| 116 |
+
vik = edge_vector[three_body_indices[:, 1].clone()]
|
| 117 |
+
rij = edge_length[three_body_indices[:, 0].clone()]
|
| 118 |
+
rik = edge_length[three_body_indices[:, 1].clone()]
|
| 119 |
+
cos_jik = torch.sum(vij * vik, dim=1) / (rij * rik)
|
| 120 |
+
# eps = 1e-7 avoid nan in torch.acos function
|
| 121 |
+
cos_jik = torch.clamp(cos_jik, min=-1.0 + 1e-7, max=1.0 - 1e-7)
|
| 122 |
+
triple_edge_length = rik.view(-1)
|
| 123 |
+
edge_length = edge_length.unsqueeze(-1)
|
| 124 |
+
atomic_numbers = atom_attr.squeeze(1).long()
|
| 125 |
+
|
| 126 |
+
# featurize
|
| 127 |
+
atom_attr = self.atom_embedding(self.one_hot_atoms(atomic_numbers))
|
| 128 |
+
edge_attr = self.rbf(edge_length.view(-1))
|
| 129 |
+
edge_attr_zero = edge_attr # e_ij^0
|
| 130 |
+
edge_attr = self.edge_encoder(edge_attr)
|
| 131 |
+
three_basis = self.sbf(triple_edge_length, torch.acos(cos_jik))
|
| 132 |
+
|
| 133 |
+
# Main Loop
|
| 134 |
+
for idx, conv in enumerate(self.graph_conv):
|
| 135 |
+
atom_attr, edge_attr = conv(
|
| 136 |
+
atom_attr,
|
| 137 |
+
edge_attr,
|
| 138 |
+
edge_attr_zero,
|
| 139 |
+
edge_index,
|
| 140 |
+
three_basis,
|
| 141 |
+
three_body_indices,
|
| 142 |
+
edge_length,
|
| 143 |
+
num_bonds,
|
| 144 |
+
num_triple_ij,
|
| 145 |
+
num_atoms,
|
| 146 |
+
total_num_atoms=total_num_atoms,
|
| 147 |
+
total_num_bonds=total_num_bonds,
|
| 148 |
+
three_body_edge_map=three_body_edge_map,
|
| 149 |
+
)
|
| 150 |
+
|
| 151 |
+
energies_i = self.final(atom_attr).view(-1) # [batch_size*num_atoms]
|
| 152 |
+
energies_i = self.normalizer(energies_i, atomic_numbers)
|
| 153 |
+
energies = scatter(energies_i, batch, dim=0, dim_size=num_graphs)
|
| 154 |
+
|
| 155 |
+
return energies # [batch_size]
|
| 156 |
+
|
| 157 |
+
def init_weights(self, m):
|
| 158 |
+
if isinstance(m, nn.Linear):
|
| 159 |
+
torch.nn.init.xavier_uniform_(m.weight)
|
| 160 |
+
|
| 161 |
+
def init_weights_uniform(self, m):
|
| 162 |
+
if isinstance(m, nn.Linear):
|
| 163 |
+
torch.nn.init.uniform_(m.weight, a=-0.05, b=0.05)
|
| 164 |
+
|
| 165 |
+
@torch.jit.export
|
| 166 |
+
def one_hot_atoms(self, species):
|
| 167 |
+
# one_hots = []
|
| 168 |
+
# for i in range(species.shape[0]):
|
| 169 |
+
# one_hots.append(
|
| 170 |
+
# F.one_hot(
|
| 171 |
+
# species[i],
|
| 172 |
+
# num_classes=self.max_z+1).float().to(species.device)
|
| 173 |
+
# )
|
| 174 |
+
# return torch.cat(one_hots, dim=0)
|
| 175 |
+
return F.one_hot(species, num_classes=self.max_z + 1).float()
|
| 176 |
+
|
| 177 |
+
def print(self):
|
| 178 |
+
from prettytable import PrettyTable
|
| 179 |
+
|
| 180 |
+
table = PrettyTable(["Modules", "Parameters"])
|
| 181 |
+
total_params = 0
|
| 182 |
+
for name, parameter in self.named_parameters():
|
| 183 |
+
if not parameter.requires_grad:
|
| 184 |
+
continue
|
| 185 |
+
params = parameter.numel()
|
| 186 |
+
table.add_row([name, params])
|
| 187 |
+
total_params += params
|
| 188 |
+
print(table)
|
| 189 |
+
print(f"Total Trainable Params: {total_params}")
|
| 190 |
+
|
| 191 |
+
@torch.jit.export
|
| 192 |
+
def set_normalizer(self, normalizer: AtomScaling):
|
| 193 |
+
self.normalizer = normalizer
|
| 194 |
+
|
| 195 |
+
def get_model_args(self):
|
| 196 |
+
return self.model_args
|
| 197 |
+
|
| 198 |
+
|
| 199 |
+
MatterSim = M3Gnet
|
| 200 |
+
|
| 201 |
+
__all__ = ["M3Gnet", "MatterSim"]
|
scripts/batch_inference.py
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import argparse
|
| 2 |
+
|
| 3 |
+
from ase.build import bulk
|
| 4 |
+
|
| 5 |
+
from onescience.models.mattersim import predict_structures
|
| 6 |
+
|
| 7 |
+
|
| 8 |
+
def main() -> None:
|
| 9 |
+
parser = argparse.ArgumentParser(description="MatterSim batch inference")
|
| 10 |
+
parser.add_argument("--checkpoint")
|
| 11 |
+
parser.add_argument("--device", choices=("cpu", "cuda"), default="cuda")
|
| 12 |
+
parser.add_argument("--batch-size", type=int, default=16)
|
| 13 |
+
args = parser.parse_args()
|
| 14 |
+
|
| 15 |
+
structures = [bulk("Si", "diamond", a=a) for a in (5.40, 5.43, 5.46)]
|
| 16 |
+
result = predict_structures(
|
| 17 |
+
structures,
|
| 18 |
+
checkpoint=args.checkpoint,
|
| 19 |
+
device=args.device,
|
| 20 |
+
batch_size=args.batch_size,
|
| 21 |
+
)
|
| 22 |
+
for index, (energy, forces) in enumerate(
|
| 23 |
+
zip(result["energies"], result["forces"], strict=True)
|
| 24 |
+
):
|
| 25 |
+
print(
|
| 26 |
+
f"Structure {index}: energy={energy:.6f} eV, "
|
| 27 |
+
f"max_force={abs(forces).max():.6e} eV/angstrom"
|
| 28 |
+
)
|
| 29 |
+
|
| 30 |
+
|
| 31 |
+
if __name__ == "__main__":
|
| 32 |
+
main()
|
scripts/finetune.py
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import argparse
|
| 2 |
+
from pathlib import Path
|
| 3 |
+
|
| 4 |
+
import yaml
|
| 5 |
+
|
| 6 |
+
from onescience.utils.mattersim import FineTuneConfig, MatterSimTrainer
|
| 7 |
+
|
| 8 |
+
|
| 9 |
+
def _load_yaml_config(path: str) -> dict:
|
| 10 |
+
with open(path, "r", encoding="utf-8") as stream:
|
| 11 |
+
return yaml.safe_load(stream) or {}
|
| 12 |
+
|
| 13 |
+
|
| 14 |
+
def _build_parser(base_config: dict) -> argparse.ArgumentParser:
|
| 15 |
+
parser = argparse.ArgumentParser(description="Fine-tune MatterSim with OneScience")
|
| 16 |
+
parser.add_argument("--config", help="Path to YAML config file")
|
| 17 |
+
parser.add_argument(
|
| 18 |
+
"--train-data-path", default=base_config.get("train_data_path")
|
| 19 |
+
)
|
| 20 |
+
parser.add_argument(
|
| 21 |
+
"--valid-data-path", default=base_config.get("valid_data_path")
|
| 22 |
+
)
|
| 23 |
+
parser.add_argument("--checkpoint", default=base_config.get("checkpoint"))
|
| 24 |
+
parser.add_argument("--save-path", default=base_config.get("save_path", "./results/mattersim"))
|
| 25 |
+
parser.add_argument("--run-name", default=base_config.get("run_name", "onescience-mattersim"))
|
| 26 |
+
parser.add_argument("--epochs", type=int, default=base_config.get("epochs", 1000))
|
| 27 |
+
parser.add_argument("--batch-size", type=int, default=base_config.get("batch_size", 16))
|
| 28 |
+
parser.add_argument("--lr", type=float, default=base_config.get("lr", 2e-4))
|
| 29 |
+
parser.add_argument(
|
| 30 |
+
"--device", choices=("cpu", "cuda"), default=base_config.get("device", "cuda")
|
| 31 |
+
)
|
| 32 |
+
parser.add_argument("--seed", type=int, default=base_config.get("seed", 42))
|
| 33 |
+
parser.add_argument(
|
| 34 |
+
"--include-stresses",
|
| 35 |
+
action="store_true",
|
| 36 |
+
default=base_config.get("include_stresses", False),
|
| 37 |
+
)
|
| 38 |
+
parser.add_argument(
|
| 39 |
+
"--no-include-forces",
|
| 40 |
+
action="store_false",
|
| 41 |
+
dest="include_forces",
|
| 42 |
+
default=base_config.get("include_forces", True),
|
| 43 |
+
)
|
| 44 |
+
parser.add_argument(
|
| 45 |
+
"--re-normalize",
|
| 46 |
+
action="store_true",
|
| 47 |
+
default=base_config.get("re_normalize", False),
|
| 48 |
+
)
|
| 49 |
+
parser.add_argument(
|
| 50 |
+
"--no-save-checkpoint",
|
| 51 |
+
action="store_false",
|
| 52 |
+
dest="save_checkpoint",
|
| 53 |
+
default=base_config.get("save_checkpoint", True),
|
| 54 |
+
)
|
| 55 |
+
return parser
|
| 56 |
+
|
| 57 |
+
|
| 58 |
+
def main() -> None:
|
| 59 |
+
# Two-phase parsing: first get --config, then use YAML defaults for the rest.
|
| 60 |
+
pre_parser = argparse.ArgumentParser(add_help=False)
|
| 61 |
+
pre_parser.add_argument("--config")
|
| 62 |
+
pre_args, remaining = pre_parser.parse_known_args()
|
| 63 |
+
|
| 64 |
+
base_config = _load_yaml_config(pre_args.config) if pre_args.config else {}
|
| 65 |
+
parser = _build_parser(base_config)
|
| 66 |
+
args = parser.parse_args(remaining)
|
| 67 |
+
|
| 68 |
+
# Drop None values and the config key itself.
|
| 69 |
+
kwargs = {k: v for k, v in vars(args).items() if v is not None and k != "config"}
|
| 70 |
+
MatterSimTrainer(FineTuneConfig(**kwargs)).fit()
|
| 71 |
+
|
| 72 |
+
|
| 73 |
+
if __name__ == "__main__":
|
| 74 |
+
main()
|
scripts/finetune_config.yaml
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# MatterSim 微调基础配置
|
| 2 |
+
# 请复制此文件后,修改下方带 "TODO:" 标记的路径为你本地实际路径。
|
| 3 |
+
|
| 4 |
+
# 数据路径(TODO: 修改为你的训练数据路径)
|
| 5 |
+
# 示例使用仓库自带的 data/high_level_water.xyz
|
| 6 |
+
train_data_path: ../data/high_level_water.xyz
|
| 7 |
+
|
| 8 |
+
# 验证数据路径,不需要可保持 null(TODO: 按需修改)
|
| 9 |
+
valid_data_path: null
|
| 10 |
+
|
| 11 |
+
# checkpoint 路径(TODO: 修改为你的预训练模型路径)
|
| 12 |
+
# 示例使用仓库自带的 weight/mattersim-v1.0.0-1M.pth
|
| 13 |
+
checkpoint: ../weight/mattersim-v1.0.0-1M.pth
|
| 14 |
+
|
| 15 |
+
# 输出设置
|
| 16 |
+
save_path: ./results/mattersim
|
| 17 |
+
run_name: onescience-mattersim
|
| 18 |
+
|
| 19 |
+
# 训练超参数
|
| 20 |
+
epochs: 1
|
| 21 |
+
batch_size: 16
|
| 22 |
+
lr: 2.0e-4
|
| 23 |
+
seed: 42
|
| 24 |
+
|
| 25 |
+
# 设备:cuda 或 cpu,留空则自动检测
|
| 26 |
+
device: cuda
|
| 27 |
+
|
| 28 |
+
# 训练目标
|
| 29 |
+
cutoff: 5.0
|
| 30 |
+
threebody_cutoff: 4.0
|
| 31 |
+
include_forces: true
|
| 32 |
+
include_stresses: false
|
| 33 |
+
|
| 34 |
+
# 损失权重
|
| 35 |
+
force_loss_ratio: 1.0
|
| 36 |
+
stress_loss_ratio: 0.1
|
| 37 |
+
|
| 38 |
+
# 保存与早停
|
| 39 |
+
save_checkpoint: true
|
| 40 |
+
ckpt_interval: 10
|
| 41 |
+
early_stop_patience: 10
|
| 42 |
+
|
| 43 |
+
# 重新归一化(可选)
|
| 44 |
+
re_normalize: false
|
scripts/md.py
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import argparse
|
| 2 |
+
|
| 3 |
+
from ase.build import bulk
|
| 4 |
+
|
| 5 |
+
from onescience.utils.mattersim import molecular_dynamics
|
| 6 |
+
|
| 7 |
+
|
| 8 |
+
parser = argparse.ArgumentParser(description="MatterSim molecular dynamics")
|
| 9 |
+
parser.add_argument(
|
| 10 |
+
"--checkpoint",
|
| 11 |
+
default="../weight/mattersim-v1.0.0-1M.pth",
|
| 12 |
+
help="Path to MatterSim checkpoint",
|
| 13 |
+
)
|
| 14 |
+
parser.add_argument("--device", choices=("cpu", "cuda"), default="cuda")
|
| 15 |
+
args = parser.parse_args()
|
| 16 |
+
|
| 17 |
+
atoms = bulk("Si", "diamond", a=5.43).repeat((2, 2, 2))
|
| 18 |
+
dynamics = molecular_dynamics(
|
| 19 |
+
atoms,
|
| 20 |
+
checkpoint=args.checkpoint,
|
| 21 |
+
ensemble="nvt_berendsen",
|
| 22 |
+
temperature=300,
|
| 23 |
+
timestep=1.0,
|
| 24 |
+
logfile="-",
|
| 25 |
+
device=args.device,
|
| 26 |
+
)
|
| 27 |
+
dynamics.run(10)
|
scripts/relax.py
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import argparse
|
| 2 |
+
|
| 3 |
+
from ase.build import bulk
|
| 4 |
+
|
| 5 |
+
from onescience.utils.mattersim import relax
|
| 6 |
+
|
| 7 |
+
|
| 8 |
+
parser = argparse.ArgumentParser(description="MatterSim structure relaxation")
|
| 9 |
+
parser.add_argument(
|
| 10 |
+
"--checkpoint",
|
| 11 |
+
default="../weight/mattersim-v1.0.0-1M.pth",
|
| 12 |
+
help="Path to MatterSim checkpoint",
|
| 13 |
+
)
|
| 14 |
+
parser.add_argument("--device", choices=("cpu", "cuda"), default="cuda")
|
| 15 |
+
args = parser.parse_args()
|
| 16 |
+
|
| 17 |
+
converged, atoms = relax(
|
| 18 |
+
bulk("Si", "diamond", a=5.43),
|
| 19 |
+
checkpoint=args.checkpoint,
|
| 20 |
+
filter="FrechetCellFilter",
|
| 21 |
+
fmax=0.01,
|
| 22 |
+
steps=20,
|
| 23 |
+
device=args.device,
|
| 24 |
+
)
|
| 25 |
+
print(f"Converged: {converged}")
|
| 26 |
+
print(f"Energy: {atoms.get_potential_energy():.6f} eV")
|
scripts/single_point.py
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import argparse
|
| 2 |
+
|
| 3 |
+
import torch
|
| 4 |
+
from ase.build import bulk
|
| 5 |
+
from ase.units import GPa
|
| 6 |
+
|
| 7 |
+
from onescience.models.mattersim import load_calculator
|
| 8 |
+
|
| 9 |
+
|
| 10 |
+
def main() -> None:
|
| 11 |
+
parser = argparse.ArgumentParser(description="MatterSim single-point inference")
|
| 12 |
+
parser.add_argument("--checkpoint")
|
| 13 |
+
parser.add_argument("--device", choices=("cpu", "cuda"), default="cuda")
|
| 14 |
+
args = parser.parse_args()
|
| 15 |
+
|
| 16 |
+
device = args.device or ("cuda" if torch.cuda.is_available() else "cpu")
|
| 17 |
+
atoms = bulk("Si", "diamond", a=5.43)
|
| 18 |
+
atoms.calc = load_calculator(checkpoint=args.checkpoint, device=device)
|
| 19 |
+
|
| 20 |
+
energy = atoms.get_potential_energy()
|
| 21 |
+
print(f"Energy (eV) = {energy}")
|
| 22 |
+
print(f"Energy per atom (eV/atom) = {energy / len(atoms)}")
|
| 23 |
+
print(f"Forces of first atom (eV/A) = {atoms.get_forces()[0]}")
|
| 24 |
+
stress = atoms.get_stress(voigt=False)
|
| 25 |
+
print(f"Stress[0][0] (eV/A^3) = {stress[0][0]}")
|
| 26 |
+
print(f"Stress[0][0] (GPa) = {stress[0][0] / GPa}")
|
| 27 |
+
|
| 28 |
+
|
| 29 |
+
if __name__ == "__main__":
|
| 30 |
+
main()
|
weight/mattersim-v1.0.0-1M.pth
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:28b0b0b0f13efefee06b47ea4c9105a26bd3e2c8396da193430da96b3b49a8be
|
| 3 |
+
size 17932943
|