Files
paddlepaddle--paddle/paddle/phi/api/include/compat/ATen/ops/std.h
T
2026-07-13 12:40:42 +08:00

147 lines
4.8 KiB
C++

// Copyright (c) 2026 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 <ATen/core/Tensor.h>
#include <c10/core/Scalar.h>
#include <c10/util/ArrayRef.h>
#include <c10/util/OptionalArrayRef.h>
#include <optional>
#include <vector>
#include "paddle/phi/api/include/api.h"
#include "paddle/phi/common/int_array.h"
#include "paddle/phi/common/scalar.h"
namespace at::detail {
// Internal implementation for std (standard deviation = sqrt(variance))
inline Tensor _PD_std_impl(const Tensor& self,
const std::vector<int64_t>& dims_vec,
double correction_value,
bool keepdim) {
// Validate dimensions before processing
int64_t ndim = self.dim();
for (int64_t d : dims_vec) {
int64_t dim_idx = d < 0 ? d + ndim : d;
if (dim_idx < 0 || dim_idx >= ndim) {
PD_CHECK(false,
"Dimension out of range (expected to be in range of [",
-ndim,
", ",
ndim - 1,
"], but got ",
d,
")");
}
}
phi::IntArray dims_int_array(dims_vec);
paddle::Tensor tensor = self._PD_GetInner();
paddle::Tensor mean_tensor;
if (dims_vec.empty()) {
mean_tensor = paddle::experimental::mean(
tensor, phi::IntArray(std::vector<int64_t>{}), true);
} else {
mean_tensor = paddle::experimental::mean(tensor, dims_int_array, true);
}
paddle::Tensor diff = paddle::experimental::subtract(tensor, mean_tensor);
paddle::Tensor diff_squared = paddle::experimental::multiply(diff, diff);
paddle::Tensor sum_squared_diff;
if (dims_vec.empty()) {
sum_squared_diff =
paddle::experimental::sum(diff_squared,
phi::IntArray(std::vector<int64_t>{}),
diff_squared.dtype(),
keepdim);
} else {
sum_squared_diff = paddle::experimental::sum(
diff_squared, dims_int_array, diff_squared.dtype(), keepdim);
}
int64_t n = tensor.numel();
if (!dims_vec.empty()) {
n = 1;
for (int64_t d : dims_vec) {
int64_t dim_idx = d < 0 ? d + tensor.dims().size() : d;
if (dim_idx >= 0 &&
dim_idx < static_cast<int64_t>(tensor.dims().size())) {
n *= tensor.dims()[dim_idx];
}
}
}
double corrected_n = static_cast<double>(n) - correction_value;
if (corrected_n <= 0.0) {
corrected_n = static_cast<double>(n);
}
std::vector<int64_t> result_shape_vec;
for (int64_t i = 0; i < sum_squared_diff.dims().size(); ++i) {
result_shape_vec.push_back(sum_squared_diff.dims()[i]);
}
paddle::Tensor correction_scalar =
paddle::experimental::full(phi::IntArray(result_shape_vec),
phi::Scalar(corrected_n),
sum_squared_diff.dtype(),
sum_squared_diff.place());
paddle::Tensor variance =
paddle::experimental::divide(sum_squared_diff, correction_scalar);
paddle::Tensor result = paddle::experimental::sqrt(variance);
return Tensor(result);
}
} // namespace at::detail
namespace at {
inline Tensor Tensor::std(bool unbiased) const {
std::vector<int64_t> empty_dims;
double correction = unbiased ? 1.0 : 0.0;
return detail::_PD_std_impl(*this, empty_dims, correction, false);
}
inline Tensor Tensor::std(at::OptionalIntArrayRef dim,
bool unbiased,
bool keepdim) const {
double correction = unbiased ? 1.0 : 0.0;
std::vector<int64_t> dims_vec;
if (dim.has_value() && dim.value().size() > 0) {
dims_vec.assign(dim.value().begin(), dim.value().end());
}
return detail::_PD_std_impl(*this, dims_vec, correction, keepdim);
}
inline Tensor Tensor::std(at::OptionalIntArrayRef dim,
const ::std::optional<at::Scalar>& correction,
bool keepdim) const {
double correction_value = 1.0;
if (correction.has_value()) {
const at::Scalar& scalar = correction.value();
correction_value = scalar.to<double>();
}
std::vector<int64_t> dims_vec;
if (dim.has_value() && dim.value().size() > 0) {
dims_vec.assign(dim.value().begin(), dim.value().end());
}
return detail::_PD_std_impl(*this, dims_vec, correction_value, keepdim);
}
} // namespace at