This issue comes from a Codex global scan of deepmodeling/deepmd-kit at commit 73de44b1f94471b2e3bdb6b11f57b34d7bc791bb.
Problem
The JAX C++ API exposes has_default_fparam(), but it does not load or materialize the default frame parameter values before constructing C API tensors.
The JAX export wrapper preserves both the flag and the default values:
|
if hasattr(self.model, "has_default_fparam"): |
|
# No attrs before v3.1.2 |
|
self._has_default_fparam = self.model.has_default_fparam().numpy().item() |
|
else: |
|
self._has_default_fparam = False |
|
if hasattr(self.model, "get_default_fparam"): |
|
self.default_fparam = self.model.get_default_fparam().numpy().tolist() |
|
else: |
|
self.default_fparam = None |
|
def has_default_fparam(self) -> bool: |
|
"""Check whether the model has default frame parameters.""" |
|
return self._has_default_fparam |
|
|
|
def get_default_fparam(self) -> list[float] | None: |
|
"""Get the default frame parameters.""" |
|
return self.default_fparam |
DeepPotJAX reads only the boolean:
|
try { |
|
has_default_fparam_ = get_scalar<bool>(ctx, "has_default_fparam", |
|
func_vector, device, status); |
|
} catch (tf_function_not_found& e) { |
|
has_default_fparam_ = false; |
|
} |
The header stores no default fparam vector, only the flag:
|
bool has_default_fparam() const { |
|
assert(inited); |
|
return has_default_fparam_; |
|
bool do_message_passing; |
|
// has default fparam |
|
bool has_default_fparam_; |
During inference, the direct path copies the caller-provided fparam vector and always shapes it as {nframes, dfparam}:
|
std::vector<double> coord_double(coord.begin(), coord.end()); |
|
std::vector<double> box_double(box.begin(), box.end()); |
|
std::vector<double> fparam_double(fparam.begin(), fparam.end()); |
|
std::vector<double> aparam_double(aparam.begin(), aparam.end()); |
|
|
|
TFE_Op* op; |
|
if (atomic) { |
|
op = get_func_op(ctx, "call_with_atomic_virial", func_vector, device, |
|
status); |
|
} else { |
|
op = get_func_op(ctx, "call_without_atomic_virial", func_vector, device, |
|
status); |
|
} |
|
std::vector<TFE_TensorHandle*> input_list(5); |
|
std::vector<TF_Tensor*> data_tensor(5); |
|
// coord |
|
std::vector<int64_t> coord_shape = {nframes, nloc_real, 3}; |
|
input_list[0] = |
|
add_input(op, coord_double, coord_shape, data_tensor[0], status); |
|
// atype |
|
std::vector<int64_t> atype_shape = {nframes, nloc_real}; |
|
input_list[1] = add_input(op, atype, atype_shape, data_tensor[1], status); |
|
// box |
|
int box_size = box_double.size() > 0 ? 3 : 0; |
|
std::vector<int64_t> box_shape = {nframes, box_size, box_size}; |
|
input_list[2] = add_input(op, box_double, box_shape, data_tensor[2], status); |
|
// fparam |
|
std::vector<int64_t> fparam_shape = {nframes, dfparam}; |
|
input_list[3] = |
|
add_input(op, fparam_double, fparam_shape, data_tensor[3], status); |
The neighbor-list path has the same behavior:
|
std::vector<double> coord_double(coord.begin(), coord.end()); |
|
std::vector<double> fparam_double(fparam.begin(), fparam.end()); |
|
std::vector<double> aparam_double(aparam.begin(), aparam.end()); |
|
// fparam |
|
std::vector<int64_t> fparam_shape = {nframes, dfparam}; |
|
input_list[4] = |
|
add_input(op, fparam_double, fparam_shape, data_tensor[4], status); |
create_tensor() allocates bytes from data.size(), not from the requested TensorFlow shape:
|
template <typename T> |
|
inline TF_Tensor* create_tensor(const std::vector<T>& data, |
|
const std::vector<int64_t>& shape) { |
|
TF_Tensor* tensor = |
|
TF_AllocateTensor(get_data_tensor_type(data), shape.data(), shape.size(), |
|
data.size() * sizeof(T)); |
|
memcpy(TF_TensorData(tensor), data.data(), TF_TensorByteSize(tensor)); |
|
return tensor; |
Therefore, when the model has a default fparam and the caller omits fparam, the C++ API reports that a default exists but still tries to build a non-empty {nframes, dfparam} tensor from an empty vector.
Impact
JAX models with default frame parameters can fail or send an invalid empty-buffer tensor through the C++ API unless callers explicitly provide fparam, even though the API advertises default fparam support.
Suggested fix
Load get_default_fparam during JAX model initialization, store it in DeepPotJAX, and materialize/tile it when the caller passes an empty fparam and has_default_fparam_ is true. Also validate create_tensor() inputs so the byte count matches the requested shape before allocating the TensorFlow tensor.
This issue comes from a Codex global scan of
deepmodeling/deepmd-kitat commit73de44b1f94471b2e3bdb6b11f57b34d7bc791bb.Problem
The JAX C++ API exposes
has_default_fparam(), but it does not load or materialize the default frame parameter values before constructing C API tensors.The JAX export wrapper preserves both the flag and the default values:
deepmd-kit/deepmd/jax/jax2tf/tfmodel.py
Lines 72 to 80 in 73de44b
deepmd-kit/deepmd/jax/jax2tf/tfmodel.py
Lines 345 to 351 in 73de44b
DeepPotJAXreads only the boolean:deepmd-kit/source/api_cc/src/DeepPotJAX.cc
Lines 335 to 340 in 73de44b
The header stores no default fparam vector, only the flag:
deepmd-kit/source/api_cc/include/DeepPotJAX.h
Lines 101 to 103 in 73de44b
deepmd-kit/source/api_cc/include/DeepPotJAX.h
Lines 201 to 203 in 73de44b
During inference, the direct path copies the caller-provided
fparamvector and always shapes it as{nframes, dfparam}:deepmd-kit/source/api_cc/src/DeepPotJAX.cc
Lines 397 to 426 in 73de44b
The neighbor-list path has the same behavior:
deepmd-kit/source/api_cc/src/DeepPotJAX.cc
Lines 546 to 548 in 73de44b
deepmd-kit/source/api_cc/src/DeepPotJAX.cc
Lines 622 to 625 in 73de44b
create_tensor()allocates bytes fromdata.size(), not from the requested TensorFlow shape:deepmd-kit/source/api_cc/src/DeepPotJAX.cc
Lines 176 to 183 in 73de44b
Therefore, when the model has a default fparam and the caller omits
fparam, the C++ API reports that a default exists but still tries to build a non-empty{nframes, dfparam}tensor from an empty vector.Impact
JAX models with default frame parameters can fail or send an invalid empty-buffer tensor through the C++ API unless callers explicitly provide
fparam, even though the API advertises default fparam support.Suggested fix
Load
get_default_fparamduring JAX model initialization, store it inDeepPotJAX, and materialize/tile it when the caller passes an emptyfparamandhas_default_fparam_is true. Also validatecreate_tensor()inputs so the byte count matches the requested shape before allocating the TensorFlow tensor.