mirror of
https://github.com/zebrajr/pytorch.git
synced 2025-12-07 12:21:27 +01:00
Summary: As GoogleTest `TEST` macro is non-compliant with it as well as `DEFINE_DISPATCH` All changes but the ones to `.clang-tidy` are generated using following script: ``` for i in `find . -type f -iname "*.c*" -or -iname "*.h"|xargs grep cppcoreguidelines-avoid-non-const-global-variables|cut -f1 -d:|sort|uniq`; do sed -i "/\/\/ NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)/d" $i; done ``` Pull Request resolved: https://github.com/pytorch/pytorch/pull/62008 Reviewed By: driazati, r-barnes Differential Revision: D29838584 Pulled By: malfet fbshipit-source-id: 1b2f8602c945bd4ce50a9bfdd204755556e31d13
132 lines
3.6 KiB
C++
132 lines
3.6 KiB
C++
#include "caffe2/operators/apmeter_op.h"
|
|
|
|
namespace caffe2 {
|
|
|
|
template <>
|
|
void APMeterOp<float, CPUContext>::BufferPredictions(
|
|
const float* XData,
|
|
const int* labelData,
|
|
int N,
|
|
int D) {
|
|
if (buffers_.empty()) {
|
|
// Initialize the buffer
|
|
buffers_.resize(D, std::vector<BufferDataType>(buffer_size_));
|
|
}
|
|
DCHECK_EQ(buffers_.size(), D);
|
|
|
|
// Fill atmose buffer_size_ data at a time, so truncate the input if needed
|
|
if (N > buffer_size_) {
|
|
XData = XData + (N - buffer_size_) * D;
|
|
labelData = labelData + (N - buffer_size_) * D;
|
|
N = buffer_size_;
|
|
}
|
|
|
|
// Reclaim space if not enough space in the buffer to hold new data
|
|
int space_to_reclaim = buffer_used_ + N - buffer_size_;
|
|
if (space_to_reclaim > 0) {
|
|
for (auto& buffer : buffers_) {
|
|
std::rotate(
|
|
buffer.begin(), buffer.begin() + space_to_reclaim, buffer.end());
|
|
}
|
|
buffer_used_ -= space_to_reclaim;
|
|
}
|
|
|
|
// Fill the buffer
|
|
for (int i = 0; i < D; i++) {
|
|
for (int j = 0; j < N; j++) {
|
|
buffers_[i][buffer_used_ + j].first = XData[j * D + i];
|
|
buffers_[i][buffer_used_ + j].second = labelData[j * D + i];
|
|
}
|
|
}
|
|
|
|
buffer_used_ += N;
|
|
}
|
|
|
|
template <>
|
|
bool APMeterOp<float, CPUContext>::RunOnDevice() {
|
|
auto& X = Input(PREDICTION);
|
|
auto& label = Input(LABEL);
|
|
|
|
// Check dimensions
|
|
DCHECK_EQ(X.dim(), 2);
|
|
int N = X.dim32(0);
|
|
int D = X.dim32(1);
|
|
DCHECK_EQ(label.dim(), 2);
|
|
DCHECK_EQ(label.dim32(0), N);
|
|
DCHECK_EQ(label.dim32(1), D);
|
|
auto* Y = Output(0, {D}, at::dtype<float>());
|
|
|
|
const auto* Xdata = X.data<float>();
|
|
const auto* labelData = label.data<int>();
|
|
auto* Ydata = Y->template mutable_data<float>();
|
|
|
|
BufferPredictions(Xdata, labelData, N, D);
|
|
|
|
// Calculate AP for each class
|
|
for (int i = 0; i < D; i++) {
|
|
auto& buffer = buffers_[i];
|
|
// Sort predictions by score
|
|
std::stable_sort(
|
|
buffer.begin(),
|
|
buffer.begin() + buffer_used_,
|
|
[](const BufferDataType& p1, const BufferDataType& p2) {
|
|
return p1.first > p2.first;
|
|
});
|
|
// Calculate cumulative precision for each sample
|
|
float tp_sum = 0.0;
|
|
float precision_sum = 0.0;
|
|
int ntruth = 0;
|
|
for (int j = 0; j < buffer_used_; j++) {
|
|
tp_sum += buffer[j].second;
|
|
if (buffer[j].second == 1) {
|
|
ntruth += 1;
|
|
// NOLINTNEXTLINE(cppcoreguidelines-narrowing-conversions,bugprone-narrowing-conversions)
|
|
precision_sum += tp_sum / (j + 1);
|
|
}
|
|
}
|
|
|
|
// Calculate AP
|
|
Ydata[i] = precision_sum / std::max(1, ntruth);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
namespace {
|
|
REGISTER_CPU_OPERATOR(APMeter, APMeterOp<float, CPUContext>);
|
|
|
|
OPERATOR_SCHEMA(APMeter)
|
|
.NumInputs(2)
|
|
.NumOutputs(1)
|
|
.ScalarType(TensorProto::FLOAT)
|
|
.SetDoc(R"DOC(
|
|
APMeter computes Average Precision for binary or multi-class classification.
|
|
It takes two inputs: prediction scores P of size (n_samples x n_classes), and
|
|
true labels Y of size (n_samples x n_classes). It returns a single float number
|
|
per class for the average precision of that class.
|
|
)DOC")
|
|
.Arg(
|
|
"buffer_size",
|
|
"(int32_t) indicates how many predictions should the op buffer. "
|
|
"defaults to 1000")
|
|
.Input(
|
|
0,
|
|
"predictions",
|
|
"2-D tensor (Tensor<float>) of size (num_samples x"
|
|
"num_classes) containing prediction scores")
|
|
.Input(
|
|
1,
|
|
"labels",
|
|
"2-D tensor (Tensor<float>) of size (num_samples) "
|
|
"containing true labels for each sample")
|
|
.Output(
|
|
0,
|
|
"AP",
|
|
"1-D tensor (Tensor<float>) of size num_classes containing "
|
|
"average precision for each class");
|
|
|
|
SHOULD_NOT_DO_GRADIENT(APMeter);
|
|
|
|
} // namespace
|
|
} // namespace caffe2
|