-
Notifications
You must be signed in to change notification settings - Fork 515
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix(pt/dp): make strip more efficient #4400
Conversation
📝 Walkthrough📝 WalkthroughWalkthroughThis pull request introduces several modifications across multiple files, primarily focusing on the addition of a new optional parameter, Changes
Possibly related PRs
Suggested labels
Suggested reviewers
📜 Recent review detailsConfiguration used: CodeRabbit UI 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media? 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 9
🧹 Outside diff range and nitpick comments (18)
deepmd/dpmodel/descriptor/descriptor.py (1)
126-126
: Document the new parameter.Consider adding parameter documentation in the docstring of the
call
method to explain the purpose and expected shape oftype_embedding
.Add documentation like this:
def call( self, nlist: np.ndarray, extended_coord: np.ndarray, extended_atype: np.ndarray, extended_atype_embd: Optional[np.ndarray] = None, mapping: Optional[np.ndarray] = None, type_embedding: Optional[np.ndarray] = None, ): """Calculate DescriptorBlock. + + Parameters + ---------- + type_embedding : np.ndarray, optional + The embedding vectors for atom types, shape: [...]. """ passdeepmd/pt/model/descriptor/descriptor.py (1)
177-177
: Add parameter documentation.Please add documentation for the new
type_embedding
parameter in the method's docstring, including:
- Parameter type and description
- Whether it can be None
- Expected tensor shape and dtype
deepmd/pt/model/network/network.py (1)
299-301
: LGTM! Clean implementation for efficient type embedding access.The new method provides a clear and efficient way to access the full type embedding for a given device, which supports the optimization of strip mode in descriptor classes.
This abstraction helps improve performance by allowing direct access to the full embedding when needed, reducing unnecessary computations in the descriptor pipeline.
deepmd/pt/model/descriptor/repformers.py (3)
Line range hint
394-396
: Consider moving assertions to the top levelThe assertion for
extended_atype_embd
is nested within a condition, making it less visible. Consider moving essential preconditions to the start of the method for better clarity and error detection.def forward( self, nlist: torch.Tensor, extended_coord: torch.Tensor, extended_atype: torch.Tensor, extended_atype_embd: Optional[torch.Tensor] = None, mapping: Optional[torch.Tensor] = None, type_embedding: Optional[torch.Tensor] = None, comm_dict: Optional[dict[str, torch.Tensor]] = None, ): + if comm_dict is None: + assert mapping is not None, "mapping is required when comm_dict is None" + assert extended_atype_embd is not None, "extended_atype_embd is required when comm_dict is None" - if comm_dict is None: - assert mapping is not None - assert extended_atype_embd is not None
Line range hint
466-513
: Consider extracting spin-related logicThe spin-related logic is complex and intertwined with the main flow. Consider extracting it into a separate method for better maintainability and readability.
+ def _handle_spin_case( + self, + g1: torch.Tensor, + nloc: int, + nall: int + ) -> tuple[torch.Tensor, int, int]: + real_nloc = nloc // 2 + real_nall = nall // 2 + real_n_padding = real_nall - real_nloc + g1_real, g1_virtual = torch.split(g1, [real_nloc, real_nloc], dim=1) + # mix_g1: nb x real_nloc x (ng1 * 2) + mix_g1 = torch.cat([g1_real, g1_virtual], dim=2) + # nb x real_nall x (ng1 * 2) + g1 = torch.nn.functional.pad( + mix_g1.squeeze(0), (0, 0, 0, real_n_padding), value=0.0 + ) + return g1, real_nloc, real_nall
Line range hint
514-538
: Enhance error handling for border_opThe border operation could fail if the required keys are missing in
comm_dict
. Consider adding more descriptive error messages and validating the tensor shapes.- assert "send_list" in comm_dict - assert "send_proc" in comm_dict - assert "recv_proc" in comm_dict - assert "send_num" in comm_dict - assert "recv_num" in comm_dict - assert "communicator" in comm_dict + required_keys = ["send_list", "send_proc", "recv_proc", "send_num", "recv_num", "communicator"] + missing_keys = [key for key in required_keys if key not in comm_dict] + if missing_keys: + raise ValueError(f"Missing required keys in comm_dict: {missing_keys}") + + # Validate tensor shapes + if comm_dict["send_list"].dim() != 1: + raise ValueError("send_list must be a 1D tensor")deepmd/pt/model/descriptor/se_a.py (1)
728-728
: Document the type_embedding parameterThe new parameter lacks documentation in the docstring, making it unclear what it's for and how it should be used.
Add parameter documentation:
def forward( self, nlist: torch.Tensor, extended_coord: torch.Tensor, extended_atype: torch.Tensor, extended_atype_embd: Optional[torch.Tensor] = None, mapping: Optional[torch.Tensor] = None, type_embedding: Optional[torch.Tensor] = None, ): """Calculate decoded embedding for each atom. Args: - coord: Tell atom coordinates with shape [nframes, natoms[1]*3]. - atype: Tell atom types with shape [nframes, natoms[1]]. - natoms: Tell atom count and element count. Its shape is [2+self.ntypes]. - box: Tell simulation box with shape [nframes, 9]. + - type_embedding: Optional tensor for type embeddings. Shape: [...]. Returns ------- - `torch.Tensor`: descriptor matrix with shape [nframes, natoms[0]*self.filter_neuron[-1]*self.axis_neuron]. """
deepmd/pt/model/descriptor/dpa1.py (1)
690-693
: Fix inconsistent indentation.The indentation in this block appears to be using spaces instead of tabs, which is inconsistent with the rest of the file.
- if self.tebd_input_mode in ["strip"]: - type_embedding = self.type_embedding.get_full_embedding(g1_ext.device) - else: - type_embedding = None + if self.tebd_input_mode in ["strip"]: + type_embedding = self.type_embedding.get_full_embedding(g1_ext.device) + else: + type_embedding = Nonedeepmd/dpmodel/descriptor/se_t_tebd.py (4)
Line range hint
713-732
: Optimize redundant computations in"concat"
modeIn the
"concat"
mode, the code performs multiple tiling and reshaping operations that may affect performance. Consider optimizing these operations to improve efficiency.Refactor the code to minimize unnecessary tiling:
if self.tebd_input_mode in ["concat"]: index = xp.tile( xp.reshape(nlist_masked, (nf, -1, 1)), (1, 1, self.tebd_dim) ) # nfnl x nnei x tebd_dim atype_embd_nlist = xp_take_along_axis(atype_embd_ext, index, axis=1) atype_embd_nlist = xp.reshape( atype_embd_nlist, (nf * nloc, nnei, self.tebd_dim) ) # nfnl x nt_i x nt_j x tebd_dim - nlist_tebd_i = xp.tile( - atype_embd_nlist[:, :, None, :], (1, 1, self.nnei, 1) - ) - nlist_tebd_j = xp.tile( - atype_embd_nlist[:, None, :, :], (1, self.nnei, 1, 1) - ) + nlist_tebd_i = atype_embd_nlist[:, :, None, :] + nlist_tebd_j = atype_embd_nlist[:, None, :, :] # nfnl x nt_i x nt_j x (1 + tebd_dim * 2) ss = xp.concat([ss, nlist_tebd_i, nlist_tebd_j], axis=-1) # nfnl x nt_i x nt_j x ng gg = self.cal_g(ss, 0)This change removes unnecessary tiling since broadcasting can handle dimension expansion.
753-775
: Optimize the indexing ofgg_t
to improve performanceThe indexing operation using
xp_take_along_axis
may be inefficient for large arrays. Consider alternative approaches to optimize performance.Explore vectorized operations or batch processing to reduce computational overhead. For example, precompute indices or leverage advanced indexing techniques.
777-777
: Clarify the combination logic ofgg_s
andgg_t
The combination
gg = gg_s * gg_t + gg_s
may not be immediately clear. Consider adding comments or refactoring for readability.Add explanatory comments:
# Combine the structural and type embeddings gg = gg_s * gg_t + gg_s # Element-wise multiplication followed by additionAlternatively, if the mathematical intention is to weight
gg_s
withgg_t
, consider expressing it more explicitly.
Line range hint
671-777
: Consider refactoring thecall
method for maintainabilityThe
call
method has become lengthy and complex with the addition of new logic. Refactor the method to improve readability and maintainability.Split the
call
method into smaller helper methods:
- One method for processing the
"concat"
mode.- Another method for processing the
"strip"
mode.- A method for common preprocessing steps.
This modular approach enhances code clarity.
deepmd/pt/model/descriptor/se_t_tebd.py (3)
178-178
: Validatetebd_input_mode
in constructorCurrently,
self.tebd_input_mode
is set directly without validation. To prevent potential errors, consider adding a validation step to ensuretebd_input_mode
is one of the supported modes ("concat", "strip"). This will help catch invalid inputs early.Apply this diff to add validation:
def __init__( self, rcut: float, rcut_smth: float, sel: Union[list[int], int], ntypes: int, neuron: list = [2, 4, 8], tebd_dim: int = 8, tebd_input_mode: str = "concat", resnet_dt: bool = False, set_davg_zero: bool = True, activation_function: str = "tanh", env_protection: float = 0.0, exclude_types: list[tuple[int, int]] = [], precision: str = "float64", trainable: bool = True, seed: Optional[Union[int, list[int]]] = None, type_map: Optional[list[str]] = None, concat_output_tebd: bool = True, use_econf_tebd: bool = False, use_tebd_bias=False, smooth: bool = True, ) -> None: + if tebd_input_mode not in ["concat", "strip"]: + raise ValueError(f"Invalid tebd_input_mode '{tebd_input_mode}'. Supported modes are 'concat' and 'strip'.") super().__init__() self.tebd_input_mode = tebd_input_mode
741-741
: Updateforward
method signature documentationThe
forward
method now includestype_embedding
as an optional parameter. Please update the method's docstring to include a description of this parameter, its expected shape, and when it should be provided.Apply this diff to update the docstring:
def forward( self, nlist: torch.Tensor, extended_coord: torch.Tensor, extended_atype: torch.Tensor, extended_atype_embd: Optional[torch.Tensor] = None, mapping: Optional[torch.Tensor] = None, type_embedding: Optional[torch.Tensor] = None, ): """Compute the descriptor. Parameters ---------- nlist The neighbor list. shape: nf x nloc x nnei extended_coord The extended coordinates of atoms. shape: nf x (nall x 3) extended_atype The extended atom types. shape: nf x nall extended_atype_embd The extended type embeddings of atoms. shape: nf x nall x nt mapping The index mapping, not required by this descriptor. + type_embedding : Optional[torch.Tensor] + Full type embeddings. Shape: (ntypes + 1) x nt. + Required when `tebd_input_mode` is "strip". Returns ------- result The descriptor. shape: nf x nloc x (ng x axis_neuron)
Line range hint
823-865
: Optimize tensor operations and ensure compatibilityIn the
forward
method, within thetebd_input_mode
handling, there are several tensor operations involving reshaping and broadcasting. Consider reviewing these operations for optimal performance and compatibility:
Use of Compatible Functions: The
torch.tile
function is available in PyTorch 1.8.0 and later. If your project supports earlier versions, consider replacingtorch.tile
withrepeat
to ensure broader compatibility.Dimension Alignment: Verify that tensor dimensions align correctly during operations like
unsqueeze
,expand
, andreshape
to prevent runtime errors, especially when dealing with batch sizes and type indices.Apply this diff to replace
torch.tile
withrepeat
for compatibility:# ntypes * ntypes * nt -type_embedding_i = torch.tile( - type_embedding.view(ntypes_with_padding, 1, nt), - [1, ntypes_with_padding, 1], -) -type_embedding_j = torch.tile( - type_embedding.view(1, ntypes_with_padding, nt), - [ntypes_with_padding, 1, 1], -) +type_embedding_i = type_embedding.view(ntypes_with_padding, 1, nt).repeat(1, ntypes_with_padding, 1) +type_embedding_j = type_embedding.view(1, ntypes_with_padding, nt).repeat(ntypes_with_padding, 1, 1)deepmd/pt/model/descriptor/se_atten.py (1)
578-579
: Remove redundant type casting totorch.long
At lines 578-579, the code applies both
.type(torch.long)
and.to(torch.long)
to the tensor, which is redundant. Since.to(torch.long)
is sufficient for casting, you can remove.type(torch.long)
to streamline the code.Suggested fix:
- .type(torch.long) .to(torch.long)
deepmd/dpmodel/descriptor/dpa2.py (1)
814-814
: Consider renaming the local variabletype_embedding
to avoid confusionUsing
type_embedding
as both an instance attribute (self.type_embedding
) and a local variable may lead to confusion. Consider renaming the local variable to something liketype_embedding_values
orembedded_types
for clarity.deepmd/dpmodel/descriptor/dpa1.py (1)
922-935
: Optimize the use ofxp.tile
for better performanceRepeated use of
xp.tile
can lead to increased memory usage and computational overhead. Consider using broadcasting or other efficient array manipulation techniques to achieve the same result with better performance.Example refactor using broadcasting:
atype_embd_nnei = xp.tile(atype_embd[:, xp.newaxis, :], (1, nnei, 1)) index = xp.tile( xp.reshape(nlist_masked, (nf, -1, 1)), (1, 1, self.tebd_dim) ) # Refactored code + atype_embd_nnei = atype_embd[:, xp.newaxis, :] + index = nlist_masked.reshape(nf, -1, 1)
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
📒 Files selected for processing (14)
deepmd/dpmodel/descriptor/descriptor.py
(1 hunks)deepmd/dpmodel/descriptor/dpa1.py
(5 hunks)deepmd/dpmodel/descriptor/dpa2.py
(3 hunks)deepmd/dpmodel/descriptor/repformers.py
(1 hunks)deepmd/dpmodel/descriptor/se_t_tebd.py
(4 hunks)deepmd/pt/model/descriptor/descriptor.py
(1 hunks)deepmd/pt/model/descriptor/dpa1.py
(1 hunks)deepmd/pt/model/descriptor/dpa2.py
(5 hunks)deepmd/pt/model/descriptor/repformers.py
(1 hunks)deepmd/pt/model/descriptor/se_a.py
(1 hunks)deepmd/pt/model/descriptor/se_atten.py
(4 hunks)deepmd/pt/model/descriptor/se_t.py
(2 hunks)deepmd/pt/model/descriptor/se_t_tebd.py
(6 hunks)deepmd/pt/model/network/network.py
(1 hunks)
🔇 Additional comments (22)
deepmd/dpmodel/descriptor/descriptor.py (1)
126-126
: LGTM! Verify derived class implementations.
The addition of the optional type_embedding
parameter is well-typed and maintains backward compatibility.
Let's verify that all derived classes have been updated with the new parameter:
deepmd/pt/model/descriptor/descriptor.py (1)
177-177
: LGTM! Verify implementation in derived classes.
The addition of the optional type_embedding
parameter is well-typed and maintains backward compatibility.
Let's verify that all derived classes properly implement this new parameter:
✅ Verification successful
Based on the comprehensive search results, I can now generate the final response:
All derived classes properly handle the type_embedding parameter
The codebase shows consistent implementation of the type_embedding
parameter across all descriptor implementations:
- All descriptor blocks that use type embeddings properly implement the
type_embedding
parameter in their forward methods - The parameter is consistently typed as
Optional[torch.Tensor]
and has proper handling in the strip mode - Key implementations found in:
- DescrptBlockSeT
- DescrptBlockSeAtten
- DescrptBlockSeTTebd
- All properly handle both concat and strip modes for type embeddings
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Description: Check if all derived classes properly implement the new type_embedding parameter
# in their forward method signatures
# Find all potential descriptor implementations
ast-grep --pattern 'class $CLASS_NAME($$$) {
$$$
def forward(self, nlist: $_, extended_coord: $_, extended_atype: $_, $$$) {
$$$
}
$$$
}'
# Also check for any TODOs or FIXMEs that might indicate incomplete implementations
rg -i "todo|fixme" --type py
Length of output: 2048
Script:
#!/bin/bash
# Let's search for all descriptor implementations and their forward methods
# to verify the type_embedding parameter implementation
# First, find all Python files that might contain descriptor implementations
fd "\.py$" deepmd/pt/model/descriptor/ --type f --exec cat {} \;
# Also, let's specifically look for classes that inherit from DescriptorBlock
ast-grep --pattern 'class $CLASS_NAME(DescriptorBlock)'
Length of output: 134798
Script:
#!/bin/bash
# Let's check all implementations of forward method in descriptor classes
# to verify they properly handle the type_embedding parameter
ast-grep --pattern 'def forward(self, $$$, type_embedding: Optional[torch.Tensor] = None, $$$)'
# Also check for any forward method implementations in descriptor classes
ast-grep --pattern 'class $CLASS_NAME($$$) {
$$$
def forward(self, $$$) {
$$$
}
$$$
}'
Length of output: 198
Script:
#!/bin/bash
# Let's try a different approach to find forward method implementations
# Search for forward method signatures in descriptor files
# First, let's look for forward method definitions in descriptor files
rg "def forward" deepmd/pt/model/descriptor/ -A 5
# Also check for type_embedding parameter usage
rg "type_embedding" deepmd/pt/model/descriptor/ -B 2 -A 2
Length of output: 38838
deepmd/pt/model/network/network.py (1)
299-301
: Verify integration with descriptor classes.
Let's confirm the proper integration of this method with the descriptor classes that use it.
✅ Verification successful
Integration verified successfully
The get_full_embedding
method is properly integrated with the descriptor classes and is used consistently in the strip mode workflow:
- It's a simple wrapper around the
embedding
method inTypeEmbedNet
class - It's correctly used by DPA1, DPA2, and SE-T-TEBD descriptors when
tebd_input_mode="strip"
- The implementation follows the same pattern across all descriptor classes:
if self.tebd_input_mode in ["strip"]: type_embedding = self.type_embedding.get_full_embedding(device)
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Description: Verify the usage of get_full_embedding in descriptor classes
# and ensure it's properly integrated with strip mode.
# Check for method usage in descriptor files
echo "Checking usage in descriptor files..."
rg -l "get_full_embedding.*device" --type py
# Check for strip mode related code
echo "Checking strip mode integration..."
rg -A 5 "tebd_input_mode.*strip" --type py
# Look for any related tests
echo "Checking test coverage..."
rg -l "get_full_embedding.*test" --type py
Length of output: 43082
Script:
#!/bin/bash
# Let's check the implementation and usage of get_full_embedding in descriptor classes
# Check the implementation in network.py
echo "Checking implementation in network.py..."
rg -A 5 "def embedding" deepmd/pt/model/network/network.py
# Check usage in descriptor classes
echo "Checking usage in DPA1..."
rg -A 5 "get_full_embedding" deepmd/pt/model/descriptor/dpa1.py
echo "Checking usage in DPA2..."
rg -A 5 "get_full_embedding" deepmd/pt/model/descriptor/dpa2.py
echo "Checking usage in se_t_tebd..."
rg -A 5 "get_full_embedding" deepmd/pt/model/descriptor/se_t_tebd.py
Length of output: 1270
Script:
#!/bin/bash
# Let's check the implementation of embedding method and its relationship with get_full_embedding
# Check the implementation of embedding method
echo "Checking embedding method implementation..."
ast-grep --pattern $'class TypeEmbedNet {
$$$
def embedding($_, $_) {
$$$
}
$$$
}'
# Check if there are any tests for the embedding functionality
echo "Checking tests..."
rg -A 5 "TypeEmbedNet.*embedding" --type py source/tests/
Length of output: 297
Script:
#!/bin/bash
# Let's check the TypeEmbedNet class implementation and its methods
echo "Checking TypeEmbedNet class implementation..."
rg -A 20 "class TypeEmbedNet" --type py
echo "Checking all methods with 'embedding' in TypeEmbedNet..."
rg -A 10 "def.*embedding" --type py deepmd/pt/model/network/
Length of output: 9206
Script:
#!/bin/bash
# Let's check the embedding method implementation and its usage
# Check the embedding method in TypeEmbedNet
echo "Checking embedding method in TypeEmbedNet..."
rg -A 10 "def embedding" deepmd/pt/model/network/network.py
# Check if there are any direct calls to embedding method
echo "Checking direct calls to embedding method..."
rg "\.embedding\(" --type py deepmd/pt/model/
# Check the relationship between embedding and get_full_embedding
echo "Checking relationship between methods..."
rg -B 5 -A 5 "get_full_embedding|embedding" deepmd/pt/model/network/network.py
Length of output: 8495
deepmd/pt/model/descriptor/repformers.py (1)
392-392
:
Unused parameter type_embedding
The type_embedding
parameter has been added to the method signature but is not utilized in the implementation. This appears to be inconsistent with the PR's objective of enhancing type embedding handling.
Please either:
- Implement the logic to use this parameter, or
- Remove it if it's not needed in this class.
Let's verify if this parameter is used in other descriptor implementations:
deepmd/pt/model/descriptor/se_a.py (1)
728-728
: Verify parent class compatibility
The addition of the type_embedding
parameter needs to be consistent with the parent class's forward method signature.
deepmd/pt/model/descriptor/dpa1.py (1)
699-700
: LGTM!
The type_embedding parameter is correctly passed to the se_atten forward call, maintaining proper alignment with the function signature.
deepmd/pt/model/descriptor/dpa2.py (3)
165-165
: LGTM: Clean attribute initialization.
The initialization of self.tebd_input_mode
from self.repinit_args.tebd_input_mode
is clean and follows good practices.
823-823
: LGTM: Clean communication dictionary handling.
The addition of comm_dict
parameter to the repformers call is well-implemented and enables parallel inference support.
769-772
: Verify TypeEmbedNet implementation.
The type embedding handling looks correct, but let's verify the implementation of get_full_embedding
method in the TypeEmbedNet class.
Also applies to: 781-781, 796-796
✅ Verification successful
Type embedding implementation verified successfully
The get_full_embedding
method is properly implemented in the PyTorch TypeEmbedNet
class in deepmd/pt/model/network/network.py
. The method is correctly used in dpa2.py
which imports and instantiates the appropriate TypeEmbedNet
class. The implementation is consistent with the conditional usage in the reviewed code.
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Description: Check if TypeEmbedNet has get_full_embedding method implemented
ast-grep --pattern 'class TypeEmbedNet {
$$$
get_full_embedding($device) {
$$$
}
$$$
}'
Length of output: 101
Script:
#!/bin/bash
# Let's try a broader search for TypeEmbedNet class and get_full_embedding method
echo "Searching for TypeEmbedNet class:"
rg "class TypeEmbedNet" -A 5
echo -e "\nSearching for get_full_embedding method:"
rg "def get_full_embedding"
echo -e "\nSearching for type_embedding related files:"
fd "type.*embed" --type f
Length of output: 3216
Script:
#!/bin/bash
# Let's check the implementation of get_full_embedding in the PyTorch network file
echo "Checking get_full_embedding implementation in PyTorch:"
rg "def get_full_embedding" deepmd/pt/model/network/network.py -A 10
# Also check which class is being used in dpa2.py
echo -e "\nChecking type embedding import and usage in dpa2.py:"
rg "TypeEmbed" deepmd/pt/model/descriptor/dpa2.py
Length of output: 1049
deepmd/dpmodel/descriptor/se_t_tebd.py (3)
736-777
: Ensure smooth
parameter affects computations as intended
In the "strip"
mode, the smooth
parameter controls whether the smooth function is applied. Verify that setting self.smooth
to False
appropriately skips or includes the smoothing in gg_t
.
Review the condition where self.smooth
is used:
if self.smooth:
gg_t = (
gg_t
* xp.reshape(sw, (nf * nloc, self.nnei, 1, 1))
* xp.reshape(sw, (nf * nloc, 1, self.nnei, 1))
)
Ensure that when self.smooth
is False
, the smoothing is correctly omitted.
335-335
: Ensure consistent handling of type_embedding
initialization
The variable type_embedding
is assigned without prior checks for its initialization. Ensure that self.type_embedding
is properly initialized before this call to prevent potential AttributeError
.
Run the following script to verify the initialization of self.type_embedding
in all code paths:
738-770
: Ensure correctness of type embedding computations in "strip"
mode
Verify the logic involved in computing two_side_type_embedding
. Ensure that the shapes and concatenations are correctly handled, especially during reshaping and indexing operations.
Run the following script to check the shapes and dimensions during execution:
Consider adding unit tests to validate these computations.
✅ Verification successful
Let me analyze the code and gather more information about the type embedding computations.
Based on the search results, I can now generate the final response as we have sufficient evidence to verify the type embedding computations.
Type embedding computations in "strip"
mode are correctly implemented
The implementation is consistent with other descriptors in the codebase (se_atten, se_a, dpa1) and follows the same pattern. The shape transformations are correct:
type_embedding_i
:(ntypes_with_padding, ntypes_with_padding, nt)
- correctly tiled for first atom typestype_embedding_j
:(ntypes_with_padding, ntypes_with_padding, nt)
- correctly tiled for second atom typestwo_side_type_embedding
:(ntypes_with_padding * ntypes_with_padding, nt * 2)
- properly reshaped concatenation
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Description: Instrument the code to print shapes of intermediate variables.
# Note: This is a conceptual script. Actual debugging should be done within a development environment.
echo "Insert debug statements to print shapes of 'nei_type_i', 'nei_type_j', 'idx', 'type_embedding_i', 'type_embedding_j', 'two_side_type_embedding'. Ensure that all shapes align as expected."
Length of output: 418
Script:
#!/bin/bash
# Search for test files related to se_t_tebd.py
fd "test.*se.*t.*tebd.*py" --type f
# Look for any existing test cases that validate type embedding shapes
rg -A 5 "two_side_type_embedding|type_embedding_[ij]" --type py
# Search for similar type embedding patterns in other descriptors
ast-grep --pattern 'type_embedding_i = $$$
type_embedding_j = $$$
two_side_type_embedding = $$$'
Length of output: 13252
deepmd/pt/model/descriptor/se_t_tebd.py (2)
453-456
: Ensure type_embedding
is correctly initialized
In the forward
method, when self.tebd_input_mode
is "strip", type_embedding
is set using self.type_embedding.get_full_embedding(g1_ext.device)
. Ensure that get_full_embedding
returns a tensor with the expected dimensions and that it aligns correctly with subsequent computations in self.se_ttebd.forward
.
463-463
: Confirm compatibility with updated forward
method
Passing type_embedding=type_embedding
to self.se_ttebd
's forward
method requires that DescrptBlockSeTTebd.forward
is updated to accept this parameter. Verify that all instances where self.se_ttebd.forward
is called are updated accordingly, and that any subclasses or overrides of this method are compatible with the new signature.
deepmd/pt/model/descriptor/se_atten.py (3)
466-468
: Clear documentation of the type_embedding
parameter
The docstring accurately documents the type_embedding
parameter and specifies that it is required for stripped type embeddings.
523-536
: Correct processing of type embeddings in 'concat' mode
The code correctly handles the reshaping and gathering of type embeddings in the 'concat'
mode. The tensor operations ensure that the embeddings are properly aligned with the neighbor list for subsequent computations.
554-601
: Proper implementation of type embeddings in 'strip' mode
The code accurately processes the type_embedding
in the 'strip'
mode. The assertions ensure necessary components are not None
, and the tensor manipulations handle both the type_one_side
conditions appropriately.
deepmd/dpmodel/descriptor/dpa2.py (3)
817-817
: Efficient reuse of type_embedding
improves performance
Storing the result of self.type_embedding.call()
in a variable and reusing it avoids redundant computations, which enhances performance and improves code readability.
829-829
: Passing type_embedding
to self.repinit
enhances functionality
Including type_embedding
as a parameter in the call to self.repinit
allows for better handling of type embeddings during descriptor computations. Ensure that the DescrptBlockSeAtten
class's method accepts this parameter.
844-844
: Consistent integration of type_embedding
in self.repinit_three_body
Passing type_embedding
to self.repinit_three_body
ensures consistent use of type embeddings across both two-body and three-body representations, enhancing the model's capability.
deepmd/dpmodel/descriptor/dpa1.py (2)
Line range hint 497-511
: Integration of type_embedding
in call
method is correctly implemented
The addition and handling of type_embedding
in the call
method enhance the descriptor's functionality and are implemented appropriately.
958-960
: Ensure type_embedding
has the correct shape
When using self.cal_g_strip(type_embedding, 0)
, verify that type_embedding
has the expected shape and dimensions to prevent runtime errors.
Run the following script to check the shape of type_embedding
:
✅ Verification successful
Based on the code analysis, I can now provide the final response:
The shape of type_embedding
is correctly handled in the implementation
The code shows that type_embedding
is properly managed:
- It's created via
TypeEmbedNet
with correct dimensions (ntypes, tebd_dim) - Its shape is correctly validated before use (ntypes_with_padding is extracted from shape[0])
- The
cal_g_strip
method properly handles the input shape for the embeddings network
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Description: Verify that type_embedding has the correct dimensions.
# Test: Extract the shape of type_embedding in the codebase.
# Expected result: type_embedding has dimensions (ntypes_with_padding, tebd_dim)
ast-grep --pattern $'type_embedding = self.type_embedding.call()' --json |
jq '.captures[] | select(.name == "pattern") | .text' |
grep -Eo 'shape\([^)]+\)' |
grep 'ntypes_with_padding, tebd_dim'
Length of output: 265
Script:
#!/bin/bash
# Let's first find where type_embedding is defined and used
rg "type_embedding" deepmd/dpmodel/descriptor/dpa1.py -B 2 -A 2
# Also check the cal_g_strip method to understand expected shape
ast-grep --pattern 'def cal_g_strip($$$)' deepmd/dpmodel/descriptor/dpa1.py
Length of output: 5311
Script:
#!/bin/bash
# Let's check the cal_g_strip implementation and type_embedding initialization
ast-grep --pattern 'def cal_g_strip' -A 10 deepmd/dpmodel/descriptor/dpa1.py
# Also check TypeEmbedNet class to understand type_embedding shape
ast-grep --pattern 'class TypeEmbedNet' -A 20 deepmd/dpmodel/descriptor/dpa1.py
Length of output: 160
Script:
#!/bin/bash
# Let's try with ripgrep to find these implementations
rg "def cal_g_strip" -A 10 deepmd/dpmodel/descriptor/dpa1.py
rg "class TypeEmbedNet" -A 20 deepmd/dpmodel/descriptor/dpa1.py
# Also check where type_embedding shape is used
rg "type_embedding.*shape" deepmd/dpmodel/descriptor/dpa1.py
Length of output: 622
Signed-off-by: Jinzhe Zeng <[email protected]>
Signed-off-by: Jinzhe Zeng <[email protected]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Outside diff range and nitpick comments (2)
deepmd/dpmodel/descriptor/se_t_tebd.py (2)
714-728
: Add shape documentation for tensor operationsThe tensor operations are correct but would benefit from inline comments documenting the intermediate tensor shapes for better maintainability.
Add shape documentation like this:
# nfnl x nnei x tebd_dim atype_embd_nlist = xp_take_along_axis(atype_embd_ext, index, axis=1) +# Reshape: (nf * nloc, nnei, tebd_dim) atype_embd_nlist = xp.reshape( atype_embd_nlist, (nf * nloc, nnei, self.tebd_dim) )
737-778
: Consider refactoring strip mode implementationThe strip mode implementation is complex and could benefit from being broken down into smaller, more focused functions for better maintainability and testability.
Consider refactoring like this:
+def _compute_neighbor_types(self, nlist_masked, atype_ext, nf, nloc, nnei): + """Compute neighbor types for strip mode.""" + # nf x (nl x nnei) + nlist_index = xp.reshape(nlist_masked, (nf, nloc * nnei)) + # nf x (nl x nnei) + nei_type = xp_take_along_axis(atype_ext, nlist_index, axis=1) + # nfnl x nnei + return xp.reshape(nei_type, (nf * nloc, nnei)) + +def _compute_type_indices(self, nei_type, nnei, ntypes_with_padding): + """Compute type indices for embedding lookup.""" + nei_type_i = xp.tile(nei_type[:, :, np.newaxis], (1, 1, nnei)) + nei_type_j = xp.tile(nei_type[:, np.newaxis, :], (1, nnei, 1)) + return nei_type_i * ntypes_with_padding, nei_type_jAdditionally, consider using vectorized operations to improve performance:
# Instead of multiple tile operations, use broadcasting type_embedding_combined = xp.stack([ type_embedding[:, None, :].repeat(ntypes_with_padding, axis=1), type_embedding[None, :, :].repeat(ntypes_with_padding, axis=0) ], axis=-1)
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
📒 Files selected for processing (1)
deepmd/dpmodel/descriptor/se_t_tebd.py
(5 hunks)
🔇 Additional comments (3)
deepmd/dpmodel/descriptor/se_t_tebd.py (3)
335-340
: LGTM: Efficient type embedding initialization
The optimization to compute type embedding once and reshape it is more efficient than computing it multiple times.
349-349
: Verify backward compatibility with existing callers
The addition of the optional type_embedding
parameter maintains backward compatibility, but we should verify all callers.
✅ Verification successful
Let me analyze the search results and generate a final response.
Optional type_embedding
parameter is safe to add
The search results show that all existing .call()
invocations in the codebase do not use the type_embedding
parameter, which confirms that making it optional maintains backward compatibility. The callers are primarily in test files and descriptor implementations, and none would be affected by this addition.
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Search for existing call() method invocations
rg -A 2 "\.call\(" | grep -v "type_embedding"
Length of output: 13192
737-738
:
Replace assertions with proper error handling
Using assertions for runtime checks is not recommended as they may be disabled with Python's -O flag.
Replace with proper error handling:
-assert self.embeddings_strip is not None
-assert type_embedding is not None
+if self.embeddings_strip is None:
+ raise ValueError("embeddings_strip must not be None in strip mode")
+if type_embedding is None:
+ raise ValueError("type_embedding must not be None in strip mode")
Likely invalid or redundant comment.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Outside diff range and nitpick comments (1)
deepmd/dpmodel/descriptor/se_t_tebd.py (1)
Line range hint
711-778
: Consider caching type embedding combinationsThe code repeatedly computes type embedding combinations. Consider pre-computing and caching
two_side_type_embedding
since it only depends ontype_embedding
and dimensions, not on the input data.Example implementation:
def __init__(self, ...): # ... existing code ... + self._cached_two_side_type_embedding = None + self._cached_tt_full = None def call(self, ...): # ... existing code ... if self.tebd_input_mode in ["strip"]: + if self._cached_two_side_type_embedding is None: type_embedding_i = xp.tile( xp.reshape(type_embedding, (ntypes_with_padding, 1, nt)), (1, ntypes_with_padding, 1), ) type_embedding_j = xp.tile( xp.reshape(type_embedding, (1, ntypes_with_padding, nt)), (ntypes_with_padding, 1, 1), ) two_side_type_embedding = xp.reshape( xp.concat([type_embedding_i, type_embedding_j], axis=-1), (-1, nt * 2) ) + self._cached_two_side_type_embedding = two_side_type_embedding + self._cached_tt_full = self.cal_g_strip(two_side_type_embedding, 0) + tt_full = self._cached_tt_full
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
📒 Files selected for processing (1)
deepmd/dpmodel/descriptor/se_t_tebd.py
(5 hunks)
🔇 Additional comments (2)
deepmd/dpmodel/descriptor/se_t_tebd.py (2)
349-349
: LGTM: Type embedding parameter correctly passed
The type_embedding parameter is properly forwarded to the underlying se_ttebd call.
335-340
: Add validation for type embedding indices
The code should validate that all indices in atype_ext
are within bounds of type_embedding
to prevent potential index errors during execution.
…e and stride (at least one dimension spans across two contiguous subspaces). Use .reshape(...) instead.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Outside diff range and nitpick comments (3)
deepmd/pt/model/descriptor/se_atten.py (3)
466-468
: Clarify the documentation for thetype_embedding
parameterIn the docstring of the
forward
method, the description oftype_embedding
could be more precise. Currently, it mentions "Required for stripped type embeddings," which may not clearly indicate when this parameter should be provided.Consider updating the docstring to specify that
type_embedding
must be provided whentebd_input_mode
is set to"strip"
. This will improve clarity for users implementing this method.
554-601
: Optimize tensor operations to improve memory efficiencyThe usage of
torch.tile
for constructingtype_embedding_nei
andtype_embedding_center
may lead to increased memory consumption, especially when dealing with a large number of types.Consider using broadcasting with
expand
instead oftorch.tile
to avoid unnecessary data replication. This can enhance memory efficiency.Apply the following changes:
-# ntypes_with_padding x ntypes_with_padding x nt -type_embedding_nei = torch.tile( - type_embedding.view(1, ntypes_with_padding, nt), - [ntypes_with_padding, 1, 1], -) -# ntypes_with_padding x ntypes_with_padding x nt -type_embedding_center = torch.tile( - type_embedding.view(ntypes_with_padding, 1, nt), - [1, ntypes_with_padding, 1], -) +type_embedding_nei = type_embedding.view(1, ntypes_with_padding, nt).expand( + ntypes_with_padding, ntypes_with_padding, nt +) +type_embedding_center = type_embedding.view(ntypes_with_padding, 1, nt).expand( + ntypes_with_padding, ntypes_with_padding, nt +)This approach reduces memory overhead by avoiding data duplication.
577-579
: Remove redundant type castingThe chain of method calls
.type(torch.long).to(torch.long)
is redundant. Casting the tensor type once is sufficient.Simplify the code by removing the extra cast:
- .type(torch.long) - .to(torch.long) + .type(torch.long)
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
📒 Files selected for processing (1)
deepmd/pt/model/descriptor/se_atten.py
(4 hunks)
🔇 Additional comments (2)
deepmd/pt/model/descriptor/se_atten.py (2)
523-536
: Code logic for the 'concat'
mode appears correct
The integration of the type_embedding
parameter in the 'concat'
mode is appropriately handled. The tensor manipulations and shape transformations correctly incorporate the new parameter into the computation.
554-601
: Ensure consistent handling of type_embedding
in different modes
While type_embedding
is required in 'strip'
mode, it's optional in the method signature. This could lead to confusion or errors if not correctly managed.
Run the following script to verify that all calls to the forward
method provide the type_embedding
parameter when tebd_input_mode
is "strip"
:
This script helps ensure that type_embedding
is consistently provided when required, preventing potential runtime errors.
✅ Verification successful
Based on the search results, I can now provide a definitive response:
Type embedding handling is correctly implemented for 'strip' mode
The code correctly handles the type_embedding
parameter in 'strip' mode:
- The assertion checks at the beginning of the relevant code block ensure both
self.filter_layers_strip
andtype_embedding
are present when needed - The codebase consistently enforces this requirement through:
- Documentation clearly stating when
type_embedding
is required - Tests verifying the behavior in 'strip' mode
- Implementation in multiple descriptor classes (se_atten, dpa1, dpa2) consistently checking for these requirements
- Documentation clearly stating when
Additionally, model compression is only supported in 'strip' mode, and the code has proper validation to ensure all required parameters are present.
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Description: Verify the usage of `type_embedding` across different modes in the codebase.
# Search for all instances of the `forward` method in descriptor classes
rg --multiline -A 5 'def forward' | rg 'def forward.*tebd_input_mode'
# Find calls to `forward` without `type_embedding` when `tebd_input_mode` is 'strip'
rg --multiline 'forward\(.*tebd_input_mode=["\']strip["\'].*\)' | rg -v 'type_embedding'
# Expected Result:
# All `forward` calls with `tebd_input_mode="strip"` should include the `type_embedding` argument.
Length of output: 188
Script:
#!/bin/bash
# Let's try a different approach to verify the usage patterns
# First, let's find all files that might contain relevant forward method definitions
fd "\.py$" | xargs rg -l "def forward.*tebd_input_mode"
# Then search for the actual forward method implementations
rg -U "def forward.*tebd_input_mode.*\n.*\n.*\n.*\n.*"
# Find all potential calls to forward with strip mode
rg -U "forward\([^)]*tebd_input_mode\s*=\s*['\"]strip['\"]"
Length of output: 180
Script:
#!/bin/bash
# Let's try a more focused approach using ast-grep to find the method definition and its usage
# Find the forward method definition with tebd_input_mode parameter
ast-grep --pattern 'def forward($$$, tebd_input_mode$$$) {
$$$
}'
# Search for any direct references to tebd_input_mode in the codebase
rg "tebd_input_mode" -B 2 -A 2
# Look for the class definition containing this forward method
ast-grep --pattern 'class $_ {
$$$
def forward($$$, tebd_input_mode$$$) {
$$$
}
$$$
}'
Length of output: 90544
Signed-off-by: Jinzhe Zeng <[email protected]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
🧹 Outside diff range and nitpick comments (4)
deepmd/pt/model/descriptor/se_atten.py (2)
466-468
: Consider clarifying the shape parameter documentationThe shape description "(ntypes+1) x nt" could be more explicit by defining what "nt" represents. Consider updating it to clarify the dimension.
- Full type embeddings. shape: (ntypes+1) x nt + Full type embeddings. shape: (ntypes+1) x embedding_dim
523-534
: Consider extracting tensor operations into named helper functionsThe tensor operations for handling type embeddings are complex and could benefit from being broken down into named helper functions for better readability and maintainability.
Consider refactoring like this:
- atype_tebd_ext = extended_atype_embd - # nb x (nloc x nnei) x nt - index = nlist.reshape(nb, nloc * nnei).unsqueeze(-1).expand(-1, -1, nt) - # nb x (nloc x nnei) x nt - atype_tebd_nlist = torch.gather(atype_tebd_ext, dim=1, index=index) # j - # nb x nloc x nnei x nt - atype_tebd_nlist = atype_tebd_nlist.view(nb, nloc, nnei, nt) - - # nf x nloc x nt -> nf x nloc x nnei x nt - atype_tebd = extended_atype_embd[:, :nloc, :] - atype_tebd_nnei = atype_tebd.unsqueeze(2).expand(-1, -1, self.nnei, -1) # i + def gather_neighbor_embeddings(nlist, extended_embeddings): + """Gather embeddings for neighbor atoms.""" + index = nlist.reshape(nb, nloc * nnei).unsqueeze(-1).expand(-1, -1, nt) + gathered = torch.gather(extended_embeddings, dim=1, index=index) + return gathered.view(nb, nloc, nnei, nt) + + def expand_center_embeddings(embeddings): + """Expand embeddings for center atoms.""" + center = embeddings[:, :nloc, :] + return center.unsqueeze(2).expand(-1, -1, self.nnei, -1) + + atype_tebd_nlist = gather_neighbor_embeddings(nlist, extended_atype_embd) + atype_tebd_nnei = expand_center_embeddings(extended_atype_embd)deepmd/dpmodel/descriptor/dpa1.py (2)
Line range hint
497-511
: Add input validation for type embeddingsThe type embedding handling looks correct, but consider adding validation for the shape and dimensions of the embeddings to prevent potential runtime errors.
Add validation before line 497:
+ if type_embedding is not None and type_embedding.shape[1] != self.tebd_dim: + raise ValueError(f"Expected type_embedding dimension {self.tebd_dim}, got {type_embedding.shape[1]}") type_embedding = self.type_embedding.call()
951-989
: Add docstrings to explain tensor operationsThe complex tensor operations and reshaping would benefit from detailed documentation explaining the dimensions and purpose.
Add docstrings to explain the operations:
+ # Shape explanation: + # type_embedding: [ntypes_with_padding, nt] - Embedding for each type + # nei_type: [nf, nloc * nnei] - Type of each neighbor atom + # atype: [nf, nloc] - Type of each central atom + # Returns: [(nf * nloc * nnei), ng] - Embedded type information for each atom pair
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
📒 Files selected for processing (2)
deepmd/dpmodel/descriptor/dpa1.py
(5 hunks)deepmd/pt/model/descriptor/se_atten.py
(4 hunks)
🔇 Additional comments (3)
deepmd/pt/model/descriptor/se_atten.py (2)
450-450
: LGTM: Well-typed optional parameter addition
The new optional parameter type_embedding
is properly typed as Optional[torch.Tensor]
with a default value of None
, maintaining backward compatibility.
569-580
: Verify index calculation for two-sided type embeddings
The index calculation for two-sided type embeddings involves complex tensor operations. Please verify that the indices are correctly calculated, especially for edge cases.
✅ Verification successful
Let me generate additional verification scripts to check the type embedding implementation and index calculations.
Let me generate additional scripts to check the neighbor type handling and index calculations.
Based on the code analysis from the shell script results, I can now provide a final response:
Index calculation for two-sided type embeddings is correctly implemented
The implementation in se_atten.py correctly handles type embeddings by:
- Computing central atom indices with proper padding using
torch.tile
- Reshaping neighbor type indices with
view(-1)
- Combining indices with bounds checking via explicit type casting to
torch.long
- Using proper tensor broadcasting for the final embedding lookup
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Description: Check for potential index out of bounds in two-sided type embeddings
# Search for array index access patterns
rg -A 5 'idx.*\.view\(-1, 1\)' .
# Search for tensor shape assertions or checks
rg -A 5 'assert.*shape' .
# Look for related test cases
fd -e py -E 'test_.*\.py$' | xargs rg 'test.*type.*embedding'
Length of output: 110327
Script:
#!/bin/bash
# Search for type embedding implementations and index calculations
ast-grep --pattern 'idx_i = torch.tile($$$)'
# Look for related type embedding calculations
rg -A 5 'atype.*reshape.*ntypes' .
# Check for type-related assertions or validations
rg -A 3 'assert.*type' .
# Search for neighbor type handling
rg -A 5 'nei_type' .
Length of output: 100208
Script:
#!/bin/bash
# Search for neighbor type handling and index calculations
rg -A 10 'nei_type.*view\(-1\)' .
# Look for related index calculations
ast-grep --pattern 'idx = (idx_i + idx_j)$$$'
# Check for type-related validations in the descriptor
rg -A 5 'assert.*type.*shape' deepmd/pt/model/descriptor/
Length of output: 1490
deepmd/dpmodel/descriptor/dpa1.py (1)
949-950
: Replace assertions with proper error handling
This was previously flagged in the past reviews. The assertions should be replaced with proper error handling.
Codecov ReportAll modified and coverable lines are covered by tests ✅
Additional details and impacted files@@ Coverage Diff @@
## devel #4400 +/- ##
==========================================
+ Coverage 84.50% 84.60% +0.09%
==========================================
Files 604 614 +10
Lines 56944 57072 +128
Branches 3486 3487 +1
==========================================
+ Hits 48122 48287 +165
+ Misses 7697 7659 -38
- Partials 1125 1126 +1 ☔ View full report in Codecov by Sentry. 🚨 Try these New Features:
|
The strip methods are different between se_atten and se_t_tebd, it's not necessary to merge them.
Summary by CodeRabbit
New Features
type_embedding
in various methods across descriptor classes to enhance handling of atomic types and embeddings.get_full_embedding
in theTypeEmbedNet
class for easier access to complete embeddings.Bug Fixes
type_embedding
parameter in multiple classes to prevent runtime errors.Documentation
type_embedding
.