Files
pytorch/caffe2/utils/math_test.cc
Will Constable 4f34cd6d1e Replace all CHECK_ and DCHECK_ with TORCH_* macros (#82032)
Avoid exposing defines that conflict with google logging, since this blocks external usage of libtorch in certain cases.

All the 'interesting' changes should be in these two files, and the rest should just be mechanical changes via sed.
c10/util/logging_is_not_google_glog.h
c10/util/logging_is_google_glog.h

Fixes https://github.com/pytorch/pytorch/issues/81415

cc @miladm @malfet
Pull Request resolved: https://github.com/pytorch/pytorch/pull/82032
Approved by: https://github.com/soumith, https://github.com/miladm
2022-07-26 01:20:44 +00:00

526 lines
14 KiB
C++

#include <array>
#include <memory>
#include <vector>
#include <gtest/gtest.h>
#include "caffe2/core/blob.h"
#include "caffe2/core/context.h"
#include "caffe2/core/tensor.h"
#include "caffe2/proto/caffe2_pb.h"
#include "caffe2/utils/conversions.h"
#include "caffe2/utils/math.h"
#include <c10/util/irange.h>
namespace caffe2 {
TEST(MathTest, GemmNoTransNoTrans) {
DeviceOption option;
CPUContext cpu_context(option);
Tensor X(std::vector<int>{5, 10}, CPU);
Tensor W(std::vector<int>{10, 6}, CPU);
Tensor Y(std::vector<int>{5, 6}, CPU);
EXPECT_EQ(X.numel(), 50);
EXPECT_EQ(W.numel(), 60);
math::Set<float, CPUContext>(
X.numel(), 1, X.mutable_data<float>(), &cpu_context);
math::Set<float, CPUContext>(
W.numel(), 1, W.mutable_data<float>(), &cpu_context);
EXPECT_EQ(Y.numel(), 30);
for (int i = 0; i < X.numel(); ++i) {
TORCH_CHECK_EQ(X.data<float>()[i], 1);
}
for (int i = 0; i < W.numel(); ++i) {
TORCH_CHECK_EQ(W.data<float>()[i], 1);
}
const float kOne = 1.0;
const float kPointFive = 0.5;
const float kZero = 0.0;
math::Gemm<float, CPUContext>(
CblasNoTrans,
CblasNoTrans,
5,
6,
10,
kOne,
X.data<float>(),
W.data<float>(),
kZero,
Y.mutable_data<float>(),
&cpu_context);
EXPECT_EQ(Y.numel(), 30);
for (int i = 0; i < Y.numel(); ++i) {
TORCH_CHECK_EQ(Y.data<float>()[i], 10) << i;
}
// Test Accumulate
math::Gemm<float, CPUContext>(
CblasNoTrans,
CblasNoTrans,
5,
6,
10,
kOne,
X.data<float>(),
W.data<float>(),
kPointFive,
Y.mutable_data<float>(),
&cpu_context);
EXPECT_EQ(Y.numel(), 30);
for (int i = 0; i < Y.numel(); ++i) {
TORCH_CHECK_EQ(Y.data<float>()[i], 15) << i;
}
// Test Accumulate
math::Gemm<float, CPUContext>(
CblasNoTrans,
CblasNoTrans,
5,
6,
10,
kPointFive,
X.data<float>(),
W.data<float>(),
kOne,
Y.mutable_data<float>(),
&cpu_context);
EXPECT_EQ(Y.numel(), 30);
for (int i = 0; i < Y.numel(); ++i) {
TORCH_CHECK_EQ(Y.data<float>()[i], 20) << i;
}
}
TEST(MathTest, GemmNoTransTrans) {
DeviceOption option;
CPUContext cpu_context(option);
Tensor X(std::vector<int>{5, 10}, CPU);
Tensor W(std::vector<int>{6, 10}, CPU);
Tensor Y(std::vector<int>{5, 6}, CPU);
EXPECT_EQ(X.numel(), 50);
EXPECT_EQ(W.numel(), 60);
math::Set<float, CPUContext>(
X.numel(), 1, X.mutable_data<float>(), &cpu_context);
math::Set<float, CPUContext>(
W.numel(), 1, W.mutable_data<float>(), &cpu_context);
EXPECT_EQ(Y.numel(), 30);
for (int i = 0; i < X.numel(); ++i) {
TORCH_CHECK_EQ(X.data<float>()[i], 1);
}
for (int i = 0; i < W.numel(); ++i) {
TORCH_CHECK_EQ(W.data<float>()[i], 1);
}
const float kOne = 1.0;
const float kPointFive = 0.5;
const float kZero = 0.0;
math::Gemm<float, CPUContext>(
CblasNoTrans,
CblasTrans,
5,
6,
10,
kOne,
X.data<float>(),
W.data<float>(),
kZero,
Y.mutable_data<float>(),
&cpu_context);
EXPECT_EQ(Y.numel(), 30);
for (int i = 0; i < Y.numel(); ++i) {
TORCH_CHECK_EQ(Y.data<float>()[i], 10) << i;
}
// Test Accumulate
math::Gemm<float, CPUContext>(
CblasNoTrans,
CblasTrans,
5,
6,
10,
kOne,
X.data<float>(),
W.data<float>(),
kPointFive,
Y.mutable_data<float>(),
&cpu_context);
EXPECT_EQ(Y.numel(), 30);
for (int i = 0; i < Y.numel(); ++i) {
TORCH_CHECK_EQ(Y.data<float>()[i], 15) << i;
}
math::Gemm<float, CPUContext>(
CblasNoTrans,
CblasTrans,
5,
6,
10,
kPointFive,
X.data<float>(),
W.data<float>(),
kOne,
Y.mutable_data<float>(),
&cpu_context);
EXPECT_EQ(Y.numel(), 30);
for (int i = 0; i < Y.numel(); ++i) {
TORCH_CHECK_EQ(Y.data<float>()[i], 20) << i;
}
}
namespace {
constexpr float kEps = 1e-5;
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-member-init)
class GemmBatchedTest
: public testing::TestWithParam<testing::tuple<bool, bool>> {
protected:
void SetUp() override {
cpu_context_ = make_unique<CPUContext>(option_);
ReinitializeTensor(
&X_, std::vector<int64_t>{3, 5, 10}, at::dtype<float>().device(CPU));
ReinitializeTensor(
&W_, std::vector<int64_t>{3, 6, 10}, at::dtype<float>().device(CPU));
ReinitializeTensor(
&Y_, std::vector<int64_t>{3, 5, 6}, at::dtype<float>().device(CPU));
math::Set<float, CPUContext>(
X_.numel(), 1, X_.mutable_data<float>(), cpu_context_.get());
math::Set<float, CPUContext>(
W_.numel(), 1, W_.mutable_data<float>(), cpu_context_.get());
trans_X_ = std::get<0>(GetParam());
trans_W_ = std::get<1>(GetParam());
}
void RunGemmBatched(const float alpha, const float beta) {
const float* X_data = X_.template data<float>();
const float* W_data = W_.template data<float>();
float* Y_data = Y_.template mutable_data<float>();
const int X_stride = 5 * 10;
const int W_stride = 6 * 10;
const int Y_stride = 5 * 6;
std::array<const float*, 3> X_array = {
X_data, X_data + X_stride, X_data + 2 * X_stride};
std::array<const float*, 3> W_array = {
W_data, W_data + W_stride, W_data + 2 * W_stride};
std::array<float*, 3> Y_array = {
Y_data, Y_data + Y_stride, Y_data + 2 * Y_stride};
math::GemmBatched(
trans_X_ ? CblasTrans : CblasNoTrans,
trans_W_ ? CblasTrans : CblasNoTrans,
3,
5,
6,
10,
alpha,
X_array.data(),
W_array.data(),
beta,
Y_array.data(),
cpu_context_.get());
}
void RunGemmStridedBatched(const float alpha, const float beta) {
const float* X_data = X_.template data<float>();
const float* W_data = W_.template data<float>();
float* Y_data = Y_.template mutable_data<float>();
const int X_stride = 5 * 10;
const int W_stride = 6 * 10;
const int Y_stride = 5 * 6;
math::GemmStridedBatched<float, CPUContext>(
trans_X_ ? CblasTrans : CblasNoTrans,
trans_W_ ? CblasTrans : CblasNoTrans,
3,
5,
6,
10,
alpha,
X_data,
X_stride,
W_data,
W_stride,
beta,
Y_data,
Y_stride,
cpu_context_.get());
}
void VerifyOutput(const float value) const {
for (int i = 0; i < Y_.numel(); ++i) {
EXPECT_FLOAT_EQ(value, Y_.template data<float>()[i]);
}
}
// NOLINTNEXTLINE(cppcoreguidelines-non-private-member-variables-in-classes)
DeviceOption option_;
// NOLINTNEXTLINE(cppcoreguidelines-non-private-member-variables-in-classes)
std::unique_ptr<CPUContext> cpu_context_;
// NOLINTNEXTLINE(cppcoreguidelines-non-private-member-variables-in-classes)
Tensor X_;
// NOLINTNEXTLINE(cppcoreguidelines-non-private-member-variables-in-classes)
Tensor W_;
// NOLINTNEXTLINE(cppcoreguidelines-non-private-member-variables-in-classes)
Tensor Y_;
// NOLINTNEXTLINE(cppcoreguidelines-non-private-member-variables-in-classes)
bool trans_X_;
// NOLINTNEXTLINE(cppcoreguidelines-non-private-member-variables-in-classes)
bool trans_W_;
};
TEST_P(GemmBatchedTest, GemmBatchedFloatTest) {
RunGemmBatched(1.0f, 0.0f);
VerifyOutput(10.0f);
RunGemmBatched(1.0f, 0.5f);
VerifyOutput(15.0f);
RunGemmBatched(0.5f, 1.0f);
VerifyOutput(20.0f);
}
TEST_P(GemmBatchedTest, GemmStridedBatchedFloatTest) {
RunGemmStridedBatched(1.0f, 0.0f);
VerifyOutput(10.0f);
RunGemmStridedBatched(1.0f, 0.5f);
VerifyOutput(15.0f);
RunGemmStridedBatched(0.5f, 1.0f);
VerifyOutput(20.0f);
}
INSTANTIATE_TEST_CASE_P(
GemmBatchedTrans,
GemmBatchedTest,
testing::Combine(testing::Bool(), testing::Bool()));
} // namespace
TEST(MathTest, GemvNoTrans) {
DeviceOption option;
CPUContext cpu_context(option);
Tensor A(std::vector<int>{5, 10}, CPU);
Tensor X(std::vector<int>{10}, CPU);
Tensor Y(std::vector<int>{5}, CPU);
EXPECT_EQ(A.numel(), 50);
EXPECT_EQ(X.numel(), 10);
math::Set<float, CPUContext>(
A.numel(), 1, A.mutable_data<float>(), &cpu_context);
math::Set<float, CPUContext>(
X.numel(), 1, X.mutable_data<float>(), &cpu_context);
EXPECT_EQ(Y.numel(), 5);
for (int i = 0; i < A.numel(); ++i) {
TORCH_CHECK_EQ(A.data<float>()[i], 1);
}
for (int i = 0; i < X.numel(); ++i) {
TORCH_CHECK_EQ(X.data<float>()[i], 1);
}
const float kOne = 1.0;
const float kPointFive = 0.5;
const float kZero = 0.0;
math::Gemv<float, CPUContext>(
CblasNoTrans,
5,
10,
kOne,
A.data<float>(),
X.data<float>(),
kZero,
Y.mutable_data<float>(),
&cpu_context);
for (int i = 0; i < Y.numel(); ++i) {
TORCH_CHECK_EQ(Y.data<float>()[i], 10) << i;
}
// Test Accumulate
math::Gemv<float, CPUContext>(
CblasNoTrans,
5,
10,
kOne,
A.data<float>(),
X.data<float>(),
kPointFive,
Y.mutable_data<float>(),
&cpu_context);
for (int i = 0; i < Y.numel(); ++i) {
TORCH_CHECK_EQ(Y.data<float>()[i], 15) << i;
}
// Test Accumulate
math::Gemv<float, CPUContext>(
CblasNoTrans,
5,
10,
kPointFive,
A.data<float>(),
X.data<float>(),
kOne,
Y.mutable_data<float>(),
&cpu_context);
for (int i = 0; i < Y.numel(); ++i) {
TORCH_CHECK_EQ(Y.data<float>()[i], 20) << i;
}
}
TEST(MathTest, GemvTrans) {
DeviceOption option;
CPUContext cpu_context(option);
Tensor A(std::vector<int>{6, 10}, CPU);
Tensor X(std::vector<int>{6}, CPU);
Tensor Y(std::vector<int>{10}, CPU);
EXPECT_EQ(A.numel(), 60);
EXPECT_EQ(X.numel(), 6);
math::Set<float, CPUContext>(
A.numel(), 1, A.mutable_data<float>(), &cpu_context);
math::Set<float, CPUContext>(
X.numel(), 1, X.mutable_data<float>(), &cpu_context);
EXPECT_EQ(Y.numel(), 10);
for (int i = 0; i < A.numel(); ++i) {
TORCH_CHECK_EQ(A.data<float>()[i], 1);
}
for (int i = 0; i < X.numel(); ++i) {
TORCH_CHECK_EQ(X.data<float>()[i], 1);
}
const float kOne = 1.0;
const float kPointFive = 0.5;
const float kZero = 0.0;
math::Gemv<float, CPUContext>(
CblasTrans,
6,
10,
kOne,
A.data<float>(),
X.data<float>(),
kZero,
Y.mutable_data<float>(),
&cpu_context);
for (int i = 0; i < Y.numel(); ++i) {
TORCH_CHECK_EQ(Y.data<float>()[i], 6) << i;
}
// Test Accumulate
math::Gemv<float, CPUContext>(
CblasTrans,
6,
10,
kOne,
A.data<float>(),
X.data<float>(),
kPointFive,
Y.mutable_data<float>(),
&cpu_context);
for (int i = 0; i < Y.numel(); ++i) {
TORCH_CHECK_EQ(Y.data<float>()[i], 9) << i;
}
// Test Accumulate
math::Gemv<float, CPUContext>(
CblasTrans,
6,
10,
kPointFive,
A.data<float>(),
X.data<float>(),
kOne,
Y.mutable_data<float>(),
&cpu_context);
for (int i = 0; i < Y.numel(); ++i) {
TORCH_CHECK_EQ(Y.data<float>()[i], 12) << i;
}
}
TEST(MathTest, FloatToHalfConversion) {
float a = 1.0f;
float b = 1.75f;
float c = 128.125f;
float converted_a = static_cast<float>(at::Half(a));
float converted_b = static_cast<float>(at::Half(b));
float converted_c = static_cast<float>(at::Half(c));
TORCH_CHECK_EQ(a, converted_a);
TORCH_CHECK_EQ(b, converted_b);
TORCH_CHECK_EQ(c, converted_c);
}
namespace {
class BroadcastTest : public testing::Test {
protected:
void SetUp() override {
cpu_context_ = make_unique<CPUContext>(option_);
}
void RunBroadcastTest(
const std::vector<int>& X_dims,
const std::vector<int>& Y_dims,
const std::vector<float>& X_data,
const std::vector<float>& Y_data) {
std::vector<int64_t> X_dims_64;
std::vector<int64_t> Y_dims_64;
std::copy(X_dims.cbegin(), X_dims.cend(), std::back_inserter(X_dims_64));
std::copy(Y_dims.cbegin(), Y_dims.cend(), std::back_inserter(Y_dims_64));
ReinitializeTensor(&X_, X_dims_64, at::dtype<float>().device(CPU));
ReinitializeTensor(&Y_, Y_dims_64, at::dtype<float>().device(CPU));
ASSERT_EQ(X_data.size(), X_.numel());
cpu_context_->CopyFromCPU<float>(
X_data.size(), X_data.data(), X_.mutable_data<float>());
for (bool allow_broadcast_fastpath : {false, true}) {
math::Broadcast<float, CPUContext>(
X_dims.size(),
X_dims.data(),
Y_dims.size(),
Y_dims.data(),
1.0f,
X_.data<float>(),
Y_.mutable_data<float>(),
cpu_context_.get(),
allow_broadcast_fastpath);
ASSERT_EQ(Y_data.size(), Y_.numel());
for (const auto i : c10::irange(Y_data.size())) {
EXPECT_FLOAT_EQ(Y_data[i], Y_.data<float>()[i]);
}
}
}
// NOLINTNEXTLINE(cppcoreguidelines-non-private-member-variables-in-classes)
DeviceOption option_;
// NOLINTNEXTLINE(cppcoreguidelines-non-private-member-variables-in-classes)
std::unique_ptr<CPUContext> cpu_context_;
// NOLINTNEXTLINE(cppcoreguidelines-non-private-member-variables-in-classes)
Tensor X_;
// NOLINTNEXTLINE(cppcoreguidelines-non-private-member-variables-in-classes)
Tensor Y_;
};
TEST_F(BroadcastTest, BroadcastFloatTest) {
RunBroadcastTest({2}, {2}, {1.0f, 2.0f}, {1.0f, 2.0f});
RunBroadcastTest({1}, {2}, {1.0f}, {1.0f, 1.0f});
RunBroadcastTest({1}, {2, 2}, {1.0f}, {1.0f, 1.0f, 1.0f, 1.0f});
RunBroadcastTest({2, 1}, {2, 2}, {1.0f, 2.0f}, {1.0f, 1.0f, 2.0f, 2.0f});
RunBroadcastTest({1, 2}, {2, 2}, {1.0f, 2.0f}, {1.0f, 2.0f, 1.0f, 2.0f});
RunBroadcastTest(
{2, 1},
{2, 2, 2},
{1.0f, 2.0f},
{1.0f, 1.0f, 2.0f, 2.0f, 1.0f, 1.0f, 2.0f, 2.0f});
RunBroadcastTest(
{1, 2},
{2, 2, 2},
{1.0f, 2.0f},
{1.0f, 2.0f, 1.0f, 2.0f, 1.0f, 2.0f, 1.0f, 2.0f});
}
class RandFixedSumTest : public testing::Test {
protected:
void SetUp() override {
cpu_context_ = make_unique<CPUContext>(option_);
}
// NOLINTNEXTLINE(cppcoreguidelines-non-private-member-variables-in-classes)
DeviceOption option_;
// NOLINTNEXTLINE(cppcoreguidelines-non-private-member-variables-in-classes)
std::unique_ptr<CPUContext> cpu_context_;
};
TEST_F(RandFixedSumTest, UpperBound) {
std::vector<int> l(20);
math::RandFixedSum<int, CPUContext>(
20, 1, 1000, 1000, l.data(), cpu_context_.get());
}
} // namespace
} // namespace caffe2