134 lines
4.7 KiB
C++
134 lines
4.7 KiB
C++
/* 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/kernels/funcs/cross_entropy.h"
|
|
|
|
#include "paddle/phi/backends/cpu/cpu_context.h"
|
|
#include "paddle/phi/core/utils/data_type.h"
|
|
|
|
namespace phi {
|
|
namespace funcs {
|
|
|
|
template <typename T, int MajorType = Eigen::RowMajor>
|
|
using EigenMatrix = EigenMatrix<T, MajorType>;
|
|
|
|
template <typename T>
|
|
struct HardLabelCrossEntropyCPUFunctorImpl {
|
|
HardLabelCrossEntropyCPUFunctorImpl(DenseTensor* out,
|
|
const DenseTensor* prob,
|
|
const DenseTensor* labels,
|
|
const int ignore_index,
|
|
const int64_t axis_dim)
|
|
: out_(out),
|
|
prob_(prob),
|
|
labels_(labels),
|
|
ignore_index_(ignore_index),
|
|
axis_dim_(axis_dim) {}
|
|
|
|
template <typename U>
|
|
void apply() const {
|
|
int64_t batch_size = prob_->dims()[0];
|
|
|
|
int64_t num_classes = prob_->dims()[1];
|
|
|
|
const int64_t num_remain = num_classes / axis_dim_;
|
|
|
|
const T* prob_data = prob_->template data<T>();
|
|
T* loss_data = out_->template data<T>();
|
|
|
|
const auto* label_data = labels_->template data<U>();
|
|
for (int64_t i = 0; i < batch_size; ++i) {
|
|
for (int64_t j = 0; j < num_remain; j++) {
|
|
int64_t lbl = static_cast<int64_t>(label_data[i * num_remain + j]);
|
|
if (lbl != ignore_index_) {
|
|
PADDLE_ENFORCE_GE(lbl,
|
|
0,
|
|
common::errors::OutOfRange(
|
|
"label value should >= 0 when label "
|
|
"value(%f) not equal to ignore_index(%f)",
|
|
lbl,
|
|
ignore_index_));
|
|
PADDLE_ENFORCE_LT(
|
|
lbl,
|
|
axis_dim_,
|
|
common::errors::OutOfRange(
|
|
"label value should less than the shape of axis dimension "
|
|
"when label value(%f) not equal to ignore_index(%f), But "
|
|
"received label value as %ld and shape of axis dimension "
|
|
"is %ld",
|
|
lbl,
|
|
ignore_index_,
|
|
lbl,
|
|
axis_dim_));
|
|
}
|
|
int64_t index = i * num_classes + lbl * num_remain + j;
|
|
int64_t loss_idx = i * num_remain + j;
|
|
loss_data[loss_idx] =
|
|
lbl == ignore_index_
|
|
? 0
|
|
: -funcs::TolerableValue<T>()(std::log(prob_data[index]));
|
|
}
|
|
}
|
|
}
|
|
|
|
private:
|
|
DenseTensor* out_;
|
|
const DenseTensor* prob_;
|
|
const DenseTensor* labels_;
|
|
const int ignore_index_;
|
|
const int64_t axis_dim_;
|
|
};
|
|
|
|
template <typename DeviceContext, typename T>
|
|
void CrossEntropyFunctor<DeviceContext, T>::operator()(
|
|
const DeviceContext& dev_ctx,
|
|
DenseTensor* out,
|
|
const DenseTensor* prob,
|
|
const DenseTensor* labels,
|
|
const bool softLabel,
|
|
const int ignore_index,
|
|
const int64_t axis_dim) {
|
|
if (softLabel) {
|
|
// TODO(large-tensor): Eigen::DSizes not support int64
|
|
PADDLE_ENFORCE_LE_INT_MAX(prob->dims()[0], "prob->dims()[0]");
|
|
PADDLE_ENFORCE_LE_INT_MAX(prob->dims()[1], "prob->dims()[1]");
|
|
PADDLE_ENFORCE_LE_INT_MAX(axis_dim, "axis_dim");
|
|
const int batch_size = static_cast<const int>(prob->dims()[0]);
|
|
const int num_classes = static_cast<const int>(prob->dims()[1]);
|
|
const int axis_dim_int = static_cast<int>(axis_dim);
|
|
const int num_remain = num_classes / axis_dim_int;
|
|
|
|
Eigen::DSizes<int, 3> batch_axis_remain(
|
|
batch_size, axis_dim_int, num_remain);
|
|
auto in = EigenMatrix<T>::From(*prob);
|
|
auto lbl = EigenMatrix<T>::From(*labels);
|
|
auto loss = EigenMatrix<T>::From(*out);
|
|
|
|
loss.device(*dev_ctx.eigen_device()) =
|
|
-((lbl * in.log().unaryExpr(funcs::TolerableValue<T>()))
|
|
.reshape(batch_axis_remain)
|
|
.sum(Eigen::DSizes<int, 1>(1)));
|
|
} else {
|
|
HardLabelCrossEntropyCPUFunctorImpl<T> functor_impl(
|
|
out, prob, labels, ignore_index, axis_dim);
|
|
phi::VisitDataType(labels->dtype(), functor_impl);
|
|
}
|
|
}
|
|
|
|
template class CrossEntropyFunctor<CPUContext, float>;
|
|
template class CrossEntropyFunctor<CPUContext, double>;
|
|
|
|
} // namespace funcs
|
|
} // namespace phi
|