// 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. #pragma once #include "paddle/phi/api/include/tensor.h" #include "paddle/phi/backends/device_guard.h" #include "paddle/phi/backends/device_manager.h" #include "paddle/phi/core/device_context.h" #include "paddle/phi/kernels/funcs/concat_and_split_functor.h" namespace paddle { namespace pybind { template struct ConcatDenseTensor { void operator()(const Context &dev_ctx, const std::vector &in, DenseTensor *out, int axis = 0) { phi::funcs::ConcatFunctor concat_functor; concat_functor(dev_ctx, in, axis, out); } }; template struct SplitDenseTensor { void operator()(const Context &dev_ctx, const DenseTensor &in, std::vector *out, int axis = 0) { std::vector shape_refer; shape_refer.reserve(out->size()); for (auto *p_tensor : *out) { shape_refer.emplace_back(p_tensor); } phi::funcs::SplitFunctor split_functor; split_functor(dev_ctx, in, shape_refer, axis, out); } }; #ifdef PADDLE_WITH_CUSTOM_DEVICE template struct ConcatDenseTensor { void operator()(const phi::CustomContext &dev_ctx, const std::vector &in, DenseTensor *out, int axis UNUSED = 0) { VLOG(10) << "ConcatDenseTensor: " << in.size(); auto kernel_result = phi::KernelFactory::Instance().SelectKernelOrThrowError( "concat", phi::KernelKey(phi::TransToPhiBackend(dev_ctx.GetPlace()), phi::DataLayout::ALL_LAYOUT, phi::CppTypeToDataType::Type())); const auto &kernel = kernel_result.kernel; using kernel_signature = void (*)(const phi::DeviceContext &, const std::vector &, const phi::Scalar &, DenseTensor *); auto *kernel_fn = kernel.GetVariadicKernelFn(); std::vector inputs; (*kernel_fn)(dev_ctx, inputs, phi::Scalar(0), out); } }; template struct SplitDenseTensor { void operator()(const phi::CustomContext &dev_ctx, const DenseTensor &in, std::vector *out, int axis UNUSED = 0) { VLOG(10) << "SplitDenseTensor: " << out->size(); auto kernel_result = phi::KernelFactory::Instance().SelectKernelOrThrowError( "split_with_num", phi::KernelKey(phi::TransToPhiBackend(dev_ctx.GetPlace()), phi::DataLayout::ALL_LAYOUT, phi::CppTypeToDataType::Type())); const auto &kernel = kernel_result.kernel; using kernel_signature = void (*)(const phi::DeviceContext &, const DenseTensor &, int, const phi::Scalar &, std::vector); auto *kernel_fn = kernel.GetVariadicKernelFn(); auto in_dims = common::vectorize(in.dims()); auto origin_out_dims = common::vectorize(out->at(0)->dims()); for (auto *tensor : *out) { if (origin_out_dims.size() != in_dims.size()) { std::vector new_dims({1}); new_dims.insert( new_dims.end(), origin_out_dims.begin(), origin_out_dims.end()); tensor->Resize(common::make_ddim(new_dims)); } } (*kernel_fn)(dev_ctx, in, out->size(), phi::Scalar(0), *out); for (auto *tensor : *out) { auto tensor_dims = common::vectorize(tensor->dims()); if (tensor_dims.size() != origin_out_dims.size()) { tensor->Resize(common::make_ddim(origin_out_dims)); } } } }; #endif template void ConcatDenseTensorWithType(const Context &dev_ctx, const std::vector &t_list, DenseTensor *p_out, DataType type) { switch (type) { case DataType::BOOL: ConcatDenseTensor()(dev_ctx, t_list, p_out); break; case DataType::UINT8: ConcatDenseTensor()(dev_ctx, t_list, p_out); break; case DataType::INT8: ConcatDenseTensor()(dev_ctx, t_list, p_out); break; case DataType::INT32: ConcatDenseTensor()(dev_ctx, t_list, p_out); break; case DataType::INT64: ConcatDenseTensor()(dev_ctx, t_list, p_out); break; case DataType::FLOAT16: ConcatDenseTensor()(dev_ctx, t_list, p_out); break; case DataType::BFLOAT16: ConcatDenseTensor()(dev_ctx, t_list, p_out); break; case DataType::FLOAT32: ConcatDenseTensor()(dev_ctx, t_list, p_out); break; case DataType::FLOAT64: ConcatDenseTensor()(dev_ctx, t_list, p_out); break; default: PADDLE_THROW(common::errors::Unimplemented( "Data type (%s) is not supported when it concats tensors.", type)); } } #ifdef PADDLE_WITH_XPU template <> void ConcatDenseTensorWithType(const phi::XPUContext &dev_ctx, const std::vector &t_list, DenseTensor *p_out, DataType type) { switch (type) { case DataType::FLOAT16: ConcatDenseTensor()( dev_ctx, t_list, p_out); break; case DataType::BFLOAT16: ConcatDenseTensor()( dev_ctx, t_list, p_out); break; case DataType::FLOAT32: ConcatDenseTensor()(dev_ctx, t_list, p_out); break; case DataType::INT32: ConcatDenseTensor()(dev_ctx, t_list, p_out); break; case DataType::INT64: ConcatDenseTensor()(dev_ctx, t_list, p_out); break; case DataType::UINT8: ConcatDenseTensor()(dev_ctx, t_list, p_out); break; default: PADDLE_THROW(common::errors::Unimplemented( "Data type (%s) is not supported when it concats tensors.", type)); } } #endif template void SplitDenseTensorWithType(const Context &dev_ctx, const DenseTensor &t_in, std::vector *p_list, DataType type) { switch (type) { case DataType::BOOL: SplitDenseTensor()(dev_ctx, t_in, p_list); break; case DataType::UINT8: SplitDenseTensor()(dev_ctx, t_in, p_list); break; case DataType::INT8: SplitDenseTensor()(dev_ctx, t_in, p_list); break; case DataType::FLOAT8_E4M3FN: SplitDenseTensor()(dev_ctx, t_in, p_list); break; case DataType::FLOAT8_E5M2: SplitDenseTensor()(dev_ctx, t_in, p_list); break; case DataType::INT32: SplitDenseTensor()(dev_ctx, t_in, p_list); break; case DataType::INT64: SplitDenseTensor()(dev_ctx, t_in, p_list); break; case DataType::FLOAT16: SplitDenseTensor()(dev_ctx, t_in, p_list); break; case DataType::BFLOAT16: SplitDenseTensor()(dev_ctx, t_in, p_list); break; case DataType::FLOAT32: SplitDenseTensor()(dev_ctx, t_in, p_list); break; case DataType::FLOAT64: SplitDenseTensor()(dev_ctx, t_in, p_list); break; default: PADDLE_THROW(common::errors::Unimplemented( "Data type (%s) is not supported when it splits tensors.", type)); } } #ifdef PADDLE_WITH_XPU template <> void SplitDenseTensorWithType(const phi::XPUContext &dev_ctx, const DenseTensor &t_in, std::vector *p_list, DataType type) { switch (type) { case DataType::FLOAT16: SplitDenseTensor()(dev_ctx, t_in, p_list); break; case DataType::BFLOAT16: SplitDenseTensor()(dev_ctx, t_in, p_list); break; case DataType::FLOAT32: SplitDenseTensor()(dev_ctx, t_in, p_list); break; case DataType::INT32: SplitDenseTensor()(dev_ctx, t_in, p_list); break; case DataType::INT64: SplitDenseTensor()(dev_ctx, t_in, p_list); break; case DataType::UINT8: SplitDenseTensor()(dev_ctx, t_in, p_list); break; default: PADDLE_THROW(common::errors::Unimplemented( "Data type (%s) is not supported when it splits tensors.", type)); } } #endif void ConcatTensor(const phi::DeviceContext &dev_ctx, const std::vector &tensor_list, const Tensor *tensor) { auto *dense_tensor = std::dynamic_pointer_cast(tensor->impl()).get(); const auto &place = dev_ctx.GetPlace(); if (phi::is_gpu_place(place)) { #if defined(PADDLE_WITH_CUDA) || defined(PADDLE_WITH_HIP) ConcatDenseTensorWithType(static_cast(dev_ctx), tensor_list, dense_tensor, tensor->dtype()); #else PADDLE_THROW(common::errors::PermissionDenied( "Paddle can't concat tensor since it's not support GPU, please " "recompile or reinstall Paddle with GPU support.")); #endif } else if (phi::is_xpu_place(place)) { #ifdef PADDLE_WITH_XPU ConcatDenseTensorWithType(static_cast(dev_ctx), tensor_list, dense_tensor, tensor->dtype()); #else PADDLE_THROW(common::errors::PermissionDenied( "Paddle can't concat tensor since it's not support XPU, please " "recompile or reinstall Paddle with XPU support.")); #endif } else if (phi::is_custom_place(place)) { #ifdef PADDLE_WITH_CUSTOM_DEVICE ConcatDenseTensorWithType(static_cast(dev_ctx), tensor_list, dense_tensor, tensor->dtype()); #else PADDLE_THROW(common::errors::PermissionDenied( "Paddle can't concat tensor since it's not compiled with " "CUSTOM_DEVICE, please recompile or reinstall Paddle with " "CUSTOM_DEVICE support.")); #endif } else if (phi::is_cpu_place(place)) { ConcatDenseTensorWithType(static_cast(dev_ctx), tensor_list, dense_tensor, tensor->dtype()); } else { PADDLE_THROW(common::errors::Unimplemented( "Concat tensor not supported on place (%s)", place)); } } void SplitTensor(const phi::DeviceContext &dev_ctx, const DenseTensor &tensor, const std::vector *tensor_list) { std::vector dense_list; for (auto &tensor : *tensor_list) { auto *p_tensor = std::dynamic_pointer_cast(tensor.impl()).get(); dense_list.emplace_back(p_tensor); } const auto &place = dev_ctx.GetPlace(); if (phi::is_gpu_place(place)) { #if defined(PADDLE_WITH_CUDA) || defined(PADDLE_WITH_HIP) SplitDenseTensorWithType(static_cast(dev_ctx), tensor, &dense_list, tensor.dtype()); #else PADDLE_THROW(common::errors::PermissionDenied( "Paddle can't split tensor since it's not support GPU, please " "recompile or reinstall Paddle with GPU support.")); #endif } else if (phi::is_xpu_place(place)) { #ifdef PADDLE_WITH_XPU SplitDenseTensorWithType(static_cast(dev_ctx), tensor, &dense_list, tensor.dtype()); #else PADDLE_THROW(common::errors::PermissionDenied( "Paddle can't split tensor since it's not compiled with XPU, " "please recompile or reinstall Paddle with XPU support.")); #endif } else if (phi::is_custom_place(place)) { #ifdef PADDLE_WITH_CUSTOM_DEVICE SplitDenseTensorWithType(static_cast(dev_ctx), tensor, &dense_list, tensor.dtype()); #else PADDLE_THROW(common::errors::PermissionDenied( "Paddle can't split tensor since it's not compiled with CUSTOM_DEVICE, " "please recompile or reinstall Paddle with CUSTOM_DEVICE support.")); #endif } else if (phi::is_cpu_place(place)) { SplitDenseTensorWithType(static_cast(dev_ctx), tensor, &dense_list, tensor.dtype()); } else { PADDLE_THROW(common::errors::Unimplemented( "Split tensor not supported on place (%s)", place)); } } inline std::vector GetDefaultSplitSizes(const DenseTensor &tensor, int world_size) { return std::vector(world_size, tensor.dims()[0] / world_size); } inline std::vector ToDenseTensors( const std::vector &tensors) { std::vector ret; for (auto &t : tensors) { ret.emplace_back(*std::dynamic_pointer_cast(t.impl())); } return ret; } } // namespace pybind } // namespace paddle