Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 28 additions & 4 deletions .github/workflows/package_c.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ jobs:
strategy:
matrix:
include:
- tensorflow_build_version: "2.20"
tensorflow_version: "==2.20.*"
- package_c_runtime_dependency_pre_exclude_regexes: 'libtorch.*\.so.*;libc10.*\.so.*;libshm\.so.*;libkineto\.so.*;libbackend_with_compiler\.so.*;libcaffe2.*\.so.*;libcuda.*\.so.*;libcudart.*\.so.*;libcublas.*\.so.*;libcufft.*\.so.*;libcufile.*\.so.*;libcupti.*\.so.*;libcurand.*\.so.*;libcusolver.*\.so.*;libcusparse.*\.so.*;libnv.*\.so.*;libcudnn.*\.so.*;libnccl.*\.so.*'
package_c_runtime_dependency_post_exclude_regexes: '.*/libtorch.*\.so.*;.*/libc10.*\.so.*;.*/libshm\.so.*;.*/libkineto\.so.*;.*/libbackend_with_compiler\.so.*;.*/libcaffe2.*\.so.*;.*/libcuda.*\.so.*;.*/libcudart.*\.so.*;.*/libcublas.*\.so.*;.*/libcufft.*\.so.*;.*/libcufile.*\.so.*;.*/libcupti.*\.so.*;.*/libcurand.*\.so.*;.*/libcusolver.*\.so.*;.*/libcusparse.*\.so.*;.*/libnv.*\.so.*;.*/libcudnn.*\.so.*;.*/libnccl.*\.so.*'
filename: libdeepmd_c.tar.gz
steps:
- name: Free Disk Space (Ubuntu)
Expand All @@ -41,8 +41,30 @@ jobs:
- name: Package C library
run: ./source/install/docker_package_c.sh
env:
TENSORFLOW_VERSION: ${{ matrix.tensorflow_version }}
TENSORFLOW_BUILD_VERSION: ${{ matrix.tensorflow_build_version }}
ENABLE_PYTORCH: "TRUE"
PACKAGE_C_RUNTIME_DEPENDENCY_PRE_EXCLUDE_REGEXES: ${{ matrix.package_c_runtime_dependency_pre_exclude_regexes }}
PACKAGE_C_RUNTIME_DEPENDENCY_POST_EXCLUDE_REGEXES: ${{ matrix.package_c_runtime_dependency_post_exclude_regexes }}
- name: Check C library package contents
run: |
tar -tzf libdeepmd_c.tar.gz | tee libdeepmd_c.contents
grep -q 'libdeepmd_c/lib/libdeepmd_backend_tf.so' libdeepmd_c.contents
grep -q 'libdeepmd_c/lib/libdeepmd_backend_pt.so' libdeepmd_c.contents
grep -q 'libdeepmd_c/lib/libdeepmd_backend_ptexpt.so' libdeepmd_c.contents
grep -q 'libdeepmd_c/lib/libdeepmd_op_pt.so' libdeepmd_c.contents
grep -q 'libdeepmd_c/download_libtorch.sh' libdeepmd_c.contents
if grep -E 'libdeepmd_c/lib/(libtorch|libc10|libshm|libkineto|libbackend_with_compiler|libcaffe2|libcuda|libcudart|libcublas|libcufft|libcufile|libcupti|libcurand|libcusolver|libcusparse|libnv|libcudnn|libnccl)' libdeepmd_c.contents; then
echo "PyTorch/CUDA runtime libraries must not be bundled in libdeepmd_c.tar.gz"
exit 1
fi
- name: Note external PyTorch runtime
run: |
libtorch_url=$(tar -xOf libdeepmd_c.tar.gz libdeepmd_c/download_libtorch.sh | sed -n 's/^LIBTORCH_DOWNLOAD_URL="\(.*\)"$/\1/p')
{
echo "PyTorch support was built into the C package, but PyTorch runtime libraries are not bundled."
echo "Download matching libtorch from: ${libtorch_url}"
echo "Or run ./download_libtorch.sh after extracting libdeepmd_c.tar.gz."
echo "The PyTorch version must match the build version exactly; the CUDA variant may be omitted only when compatible."
} >> "$GITHUB_STEP_SUMMARY"
- run: cp libdeepmd_c.tar.gz ${{ matrix.filename }}
if: matrix.filename != 'libdeepmd_c.tar.gz'
# for download and debug
Expand All @@ -53,6 +75,8 @@ jobs:
path: ${{ matrix.filename }}
- name: Test C library
run: ./source/install/docker_test_package_c.sh
env:
CHECK_PYTORCH_RUNTIME: "1"
- name: Release
uses: softprops/action-gh-release@v3
if: startsWith(github.ref, 'refs/tags/')
Expand Down
16 changes: 13 additions & 3 deletions doc/install/install-from-c-library.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Install from pre-compiled C library {{ tensorflow_icon }} {{ jax_icon }}
# Install from pre-compiled C library {{ tensorflow_icon }} {{ pytorch_icon }} {{ jax_icon }}

