From 9baf22ec92e98925980b18e2b60babf22b73e2e4 Mon Sep 17 00:00:00 2001 From: zhoushunjie Date: Wed, 23 Nov 2022 17:13:00 +0000 Subject: [PATCH 1/7] add tile --- fastdeploy/function/tile.cc | 105 ++++++++++++++++++++++++++++++++++++ fastdeploy/function/tile.h | 35 ++++++++++++ 2 files changed, 140 insertions(+) create mode 100644 fastdeploy/function/tile.cc create mode 100644 fastdeploy/function/tile.h diff --git a/fastdeploy/function/tile.cc b/fastdeploy/function/tile.cc new file mode 100644 index 000000000..0e9e8389d --- /dev/null +++ b/fastdeploy/function/tile.cc @@ -0,0 +1,105 @@ +// 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 "fastdeploy/function/tile.h" +#include "fastdeploy/function/eigen.h" + +namespace fastdeploy { +namespace function { + +template +void TileFunctor(const FDTensor& x, std::vector repeat_times, + FDTensor* out) { + auto x_shape = x.Shape(); + for (size_t i = 0; i < repeat_times.size(); ++i) { + FDASSERT(repeat_times[i] > 0, + "All elements of the input 'repeat_times' " + "for tile op must be positive integers, but " + "the value received is %d.", + repeat_times[i]); + } + if (repeat_times.size() < x_shape.size()) { + int diff = x_shape.size() - repeat_times.size(); + repeat_times.insert(repeat_times.begin(), diff, 1); + } else { + int diff = repeat_times.size() - x_shape.size(); + x_shape.insert(x_shape.begin(), diff, 1); + } + FDASSERT(repeat_times.size() == x_shape.size(), + "The rank (%d) of the input 'x' and the rank (%d) of the input " + "'repeat_times' for tile op must match after promotion.", + x_shape.size(), repeat_times.size()); + + if (Rank == 0) { + // Deep copy + *out = x; + return; + } + + Eigen::DSizes bcast_dims; + for (size_t i = 0; i < repeat_times.size(); ++i) { + bcast_dims[i] = repeat_times[i]; + } + + std::vector out_shape(x_shape); + for (size_t i = 0; i < repeat_times.size(); ++i) { + out_shape[i] *= repeat_times[i]; + } + + out->Allocate(out_shape, x.Dtype()); + auto eigen_x = EigenTensor::From(x, x_shape); + auto eigen_out = EigenTensor::From(*out, out_shape); + + const auto& dev = *EigenDeviceWrapper::GetInstance()->GetDevice(); + eigen_out.device(dev) = eigen_x.broadcast(bcast_dims); +} + +template +void TileKernel(const FDTensor& x, std::vector repeat_times, + FDTensor* out) { + auto rank = x.Shape().size(); + auto repeat_times_size = repeat_times.size(); + rank = (std::max)(rank, repeat_times_size); + switch (rank) { + case 0: + *out = x; + break; + case 1: + TileFunctor(x, repeat_times, out); + break; + case 2: + TileFunctor(x, repeat_times, out); + break; + case 3: + TileFunctor(x, repeat_times, out); + break; + case 4: + TileFunctor(x, repeat_times, out); + break; + case 5: + TileFunctor(x, repeat_times, out); + break; + case 6: + TileFunctor(x, repeat_times, out); + break; + } +} + +void Tile(const FDTensor& x, std::vector repeat_times, FDTensor* out) { + FD_VISIT_ALL_TYPES(x.dtype, "TileKernel", + ([&] { TileKernel(x, repeat_times, out); })); +} + +} // namespace function +} // namespace fastdeploy \ No newline at end of file diff --git a/fastdeploy/function/tile.h b/fastdeploy/function/tile.h new file mode 100644 index 000000000..b3a6bf2fb --- /dev/null +++ b/fastdeploy/function/tile.h @@ -0,0 +1,35 @@ +// 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 "fastdeploy/core/fd_tensor.h" + +namespace fastdeploy { +namespace function { + +/** Construct a new Tensor by repeating x the number of times given by + ** repeat_times. After tiling, the value of the i’th dimension of the + ** output is equal to x.shape[i]*repeat_times[i]. Both the number of + ** dimensions of x and the number of elements in repeat_times should + ** be less than or equal to 6.Support all data types. + @param x The input tensor. + @param repeat_times The lower bound + @param out The output tensor which stores the result. +*/ +FASTDEPLOY_DECL void Tile(const FDTensor& x, std::vector repeat_times, + FDTensor* out); + +} // namespace function +} // namespace fastdeploy From e147dec59eed15da7583c8e484a9290be12fe0c1 Mon Sep 17 00:00:00 2001 From: zhoushunjie Date: Thu, 24 Nov 2022 02:34:33 +0000 Subject: [PATCH 2/7] Add tile unittest --- tests/function/test_tile.cc | 68 +++++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100644 tests/function/test_tile.cc diff --git a/tests/function/test_tile.cc b/tests/function/test_tile.cc new file mode 100644 index 000000000..db8e0eca3 --- /dev/null +++ b/tests/function/test_tile.cc @@ -0,0 +1,68 @@ +// 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 "fastdeploy/core/fd_tensor.h" +#include "fastdeploy/function/tile.h" +#include "glog/logging.h" +#include "gtest_utils.h" +#include "gtest/gtest.h" +#include + +namespace fastdeploy { +namespace function { + +std::vector CreateTestData() { + // Shape: [2, 3] + std::vector x_data = {0.8428625, 0.6461913, 0.13740455, + 0.11430702, 0.659926, 0.535816}; + return x_data; +} + +TEST(fastdeploy, tile) { + CheckShape check_shape; + CheckData check_data; + FDTensor x, y; + auto test_data = CreateTestData(); + x.SetExternalData({2, 3}, FDDataType::FP32, test_data.data()); + Tile(x, {2}, &y); + std::vector result = {0.842862, 0.646191, 0.137405, 0.842862, + 0.646191, 0.137405, 0.114307, 0.659926, + 0.535816, 0.114307, 0.659926, 0.535816}; + check_shape(y.Shape(), {2, 6}); + check_data(reinterpret_cast(y.Data()), result.data(), + result.size()); + + result = {0.842862, 0.646191, 0.137405, 0.842862, 0.646191, 0.137405, + 0.842862, 0.646191, 0.137405, 0.114307, 0.659926, 0.535816, + 0.114307, 0.659926, 0.535816, 0.114307, 0.659926, 0.535816, + 0.842862, 0.646191, 0.137405, 0.842862, 0.646191, 0.137405, + 0.842862, 0.646191, 0.137405, 0.114307, 0.659926, 0.535816, + 0.114307, 0.659926, 0.535816, 0.114307, 0.659926, 0.535816}; + Tile(x, {2, 3}, &y); + check_shape(y.Shape(), {4, 9}); + check_data(reinterpret_cast(y.Data()), result.data(), + result.size()); + + result = {0.842862, 0.646191, 0.137405, 0.842862, 0.646191, 0.137405, + 0.114307, 0.659926, 0.535816, 0.114307, 0.659926, 0.535816, + 0.842862, 0.646191, 0.137405, 0.842862, 0.646191, 0.137405, + 0.114307, 0.659926, 0.535816, 0.114307, 0.659926, 0.535816, + 0.842862, 0.646191, 0.137405, 0.842862, 0.646191, 0.137405, + 0.114307, 0.659926, 0.535816, 0.114307, 0.659926, 0.535816}; + Tile(x, {3, 2}, &y); + check_shape(y.Shape(), {6, 6}); +} + +} // namespace function +} // namespace fastdeploy From a14c55069fb235b068f18fc049818001f0b9f903 Mon Sep 17 00:00:00 2001 From: zhoushunjie Date: Thu, 24 Nov 2022 03:46:05 +0000 Subject: [PATCH 3/7] Add linspace --- fastdeploy/function/linspace.cc | 52 ++++++++++++++++++++++++++++++++ fastdeploy/function/linspace.h | 33 ++++++++++++++++++++ tests/function/test_linspace.cc | 53 +++++++++++++++++++++++++++++++++ 3 files changed, 138 insertions(+) create mode 100644 fastdeploy/function/linspace.cc create mode 100644 fastdeploy/function/linspace.h create mode 100644 tests/function/test_linspace.cc diff --git a/fastdeploy/function/linspace.cc b/fastdeploy/function/linspace.cc new file mode 100644 index 000000000..88462bb03 --- /dev/null +++ b/fastdeploy/function/linspace.cc @@ -0,0 +1,52 @@ +// 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 "fastdeploy/function/linspace.h" + +namespace fastdeploy { +namespace function { + +template +void LinspaceKernel(double start, double end, int num, FDTensor* out) { + FDASSERT( + num > 0, + "The num of linspace op should be larger than 0, but received num is %d", + num); + out->Allocate({num}, TypeToDataType::dtype); + T* out_data = reinterpret_cast(out->Data()); + if (num > 1) { + // step should be of double type for all types + double step = (static_cast(end - start)) / (num - 1); + int half_num = num / 2; + for (int i = 0; i < num; ++i) { + if (i < half_num) { + out_data[i] = static_cast(start + step * i); + } else { + out_data[i] = static_cast(end - step * (num - i - 1)); + } + } + } else { + out_data[0] = static_cast(start); + } +} + +void Linspace(double start, double end, int num, FDTensor* out, + FDDataType dtype) { + FD_VISIT_INT_FLOAT_TYPES(dtype, "LinspaceKernel", ([&] { + LinspaceKernel(start, end, num, out); + })); +} + +} // namespace function +} // namespace fastdeploy \ No newline at end of file diff --git a/fastdeploy/function/linspace.h b/fastdeploy/function/linspace.h new file mode 100644 index 000000000..c3b6ac8a5 --- /dev/null +++ b/fastdeploy/function/linspace.h @@ -0,0 +1,33 @@ +// 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 "fastdeploy/core/fd_tensor.h" + +namespace fastdeploy { +namespace function { + +/** Return fixed number of evenly spaced values within a given interval. + @param start The input start is start variable of range. + @param end The input stop is start variable of range. + @param num The input num is given num of the sequence. + @param out The output tensor which stores the result. + @param dtype The data type of output tensor, default to float32. +*/ +FASTDEPLOY_DECL void Linspace(double start, double end, int num, FDTensor* out, + FDDataType dtype = FDDataType::FP32); + +} // namespace function +} // namespace fastdeploy diff --git a/tests/function/test_linspace.cc b/tests/function/test_linspace.cc new file mode 100644 index 000000000..0feffa43d --- /dev/null +++ b/tests/function/test_linspace.cc @@ -0,0 +1,53 @@ +// 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 "fastdeploy/core/fd_tensor.h" +#include "fastdeploy/function/linspace.h" +#include +#include + +#include "glog/logging.h" +#include "gtest_utils.h" +#include "gtest/gtest.h" + +namespace fastdeploy { +namespace function { + +TEST(fastdeploy, linspace) { + CheckShape check_shape; + CheckData check_data; + + FDTensor x; + + std::vector result = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + Linspace(0, 10, 11, &x); + check_shape({11}, x.Shape()); + check_data(reinterpret_cast(x.Data()), result.data(), + result.size()); + + result = {10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0}; + Linspace(10, 0, 11, &x); + check_shape({11}, x.Shape()); + check_data(reinterpret_cast(x.Data()), result.data(), + result.size()); + + result = {10}; + Linspace(10, 0, 1, &x); + check_shape({1}, x.Shape()); + check_data(reinterpret_cast(x.Data()), result.data(), + result.size()); +} + +} // namespace function +} // namespace fastdeploy \ No newline at end of file From 12af6b4464ac578bf332aa3a3fc62b6838df9965 Mon Sep 17 00:00:00 2001 From: zhoushunjie Date: Thu, 24 Nov 2022 04:02:00 +0000 Subject: [PATCH 4/7] Add abs functions --- fastdeploy/function/math.cc | 6 ++++++ fastdeploy/function/math.h | 6 ++++++ fastdeploy/function/math_functor.h | 9 +++++++++ tests/function/test_math.cc | 13 +++++++++++++ 4 files changed, 34 insertions(+) diff --git a/fastdeploy/function/math.cc b/fastdeploy/function/math.cc index 292b1ae15..3889ca698 100644 --- a/fastdeploy/function/math.cc +++ b/fastdeploy/function/math.cc @@ -39,6 +39,7 @@ DEFINE_ACTIVATION_KERNEL(Sqrt, SqrtFunctor) DEFINE_ACTIVATION_KERNEL(Log, LogFunctor) DEFINE_ACTIVATION_KERNEL(Round, RoundFunctor) DEFINE_ACTIVATION_KERNEL(Exp, ExpFunctor) +DEFINE_ACTIVATION_KERNEL(Abs, AbsFunctor) void Sqrt(const FDTensor& x, FDTensor* out) { FD_VISIT_FLOAT_TYPES(x.dtype, "SqrtKernel", @@ -60,5 +61,10 @@ void Exp(const FDTensor& x, FDTensor* out) { ([&] { ExpKernel(x, out); })); } +void Abs(const FDTensor& x, FDTensor* out) { + FD_VISIT_FLOAT_TYPES(x.dtype, "AbsKernel", + ([&] { AbsKernel(x, out); })); +} + } // namespace function } // namespace fastdeploy \ No newline at end of file diff --git a/fastdeploy/function/math.h b/fastdeploy/function/math.h index 3dd93c818..14ac79c64 100644 --- a/fastdeploy/function/math.h +++ b/fastdeploy/function/math.h @@ -43,5 +43,11 @@ FASTDEPLOY_DECL void Round(const FDTensor& x, FDTensor* out); */ FASTDEPLOY_DECL void Exp(const FDTensor& x, FDTensor* out); +/** This operator is used to perform elementwise abs for input X. Only for float type FDTensor + @param x The input tensor. + @param out The output tensor which stores the result. +*/ +FASTDEPLOY_DECL void Abs(const FDTensor& x, FDTensor* out); + } // namespace function } // namespace fastdeploy diff --git a/fastdeploy/function/math_functor.h b/fastdeploy/function/math_functor.h index 440ce94a9..f82224c97 100644 --- a/fastdeploy/function/math_functor.h +++ b/fastdeploy/function/math_functor.h @@ -52,5 +52,14 @@ template struct SqrtFunctor { } }; +// abs(x) = x if x > 0 else -x +template struct AbsFunctor { + template + void operator()(Device d, X x, Out out) const { + out.device(d) = + x.unaryExpr([](T v) { return v > static_cast(0) ? v : -v; }); + } +}; + } // namespace function } // namespace fastdeploy diff --git a/tests/function/test_math.cc b/tests/function/test_math.cc index ec09fa7ef..8027012e9 100644 --- a/tests/function/test_math.cc +++ b/tests/function/test_math.cc @@ -83,5 +83,18 @@ TEST(fastdeploy, exp_sqrt_round_log) { log_result.size()); } +TEST(fastdeploy, abs) { + CheckShape check_shape; + CheckData check_data; + FDTensor x, y; + std::vector test_data = {-1, 2, 3, -5, -4, -6}; + x.SetExternalData({2, 3}, FDDataType::FP32, test_data.data()); + std::vector result = {1, 2, 3, 5, 4, 6}; + Abs(x, &y); + check_shape(y.shape, {2, 3}); + check_data(reinterpret_cast(y.Data()), result.data(), + result.size()); +} + } // namespace function } // namespace fastdeploy \ No newline at end of file From 6e2e646422935b4babbb4ac1096854d1482cda4c Mon Sep 17 00:00:00 2001 From: zhoushunjie Date: Thu, 24 Nov 2022 06:56:47 +0000 Subject: [PATCH 5/7] Add cumprod function --- fastdeploy/function/cumprod.cc | 78 ++++++++++++++++++++++++++++++++++ fastdeploy/function/cumprod.h | 31 ++++++++++++++ tests/function/test_cumprod.cc | 73 +++++++++++++++++++++++++++++++ 3 files changed, 182 insertions(+) create mode 100644 fastdeploy/function/cumprod.cc create mode 100644 fastdeploy/function/cumprod.h create mode 100644 tests/function/test_cumprod.cc diff --git a/fastdeploy/function/cumprod.cc b/fastdeploy/function/cumprod.cc new file mode 100644 index 000000000..77b4ff5ab --- /dev/null +++ b/fastdeploy/function/cumprod.cc @@ -0,0 +1,78 @@ +// 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 "fastdeploy/function/cumprod.h" + +namespace fastdeploy { +namespace function { + +void GetCumprodDimInfo(const std::vector& dim, int cumprod_dim, + size_t* outer_dim, size_t* mid_dim, size_t* inner_dim) { + int dim_size = dim.size(); + FDASSERT(cumprod_dim >= -dim_size, + "The input dim of CumprodOp should be larger than the opposite " + "rank of input x which is %d. But received dim = %d", + -dim_size, cumprod_dim); + FDASSERT(cumprod_dim < dim_size, + "The input dim of CumprodOp should be smaller than the " + "rank of input x which is %d. But received dim = %d", + dim_size, cumprod_dim); + if (cumprod_dim < 0) + cumprod_dim += dim_size; + + *outer_dim = 1; + for (int i = 0; i < cumprod_dim; ++i) { + *outer_dim *= dim[i]; + } + *mid_dim = dim[cumprod_dim]; + *inner_dim = 1; + for (int i = cumprod_dim + 1; i < dim_size; ++i) { + *inner_dim *= dim[i]; + } +} + +template +void CumprodKernel(const FDTensor& x, FDTensor* out, int axis) { + auto* x_data = reinterpret_cast(x.Data()); + auto shape = x.Shape(); + + size_t outer_dim = 1; + size_t mid_dim = 1; + size_t inner_dim = 1; + GetCumprodDimInfo(shape, axis, &outer_dim, &mid_dim, &inner_dim); + + out->Allocate(x.Shape(), x.Dtype()); + auto* out_data = reinterpret_cast(out->Data()); + + for (size_t i = 0; i < outer_dim; i++) { + for (size_t j = 0; j < mid_dim; j++) { + for (size_t k = 0; k < inner_dim; k++) { + size_t pos = i * mid_dim * inner_dim + j * inner_dim + k; + if (j == 0) { + out_data[pos] = x_data[pos]; + } else { + out_data[pos] = out_data[pos - inner_dim] * x_data[pos]; + } + } + } + } +} + +void Cumprod(const FDTensor& x, FDTensor* out, int axis) { + FD_VISIT_INT_FLOAT_TYPES(x.dtype, "CumprodKernel", + ([&] { CumprodKernel(x, out, axis); })); +} + +} // namespace function +} // namespace fastdeploy diff --git a/fastdeploy/function/cumprod.h b/fastdeploy/function/cumprod.h new file mode 100644 index 000000000..fd73e0a43 --- /dev/null +++ b/fastdeploy/function/cumprod.h @@ -0,0 +1,31 @@ +// 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 "fastdeploy/core/fd_tensor.h" + +namespace fastdeploy { +namespace function { + +/** Excute the concatenate operation for input FDTensor along given axis. + @param x The input tensor. + @param out The output tensor which stores the result. + @param axisi Axis which will be concatenated. +*/ + +FASTDEPLOY_DECL void Cumprod(const FDTensor& x, FDTensor* out, int axis = 0); + +} // namespace function +} // namespace fastdeploy diff --git a/tests/function/test_cumprod.cc b/tests/function/test_cumprod.cc new file mode 100644 index 000000000..f1d55ba10 --- /dev/null +++ b/tests/function/test_cumprod.cc @@ -0,0 +1,73 @@ +// 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 "fastdeploy/core/fd_tensor.h" +#include "fastdeploy/function/cumprod.h" +#include "glog/logging.h" +#include "gtest_utils.h" +#include "gtest/gtest.h" +#include +#include + +namespace fastdeploy { +namespace function { + +std::vector CreateTestData() { + // Shape: [2, 3, 4] + std::vector x_data = { + 0.8428625, 0.6461913, 0.13740455, 0.11430702, 0.659926, 0.535816, + 0.7429162, 0.8456049, 0.21228176, 0.29970083, 0.8621713, 0.40894133, + 0.12684688, 0.1566195, 0.42884097, 0.8476526, 0.2458633, 0.669046, + 0.87888306, 0.6762589, 0.666453, 0.32523027, 0.4139388, 0.8341406}; + return x_data; +} + +TEST(fastdeploy, cumprod) { + CheckShape check_shape; + CheckData check_data; + FDTensor x, y; + auto test_data = CreateTestData(); + x.SetExternalData({2, 3, 4}, FDDataType::FP32, test_data.data()); + + std::vector result = {0.842862, 0.646191, 0.137405, 0.114307, 0.659926, + 0.535816, 0.742916, 0.845605, 0.212282, 0.299701, + 0.862171, 0.408941, 0.106914, 0.101206, 0.058925, + 0.096893, 0.162252, 0.358486, 0.652937, 0.571848, + 0.141476, 0.097472, 0.356886, 0.341115}; + Cumprod(x, &y, 0); + check_shape(y.shape, {2, 3, 4}); + check_data(reinterpret_cast(y.Data()), result.data(), + result.size()); + + result = {0.842862, 0.646191, 0.137405, 0.114307, 0.556227, 0.34624, + 0.10208, 0.096659, 0.118077, 0.103768, 0.088011, 0.039528, + 0.126847, 0.15662, 0.428841, 0.847653, 0.031187, 0.104786, + 0.376901, 0.573233, 0.020785, 0.034079, 0.156014, 0.478157}; + Cumprod(x, &y, 1); + check_shape(y.shape, {2, 3, 4}); + check_data(reinterpret_cast(y.Data()), result.data(), + result.size()); + + result = {0.842862, 0.54465, 0.074837, 0.008554, 0.659926, 0.353599, + 0.262694, 0.222136, 0.212282, 0.063621, 0.054852, 0.022431, + 0.126847, 0.019867, 0.00852, 0.007222, 0.245863, 0.164494, + 0.144571, 0.097767, 0.666453, 0.216751, 0.089722, 0.07484}; + Cumprod(x, &y, 2); + check_shape(y.shape, {2, 3, 4}); + check_data(reinterpret_cast(y.Data()), result.data(), + result.size()); +} + +} // namespace function +} // namespace fastdeploy From 5555630dcdd02b9d51600e90769344280bd671f3 Mon Sep 17 00:00:00 2001 From: zhoushunjie Date: Thu, 24 Nov 2022 09:19:28 +0000 Subject: [PATCH 6/7] Add split functions --- fastdeploy/function/split.cc | 160 +++++++++++++++++++++++++++++++++++ fastdeploy/function/split.h | 36 ++++++++ fastdeploy/utils/utils.cc | 10 --- fastdeploy/utils/utils.h | 13 ++- tests/function/test_split.cc | 113 +++++++++++++++++++++++++ 5 files changed, 321 insertions(+), 11 deletions(-) create mode 100644 fastdeploy/function/split.cc create mode 100644 fastdeploy/function/split.h create mode 100644 tests/function/test_split.cc diff --git a/fastdeploy/function/split.cc b/fastdeploy/function/split.cc new file mode 100644 index 000000000..4cc923a9b --- /dev/null +++ b/fastdeploy/function/split.cc @@ -0,0 +1,160 @@ +// 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 "fastdeploy/function/split.h" +#include "fastdeploy/utils/utils.h" +#include + +namespace fastdeploy { +namespace function { + +/* + * All tensors' dimension should be the same and the values of + * each dimension must be the same, except the axis dimension. + */ +template struct SplitFunctor { + public: + void operator()(const FDTensor& input, + const std::vector& ref_inputs, int axis, + std::vector* outputs) { + if (input.Numel() == 0) { + return; + } + + size_t num = outputs->size(); + + int input_rows = 1; + auto dim_0 = ref_inputs[0]->Shape(); + for (int i = 0; i < axis; ++i) { + input_rows *= dim_0[i]; + } + + int input_cols = 0; + + std::vector output_cols(outputs->size()); + for (size_t i = 0; i < num; ++i) { + int t_cols = ref_inputs[i]->Numel() / input_rows; + input_cols += t_cols; + output_cols[i] = t_cols; + } + + // computation + for (int k = 0; k < input_rows; ++k) { + const T* src_ptr = + reinterpret_cast(input.Data()) + k * input_cols; + int col_idx = 0; + for (size_t j = 0; j < num; ++j) { + int col_len = output_cols[j]; + auto* out_tensor = &(outputs->at(j)); + if (out_tensor != nullptr) { + T* dst_ptr = reinterpret_cast(out_tensor->Data()) + k * col_len; + std::memcpy(dst_ptr, src_ptr + col_idx, sizeof(T) * col_len); + } + col_idx += col_len; + } + } + } +}; + +inline int GetSplitAxisValue(const FDTensor& x, int axis) { + int rank = x.Shape().size(); + FDASSERT(axis >= -rank && axis < rank, + "The axis is expected to be in range of [%d, %d), but got %d", -rank, + rank, axis); + if (axis < 0) { + axis = axis + rank; + } + return axis; +} + +void CreateSplitOutputs(const FDTensor& x, + const std::vector& sections_data, + std::vector* outs, int axis) { + axis = GetSplitAxisValue(x, axis); + auto input_axis_dim = x.Shape().at(axis); + std::vector sections_vec; + const int unknow_dim_val = -1; + int unknow_dim_idx = -1; + int num_of_unknow = 0; + int sum_of_section = 0; + + for (size_t i = 0; i < sections_data.size(); ++i) { + sections_vec.push_back(sections_data[i]); + if (sections_data[i] == unknow_dim_val) { + num_of_unknow++; + unknow_dim_idx = i; + } else { + sum_of_section += sections_data[i]; + } + } + + FDASSERT(num_of_unknow <= 1, + "Only one dimension value of Attr(num_or_sections) " + "in SplitOp can be -1. " + "But received Attr(num_or_sections) = [%s].", + Str(sections_data).c_str()); + if (unknow_dim_idx != -1) { + // for example, input shape = [4 ,5], axis = 1, sections = [2, 3, -1]. + // input_axis_dim = 5, sum_of_sections = 5. + // the following check will fail. + FDASSERT(sum_of_section < input_axis_dim, + "Sum of Attr(num_or_sections) other than unknown section " + "must be less than the input's " + "size " + "along the split dimension. But received Attr(num_or_sections) " + "= [%s], input(X)'s shape = [%s], Attr(dim) = %d.", + Str(sections_data).c_str(), Str(x.Shape()).c_str(), axis); + sections_vec[unknow_dim_idx] = input_axis_dim - sum_of_section; + } else { + FDASSERT(sum_of_section == input_axis_dim, + "Sum of Attr(num_or_sections) must be equal to the input's " + "size " + "along the split dimension. But received Attr(num_or_sections)" + " = [%s], input(X)'s shape = [%s], Attr(dim) = %d.", + Str(sections_data).c_str(), Str(x.Shape()).c_str(), axis); + } + // fill out dims + std::vector> out_dims(sections_vec.size(), x.Shape()); + for (size_t i = 0; i < sections_vec.size(); ++i) { + out_dims[i][axis] = sections_vec[i]; + } + for (size_t i = 0; i < sections_vec.size(); ++i) { + (*outs)[i].Allocate(out_dims[i], x.Dtype()); + } +} + +template +void SplitKernel(const FDTensor& x, const std::vector& section, + std::vector* outs, int axis) { + size_t out_number = section.size(); + outs->resize(out_number); + CreateSplitOutputs(x, section, outs, axis); + + std::vector shape_refer; + for (size_t j = 0; j < outs->size(); ++j) { + shape_refer.emplace_back(&((*outs)[j])); + } + SplitFunctor functor; + functor(x, shape_refer, axis, outs); +} + +void Split(const FDTensor& x, const std::vector& num_or_sections, + std::vector* out, int axis) { + FD_VISIT_ALL_TYPES(x.Dtype(), "Split", ([&] { + SplitKernel(x, num_or_sections, out, axis); + })); +} + +} // namespace function +} // namespace fastdeploy \ No newline at end of file diff --git a/fastdeploy/function/split.h b/fastdeploy/function/split.h new file mode 100644 index 000000000..162845d0d --- /dev/null +++ b/fastdeploy/function/split.h @@ -0,0 +1,36 @@ +// 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 "fastdeploy/core/fd_tensor.h" + +namespace fastdeploy { +namespace function { + +/** Split the input tensor into multiple sub-Tensors. + @param x The input tensor. + @param num_or_sections f num_or_sections is an int, then num_or_sections + indicates the number of equal sized sub-Tensors that the x will + be divided into. + @param out The output vector tensor which stores the result. + @param axis Axis which will be splitted. +*/ + +FASTDEPLOY_DECL void Split(const FDTensor& x, + const std::vector& num_or_sections, + std::vector* out, int axis = 0); + +} // namespace function +} // namespace fastdeploy diff --git a/fastdeploy/utils/utils.cc b/fastdeploy/utils/utils.cc index d89b1d555..4389cf6a7 100644 --- a/fastdeploy/utils/utils.cc +++ b/fastdeploy/utils/utils.cc @@ -56,14 +56,4 @@ std::vector GetStride(const std::vector& dims) { return result; } -std::string Str(const std::vector& shape) { - std::ostringstream oss; - oss << "[ " << shape[0]; - for (int i = 1; i < shape.size(); ++i) { - oss << " ," << shape[i]; - } - oss << " ]"; - return oss.str(); -} - } // namespace fastdeploy diff --git a/fastdeploy/utils/utils.h b/fastdeploy/utils/utils.h index 45b0f57cd..4114bc415 100644 --- a/fastdeploy/utils/utils.h +++ b/fastdeploy/utils/utils.h @@ -22,6 +22,7 @@ #include #include #include +#include #include #if defined(_WIN32) @@ -186,6 +187,16 @@ FASTDEPLOY_DECL bool ReadBinaryFromFile(const std::string& file, FASTDEPLOY_DECL std::vector GetStride(const std::vector& dims); -FASTDEPLOY_DECL std::string Str(const std::vector& shape); +template ::value, + bool>::type = true> +std::string Str(const std::vector& shape) { + std::ostringstream oss; + oss << "[ " << shape[0]; + for (int i = 1; i < shape.size(); ++i) { + oss << " ," << shape[i]; + } + oss << " ]"; + return oss.str(); +} } // namespace fastdeploy diff --git a/tests/function/test_split.cc b/tests/function/test_split.cc new file mode 100644 index 000000000..9e8f1b15b --- /dev/null +++ b/tests/function/test_split.cc @@ -0,0 +1,113 @@ +// 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 "fastdeploy/core/fd_tensor.h" +#include "fastdeploy/function/split.h" +#include "glog/logging.h" +#include "gtest_utils.h" +#include "gtest/gtest.h" +#include +#include + +namespace fastdeploy { +namespace function { + +std::vector CreateTestData() { + // Shape: [2, 3, 4] + std::vector x_data = { + 0.8428625, 0.6461913, 0.13740455, 0.11430702, 0.659926, 0.535816, + 0.7429162, 0.8456049, 0.21228176, 0.29970083, 0.8621713, 0.40894133, + 0.12684688, 0.1566195, 0.42884097, 0.8476526, 0.2458633, 0.669046, + 0.87888306, 0.6762589, 0.666453, 0.32523027, 0.4139388, 0.8341406}; + return x_data; +} + +TEST(fastdeploy, split_axis0) { + CheckShape check_shape; + CheckData check_data; + FDTensor x; + std::vector out; + auto test_data = CreateTestData(); + x.SetExternalData({2, 3, 4}, FDDataType::FP32, test_data.data()); + + Split(x, {1, 1}, &out, 0); + ASSERT_EQ(out.size(), 2); + check_shape(out[0].Shape(), {1, 3, 4}); + check_shape(out[1].Shape(), {1, 3, 4}); + std::vector result1 = {0.842862, 0.646191, 0.137405, 0.114307, + 0.659926, 0.535816, 0.742916, 0.845605, + 0.212282, 0.299701, 0.862171, 0.408941}; + std::vector result2 = {0.126847, 0.15662, 0.428841, 0.847653, + 0.245863, 0.669046, 0.878883, 0.676259, + 0.666453, 0.32523, 0.413939, 0.834141}; + check_data(reinterpret_cast(out[0].Data()), result1.data(), + result1.size()); + check_data(reinterpret_cast(out[1].Data()), result2.data(), + result2.size()); +} + +TEST(fastdeploy, split_axis1) { + CheckShape check_shape; + CheckData check_data; + FDTensor x; + std::vector out; + auto test_data = CreateTestData(); + x.SetExternalData({2, 3, 4}, FDDataType::FP32, test_data.data()); + + Split(x, {2, 1}, &out, 1); + ASSERT_EQ(out.size(), 2); + check_shape(out[0].Shape(), {2, 2, 4}); + check_shape(out[1].Shape(), {2, 1, 4}); + std::vector result1 = {0.842862, 0.646191, 0.137405, 0.114307, + 0.659926, 0.535816, 0.742916, 0.845605, + 0.126847, 0.15662, 0.428841, 0.847653, + 0.245863, 0.669046, 0.878883, 0.676259}; + std::vector result2 = {0.212282, 0.299701, 0.862171, 0.408941, + 0.666453, 0.32523, 0.413939, 0.834141}; + check_data(reinterpret_cast(out[0].Data()), result1.data(), + result1.size()); + check_data(reinterpret_cast(out[1].Data()), result2.data(), + result2.size()); +} + +TEST(fastdeploy, split_axis2) { + CheckShape check_shape; + CheckData check_data; + FDTensor x; + std::vector out; + auto test_data = CreateTestData(); + x.SetExternalData({2, 3, 4}, FDDataType::FP32, test_data.data()); + + Split(x, {1, 2, 1}, &out, 2); + ASSERT_EQ(out.size(), 3); + check_shape(out[0].Shape(), {2, 3, 1}); + check_shape(out[1].Shape(), {2, 3, 2}); + check_shape(out[2].Shape(), {2, 3, 1}); + std::vector result1 = {0.842862, 0.659926, 0.212282, + 0.126847, 0.245863, 0.666453}; + std::vector result2 = {0.646191, 0.137405, 0.535816, 0.742916, + 0.299701, 0.862171, 0.15662, 0.428841, + 0.669046, 0.878883, 0.32523, 0.413939}; + std::vector result3 = {0.114307, 0.845605, 0.408941, + 0.847653, 0.676259, 0.834141}; + check_data(reinterpret_cast(out[0].Data()), result1.data(), + result1.size()); + check_data(reinterpret_cast(out[1].Data()), result2.data(), + result2.size()); + check_data(reinterpret_cast(out[2].Data()), result3.data(), + result3.size()); +} + +} // namespace function +} // namespace fastdeploy \ No newline at end of file From 97165faa814890694a986aeaf7d373698c3f6e5e Mon Sep 17 00:00:00 2001 From: zhoushunjie Date: Fri, 25 Nov 2022 02:25:09 +0000 Subject: [PATCH 7/7] update args --- fastdeploy/function/tile.cc | 9 ++++++--- fastdeploy/function/tile.h | 3 ++- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/fastdeploy/function/tile.cc b/fastdeploy/function/tile.cc index 0e9e8389d..6437b4ec6 100644 --- a/fastdeploy/function/tile.cc +++ b/fastdeploy/function/tile.cc @@ -19,9 +19,11 @@ namespace fastdeploy { namespace function { template -void TileFunctor(const FDTensor& x, std::vector repeat_times, +void TileFunctor(const FDTensor& x, + const std::vector& origin_repeat_times, FDTensor* out) { auto x_shape = x.Shape(); + auto repeat_times = origin_repeat_times; for (size_t i = 0; i < repeat_times.size(); ++i) { FDASSERT(repeat_times[i] > 0, "All elements of the input 'repeat_times' " @@ -66,7 +68,7 @@ void TileFunctor(const FDTensor& x, std::vector repeat_times, } template -void TileKernel(const FDTensor& x, std::vector repeat_times, +void TileKernel(const FDTensor& x, const std::vector& repeat_times, FDTensor* out) { auto rank = x.Shape().size(); auto repeat_times_size = repeat_times.size(); @@ -96,7 +98,8 @@ void TileKernel(const FDTensor& x, std::vector repeat_times, } } -void Tile(const FDTensor& x, std::vector repeat_times, FDTensor* out) { +void Tile(const FDTensor& x, const std::vector& repeat_times, + FDTensor* out) { FD_VISIT_ALL_TYPES(x.dtype, "TileKernel", ([&] { TileKernel(x, repeat_times, out); })); } diff --git a/fastdeploy/function/tile.h b/fastdeploy/function/tile.h index b3a6bf2fb..26d6abd76 100644 --- a/fastdeploy/function/tile.h +++ b/fastdeploy/function/tile.h @@ -28,7 +28,8 @@ namespace function { @param repeat_times The lower bound @param out The output tensor which stores the result. */ -FASTDEPLOY_DECL void Tile(const FDTensor& x, std::vector repeat_times, +FASTDEPLOY_DECL void Tile(const FDTensor& x, + const std::vector& repeat_times, FDTensor* out); } // namespace function