ludwig-ai--ludwig
593b94c120
pytest / Unit Tests (push) Has been cancelled
pytest / Integration (integration_tests_a) (push) Has been cancelled
pytest / Integration (integration_tests_b) (push) Has been cancelled
pytest / Integration (integration_tests_c) (push) Has been cancelled
pytest / Integration (integration_tests_d) (push) Has been cancelled
pytest / Integration (integration_tests_e) (push) Has been cancelled
pytest / Integration (integration_tests_f) (push) Has been cancelled
pytest / Integration (integration_tests_g) (push) Has been cancelled
pytest / Integration (integration_tests_h) (push) Has been cancelled
pytest / Integration (integration_tests_i) (push) Has been cancelled
pytest / Integration (integration_tests_j) (push) Has been cancelled
pytest / Distributed (distributed_a) (push) Has been cancelled
pytest / Distributed (distributed_b) (push) Has been cancelled
pytest / Distributed (distributed_c) (push) Has been cancelled
pytest / Distributed (distributed_d) (push) Has been cancelled
pytest / Distributed (distributed_e) (push) Has been cancelled
pytest / Distributed (distributed_f) (push) Has been cancelled
pytest / Minimal Install (push) Has been cancelled
pytest / Event File (push) Has been cancelled
pytest (slow) / py-slow (push) Has been cancelled
Publish JSON Schema / publish-schema (push) Has been cancelled
123 行
5.4 KiB
Python
123 行
5.4 KiB
Python
"""Utilities used for managing output feature dicts."""
|
|
|
|
import numpy as np
|
|
import torch
|
|
|
|
from ludwig.utils.torch_utils import sequence_length_3D, sequence_mask
|
|
|
|
|
|
def get_feature_concat_name(feature_name: str, tensor_name: str) -> str:
|
|
return feature_name + "::" + tensor_name
|
|
|
|
|
|
def get_tensor_name_from_concat_name(concat_name: str) -> str:
|
|
return concat_name.split("::")[-1]
|
|
|
|
|
|
def get_feature_name_from_concat_name(concat_name: str) -> str:
|
|
return "::".join(concat_name.split("::")[:-1])
|
|
|
|
|
|
def get_single_output_feature_tensors(
|
|
output_feature_dict: dict[str, torch.Tensor], feature_name: str
|
|
) -> dict[str, torch.Tensor]:
|
|
"""Returns a map of tensors related to the given feature_name."""
|
|
single_output_feature_tensors = {}
|
|
for concat_name, tensor in output_feature_dict.items():
|
|
if get_feature_name_from_concat_name(concat_name) == feature_name:
|
|
single_output_feature_tensors[get_tensor_name_from_concat_name(concat_name)] = tensor
|
|
return single_output_feature_tensors
|
|
|
|
|
|
def get_output_feature_tensor(
|
|
output_dict: dict[str, torch.Tensor], feature_name: str, tensor_name: str
|
|
) -> torch.Tensor:
|
|
"""Returns a tensor related for the given feature_name and tensor_name."""
|
|
concat_name = get_feature_concat_name(feature_name, tensor_name)
|
|
if concat_name not in output_dict:
|
|
raise ValueError(
|
|
f"Could not find {tensor_name} for {feature_name} in the output_dict with keys: {output_dict.keys()}"
|
|
)
|
|
return output_dict[get_feature_concat_name(feature_name, tensor_name)]
|
|
|
|
|
|
def set_output_feature_tensor(
|
|
output_dict: dict[str, torch.Tensor], feature_name: str, tensor_name: str, tensor: torch.Tensor
|
|
):
|
|
"""Adds tensor for the given feature_name and tensor_name to the tensor dict."""
|
|
output_dict[get_feature_concat_name(feature_name, tensor_name)] = tensor
|
|
|
|
|
|
def concat_dependencies(
|
|
feature_name: str,
|
|
dependencies: list[str],
|
|
dependency_reducers: torch.ModuleDict,
|
|
combiner_hidden_state: torch.Tensor,
|
|
other_output_feature_states: dict[str, torch.Tensor],
|
|
) -> torch.Tensor:
|
|
"""Concatenates combiner_hidden_state with other output feature hidden states based on listed dependencies."""
|
|
# No dependencies.
|
|
if not dependencies:
|
|
return combiner_hidden_state
|
|
|
|
dependency_hidden_states = []
|
|
for feature_name in dependencies:
|
|
# The dependent feature should be present since ECD does a topological sort over output features.
|
|
feature_hidden_state = other_output_feature_states[feature_name]
|
|
|
|
# This feature is sequential.
|
|
if len(combiner_hidden_state.shape) > 2:
|
|
if len(feature_hidden_state.shape) > 2:
|
|
# The dependent feature is also sequential.
|
|
# matrix matrix -> concat
|
|
if combiner_hidden_state.shape[1] != feature_hidden_state.shape[1]:
|
|
raise ValueError(
|
|
f"Sequence length mismatch between combiner output ({combiner_hidden_state.shape[1]}) "
|
|
f"and dependent feature '{feature_name}' ({feature_hidden_state.shape[1]}). "
|
|
f"Both sequential features must have the same sequence length."
|
|
)
|
|
dependency_hidden_states.append(feature_hidden_state)
|
|
else:
|
|
# The dependent feature is not sequential.
|
|
# matrix vector -> tile concat
|
|
sequence_max_length = combiner_hidden_state.shape[1]
|
|
multipliers = (1, sequence_max_length, 1)
|
|
tiled_representation = torch.tile(torch.unsqueeze(feature_hidden_state, 1), multipliers)
|
|
|
|
sequence_length = sequence_length_3D(combiner_hidden_state)
|
|
mask = sequence_mask(sequence_length, sequence_max_length)
|
|
tiled_representation = torch.mul(
|
|
tiled_representation,
|
|
mask[:, :, np.newaxis].type(torch.float32),
|
|
)
|
|
|
|
dependency_hidden_states.append(tiled_representation)
|
|
|
|
else:
|
|
# This feature is not sequential.
|
|
if len(feature_hidden_state.shape) > 2:
|
|
# The dependent feature is sequential.
|
|
# vector matrix -> reduce concat
|
|
reducer = dependency_reducers[feature_name]
|
|
dependency_hidden_states.append(reducer(feature_hidden_state))
|
|
else:
|
|
# The dependent feature is not sequential.
|
|
# vector vector -> concat
|
|
dependency_hidden_states.append(feature_hidden_state)
|
|
|
|
try:
|
|
hidden = torch.cat([combiner_hidden_state] + dependency_hidden_states, dim=-1)
|
|
except Exception as e:
|
|
raise ValueError(
|
|
f"Shape mismatch {e} while concatenating dependent features of {feature_name}: "
|
|
f"{dependencies}. Concatenating the feature activations tensor {combiner_hidden_state} "
|
|
f"with activation tensors of dependencies: {dependency_hidden_states}. The error is "
|
|
"likely due to a mismatch of the second dimension (sequence length) or a "
|
|
"difference in ranks. Likely solutions are setting the maximum_sequence_length "
|
|
"of all sequential features to be the same, or reduce the output of some "
|
|
"features, or disabling the bucketing setting bucketing_field to None / null, "
|
|
"as activating it will reduce the length of the field the bucketing is "
|
|
"performed on."
|
|
)
|
|
return hidden
|