/* Copyright (c) 2022 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. */ #include "paddle/phi/api/lib/api_custom_impl.h" #include "glog/logging.h" #include "paddle/common/flags.h" #include "paddle/phi/api/lib/api_gen_utils.h" #include "paddle/phi/api/lib/data_transform.h" #include "paddle/phi/api/lib/kernel_dispatch.h" #include "paddle/phi/api/lib/tensor_copy.h" #include "paddle/phi/common/type_traits.h" #include "paddle/phi/core/compat/convert_utils.h" #include "paddle/phi/core/kernel_registry.h" #include "paddle/phi/core/meta_tensor.h" #include "paddle/phi/infermeta/backward.h" #include "paddle/phi/infermeta/binary.h" #include "paddle/phi/infermeta/fusion.h" #include "paddle/phi/infermeta/multiary.h" #include "paddle/phi/infermeta/nullary.h" #include "paddle/phi/infermeta/unary.h" #include "paddle/phi/api/profiler/event_tracing.h" #include "paddle/phi/api/profiler/supplement_tracing.h" #ifdef PADDLE_WITH_DISTRIBUTE #include "paddle/phi/core/distributed/auto_parallel/reshard/reshard_utils.h" #include "paddle/phi/infermeta/spmd_rules/rules.h" #endif COMMON_DECLARE_int32(low_precision_op_list); COMMON_DECLARE_bool(benchmark); namespace paddle::experimental { ////////////////// Forward api impls ////////////////////// Tensor add_n_impl(const std::vector& x) { Backend kernel_backend = Backend::UNDEFINED; DataLayout kernel_layout = DataLayout::UNDEFINED; DataType kernel_data_type = DataType::UNDEFINED; if (kernel_backend == Backend::UNDEFINED || kernel_layout == DataLayout::UNDEFINED || kernel_data_type == DataType::UNDEFINED) { auto kernel_key_set = ParseKernelKeyByInputArgs(x); auto kernel_key = kernel_key_set.GetHighestPriorityKernelKey(); if (kernel_backend == Backend::UNDEFINED) { kernel_backend = kernel_key.backend(); } if (kernel_layout == DataLayout::UNDEFINED) { kernel_layout = kernel_key.layout(); } if (kernel_data_type == DataType::UNDEFINED) { kernel_data_type = kernel_key.dtype(); } } bool is_sr_kernel = true; for (auto& input : x) { if (phi::DenseTensor::classof(input.impl().get()) || phi::distributed::DistTensor::classof(input.impl().get())) { is_sr_kernel = false; break; } } const std::string kernel_name = (is_sr_kernel ? "add_n_sr" : "add_n"); VLOG(6) << "add_n API kernel key: [" << kernel_backend << ", " << kernel_layout << ", " << kernel_data_type << "]"; auto kernel_result = phi::KernelFactory::Instance().SelectKernelOrThrowError( kernel_name, {kernel_backend, kernel_layout, kernel_data_type}); const auto& kernel = kernel_result.kernel; VLOG(6) << kernel_name << " kernel: " << kernel; auto* dev_ctx = GetDeviceContextByBackend( kernel_result.has_fallback_cpu ? Backend::CPU : kernel_backend); Tensor api_output; if (is_sr_kernel) { std::vector input_x(x.size()); for (size_t i = 0; i < input_x.size(); ++i) { input_x[i] = static_cast(x[i].impl().get()); } auto x_meta_vec = MakeMetaTensor(input_x); std::vector x_metas(x_meta_vec.size()); for (size_t i = 0; i < x_meta_vec.size(); ++i) { x_metas[i] = &x_meta_vec[i]; } auto kernel_out = SetSelectedRowsKernelOutput(&api_output); phi::MetaTensor meta_out(kernel_out); phi::AddNInferMeta(x_metas, &meta_out); using kernel_signature = void (*)(const phi::DeviceContext&, const std::vector&, phi::SelectedRows*); auto* kernel_fn = kernel.GetVariadicKernelFn(); (*kernel_fn)(*dev_ctx, input_x, kernel_out); } else { #ifdef PADDLE_WITH_DISTRIBUTE bool run_auto_parallel = AllInputsAreDistTensor(x); bool rank_is_in_current_mesh = true; if (run_auto_parallel) { auto mesh = std::static_pointer_cast(x[0].impl()) ->dist_attr() .process_mesh(); rank_is_in_current_mesh = phi::distributed::IsCurRankInMesh(mesh); std::vector input_x(x.size()); for (size_t i = 0; i < input_x.size(); ++i) { input_x[i] = x[i].impl().get(); } auto meta_dist_input_x = MakeDistMetaTensor(input_x); auto spmd_info = phi::distributed::VariadicReplicatedInferSpmdDynamic( meta_dist_input_x); auto dist_out = SetKernelDistOutput(&api_output); auto dense_out = dist_out->unsafe_mutable_value(); if (!rank_is_in_current_mesh) { *dense_out = phi::DenseTensor( std::make_shared( nullptr, 0, phi::distributed::GetDefaultPlace()), phi::DenseTensorMeta()); } phi::MetaTensor meta_dist_out(dist_out); auto x_meta_vec = MakeMetaTensor(input_x); std::vector x_metas(x_meta_vec.size()); for (size_t i = 0; i < x_meta_vec.size(); ++i) { x_metas[i] = &x_meta_vec[i]; } phi::AddNInferMeta(x_metas, &meta_dist_out); if (rank_is_in_current_mesh) { auto dist_input_x = ReshardApiInputToKernelInput(dev_ctx, x, spmd_info.first[0]); dist_input_x = PrepareDataForDistTensor( dist_input_x, GetKernelInputArgDef(kernel.InputAt(0), kernel_backend), {}, kernel_result.is_stride_kernel); std::vector input_x(dist_input_x.size()); for (size_t i = 0; i < dist_input_x.size(); ++i) { input_x[i] = dist_input_x[i]->unsafe_mutable_value(); } auto x_meta_vec = MakeMetaTensor(input_x); std::vector x_metas(x_meta_vec.size()); for (size_t i = 0; i < x_meta_vec.size(); ++i) { x_metas[i] = &x_meta_vec[i]; } phi::MetaTensor meta_dense_out(dense_out); phi::AddNInferMeta(x_metas, &meta_dense_out); using kernel_signature = void (*)(const phi::DeviceContext&, const std::vector&, phi::DenseTensor*); auto* kernel_fn = kernel.GetVariadicKernelFn(); (*kernel_fn)(*dev_ctx, input_x, dense_out); } PADDLE_ENFORCE_EQ(paddle::holds_alternative< std::vector>( spmd_info.first[0]), true, common::errors::PreconditionNotMet( "Arg must be a vector of TensorDistAttr")); auto current_process_mesh = paddle::get<1>(spmd_info.first[0]).at(0).process_mesh(); SetReplicatedDistAttrForOutput(dist_out, current_process_mesh); return api_output; } #endif std::vector input_x(x.size()); std::vector> temp_dense_tensors; temp_dense_tensors.reserve(x.size()); for (size_t i = 0; i < input_x.size(); ++i) { if (phi::DenseTensor::classof(x[i].impl().get())) { temp_dense_tensors.push_back( PrepareData(x[i], kernel.InputAt(0), {}, false)); input_x[i] = temp_dense_tensors.back().get(); } else { input_x[i] = x[i].impl().get(); } } auto x_meta_vec = MakeMetaTensor(input_x); std::vector x_metas(x_meta_vec.size()); for (size_t i = 0; i < x_meta_vec.size(); ++i) { x_metas[i] = &x_meta_vec[i]; } auto kernel_out = SetKernelOutput(&api_output); phi::MetaTensor meta_out(kernel_out); std::vector output_metas_for_compact; output_metas_for_compact.push_back(&meta_out); phi::AddNInferMeta(x_metas, &meta_out); CheckAndDoCompact(output_metas_for_compact, "add_n"); using kernel_signature = void (*)(const phi::DeviceContext&, const std::vector&, phi::DenseTensor*); auto* kernel_fn = kernel.GetVariadicKernelFn(); (*kernel_fn)(*dev_ctx, input_x, kernel_out); if (kernel_result.has_fallback_cpu) { TransDataBackend(kernel_out, kernel_backend, kernel_out); } } return api_output; } Tensor copy_to_impl(const Tensor& x, Place place, bool blocking) { Tensor out; copy(x, place, blocking, &out); out.set_name(x.name()); return out; } std::tuple fused_gemm_epilogue_impl( const Tensor& x, const Tensor& y, const Tensor& bias, bool trans_x, bool trans_y, const std::string& activation) { // Kernel Key Construction Backend kernel_backend = Backend::UNDEFINED; DataLayout kernel_layout = DataLayout::UNDEFINED; DataType kernel_data_type = DataType::UNDEFINED; if (kernel_backend == Backend::UNDEFINED || kernel_layout == DataLayout::UNDEFINED || kernel_data_type == DataType::UNDEFINED) { auto kernel_key_set = ParseKernelKeyByInputArgs(x, y, bias); auto kernel_key = kernel_key_set.GetHighestPriorityKernelKey(); if (kernel_backend == Backend::UNDEFINED) { kernel_backend = kernel_key.backend(); } if (kernel_layout == DataLayout::UNDEFINED) { kernel_layout = kernel_key.layout(); } if (kernel_data_type == DataType::UNDEFINED) { kernel_data_type = kernel_key.dtype(); } } #ifdef PADDLE_WITH_DISTRIBUTE bool run_auto_parallel = AllInputsAreDistTensor(x, y, bias); bool rank_is_in_current_mesh = true; if (run_auto_parallel) { auto mesh = std::static_pointer_cast(bias.impl()) ->dist_attr() .process_mesh(); rank_is_in_current_mesh = phi::distributed::IsCurRankInMesh(mesh); } // Kernel Dispatch Body // Auto Parallel condition if (run_auto_parallel) { // 1. InferSpmd (Infer DistAttr of Inputs&Outputs) auto meta_dist_input_x = MakeDistMetaTensor(*x.impl()); auto meta_dist_input_y = MakeDistMetaTensor(*y.impl()); auto meta_dist_input_bias = MakeDistMetaTensor(*bias.impl()); auto spmd_info = phi::distributed::FusedGemmEpilogueInferSpmd(meta_dist_input_x, meta_dist_input_y, meta_dist_input_bias, trans_x, trans_y, activation); DebugInfoForInferSpmd("fused_gemm_epilogue", spmd_info); // 2. Create API Output & Prepare Dist and Dense Output phi::DeviceContext* dev_ctx = nullptr; std::tuple api_output; auto dist_out_0 = SetKernelDistOutput(&std::get<0>(api_output), spmd_info.second[0]); auto dense_out_0 = dist_out_0 ? dist_out_0->unsafe_mutable_value() : nullptr; if (!rank_is_in_current_mesh) { *dense_out_0 = phi::DenseTensor(std::make_shared( nullptr, 0, phi::distributed::GetDefaultPlace()), phi::DenseTensorMeta()); } phi::distributed::DistTensor* dist_out_1 = nullptr; if (activation != "none") { dist_out_1 = SetKernelDistOutput(&std::get<1>(api_output), spmd_info.second[1]); } auto dense_out_1 = dist_out_1 ? dist_out_1->unsafe_mutable_value() : nullptr; if (!rank_is_in_current_mesh) { *dense_out_1 = phi::DenseTensor(std::make_shared( nullptr, 0, phi::distributed::GetDefaultPlace()), phi::DenseTensorMeta()); } // 3. Infer DistTensor's Global Shape phi::MetaTensor meta_dist_out_0(dist_out_0); phi::MetaTensor meta_dist_out_1(dist_out_1); phi::FusedGemmEpilogueInferMeta(MakeMetaTensor(*x.impl()), MakeMetaTensor(*y.impl()), MakeMetaTensor(*bias.impl()), trans_x, trans_y, activation, dist_out_0 ? &meta_dist_out_0 : nullptr, dist_out_1 ? &meta_dist_out_1 : nullptr); if (rank_is_in_current_mesh) { // 4. Select Kernel VLOG(6) << "fused_gemm_epilogue API dist branch: kernel key: [" << kernel_backend << ", " << kernel_layout << ", " << kernel_data_type << "]"; auto kernel_result = phi::KernelFactory::Instance().SelectKernelOrThrowError( "fused_gemm_epilogue", {kernel_backend, kernel_layout, kernel_data_type}); const auto& kernel = kernel_result.kernel; VLOG(6) << "fused_gemm_epilogue kernel: " << kernel; dev_ctx = GetDeviceContextByBackend( kernel_result.has_fallback_cpu ? Backend::CPU : kernel_backend); // 5. Reshard Input auto dist_input_x = ReshardApiInputToKernelInput(dev_ctx, x, spmd_info.first[0], "x"); auto dist_input_y = ReshardApiInputToKernelInput(dev_ctx, y, spmd_info.first[1], "y"); auto dist_input_bias = ReshardApiInputToKernelInput( dev_ctx, bias, spmd_info.first[2], "bias"); // 6. PrepareData (DataTransform & Prepare Dense Input) dist_input_x = PrepareDataForDistTensor( dist_input_x, GetKernelInputArgDef(kernel.InputAt(0), kernel_backend), {}, kernel_result.is_stride_kernel); auto input_x = &dist_input_x->value(); dist_input_y = PrepareDataForDistTensor( dist_input_y, GetKernelInputArgDef(kernel.InputAt(1), kernel_backend), {}, kernel_result.is_stride_kernel); auto input_y = &dist_input_y->value(); dist_input_bias = PrepareDataForDistTensor( dist_input_bias, GetKernelInputArgDef(kernel.InputAt(2), kernel_backend), {}, kernel_result.is_stride_kernel); auto input_bias = &dist_input_bias->value(); // 7. RecordOpInfoSupplement if (phi::RecordOpInfoSupplement::IsEnabled()) { std::vector>> input_shapes{{"x", {(*input_x).dims()}}, {"y", {(*input_y).dims()}}, {"bias", {(*input_bias).dims()}}}; phi::AttributeMap attrs; attrs["trans_x"] = trans_x; attrs["trans_y"] = trans_y; attrs["activation"] = activation; phi::RecordOpInfoSupplement("fused_gemm_epilogue", input_shapes, attrs); } // 8. Infer Local DenseTensor Meta phi::MetaTensor meta_dense_out_0(dense_out_0); phi::MetaTensor meta_dense_out_1(dense_out_1); phi::FusedGemmEpilogueInferMeta( MakeMetaTensor(*input_x), MakeMetaTensor(*input_y), MakeMetaTensor(*input_bias), trans_x, trans_y, activation, dense_out_0 ? &meta_dense_out_0 : nullptr, dense_out_1 ? &meta_dense_out_1 : nullptr); // 9. DenseTensor Kernel Call phi::RecordEvent* kernel_record_event = nullptr; if (phi::RecordEvent::IsEnabled()) { kernel_record_event = new phi::RecordEvent("fused_gemm_epilogue dist compute", phi::TracerEventType::DygraphKernelLaunch, 1); } using kernel_signature = void (*)(const phi::DeviceContext&, const phi::DenseTensor&, const phi::DenseTensor&, const phi::DenseTensor&, bool, bool, const std::string&, phi::DenseTensor*, phi::DenseTensor*); auto* kernel_fn = kernel.GetVariadicKernelFn(); (*kernel_fn)(*dev_ctx, *input_x, *input_y, *input_bias, trans_x, trans_y, activation, dense_out_0, dense_out_1); if (FLAGS_benchmark) { dev_ctx->Wait(); std::cout << "fused_gemm_epilogue kernel run finish." << std::endl; } if (kernel_record_event != nullptr) { delete kernel_record_event; } // 10. Fallback if (kernel_result.has_fallback_cpu) { TransDataBackend(dense_out_0, kernel_backend, dense_out_0); TransDataBackend(dense_out_1, kernel_backend, dense_out_1); } } // 11. Set Output Dist Attr For Default Impl // API `fused_gemm_epilogue` does not need to set DistAttr for output. // 12. Return return api_output; } #endif // PADDLE_WITH_DISTRIBUTE VLOG(6) << "fused_gemm_epilogue API kernel key: [" << kernel_backend << ", " << kernel_layout << ", " << kernel_data_type << "]"; auto kernel_result = phi::KernelFactory::Instance().SelectKernelOrThrowError( "fused_gemm_epilogue", {kernel_backend, kernel_layout, kernel_data_type}, true); const auto& kernel = kernel_result.kernel; if (FLAGS_low_precision_op_list) { phi::KernelFactory::Instance().AddToLowPrecisionKernelList( "fused_gemm_epilogue", kernel_data_type); } VLOG(6) << "fused_gemm_epilogue kernel: " << kernel; // add actual_kernel_backend to select actual kernel backend after a potential // falling-back to CPU Backend actual_kernel_backend = kernel_result.has_fallback_cpu ? Backend::CPU : kernel_backend; auto* dev_ctx = GetDeviceContextByBackend(actual_kernel_backend); auto input_x = PrepareData( x, GetKernelInputArgDef(kernel.InputAt(0), actual_kernel_backend), {}, kernel_result.is_stride_kernel); auto input_y = PrepareData( y, GetKernelInputArgDef(kernel.InputAt(1), actual_kernel_backend), {}, kernel_result.is_stride_kernel); auto input_bias = PrepareData( bias, GetKernelInputArgDef(kernel.InputAt(2), actual_kernel_backend), {}, kernel_result.is_stride_kernel); if (phi::RecordOpInfoSupplement::IsEnabled()) { std::vector>> input_shapes{ {"x", {(*input_x).dims()}}, {"y", {(*input_y).dims()}}, {"bias", {(*input_bias).dims()}}}; phi::AttributeMap attrs; attrs["trans_x"] = trans_x; attrs["trans_y"] = trans_y; attrs["activation"] = activation; phi::RecordOpInfoSupplement("fused_gemm_epilogue", input_shapes, attrs); } std::tuple api_output; auto kernel_out_0 = SetKernelOutput(&std::get<0>(api_output)); phi::DenseTensor* kernel_out_1 = nullptr; if (activation != "none") { kernel_out_1 = SetKernelOutput(&std::get<1>(api_output)); } phi::RecordEvent* infer_shape_record_event = nullptr; if (phi::RecordEvent::IsEnabled()) { infer_shape_record_event = new phi::RecordEvent("fused_gemm_epilogue infer_meta", phi::TracerEventType::OperatorInner, 1); } phi::MetaTensor meta_out_0(kernel_out_0, kernel_result.is_stride_kernel); phi::MetaTensor meta_out_1(kernel_out_1, kernel_result.is_stride_kernel); std::vector output_metas_for_compact; if (kernel_out_0) output_metas_for_compact.push_back(&meta_out_0); if (kernel_out_1) output_metas_for_compact.push_back(&meta_out_1); phi::FusedGemmEpilogueInferMeta(MakeMetaTensor(*input_x), MakeMetaTensor(*input_y), MakeMetaTensor(*input_bias), trans_x, trans_y, activation, kernel_out_0 ? &meta_out_0 : nullptr, kernel_out_1 ? &meta_out_1 : nullptr); CheckAndDoCompact(output_metas_for_compact, "fused_gemm_epilogue"); if (infer_shape_record_event != nullptr) { delete infer_shape_record_event; } using kernel_signature = void (*)(const phi::DeviceContext&, const phi::DenseTensor&, const phi::DenseTensor&, const phi::DenseTensor&, bool, bool, const std::string&, phi::DenseTensor*, phi::DenseTensor*); auto* kernel_fn = kernel.GetVariadicKernelFn(); phi::RecordEvent* kernel_record_event = nullptr; if (phi::RecordEvent::IsEnabled()) { kernel_record_event = new phi::RecordEvent("fused_gemm_epilogue kernel launch", phi::TracerEventType::DygraphKernelLaunch, 1); } (*kernel_fn)(*dev_ctx, *input_x, *input_y, *input_bias, trans_x, trans_y, activation, kernel_out_0, kernel_out_1); if (FLAGS_benchmark) { dev_ctx->Wait(); std::cout << "fused_gemm_epilogue kernel run finish." << std::endl; } if (kernel_record_event != nullptr) { delete kernel_record_event; } if (kernel_result.has_fallback_cpu) { TransDataBackend(kernel_out_0, kernel_backend, kernel_out_0); TransDataBackend(kernel_out_1, kernel_backend, kernel_out_1); } return api_output; } // weight_list.size() should be weight_list.get_ptr()->size() but can't modify // yaml file std::tuple> cudnn_lstm_grad_impl( const Tensor& x, const Tensor& init_h, const Tensor& init_c, const paddle::optional>& weight_list, const paddle::optional& sequence_length, const Tensor& out, const Tensor& reserve, const Tensor& state_out, const Tensor& out_grad, const Tensor& last_h_grad, const Tensor& last_c_grad, float dropout_prob, bool is_bidirec, int hidden_size, int num_layers, bool is_test, int seed) { // Kernel Key Construction Backend kernel_backend = Backend::UNDEFINED; DataLayout kernel_layout = DataLayout::UNDEFINED; DataType kernel_data_type = DataType::UNDEFINED; #ifdef PADDLE_WITH_DISTRIBUTE bool run_auto_parallel = AllInputsAreDistTensor(x, init_h, init_c, weight_list, sequence_length, out, reserve, state_out, out_grad, last_h_grad, last_c_grad); bool rank_is_in_current_mesh = true; if (run_auto_parallel) { auto mesh = std::static_pointer_cast( last_c_grad.impl()) ->dist_attr() .process_mesh(); rank_is_in_current_mesh = phi::distributed::IsCurRankInMesh(mesh); } if (rank_is_in_current_mesh) { kernel_data_type = ParseDataType(out_grad); if (kernel_backend == Backend::UNDEFINED || kernel_layout == DataLayout::UNDEFINED || kernel_data_type == DataType::UNDEFINED) { auto kernel_key_set = ParseKernelKeyByInputArgs(x, init_h, init_c, weight_list, sequence_length, out, reserve, state_out, out_grad, last_h_grad, last_c_grad); auto kernel_key = kernel_key_set.GetHighestPriorityKernelKey(); if (kernel_backend == Backend::UNDEFINED) { kernel_backend = kernel_key.backend(); } if (kernel_layout == DataLayout::UNDEFINED) { kernel_layout = kernel_key.layout(); } if (kernel_data_type == DataType::UNDEFINED) { kernel_data_type = kernel_key.dtype(); } } } // Kernel Dispatch Body // Auto Parallel condition if (run_auto_parallel) { // 1. InferSpmd (Infer DistAttr of Inputs&Outputs) auto meta_dist_input_x = MakeDistMetaTensor(*x.impl()); auto meta_dist_input_init_h = MakeDistMetaTensor(*init_h.impl()); auto meta_dist_input_init_c = MakeDistMetaTensor(*init_c.impl()); std::vector meta_dist_input_weight_list; if (weight_list) { for (auto& e : *weight_list) { meta_dist_input_weight_list.push_back(MakeDistMetaTensor(*e.impl())); } } auto meta_dist_input_sequence_length = sequence_length ? MakeDistMetaTensor(*(*sequence_length).impl()) : phi::distributed::DistMetaTensor(); auto meta_dist_input_out = MakeDistMetaTensor(*out.impl()); auto meta_dist_input_reserve = MakeDistMetaTensor(*reserve.impl()); auto meta_dist_input_state_out = MakeDistMetaTensor(*state_out.impl()); auto meta_dist_input_out_grad = MakeDistMetaTensor(*out_grad.impl()); auto meta_dist_input_last_h_grad = MakeDistMetaTensor(*last_h_grad.impl()); auto meta_dist_input_last_c_grad = MakeDistMetaTensor(*last_c_grad.impl()); auto spmd_info = phi::distributed::VariadicReplicatedInferSpmdDynamic( meta_dist_input_x, meta_dist_input_init_h, meta_dist_input_init_c, meta_dist_input_weight_list, meta_dist_input_sequence_length, meta_dist_input_out, meta_dist_input_reserve, meta_dist_input_state_out, meta_dist_input_out_grad, meta_dist_input_last_h_grad, meta_dist_input_last_c_grad); DebugInfoForInferSpmd("cudnn_lstm_grad", spmd_info); // 2. Create API Output & Prepare Dist and Dense Output phi::DeviceContext* dev_ctx = nullptr; std::tuple> api_output; auto dist_out_0 = SetKernelDistOutput(&std::get<0>(api_output)); auto dense_out_0 = dist_out_0 ? dist_out_0->unsafe_mutable_value() : nullptr; if (!rank_is_in_current_mesh) { *dense_out_0 = phi::DenseTensor(std::make_shared( nullptr, 0, phi::distributed::GetDefaultPlace()), phi::DenseTensorMeta()); } auto dist_out_1 = SetKernelDistOutput(&std::get<1>(api_output)); auto dense_out_1 = dist_out_1 ? dist_out_1->unsafe_mutable_value() : nullptr; if (!rank_is_in_current_mesh) { *dense_out_1 = phi::DenseTensor(std::make_shared( nullptr, 0, phi::distributed::GetDefaultPlace()), phi::DenseTensorMeta()); } auto dist_out_2 = SetKernelDistOutput(&std::get<2>(api_output)); auto dense_out_2 = dist_out_2 ? dist_out_2->unsafe_mutable_value() : nullptr; if (!rank_is_in_current_mesh) { *dense_out_2 = phi::DenseTensor(std::make_shared( nullptr, 0, phi::distributed::GetDefaultPlace()), phi::DenseTensorMeta()); } auto dist_out_3 = SetKernelDistOutput(weight_list.get_ptr()->size(), &std::get<3>(api_output)); std::vector dense_out_3(dist_out_3.size()); for (size_t i = 0; i < dist_out_3.size(); ++i) { dense_out_3[i] = const_cast(&dist_out_3[i]->value()); if (!rank_is_in_current_mesh) { *dense_out_3[i] = phi::DenseTensor( std::make_shared( nullptr, 0, phi::distributed::GetDefaultPlace()), phi::DenseTensorMeta()); } } // 3. Infer DistTensor's Global Shape phi::MetaTensor meta_dist_out_0(dist_out_0); phi::MetaTensor meta_dist_out_1(dist_out_1); phi::MetaTensor meta_dist_out_2(dist_out_2); std::vector dist_out_3_meta_vec; for (phi::distributed::DistTensor* tmp : dist_out_3) { dist_out_3_meta_vec.emplace_back(phi::MetaTensor(tmp)); } std::vector dist_out_3_meta_ptr_vec(dist_out_3.size()); for (size_t i = 0; i < dist_out_3_meta_vec.size(); ++i) { dist_out_3_meta_ptr_vec[i] = dist_out_3[i] ? &dist_out_3_meta_vec[i] : nullptr; } std::vector weight_list_meta_vec_tmp; if (weight_list) { for (auto tmp : *weight_list) { weight_list_meta_vec_tmp.emplace_back(MakeMetaTensor(*tmp.impl())); } } std::vector weight_list_meta_ptr_vec_tmp( weight_list_meta_vec_tmp.size()); for (size_t i = 0; i < weight_list_meta_ptr_vec_tmp.size(); ++i) { weight_list_meta_ptr_vec_tmp[i] = &weight_list_meta_vec_tmp[i]; } paddle::optional> weight_list_meta_ptr_vec = weight_list ? paddle::make_optional>( weight_list_meta_ptr_vec_tmp) : paddle::none; phi::CudnnLSTMGradInferMeta(MakeMetaTensor(*x.impl()), MakeMetaTensor(*init_h.impl()), MakeMetaTensor(*init_c.impl()), weight_list_meta_ptr_vec, dist_out_0 ? &meta_dist_out_0 : nullptr, dist_out_1 ? &meta_dist_out_1 : nullptr, dist_out_2 ? &meta_dist_out_2 : nullptr, dist_out_3_meta_ptr_vec); if (rank_is_in_current_mesh) { // 4. Select Kernel VLOG(6) << "cudnn_lstm_grad API dist branch: kernel key: [" << kernel_backend << ", " << kernel_layout << ", " << kernel_data_type << "]"; auto kernel_result = phi::KernelFactory::Instance().SelectKernelOrThrowError( "cudnn_lstm_grad", {kernel_backend, kernel_layout, kernel_data_type}); const auto& kernel = kernel_result.kernel; VLOG(6) << "cudnn_lstm_grad kernel: " << kernel; dev_ctx = GetDeviceContextByBackend( kernel_result.has_fallback_cpu ? Backend::CPU : kernel_backend); // 5. Reshard Input auto dist_input_x = ReshardApiInputToKernelInput(dev_ctx, x, spmd_info.first[0], "x"); auto dist_input_init_h = ReshardApiInputToKernelInput( dev_ctx, init_h, spmd_info.first[1], "init_h"); auto dist_input_init_c = ReshardApiInputToKernelInput( dev_ctx, init_c, spmd_info.first[2], "init_c"); auto dist_input_weight_list = ReshardApiInputToKernelInput( dev_ctx, weight_list, spmd_info.first[3], "weight_list"); auto dist_input_sequence_length = ReshardApiInputToKernelInput( dev_ctx, sequence_length, spmd_info.first[4], "sequence_length"); auto dist_input_out = ReshardApiInputToKernelInput(dev_ctx, out, spmd_info.first[5], "out"); auto dist_input_reserve = ReshardApiInputToKernelInput( dev_ctx, reserve, spmd_info.first[6], "reserve"); auto dist_input_state_out = ReshardApiInputToKernelInput( dev_ctx, state_out, spmd_info.first[7], "state_out"); auto dist_input_out_grad = ReshardApiInputToKernelInput( dev_ctx, out_grad, spmd_info.first[8], "out_grad"); auto dist_input_last_h_grad = ReshardApiInputToKernelInput( dev_ctx, last_h_grad, spmd_info.first[9], "last_h_grad"); auto dist_input_last_c_grad = ReshardApiInputToKernelInput( dev_ctx, last_c_grad, spmd_info.first[10], "last_c_grad"); // 6. PrepareData (DataTransform & Prepare Dense Input) dist_input_x = PrepareDataForDistTensor( dist_input_x, GetKernelInputArgDef(kernel.InputAt(0), kernel_backend), {}, kernel_result.is_stride_kernel); auto input_x = &dist_input_x->value(); dist_input_init_h = PrepareDataForDistTensor( dist_input_init_h, GetKernelInputArgDef(kernel.InputAt(1), kernel_backend), {}, kernel_result.is_stride_kernel); auto input_init_h = &dist_input_init_h->value(); dist_input_init_c = PrepareDataForDistTensor( dist_input_init_c, GetKernelInputArgDef(kernel.InputAt(2), kernel_backend), {}, kernel_result.is_stride_kernel); auto input_init_c = &dist_input_init_c->value(); auto dist_input_weight_list_vec = PrepareDataForDistTensor( dist_input_weight_list, GetKernelInputArgDef(kernel.InputAt(3), kernel_backend), {}, kernel_result.is_stride_kernel); std::vector dense_input_weight_list_vec; if (weight_list) { for (auto tmp : *dist_input_weight_list_vec) { dense_input_weight_list_vec.emplace_back(&tmp->value()); } } paddle::optional> input_weight_list( dense_input_weight_list_vec); std::vector dense_input_weight_list_meta_vec = MakeMetaTensor(dense_input_weight_list_vec); std::vector dense_input_weight_list_meta_ptr_vec_tmp( dense_input_weight_list_meta_vec.size()); for (size_t i = 0; i < dense_input_weight_list_meta_ptr_vec_tmp.size(); ++i) { dense_input_weight_list_meta_ptr_vec_tmp[i] = &dense_input_weight_list_meta_vec[i]; } paddle::optional> dense_input_weight_list_meta_ptr_vec = weight_list ? paddle::make_optional>( dense_input_weight_list_meta_ptr_vec_tmp) : paddle::none; dist_input_sequence_length = PrepareDataForDistTensor( dist_input_sequence_length, GetKernelInputArgDef(kernel.InputAt(4), kernel_backend), {}, kernel_result.is_stride_kernel); paddle::optional input_sequence_length = dist_input_sequence_length ? paddle::make_optional( (*dist_input_sequence_length)->value()) : paddle::none; dist_input_out = PrepareDataForDistTensor( dist_input_out, GetKernelInputArgDef(kernel.InputAt(5), kernel_backend), {}, kernel_result.is_stride_kernel); auto input_out = &dist_input_out->value(); dist_input_reserve = PrepareDataForDistTensor( dist_input_reserve, GetKernelInputArgDef(kernel.InputAt(6), kernel_backend), {}, kernel_result.is_stride_kernel); auto input_reserve = &dist_input_reserve->value(); dist_input_state_out = PrepareDataForDistTensor( dist_input_state_out, GetKernelInputArgDef(kernel.InputAt(7), kernel_backend), {}, kernel_result.is_stride_kernel); auto input_state_out = &dist_input_state_out->value(); dist_input_out_grad = PrepareDataForDistTensor( dist_input_out_grad, GetKernelInputArgDef(kernel.InputAt(8), kernel_backend), {}, kernel_result.is_stride_kernel); auto input_out_grad = &dist_input_out_grad->value(); dist_input_last_h_grad = PrepareDataForDistTensor( dist_input_last_h_grad, GetKernelInputArgDef(kernel.InputAt(9), kernel_backend), {}, kernel_result.is_stride_kernel); auto input_last_h_grad = &dist_input_last_h_grad->value(); dist_input_last_c_grad = PrepareDataForDistTensor( dist_input_last_c_grad, GetKernelInputArgDef(kernel.InputAt(10), kernel_backend), {}, kernel_result.is_stride_kernel); auto input_last_c_grad = &dist_input_last_c_grad->value(); // 7. RecordOpInfoSupplement if (phi::RecordOpInfoSupplement::IsEnabled()) { std::vector sequence_length_record_shapes; if (input_sequence_length) { sequence_length_record_shapes.push_back( (*input_sequence_length).dims()); } std::vector>> input_shapes{{"x", {(*input_x).dims()}}, {"init_h", {(*input_init_h).dims()}}, {"init_c", {(*input_init_c).dims()}}, {"sequence_length", sequence_length_record_shapes}, {"out", {(*input_out).dims()}}, {"reserve", {(*input_reserve).dims()}}, {"state_out", {(*input_state_out).dims()}}, {"out_grad", {(*input_out_grad).dims()}}, {"last_h_grad", {(*input_last_h_grad).dims()}}, {"last_c_grad", {(*input_last_c_grad).dims()}}}; std::vector ddims_vec; ddims_vec.clear(); if (input_weight_list) { ddims_vec.reserve(input_weight_list->size()); for (size_t i = 0; i < input_weight_list->size(); ++i) { ddims_vec.emplace_back((*input_weight_list->at(i)).dims()); } } input_shapes.emplace_back("weight_list", ddims_vec); phi::AttributeMap attrs; attrs["dropout_prob"] = dropout_prob; attrs["is_bidirec"] = is_bidirec; attrs["hidden_size"] = hidden_size; attrs["num_layers"] = num_layers; attrs["is_test"] = is_test; attrs["seed"] = seed; phi::RecordOpInfoSupplement("cudnn_lstm_grad", input_shapes, attrs); } // 8. Infer Local DenseTensor Meta phi::MetaTensor meta_dense_out_0(dense_out_0); phi::MetaTensor meta_dense_out_1(dense_out_1); phi::MetaTensor meta_dense_out_2(dense_out_2); std::vector dense_out_3_meta_vec = MakeMetaTensor(dense_out_3); std::vector dense_out_3_meta_ptr_vec( dense_out_3_meta_vec.size()); for (size_t i = 0; i < dense_out_3_meta_vec.size(); ++i) { dense_out_3_meta_ptr_vec[i] = dense_out_3[i] ? &dense_out_3_meta_vec[i] : nullptr; } phi::CudnnLSTMGradInferMeta(MakeMetaTensor(*input_x), MakeMetaTensor(*input_init_h), MakeMetaTensor(*input_init_c), dense_input_weight_list_meta_ptr_vec, dense_out_0 ? &meta_dense_out_0 : nullptr, dense_out_1 ? &meta_dense_out_1 : nullptr, dense_out_2 ? &meta_dense_out_2 : nullptr, dense_out_3_meta_ptr_vec); // 9. DenseTensor Kernel Call phi::RecordEvent* kernel_record_event = nullptr; if (phi::RecordEvent::IsEnabled()) { kernel_record_event = new phi::RecordEvent("cudnn_lstm_grad dist compute", phi::TracerEventType::DygraphKernelLaunch, 1); } using kernel_signature = void (*)( const phi::DeviceContext&, const phi::DenseTensor&, const phi::DenseTensor&, const phi::DenseTensor&, const paddle::optional>&, const paddle::optional&, const phi::DenseTensor&, const phi::DenseTensor&, const phi::DenseTensor&, const phi::DenseTensor&, const phi::DenseTensor&, const phi::DenseTensor&, float, bool, int, int, bool, int, phi::DenseTensor*, phi::DenseTensor*, phi::DenseTensor*, std::vector); auto* kernel_fn = kernel.GetVariadicKernelFn(); (*kernel_fn)(*dev_ctx, *input_x, *input_init_h, *input_init_c, input_weight_list, input_sequence_length, *input_out, *input_reserve, *input_state_out, *input_out_grad, *input_last_h_grad, *input_last_c_grad, dropout_prob, is_bidirec, hidden_size, num_layers, is_test, seed, dense_out_0, dense_out_1, dense_out_2, dense_out_3); if (FLAGS_benchmark) { dev_ctx->Wait(); std::cout << "cudnn_lstm_grad kernel run finish." << std::endl; } if (kernel_record_event != nullptr) { delete kernel_record_event; } // 10. Fallback if (kernel_result.has_fallback_cpu) { TransDataBackend(dense_out_0, kernel_backend, dense_out_0); TransDataBackend(dense_out_1, kernel_backend, dense_out_1); TransDataBackend(dense_out_2, kernel_backend, dense_out_2); TransDataBackend(dense_out_3, kernel_backend, dense_out_3); } } // 11. Set Output Dist Attr For Default Impl auto current_process_mesh = paddle::holds_alternative( spmd_info.first[0]) ? paddle::get<0>(spmd_info.first[0]).process_mesh() : paddle::get<1>(spmd_info.first[0]).at(0).process_mesh(); SetReplicatedDistAttrForOutput(dist_out_0, current_process_mesh); SetReplicatedDistAttrForOutput(dist_out_1, current_process_mesh); SetReplicatedDistAttrForOutput(dist_out_2, current_process_mesh); for (size_t i = 0; i < dist_out_3.size(); ++i) { SetReplicatedDistAttrForOutput(dist_out_3[i], current_process_mesh); } // 12. Return return api_output; } #endif // PADDLE_WITH_DISTRIBUTE VLOG(6) << "cudnn_lstm_grad API kernel key: [" << kernel_backend << ", " << kernel_layout << ", " << kernel_data_type << "]"; auto kernel_result = phi::KernelFactory::Instance().SelectKernelOrThrowError( "cudnn_lstm_grad", {kernel_backend, kernel_layout, kernel_data_type}, true); const auto& kernel = kernel_result.kernel; if (FLAGS_low_precision_op_list) { phi::KernelFactory::Instance().AddToLowPrecisionKernelList( "cudnn_lstm_grad", kernel_data_type); } VLOG(6) << "cudnn_lstm_grad kernel: " << kernel; // add actual_kernel_backend to select actual kernel backend after a potential // falling-back to CPU Backend actual_kernel_backend = kernel_result.has_fallback_cpu ? Backend::CPU : kernel_backend; auto* dev_ctx = GetDeviceContextByBackend(actual_kernel_backend); auto input_x = PrepareData( x, GetKernelInputArgDef(kernel.InputAt(0), actual_kernel_backend), {}, kernel_result.is_stride_kernel); auto input_init_h = PrepareData( init_h, GetKernelInputArgDef(kernel.InputAt(1), actual_kernel_backend), {}, kernel_result.is_stride_kernel); auto input_init_c = PrepareData( init_c, GetKernelInputArgDef(kernel.InputAt(2), actual_kernel_backend), {}, kernel_result.is_stride_kernel); auto input_weight_list_vec = PrepareData( weight_list, GetKernelInputArgDef(kernel.InputAt(3), actual_kernel_backend), {}, kernel_result.is_stride_kernel); paddle::optional> input_weight_list; if (input_weight_list_vec) { input_weight_list = paddle::optional>( input_weight_list_vec->size()); for (size_t i = 0; i < input_weight_list_vec->size(); ++i) { input_weight_list->at(i) = &input_weight_list_vec->at(i); } } auto input_sequence_length = PrepareData( sequence_length, GetKernelInputArgDef(kernel.InputAt(4), actual_kernel_backend), {}, kernel_result.is_stride_kernel); auto input_out = PrepareData( out, GetKernelInputArgDef(kernel.InputAt(5), actual_kernel_backend), {}, kernel_result.is_stride_kernel); auto input_reserve = PrepareData( reserve, GetKernelInputArgDef(kernel.InputAt(6), actual_kernel_backend), {}, kernel_result.is_stride_kernel); auto input_state_out = PrepareData( state_out, GetKernelInputArgDef(kernel.InputAt(7), actual_kernel_backend), {}, kernel_result.is_stride_kernel); auto input_out_grad = PrepareData( out_grad, GetKernelInputArgDef(kernel.InputAt(8), actual_kernel_backend), {}, kernel_result.is_stride_kernel); auto input_last_h_grad = PrepareData( last_h_grad, GetKernelInputArgDef(kernel.InputAt(9), actual_kernel_backend), {}, kernel_result.is_stride_kernel); auto input_last_c_grad = PrepareData( last_c_grad, GetKernelInputArgDef(kernel.InputAt(10), actual_kernel_backend), {}, kernel_result.is_stride_kernel); if (phi::RecordOpInfoSupplement::IsEnabled()) { std::vector sequence_length_record_shapes; if (input_sequence_length) { sequence_length_record_shapes.push_back((*input_sequence_length).dims()); } std::vector>> input_shapes{ {"x", {(*input_x).dims()}}, {"init_h", {(*input_init_h).dims()}}, {"init_c", {(*input_init_c).dims()}}, {"sequence_length", sequence_length_record_shapes}, {"out", {(*input_out).dims()}}, {"reserve", {(*input_reserve).dims()}}, {"state_out", {(*input_state_out).dims()}}, {"out_grad", {(*input_out_grad).dims()}}, {"last_h_grad", {(*input_last_h_grad).dims()}}, {"last_c_grad", {(*input_last_c_grad).dims()}}}; std::vector ddims_vec; ddims_vec.clear(); if (input_weight_list) { ddims_vec.reserve(input_weight_list->size()); for (size_t i = 0; i < input_weight_list->size(); ++i) { ddims_vec.emplace_back((*input_weight_list->at(i)).dims()); } } input_shapes.emplace_back("weight_list", ddims_vec); phi::AttributeMap attrs; attrs["dropout_prob"] = dropout_prob; attrs["is_bidirec"] = is_bidirec; attrs["hidden_size"] = hidden_size; attrs["num_layers"] = num_layers; attrs["is_test"] = is_test; attrs["seed"] = seed; phi::RecordOpInfoSupplement("cudnn_lstm_grad", input_shapes, attrs); } std::tuple> api_output; auto kernel_out_0 = SetKernelOutput(&std::get<0>(api_output)); auto kernel_out_1 = SetKernelOutput(&std::get<1>(api_output)); auto kernel_out_2 = SetKernelOutput(&std::get<2>(api_output)); auto kernel_out_3 = SetKernelOutput(weight_list.get_ptr()->size(), &std::get<3>(api_output)); phi::RecordEvent* infer_shape_record_event = nullptr; if (phi::RecordEvent::IsEnabled()) { infer_shape_record_event = new phi::RecordEvent( "cudnn_lstm_grad infer_meta", phi::TracerEventType::OperatorInner, 1); } auto weight_list_meta_vec = MakeMetaTensor(input_weight_list); paddle::optional> weight_list_metas( weight_list_meta_vec.size()); for (size_t i = 0; i < weight_list_meta_vec.size(); ++i) { weight_list_metas->at(i) = &weight_list_meta_vec[i]; } phi::MetaTensor meta_out_0(kernel_out_0, kernel_result.is_stride_kernel); phi::MetaTensor meta_out_1(kernel_out_1, kernel_result.is_stride_kernel); phi::MetaTensor meta_out_2(kernel_out_2, kernel_result.is_stride_kernel); auto kernel_out_3_meta_vec = MakeMetaTensor(kernel_out_3); std::vector kernel_out_3_metas( kernel_out_3_meta_vec.size()); for (size_t i = 0; i < kernel_out_3_meta_vec.size(); ++i) { kernel_out_3_metas[i] = kernel_out_3[i] ? &kernel_out_3_meta_vec[i] : nullptr; } std::vector output_metas_for_compact; if (kernel_out_0) output_metas_for_compact.push_back(&meta_out_0); if (kernel_out_1) output_metas_for_compact.push_back(&meta_out_1); if (kernel_out_2) output_metas_for_compact.push_back(&meta_out_1); output_metas_for_compact.insert(output_metas_for_compact.end(), kernel_out_3_metas.begin(), kernel_out_3_metas.end()); phi::CudnnLSTMGradInferMeta(MakeMetaTensor(*input_x), MakeMetaTensor(*input_init_h), MakeMetaTensor(*input_init_c), weight_list_metas, kernel_out_0 ? &meta_out_0 : nullptr, kernel_out_1 ? &meta_out_1 : nullptr, kernel_out_2 ? &meta_out_2 : nullptr, kernel_out_3_metas); CheckAndDoCompact(output_metas_for_compact, "cudnn_lstm_grad"); if (infer_shape_record_event != nullptr) { delete infer_shape_record_event; } using kernel_signature = void (*)(const phi::DeviceContext&, const phi::DenseTensor&, const phi::DenseTensor&, const phi::DenseTensor&, const paddle::optional>&, const paddle::optional&, const phi::DenseTensor&, const phi::DenseTensor&, const phi::DenseTensor&, const phi::DenseTensor&, const phi::DenseTensor&, const phi::DenseTensor&, float, bool, int, int, bool, int, phi::DenseTensor*, phi::DenseTensor*, phi::DenseTensor*, std::vector); auto* kernel_fn = kernel.GetVariadicKernelFn(); phi::RecordEvent* kernel_record_event = nullptr; if (phi::RecordEvent::IsEnabled()) { kernel_record_event = new phi::RecordEvent("cudnn_lstm_grad kernel launch", phi::TracerEventType::DygraphKernelLaunch, 1); } (*kernel_fn)(*dev_ctx, *input_x, *input_init_h, *input_init_c, input_weight_list, input_sequence_length, *input_out, *input_reserve, *input_state_out, *input_out_grad, *input_last_h_grad, *input_last_c_grad, dropout_prob, is_bidirec, hidden_size, num_layers, is_test, seed, kernel_out_0, kernel_out_1, kernel_out_2, kernel_out_3); if (FLAGS_benchmark) { dev_ctx->Wait(); std::cout << "cudnn_lstm_grad kernel run finish." << std::endl; } if (kernel_record_event != nullptr) { delete kernel_record_event; } if (kernel_result.has_fallback_cpu) { TransDataBackend(kernel_out_0, kernel_backend, kernel_out_0); TransDataBackend(kernel_out_1, kernel_backend, kernel_out_1); TransDataBackend(kernel_out_2, kernel_backend, kernel_out_2); TransDataBackend(kernel_out_3, kernel_backend, kernel_out_3); } return api_output; } ////////////////// Backward(grad) api impls ////////////////////// void embedding_grad_impl(const Tensor& x, const Tensor& weight, const Tensor& out_grad, int64_t padding_idx, bool sparse, Tensor* weight_grad) { DataType kernel_data_type = ParseDataType(weight); auto kernel_key_set = ParseKernelKeyByInputArgs(weight); auto kernel_key = kernel_key_set.GetHighestPriorityKernelKey(); VLOG(6) << "embedding_grad API kernel key: [" << kernel_key.backend() << ", " << kernel_key.layout() << ", " << kernel_data_type << "]"; if (phi::DenseTensor::classof(weight.impl().get()) || phi::distributed::DistTensor::classof(weight.impl().get())) { std::string kernel_name = sparse ? "embedding_sparse_grad" : "embedding_grad"; auto kernel_result = phi::KernelFactory::Instance().SelectKernelOrThrowError( kernel_name, {kernel_key.backend(), kernel_key.layout(), kernel_data_type}); const auto& kernel = kernel_result.kernel; VLOG(6) << kernel_name << " API kernel: " << kernel; auto* dev_ctx = GetDeviceContextByBackend( kernel_result.has_fallback_cpu ? Backend::CPU : kernel_key.backend()); #ifdef PADDLE_WITH_DISTRIBUTE bool run_auto_parallel = AllInputsAreDistTensor(x, weight, out_grad); // Auto Parallel condition if (run_auto_parallel) { bool rank_is_in_current_mesh = true; auto mesh = std::static_pointer_cast(x.impl()) ->dist_attr() .process_mesh(); rank_is_in_current_mesh = phi::distributed::IsCurRankInMesh(mesh); // 1. InferSpmd (Infer DistAttr of Inputs&Outputs) auto meta_dist_input_x = MakeDistMetaTensor(*x.impl()); auto meta_dist_input_weight = MakeDistMetaTensor(*weight.impl()); auto meta_dist_input_out_grad = MakeDistMetaTensor(*out_grad.impl()); auto spmd_info = phi::distributed::EmbeddingGradInferSpmd(meta_dist_input_x, meta_dist_input_weight, meta_dist_input_out_grad, padding_idx, sparse); // 2. Create Temporary Output & Prepare Dist and Dense Output std::shared_ptr shared_dist_out = CreateKernelDistOutput( weight_grad, !rank_is_in_current_mesh, spmd_info.second[0]); phi::distributed::DistTensor* dist_out = shared_dist_out.get(); phi::DenseTensor* dense_out = dist_out->unsafe_mutable_value(); if (dense_out && !rank_is_in_current_mesh && !dist_out->defined()) { *dense_out = phi::DenseTensor( std::make_shared( nullptr, 0, phi::distributed::GetDefaultPlace()), phi::DenseTensorMeta()); } // 3. Infer DistTensor's Global Shape phi::MetaTensor meta_dist_out(dist_out); UnchangedInferMeta(MakeMetaTensor(*weight.impl()), &meta_dist_out); // 4. Set Output Dist Attr For Default Impl if (rank_is_in_current_mesh) { // 5. Reshard Input auto dist_input_x = ReshardApiInputToKernelInput(dev_ctx, x, spmd_info.first[0]); auto dist_input_weight = ReshardApiInputToKernelInput(dev_ctx, weight, spmd_info.first[1]); auto dist_input_out_grad = ReshardApiInputToKernelInput(dev_ctx, out_grad, spmd_info.first[2]); // 6. PrepareData (DataTransform & Prepare Dense Input) dist_input_x = PrepareDataForDistTensor( dist_input_x, GetKernelInputArgDef(kernel.InputAt(0), kernel_key.backend()), {}, kernel_result.is_stride_kernel); auto input_x = &dist_input_x->value(); dist_input_weight = PrepareDataForDistTensor( dist_input_weight, GetKernelInputArgDef(kernel.InputAt(1), kernel_key.backend()), {}, kernel_result.is_stride_kernel); auto input_weight = &dist_input_weight->value(); dist_input_out_grad = PrepareDataForDistTensor( dist_input_out_grad, GetKernelInputArgDef(kernel.InputAt(2), kernel_key.backend()), {}, kernel_result.is_stride_kernel); auto input_out_grad = &dist_input_out_grad->value(); // 7. Infer Local DenseTensor Meta phi::MetaTensor meta_dense_out(dense_out); phi::EmbeddingGradInferMeta(MakeMetaTensor(*input_x), MakeMetaTensor(*input_weight), &meta_dense_out); // 8. DenseTensor Kernel Call using kernel_signature = void (*)(const phi::DeviceContext&, const phi::DenseTensor&, const phi::DenseTensor&, const phi::DenseTensor&, int64_t, phi::DenseTensor*); auto* kernel_fn = kernel.GetVariadicKernelFn(); (*kernel_fn)(*dev_ctx, *input_x, *input_weight, *input_out_grad, padding_idx, dense_out); } // 9. Reshard Kernel Output to API output ReshardKernelOutputToApiOutput(dev_ctx, shared_dist_out, weight_grad); // 10. Return return; } #endif // PADDLE_WITH_DISTRIBUTE auto input_x = PrepareData(x, kernel.InputAt(0), {}, false); auto input_weight = PrepareData(weight, kernel.InputAt(1), {}, false); auto input_out_grad = PrepareData(out_grad, kernel.InputAt(2), {}, false); if (sparse) { auto* kernel_out = SetSelectedRowsKernelOutput(weight_grad); phi::MetaTensor meta_out(kernel_out); meta_out.set_dims(input_weight->dims()); meta_out.set_dtype(input_weight->dtype()); kernel_out->set_height(input_weight->dims()[0]); using kernel_signature = void (*)(const phi::DeviceContext&, const phi::DenseTensor&, const phi::DenseTensor&, const phi::DenseTensor&, int64_t, phi::SelectedRows*); auto* kernel_fn = kernel.GetVariadicKernelFn(); (*kernel_fn)(*dev_ctx, *input_x, *input_weight, *input_out_grad, padding_idx, kernel_out); } else { auto* kernel_out = SetKernelOutput(weight_grad); phi::MetaTensor meta_out(kernel_out); std::vector output_metas_for_compact; output_metas_for_compact.push_back(&meta_out); phi::UnchangedInferMeta(MakeMetaTensor(*input_weight), &meta_out); CheckAndDoCompact(output_metas_for_compact, "embedding_grad"); using kernel_signature = void (*)(const phi::DeviceContext&, const phi::DenseTensor&, const phi::DenseTensor&, const phi::DenseTensor&, int64_t, phi::DenseTensor*); auto* kernel_fn = kernel.GetVariadicKernelFn(); (*kernel_fn)(*dev_ctx, *input_x, *input_weight, *input_out_grad, padding_idx, kernel_out); } } else { std::string kernel_name = sparse ? "sparse_weight_embedding_sparse_grad" : "sparse_weight_embedding_grad"; auto kernel_result = phi::KernelFactory::Instance().SelectKernelOrThrowError( kernel_name, {kernel_key.backend(), kernel_key.layout(), kernel_data_type}); const auto& kernel = kernel_result.kernel; VLOG(6) << kernel_name << " API kernel: " << kernel; auto* dev_ctx = GetDeviceContextByBackend( kernel_result.has_fallback_cpu ? Backend::CPU : kernel_key.backend()); auto input_x = PrepareData(x, kernel.InputAt(0), {}, false); auto input_weight = TensorToSelectedRows(weight); auto input_out_grad = PrepareData(out_grad, kernel.InputAt(2), {}, false); if (sparse) { auto* kernel_out = SetSelectedRowsKernelOutput(weight_grad); phi::MetaTensor meta_out(kernel_out); phi::UnchangedInferMeta(MakeMetaTensor(*input_weight), &meta_out); using kernel_signature = void (*)(const phi::DeviceContext&, const phi::DenseTensor&, const phi::SelectedRows&, const phi::DenseTensor&, int64_t, phi::SelectedRows*); auto* kernel_fn = kernel.GetVariadicKernelFn(); (*kernel_fn)(*dev_ctx, *input_x, *input_weight, *input_out_grad, padding_idx, kernel_out); } else { auto* kernel_out = SetKernelOutput(weight_grad); phi::MetaTensor meta_out(kernel_out); meta_out.set_dims(input_weight->GetCompleteDims()); meta_out.set_dtype(input_weight->dtype()); using kernel_signature = void (*)(const phi::DeviceContext&, const phi::DenseTensor&, const phi::SelectedRows&, const phi::DenseTensor&, int64_t, phi::DenseTensor*); auto* kernel_fn = kernel.GetVariadicKernelFn(); (*kernel_fn)(*dev_ctx, *input_x, *input_weight, *input_out_grad, padding_idx, kernel_out); } } } } // namespace paddle::experimental