Skip to content
Draft
Show file tree
Hide file tree
Changes from 3 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
35 changes: 23 additions & 12 deletions source/op/pt/tabulate_multi_device.cc
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,17 @@ void GetTensorDevice(const torch::Tensor& t, std::string& str) {
}
}

static void ValidateGpuLastLayerSize(const int64_t last_layer_size) {
// The GPU tabulation kernels use this dimension either as the block size or
// to size dynamic shared memory, so reject invalid models before any launch:
// an out-of-range value overflows the block dimension (or divides by zero)
// inside the launch configuration.
TORCH_CHECK(last_layer_size > 0 && last_layer_size <= 1024,
"last_layer_size must be between 1 and 1024 for GPU tabulation, "
"but got ",
last_layer_size);
}

template <typename FPTYPE>
void TabulateFusionSeAForward(const torch::Tensor& table_tensor,
const torch::Tensor& table_info_tensor,
Expand Down Expand Up @@ -58,6 +69,7 @@ void TabulateFusionSeAForward(const torch::Tensor& table_tensor,
const int64_t nnei = em_tensor.size(1);
// compute
if (device == "GPU") {
ValidateGpuLastLayerSize(last_layer_size);
#if GOOGLE_CUDA || TENSORFLOW_USE_ROCM
deepmd::tabulate_fusion_se_a_gpu(descriptor, table, table_info, em_x, em,
two_embed, nloc, nnei, last_layer_size);
Expand Down Expand Up @@ -110,6 +122,7 @@ void TabulateFusionSeAGradForward(const torch::Tensor& table_tensor,
const int64_t last_layer_size = descriptor_tensor.size(2);
// compute
if (device == "GPU") {
ValidateGpuLastLayerSize(last_layer_size);
#if GOOGLE_CUDA || TENSORFLOW_USE_ROCM
deepmd::tabulate_fusion_se_a_grad_gpu(dy_dem_x, dy_dem, dy_dtwo, table,
table_info, em_x, em, two_embed, dy,
Expand Down Expand Up @@ -170,6 +183,7 @@ void TabulateFusionSeAGradGradForward(const torch::Tensor& table_tensor,
const int64_t last_layer_size = descriptor_tensor.size(2);
// compute
if (device == "GPU") {
ValidateGpuLastLayerSize(last_layer_size);
#if GOOGLE_CUDA || TENSORFLOW_USE_ROCM
deepmd::tabulate_fusion_se_a_grad_grad_gpu(
dz_dy, table, table_info, em_x, em, two_embed, dz_dy_dem_x, dz_dy_dem,
Expand All @@ -179,9 +193,6 @@ void TabulateFusionSeAGradGradForward(const torch::Tensor& table_tensor,
"The input tensor is on the GPU, but the GPU support for the "
"customized OP library is not enabled.");
#endif // GOOGLE_CUDA || TENSORFLOW_USE_ROCM
TORCH_CHECK(last_layer_size <= 1024,
"In the process of model compression, the size of the "
"last layer of embedding net must be less than 1024!");
} else if (device == "CPU") {
deepmd::tabulate_fusion_se_a_grad_grad_cpu(
dz_dy, table, table_info, em_x, em, two_embed, dz_dy_dem_x, dz_dy_dem,
Expand Down Expand Up @@ -221,6 +232,7 @@ void TabulateFusionSeTForward(const torch::Tensor& table_tensor,
const int64_t nnei_j = em_tensor.size(2);
// compute
if (device == "GPU") {
ValidateGpuLastLayerSize(last_layer_size);
#if GOOGLE_CUDA || TENSORFLOW_USE_ROCM
deepmd::tabulate_fusion_se_t_gpu(descriptor, table, table_info, em_x, em,
nloc, nnei_i, nnei_j, last_layer_size);
Expand Down Expand Up @@ -266,6 +278,7 @@ void TabulateFusionSeTGradForward(const torch::Tensor& table_tensor,
const int64_t last_layer_size = descriptor_tensor.size(1);
// compute
if (device == "GPU") {
ValidateGpuLastLayerSize(last_layer_size);
#if GOOGLE_CUDA || TENSORFLOW_USE_ROCM
deepmd::tabulate_fusion_se_t_grad_gpu(dy_dem_x, dy_dem, table, table_info,
em_x, em, dy, nloc, nnei_i, nnei_j,
Expand Down Expand Up @@ -316,6 +329,7 @@ void TabulateFusionSeTGradGradForward(const torch::Tensor& table_tensor,
const int64_t last_layer_size = descriptor_tensor.size(1);
// compute
if (device == "GPU") {
ValidateGpuLastLayerSize(last_layer_size);
#if GOOGLE_CUDA || TENSORFLOW_USE_ROCM
deepmd::tabulate_fusion_se_t_grad_grad_gpu(dz_dy, table, table_info, em_x,
em, dz_dy_dem_x, dz_dy_dem, nloc,
Expand All @@ -325,9 +339,6 @@ void TabulateFusionSeTGradGradForward(const torch::Tensor& table_tensor,
"The input tensor is on the GPU, but the GPU support for the "
"customized OP library is not enabled.");
#endif // GOOGLE_CUDA || TENSORFLOW_USE_ROCM
TORCH_CHECK(last_layer_size <= 1024,
"In the process of model compression, the size of the "
"last layer of embedding net must be less than 1024!");
} else if (device == "CPU") {
deepmd::tabulate_fusion_se_t_grad_grad_cpu(dz_dy, table, table_info, em_x,
em, dz_dy_dem_x, dz_dy_dem, nloc,
Expand Down Expand Up @@ -368,6 +379,7 @@ void TabulateFusionSeTTebdForward(const torch::Tensor& table_tensor,
const int64_t nnei_j = em_tensor.size(2);
// compute
if (device == "GPU") {
ValidateGpuLastLayerSize(last_layer_size);
Comment thread
njzjz marked this conversation as resolved.
Outdated
#if GOOGLE_CUDA || TENSORFLOW_USE_ROCM
deepmd::tabulate_fusion_se_t_tebd_gpu(descriptor, table, table_info, em_x,
em, nloc, nnei_i, nnei_j,
Expand Down Expand Up @@ -414,6 +426,7 @@ void TabulateFusionSeTTebdGradForward(const torch::Tensor& table_tensor,

// compute
if (device == "GPU") {
ValidateGpuLastLayerSize(last_layer_size);
#if GOOGLE_CUDA || TENSORFLOW_USE_ROCM
deepmd::tabulate_fusion_se_t_tebd_grad_gpu(dy_dem_x, table, table_info,
em_x, em, dy, nloc, nnei_i,
Expand Down Expand Up @@ -460,6 +473,7 @@ void TabulateFusionSeTTebdGradGradForward(
const int64_t last_layer_size = descriptor_tensor.size(3);
// compute
if (device == "GPU") {
ValidateGpuLastLayerSize(last_layer_size);
#if GOOGLE_CUDA || TENSORFLOW_USE_ROCM
deepmd::tabulate_fusion_se_t_tebd_grad_grad_gpu(
dz_dy, table, table_info, em_x, em, dz_dy_dem_x, nloc, nnei_i, nnei_j,
Expand All @@ -469,9 +483,6 @@ void TabulateFusionSeTTebdGradGradForward(
"The input tensor is on the GPU, but the GPU support for the "
"customized OP library is not enabled.");
#endif // GOOGLE_CUDA || TENSORFLOW_USE_ROCM
TORCH_CHECK(last_layer_size <= 1024,
"In the process of model compression, the size of the "
"last layer of embedding net must be less than 1024!");
} else if (device == "CPU") {
deepmd::tabulate_fusion_se_t_tebd_grad_grad_cpu(
dz_dy, table, table_info, em_x, em, dz_dy_dem_x, nloc, nnei_i, nnei_j,
Expand Down Expand Up @@ -505,6 +516,7 @@ void TabulateFusionSeRForward(const torch::Tensor& table_tensor,
const int64_t nnei = em_tensor.size(1);
// compute
if (device == "GPU") {
ValidateGpuLastLayerSize(last_layer_size);
#if GOOGLE_CUDA || TENSORFLOW_USE_ROCM
deepmd::tabulate_fusion_se_r_gpu(descriptor, table, table_info, em, nloc,
nnei, last_layer_size);
Expand Down Expand Up @@ -545,6 +557,7 @@ void TabulateFusionSeRGradForward(const torch::Tensor& table_tensor,
const int64_t last_layer_size = descriptor_tensor.size(2);
// compute
if (device == "GPU") {
ValidateGpuLastLayerSize(last_layer_size);
#if GOOGLE_CUDA || TENSORFLOW_USE_ROCM
deepmd::tabulate_fusion_se_r_grad_gpu(dy_dem, table, table_info, em, dy,
nloc, nnei, last_layer_size);
Expand Down Expand Up @@ -585,6 +598,7 @@ void TabulateFusionSeRGradGradForward(const torch::Tensor& table_tensor,
const int64_t last_layer_size = descriptor_tensor.size(2);
// compute
if (device == "GPU") {
ValidateGpuLastLayerSize(last_layer_size);
#if GOOGLE_CUDA || TENSORFLOW_USE_ROCM
deepmd::tabulate_fusion_se_r_grad_grad_gpu(
dz_dy, table, table_info, em, dz_dy_dem, nloc, nnei, last_layer_size);
Expand All @@ -593,9 +607,6 @@ void TabulateFusionSeRGradGradForward(const torch::Tensor& table_tensor,
"The input tensor is on the GPU, but the GPU support for the "
"customized OP library is not enabled.");
#endif // GOOGLE_CUDA || TENSORFLOW_USE_ROCM
TORCH_CHECK(last_layer_size <= 1024,
"In the process of model compression, the size of the "
"last layer of embedding net must be less than 1024!");
} else if (device == "CPU") {
deepmd::tabulate_fusion_se_r_grad_grad_cpu(
dz_dy, table, table_info, em, dz_dy_dem, nloc, nnei, last_layer_size);
Expand Down
39 changes: 23 additions & 16 deletions source/op/tf/tabulate_multi_device.cc
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,17 @@ REGISTER_OP("TabulateFusionSeRGradGrad")
.Input("descriptor: T")
.Output("dz_dy: T");

static deepmd::tf_compat::Status validate_gpu_last_layer_size(
Comment thread
njzjz-bot marked this conversation as resolved.
const int last_layer_size) {
// GPU tabulation kernels use this dimension either as the block size or to
// size dynamic shared memory, so reject invalid models before any launch.
if (last_layer_size <= 0 || last_layer_size > 1024) {
return deepmd::tf_compat::InvalidArgument(
"last_layer_size must be between 1 and 1024 for GPU tabulation");
}
return deepmd::tf_compat::Status();
}

template <typename Device, typename FPTYPE>
class TabulateFusionSeAOp : public OpKernel {
public:
Expand Down Expand Up @@ -210,6 +221,7 @@ class TabulateFusionSeAOp : public OpKernel {
const int nnei = em_tensor.shape().dim_size(1);

if (device == "GPU") {
OP_REQUIRES_OK(context, validate_gpu_last_layer_size(last_layer_size));
#if GOOGLE_CUDA || TENSORFLOW_USE_ROCM
deepmd::tabulate_fusion_se_a_gpu(descriptor, table, table_info, em_x, em,
two_embed, nloc, nnei, last_layer_size);
Expand Down Expand Up @@ -276,6 +288,7 @@ class TabulateFusionSeAGradOp : public OpKernel {
const int last_layer_size = descriptor_tensor.shape().dim_size(2);

if (device == "GPU") {
OP_REQUIRES_OK(context, validate_gpu_last_layer_size(last_layer_size));
#if GOOGLE_CUDA || TENSORFLOW_USE_ROCM
deepmd::tabulate_fusion_se_a_grad_gpu(dy_dem_x, dy_dem, dy_dtwo, table,
table_info, em_x, em, two_embed, dy,
Expand Down Expand Up @@ -336,15 +349,12 @@ class TabulateFusionSeAGradGradOp : public OpKernel {
const int last_layer_size = descriptor_tensor.shape().dim_size(2);

if (device == "GPU") {
OP_REQUIRES_OK(context, validate_gpu_last_layer_size(last_layer_size));
#if GOOGLE_CUDA || TENSORFLOW_USE_ROCM
deepmd::tabulate_fusion_se_a_grad_grad_gpu(
dz_dy, table, table_info, em_x, em, two_embed, dz_dy_dem_x, dz_dy_dem,
dz_dy_dtwo, nloc, nnei, last_layer_size, is_sorted);
#endif // GOOGLE_CUDA || TENSORFLOW_USE_ROCM
OP_REQUIRES(context, (last_layer_size <= 1024),
deepmd::tf_compat::InvalidArgument(
"In the process of model compression, the size of the "
"last layer of embedding net must be less than 1024!"));
} else if (device == "CPU") {
deepmd::tabulate_fusion_se_a_grad_grad_cpu(
dz_dy, table, table_info, em_x, em, two_embed, dz_dy_dem_x, dz_dy_dem,
Expand Down Expand Up @@ -409,6 +419,7 @@ class TabulateFusionSeAttenOp : public OpKernel {
const int nnei = em_tensor.shape().dim_size(1);

if (device == "GPU") {
OP_REQUIRES_OK(context, validate_gpu_last_layer_size(last_layer_size));
#if GOOGLE_CUDA || TENSORFLOW_USE_ROCM
deepmd::tabulate_fusion_se_a_gpu(descriptor, table, table_info, em_x, em,
two_embed, nloc, nnei, last_layer_size,
Expand Down Expand Up @@ -485,6 +496,7 @@ class TabulateFusionSeAttenGradOp : public OpKernel {
const int last_layer_size = descriptor_tensor.shape().dim_size(2);

if (device == "GPU") {
OP_REQUIRES_OK(context, validate_gpu_last_layer_size(last_layer_size));
#if GOOGLE_CUDA || TENSORFLOW_USE_ROCM
deepmd::tabulate_fusion_se_a_grad_gpu(
dy_dem_x, dy_dem, dy_dtwo, table, table_info, em_x, em, two_embed, dy,
Expand Down Expand Up @@ -553,15 +565,12 @@ class TabulateFusionSeAttenGradGradOp : public OpKernel {
const int last_layer_size = descriptor_tensor.shape().dim_size(2);

if (device == "GPU") {
OP_REQUIRES_OK(context, validate_gpu_last_layer_size(last_layer_size));
#if GOOGLE_CUDA || TENSORFLOW_USE_ROCM
deepmd::tabulate_fusion_se_a_grad_grad_gpu(
dz_dy, table, table_info, em_x, em, two_embed, dz_dy_dem_x, dz_dy_dem,
dz_dy_dtwo, nloc, nnei, last_layer_size, is_sorted);
#endif // GOOGLE_CUDA || TENSORFLOW_USE_ROCM
OP_REQUIRES(context, (last_layer_size <= 1024),
deepmd::tf_compat::InvalidArgument(
"In the process of model compression, the size of the "
"last layer of embedding net must be less than 1024!"));
} else if (device == "CPU") {
deepmd::tabulate_fusion_se_a_grad_grad_cpu(
dz_dy, table, table_info, em_x, em, two_embed, dz_dy_dem_x, dz_dy_dem,
Expand Down Expand Up @@ -623,6 +632,7 @@ class TabulateFusionSeTOp : public OpKernel {
const int nnei_j = em_tensor.shape().dim_size(2);

if (device == "GPU") {
OP_REQUIRES_OK(context, validate_gpu_last_layer_size(last_layer_size));
#if GOOGLE_CUDA || TENSORFLOW_USE_ROCM
deepmd::tabulate_fusion_se_t_gpu(descriptor, table, table_info, em_x, em,
nloc, nnei_i, nnei_j, last_layer_size);
Expand Down Expand Up @@ -687,6 +697,7 @@ class TabulateFusionSeTGradOp : public OpKernel {
const int last_layer_size = descriptor_tensor.shape().dim_size(1);

if (device == "GPU") {
OP_REQUIRES_OK(context, validate_gpu_last_layer_size(last_layer_size));
#if GOOGLE_CUDA || TENSORFLOW_USE_ROCM
deepmd::tabulate_fusion_se_t_grad_gpu(dy_dem_x, dy_dem, table, table_info,
em_x, em, dy, nloc, nnei_i, nnei_j,
Expand Down Expand Up @@ -744,15 +755,12 @@ class TabulateFusionSeTGradGradOp : public OpKernel {
const int last_layer_size = descriptor_tensor.shape().dim_size(1);

if (device == "GPU") {
OP_REQUIRES_OK(context, validate_gpu_last_layer_size(last_layer_size));
#if GOOGLE_CUDA || TENSORFLOW_USE_ROCM
deepmd::tabulate_fusion_se_t_grad_grad_gpu(
dz_dy, table, table_info, em_x, em, dz_dy_dem_x, dz_dy_dem, nloc,
nnei_i, nnei_j, last_layer_size);
#endif // GOOGLE_CUDA || TENSORFLOW_USE_ROCM
OP_REQUIRES(context, (last_layer_size <= 1024),
deepmd::tf_compat::InvalidArgument(
"In the process of model compression, the size of the "
"last layer of embedding net must be less than 1024!"));
} else if (device == "CPU") {
deepmd::tabulate_fusion_se_t_grad_grad_cpu(
dz_dy, table, table_info, em_x, em, dz_dy_dem_x, dz_dy_dem, nloc,
Expand Down Expand Up @@ -806,6 +814,7 @@ class TabulateFusionSeROp : public OpKernel {
const int nnei = em_tensor.shape().dim_size(1);

if (device == "GPU") {
OP_REQUIRES_OK(context, validate_gpu_last_layer_size(last_layer_size));
#if GOOGLE_CUDA || TENSORFLOW_USE_ROCM
deepmd::tabulate_fusion_se_r_gpu(descriptor, table, table_info, em, nloc,
nnei, last_layer_size);
Expand Down Expand Up @@ -861,6 +870,7 @@ class TabulateFusionSeRGradOp : public OpKernel {
const int last_layer_size = descriptor_tensor.shape().dim_size(2);

if (device == "GPU") {
OP_REQUIRES_OK(context, validate_gpu_last_layer_size(last_layer_size));
#if GOOGLE_CUDA || TENSORFLOW_USE_ROCM
deepmd::tabulate_fusion_se_r_grad_gpu(dy_dem, table, table_info, em, dy,
nloc, nnei, last_layer_size);
Expand Down Expand Up @@ -909,14 +919,11 @@ class TabulateFusionSeRGradGradOp : public OpKernel {
const int last_layer_size = descriptor_tensor.shape().dim_size(2);

if (device == "GPU") {
OP_REQUIRES_OK(context, validate_gpu_last_layer_size(last_layer_size));
#if GOOGLE_CUDA || TENSORFLOW_USE_ROCM
deepmd::tabulate_fusion_se_r_grad_grad_gpu(
dz_dy, table, table_info, em, dz_dy_dem, nloc, nnei, last_layer_size);
#endif // GOOGLE_CUDA || TENSORFLOW_USE_ROCM
OP_REQUIRES(context, (last_layer_size <= 1024),
deepmd::tf_compat::InvalidArgument(
"In the process of model compression, the size of the "
"last layer of embedding net must be less than 1024!"));
} else if (device == "CPU") {
deepmd::tabulate_fusion_se_r_grad_grad_cpu(
dz_dy, table, table_info, em, dz_dy_dem, nloc, nnei, last_layer_size);
Expand Down
89 changes: 89 additions & 0 deletions source/tests/pt/test_tabulate_gpu_size_validation.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
# SPDX-License-Identifier: LGPL-3.0-or-later
"""Reject invalid tabulation widths before any PyTorch GPU kernel launch."""

import unittest

import torch

from deepmd.pt.cxx_op import (
ENABLE_CUSTOMIZED_OP,
)

ERROR_MESSAGE = "last_layer_size must be between 1 and 1024"


@unittest.skipIf(not ENABLE_CUSTOMIZED_OP, "PyTorch customized OPs are not built")
@unittest.skipUnless(
torch.cuda.is_available(), "GPU tabulation validation requires a GPU"
)
class TestTabulateGpuSizeValidation(unittest.TestCase):
"""The GPU wrappers must fail on the host, not inside a launch config."""

dtype = torch.float64

def _zeros(self, *shape: int) -> torch.Tensor:
return torch.zeros(shape, dtype=self.dtype, device="cuda")

def _table(self, last_layer_size: int) -> torch.Tensor:
return self._zeros(1, max(1, 6 * last_layer_size))

def _table_info(self) -> torch.Tensor:
# table_info stays on the CPU for every backend.
return torch.tensor([0.0, 1.0, 1.0, 1.0, 1.0, 1.0], dtype=self.dtype)

def _forward_calls(self, last_layer_size: int) -> dict[str, callable]:
table = self._table(last_layer_size)
table_info = self._table_info()
em_x = self._zeros(1, 1)
em_a = self._zeros(1, 1, 4)
em_t = self._zeros(1, 1, 1)
em_r = self._zeros(1, 1)
two_embed = self._zeros(1, max(1, last_layer_size))
return {
"se_a": lambda: torch.ops.deepmd.tabulate_fusion_se_a(
table, table_info, em_x, em_a, last_layer_size
),
"se_atten": lambda: torch.ops.deepmd.tabulate_fusion_se_atten(
table, table_info, em_x, em_a, two_embed, last_layer_size, True
),
"se_t": lambda: torch.ops.deepmd.tabulate_fusion_se_t(
table, table_info, em_x, em_t, last_layer_size
),
"se_t_tebd": lambda: torch.ops.deepmd.tabulate_fusion_se_t_tebd(
table, table_info, em_x, em_t, last_layer_size
),
"se_r": lambda: torch.ops.deepmd.tabulate_fusion_se_r(
table, table_info, em_r, last_layer_size
),
}

def _assert_rejected(self, last_layer_size: int) -> None:
for name, call in self._forward_calls(last_layer_size).items():
with self.subTest(op=name, last_layer_size=last_layer_size):
with self.assertRaisesRegex(RuntimeError, ERROR_MESSAGE):
call()

def test_rejects_oversized_width(self) -> None:
"""A width past the maximum block dimension must be refused."""
self._assert_rejected(1025)

def test_rejects_zero_width(self) -> None:
"""A zero width would divide by zero while sizing the launch."""
self._assert_rejected(0)
Comment thread
coderabbitai[bot] marked this conversation as resolved.

def test_gradient_paths_reject_oversized_width(self) -> None:
"""The autograd wrappers derive the width from the descriptor."""
last_layer_size = 1025
table = self._table(last_layer_size)
table_info = self._table_info()
em_x = self._zeros(1, 1).requires_grad_(True)
em_a = self._zeros(1, 1, 4).requires_grad_(True)
with self.assertRaisesRegex(RuntimeError, ERROR_MESSAGE):
descriptor = torch.ops.deepmd.tabulate_fusion_se_a(
table, table_info, em_x, em_a, last_layer_size
)[0]
descriptor.sum().backward()
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Outdated


if __name__ == "__main__":
unittest.main()
Loading
Loading