:::{note}
**Supported backends**: TensorFlow {{ tensorflow_icon }}, JAX {{ jax_icon }}
**Supported backends**: TensorFlow {{ tensorflow_icon }}, PyTorch {{ pytorch_icon }}, JAX {{ jax_icon }}
:::

DeePMD-kit provides pre-compiled C library package (`libdeepmd_c.tar.gz`) in each [release](https://github.com/deepmodeling/deepmd-kit/releases). It can be used to build the [LAMMPS plugin](./install-lammps.md) and the [i-PI driver](./install-ipi.md), as well as many [third-party software packages](../third-party/out-of-deepmd-kit.md), without building TensorFlow and DeePMD-kit on one's own.
Expand All @@ -12,7 +12,17 @@ wget https://github.com/deepmodeling/deepmd-kit/releases/latest/download/libdeep
tar xzf libdeepmd_c.tar.gz
```

The library is built in Linux (GLIBC 2.17) with CUDA 12.2 (`libdeepmd_c.tar.gz`). It's noted that this package does not contain CUDA Toolkit and cuDNN, so one needs to download them from the NVIDIA website.
The library is built in Linux (GLIBC 2.28) with CUDA 12.9 (`libdeepmd_c.tar.gz`). It's noted that this package does not contain CUDA Toolkit, cuDNN, or PyTorch runtime libraries.
To use the PyTorch C/C++ backend on Linux, install a libtorch runtime that exactly matches the PyTorch version used to build the package.
The PyTorch version must match exactly, while the CUDA variant may be omitted only when the target runtime is compatible.
Make the libtorch `lib` directory discoverable by the dynamic linker, for example by adding it to `LD_LIBRARY_PATH`.
The C library package includes `download_libtorch.sh`, which downloads and unpacks the matching libtorch runtime and writes `libtorch_env.sh`:

```sh
cd libdeepmd_c
./download_libtorch.sh
. ./libtorch_env.sh
```

## Use Pre-compiled C Library to build the LAMMPS plugin and i-PI driver

Expand Down
62 changes: 48 additions & 14 deletions source/api_c/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -31,44 +31,78 @@ endif(BUILD_PY_IF)

if(PACKAGE_C)
message(STATUS "Packaging C API library")
set(PACKAGE_C_RUNTIME_DEPENDENCY_PRE_EXCLUDE_REGEXES
""
CACHE STRING
"Additional file(GET_RUNTIME_DEPENDENCIES) pre-exclude regexes")
set(PACKAGE_C_RUNTIME_DEPENDENCY_POST_EXCLUDE_REGEXES
""
CACHE STRING
"Additional file(GET_RUNTIME_DEPENDENCIES) post-exclude regexes")
set(PACKAGE_C_RUNTIME_DEPENDENCY_PRE_EXCLUDE_REGEXES_DEFAULT
"libgcc_s\\.so.*"
"libstdc\\+\\+\\.so.*"
"libm\\.so.*"
"libdl\\.so.*"
"librt\\.so.*"
"libc\\.so.*"
"libpthread\\.so.*"
"ld-.*\\.so.*"
"libgomp\\.so.*")
set(PACKAGE_C_RUNTIME_DEPENDENCY_PRE_EXCLUDE_REGEXES_ALL
${PACKAGE_C_RUNTIME_DEPENDENCY_PRE_EXCLUDE_REGEXES_DEFAULT}
${PACKAGE_C_RUNTIME_DEPENDENCY_PRE_EXCLUDE_REGEXES})
get_property(DEEPMD_BACKEND_PLUGIN_TARGETS GLOBAL
PROPERTY DEEPMD_BACKEND_PLUGIN_TARGETS)
set(PACKAGE_C_RUNTIME_LIBRARIES "$<TARGET_FILE:${libname}>"
"$<TARGET_FILE:${LIB_DEEPMD_OP}>")
set(PACKAGE_C_RUNTIME_LIBRARIES "$<TARGET_FILE:${libname}>")
if(TARGET ${LIB_DEEPMD_OP})
list(APPEND PACKAGE_C_RUNTIME_LIBRARIES "$<TARGET_FILE:${LIB_DEEPMD_OP}>")
endif()
foreach(_target deepmd_op_pt deepmd_op_pd)
if(TARGET ${_target})
list(APPEND PACKAGE_C_RUNTIME_LIBRARIES "$<TARGET_FILE:${_target}>")
endif()
endforeach()
foreach(_target ${DEEPMD_BACKEND_PLUGIN_TARGETS})
list(APPEND PACKAGE_C_RUNTIME_LIBRARIES "$<TARGET_FILE:${_target}>")
endforeach()
string(REPLACE ";" " " PACKAGE_C_RUNTIME_LIBRARIES_CODE
"${PACKAGE_C_RUNTIME_LIBRARIES}")
# follow pypa/auditwheel convention
install(CODE "set(_dp_runtime_libraries ${PACKAGE_C_RUNTIME_LIBRARIES_CODE})")
install(
CODE "set(_dp_package_c_lib_dir [==[${CMAKE_BINARY_DIR}/libdeepmd_c/lib]==])
set(_dp_runtime_pre_exclude_regexes [==[${PACKAGE_C_RUNTIME_DEPENDENCY_PRE_EXCLUDE_REGEXES_ALL}]==])
set(_dp_runtime_post_exclude_regexes [==[${PACKAGE_C_RUNTIME_DEPENDENCY_POST_EXCLUDE_REGEXES}]==])"
)
install(
CODE [[
file(GET_RUNTIME_DEPENDENCIES
LIBRARIES ${_dp_runtime_libraries}
RESOLVED_DEPENDENCIES_VAR _r_deps
PRE_EXCLUDE_REGEXES "libgcc_s\\.so.*"
"libstdc\\+\\+\\.so.*"
"libm\\.so.*"
"libdl\\.so.*"
"librt\\.so.*"
"libc\\.so.*"
"libpthread\\.so.*"
"ld-.*\\.so.*"
"libgomp\\.so.*"
PRE_EXCLUDE_REGEXES ${_dp_runtime_pre_exclude_regexes}
POST_EXCLUDE_REGEXES ${_dp_runtime_post_exclude_regexes}
)
message(STATUS "Runtime dependencies: ${_r_deps}")
foreach(_file ${_r_deps})
file(INSTALL ${_file} DESTINATION libdeepmd_c/lib
file(INSTALL ${_file} DESTINATION "${_dp_package_c_lib_dir}"
FOLLOW_SYMLINK_CHAIN
)
endforeach()
]])
install(FILES ${INC_SRC}
DESTINATION ${CMAKE_BINARY_DIR}/libdeepmd_c/include/deepmd)
install(TARGETS ${libname} DESTINATION ${CMAKE_BINARY_DIR}/libdeepmd_c/lib)
install(TARGETS ${LIB_DEEPMD_OP}
DESTINATION ${CMAKE_BINARY_DIR}/libdeepmd_c/lib)
if(TARGET ${LIB_DEEPMD_OP})
install(TARGETS ${LIB_DEEPMD_OP}
DESTINATION ${CMAKE_BINARY_DIR}/libdeepmd_c/lib)
endif()
foreach(_target deepmd_op_pt deepmd_op_pd)
if(TARGET ${_target})
install(TARGETS ${_target}
DESTINATION ${CMAKE_BINARY_DIR}/libdeepmd_c/lib)
endif()
endforeach()
foreach(_target ${DEEPMD_BACKEND_PLUGIN_TARGETS})
install(TARGETS ${_target} DESTINATION ${CMAKE_BINARY_DIR}/libdeepmd_c/lib)
endforeach()
Expand Down
45 changes: 36 additions & 9 deletions source/install/docker_package_c.sh
Original file line number Diff line number Diff line change
@@ -1,12 +1,39 @@
set -e

SCRIPT_PATH=$(dirname $(realpath -s $0))
SCRIPT_PATH=$(dirname "$(realpath -s "$0")")
MANYLINUX_CUDA_IMAGE=${MANYLINUX_CUDA_IMAGE:-quay.io/manylinux_cuda/manylinux_2_28_x86_64_cuda12_9:latest}
PYTHON_BIN=${PYTHON_BIN:-/opt/python/cp311-cp311/bin/python}
PYTORCH_DEPENDENCY_GROUP=${PYTORCH_DEPENDENCY_GROUP:-pin_pytorch_cpu}
PYTORCH_TORCH_BACKEND=${PYTORCH_TORCH_BACKEND:-cpu}
TENSORFLOW_DEPENDENCY_GROUP=${TENSORFLOW_DEPENDENCY_GROUP:-pin_tensorflow_cpu}

docker run --rm -v ${SCRIPT_PATH}/../..:/root/deepmd-kit -w /root/deepmd-kit \
tensorflow/build:${TENSORFLOW_BUILD_VERSION:-2.15}-python3.11 \
/bin/sh -c "pip install \"tensorflow${TENSORFLOW_VERSION}\" cmake \
&& git config --global --add safe.directory /root/deepmd-kit \
&& cd /root/deepmd-kit/source/install \
&& CC=/dt9/usr/bin/gcc \
CXX=/dt9/usr/bin/g++ \
/bin/sh package_c.sh"
docker run --rm -v "${SCRIPT_PATH}/../..":/root/deepmd-kit -w /root/deepmd-kit \
-e CIBUILDWHEEL="${CIBUILDWHEEL:-1}" \
-e ENABLE_PYTORCH="${ENABLE_PYTORCH:-FALSE}" \
-e MANYLINUX_CUDA_IMAGE="${MANYLINUX_CUDA_IMAGE}" \
-e PACKAGE_C_RUNTIME_DEPENDENCY_PRE_EXCLUDE_REGEXES="${PACKAGE_C_RUNTIME_DEPENDENCY_PRE_EXCLUDE_REGEXES:-}" \
-e PACKAGE_C_RUNTIME_DEPENDENCY_POST_EXCLUDE_REGEXES="${PACKAGE_C_RUNTIME_DEPENDENCY_POST_EXCLUDE_REGEXES:-}" \
-e PYTORCH_DEPENDENCY_GROUP="${PYTORCH_DEPENDENCY_GROUP}" \
-e PYTHON_BIN="${PYTHON_BIN}" \
-e PYTORCH_RUNTIME_DOWNLOAD_URL="${PYTORCH_RUNTIME_DOWNLOAD_URL:-}" \
-e PYTORCH_TORCH_BACKEND="${PYTORCH_TORCH_BACKEND}" \
-e TENSORFLOW_DEPENDENCY_GROUP="${TENSORFLOW_DEPENDENCY_GROUP}" \
"${MANYLINUX_CUDA_IMAGE}" \
/bin/bash -lc 'set -euo pipefail
export PATH="$(dirname "${PYTHON_BIN}"):${PATH}"
"${PYTHON_BIN}" -m pip install uv
UV_INSTALL_ARGS=(
pip install
--python "${PYTHON_BIN}"
cmake
ninja
patchelf
--group "${TENSORFLOW_DEPENDENCY_GROUP}"
)
if [ "${ENABLE_PYTORCH}" = "TRUE" ]; then
UV_INSTALL_ARGS+=(--group "${PYTORCH_DEPENDENCY_GROUP}" --torch-backend "${PYTORCH_TORCH_BACKEND}")
fi
source/install/uv_with_retry.sh "${UV_INSTALL_ARGS[@]}"
git config --global --add safe.directory /root/deepmd-kit
cd /root/deepmd-kit/source/install
/bin/sh package_c.sh'
99 changes: 89 additions & 10 deletions source/install/docker_test_package_c.sh
Original file line number Diff line number Diff line change
@@ -1,15 +1,94 @@
# test libdeepmd_c.tar.gz works with gcc 4.9.0, glibc 2.19
# test libdeepmd_c.tar.gz works on a manylinux 2.28 runtime
set -e

SCRIPT_PATH=$(dirname $(realpath -s $0))
SCRIPT_PATH=$(dirname "$(realpath -s "$0")")
MANYLINUX_IMAGE=${MANYLINUX_IMAGE:-quay.io/pypa/manylinux_2_28_x86_64:latest}
PYTHON_BIN=${PYTHON_BIN:-/opt/python/cp311-cp311/bin/python}
PYTORCH_DEPENDENCY_GROUP=${PYTORCH_DEPENDENCY_GROUP:-pin_pytorch_cpu}
PYTORCH_TORCH_BACKEND=${PYTORCH_TORCH_BACKEND:-cpu}

# assume libdeepmd_c.tar.gz has been created

docker run --rm -v ${SCRIPT_PATH}/../..:/root/deepmd-kit -w /root/deepmd-kit \
gcc:4.9 \
/bin/sh -c "tar vxzf libdeepmd_c.tar.gz \
&& cd examples/infer_water \
&& gcc convert_model.c -std=c99 -L ../../libdeepmd_c/lib -I ../../libdeepmd_c/include -Wl,--no-as-needed -ldeepmd_c -Wl,-rpath=../../libdeepmd_c/lib -o convert_model \
&& gcc infer_water.c -std=c99 -L ../../libdeepmd_c/lib -I ../../libdeepmd_c/include -Wl,--no-as-needed -ldeepmd_c -Wl,-rpath=../../libdeepmd_c/lib -o infer_water \
&& ./convert_model \
&& ./infer_water"
docker run --rm -v "${SCRIPT_PATH}/../..":/root/deepmd-kit -w /root/deepmd-kit \
-e CHECK_PYTORCH_RUNTIME="${CHECK_PYTORCH_RUNTIME:-0}" \
-e PYTHON_BIN="${PYTHON_BIN}" \
-e PYTORCH_DEPENDENCY_GROUP="${PYTORCH_DEPENDENCY_GROUP}" \
-e PYTORCH_TORCH_BACKEND="${PYTORCH_TORCH_BACKEND}" \
"${MANYLINUX_IMAGE}" \
/bin/bash -lc 'set -euo pipefail
export PATH="$(dirname "${PYTHON_BIN}"):${PATH}"
tar vxzf libdeepmd_c.tar.gz
if [ -f libdeepmd_c/download_libtorch.sh ]; then
sh -n libdeepmd_c/download_libtorch.sh
fi
cd examples/infer_water
gcc convert_model.c -std=c99 -L ../../libdeepmd_c/lib -I ../../libdeepmd_c/include -Wl,--no-as-needed -ldeepmd_c -Wl,-rpath=../../libdeepmd_c/lib -o convert_model
gcc infer_water.c -std=c99 -L ../../libdeepmd_c/lib -I ../../libdeepmd_c/include -Wl,--no-as-needed -ldeepmd_c -Wl,-rpath=../../libdeepmd_c/lib -o infer_water
./convert_model
./infer_water
cd /root/deepmd-kit
if [ "${CHECK_PYTORCH_RUNTIME}" = "1" ]; then
"${PYTHON_BIN}" -m pip install uv
source/install/uv_with_retry.sh pip install --python "${PYTHON_BIN}" --group "${PYTORCH_DEPENDENCY_GROUP}" --torch-backend "${PYTORCH_TORCH_BACKEND}"
TORCH_RUNTIME_LIB_DIRS=$("${PYTHON_BIN}" - <<'"'"'PY'"'"'
import pathlib
import site
import sys

import torch

dirs = [pathlib.Path(torch.__file__).resolve().parent / "lib"]
roots = []
try:
roots.extend(site.getsitepackages())
except AttributeError:
pass
try:
roots.append(site.getusersitepackages())
except AttributeError:
pass
roots.extend(sys.path)
for root in roots:
if not root:
continue
nvidia_dir = pathlib.Path(root) / "nvidia"
if nvidia_dir.is_dir():
dirs.extend(sorted(path for path in nvidia_dir.glob("*/lib") if path.is_dir()))
seen = set()
unique_dirs = []
for path in dirs:
path = path.resolve()
if path in seen:
continue
seen.add(path)
unique_dirs.append(str(path))
print(":".join(unique_dirs))
PY
)
RUNTIME_LIBRARY_PATH="${PWD}/libdeepmd_c/lib:${TORCH_RUNTIME_LIB_DIRS}"
if [ -n "${LD_LIBRARY_PATH:-}" ]; then
RUNTIME_LIBRARY_PATH="${RUNTIME_LIBRARY_PATH}:${LD_LIBRARY_PATH}"
fi
LD_LIBRARY_PATH="${RUNTIME_LIBRARY_PATH}" ldd libdeepmd_c/lib/libdeepmd_backend_pt.so > /tmp/deepmd_pt_ldd.txt
LD_LIBRARY_PATH="${RUNTIME_LIBRARY_PATH}" ldd libdeepmd_c/lib/libdeepmd_backend_ptexpt.so >> /tmp/deepmd_pt_ldd.txt
LD_LIBRARY_PATH="${RUNTIME_LIBRARY_PATH}" ldd libdeepmd_c/lib/libdeepmd_op_pt.so >> /tmp/deepmd_pt_ldd.txt
cat /tmp/deepmd_pt_ldd.txt
if grep -q "not found" /tmp/deepmd_pt_ldd.txt; then
exit 1
fi
LD_LIBRARY_PATH="${RUNTIME_LIBRARY_PATH}" "${PYTHON_BIN}" - <<'"'"'PY'"'"'
import ctypes
import os
import pathlib

import torch # noqa: F401

libdir = pathlib.Path("libdeepmd_c/lib").resolve()
for name in [
"libdeepmd_op_pt.so",
"libdeepmd_backend_pt.so",
"libdeepmd_backend_ptexpt.so",
]:
ctypes.CDLL(str(libdir / name), mode=os.RTLD_NOW | os.RTLD_LOCAL)
PY
fi'
Loading
Loading