chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,60 @@
|
||||
set(parsed_yaml_path ${PADDLE_BINARY_DIR}/paddle/phi/ops/yaml)
|
||||
set(fwd_path ${parsed_yaml_path}/ops.parsed.yaml)
|
||||
set(rev_path ${parsed_yaml_path}/backward.parsed.yaml)
|
||||
set(fwd_pd_op_path ${parsed_yaml_path}/inconsistent/static_ops.parsed.yaml)
|
||||
set(update_fwd_pd_op_path
|
||||
${parsed_yaml_path}/inconsistent/update_ops.parsed.yaml)
|
||||
set(rev_pd_op_path ${parsed_yaml_path}/inconsistent/static_backward.parsed.yaml)
|
||||
set(fused_op_path ${parsed_yaml_path}/fused_ops.parsed.yaml)
|
||||
set(fused_rev_op_path ${parsed_yaml_path}/fused_backward.parsed.yaml)
|
||||
|
||||
set(sparse_op_path ${parsed_yaml_path}/sparse_ops.parsed.yaml)
|
||||
set(sparse_rev_op_path ${parsed_yaml_path}/sparse_backward.parsed.yaml)
|
||||
set(prim_path
|
||||
${PADDLE_SOURCE_DIR}/paddle/fluid/primitive/primitive/primitive.yaml)
|
||||
set(templates_dir
|
||||
${PADDLE_SOURCE_DIR}/paddle/fluid/primitive/codegen/templates/)
|
||||
set(compat_path ${PADDLE_SOURCE_DIR}/paddle/phi/ops/yaml/op_compat.yaml)
|
||||
set(destination_dir ${PADDLE_BINARY_DIR}/paddle/fluid/primitive/)
|
||||
set(decomp_vjp_destination_dir
|
||||
${PADDLE_BINARY_DIR}/paddle/fluid/pir/dialect/operator/ir/op_decomp_vjp.cc)
|
||||
set(scripts
|
||||
${PADDLE_SOURCE_DIR}/paddle/fluid/primitive/codegen/decomp_vjp_gen.py)
|
||||
|
||||
message("Automatic code generation for paddle/fluid/primitive")
|
||||
execute_process(
|
||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/paddle/fluid/primitive/codegen
|
||||
COMMAND
|
||||
${PYTHON_EXECUTABLE}
|
||||
${PADDLE_SOURCE_DIR}/paddle/fluid/primitive/codegen/decomp_vjp_gen.py
|
||||
--fwd_path ${fwd_path} --rev_path ${rev_path} --fwd_pd_op_path
|
||||
${fwd_pd_op_path} --update_fwd_pd_op_path ${update_fwd_pd_op_path}
|
||||
--rev_pd_op_path ${rev_pd_op_path} --prim_path ${prim_path} --fused_op_path
|
||||
${fused_op_path} --fused_rev_op_path ${fused_rev_op_path} --sparse_op_path
|
||||
${sparse_op_path} --sparse_rev_op_path ${sparse_rev_op_path} --templates_dir
|
||||
${templates_dir} --compat_path ${compat_path} --destination_dir
|
||||
${destination_dir} --decomp_vjp_destination_dir
|
||||
${decomp_vjp_destination_dir}
|
||||
RESULT_VARIABLE _result)
|
||||
if(${_result})
|
||||
message(
|
||||
FATAL_ERROR
|
||||
"Automatic code generation for paddle/fluid/primitive failed, exiting.")
|
||||
endif()
|
||||
message("Automatic code generation for paddle/fluid/primitive succeed.")
|
||||
execute_process(
|
||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/paddle/fluid/primitive/codegen
|
||||
COMMAND
|
||||
${PYTHON_EXECUTABLE}
|
||||
${PADDLE_SOURCE_DIR}/paddle/fluid/primitive/codegen/decomp_rule_gen.py
|
||||
--fwd_path ${fwd_path} --fwd_pd_op_path ${fwd_pd_op_path} --templates_dir
|
||||
${templates_dir} --compat_path ${compat_path} --destination_dir
|
||||
${PADDLE_BINARY_DIR}/paddle/fluid/pir/dialect/operator/ir/op_decomp_rule.cc
|
||||
RESULT_VARIABLE _result)
|
||||
if(${_result})
|
||||
message(
|
||||
FATAL_ERROR
|
||||
"Automatic code generation for build/paddle/fluid/pir/dialect/operator/ir/op_decomp_rule.cc failed."
|
||||
)
|
||||
endif()
|
||||
message("Automatic code generation for decomp interface succeed.")
|
||||
@@ -0,0 +1,252 @@
|
||||
# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import argparse
|
||||
import hashlib
|
||||
import pathlib
|
||||
import sys
|
||||
|
||||
import jinja2
|
||||
import yaml
|
||||
|
||||
# import from paddle/fluid/operators/generator
|
||||
sys.path.insert(
|
||||
0, str(pathlib.Path(__file__).resolve().parents[2] / 'operators/generator')
|
||||
)
|
||||
import filters as op_gen_filters
|
||||
import tests_utils as op_gen_tests
|
||||
from decomp_vjp_gen import extend_compat_info, filter_compat_info
|
||||
from parse_utils import to_named_dict
|
||||
from type_mapping import output_type_map
|
||||
|
||||
# import from paddle/fluid/pir/dialect/op_generator/api_gen.py
|
||||
sys.path.insert(
|
||||
0,
|
||||
str(
|
||||
pathlib.Path(__file__).resolve().parents[2] / 'pir/dialect/op_generator'
|
||||
),
|
||||
)
|
||||
|
||||
from decomp_interface_gen_op_list import (
|
||||
decomp_ops_contain_unused_output,
|
||||
decomp_rule_interface_implementation_gen_op_list,
|
||||
)
|
||||
from op_gen import attr_types_map, to_pascal_case
|
||||
|
||||
# fmt: on
|
||||
|
||||
|
||||
def load(path: pathlib.Path):
|
||||
"""Load config from yaml file.
|
||||
|
||||
Args:
|
||||
path (pathlib.Path): The path of yaml config.
|
||||
|
||||
Returns:
|
||||
dict: The config info.
|
||||
|
||||
"""
|
||||
with open(path, 'rt') as f:
|
||||
return yaml.safe_load(f)
|
||||
|
||||
|
||||
def render(src_dir: pathlib.Path, dst_dir: pathlib.Path, *args, **kwargs):
|
||||
"""Render and save Jinja2 templates to the destination directory.
|
||||
|
||||
Args:
|
||||
src_dir (pathlib.Path): The source directory containing Jinja2 templates.
|
||||
dst_dir (pathlib.Path): The destination directory to save rendered files.
|
||||
*args: Additional positional arguments passed to the `render` function.
|
||||
**kwargs: Additional keyword arguments passed to the `render` function.
|
||||
|
||||
Returns:
|
||||
None
|
||||
"""
|
||||
env = jinja2.Environment(
|
||||
loader=jinja2.FileSystemLoader(src_dir),
|
||||
keep_trailing_newline=True,
|
||||
trim_blocks=True,
|
||||
lstrip_blocks=True,
|
||||
undefined=jinja2.StrictUndefined,
|
||||
extensions=['jinja2.ext.do'],
|
||||
)
|
||||
env.filters.update(
|
||||
{
|
||||
'to_paddle_attr_type': op_gen_filters.to_paddle_attr_type,
|
||||
'to_paddle_input_type': op_gen_filters.to_paddle_input_type,
|
||||
'to_paddle_output_type': op_gen_filters.to_paddle_output_type,
|
||||
'trip_intermediate': op_gen_filters.filter_intermediate,
|
||||
}
|
||||
)
|
||||
env.tests.update(
|
||||
{
|
||||
'scalar': op_gen_tests.is_scalar,
|
||||
'intarray': op_gen_tests.is_intarray,
|
||||
'datatype': op_gen_tests.is_datatype,
|
||||
'exist_mutable_attribute': op_gen_tests.exist_mutable_attribute,
|
||||
'mutable_attribute': op_gen_tests.is_mutable_attribute,
|
||||
'only_composite_op': op_gen_tests.is_only_composite_op,
|
||||
}
|
||||
)
|
||||
|
||||
decomp_temp = "decomp/generated_decomp.j2"
|
||||
save(
|
||||
env.get_template(decomp_temp).render(*args, **kwargs),
|
||||
pathlib.Path(dst_dir),
|
||||
)
|
||||
|
||||
|
||||
def save(content: str, path: pathlib.Path):
|
||||
"""Saves the given string contents to a file in the specified path.
|
||||
|
||||
Args:
|
||||
content (str): The string content that needs to be saved.
|
||||
path (pathlib.Path): The path to save the file, a Pathlib path object
|
||||
|
||||
Returns:
|
||||
None
|
||||
"""
|
||||
path.parent.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
dst_content = ''
|
||||
if path.is_file():
|
||||
with open(path, 'r') as f:
|
||||
dst_content = f.read()
|
||||
|
||||
if (
|
||||
hashlib.md5(content.encode("UTF-8")).hexdigest()
|
||||
!= hashlib.md5(dst_content.encode("UTF-8")).hexdigest()
|
||||
):
|
||||
with open(path, 'w') as f:
|
||||
f.write(content)
|
||||
|
||||
|
||||
def process_optional_output_info(apis):
|
||||
for api in apis:
|
||||
inputs_dict = to_named_dict(api['inputs'])
|
||||
for output in api['outputs']:
|
||||
if (
|
||||
api.get("inplace", None)
|
||||
and output['name'] in api['inplace']
|
||||
and inputs_dict[api['inplace'][output['name']]]['optional']
|
||||
):
|
||||
output['optional'] = True
|
||||
else:
|
||||
output['optional'] = False
|
||||
|
||||
|
||||
def gen(
|
||||
fwd_path: pathlib.Path,
|
||||
compat_path: pathlib.Path,
|
||||
fwd_pd_op_path: pathlib.Path,
|
||||
templates_dir: pathlib.Path,
|
||||
destination_dir: pathlib.Path,
|
||||
):
|
||||
"""The `gen` load jinja2 templates and relative config info, use jinja2
|
||||
templating engine to generate c++ code, and save the code into destination.
|
||||
|
||||
Args:
|
||||
prim_path (pathlib.Path): The YAML file path of the primitive API.
|
||||
fwd_path (pathlib.Path): The YAML file path of the forward API.
|
||||
rev_path (pathlib.Path): The YAML file path of the backward API.
|
||||
compat_path: (pathlib.Path): The YAML file path of the ops compat.
|
||||
fwd_pd_op_path (pathlib.Path): The YAML file path of the ir forward API.
|
||||
rev_pd_op_path (pathlib.Path): The YAML file path of the ir backward API.
|
||||
templates_dir (pathlib.Path): The directory of the templates.
|
||||
destination_dir (pathlib.Path): The Directory of the generated file.
|
||||
|
||||
Returns:
|
||||
None
|
||||
"""
|
||||
(
|
||||
fwds,
|
||||
compats,
|
||||
ir_fwds,
|
||||
) = (
|
||||
load(fwd_path),
|
||||
load(compat_path),
|
||||
load(fwd_pd_op_path),
|
||||
)
|
||||
filter_compat_info(compats)
|
||||
apis = [
|
||||
{**api, **{'class_name': to_pascal_case(api["name"]) + "Op"}}
|
||||
for api in fwds + ir_fwds
|
||||
]
|
||||
|
||||
apis = extend_compat_info(apis, compats)
|
||||
|
||||
process_optional_output_info(apis)
|
||||
|
||||
for item in apis:
|
||||
for attr_item in item["attrs"]:
|
||||
if attr_item["typename"] not in attr_types_map.keys():
|
||||
raise TypeError
|
||||
attr_item["mapped_type"] = attr_types_map[attr_item["typename"]]
|
||||
for out_item in item["outputs"]:
|
||||
if out_item["typename"] not in output_type_map.keys():
|
||||
name = out_item["typename"]
|
||||
raise TypeError(f"err type {name}")
|
||||
if out_item["optional"]:
|
||||
out_item["mapped_type"] = (
|
||||
"paddle::optional<"
|
||||
+ output_type_map[out_item["typename"]]
|
||||
+ ">"
|
||||
)
|
||||
else:
|
||||
out_item["mapped_type"] = output_type_map[out_item["typename"]]
|
||||
render(
|
||||
templates_dir,
|
||||
destination_dir,
|
||||
apis=apis,
|
||||
decomp_white_list=decomp_rule_interface_implementation_gen_op_list,
|
||||
decomp_ops_list_contain_unused_output=decomp_ops_contain_unused_output,
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = argparse.ArgumentParser(
|
||||
description='Generate Static Primitive API'
|
||||
)
|
||||
parser.add_argument(
|
||||
'--fwd_path', type=str, help='The parsed ops yaml file.'
|
||||
)
|
||||
parser.add_argument(
|
||||
'--compat_path',
|
||||
type=str,
|
||||
help='The parsed ops compat yaml file.',
|
||||
)
|
||||
parser.add_argument(
|
||||
'--fwd_pd_op_path',
|
||||
type=str,
|
||||
help='The ir forward ops parsed yaml file.',
|
||||
)
|
||||
parser.add_argument(
|
||||
'--templates_dir',
|
||||
type=str,
|
||||
help='JinJa2 templates base directory.',
|
||||
)
|
||||
parser.add_argument(
|
||||
'--destination_dir',
|
||||
type=str,
|
||||
help='Destination base directory for generated file.',
|
||||
)
|
||||
args = parser.parse_args()
|
||||
|
||||
gen(
|
||||
pathlib.Path(args.fwd_path),
|
||||
pathlib.Path(args.compat_path),
|
||||
pathlib.Path(args.fwd_pd_op_path),
|
||||
pathlib.Path(args.templates_dir),
|
||||
pathlib.Path(args.destination_dir),
|
||||
)
|
||||
@@ -0,0 +1,684 @@
|
||||
# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import argparse
|
||||
import hashlib
|
||||
import pathlib
|
||||
import sys
|
||||
|
||||
import jinja2
|
||||
import yaml
|
||||
|
||||
# import from paddle/fluid/operators/generator
|
||||
sys.path.append(
|
||||
str(pathlib.Path(__file__).resolve().parents[2] / 'operators/generator')
|
||||
)
|
||||
import filters as op_gen_filters
|
||||
import tests_utils as op_gen_tests
|
||||
from parse_utils import to_named_dict
|
||||
|
||||
# import from paddle/fluid/pir/dialect/op_generator/api_gen.py
|
||||
sys.path.append(
|
||||
str(
|
||||
pathlib.Path(__file__).resolve().parents[2] / 'pir/dialect/op_generator'
|
||||
)
|
||||
)
|
||||
|
||||
from decomp_interface_gen_op_list import (
|
||||
decomp_vjp_interface_implementation_gen_op_list,
|
||||
)
|
||||
from gen_utils import attr_types_map, to_pascal_case
|
||||
from type_mapping import output_type_map
|
||||
|
||||
# fmt: on
|
||||
|
||||
|
||||
VJPS_BLACK_LIST = [
|
||||
'reshape_grad',
|
||||
'add_n_grad',
|
||||
'fused_attention_grad',
|
||||
]
|
||||
|
||||
BACKENDS_BLACK_LIST = [
|
||||
'accuracy_check',
|
||||
'copy_to',
|
||||
'add_n_grad',
|
||||
"allclose",
|
||||
"isclose",
|
||||
"send_v2",
|
||||
"assert",
|
||||
"embedding_sparse_grad",
|
||||
"embedding_grad",
|
||||
"full",
|
||||
"partial_send",
|
||||
"push_dense",
|
||||
"comm_init_all",
|
||||
]
|
||||
|
||||
# which is prim vjp
|
||||
# op only has backward decomp_vjp rules
|
||||
PRIM_VJP = [
|
||||
'abs_grad',
|
||||
'add_grad',
|
||||
'amax_grad',
|
||||
'amin_grad',
|
||||
'angle_grad',
|
||||
'argsort_grad',
|
||||
'assign_grad',
|
||||
'atan_grad',
|
||||
'atan2_grad',
|
||||
'cast_grad',
|
||||
'ceil_grad',
|
||||
'concat_grad',
|
||||
'cos_grad',
|
||||
'cumprod_grad',
|
||||
'cumsum_grad',
|
||||
'divide_grad',
|
||||
'dot_grad',
|
||||
'elementwise_pow_grad',
|
||||
'erf_grad',
|
||||
'exp_grad',
|
||||
'expm1_grad',
|
||||
'expand_grad',
|
||||
'floor_grad',
|
||||
'fmax_grad',
|
||||
'fmin_grad',
|
||||
'gather_grad',
|
||||
'gather_nd_grad',
|
||||
'kron_grad',
|
||||
'kthvalue_grad',
|
||||
'log_grad',
|
||||
'logcumsumexp_grad',
|
||||
'logsumexp_grad',
|
||||
'masked_select_grad',
|
||||
'matmul_grad',
|
||||
'linear_v2_grad',
|
||||
'max_grad',
|
||||
'maximum_grad',
|
||||
'minimum_grad',
|
||||
'multiply_grad',
|
||||
'pad_grad',
|
||||
'pow_grad',
|
||||
'prod_grad',
|
||||
'put_along_axis_grad',
|
||||
'reduce_as_grad',
|
||||
'reshape_grad',
|
||||
'roll_grad',
|
||||
'rsqrt_grad',
|
||||
'scale_grad',
|
||||
"div_scale_grad",
|
||||
'scatter_grad',
|
||||
'scatter_nd_add_grad',
|
||||
'sigmoid_grad',
|
||||
'sin_grad',
|
||||
'slice_grad',
|
||||
'squeeze_grad',
|
||||
'split_grad',
|
||||
'sqrt_grad',
|
||||
'square_grad',
|
||||
'subtract_grad',
|
||||
'sum_grad',
|
||||
'take_along_axis_grad',
|
||||
'tanh_grad',
|
||||
'tile_grad',
|
||||
'topk_grad',
|
||||
'transpose_grad',
|
||||
'trunc_grad',
|
||||
'unsqueeze_grad',
|
||||
'where_grad',
|
||||
]
|
||||
|
||||
# which op is custom_vjp?
|
||||
# op has forward decomp_rules and backward decomp_vjp rules
|
||||
CUSTOM_VJP = [
|
||||
'batch_norm_grad',
|
||||
'bce_loss_grad',
|
||||
'dropout_grad',
|
||||
'gelu_grad',
|
||||
'group_norm_grad',
|
||||
'hardsigmoid_grad',
|
||||
'hardswish_grad',
|
||||
'instance_norm_grad',
|
||||
'layer_norm_grad',
|
||||
'leaky_relu_grad',
|
||||
'mean_grad',
|
||||
'relu_grad',
|
||||
'relu6_grad',
|
||||
'silu_grad',
|
||||
'softmax_grad',
|
||||
'softsign_grad',
|
||||
'stack_grad',
|
||||
'swish_grad',
|
||||
'elu_grad',
|
||||
'swiglu_grad',
|
||||
'p_norm_grad',
|
||||
'masked_fill_grad',
|
||||
'index_put_grad',
|
||||
'index_add_grad',
|
||||
"var_grad",
|
||||
] # custom vjp list of composite op
|
||||
|
||||
VJP_COMPS = PRIM_VJP + CUSTOM_VJP
|
||||
|
||||
|
||||
def load(path: pathlib.Path):
|
||||
"""Load config from yaml file.
|
||||
|
||||
Args:
|
||||
path (pathlib.Path): The path of yaml config.
|
||||
|
||||
Returns:
|
||||
dict: The config info.
|
||||
|
||||
"""
|
||||
with open(path, 'rt') as f:
|
||||
return yaml.safe_load(f)
|
||||
|
||||
|
||||
def render(src_dir: pathlib.Path, dst_dir: pathlib.Path, *args, **kwargs):
|
||||
"""Render and save Jinja2 templates to the destination directory.
|
||||
|
||||
Args:
|
||||
src_dir (pathlib.Path): The source directory containing Jinja2 templates.
|
||||
dst_dir (pathlib.Path): The destination directory to save rendered files.
|
||||
*args: Additional positional arguments passed to the `render` function.
|
||||
**kwargs: Additional keyword arguments passed to the `render` function.
|
||||
|
||||
Returns:
|
||||
None
|
||||
"""
|
||||
env = jinja2.Environment(
|
||||
loader=jinja2.FileSystemLoader(src_dir),
|
||||
keep_trailing_newline=True,
|
||||
trim_blocks=True,
|
||||
lstrip_blocks=True,
|
||||
undefined=jinja2.StrictUndefined,
|
||||
extensions=['jinja2.ext.do'],
|
||||
)
|
||||
env.filters.update(
|
||||
{
|
||||
'to_paddle_attr_type': op_gen_filters.to_paddle_attr_type,
|
||||
'to_paddle_input_type': op_gen_filters.to_paddle_input_type,
|
||||
'to_paddle_output_type': op_gen_filters.to_paddle_output_type,
|
||||
'trip_intermediate': op_gen_filters.filter_intermediate,
|
||||
}
|
||||
)
|
||||
env.tests.update(
|
||||
{
|
||||
'scalar': op_gen_tests.is_scalar,
|
||||
'intarray': op_gen_tests.is_intarray,
|
||||
'datatype': op_gen_tests.is_datatype,
|
||||
'exist_mutable_attribute': op_gen_tests.exist_mutable_attribute,
|
||||
'mutable_attribute': op_gen_tests.is_mutable_attribute,
|
||||
'only_composite_op': op_gen_tests.is_only_composite_op,
|
||||
}
|
||||
)
|
||||
for tpl in env.list_templates(
|
||||
filter_func=lambda name: ".h" in name or ".cc" in name
|
||||
):
|
||||
save(
|
||||
env.get_template(tpl).render(*args, **kwargs),
|
||||
dst_dir / tpl.rstrip('.j2'),
|
||||
)
|
||||
|
||||
|
||||
def render_decomp_vjp(
|
||||
src_dir: pathlib.Path, dst_dir: pathlib.Path, *args, **kwargs
|
||||
):
|
||||
"""Render and save Jinja2 templates to the destination directory.
|
||||
|
||||
Args:
|
||||
src_dir (pathlib.Path): The source directory containing Jinja2 templates.
|
||||
dst_dir (pathlib.Path): The destination directory to save rendered files.
|
||||
*args: Additional positional arguments passed to the `render` function.
|
||||
**kwargs: Additional keyword arguments passed to the `render` function.
|
||||
|
||||
Returns:
|
||||
None
|
||||
"""
|
||||
env = jinja2.Environment(
|
||||
loader=jinja2.FileSystemLoader(src_dir),
|
||||
keep_trailing_newline=True,
|
||||
trim_blocks=True,
|
||||
lstrip_blocks=True,
|
||||
undefined=jinja2.StrictUndefined,
|
||||
extensions=['jinja2.ext.do'],
|
||||
)
|
||||
env.filters.update(
|
||||
{
|
||||
'to_paddle_attr_type': op_gen_filters.to_paddle_attr_type,
|
||||
'to_paddle_input_type': op_gen_filters.to_paddle_input_type,
|
||||
'to_paddle_output_type': op_gen_filters.to_paddle_output_type,
|
||||
'trip_intermediate': op_gen_filters.filter_intermediate,
|
||||
}
|
||||
)
|
||||
env.tests.update(
|
||||
{
|
||||
'scalar': op_gen_tests.is_scalar,
|
||||
'intarray': op_gen_tests.is_intarray,
|
||||
'datatype': op_gen_tests.is_datatype,
|
||||
'exist_mutable_attribute': op_gen_tests.exist_mutable_attribute,
|
||||
'mutable_attribute': op_gen_tests.is_mutable_attribute,
|
||||
'only_composite_op': op_gen_tests.is_only_composite_op,
|
||||
}
|
||||
)
|
||||
|
||||
decomp_temp = "decomp/generated_decomp_vjp.j2"
|
||||
save(
|
||||
env.get_template(decomp_temp).render(*args, **kwargs),
|
||||
pathlib.Path(dst_dir),
|
||||
)
|
||||
|
||||
|
||||
def save(content: str, path: pathlib.Path):
|
||||
"""Saves the given string contents to a file in the specified path.
|
||||
|
||||
Args:
|
||||
content (str): The string content that needs to be saved.
|
||||
path (pathlib.Path): The path to save the file, a Pathlib path object
|
||||
|
||||
Returns:
|
||||
None
|
||||
"""
|
||||
path.parent.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
dst_content = ''
|
||||
if path.is_file():
|
||||
with open(path, 'r') as f:
|
||||
dst_content = f.read()
|
||||
|
||||
if (
|
||||
hashlib.md5(content.encode("UTF-8")).hexdigest()
|
||||
!= hashlib.md5(dst_content.encode("UTF-8")).hexdigest()
|
||||
):
|
||||
with open(path, 'w') as f:
|
||||
f.write(content)
|
||||
print(f"Generate source file {path}")
|
||||
|
||||
|
||||
def get_inplace_api(apis):
|
||||
inplace_apis = []
|
||||
for api in apis:
|
||||
if (
|
||||
'inplace' in api
|
||||
and api['inplace'] is not None
|
||||
and not api['name'].endswith('_')
|
||||
):
|
||||
inplace_api = api.copy()
|
||||
inplace_api['name'] = api['name'] + '_'
|
||||
inplace_apis.append(inplace_api)
|
||||
return inplace_apis
|
||||
|
||||
|
||||
def filter_compat_info(items):
|
||||
for item in items:
|
||||
item['op'] = item['op'].split('(')[0].strip()
|
||||
if 'backward' in item:
|
||||
item_backwards = item['backward'].split(',')
|
||||
for idx, item_backward in enumerate(item_backwards):
|
||||
item_backward = item_backward.split('(')[0].strip()
|
||||
item_backwards[idx] = item_backward
|
||||
item['backward'] = (
|
||||
','.join(item_backwards)
|
||||
if len(item_backwards) > 0
|
||||
else item_backwards[0]
|
||||
)
|
||||
|
||||
|
||||
def extend_compat_info(apis, compats):
|
||||
for api in apis:
|
||||
if api['name'].endswith('sp') or api['name'].endswith('sp_'):
|
||||
continue
|
||||
attrs = api["attrs"]
|
||||
for attr in attrs:
|
||||
if op_gen_tests.is_scalar(
|
||||
attr['typename']
|
||||
) or op_gen_tests.is_intarray(attr['typename']):
|
||||
attr["support_tensor"] = False
|
||||
apis_dict = to_named_dict(apis)
|
||||
for compat_item in compats:
|
||||
fwd_op_name = compat_item["op"]
|
||||
if fwd_op_name not in apis_dict:
|
||||
continue
|
||||
fwd_api = apis_dict[fwd_op_name]
|
||||
backward_op_names = []
|
||||
while fwd_op_name is not None and fwd_op_name in apis_dict:
|
||||
backward_op_names.append(apis_dict[fwd_op_name]['backward'])
|
||||
fwd_op_name = apis_dict[fwd_op_name]['backward']
|
||||
backward_apis = []
|
||||
for backward_op_name in backward_op_names:
|
||||
if backward_op_name in apis_dict:
|
||||
backward_apis.append(apis_dict[backward_op_name])
|
||||
support_tensor_attrs_names = []
|
||||
compat_attrs_data_type = {}
|
||||
if 'scalar' in compat_item and compat_item['op'] != "pow":
|
||||
for attr_name, attr_info in compat_item['scalar'].items():
|
||||
if (
|
||||
'support_tensor' in attr_info
|
||||
and attr_info['support_tensor'] is True
|
||||
or 'tensor_name' in attr_info
|
||||
):
|
||||
support_tensor_attrs_names.append(attr_name)
|
||||
if 'data_type' in attr_info:
|
||||
compat_attrs_data_type.update(
|
||||
{attr_name: attr_info['data_type']}
|
||||
)
|
||||
if 'int_array' in compat_item:
|
||||
for attr_name, attr_info in compat_item['int_array'].items():
|
||||
if (
|
||||
'support_tensor' in attr_info
|
||||
and attr_info['support_tensor'] is True
|
||||
or 'tensor_name' in attr_info
|
||||
or 'tensors_name' in attr_info
|
||||
):
|
||||
support_tensor_attrs_names.append(attr_name)
|
||||
if len(support_tensor_attrs_names) > 0:
|
||||
for api in [fwd_api, *backward_apis]:
|
||||
attrs = api["attrs"]
|
||||
for attr in attrs:
|
||||
if attr['name'] in support_tensor_attrs_names:
|
||||
attr['support_tensor'] = True
|
||||
for api in [fwd_api, *backward_apis]:
|
||||
attrs = api["attrs"]
|
||||
for attr in attrs:
|
||||
if attr['name'] in compat_attrs_data_type:
|
||||
attr['data_type'] = compat_attrs_data_type[attr['name']]
|
||||
return apis
|
||||
|
||||
|
||||
def process_backward_invoke_info(apis):
|
||||
apis_dict = to_named_dict(apis)
|
||||
for api in apis:
|
||||
if api['is_fwd']:
|
||||
continue
|
||||
if 'invoke' in api and api['invoke']['func'] in apis_dict:
|
||||
args = api['invoke']['args'].split(',')
|
||||
args = [arg.strip() for arg in args]
|
||||
attrs_dict = to_named_dict(api['attrs'])
|
||||
inputs_dict = to_named_dict(api['inputs'])
|
||||
arg_inputs = []
|
||||
arg_attrs = []
|
||||
for arg in args:
|
||||
if arg in inputs_dict:
|
||||
arg_inputs.append(arg)
|
||||
elif arg in attrs_dict and attrs_dict[arg].get(
|
||||
"support_tensor", False
|
||||
):
|
||||
arg_inputs.append(arg + '_')
|
||||
else:
|
||||
arg_attrs.append(arg)
|
||||
args = arg_inputs + arg_attrs
|
||||
api['invoke']['args'] = ', '.join(args)
|
||||
|
||||
|
||||
def process_optional_inplace_output_info(apis):
|
||||
for api in apis:
|
||||
inputs_dict = to_named_dict(api['inputs'])
|
||||
for output in api['outputs']:
|
||||
if not api['is_fwd']:
|
||||
return
|
||||
else:
|
||||
if (
|
||||
api.get("inplace", None)
|
||||
and output['name'] in api['inplace']
|
||||
and inputs_dict[api['inplace'][output['name']]]['optional']
|
||||
):
|
||||
output['optional'] = True
|
||||
else:
|
||||
output['optional'] = False
|
||||
|
||||
|
||||
def update_apis(op_yaml_items, update_yaml_file):
|
||||
with open(update_yaml_file, "r") as f:
|
||||
update_apis = yaml.safe_load(f)
|
||||
for i in range(len(op_yaml_items)):
|
||||
for update_api in update_apis:
|
||||
if op_yaml_items[i]['name'] == update_api['name']:
|
||||
op_yaml_items[i] = update_api
|
||||
break
|
||||
|
||||
|
||||
def gen(
|
||||
prim_path: pathlib.Path,
|
||||
fwd_path: pathlib.Path,
|
||||
rev_path: pathlib.Path,
|
||||
compat_path: pathlib.Path,
|
||||
fwd_pd_op_path: pathlib.Path,
|
||||
update_fwd_pd_op_path: pathlib.Path,
|
||||
rev_pd_op_path: pathlib.Path,
|
||||
fused_op_path: pathlib.Path,
|
||||
fused_rev_path: pathlib.Path,
|
||||
sparse_op_path: pathlib.Path,
|
||||
sparse_rev_op_path: pathlib.Path,
|
||||
templates_dir: pathlib.Path,
|
||||
destination_dir: pathlib.Path,
|
||||
decomp_vjp_destination_dir: pathlib.Path,
|
||||
):
|
||||
"""The `gen` load jinja2 templates and relative config info, use jinja2
|
||||
templating engine to generate c++ code, and save the code into destination.
|
||||
|
||||
Args:
|
||||
prim_path (pathlib.Path): The YAML file path of the primitive API.
|
||||
fwd_path (pathlib.Path): The YAML file path of the forward API.
|
||||
rev_path (pathlib.Path): The YAML file path of the backward API.
|
||||
compat_path: (pathlib.Path): The YAML file path of the ops compat.
|
||||
fwd_pd_op_path (pathlib.Path): The YAML file path of the ir forward API.
|
||||
update_fwd_pd_op_path (pathlib.Path): The YAML file path of the ir update_ops.
|
||||
rev_pd_op_path (pathlib.Path): The YAML file path of the ir backward API.
|
||||
fused_op_path (pathlib.Path): The YAML file path of the fused API.
|
||||
fused_rev_path (pathlib.Path): The YAML file path of the fused backward API.
|
||||
sparse_op_path (pathlib.Path): The YAML file path of the sparse API.
|
||||
sparse_rev_op_path (pathlib.Path): The YAML file path of the sparse backward API.
|
||||
templates_dir (pathlib.Path): The directory of the templates.
|
||||
destination_dir (pathlib.Path): The Directory of the generated file.
|
||||
|
||||
Returns:
|
||||
None
|
||||
"""
|
||||
(
|
||||
prims,
|
||||
fwds,
|
||||
revs,
|
||||
compats,
|
||||
ir_fwds,
|
||||
ir_revs,
|
||||
ir_update_fwds,
|
||||
fused_fwds,
|
||||
fused_revs,
|
||||
sparse_fwds,
|
||||
sparse_revs,
|
||||
) = (
|
||||
load(prim_path),
|
||||
load(fwd_path),
|
||||
load(rev_path),
|
||||
load(compat_path),
|
||||
load(fwd_pd_op_path),
|
||||
load(rev_pd_op_path),
|
||||
load(update_fwd_pd_op_path),
|
||||
load(fused_op_path),
|
||||
load(fused_rev_path),
|
||||
load(sparse_op_path),
|
||||
load(sparse_rev_op_path),
|
||||
)
|
||||
filter_compat_info(compats)
|
||||
for sparse_op in sparse_fwds:
|
||||
if sparse_op['name'].endswith("_"):
|
||||
sparse_op['name'] += 'sp_'
|
||||
if sparse_op['backward'] is not None:
|
||||
sparse_op['backward'] += '_sp'
|
||||
else:
|
||||
sparse_op['name'] += '_sp'
|
||||
if sparse_op['backward'] is not None:
|
||||
sparse_op['backward'] += '_sp'
|
||||
fwd_apis = fwds + ir_fwds + ir_update_fwds + fused_fwds + sparse_fwds
|
||||
|
||||
for sparse_op in sparse_revs:
|
||||
sparse_op['name'] += '_sp'
|
||||
if sparse_op['forward']['name'].endswith("_"):
|
||||
sparse_op['forward']['name'] += 'sp_'
|
||||
if sparse_op.get('invoke') is not None:
|
||||
sparse_op['invoke']['func'] += 'sp_'
|
||||
else:
|
||||
sparse_op['forward']['name'] += '_sp'
|
||||
if sparse_op.get('invoke') is not None:
|
||||
sparse_op['invoke']['func'] += '_sp'
|
||||
apis = [{**api, **{'is_fwd': True}} for api in fwd_apis]
|
||||
apis = apis + [
|
||||
{**api, **{'is_fwd': False}}
|
||||
for api in revs + ir_revs + fused_revs + sparse_revs
|
||||
]
|
||||
apis = [
|
||||
(
|
||||
{**api, **{'is_prim': True}}
|
||||
if api['name'] in prims
|
||||
else {**api, **{'is_prim': False}}
|
||||
)
|
||||
for api in apis
|
||||
]
|
||||
|
||||
apis = extend_compat_info(apis, compats)
|
||||
apis = apis + get_inplace_api(apis)
|
||||
process_backward_invoke_info(apis)
|
||||
process_optional_inplace_output_info(apis)
|
||||
|
||||
apis = [
|
||||
{**api, **{'class_name': to_pascal_case(api["name"]) + "Op"}}
|
||||
for api in apis
|
||||
]
|
||||
|
||||
for item in apis:
|
||||
for attr_item in item["attrs"]:
|
||||
if attr_item["typename"] not in attr_types_map.keys():
|
||||
raise TypeError
|
||||
attr_item["mapped_type"] = attr_types_map[attr_item["typename"]]
|
||||
for out_item in item["outputs"]:
|
||||
if out_item["typename"] not in output_type_map.keys():
|
||||
name = out_item["typename"]
|
||||
raise TypeError(f"err type {name}")
|
||||
if out_item["optional"]:
|
||||
out_item["mapped_type"] = (
|
||||
"paddle::optional<"
|
||||
+ output_type_map[out_item["typename"]]
|
||||
+ ">"
|
||||
)
|
||||
else:
|
||||
out_item["mapped_type"] = output_type_map[out_item["typename"]]
|
||||
|
||||
render(
|
||||
templates_dir,
|
||||
destination_dir,
|
||||
apis=apis,
|
||||
backend_black_list=BACKENDS_BLACK_LIST,
|
||||
vjp_black_list=VJPS_BLACK_LIST,
|
||||
vjp_comp_white_list=VJP_COMPS,
|
||||
)
|
||||
render_decomp_vjp(
|
||||
templates_dir,
|
||||
decomp_vjp_destination_dir,
|
||||
apis=apis,
|
||||
backend_black_list=BACKENDS_BLACK_LIST,
|
||||
vjp_black_list=VJPS_BLACK_LIST,
|
||||
vjp_comp_white_list=VJP_COMPS,
|
||||
decomp_vjp_white_list=decomp_vjp_interface_implementation_gen_op_list,
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = argparse.ArgumentParser(
|
||||
description='Generate Static Primitive API'
|
||||
)
|
||||
parser.add_argument(
|
||||
'--prim_path',
|
||||
type=str,
|
||||
help='The primitive API yaml file.',
|
||||
)
|
||||
parser.add_argument(
|
||||
'--fwd_path', type=str, help='The parsed ops yaml file.'
|
||||
)
|
||||
parser.add_argument(
|
||||
'--rev_path', type=str, help='The parsed ops yaml file.'
|
||||
)
|
||||
parser.add_argument(
|
||||
'--compat_path',
|
||||
type=str,
|
||||
help='The parsed ops compat yaml file.',
|
||||
)
|
||||
parser.add_argument(
|
||||
'--fwd_pd_op_path',
|
||||
type=str,
|
||||
help='The ir forward ops parsed yaml file.',
|
||||
)
|
||||
parser.add_argument(
|
||||
'--update_fwd_pd_op_path',
|
||||
type=str,
|
||||
help='The ir update forward ops parsed yaml file.',
|
||||
)
|
||||
parser.add_argument(
|
||||
'--rev_pd_op_path',
|
||||
type=str,
|
||||
help='The ir backward ops parsed yaml file.',
|
||||
)
|
||||
parser.add_argument(
|
||||
'--fused_op_path',
|
||||
type=str,
|
||||
help='The parsed fused forward ops yaml file.',
|
||||
)
|
||||
parser.add_argument(
|
||||
'--fused_rev_op_path',
|
||||
type=str,
|
||||
help='The parsed fused backward ops yaml file.',
|
||||
)
|
||||
parser.add_argument(
|
||||
'--sparse_op_path',
|
||||
type=str,
|
||||
help='The parsed sparse forward ops yaml file.',
|
||||
)
|
||||
parser.add_argument(
|
||||
'--sparse_rev_op_path',
|
||||
type=str,
|
||||
help='The parsed sparse backward ops yaml file.',
|
||||
)
|
||||
parser.add_argument(
|
||||
'--templates_dir',
|
||||
type=str,
|
||||
help='JinJa2 templates base directory.',
|
||||
)
|
||||
parser.add_argument(
|
||||
'--destination_dir',
|
||||
type=str,
|
||||
help='Destination base directory for generated file.',
|
||||
)
|
||||
parser.add_argument(
|
||||
'--decomp_vjp_destination_dir',
|
||||
type=str,
|
||||
help='Destination base directory for generated file.',
|
||||
)
|
||||
args = parser.parse_args()
|
||||
|
||||
gen(
|
||||
pathlib.Path(args.prim_path),
|
||||
pathlib.Path(args.fwd_path),
|
||||
pathlib.Path(args.rev_path),
|
||||
pathlib.Path(args.compat_path),
|
||||
pathlib.Path(args.fwd_pd_op_path),
|
||||
pathlib.Path(args.update_fwd_pd_op_path),
|
||||
pathlib.Path(args.rev_pd_op_path),
|
||||
pathlib.Path(args.fused_op_path),
|
||||
pathlib.Path(args.fused_rev_op_path),
|
||||
pathlib.Path(args.sparse_op_path),
|
||||
pathlib.Path(args.sparse_rev_op_path),
|
||||
pathlib.Path(args.templates_dir),
|
||||
pathlib.Path(args.destination_dir),
|
||||
pathlib.Path(args.decomp_vjp_destination_dir),
|
||||
)
|
||||
@@ -0,0 +1,38 @@
|
||||
{% import "common.j2" as common %}
|
||||
// Auto Generated, DO NOT EDIT!
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "paddle/phi/api/include/tensor.h"
|
||||
#include "paddle/utils/optional.h"
|
||||
|
||||
|
||||
namespace paddle {
|
||||
namespace primitive {
|
||||
namespace backend {
|
||||
|
||||
using Tensor = paddle::Tensor;
|
||||
using Scalar = phi::Scalar;
|
||||
using IntArray = paddle::experimental::IntArray;
|
||||
using DataType = phi::DataType;
|
||||
|
||||
{% for api in apis %}
|
||||
{%- if api is only_composite_op or "infer_meta" not in api and "composite" not in api and "invoke" not in api -%}{#- render nothing -#}
|
||||
{%- elif api.name not in backend_black_list -%}
|
||||
{%- if 'invoke' not in api or 'invoke' in api and api.is_fwd -%}
|
||||
{% if api.attrs is exist_mutable_attribute %}
|
||||
{{common.sig(api.name, api.inputs, api.outputs|trip_intermediate , api.attrs, True, True)}};
|
||||
|
||||
{% endif %}
|
||||
{{common.sig(api.name, api.inputs, api.outputs|trip_intermediate , api.attrs, False, True)}};
|
||||
|
||||
{% endif %}
|
||||
{% else %}{#- render nothing -#}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
} // namespace backend
|
||||
} // namespace primitive
|
||||
} // namespace paddle
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
{% import "common.j2" as common %}
|
||||
// Auto Generated, DO NOT EDIT!
|
||||
|
||||
#include "paddle/fluid/eager/api/all.h"
|
||||
#include "paddle/fluid/eager/api/generated/eager_generated/forwards/dygraph_functions.h"
|
||||
#include "paddle/fluid/eager/api/manual/eager_manual/dygraph_forward_api.h"
|
||||
#include "paddle/fluid/primitive/backend/generated/generated_backend.h"
|
||||
|
||||
namespace paddle {
|
||||
namespace primitive {
|
||||
namespace backend {
|
||||
|
||||
{%- macro args(inputs, attrs) -%} {#- Arguments are variable pass into method -#}
|
||||
{{common.sequence('', '', ', ', inputs)}}
|
||||
{%- if attrs|length > 0 -%} {{", "}} {%- endif -%} {#- append comma between
|
||||
nputs and attrs -#}
|
||||
{{common.sequence('', '', ', ', attrs)}}
|
||||
{%- endmacro -%}
|
||||
|
||||
{%- macro sig(name, inputs, attrs, outputs) -%}
|
||||
template <>
|
||||
{{common.ret(outputs)}} {{name}}<Tensor>({{common.params(inputs, attrs, False)}})
|
||||
{%- endmacro -%}
|
||||
|
||||
{% macro body(name, inputs, attrs, outputs) %}
|
||||
{%- set input_names = [] -%}
|
||||
{%- for i in inputs -%} {%- do input_names.append(i.name) -%} {%-endfor-%}
|
||||
{%- set attr_names = [] -%}
|
||||
{%- for i in attrs -%} {%- do attr_names.append(i.name) -%} {%-endfor-%}
|
||||
{% filter indent(2, True) %}
|
||||
VLOG(4) << "Eager Prim API {{name}}_ad_func call";
|
||||
return ::{{name}}_ad_func({{common.args(input_names, attr_names)}});
|
||||
{% endfilter %}
|
||||
{% endmacro %}
|
||||
|
||||
|
||||
{% for api in apis %}
|
||||
{%- if api.is_prim and api.name not in backend_black_list and api.name[-1] != '_' -%}
|
||||
{{sig(api.name, api.inputs, api.attrs, api.outputs | trip_intermediate)}} {
|
||||
{{body(api.name, api.inputs, api.attrs, api.outputs | trip_intermediate)}}
|
||||
}
|
||||
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
|
||||
} // namespace backend
|
||||
} // namespace primitive
|
||||
} // namespace paddle
|
||||
+167
@@ -0,0 +1,167 @@
|
||||
{% import "common.j2" as common %}
|
||||
// Auto Generated, DO NOT EDIT!
|
||||
|
||||
#include "paddle/fluid/primitive/backend/generated/generated_backend.h"
|
||||
#include "paddle/fluid/pir/dialect/operator/ir/pd_api.h"
|
||||
#include "paddle/fluid/primitive/primitive/primitive.h"
|
||||
#include "paddle/fluid/primitive/base/lazy_tensor.h"
|
||||
|
||||
namespace paddle {
|
||||
namespace primitive {
|
||||
namespace backend {
|
||||
|
||||
using LazyTensor = paddle::primitive::LazyTensor;
|
||||
|
||||
{%- macro sig(name, inputs, outputs, attrs, mutable_attribute_as_inputs=False) -%}
|
||||
template <>
|
||||
{{common.ret(outputs)}} {{name}}<LazyTensor>({{common.params(inputs, attrs, mutable_attribute_as_inputs, False)}})
|
||||
{%- endmacro -%}
|
||||
|
||||
{%- macro prepare_ir_api_inputs(inputs)-%}
|
||||
{%- for input in inputs -%}
|
||||
{% if input.typename=='Tensor[]' and not input.optional %}
|
||||
std::vector<pir::Value> {{input.name}}_res({{input.name}}.size());
|
||||
std::transform({{input.name}}.begin(), {{input.name}}.end(), {{input.name}}_res.begin(), [](const Tensor& t) {
|
||||
return std::static_pointer_cast<LazyTensor>(t.impl())->value();
|
||||
});
|
||||
{% elif input.typename=='Tensor[]' and input.optional %}
|
||||
paddle::optional<std::vector<pir::Value>> {{input.name}}_res;
|
||||
if({{input.name}}) {
|
||||
std::vector<pir::Value> {{input.name}}_res_inner({{input.name}}.get().size());
|
||||
std::transform({{input.name}}.get().begin(), {{input.name}}.get().end(), {{input.name}}_res_inner.begin(), [](const Tensor& t) {
|
||||
return std::static_pointer_cast<LazyTensor>(t.impl())->value();
|
||||
});
|
||||
{{input.name}}_res = paddle::make_optional<std::vector<pir::Value>>({{input.name}}_res_inner);
|
||||
}
|
||||
{% elif input.typename=='Tensor' and not input.optional %}
|
||||
pir::Value {{input.name}}_res = std::static_pointer_cast<LazyTensor>({{input.name}}.impl())->value();
|
||||
{% else %}
|
||||
paddle::optional<pir::Value> {{input.name}}_res;
|
||||
if({{input.name}}) {
|
||||
pir::Value {{input.name}}_res_inner;
|
||||
{{input.name}}_res_inner = std::static_pointer_cast<LazyTensor>({{input.name}}.get().impl())->value();
|
||||
{{input.name}}_res = paddle::make_optional<pir::Value>({{input.name}}_res_inner);
|
||||
}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{%- endmacro -%}
|
||||
|
||||
{%- macro get_static_backend_outputs(outputs)-%}
|
||||
{%- if outputs|length == 1 -%}
|
||||
{%- if outputs[0].typename == 'Tensor' and not outputs[0].optional -%}
|
||||
Tensor {{outputs[0].name}}(std::make_shared<LazyTensor>(op_res));
|
||||
return {{outputs[0].name}};
|
||||
{%- elif outputs[0].typename == 'Tensor' and outputs[0].optional -%}
|
||||
paddle::optional<Tensor> {{outputs[0].name}};
|
||||
if(op_res){
|
||||
{{outputs[0].name}} = paddle::make_optional<Tensor>(Tensor(std::make_shared<LazyTensor>(op_res.get())));
|
||||
}
|
||||
return {{outputs[0].name}};
|
||||
{%- elif outputs[0].typename == 'Tensor[]' and not outputs[0].optional -%}
|
||||
std::vector<Tensor> {{outputs[0].name}}(op_res.size());
|
||||
std::transform(op_res.begin(), op_res.end(), {{outputs[0].name}}.begin(), [](const pir::Value& res) {
|
||||
return Tensor(std::make_shared<LazyTensor>(res));
|
||||
});
|
||||
return {{outputs[0].name}};
|
||||
{%- elif outputs[0].typename == 'Tensor[]' and outputs[0].optional -%}
|
||||
paddle::optional<std::vector<Tensor>> {{outputs[0].name}};
|
||||
if({{op_res}}) {
|
||||
std::vector<pir::Value> {{outputs[0].name}}_inner(op_res.get().size());
|
||||
std::transform(op_res.get().begin(), op_res.get().end(), {{outputs[0].name}}_inner.begin(), [](const pir::Value& res) {
|
||||
return Tensor(std::make_shared<LazyTensor>(res));
|
||||
});
|
||||
{{outputs[0].name}} = paddle::make_optional<std::vector<Tensor>>({{outputs[0].name}}_inner);
|
||||
}
|
||||
return {{outputs[0].name}};
|
||||
{%- else -%} {#- render nothing -#}
|
||||
{%- endif -%}
|
||||
{%- elif outputs|length > 1 -%}
|
||||
{%- for i in range(outputs|length) %}
|
||||
auto op_res_{{i}} = std::get<{{i}}>(op_res);
|
||||
{% if outputs[i].typename == 'Tensor' and not outputs[i].optional %}
|
||||
Tensor {{outputs[i].name}}(std::make_shared<LazyTensor>(op_res_{{i}}));
|
||||
{% elif outputs[i].typename == 'Tensor' and outputs[i].optional %}
|
||||
paddle::optional<Tensor> {{outputs[i].name}} = paddle::make_optional<Tensor>(Tensor());
|
||||
if(op_res_{{i}}){
|
||||
{{outputs[i].name}} = paddle::make_optional<Tensor>(Tensor(std::make_shared<LazyTensor>(op_res_{{i}}.get())));
|
||||
}
|
||||
{% elif outputs[i].typename == 'Tensor[]' and not outputs[i].optional %}
|
||||
std::vector<Tensor> {{outputs[i].name}}(op_res_{{i}}.size());
|
||||
std::transform(op_res_{{i}}.begin(), op_res_{{i}}.end(), {{outputs[i].name}}.begin(), [](const pir::Value& res) {
|
||||
return Tensor(std::make_shared<LazyTensor>(res));
|
||||
});
|
||||
{% elif outputs[i].typename == 'Tensor[]' and outputs[i].optional %}
|
||||
paddle::optional<std::vector<Tensor>> {{outputs[i].name}};
|
||||
if(op_res_{{i}}){
|
||||
std::vector<Tensor> {{outputs[i].name}}_inner(op_res_{{i}}.get().size());
|
||||
std::transform(op_res_{{i}}.get().begin(), op_res_{{i}}.get().end(), {{outputs[i].name}}_inner.begin(), [](const pir::Value& res) {
|
||||
return Tensor(std::make_shared<LazyTensor>(res));
|
||||
});
|
||||
{{outputs[i].name}} = paddle::make_optional<std::vector<Tensor>>({{outputs[i].name}}_inner);
|
||||
}
|
||||
{% else %} {#- render nothing -#}
|
||||
{% endif %}
|
||||
{% endfor -%}
|
||||
return std::make_tuple({%- for i in range(outputs|length) -%}{{outputs[i].name}}{%- if i!=outputs|length - 1 -%}, {% endif -%}{%- endfor -%});
|
||||
{%- else -%} {#- render nothing -#}
|
||||
{%- endif -%}
|
||||
{%- endmacro -%}
|
||||
|
||||
{% macro body(name, inputs, outputs, attrs, mutable_attribute_as_inputs=False) %}
|
||||
{%- set output_names = [] -%}
|
||||
{%- for o in outputs -%} {%- do output_names.append(o.name) -%} {%-endfor-%}
|
||||
{{prepare_ir_api_inputs(inputs)}}
|
||||
{%- for attr in attrs %}
|
||||
{% if mutable_attribute_as_inputs and attr is mutable_attribute %}
|
||||
pir::Value {{attr.name}}_res = std::static_pointer_cast<LazyTensor>({{attr.name~'_'}}.impl())->value();
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{%- set input_names = [] -%}
|
||||
{%- for i in inputs -%}
|
||||
{%- do input_names.append(i.name~'_res') -%}
|
||||
{%- endfor -%}
|
||||
{%- if mutable_attribute_as_inputs -%}
|
||||
{%- for i in attrs -%}
|
||||
{%- if i is mutable_attribute -%}
|
||||
{%- do input_names.append(i.name~'_res') -%}
|
||||
{%- endif -%}
|
||||
{%- endfor -%}
|
||||
{%- endif -%}
|
||||
{%- set attr_names = [] -%}
|
||||
{%- for i in attrs -%}
|
||||
{%- if not mutable_attribute_as_inputs or mutable_attribute_as_inputs and i is not mutable_attribute -%}{#- do nothing -#}
|
||||
{%- do attr_names.append(common.phi2ir_attr(i)) -%}
|
||||
{%- endif -%}
|
||||
{% endfor %}
|
||||
auto op_res = paddle::dialect::{{name}}({{common.args(input_names, attr_names)}});
|
||||
{{get_static_backend_outputs(outputs)}}
|
||||
{%- endmacro %}
|
||||
|
||||
|
||||
{% for api in apis %}
|
||||
{%- if api is only_composite_op or "infer_meta" not in api and "composite" not in api and "invoke" not in api -%}{#- render nothing -#}
|
||||
{% elif api.name not in backend_black_list %}
|
||||
{%- if 'invoke' not in api or 'invoke' in api and api.is_fwd-%}
|
||||
{% set api_outputs = api.outputs | trip_intermediate %}
|
||||
{{sig(api.name, api.inputs, api_outputs, api.attrs)}} {
|
||||
{% filter indent(2, True) %}
|
||||
{{body(api.name, api.inputs, api_outputs, api.attrs)}}
|
||||
{% endfilter %}
|
||||
}
|
||||
|
||||
{% if api.attrs is exist_mutable_attribute %}
|
||||
{{sig(api.name, api.inputs, api_outputs, api.attrs, True)}} {
|
||||
{% filter indent(2, True) %}
|
||||
{{body(api.name, api.inputs, api_outputs, api.attrs, True)}}
|
||||
{% endfilter %}
|
||||
}
|
||||
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% else %}{#- render nothing -#}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
|
||||
} // namespace backend
|
||||
} // namespace primitive
|
||||
} // namespace paddle
|
||||
@@ -0,0 +1,81 @@
|
||||
{%- macro sig(name, inputs, outputs, attrs, mutable_attribute_as_inputs=False, default=False) -%}
|
||||
template <typename T>
|
||||
{{ret(outputs)}} {{name}}({{params(inputs, attrs, mutable_attribute_as_inputs, default)}})
|
||||
{%- endmacro %}
|
||||
|
||||
|
||||
{%- macro params(inputs, attrs, mutable_attribute_as_inputs=False, default=False) -%}
|
||||
{%- set input_params = [] -%}
|
||||
{%- for i in inputs -%} {%- do input_params.append(i.typename|to_paddle_input_type(i.optional)~' '~i.name) -%} {%- endfor -%}
|
||||
{%- set attr_params = [] -%}
|
||||
{%- for i in attrs -%}
|
||||
{%- if not mutable_attribute_as_inputs or i is not mutable_attribute -%}
|
||||
{%- if default -%}
|
||||
{%- do attr_params.append(i.typename|to_paddle_attr_type~' '~i.name~default_value(i)) -%}
|
||||
{%- else -%}
|
||||
{%- do attr_params.append(i.typename|to_paddle_attr_type~' '~i.name) -%}
|
||||
{%- endif -%}
|
||||
{%- else -%}
|
||||
{%- do input_params.append('const Tensor&'~' '~i.name~'_') -%}
|
||||
{%- endif -%}
|
||||
{%- endfor -%}
|
||||
{{sequence('', '', ', ', input_params)}}
|
||||
{%- if input_params|length>0 and attr_params|length > 0 -%} {{", "}} {%- endif -%} {#- append comma between inputs and attrs -#}
|
||||
{{sequence('', '', ', ', attr_params)}}
|
||||
{%- endmacro -%}
|
||||
|
||||
|
||||
{%- macro default_value(attr) -%}
|
||||
{%- if 'default_value' in attr %}
|
||||
= {{attr.default_value}}
|
||||
{%- else -%} {#- render nothing -#}
|
||||
{%- endif -%}
|
||||
{%- endmacro -%}
|
||||
|
||||
|
||||
{%- macro args(arg1, arg2) -%} {#- Arguments are variable pass into method -#}
|
||||
{{sequence('', '', ', ', arg1)}}
|
||||
{%- if arg1|length>0 and arg2|length > 0 -%} {{", "}} {%- endif -%} {#- append comma between arg1 and arg2 -#}
|
||||
{{sequence('', '', ', ', arg2)}}
|
||||
{%- endmacro -%}
|
||||
|
||||
|
||||
{%- macro ret(outputs) -%}
|
||||
{%- set names = [] -%}
|
||||
{%- for i in outputs -%} {%- do names.append(i.typename|to_paddle_output_type(i.optional)) -%} {%- endfor -%}
|
||||
{%- if names|length > 1 -%}
|
||||
std::tuple<{{sequence('', '', ', ', names)}}>
|
||||
{%- else -%}
|
||||
{{names[0]}}
|
||||
{%- endif -%}
|
||||
{%- endmacro -%}
|
||||
|
||||
|
||||
{%- macro sequence(lsymbol, rsymbol, delimiter, items) -%}
|
||||
{{lsymbol}}{%- for item in items -%}{{item}}{{delimiter if not loop.last else "" }}{%- endfor -%}{{rsymbol}}
|
||||
{%- endmacro -%}
|
||||
|
||||
|
||||
{%- macro phi2ir_attr(attr) -%}
|
||||
{%- if attr.typename is intarray -%}
|
||||
{{intarray2ir(attr.name)}}
|
||||
{%- elif attr.typename is scalar -%}
|
||||
{{scalar2ir(attr.name, attr.data_type)}}
|
||||
{%- else -%}
|
||||
{{attr.name}}
|
||||
{%- endif -%}
|
||||
{%- endmacro %}
|
||||
|
||||
|
||||
{%- macro intarray2ir(name) -%}
|
||||
{{name}}.GetData()
|
||||
{%- endmacro -%}
|
||||
|
||||
|
||||
{%- macro scalar2ir(name, data_type) -%}
|
||||
{%- if data_type == 'std::vector<Scalar>' -%}
|
||||
{{name}}
|
||||
{%- else -%}
|
||||
{{name}}.to<{{data_type}}>()
|
||||
{%- endif -%}
|
||||
{%- endmacro -%}
|
||||
@@ -0,0 +1,183 @@
|
||||
{% import "common.j2" as common %}
|
||||
// Auto Generated by decomp_gen.py, DO NOT EDIT!
|
||||
|
||||
#include "paddle/fluid/pir/dialect/operator/ir/op_attribute.h"
|
||||
#include "paddle/fluid/pir/dialect/operator/ir/pd_op.h"
|
||||
#include "paddle/fluid/pir/dialect/operator/utils/utils.h"
|
||||
#include "paddle/fluid/primitive/decomp_rule/decomp_rule/composite.h"
|
||||
#include "paddle/fluid/primitive/base/lazy_tensor.h"
|
||||
#include "paddle/phi/api/include/tensor.h"
|
||||
#include "paddle/phi/common/int_array.h"
|
||||
#include "paddle/pir/include/core/builtin_op.h"
|
||||
#include "paddle/pir/include/core/op_base.h"
|
||||
|
||||
namespace paddle {
|
||||
namespace dialect {
|
||||
using IntArray = paddle::experimental::IntArray;
|
||||
{% macro sig(fwd_name, class_name, inputs, attrs, outputs) %}
|
||||
|
||||
{% set input_names=[] %}
|
||||
{% set attr_names=[] %}
|
||||
{% set output_names=[] %}
|
||||
{% set output_types=[] %}
|
||||
|
||||
std::vector<std::vector<pir::Value>> {{class_name}}::Decomp(pir::Operation* op) {
|
||||
VLOG(4) << "Decomp call {{fwd_name}}'s decomp interface begin";
|
||||
|
||||
{{class_name}} op_obj = op->dyn_cast<{{class_name}}>();
|
||||
(void)op_obj;
|
||||
|
||||
FLAGS_tensor_operants_mode = "static";
|
||||
|
||||
VLOG(6) << "Decomp Prepare inputs of {{fwd_name}}";
|
||||
|
||||
{% for item in inputs -%}
|
||||
{% do input_names.append(item.name) %}
|
||||
{% if item.typename == "Tensor" %} {#- Tensor or Tensor[] #}
|
||||
{% if item.optional %}
|
||||
paddle::optional<Tensor> {{item.name}};
|
||||
if (!IsEmptyValue(op_obj.{{item.name}}())){
|
||||
{{item.name}} = paddle::make_optional<Tensor>(Tensor(std::make_shared<primitive::LazyTensor>(op_obj.{{item.name}}())));
|
||||
}
|
||||
{% else %}
|
||||
{{item.typename}} {{item.name}}(std::make_shared<primitive::LazyTensor>(op_obj.{{item.name}}()));
|
||||
{% endif %}
|
||||
{% elif item.typename == "Tensor[]" %}
|
||||
{% if item.optional %}
|
||||
|
||||
paddle::optional<std::vector<Tensor>> {{item.name}};
|
||||
if (!IsEmptyValue(op_obj.{{item.name}}())){
|
||||
pir::CombineOp combine_op_obj =
|
||||
op_obj.{{item.name}}().defining_op()->dyn_cast<pir::CombineOp>();
|
||||
std::vector<Tensor> optional_{{item.name}};
|
||||
for (size_t idx = 0; idx < combine_op_obj.inputs().size(); idx++) {
|
||||
optional_{{item.name}}.emplace_back(
|
||||
std::make_shared<primitive::LazyTensor>(combine_op_obj.inputs()[idx]));
|
||||
}
|
||||
{{item.name}} = paddle::make_optional<std::vector<Tensor>>(optional_{{item.name}});
|
||||
}
|
||||
|
||||
{% else %}
|
||||
pir::CombineOp combine_op_obj_{{item.name}} =
|
||||
op_obj.{{item.name}}().defining_op()->dyn_cast<pir::CombineOp>();
|
||||
std::vector<Tensor> {{item.name}};
|
||||
for (size_t idx = 0; idx < combine_op_obj_{{item.name}}.inputs().size(); idx++) {
|
||||
{{item.name}}.emplace_back(
|
||||
std::make_shared<primitive::LazyTensor>(combine_op_obj_{{item.name}}.inputs()[idx]));
|
||||
}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
|
||||
VLOG(6) << "Decomp prepare attributes of {{fwd_name}}";
|
||||
{% if attrs %}
|
||||
{% for item in attrs %}
|
||||
{% do attr_names.append(item.name) %}
|
||||
{% if item.typename.startswith("Scalar") and item.support_tensor %}
|
||||
|
||||
Tensor {{item.name}}_(std::make_shared<primitive::LazyTensor>(op_obj.{{item.name}}()));
|
||||
|
||||
auto* {{item.name}}_define_op =
|
||||
std::static_pointer_cast<primitive::LazyTensor>({{item.name}}_.impl())
|
||||
->value()
|
||||
.defining_op();
|
||||
if ({{item.name}}_define_op->name() != "pd_op.full") {
|
||||
return {};
|
||||
}
|
||||
Scalar {{item.name}} = {{item.name}}_define_op->attribute("value").dyn_cast<paddle::dialect::ScalarAttribute>().data();
|
||||
|
||||
{% elif item.typename == "IntArray" and item.support_tensor %}
|
||||
|
||||
Tensor {{item.name}}_(std::make_shared<primitive::LazyTensor>(op_obj.{{item.name}}()));
|
||||
|
||||
auto* {{item.name}}_define_op =
|
||||
std::static_pointer_cast<primitive::LazyTensor>({{item.name}}_.impl())
|
||||
->value()
|
||||
.defining_op();
|
||||
if ({{item.name}}_define_op->name() != "pd_op.full_int_array") {
|
||||
return {};
|
||||
}
|
||||
IntArray {{item.name}} = phi::IntArray(
|
||||
paddle::dialect::GetInt64Vector({{item.name}}_define_op->attribute("value")));
|
||||
|
||||
{% else %}
|
||||
{% if item.mapped_type[0] == "pir::StrAttribute" %}
|
||||
{{item.mapped_type[1]}} {{item.name}} = op->attribute("{{item.name}}").dyn_cast<{{item.mapped_type[0]}}>().AsString();
|
||||
{% elif "[]" in item.typename %}
|
||||
auto array_list = op->attribute("{{item.name}}").dyn_cast<pir::ArrayAttribute>().AsVector();
|
||||
{% set temp_type= item.mapped_type[0]|replace('pir::ArrayAttribute<', '')|replace('>', '')%}
|
||||
{{item.mapped_type[1]|replace('const ', '')|replace('&', '')}} {{item.name}};
|
||||
if (array_list.size() > 0) {
|
||||
if (array_list[0].isa<{{temp_type}}>()) {
|
||||
for (size_t i = 0; i < array_list.size(); ++i) {
|
||||
{{item.name}}.push_back(
|
||||
array_list[i].dyn_cast<{{temp_type}}>().data());
|
||||
}
|
||||
|
||||
} else {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
{% else %}
|
||||
{{item.mapped_type[1]}} {{item.name}} = op->attribute("{{item.name}}").dyn_cast<{{item.mapped_type[0]}}>().data();
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
VLOG(6) << "Decomp call {{fwd_name}}'s forward composite rule prepare";
|
||||
|
||||
auto org_res = op->results();
|
||||
std::vector<std::vector<pir::Value>> res(org_res.size());
|
||||
|
||||
VLOG(6) << "Decomp call {{fwd_name}}'s forward composite rule begin";
|
||||
{% if outputs|length == 1 %}
|
||||
{% if outputs[0].typename == "Tensor[]" %}
|
||||
std::vector<Tensor> op_res = paddle::primitive::details::{{fwd_name}}_decomp<primitive::LazyTensor>({{common.args(input_names, attr_names)}});
|
||||
{% else %}
|
||||
Tensor op_res = paddle::primitive::details::{{fwd_name}}_decomp<primitive::LazyTensor>({{common.args(input_names, attr_names)}});
|
||||
{% endif %}
|
||||
VLOG(6) << "Decomp call {{fwd_name}}'s forward composite rule end";
|
||||
{% if outputs[0].typename == "Tensor[]" %}
|
||||
for (size_t idx = 0; idx < op_res.size(); idx++) {
|
||||
res[0].push_back(
|
||||
std::static_pointer_cast<primitive::LazyTensor>(op_res[idx].impl())
|
||||
->value());
|
||||
}
|
||||
{% else %}
|
||||
res[0].push_back(
|
||||
std::static_pointer_cast<primitive::LazyTensor>(op_res.impl())
|
||||
->value());
|
||||
{% endif %}
|
||||
{% else %}
|
||||
{% for item in outputs %}
|
||||
{% do output_names.append(item.name) %}
|
||||
{% do output_types.append(item.mapped_type) %}
|
||||
{% endfor %}
|
||||
std::tuple<{{common.sequence('', '', ', ', output_types)}}> op_res = paddle::primitive::details::{{fwd_name}}_decomp<primitive::LazyTensor>(
|
||||
{{common.args(input_names, attr_names)}});
|
||||
VLOG(6) << "Decomp call {{fwd_name}}'s forward composite rule end";
|
||||
{% for k in range(outputs|length) %}
|
||||
{% if outputs[k].intermediate and fwd_name in decomp_ops_list_contain_unused_output %}
|
||||
pir::Value {{outputs[k].name}};
|
||||
res[{{k}}].push_back({{outputs[k].name}});
|
||||
{% else %}
|
||||
res[{{k}}].push_back(std::static_pointer_cast<primitive::LazyTensor>(std::get<{{k}}>(op_res).impl())->value());
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
VLOG(4) << "Decomp call {{fwd_name}}'s decomp interface end";
|
||||
return res;
|
||||
}
|
||||
{% endmacro %}
|
||||
|
||||
{% for api in apis -%}
|
||||
{% if api.name in decomp_white_list %}
|
||||
{{sig(api.name, api.class_name, api.inputs, api.attrs, api.outputs)}}
|
||||
{% else %} {# render nothing #}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
|
||||
} // namespace dialect
|
||||
} // namespace paddle
|
||||
@@ -0,0 +1,185 @@
|
||||
{% import "common.j2" as common %}
|
||||
// Auto Generated by decomp_gen.py, DO NOT EDIT!
|
||||
|
||||
#include "paddle/fluid/pir/dialect/operator/ir/op_attribute.h"
|
||||
#include "paddle/fluid/pir/dialect/operator/ir/pd_op.h"
|
||||
#include "paddle/fluid/pir/dialect/operator/utils/utils.h"
|
||||
#include "paddle/fluid/primitive/decomp_rule/decomp_rule/composite.h"
|
||||
#include "paddle/fluid/primitive/decomp_rule/decomp_vjp/details.h"
|
||||
#include "paddle/fluid/primitive/vjp_interface/generated/generated_vjp.h"
|
||||
#include "paddle/fluid/primitive/base/lazy_tensor.h"
|
||||
#include "paddle/phi/api/include/tensor.h"
|
||||
#include "paddle/phi/common/int_array.h"
|
||||
#include "paddle/pir/include/core/builtin_op.h"
|
||||
#include "paddle/pir/include/core/op_base.h"
|
||||
|
||||
namespace paddle {
|
||||
namespace dialect {
|
||||
using IntArray = paddle::experimental::IntArray;
|
||||
{% macro sig(fwd_name, class_name, inputs, attrs, outputs) %}
|
||||
{% set input_names=[] %}
|
||||
{% set attr_names=[] %}
|
||||
{% set output_names=[] %}
|
||||
{% set output_types=[] %}
|
||||
|
||||
std::vector<std::vector<pir::Value>> {{class_name}}::DecompVjp(pir::Operation* op) {
|
||||
VLOG(4) << "Decomp call {{fwd_name}}'s decomp interface begin";
|
||||
|
||||
{{class_name}} op_obj = op->dyn_cast<{{class_name}}>();
|
||||
(void)op_obj;
|
||||
|
||||
FLAGS_tensor_operants_mode = "static";
|
||||
|
||||
VLOG(6) << "Decomp Prepare inputs of {{fwd_name}}";
|
||||
|
||||
{% for item in inputs -%}
|
||||
{% do input_names.append(item.name) %}
|
||||
{% if item.typename == "Tensor" %} {#- Tensor or Tensor[] #}
|
||||
{% if item.optional %}
|
||||
paddle::optional<Tensor> {{item.name}};
|
||||
if (!IsEmptyValue(op_obj.{{item.name}}())){
|
||||
{{item.name}} = paddle::make_optional<Tensor>(Tensor(std::make_shared<primitive::LazyTensor>(op_obj.{{item.name}}())));
|
||||
}
|
||||
{% else %}
|
||||
{{item.typename}} {{item.name}}(std::make_shared<primitive::LazyTensor>(op_obj.{{item.name}}()));
|
||||
{% endif %}
|
||||
{% elif item.typename == "Tensor[]" %}
|
||||
{% if item.optional %}
|
||||
|
||||
paddle::optional<std::vector<Tensor>> {{item.name}};
|
||||
if (!IsEmptyValue(op_obj.{{item.name}}())){
|
||||
pir::CombineOp combine_op_obj =
|
||||
op_obj.{{item.name}}().defining_op()->dyn_cast<pir::CombineOp>();
|
||||
std::vector<Tensor> optional_{{item.name}};
|
||||
for (size_t idx = 0; idx < combine_op_obj.inputs().size(); idx++) {
|
||||
optional_{{item.name}}.emplace_back(
|
||||
std::make_shared<primitive::LazyTensor>(combine_op_obj.inputs()[idx]));
|
||||
}
|
||||
{{item.name}} = paddle::make_optional<std::vector<Tensor>>(optional_{{item.name}});
|
||||
}
|
||||
|
||||
{% else %}
|
||||
pir::CombineOp combine_op_obj_{{item.name}} =
|
||||
op_obj.{{item.name}}().defining_op()->dyn_cast<pir::CombineOp>();
|
||||
std::vector<Tensor> {{item.name}};
|
||||
for (size_t idx = 0; idx < combine_op_obj_{{item.name}}.inputs().size(); idx++) {
|
||||
{{item.name}}.emplace_back(
|
||||
std::make_shared<primitive::LazyTensor>(combine_op_obj_{{item.name}}.inputs()[idx]));
|
||||
}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
|
||||
VLOG(6) << "Decomp prepare attributes of {{fwd_name}}";
|
||||
{% if attrs %}
|
||||
{% for item in attrs %}
|
||||
{% do attr_names.append(item.name) %}
|
||||
{% if item.typename == "Scalar" and item.support_tensor %}
|
||||
|
||||
Tensor {{item.name}}_(std::make_shared<primitive::LazyTensor>(op_obj.{{item.name}}()));
|
||||
|
||||
auto* {{item.name}}_define_op =
|
||||
std::static_pointer_cast<primitive::LazyTensor>({{item.name}}_.impl())
|
||||
->value()
|
||||
.defining_op();
|
||||
if ({{item.name}}_define_op->name() != "pd_op.full") {
|
||||
PADDLE_THROW(
|
||||
common::errors::Unimplemented("We don't support dynamic tensors "
|
||||
"attribute {{item.name}} for {{fwd_name}} decomposition "
|
||||
"for now. "));
|
||||
}
|
||||
Scalar {{item.name}} = {{item.name}}_define_op->attribute("value").dyn_cast<paddle::dialect::ScalarAttribute>().data();
|
||||
|
||||
{% elif item.typename == "IntArray" and item.support_tensor %}
|
||||
|
||||
Tensor {{item.name}}_(std::make_shared<primitive::LazyTensor>(op_obj.{{item.name}}()));
|
||||
|
||||
auto* {{item.name}}_define_op =
|
||||
std::static_pointer_cast<primitive::LazyTensor>({{item.name}}_.impl())
|
||||
->value()
|
||||
.defining_op();
|
||||
if ({{item.name}}_define_op->name() != "pd_op.full_int_array") {
|
||||
PADDLE_THROW(
|
||||
common::errors::Unimplemented("We don't support dynamic tensors "
|
||||
"attribute {{item.name}} for {{fwd_name}} decomposition "
|
||||
"for now. "));
|
||||
}
|
||||
IntArray {{item.name}} = phi::IntArray(
|
||||
paddle::dialect::GetInt64Vector({{item.name}}_define_op->attribute("value")));
|
||||
|
||||
{% else %}
|
||||
{% if item.mapped_type[0] == "pir::StrAttribute" %}
|
||||
{{item.mapped_type[1]}} {{item.name}} = op->attribute("{{item.name}}").dyn_cast<{{item.mapped_type[0]}}>().AsString();
|
||||
{% elif "[]" in item.typename %}
|
||||
auto array_list = op->attribute("{{item.name}}").dyn_cast<pir::ArrayAttribute>().AsVector();
|
||||
{% set temp_type= item.mapped_type[0]|replace('pir::ArrayAttribute<', '')|replace('>', '')%}
|
||||
{{item.mapped_type[1]|replace('const ', '')|replace('&', '')}} {{item.name}};
|
||||
if (array_list.size() > 0) {
|
||||
if (array_list[0].isa<{{temp_type}}>()) {
|
||||
for (size_t i = 0; i < array_list.size(); ++i) {
|
||||
{{item.name}}.push_back(
|
||||
array_list[i].dyn_cast<{{temp_type}}>().data());
|
||||
}
|
||||
|
||||
} else {
|
||||
PADDLE_THROW(common::errors::Unimplemented("attr is not vector of {{temp_type}} "));
|
||||
}
|
||||
}
|
||||
{% else %}
|
||||
{{item.mapped_type[1]}} {{item.name}} = op->attribute("{{item.name}}").dyn_cast<{{item.mapped_type[0]}}>().data();
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
VLOG(6) << "Decomp call {{fwd_name}}'s backward composite rule prepare";
|
||||
|
||||
std::vector<std::vector<bool>> stop_gradients = ConstructStopGradient(op);
|
||||
|
||||
std::vector<std::vector<paddle::Tensor>> tensor_res;
|
||||
for (auto arg : stop_gradients) {
|
||||
tensor_res.push_back(std::vector<paddle::Tensor>(arg.size()));
|
||||
}
|
||||
std::string op_name = "{{fwd_name}}";
|
||||
FLAGS_tensor_operants_mode = "static";
|
||||
VLOG(4) << "Call Pir Decomposed backward op {{fwd_name}}";
|
||||
|
||||
|
||||
{% for k in range(outputs|length) %}
|
||||
paddle::Tensor* {{outputs[k].name}} = !stop_gradients[{{k}}][0] ? &tensor_res[{{k}}][0] : nullptr;
|
||||
{% endfor %}
|
||||
|
||||
{% for item in outputs %}
|
||||
{% do output_names.append(item.name) %}
|
||||
{% do output_types.append(item.mapped_type) %}
|
||||
{% endfor %}
|
||||
|
||||
paddle::primitive::details::{{fwd_name}}<primitive::LazyTensor>(
|
||||
{{common.args(input_names, attr_names)}}, {{common.sequence('', '', ', ', output_names)}});
|
||||
std::vector<std::vector<pir::Value>> res(tensor_res.size());
|
||||
|
||||
for (size_t i = 0; i < tensor_res.size(); ++i) {
|
||||
res[i].resize(tensor_res[i].size());
|
||||
for (size_t j = 0; j < tensor_res[i].size(); ++j) {
|
||||
if (tensor_res[i][j].defined()) {
|
||||
res[i][j] = std::static_pointer_cast<primitive::LazyTensor>(
|
||||
tensor_res[i][j].impl())
|
||||
->value();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
VLOG(4) << "Decomp call {{fwd_name}}'s decomp interface end";
|
||||
return res;
|
||||
}
|
||||
{% endmacro %}
|
||||
|
||||
{% for api in apis -%}
|
||||
{% if api.name in decomp_vjp_white_list %}
|
||||
{{sig(api.name, api.class_name, api.inputs, api.attrs, api.outputs)}}
|
||||
{% else %} {# render nothing #}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
|
||||
} // namespace dialect
|
||||
} // namespace paddle
|
||||
@@ -0,0 +1,29 @@
|
||||
{% import "common.j2" as common %}
|
||||
// Auto Generated, DO NOT EDIT!
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "paddle/fluid/primitive/backend/backend.h"
|
||||
|
||||
|
||||
namespace paddle {
|
||||
namespace primitive {
|
||||
|
||||
using Tensor = paddle::Tensor;
|
||||
using IntArray = paddle::experimental::IntArray;
|
||||
|
||||
{% for api in apis %}
|
||||
{%- if api.is_prim and api.name not in backend_black_list and api.name[-1] != '_' -%}
|
||||
{%- set input_names = [] -%}
|
||||
{%- for i in api.inputs -%} {%- do input_names.append(i.name) -%} {%- endfor -%}
|
||||
{%- set attr_names = [] -%}
|
||||
{%- for i in api.attrs -%} {%- do attr_names.append(i.name) -%} {% endfor %}
|
||||
{{common.sig(api.name, api.inputs, api.outputs | trip_intermediate, api.attrs, False, True)}} {
|
||||
return backend::{{api.name}}<T>({{common.args(input_names, attr_names)}});
|
||||
}
|
||||
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
|
||||
} // namespace primitive
|
||||
} // namespace paddle
|
||||
@@ -0,0 +1,180 @@
|
||||
{% import "common.j2" as common %}
|
||||
// Auto Generated, DO NOT EDIT!
|
||||
|
||||
#include "paddle/fluid/primitive/vjp_interface/generated/generated_vjp.h"
|
||||
#include "paddle/fluid/pir/dialect/operator/ir/pd_api.h"
|
||||
#include "paddle/fluid/pir/dialect/operator/ir/op_attribute.h"
|
||||
#include "paddle/fluid/prim/utils/static/static_global_utils.h"
|
||||
#include "paddle/fluid/primitive/backend/backend.h"
|
||||
#include "paddle/fluid/primitive/decomp_rule/decomp_vjp/details.h"
|
||||
#include "paddle/fluid/primitive/base/lazy_tensor.h"
|
||||
#include "paddle/fluid/primitive/decomp_utils/decomp_utils.h"
|
||||
#include "paddle/pir/include/core/operation.h"
|
||||
#include "paddle/common/flags.h"
|
||||
#include "paddle/utils/optional.h"
|
||||
#include "paddle/fluid/pir/dialect/operator/utils/utils.h"
|
||||
|
||||
COMMON_DECLARE_string(tensor_operants_mode);
|
||||
|
||||
namespace paddle {
|
||||
namespace primitive {
|
||||
{% macro sig(fwd_name, name, inputs, attrs, outputs) -%}
|
||||
std::vector<std::vector<paddle::Tensor>> {{fwd_name}}_vjp({{common.params(inputs, attrs, attrs is exist_mutable_attribute)}}, const std::vector<std::vector<bool>>& stop_gradients)
|
||||
{%- endmacro -%}
|
||||
|
||||
{% macro join_need_skip(attrs, api_name) %}
|
||||
{% for i in attrs %}
|
||||
{%- if i is mutable_attribute -%}
|
||||
{% if i.typename is scalar %}
|
||||
auto* {{i.name}}_define_op = std::static_pointer_cast<primitive::LazyTensor>({{i.name~'_'}}.impl())->value().defining_op();
|
||||
if({{i.name}}_define_op->name() != "pd_op.full") {
|
||||
need_skip = true;
|
||||
VLOG(4) << "We don't support dynamic tensors attribute {{i.name}} for {{api_name}} composite for now, set need_skip=true.";
|
||||
}
|
||||
{% elif i.typename is intarray %}
|
||||
auto* {{i.name}}_define_op = std::static_pointer_cast<primitive::LazyTensor>({{i.name~'_'}}.impl())->value().defining_op();
|
||||
if({{i.name}}_define_op->name() != "pd_op.full_int_array") {
|
||||
need_skip = true;
|
||||
VLOG(4) << "We don't support dynamic tensors attribute {{i.name}} for {{api_name}} composite for now, set need_skip=true.";
|
||||
}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% endmacro %}
|
||||
|
||||
{% macro body(api) %}
|
||||
std::vector<std::vector<paddle::Tensor>> vjp_res;
|
||||
for (auto arg: stop_gradients) {
|
||||
vjp_res.push_back(std::vector<paddle::Tensor>(arg.size()));
|
||||
}
|
||||
{% if api.name in vjp_comp_white_list %}
|
||||
std::string op_name = "{{api.name}}";
|
||||
auto need_skip = paddle::prim::StaticCompositeContext::Instance().CheckSkipCompOps(op_name);
|
||||
{{join_need_skip(api.attrs, api.name)}}
|
||||
if (paddle::prim::StaticCompositeContext::Instance().IsBwdPrimEnabled() && !need_skip) {
|
||||
{% filter indent(2, True) %}{{body_prim(api)}}{% endfilter %}
|
||||
} else {
|
||||
{% filter indent(2, True) %}{{body_unprim(api)}}{% endfilter %}
|
||||
}
|
||||
{% else %}
|
||||
{{body_unprim(api)}}
|
||||
{%- endif %}
|
||||
return vjp_res;
|
||||
{%- endmacro -%}
|
||||
|
||||
{% macro get_mutable_attribute(attrs, api_name) %}
|
||||
{% for i in attrs %}
|
||||
{%- if i is mutable_attribute -%}
|
||||
{% if i.typename is scalar %}
|
||||
auto {{i.name}} = {{i.name}}_define_op->attribute("value").dyn_cast<paddle::dialect::ScalarAttribute>().data();
|
||||
{% elif i.typename is intarray %}
|
||||
auto {{i.name}} = phi::IntArray(paddle::dialect::GetInt64Vector({{i.name}}_define_op->attribute("value")));
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% endmacro %}
|
||||
|
||||
{% macro body_unprim(api) %}
|
||||
{%- set input_names=[] -%}
|
||||
{%- for api in apis -%} {%- do api_map.update({api.name: api}) -%} {%- endfor -%}
|
||||
{%- for i in api.inputs -%} {%- do input_names.append(i.name) -%} {%- endfor -%}
|
||||
{%- set attr_names=[] -%}
|
||||
{%- for i in api.attrs -%}
|
||||
{%- if i is mutable_attribute -%}
|
||||
{%- do input_names.append(i.name~'_') -%}
|
||||
{%- else -%}
|
||||
{%- do attr_names.append(i.name) -%}
|
||||
{%- endif -%}
|
||||
{%- endfor %}
|
||||
{% if 'invoke' in api and api.invoke.func in api_map %}
|
||||
auto op_res = backend::{{api.invoke.func}}<LazyTensor>({{api.invoke.args}});
|
||||
{% else %}
|
||||
auto op_res = backend::{{api.name}}<LazyTensor>({{common.args(input_names, attr_names)}});
|
||||
{% endif %}
|
||||
{% set outputs = api.outputs|trip_intermediate %} {#- ignore intermediate output -#}
|
||||
{% if outputs|length > 1 %}
|
||||
{% for i in range(outputs|length) %}
|
||||
{% if outputs[i].typename=='Tensor' %}
|
||||
{% if outputs[i].optional %}
|
||||
if(std::get<{{i}}>(op_res)){
|
||||
vjp_res[{{i}}][0] = std::get<{{i}}>(op_res).get();
|
||||
}
|
||||
{% else %}
|
||||
vjp_res[{{i}}][0] = std::get<{{i}}>(op_res);
|
||||
{% endif %}
|
||||
{% else %}
|
||||
{% if outputs[i].optional %}
|
||||
if(std::get<{{i}}>(op_res)){
|
||||
vjp_res[{{i}}] = std::get<{{i}}>(op_res).get();
|
||||
}
|
||||
{% else %}
|
||||
vjp_res[{{i}}] = std::get<{{i}}>(op_res);
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% elif outputs|length == 1 %}
|
||||
{% if outputs[0].typename=='Tensor' %}
|
||||
{% if outputs[0].optional %}
|
||||
if(op_res){
|
||||
vjp_res[0][0] = op_res.get();
|
||||
}
|
||||
{% else %}
|
||||
vjp_res[0][0] = op_res;
|
||||
{% endif %}
|
||||
{% else %}
|
||||
{% if outputs[0].optional %}
|
||||
if(op_res){
|
||||
vjp_res[0] = op_res.get();
|
||||
}
|
||||
{% else %}
|
||||
vjp_res[0] = op_res;
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% else %} {#- render nothing -#}
|
||||
{% endif %}
|
||||
vjp_res = ConstructVjpResultByStopGradients(vjp_res, stop_gradients);
|
||||
{% endmacro %}
|
||||
|
||||
{% macro body_prim(api) %}
|
||||
FLAGS_tensor_operants_mode = "static";
|
||||
VLOG(4) << "Call Pir Decomposed backward op {{api.name}}";
|
||||
{% for i in range(api.outputs|length) %}
|
||||
{% if api.outputs[i].typename=='Tensor' %}
|
||||
paddle::Tensor* {{api.outputs[i].name}} = !stop_gradients[{{i}}][0] ? &vjp_res[{{i}}][0] : nullptr;
|
||||
{% else %}
|
||||
std::vector<paddle::Tensor*> {{api.outputs[i].name}}(stop_gradients[{{i}}].size(), nullptr);
|
||||
for (size_t i=0; i< stop_gradients[{{i}}].size(); i++ ) {
|
||||
{{api.outputs[i].name}}[i] = !stop_gradients[{{i}}][i] ? &vjp_res[{{i}}][i] : nullptr;
|
||||
}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{{get_mutable_attribute(api.attrs, api.name)}}
|
||||
|
||||
{%- set args_names=[] -%}
|
||||
{%- for i in api.inputs -%} {%- do args_names.append(i.name) -%} {%- endfor -%}
|
||||
{%- for i in api.attrs -%} {%- do args_names.append(i.name) -%} {%- endfor %}
|
||||
{%- set outputs_names=[] -%}
|
||||
{%- for i in api.outputs -%} {%- do outputs_names.append(i.name) -%} {%- endfor -%}
|
||||
details::{{api.name}}<LazyTensor>({{common.args(args_names, outputs_names)}});
|
||||
{% endmacro %}
|
||||
|
||||
{%- set api_map = {} -%}
|
||||
{%- for api in apis -%} {%- do api_map.update({api.name: api}) -%} {%- endfor -%}
|
||||
{%- for api in apis %}
|
||||
{%- if api.backward and api.backward in api_map and api.backward not in vjp_black_list -%}
|
||||
{%- set backward_api = api_map[api.backward] %}
|
||||
{%- if backward_api is only_composite_op -%}{#- render nothing -#}
|
||||
{%- else -%}
|
||||
{{sig(api.name, backward_api.name, backward_api.inputs, backward_api.attrs, backward_api.outputs)}} {
|
||||
{% filter indent(2, True) %}
|
||||
{{body(backward_api)}}
|
||||
{% endfilter -%}
|
||||
}
|
||||
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
|
||||
|
||||
} // namespace primitive
|
||||
} // namespace paddle
|
||||
@@ -0,0 +1,33 @@
|
||||
{% import "common.j2" as common %}
|
||||
// Auto Generated, DO NOT EDIT!
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "paddle/fluid/primitive/primitive/primitive.h"
|
||||
#include "paddle/pir/include/core/value.h"
|
||||
#include "paddle/phi/api/include/tensor.h"
|
||||
#include "paddle/phi/common/int_array.h"
|
||||
|
||||
namespace paddle {
|
||||
namespace primitive {
|
||||
|
||||
using IntArray = paddle::experimental::IntArray;
|
||||
|
||||
{% macro sig(fwd_name, name, inputs, attrs, outputs) %}
|
||||
std::vector<std::vector<paddle::Tensor>> {{fwd_name}}_vjp({{common.params(inputs, attrs, attrs is exist_mutable_attribute)}}, const std::vector<std::vector<bool>>& stop_gradients);
|
||||
{% endmacro %}
|
||||
|
||||
{%- set api_map = {} -%}
|
||||
{%- for api in apis -%} {%- do api_map.update({api.name: api}) -%} {%- endfor -%}
|
||||
{% for api in apis %}
|
||||
{%- if api.backward and api.backward in api_map and api.backward not in vjp_black_list -%}
|
||||
{%- set backward_api = api_map[api.backward] -%}
|
||||
{%- if backward_api is only_composite_op -%}{#- render nothing -#}
|
||||
{%- else -%}
|
||||
{{sig(api.name, backward_api.name, backward_api.inputs, backward_api.attrs, backward_api.outputs)}}
|
||||
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
} // namespace primitive
|
||||
} // namespace paddle
|
||||
Reference in New Issue
Block a user