Files
paddlepaddle--paddle/test/custom_op/custom_optional.cc
T
2026-07-13 12:40:42 +08:00

418 lines
13 KiB
C++

// 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,
// WIdata_tHOUdata_t WARRANdata_tIES OR CONDIdata_tIONS OF ANY KIND, either
// express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <iostream>
#include <vector>
#include "paddle/extension.h"
#define CHECK_INPUT(x) PD_CHECK(x.is_cpu(), #x " must be a CPU Tensor.")
template <typename data_t>
void add_one_pointer(const data_t* x_data, data_t* out_data, int64_t numel) {
for (size_t i = 0; i < numel; ++i) {
out_data[i] += x_data[i];
}
}
template <typename data_t>
void add_two_pointers(const data_t* x_data,
const data_t* y_data,
data_t* out_data,
int64_t numel) {
for (size_t i = 0; i < numel; ++i) {
out_data[i] = x_data[i] + y_data[i];
}
}
/*
if (y) {
out = x + y;
} else {
out = x + x;
}
*/
std::vector<paddle::Tensor> AddForward(
const paddle::Tensor& x,
const paddle::optional<paddle::Tensor>& y) { // NOLINT
CHECK_INPUT(x);
paddle::Tensor out = paddle::empty(x.shape(), x.dtype(), x.place());
if (y) {
out = x + y.get();
} else {
out = x + x;
}
return {out};
}
std::vector<paddle::DataType> AddInferDtype(
const paddle::DataType& x_dtype,
const paddle::optional<paddle::DataType>& y_dtype) {
if (y_dtype) {
return {*y_dtype};
}
return {x_dtype};
}
std::vector<std::vector<int64_t>> AddInferShape(
const std::vector<int64_t>& x_shape,
const paddle::optional<std::vector<int64_t>>& y_shape) {
if (y_shape) {
return {*y_shape};
}
return {x_shape};
}
/*
if (y) {
x_grad = out_grad;
} else {
x_grad = out_grad + out_grad;
}
*/
std::vector<paddle::Tensor> AddBackward(
const paddle::Tensor& x,
const paddle::optional<paddle::Tensor>& y,
const paddle::Tensor& out_grad) { // NOLINT
CHECK_INPUT(x);
paddle::Tensor x_grad = paddle::zeros(x.shape(), x.dtype(), x.place());
if (y) {
x_grad = out_grad;
} else {
x_grad = out_grad + out_grad;
}
return {x_grad};
}
PD_BUILD_OP(custom_add)
.Inputs({"X", paddle::Optional("Y")})
.Outputs({"Out"})
.SetKernelFn(PD_KERNEL(AddForward))
.SetInferShapeFn(PD_INFER_SHAPE(AddInferShape))
.SetInferDtypeFn(PD_INFER_DTYPE(AddInferDtype));
PD_BUILD_GRAD_OP(custom_add)
.Inputs({"X", paddle::Optional("Y"), paddle::Grad("Out")})
.Outputs({paddle::Grad("X")})
.SetKernelFn(PD_KERNEL(AddBackward));
/*
if (y) {
out = x + y[0] + y[1] + ...;
} else {
out = x + x;
}
*/
std::vector<paddle::Tensor> AddVectorForward(
const paddle::Tensor& x,
const paddle::optional<std::vector<paddle::Tensor>>& y) { // NOLINT
CHECK_INPUT(x);
paddle::Tensor out = paddle::zeros(x.shape(), x.dtype(), x.place());
PD_DISPATCH_FLOATING_TYPES(
x.type(), "AddVectorForward", ([&] {
if (y) {
add_one_pointer<data_t>(
x.data<data_t>(), out.data<data_t>(), out.size());
for (size_t i = 0; i < y->size(); ++i) {
add_one_pointer<data_t>(
y->at(i).data<data_t>(), out.data<data_t>(), out.size());
}
} else {
add_two_pointers<data_t>(
x.data<data_t>(), x.data<data_t>(), out.data<data_t>(), x.size());
}
}));
return {out};
}
std::vector<paddle::DataType> AddVectorInferDtype(
const paddle::DataType& x_dtype,
const paddle::optional<std::vector<paddle::DataType>>& y_dtype) {
if (y_dtype) {
return {y_dtype->at(0)};
}
return {x_dtype};
}
std::vector<std::vector<int64_t>> AddVectorInferShape(
const std::vector<int64_t>& x_shape,
const paddle::optional<std::vector<std::vector<int64_t>>>& y_shape) {
if (y_shape) {
return {y_shape->at(0)};
}
return {x_shape};
}
/*
if (y) {
x_grad = out_grad;
} else {
x_grad = out_grad + out_grad;
}
*/
std::vector<paddle::Tensor> AddVectorBackward(
const paddle::Tensor& x,
const paddle::optional<std::vector<paddle::Tensor>>& y,
const paddle::Tensor& out_grad) { // NOLINT
CHECK_INPUT(x);
paddle::Tensor x_grad = paddle::zeros(x.shape(), x.dtype(), x.place());
PD_DISPATCH_FLOATING_TYPES(
out_grad.type(), "AddVectorBackward", ([&] {
add_one_pointer<data_t>(
out_grad.data<data_t>(), x_grad.data<data_t>(), out_grad.size());
if (!y) {
add_one_pointer<data_t>(
out_grad.data<data_t>(), x_grad.data<data_t>(), out_grad.size());
}
}));
return {x_grad};
}
PD_BUILD_OP(custom_add_vec)
.Inputs({"X", paddle::Optional(paddle::Vec("Y"))})
.Outputs({"Out"})
.SetKernelFn(PD_KERNEL(AddVectorForward))
.SetInferShapeFn(PD_INFER_SHAPE(AddVectorInferShape))
.SetInferDtypeFn(PD_INFER_DTYPE(AddVectorInferDtype));
PD_BUILD_GRAD_OP(custom_add_vec)
.Inputs({"X", paddle::Optional(paddle::Vec("Y")), paddle::Grad("Out")})
.Outputs({paddle::Grad("X")})
.SetKernelFn(PD_KERNEL(AddVectorBackward));
/*
if (y) {
outX = 2 * x + y;
outY = x + y;
} else {
outX = 2 * x;
outY = None;
}
*/
std::vector<paddle::Tensor> AddOptionalInplaceForward(
const paddle::Tensor& x,
paddle::optional<paddle::Tensor>& y) { // NOLINT
CHECK_INPUT(x);
paddle::Tensor outX = paddle::zeros(x.shape(), x.dtype(), x.place());
PD_DISPATCH_FLOATING_TYPES(
x.type(), "AddOptionalInplaceForward", ([&] {
add_two_pointers<data_t>(
x.data<data_t>(), x.data<data_t>(), outX.data<data_t>(), x.size());
if (y) {
add_one_pointer<data_t>(
y->data<data_t>(), outX.data<data_t>(), outX.size());
add_one_pointer<data_t>(
x.data<data_t>(), y->data<data_t>(), x.size());
}
}));
// No need to return y, because we set it as inplace input.
return {outX};
}
std::vector<paddle::DataType> AddOptionalInplaceInferDtype(
const paddle::DataType& x_dtype,
const paddle::optional<paddle::DataType>& y_dtype) {
return {x_dtype};
}
std::vector<std::vector<int64_t>> AddOptionalInplaceInferShape(
const std::vector<int64_t>& x_shape,
const paddle::optional<std::vector<int64_t>>& y_shape) {
return {x_shape};
}
/*
if (y) {
x_grad = outX_grad * 2 + outY_grad;
y_grad = outX_grad + outY_grad;
} else {
x_grad = outX_grad * 2;
y_grad = None;
}
*/
std::vector<paddle::Tensor> AddOptionalInplaceBackward(
const paddle::Tensor& x,
const paddle::optional<paddle::Tensor>& y,
const paddle::Tensor& outx_grad,
paddle::optional<paddle::Tensor>& outy_grad) { // NOLINT
CHECK_INPUT(x);
paddle::Tensor x_grad = paddle::zeros(x.shape(), x.dtype(), x.place());
PD_DISPATCH_FLOATING_TYPES(
outx_grad.type(), "AddOptionalInplaceBackward", ([&] {
add_two_pointers<data_t>(outx_grad.data<data_t>(),
outx_grad.data<data_t>(),
x_grad.data<data_t>(),
x_grad.size());
if (outy_grad) {
add_one_pointer<data_t>(
outy_grad->data<data_t>(), x_grad.data<data_t>(), x_grad.size());
add_one_pointer<data_t>(outx_grad.data<data_t>(),
outy_grad->data<data_t>(),
outx_grad.size());
}
}));
return {x_grad};
}
std::vector<std::vector<int64_t>> AddOptionalInplaceBackwardInferShape(
const std::vector<int64_t>& x_shape,
const paddle::optional<std::vector<int64_t>>& y_shape,
const std::vector<int64_t>& x_grad_shape,
const paddle::optional<std::vector<int64_t>>& y_grad_shape) {
return {x_shape};
}
PD_BUILD_OP(custom_optional_inplace_add)
.Inputs({"X", paddle::Optional("Y")})
.Outputs({"OutX", paddle::Optional("OutY")})
.SetInplaceMap({{paddle::Optional("Y"), paddle::Optional("OutY")}})
.SetKernelFn(PD_KERNEL(AddOptionalInplaceForward))
.SetInferShapeFn(PD_INFER_SHAPE(AddOptionalInplaceInferShape))
.SetInferDtypeFn(PD_INFER_DTYPE(AddOptionalInplaceInferDtype));
PD_BUILD_GRAD_OP(custom_optional_inplace_add)
.Inputs({"X",
paddle::Optional("Y"),
paddle::Grad("OutX"),
paddle::Grad(paddle::Optional("OutY"))})
.Outputs({paddle::Grad("X"), paddle::Grad(paddle::Optional("Y"))})
.SetInplaceMap({{paddle::Grad(paddle::Optional("OutY")),
paddle::Grad(paddle::Optional("Y"))}})
.SetKernelFn(PD_KERNEL(AddOptionalInplaceBackward))
.SetInferShapeFn(PD_INFER_SHAPE(AddOptionalInplaceBackwardInferShape));
/*
if (y) {
outX = 2 * x + y[1...n];
outY[i] = x + y[i];
} else {
outX = 2 * x;
outY = None;
}
*/
std::vector<paddle::Tensor> AddOptionalInplaceVectorForward(
const paddle::Tensor& x,
paddle::optional<std::vector<paddle::Tensor>>& y) { // NOLINT
CHECK_INPUT(x);
paddle::Tensor outX = paddle::zeros(x.shape(), x.dtype(), x.place());
PD_DISPATCH_FLOATING_TYPES(
x.type(), "AddOptionalInplaceVectorForward", ([&] {
add_two_pointers<data_t>(
x.data<data_t>(), x.data<data_t>(), outX.data<data_t>(), x.size());
if (y) {
for (size_t i = 0; i < y->size(); ++i) {
add_one_pointer<data_t>(
y->at(i).data<data_t>(), outX.data<data_t>(), outX.size());
add_one_pointer<data_t>(
x.data<data_t>(), y->at(i).data<data_t>(), x.size());
}
}
}));
// No need to return y, because we set it as inplace input.
return {outX};
}
std::vector<paddle::DataType> AddOptionalInplaceVectorInferDtype(
const paddle::DataType& x_dtype,
const paddle::optional<std::vector<paddle::DataType>>& y_dtype) {
return {x_dtype};
}
std::vector<std::vector<int64_t>> AddOptionalInplaceVectorInferShape(
const std::vector<int64_t>& x_shape,
const paddle::optional<std::vector<std::vector<int64_t>>>& y_shape) {
return {x_shape};
}
/*
if (outy_grad) {
x_grad = outX_grad * 2 + outY_grad[1...n];
y_grad[i] = outX_grad + outY_grad[i];
} else {
x_grad = outX_grad * 2;
y_grad = None;
}
*/
std::vector<paddle::Tensor> AddOptionalInplaceVectorBackward(
const paddle::Tensor& x,
const paddle::optional<std::vector<paddle::Tensor>>& y,
const paddle::Tensor& outx_grad,
paddle::optional<std::vector<paddle::Tensor>>& outy_grad) { // NOLINT
CHECK_INPUT(x);
paddle::Tensor x_grad = paddle::zeros(x.shape(), x.dtype(), x.place());
PD_DISPATCH_FLOATING_TYPES(
outx_grad.type(), "AddOptionalInplaceVectorBackward", ([&] {
add_two_pointers<data_t>(outx_grad.data<data_t>(),
outx_grad.data<data_t>(),
x_grad.data<data_t>(),
x_grad.size());
if (outy_grad) {
for (size_t i = 0; i < outy_grad->size(); ++i) {
add_one_pointer<data_t>(outy_grad->at(i).data<data_t>(),
x_grad.data<data_t>(),
x_grad.size());
add_one_pointer<data_t>(outx_grad.data<data_t>(),
outy_grad->at(i).data<data_t>(),
outx_grad.size());
}
}
}));
return {x_grad};
}
std::vector<std::vector<int64_t>> AddOptionalInplaceVectorBackwardInferShape(
const std::vector<int64_t>& x_shape,
const paddle::optional<std::vector<std::vector<int64_t>>>& y_shape,
const std::vector<int64_t>& x_grad_shape,
const paddle::optional<std::vector<std::vector<int64_t>>>& y_grad_shape) {
return {x_shape};
}
PD_BUILD_OP(custom_optional_inplace_add_vec)
.Inputs({"X", paddle::Optional(paddle::Vec("Y"))})
.Outputs({"OutX", paddle::Optional(paddle::Vec("OutY"))})
.SetInplaceMap({{paddle::Optional(paddle::Vec("Y")),
paddle::Optional(paddle::Vec("OutY"))}})
.SetKernelFn(PD_KERNEL(AddOptionalInplaceVectorForward))
.SetInferShapeFn(PD_INFER_SHAPE(AddOptionalInplaceVectorInferShape))
.SetInferDtypeFn(PD_INFER_DTYPE(AddOptionalInplaceVectorInferDtype));
PD_BUILD_GRAD_OP(custom_optional_inplace_add_vec)
.Inputs({"X",
paddle::Optional(paddle::Vec("Y")),
paddle::Grad("OutX"),
paddle::Grad(paddle::Optional(paddle::Vec("OutY")))})
.Outputs({paddle::Grad("X"),
paddle::Grad(paddle::Optional(paddle::Vec("Y")))})
.SetInplaceMap({{paddle::Grad(paddle::Optional(paddle::Vec("OutY"))),
paddle::Grad(paddle::Optional(paddle::Vec("Y")))}})
.SetKernelFn(PD_KERNEL(AddOptionalInplaceVectorBackward))
.SetInferShapeFn(
PD_INFER_SHAPE(AddOptionalInplaceVectorBackwardInferShape));