blob: aa31ffc59bb51a3bba433b711d21ccf5835658a8 [file] [log] [blame]
#include <c10/core/Device.h>
#include <c10/core/DeviceType.h>
#include <gtest/gtest.h>
#include <test/cpp/lazy/test_lazy_ops_util.h>
#include <torch/csrc/lazy/core/debug_util.h>
#include <torch/csrc/lazy/core/helpers.h>
#include <torch/csrc/lazy/core/ir_builder.h>
#include <torch/csrc/lazy/core/lazy_graph_executor.h>
#include <torch/csrc/lazy/core/metrics.h>
#include <torch/csrc/lazy/core/permutation_util.h>
#include <torch/csrc/lazy/ts_backend/dynamic_ir.h>
#include <torch/csrc/lazy/ts_backend/ts_backend_impl.h>
#include <torch/torch.h>
#include <iostream>
namespace torch {
namespace lazy {
// Lazy Tensor is disabled in FBCODE until addressing non-virtual methods (e.g.
// sizes) in TensorImpl
#ifndef FBCODE_CAFFE2
namespace {
// This registers the torchscript backend, without which lazy device won't work.
// FIXME: This registers the backend for the whole test binary. We should
// probably do it and undo it in the test fixture below.
static bool inline init_backend() {
torch::lazy::InitTorchScriptBackend();
return true;
}
static const bool backend_initialized = init_backend();
} // namespace
class LazyTsTest : public ::testing::Test {
protected:
void SetUp() override;
void TearDown() override;
static void CommonSetup() {}
void ExpectCounterNotChanged(
const std::string& counter_regex,
const std::unordered_set<std::string>* ignore_set) {}
void ExpectCounterChanged(
const std::string& counter_regex,
const std::unordered_set<std::string>* ignore_set) {}
void ResetCounters() {}
private:
void MakeEndSnapshot() {}
};
class LazyOpsTestBase : public LazyTsTest {
protected:
static void SetUpTestCase() {}
};
void LazyTsTest::SetUp() {
(void)backend_initialized; // avoid unused parameter warning
at::manual_seed(42);
torch::lazy::LazyGraphExecutor::Get()->SetRngSeed(
torch::lazy::BackendDevice(), 42);
}
void LazyTsTest::TearDown() {}
namespace {
using torch::lazy::DebugUtil;
class LazyOpsTest : public LazyOpsTestBase {};
static inline bool IsCuda() {
return torch::lazy::getBackend()->EagerFallbackDeviceType() == at::kCUDA;
}
static inline at::DeviceType DefaultDevice() {
return torch::lazy::getBackend()->EagerFallbackDeviceType();
}
} // namespace
TEST_F(LazyOpsTest, TestScalarTensor) {
torch::Tensor scalar_tensor = torch::scalar_tensor(
1., torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_scalar_tensor = torch::scalar_tensor(
1., torch::TensorOptions(torch::kFloat).device(torch::kLazy));
AllClose(scalar_tensor, lazy_scalar_tensor);
});
}
TEST_F(LazyOpsTest, TestClone) {
ForEachDevice([&](const torch::Device& device) {
torch::Tensor a = torch::rand(
{2, 2}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = lazy_a.clone();
AllClose(a, lazy_b);
lazy_a.add_(1.0);
AllClose(a, lazy_b);
});
}
TEST_F(LazyOpsTest, TestTo) {
ForEachDevice([&](const torch::Device& device) {
torch::Tensor a = torch::rand(
{2, 2}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor lazy_a = CopyToDevice(a, device);
AllClose(a, lazy_a);
});
}
TEST_F(LazyOpsTest, TestIsFloatingPoint) {
ForEachDevice([&](const torch::Device& device) {
torch::Tensor a = torch::rand(
{2, 2}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor lazy_a = CopyToDevice(a, device);
bool is_float = torch::is_floating_point(a);
bool lazy_is_float = torch::is_floating_point(lazy_a);
EXPECT_EQ(is_float, lazy_is_float);
});
}
TEST_F(LazyOpsTest, TestIsSigned) {
ForEachDevice([&](const torch::Device& device) {
torch::Tensor a = torch::rand(
{2, 2}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor lazy_a = CopyToDevice(a, device);
bool is_signed = torch::is_signed(a);
bool lazy_is_signed = torch::is_signed(lazy_a);
EXPECT_EQ(is_signed, lazy_is_signed);
});
}
TEST_F(LazyOpsTest, TestCastByte) {
torch::Tensor a =
torch::rand(
{2, 2}, torch::TensorOptions(torch::kFloat).device(DefaultDevice())) *
100.0;
torch::Tensor b = torch::_cast_Byte(a);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = torch::_cast_Byte(lazy_a);
AllEqual(b, lazy_b);
});
}
TEST_F(LazyOpsTest, TestCastChar) {
torch::Tensor a =
torch::rand(
{2, 2}, torch::TensorOptions(torch::kFloat).device(DefaultDevice())) *
100.0;
torch::Tensor b = torch::_cast_Char(a);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = torch::_cast_Char(lazy_a);
AllEqual(b, lazy_b);
});
}
TEST_F(LazyOpsTest, TestCastShort) {
torch::Tensor a =
torch::rand(
{2, 2}, torch::TensorOptions(torch::kFloat).device(DefaultDevice())) *
100.0;
torch::Tensor b = torch::_cast_Short(a);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = torch::_cast_Short(lazy_a);
AllEqual(b, lazy_b);
});
}
TEST_F(LazyOpsTest, TestCastInt) {
torch::Tensor a =
torch::rand(
{2, 2}, torch::TensorOptions(torch::kFloat).device(DefaultDevice())) *
100.0;
torch::Tensor b = torch::_cast_Int(a);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = torch::_cast_Int(lazy_a);
AllEqual(b, lazy_b);
});
}
TEST_F(LazyOpsTest, TestCastLong) {
torch::Tensor a =
torch::rand(
{2, 2}, torch::TensorOptions(torch::kFloat).device(DefaultDevice())) *
100.0;
torch::Tensor b = torch::_cast_Long(a);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = torch::_cast_Long(lazy_a);
AllEqual(b, lazy_b);
});
}
TEST_F(LazyOpsTest, TestCastFloat) {
torch::Tensor a =
torch::rand(
{2, 2}, torch::TensorOptions(torch::kFloat).device(DefaultDevice())) *
100.0;
torch::Tensor b = torch::_cast_Float(a);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = torch::_cast_Float(lazy_a);
AllEqual(b, lazy_b);
});
}
TEST_F(LazyOpsTest, TestRetainType) {
torch::Tensor lazy_a = torch::zeros(
{2, 2}, torch::TensorOptions(torch::kByte).device(torch::kLazy));
torch::Tensor lazy_b = torch::ones(
{2, 2}, torch::TensorOptions(torch::kByte).device(torch::kLazy));
torch::Tensor lazy_c = lazy_a + lazy_b;
EXPECT_EQ(lazy_c.scalar_type(), torch::ScalarType::Byte);
}
TEST_F(LazyOpsTest, TestLogicalTypeWithInterop) {
torch::Tensor query = torch::rand(
{2, 12, 20, 64},
torch::TensorOptions(torch::kFloat).device(torch::kLazy));
torch::Tensor key = torch::rand(
{2, 12, 64, 20},
torch::TensorOptions(torch::kFloat).device(torch::kLazy));
torch::Tensor scores =
torch::matmul(query, key) /
torch::scalar_tensor(
8, torch::TensorOptions(torch::kDouble).device(torch::kLazy));
torch::Tensor p_attn = torch::softmax(scores, /*dim=*/-1);
EXPECT_EQ(p_attn.scalar_type(), torch::ScalarType::Float);
}
TEST_F(LazyOpsTest, TestAdd) {
torch::Tensor a = torch::rand(
{2, 2}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor b = torch::rand(
{2, 2}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor c = torch::add(a, b);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = CopyToDevice(b, device);
torch::Tensor lazy_c = torch::add(lazy_a, lazy_b);
AllClose(c, lazy_c);
});
}
TEST_F(LazyOpsTest, TestAddHalf) {
torch::Tensor a = torch::rand(
{2, 2}, torch::TensorOptions(torch::kHalf).device(DefaultDevice()));
torch::Tensor b = torch::rand(
{2, 2}, torch::TensorOptions(torch::kHalf).device(DefaultDevice()));
torch::Tensor c = torch::add(a, b);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = CopyToDevice(b, device);
torch::Tensor lazy_c = torch::add(lazy_a, lazy_b);
AllClose(c, lazy_c);
});
}
TEST_F(LazyOpsTest, TestAddMixedPrecision) {
torch::Tensor a = torch::rand(
{2, 2}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor b = torch::rand(
{2, 2}, torch::TensorOptions(torch::kHalf).device(DefaultDevice()));
torch::Tensor c = torch::add(a, b);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = CopyToDevice(b, device);
torch::Tensor lazy_c = torch::add(lazy_a, lazy_b);
AllClose(c, lazy_c);
});
}
TEST_F(LazyOpsTest, TestAddInPlace) {
ForEachDevice([&](const torch::Device& device) {
torch::Tensor a = torch::rand(
{2, 2}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor b = torch::rand(
{2, 2}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor lazy_b = CopyToDevice(b, device);
torch::Tensor c = a.add_(b);
torch::Tensor lazy_c = lazy_a.add_(lazy_b);
AllClose(a, lazy_a);
AllClose(c, lazy_c);
});
}
TEST_F(LazyOpsTest, TestAddScalar) {
torch::Tensor a = torch::rand(
{2, 2}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Scalar b(1);
torch::Tensor c = torch::add(a, b);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_c = torch::add(lazy_a, b);
AllClose(c, lazy_c);
});
}
TEST_F(LazyOpsTest, TestAddScalarInPlace) {
torch::Scalar b(1);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor a = torch::rand(
{2, 2}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor c = a.add_(b);
torch::Tensor lazy_c = lazy_a.add_(b);
AllClose(a, lazy_a);
AllClose(c, lazy_c);
});
}
TEST_F(LazyOpsTest, TestAddZeroSizeDim) {
torch::Tensor a = torch::rand(
{0, 2}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor b = torch::rand(
{1, 2}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor c = torch::add(a, b);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = CopyToDevice(b, device);
torch::Tensor lazy_c = torch::add(lazy_a, lazy_b);
AllClose(c, lazy_c);
});
}
TEST_F(LazyOpsTest, TestSub) {
torch::Tensor a = torch::rand(
{2, 2}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor b = torch::rand(
{2, 2}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor c = torch::sub(a, b);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = CopyToDevice(b, device);
torch::Tensor lazy_c = torch::sub(lazy_a, lazy_b);
AllClose(c, lazy_c);
});
}
TEST_F(LazyOpsTest, TestSubInPlace) {
ForEachDevice([&](const torch::Device& device) {
torch::Tensor a = torch::rand(
{2, 2}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor b = torch::rand(
{2, 2}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor lazy_b = CopyToDevice(b, device);
torch::Tensor c = a.sub_(b);
torch::Tensor lazy_c = lazy_a.sub_(lazy_b);
AllClose(a, lazy_a);
AllClose(c, lazy_c);
});
}
TEST_F(LazyOpsTest, TestSubScalar) {
torch::Tensor a = torch::rand(
{2, 2}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Scalar b(1);
torch::Tensor c = torch::sub(a, b);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_c = torch::sub(lazy_a, b);
AllClose(c, lazy_c);
});
}
TEST_F(LazyOpsTest, TestSubScalarInPlace) {
torch::Scalar b(1);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor a = torch::rand(
{2, 2}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor c = a.sub_(b);
torch::Tensor lazy_c = lazy_a.sub_(b);
AllClose(a, lazy_a);
AllClose(c, lazy_c);
});
}
TEST_F(LazyOpsTest, TestMul) {
torch::Tensor a = torch::rand(
{2, 2}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor b = torch::rand(
{2, 2}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor c = torch::mul(a, b);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = CopyToDevice(b, device);
torch::Tensor lazy_c = torch::mul(lazy_a, lazy_b);
AllClose(c, lazy_c);
});
}
TEST_F(LazyOpsTest, TestMulInPlace) {
ForEachDevice([&](const torch::Device& device) {
torch::Tensor a = torch::rand(
{2, 2}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor b = torch::rand(
{2, 2}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor lazy_b = CopyToDevice(b, device);
torch::Tensor c = a.mul_(b);
torch::Tensor lazy_c = lazy_a.mul_(lazy_b);
AllClose(a, lazy_a);
AllClose(c, lazy_c);
});
}
TEST_F(LazyOpsTest, TestMulScalar) {
torch::Tensor a = torch::rand(
{2, 2}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Scalar b(3);
torch::Tensor c = torch::mul(a, b);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_c = torch::mul(lazy_a, b);
AllClose(c, lazy_c);
});
}
TEST_F(LazyOpsTest, TestMulScalarInPlace) {
torch::Scalar b(3);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor a = torch::rand(
{2, 2}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor c = a.mul_(b);
torch::Tensor lazy_c = lazy_a.mul_(b);
AllClose(a, lazy_a);
AllClose(c, lazy_c);
});
}
TEST_F(LazyOpsTest, TestDiv) {
for (torch::ScalarType scalar_type1 :
{torch::kFloat,
torch::kByte,
torch::kChar,
torch::kShort,
torch::kInt,
torch::kLong}) {
torch::Tensor a = isFloatingType(scalar_type1)
? torch::rand({3, 4}, torch::TensorOptions(scalar_type1))
: torch::randint(0, 100, {3, 4}, torch::TensorOptions(scalar_type1));
for (torch::ScalarType scalar_type2 :
{torch::kFloat,
torch::kByte,
torch::kChar,
torch::kShort,
torch::kInt,
torch::kLong}) {
torch::Tensor b = isFloatingType(scalar_type2)
? torch::rand({3, 4}, torch::TensorOptions(scalar_type2))
: torch::randint(1, 100, {3, 4}, torch::TensorOptions(scalar_type2));
torch::Tensor c = torch::div(a, b);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = CopyToDevice(b, device);
torch::Tensor lazy_c = torch::div(lazy_a, lazy_b);
AllClose(c, lazy_c);
});
}
}
}
TEST_F(LazyOpsTest, TestDivWithRoundingMode) {
c10::optional<c10::string_view> rounding_modes[] = {
"trunc", "floor", c10::nullopt};
for (const auto& rounding_mode : rounding_modes) {
for (torch::ScalarType scalar_type1 :
{torch::kFloat,
torch::kByte,
torch::kChar,
torch::kShort,
torch::kInt,
torch::kLong}) {
int lower_bound = (scalar_type1 == torch::kByte) ? 0 : -100;
torch::Tensor a = isFloatingType(scalar_type1)
? torch::rand({3, 4}, torch::TensorOptions(scalar_type1))
: torch::randint(
lower_bound, 50, {3, 4}, torch::TensorOptions(scalar_type1));
for (torch::ScalarType scalar_type2 :
{torch::kFloat,
torch::kByte,
torch::kChar,
torch::kShort,
torch::kInt,
torch::kLong}) {
torch::Tensor b = isFloatingType(scalar_type2)
? torch::rand({3, 4}, torch::TensorOptions(scalar_type2))
: torch::randint(
51, 100, {3, 4}, torch::TensorOptions(scalar_type2));
torch::Tensor c = torch::div(a, b, rounding_mode);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = CopyToDevice(b, device);
torch::Tensor lazy_c = torch::div(lazy_a, lazy_b, rounding_mode);
AllClose(c, lazy_c);
});
}
}
}
}
TEST_F(LazyOpsTest, TestDivInPlace) {
for (torch::ScalarType scalar_type1 : {torch::kFloat}) {
torch::Tensor a = isFloatingType(scalar_type1)
? torch::rand({3, 4}, torch::TensorOptions(scalar_type1))
: torch::randint(0, 100, {3, 4}, torch::TensorOptions(scalar_type1));
for (torch::ScalarType scalar_type2 : {torch::kFloat}) {
torch::Tensor b = isFloatingType(scalar_type2)
? torch::rand({3, 4}, torch::TensorOptions(scalar_type2))
: torch::randint(1, 100, {3, 4}, torch::TensorOptions(scalar_type2));
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor c = a.div_(b);
torch::Tensor lazy_b = CopyToDevice(b, device);
torch::Tensor lazy_c = lazy_a.div_(lazy_b);
;
AllClose(c, lazy_c);
});
}
}
}
TEST_F(LazyOpsTest, TestDivInPlaceWithRoundingMode) {
c10::optional<c10::string_view> rounding_modes[] = {
"trunc", "floor", c10::nullopt};
for (const auto& rounding_mode : rounding_modes) {
for (torch::ScalarType scalar_type1 : {torch::kFloat}) {
torch::Tensor a = isFloatingType(scalar_type1)
? torch::rand({3, 4}, torch::TensorOptions(scalar_type1))
: torch::randint(
-100, 100, {3, 4}, torch::TensorOptions(scalar_type1));
for (torch::ScalarType scalar_type2 : {torch::kFloat}) {
torch::Tensor b = isFloatingType(scalar_type2)
? torch::rand({3, 4}, torch::TensorOptions(scalar_type2))
: torch::randint(
1, 100, {3, 4}, torch::TensorOptions(scalar_type2));
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor c = a.div_(b, rounding_mode);
torch::Tensor lazy_b = CopyToDevice(b, device);
torch::Tensor lazy_c = lazy_a.div_(lazy_b, rounding_mode);
AllClose(c, lazy_c);
});
}
}
}
}
TEST_F(LazyOpsTest, TestDivScalar) {
for (torch::ScalarType scalar_type :
{torch::kFloat,
torch::kByte,
torch::kChar,
torch::kShort,
torch::kInt,
torch::kLong}) {
torch::Tensor a = isFloatingType(scalar_type)
? torch::rand(
{3, 4}, torch::TensorOptions(scalar_type).device(DefaultDevice()))
: torch::randint(
1,
100,
{3, 4},
torch::TensorOptions(scalar_type).device(DefaultDevice()));
for (bool is_float : {true, false}) {
torch::Scalar b = is_float ? torch::Scalar(3.0) : torch::Scalar(3);
torch::Tensor c = torch::div(a, b);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_c = torch::div(lazy_a, b);
AllClose(c, lazy_c);
});
}
}
}
TEST_F(LazyOpsTest, TestDivScalarInPlace) {
for (torch::ScalarType scalar_type : {torch::kFloat}) {
torch::Tensor a = isFloatingType(scalar_type)
? torch::rand(
{3, 4}, torch::TensorOptions(scalar_type).device(DefaultDevice()))
: torch::randint(
1,
100,
{3, 4},
torch::TensorOptions(scalar_type).device(DefaultDevice()));
for (bool is_float : {true, false}) {
torch::Scalar b = is_float ? torch::Scalar(3.0) : torch::Scalar(3);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor c = a.div_(b);
torch::Tensor lazy_c = lazy_a.div_(b);
AllClose(c, lazy_c);
});
}
}
}
TEST_F(LazyOpsTest, TestDivOut) {
for (torch::ScalarType scalar_type : {torch::kFloat, torch::kDouble}) {
torch::Tensor a = torch::rand(
{3, 4}, torch::TensorOptions(scalar_type).device(DefaultDevice()));
torch::Tensor b = torch::rand(
{3, 4}, torch::TensorOptions(scalar_type).device(DefaultDevice()));
torch::Tensor c = torch::empty(
{3, 4}, torch::TensorOptions(scalar_type).device(DefaultDevice()));
torch::div_out(c, a, b);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = CopyToDevice(b, device);
torch::Tensor lazy_c = torch::empty({3, 4}, lazy_b.options());
torch::div_out(lazy_c, lazy_a, lazy_b);
AllClose(c, lazy_c);
});
}
}
TEST_F(LazyOpsTest, TestRsubScalar) {
torch::Tensor input = torch::rand(
{2, 2}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Scalar other(1.5);
torch::Scalar alpha(2.5);
torch::Tensor result = torch::rsub(input, other, alpha);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor lazy_result = torch::rsub(lazy_input, other, alpha);
AllClose(result, lazy_result);
});
}
TEST_F(LazyOpsTest, TestNe) {
torch::Tensor a = torch::rand(
{2, 3}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor b = torch::rand(
{2, 3}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor c = torch::ne(a, b);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = CopyToDevice(b, device);
torch::Tensor lazy_c = torch::ne(lazy_a, lazy_b);
AllEqual(c, lazy_c);
});
}
TEST_F(LazyOpsTest, TestNeInplace) {
torch::Tensor a = torch::rand(
{2, 3}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor a_copy = a.clone();
torch::Tensor b = a.clone();
b[0] += 1;
a.ne_(b);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a_copy, device);
torch::Tensor lazy_b = CopyToDevice(b, device);
lazy_a.ne_(lazy_b);
AllClose(a, lazy_a);
});
}
TEST_F(LazyOpsTest, TestEq) {
torch::Tensor a = torch::rand(
{2, 3}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor b = a.clone();
torch::Tensor c = torch::eq(a, b);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = CopyToDevice(b, device);
torch::Tensor lazy_c = torch::eq(lazy_a, lazy_b);
AllEqual(c, lazy_c);
});
}
TEST_F(LazyOpsTest, TestEqInplace) {
torch::Tensor a = torch::rand(
{2, 3}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor b = a.clone();
b[0] += 1;
torch::Tensor a_copy = a.clone();
a.eq_(b);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a_copy, device);
torch::Tensor lazy_b = CopyToDevice(b, device);
lazy_a.eq_(lazy_b);
AllClose(lazy_a, a);
});
}
TEST_F(LazyOpsTest, TestGe) {
torch::Tensor a = torch::rand(
{2, 3}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor b = a.clone();
torch::Tensor c = torch::ge(a, b);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = CopyToDevice(b, device);
torch::Tensor lazy_c = torch::ge(lazy_a, lazy_b);
AllEqual(c, lazy_c);
});
}
TEST_F(LazyOpsTest, TestGeInplace) {
torch::Tensor a = torch::rand(
{2, 3}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor b = a.clone();
b[0] += 1;
b[1] -= 1;
torch::Tensor a_copy = a.clone();
a.ge_(b);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a_copy, device);
torch::Tensor lazy_b = CopyToDevice(b, device);
lazy_a.ge_(lazy_b);
AllClose(lazy_a, a);
});
}
TEST_F(LazyOpsTest, TestLe) {
torch::Tensor a = torch::rand(
{2, 3}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor b = a.clone();
torch::Tensor c = torch::le(a, b);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = CopyToDevice(b, device);
torch::Tensor lazy_c = torch::le(lazy_a, lazy_b);
AllEqual(c, lazy_c);
});
}
TEST_F(LazyOpsTest, TestLeInplace) {
torch::Tensor a = torch::rand(
{2, 3}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor b = a.clone();
b[0] += 1;
b[1] -= 1;
torch::Tensor a_copy = a.clone();
a.le_(b);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a_copy, device);
torch::Tensor lazy_b = CopyToDevice(b, device);
lazy_a.le_(lazy_b);
AllClose(lazy_a, a);
});
}
TEST_F(LazyOpsTest, TestGt) {
torch::Tensor a = torch::rand(
{2, 3}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor b = torch::add(a.clone(), torch::ones_like(a));
torch::Tensor c = torch::gt(b, a);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = CopyToDevice(b, device);
torch::Tensor lazy_c = torch::gt(lazy_b, lazy_a);
AllEqual(c, lazy_c);
});
}
TEST_F(LazyOpsTest, TestGtInplace) {
torch::Tensor a = torch::rand(
{2, 3}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor b = a.clone();
b[0] += 1;
b[1] -= 1;
torch::Tensor a_copy = a.clone();
a.gt_(b);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a_copy, device);
torch::Tensor lazy_b = CopyToDevice(b, device);
lazy_a.gt_(lazy_b);
AllClose(lazy_a, a);
});
}
TEST_F(LazyOpsTest, TestLt) {
torch::Tensor a = torch::rand(
{2, 3}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor b = torch::add(a.clone(), torch::ones_like(a));
torch::Tensor c = torch::lt(a, b);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = CopyToDevice(b, device);
torch::Tensor lazy_c = torch::lt(lazy_a, lazy_b);
AllEqual(c, lazy_c);
});
}
TEST_F(LazyOpsTest, TestLtInplace) {
torch::Tensor a = torch::rand(
{2, 3}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor b = a.clone();
b[0] += 1;
b[1] -= 1;
torch::Tensor a_copy = a.clone();
a.lt_(b);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a_copy, device);
torch::Tensor lazy_b = CopyToDevice(b, device);
lazy_a.lt_(lazy_b);
AllClose(lazy_a, a);
});
}
TEST_F(LazyOpsTest, TestNeScalar) {
torch::Tensor input = torch::ones({2, 3});
torch::Scalar other(float(0));
torch::Tensor result = torch::ne(input, other);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor lazy_result = torch::ne(lazy_input, other);
AllEqual(result, lazy_result);
});
}
TEST_F(LazyOpsTest, TestEqScalar) {
torch::Tensor input = torch::ones({2, 3});
torch::Scalar other(float(1));
torch::Tensor result = torch::eq(input, other);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor lazy_result = torch::eq(lazy_input, other);
AllEqual(result, lazy_result);
});
}
TEST_F(LazyOpsTest, TestGeScalar) {
torch::Tensor input = torch::ones({2, 3});
torch::Scalar other(float(1));
torch::Tensor result = torch::ge(input, other);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor lazy_result = torch::ge(lazy_input, other);
AllEqual(result, lazy_result);
});
}
TEST_F(LazyOpsTest, TestGeScalarInplace) {
torch::Tensor input = torch::arange(
-1.,
1.5,
0.5,
torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Scalar other(float(0));
torch::Tensor input_copy = input.clone();
input.ge_(other);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input_copy, device);
lazy_input.ge_(other);
AllClose(lazy_input, input);
});
}
TEST_F(LazyOpsTest, TestLeScalar) {
torch::Tensor input = torch::ones({2, 3});
torch::Scalar other(float(1));
torch::Tensor result = torch::le(input, other);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor lazy_result = torch::le(lazy_input, other);
AllEqual(result, lazy_result);
});
}
TEST_F(LazyOpsTest, TestLeScalarInplace) {
torch::Tensor input = torch::arange(
-1.,
1.5,
0.5,
torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Scalar other(float(0));
torch::Tensor input_copy = input.clone();
input.le_(other);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input_copy, device);
lazy_input.le_(other);
AllClose(lazy_input, input);
});
}
TEST_F(LazyOpsTest, TestGtScalar) {
torch::Tensor input = torch::ones({2, 3});
torch::Scalar other(float(0.5));
torch::Tensor result = torch::gt(input, other);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor lazy_result = torch::gt(lazy_input, other);
AllEqual(result, lazy_result);
});
}
TEST_F(LazyOpsTest, TestGtScalarInplace) {
torch::Tensor input = torch::arange(
-1.,
1.5,
0.5,
torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Scalar other(float(0));
torch::Tensor input_copy = input.clone();
input.gt_(other);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input_copy, device);
lazy_input.gt_(other);
AllClose(lazy_input, input);
});
}
TEST_F(LazyOpsTest, TestLtScalar) {
torch::Tensor input = torch::ones({2, 3});
torch::Scalar other(float(1.5));
torch::Tensor result = torch::lt(input, other);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor lazy_result = torch::lt(lazy_input, other);
AllEqual(result, lazy_result);
});
}
TEST_F(LazyOpsTest, TestLtScalarInplace) {
torch::Tensor input = torch::arange(
-1.,
1.5,
0.5,
torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Scalar other(float(0));
torch::Tensor input_copy = input.clone();
input.lt_(other);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input_copy, device);
lazy_input.lt_(other);
AllClose(lazy_input, input);
});
}
TEST_F(LazyOpsTest, TestIntegerAdd) {
std::vector<torch::ScalarType> types(
{torch::kByte, torch::kChar, torch::kShort, torch::kInt, torch::kLong});
ForEachDevice([&](const torch::Device& device) {
for (auto type : types) {
torch::Tensor a =
torch::randint(0, 63, {2, 2}, torch::TensorOptions(type));
torch::Tensor b =
torch::randint(0, 63, {2, 2}, torch::TensorOptions(type));
torch::Scalar one =
isIntegralType(type, false) ? torch::Scalar(1) : torch::Scalar(1.0);
torch::Tensor c = torch::add(b, one);
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = CopyToDevice(b, device);
torch::Tensor lazy_c = torch::add(lazy_b, one);
AllEqual(c, lazy_c);
}
});
}
TEST_F(LazyOpsTest, TestSVD) {
static const int dims[] = {4, 7};
for (auto m : dims) {
for (auto n : dims) {
torch::Tensor a = torch::rand(
{m, n}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
auto b = torch::svd(a, /*some=*/true, /*compute_uv=*/true);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
auto lazy_b = torch::svd(lazy_a, /*some=*/true, /*compute_uv=*/true);
// The U and V matrices might have different sign for column vectors, so
// cannot be compared if not by absolute value.
AllClose(
std::get<0>(b).abs(),
std::get<0>(lazy_b).abs(),
/*rtol=*/1e-3,
/*atol=*/1e-4);
torch::Tensor diag = std::get<1>(b);
torch::Tensor lazy_diag = std::get<1>(lazy_b);
ASSERT_EQ(diag.sizes(), lazy_diag.sizes());
AllClose(
diag,
lazy_diag,
/*rtol=*/1e-3,
/*atol=*/1e-4);
AllClose(
std::get<2>(b).abs(),
std::get<2>(lazy_b).abs(),
/*rtol=*/1e-3,
/*atol=*/1e-4);
});
}
}
}
TEST_F(LazyOpsTest, TestQR) {
static const int dims[] = {4, 7};
for (auto m : dims) {
for (auto n : dims) {
torch::Tensor a = torch::rand(
{m, n}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
auto b = torch::qr(a);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
auto lazy_b = torch::qr(lazy_a);
AllClose(
std::get<0>(b).abs(),
std::get<0>(lazy_b).abs(),
/*rtol=*/1e-3,
/*atol=*/1e-4);
AllClose(
std::get<1>(b).abs(),
std::get<1>(lazy_b).abs(),
/*rtol=*/1e-3,
/*atol=*/1e-4);
});
}
}
}
TEST_F(LazyOpsTest, TestCholesky) {
static const int dims[] = {4, 7};
for (auto m : dims) {
for (bool upper : {true, false}) {
torch::Tensor a = torch::rand(
{3, m, m},
torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor pd_a =
torch::matmul(a, torch::transpose(a, 1, 2)) +
torch::eye(
m, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
auto b = torch::cholesky(pd_a, upper);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(pd_a, device);
auto lazy_b = torch::cholesky(lazy_a, upper);
AllClose(b, lazy_b, /*rtol=*/1e-3, /*atol=*/1e-4);
});
}
}
}
TEST_F(LazyOpsTest, TestLogDet) {
static const int dims[] = {4, 7};
for (auto m : dims) {
torch::Tensor a = torch::rand(
{3, m, m}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor pd_a = torch::matmul(a, torch::transpose(a, 1, 2)) +
torch::eye(m,
torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor b = torch::logdet(pd_a);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(pd_a, device);
torch::Tensor lazy_b = torch::logdet(lazy_a);
AllClose(b, lazy_b, /*rtol=*/1e-3, /*atol=*/1e-4);
});
}
}
TEST_F(LazyOpsTest, TestTriangularSolve) {
static const int dims[] = {4, 7};
for (bool batched_a : {true, false}) {
for (bool batched_b : {true, false}) {
for (auto m : dims) {
for (auto n : dims) {
for (bool upper : {true, false}) {
for (bool transpose : {true, false}) {
for (bool unitriangular : {true, false}) {
torch::Tensor a = torch::randn(
{m, m},
torch::TensorOptions(torch::kFloat)
.device(DefaultDevice()));
torch::Tensor b = torch::randn(
{m, n},
torch::TensorOptions(torch::kFloat)
.device(DefaultDevice()));
a = batched_a ? a.expand({3, m, m}).clone() : a;
b = batched_b ? b.expand({3, m, n}).clone() : b;
auto result = torch::triangular_solve(
b,
a,
/*upper=*/upper,
/*transpose=*/transpose,
/*unitriangular=*/unitriangular);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = CopyToDevice(b, device);
auto lazy_result = torch::triangular_solve(
lazy_b,
lazy_a,
/*upper=*/upper,
/*transpose=*/transpose,
/*unitriangular=*/unitriangular);
AllClose(
std::get<0>(result),
std::get<0>(lazy_result),
/*rtol=*/1e-3,
/*atol=*/1e-4);
AllClose(
std::get<1>(result),
std::get<1>(lazy_result),
/*rtol=*/1e-3,
/*atol=*/1e-4);
});
}
}
}
}
}
}
}
}
TEST_F(LazyOpsTest, TestKthValue) {
torch::Tensor a = torch::rand(
{4, 5, 3}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
for (int k = 1; k <= 3; ++k) {
int rank = a.dim();
for (int dim = -rank; dim < rank; ++dim) {
for (bool keepdim : {false, true}) {
auto b = torch::kthvalue(a, k, dim, keepdim);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
auto lazy_b = torch::kthvalue(lazy_a, k, dim, keepdim);
AllClose(std::get<0>(b), std::get<0>(lazy_b));
AllEqual(std::get<1>(b), std::get<1>(lazy_b));
});
}
}
}
}
TEST_F(LazyOpsTest, TestTopK) {
torch::Tensor a = torch::rand(
{4, 5, 3}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
for (int k = 1; k <= 3; ++k) {
int rank = a.dim();
for (int dim = -rank; dim < rank; ++dim) {
for (bool largest : {false, true}) {
auto b = torch::topk(a, k, dim, largest, /*sorted=*/true);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
auto lazy_b = torch::topk(lazy_a, k, dim, largest, /*sorted=*/true);
AllClose(std::get<0>(b), std::get<0>(lazy_b));
AllEqual(std::get<1>(b), std::get<1>(lazy_b));
});
}
}
}
}
TEST_F(LazyOpsTest, TestSort) {
torch::Tensor a = torch::rand(
{4, 5, 3}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
for (int k = 1; k <= 3; ++k) {
for (int dim = 0; dim < 3; ++dim) {
for (bool descending : {false, true}) {
auto b = torch::sort(a, dim, descending);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
auto lazy_b = torch::sort(lazy_a, dim, descending);
AllClose(std::get<0>(b), std::get<0>(lazy_b));
AllEqual(std::get<1>(b), std::get<1>(lazy_b));
});
}
}
}
}
TEST_F(LazyOpsTest, TestSortDescWithMinValue) {
std::vector<int8_t> values{-128, 100};
torch::Tensor input =
torch::tensor(values, torch::TensorOptions(torch::kChar));
auto output = torch::sort(input, /*dim=*/0, /*descending=*/true);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
auto lazy_output = torch::sort(lazy_input, /*dim=*/0, /*descending=*/true);
AllEqual(std::get<0>(output), std::get<0>(lazy_output));
AllEqual(std::get<1>(output), std::get<1>(lazy_output));
});
}
TEST_F(LazyOpsTest, TestArgSort) {
torch::Tensor a = torch::rand(
{4, 5, 3}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
for (int k = 1; k <= 3; ++k) {
for (int dim = 0; dim < 3; ++dim) {
for (bool descending : {false, true}) {
torch::Tensor b = torch::argsort(a, dim, descending);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = torch::argsort(lazy_a, dim, descending);
AllEqual(b, lazy_b);
});
}
}
}
}
TEST_F(LazyOpsTest, TestMin) {
torch::Tensor a = torch::rand(
{2, 2}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor b = torch::rand(
{2, 2}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor c = torch::min(a, b);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = CopyToDevice(b, device);
torch::Tensor lazy_c = torch::min(lazy_a, lazy_b);
AllClose(c, lazy_c);
});
}
TEST_F(LazyOpsTest, TestMax) {
torch::Tensor a = torch::rand(
{2, 2}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor b = torch::rand(
{2, 2}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor c = torch::max(a, b);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = CopyToDevice(b, device);
torch::Tensor lazy_c = torch::max(lazy_a, lazy_b);
AllClose(c, lazy_c);
});
}
TEST_F(LazyOpsTest, TestUnaryMin) {
torch::Tensor input = torch::rand(
{2, 2}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor output = torch::min(input);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor lazy_output = torch::min(lazy_input);
AllClose(output, lazy_output);
});
}
TEST_F(LazyOpsTest, TestUnaryMax) {
torch::Tensor input = torch::rand(
{2, 2}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor output = torch::max(input);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor lazy_output = torch::max(lazy_input);
AllClose(output, lazy_output);
});
}
TEST_F(LazyOpsTest, TestAll) {
for (torch::ScalarType scalar_type :
{torch::kFloat,
torch::kByte,
torch::kChar,
torch::kShort,
torch::kInt,
torch::kLong}) {
torch::Tensor a = isFloatingType(scalar_type)
? torch::rand(
{3, 4}, torch::TensorOptions(scalar_type).device(DefaultDevice()))
: torch::randint(
100,
{3, 4},
torch::TensorOptions(scalar_type).device(DefaultDevice()));
torch::Tensor b = torch::all(a);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = torch::all(lazy_a);
EqualValues(b, lazy_b);
});
}
}
TEST_F(LazyOpsTest, TestAllDim) {
torch::Tensor a = torch::randint(
0,
5,
{2, 3, 4},
torch::TensorOptions(torch::kByte).device(DefaultDevice()));
int rank = a.dim();
for (int dim = -rank; dim < rank; ++dim) {
torch::Tensor b = torch::all(a, dim, /*keepdim=*/false);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = torch::all(lazy_a, dim, /*keepdim=*/false);
EqualValues(b, lazy_b);
});
}
}
TEST_F(LazyOpsTest, TestAllDimKeep) {
torch::Tensor a = torch::randint(
0,
5,
{2, 3, 4},
torch::TensorOptions(torch::kByte).device(DefaultDevice()));
int rank = a.dim();
for (int dim = -rank; dim < rank; ++dim) {
torch::Tensor b = torch::all(a, dim, /*keepdim=*/true);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = torch::all(lazy_a, dim, /*keepdim=*/true);
EqualValues(b, lazy_b);
});
}
}
TEST_F(LazyOpsTest, TestAmax) {
torch::Tensor input = torch::rand(
{4, 3, 4}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
int rank = input.dim();
for (bool keepdim : {false, true}) {
for (int dim = -rank; dim < rank; ++dim) {
torch::Tensor values = torch::amax(input, {dim}, /*keepdim=*/keepdim);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor lazy_values =
torch::amax(lazy_input, {dim}, /*keepdim=*/keepdim);
AllClose(values, lazy_values);
});
}
for (int dim1 = -rank; dim1 < rank; ++dim1) {
for (int dim2 = -rank; dim2 < rank; ++dim2) {
if ((dim1 == dim2) || (dim1 == rank + dim2) || (dim2 == rank + dim1))
continue;
torch::Tensor values =
torch::amax(input, {dim1, dim2}, /*keepdim=*/keepdim);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor lazy_values =
torch::amax(lazy_input, {dim1, dim2}, /*keepdim=*/keepdim);
AllClose(values, lazy_values);
});
}
}
}
ExpectCounterNotChanged("aten::.*", GetIgnoredCounters());
ExpectCounterChanged("xla::amax", GetIgnoredCounters());
}
TEST_F(LazyOpsTest, TestAmin) {
torch::Tensor input = torch::rand(
{4, 3, 4}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
int rank = input.dim();
for (bool keepdim : {false, true}) {
for (int dim = -rank; dim < rank; ++dim) {
torch::Tensor values = torch::amin(input, {dim}, /*keepdim=*/keepdim);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor lazy_values =
torch::amin(lazy_input, {dim}, /*keepdim=*/keepdim);
AllClose(values, lazy_values);
});
}
for (int dim1 = -rank; dim1 < rank; ++dim1) {
for (int dim2 = -rank; dim2 < rank; ++dim2) {
if ((dim1 == dim2) || (dim1 == rank + dim2) || (dim2 == rank + dim1))
continue;
torch::Tensor values =
torch::amin(input, {dim1, dim2}, /*keepdim=*/keepdim);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor lazy_values =
torch::amin(lazy_input, {dim1, dim2}, /*keepdim=*/keepdim);
AllClose(values, lazy_values);
});
}
}
}
ExpectCounterNotChanged("aten::.*", GetIgnoredCounters());
ExpectCounterChanged("xla::amin", GetIgnoredCounters());
}
TEST_F(LazyOpsTest, TestAny) {
for (torch::ScalarType scalar_type :
{torch::kFloat,
torch::kByte,
torch::kChar,
torch::kShort,
torch::kInt,
torch::kLong}) {
torch::Tensor a = isFloatingType(scalar_type)
? torch::rand(
{3, 4}, torch::TensorOptions(scalar_type).device(DefaultDevice()))
: torch::randint(
100,
{3, 4},
torch::TensorOptions(scalar_type).device(DefaultDevice()));
torch::Tensor b = torch::any(a);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = torch::any(lazy_a);
EqualValues(b, lazy_b);
});
}
}
TEST_F(LazyOpsTest, TestAnyDim) {
torch::Tensor a = torch::randint(
0,
5,
{2, 3, 4},
torch::TensorOptions(torch::kByte).device(DefaultDevice()));
int rank = a.dim();
for (int dim = -rank; dim < rank; ++dim) {
torch::Tensor b = torch::any(a, dim, /*keepdim=*/false);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = torch::any(lazy_a, dim, /*keepdim=*/false);
EqualValues(b, lazy_b);
});
}
}
TEST_F(LazyOpsTest, TestAnyDimKeep) {
torch::Tensor a = torch::randint(
0,
5,
{2, 3, 4},
torch::TensorOptions(torch::kByte).device(DefaultDevice()));
int rank = a.dim();
for (int dim = -rank; dim < rank; ++dim) {
torch::Tensor b = torch::any(a, dim, /*keepdim=*/true);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = torch::any(lazy_a, dim, /*keepdim=*/true);
EqualValues(b, lazy_b);
});
}
}
TEST_F(LazyOpsTest, TestMean) {
torch::Tensor a = torch::rand(
{4, 3, 4}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor b = torch::mean(a);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = torch::mean(lazy_a);
ASSERT_EQ(b.sizes(), lazy_b.sizes());
AllClose(b, lazy_b);
});
}
TEST_F(LazyOpsTest, TestMeanCast) {
torch::Tensor a = torch::rand(
{4, 3, 4}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor b = torch::mean(a, torch::kDouble);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = torch::mean(lazy_a, torch::kDouble);
AllClose(b, lazy_b);
});
}
TEST_F(LazyOpsTest, TestMeanInDim) {
torch::Tensor a = torch::rand(
{4, 3, 4}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
int rank = a.dim();
for (int dim = -rank; dim < rank; ++dim) {
torch::Tensor b = torch::mean(a, {dim});
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = torch::mean(lazy_a, {dim});
AllClose(b, lazy_b);
});
}
}
TEST_F(LazyOpsTest, TestMeanInDims) {
torch::Tensor a = torch::rand(
{4, 3, 4}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
for (auto dims : std::vector<std::vector<int64_t>>{{0, 1}, {-3, -2}}) {
torch::Tensor b = torch::mean(a, dims);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = torch::mean(lazy_a, dims);
AllClose(b, lazy_b);
});
}
}
TEST_F(LazyOpsTest, TestMeanInDimsKeepCast) {
torch::Tensor a = torch::rand(
{4, 3, 4}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
for (auto dims : std::vector<std::vector<int64_t>>{{0, 1}, {-3, -2}}) {
torch::Tensor b = torch::mean(a, dims, true, torch::kDouble);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = torch::mean(lazy_a, dims, true, torch::kDouble);
AllClose(b, lazy_b);
});
}
}
TEST_F(LazyOpsTest, TestMeanInDimOut) {
torch::Tensor a = torch::rand(
{4, 4, 4}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
int rank = a.dim();
for (int dim = -rank; dim < rank; ++dim) {
torch::Tensor b = torch::empty(
{4, 4}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::mean_out(b, a, {dim});
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = torch::empty({4, 4}, lazy_a.options());
torch::mean_out(lazy_b, lazy_a, {dim});
AllClose(b, lazy_b);
});
}
}
TEST_F(LazyOpsTest, TestStd) {
torch::Tensor a = torch::rand(
{4, 3, 4}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
for (auto unbiased : {true, false}) {
torch::Tensor b = torch::std(a, unbiased);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = torch::std(lazy_a, unbiased);
AllClose(b, lazy_b);
});
}
}
TEST_F(LazyOpsTest, TestStdInDim) {
torch::Tensor a = torch::rand(
{4, 3, 4}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
int rank = a.dim();
for (auto unbiased : {true, false}) {
for (auto keepdim : {true, false}) {
for (int dim = -rank; dim < rank; ++dim) {
torch::Tensor b = torch::std(a, {dim}, unbiased, keepdim);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = torch::std(lazy_a, {dim}, unbiased, keepdim);
AllClose(b, lazy_b);
});
}
}
}
}
TEST_F(LazyOpsTest, TestStdWithCorrection) {
torch::Tensor a = torch::rand(
{4, 3, 4}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
// int rank = a.dim();
c10::optional<c10::Scalar> corrections[] = {1, 2, c10::nullopt};
for (const auto& correction : corrections) {
for (auto keepdim : {true, false}) {
for (const auto& dim :
std::vector<std::vector<int64_t>>{{0, 1}, {-3, -2}}) {
torch::Tensor b = torch::std(a, dim, correction, keepdim);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = torch::std(lazy_a, dim, correction, keepdim);
AllClose(b, lazy_b);
});
}
}
}
}
TEST_F(LazyOpsTest, TestStdMeanWithCorrection) {
torch::Tensor a = torch::rand(
{4, 3, 4}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
// int rank = a.dim();
c10::optional<c10::Scalar> corrections[] = {1, 2, c10::nullopt};
for (const auto& correction : corrections) {
for (auto keepdim : {true, false}) {
for (const auto& dim :
std::vector<std::vector<int64_t>>{{0, 1}, {-3, -2}}) {
auto b = torch::std_mean(a, dim, correction, keepdim);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
auto lazy_b = torch::std_mean(lazy_a, dim, correction, keepdim);
AllClose(std::get<0>(b), std::get<0>(lazy_b));
AllClose(std::get<1>(b), std::get<1>(lazy_b));
});
}
}
}
}
TEST_F(LazyOpsTest, TestSum) {
torch::Tensor a = torch::rand(
{4, 3, 4}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor b = torch::sum(a);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = torch::sum(lazy_a);
AllClose(b, lazy_b);
});
}
TEST_F(LazyOpsTest, TestSumCast) {
torch::Tensor a = torch::rand(
{4, 3, 4}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor b = torch::sum(a, torch::kDouble);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = torch::sum(lazy_a, torch::kDouble);
AllClose(b, lazy_b);
});
}
TEST_F(LazyOpsTest, TestSumU8) {
torch::Tensor a = torch::ones(
{256}, torch::TensorOptions(torch::kByte).device(DefaultDevice()));
torch::Tensor b = torch::sum(a);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = torch::sum(lazy_a);
AllEqual(b, lazy_b);
});
}
TEST_F(LazyOpsTest, TestSumInDim) {
torch::Tensor a = torch::rand(
{4, 3, 4}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
int rank = a.dim();
for (int dim = -rank; dim < rank; ++dim) {
torch::Tensor b = torch::sum(a, {dim});
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = torch::sum(lazy_a, {dim});
AllClose(b, lazy_b);
});
}
}
TEST_F(LazyOpsTest, TestSumInDims) {
torch::Tensor a = torch::rand(
{4, 3, 4}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
for (auto dims : std::vector<std::vector<int64_t>>{{0, 1}, {-3, -2}}) {
torch::Tensor b = torch::sum(a, dims);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = torch::sum(lazy_a, dims);
AllClose(b, lazy_b);
});
}
}
TEST_F(LazyOpsTest, TestSumInDimsKeep) {
torch::Tensor a = torch::rand(
{4, 3, 4}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
for (auto dims : std::vector<std::vector<int64_t>>{{0, 1}, {-3, -2}}) {
torch::Tensor b = torch::sum(a, dims, /*keepdim=*/true);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = torch::sum(lazy_a, dims, /*keepdim=*/true);
AllClose(b, lazy_b);
});
}
}
TEST_F(LazyOpsTest, TestSumInDimsKeepCast) {
torch::Tensor a = torch::rand(
{4, 3, 4}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
for (auto dims : std::vector<std::vector<int64_t>>{{0, 1}, {-3, -2}}) {
torch::Tensor b = torch::sum(a, dims, /*keepdim=*/true, torch::kDouble);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b =
torch::sum(lazy_a, dims, /*keepdim=*/true, torch::kDouble);
AllClose(b, lazy_b);
});
}
}
TEST_F(LazyOpsTest, TestVar) {
torch::Tensor a = torch::rand(
{4, 3, 4}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
for (bool unbiased : {true, false}) {
torch::Tensor b = torch::var(a, unbiased);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = torch::var(lazy_a, unbiased);
AllClose(b, lazy_b);
});
}
}
TEST_F(LazyOpsTest, TestVarWithDim) {
torch::Tensor a = torch::rand(
{4, 3, 4}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
for (auto dims : std::vector<std::vector<int64_t>>{{0, 1}, {-3, -2}}) {
for (bool keepDim : {true, false}) {
for (bool unbiased : {true, false}) {
torch::Tensor b = torch::var(a, dims, unbiased, keepDim);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = torch::var(lazy_a, dims, unbiased, keepDim);
AllClose(b, lazy_b);
});
}
}
}
}
TEST_F(LazyOpsTest, TestVarWithCorrection) {
torch::Tensor a = torch::rand(
{4, 3, 4}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
c10::optional<c10::Scalar> corrections[] = {1, 2, c10::nullopt};
for (const auto& dim : std::vector<std::vector<int64_t>>{{0, 1}, {-3, -2}}) {
for (bool keepDim : {true, false}) {
for (const auto& correction : corrections) {
torch::Tensor b = torch::var(a, dim, correction, keepDim);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = torch::var(lazy_a, dim, correction, keepDim);
AllClose(b, lazy_b);
});
}
}
}
ExpectCounterNotChanged("aten::.*", GetIgnoredCounters());
ExpectCounterChanged("lazy::var", GetIgnoredCounters());
}
TEST_F(LazyOpsTest, TestVarMeanWithCorrection) {
torch::Tensor a = torch::rand(
{4, 3, 4}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
c10::optional<c10::Scalar> corrections[] = {1, 2, c10::nullopt};
for (const auto& dim : std::vector<std::vector<int64_t>>{{0, 1}, {-3, -2}}) {
for (const auto& correction : corrections) {
for (auto keepdim : {true, false}) {
auto b = torch::var_mean(a, dim, correction, keepdim);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
auto lazy_b = torch::var_mean(lazy_a, dim, correction, keepdim);
AllClose(std::get<0>(b), std::get<0>(lazy_b));
AllClose(std::get<1>(b), std::get<1>(lazy_b));
});
}
}
}
}
TEST_F(LazyOpsTest, TestMaxInDim) {
torch::Tensor input = torch::rand(
{4, 3, 4}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
int rank = input.dim();
for (int dim = -rank; dim < rank; ++dim) {
for (bool keepdim : {false, true}) {
auto values_indices = torch::max(input, dim, /*keepdim=*/keepdim);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
auto lazy_values_indices =
torch::max(lazy_input, dim, /*keepdim=*/keepdim);
AllClose(std::get<0>(values_indices), std::get<0>(lazy_values_indices));
AllEqual(std::get<1>(values_indices), std::get<1>(lazy_values_indices));
});
}
}
}
TEST_F(LazyOpsTest, TestMinInDim) {
torch::Tensor input = torch::rand(
{4, 3, 4}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
int rank = input.dim();
for (int dim = -rank; dim < rank; ++dim) {
for (bool keepdim : {false, true}) {
auto values_indices = torch::min(input, dim, /*keepdim=*/keepdim);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
auto lazy_values_indices =
torch::min(lazy_input, dim, /*keepdim=*/keepdim);
AllClose(std::get<0>(values_indices), std::get<0>(lazy_values_indices));
AllEqual(std::get<1>(values_indices), std::get<1>(lazy_values_indices));
});
}
}
}
TEST_F(LazyOpsTest, TestNorm) {
torch::Tensor a = torch::rand(
{4, 3, 4}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor b = torch::norm(a);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = torch::norm(lazy_a);
AllClose(b, lazy_b);
});
}
TEST_F(LazyOpsTest, TestNormInDim) {
torch::Tensor a = torch::rand(
{4, 3, 4}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
for (int dim : {1, -2}) {
torch::Tensor b = torch::norm(a, 2, {dim}, /*keepdim=*/false);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = torch::norm(lazy_a, 2, {dim}, /*keepdim=*/false);
AllClose(b, lazy_b);
});
}
}
TEST_F(LazyOpsTest, TestNormInDims) {
torch::Tensor a = torch::rand(
{4, 3, 4}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
for (auto dims : std::vector<std::vector<int64_t>>{{1, 2}, {-2, -1}}) {
torch::Tensor b = torch::norm(a, 2, dims, /*keepdim=*/false);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = torch::norm(lazy_a, 2, dims, /*keepdim=*/false);
AllClose(b, lazy_b);
});
}
}
TEST_F(LazyOpsTest, TestNormInDimsKeep) {
torch::Tensor a = torch::rand(
{4, 3, 4}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
for (auto dims : std::vector<std::vector<int64_t>>{{1, 2}, {-2, -1}}) {
torch::Tensor b = torch::norm(a, 2, dims, /*keepdim=*/true);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = torch::norm(lazy_a, 2, dims, /*keepdim=*/true);
AllClose(b, lazy_b);
});
}
}
TEST_F(LazyOpsTest, TestNormalTwoTensor) {
at::Tensor mean = at::zeros({10, 10, 10}, at::dtype(at::kFloat));
at::Tensor std = at::ones({10, 10, 10}, at::dtype(at::kFloat));
ForEachDevice([&](const torch::Device& device) {
at::Tensor lazy_mean = CopyToDevice(mean, device);
at::Tensor lazy_std = CopyToDevice(std, device);
at::Tensor lazy_normal = at::normal(lazy_mean, lazy_std);
double res_mean = lazy_normal.mean().item().toDouble();
double res_std = lazy_normal.std().item().toDouble();
EXPECT_GT(res_mean, -0.06);
EXPECT_LT(res_mean, 0.06);
EXPECT_GT(res_std, 0.94);
EXPECT_LT(res_std, 1.06);
});
}
TEST_F(LazyOpsTest, TestNormalDoubleMean) {
at::Tensor std = at::ones({10, 10, 10}, at::dtype(at::kFloat));
ForEachDevice([&](const torch::Device& device) {
at::Tensor lazy_std = CopyToDevice(std, device);
at::Tensor lazy_normal = at::normal(0, lazy_std);
double res_mean = lazy_normal.mean().item().toDouble();
double res_std = lazy_normal.std().item().toDouble();
EXPECT_GT(res_mean, -0.06);
EXPECT_LT(res_mean, 0.06);
EXPECT_GT(res_std, 0.94);
EXPECT_LT(res_std, 1.06);
});
}
TEST_F(LazyOpsTest, TestNormalDoubleStd) {
at::Tensor mean = at::zeros({10, 10, 10}, at::dtype(at::kFloat));
ForEachDevice([&](const torch::Device& device) {
at::Tensor lazy_mean = CopyToDevice(mean, device);
at::Tensor lazy_normal = at::normal(lazy_mean, 1);
double res_mean = lazy_normal.mean().item().toDouble();
double res_std = lazy_normal.std().item().toDouble();
EXPECT_GT(res_mean, -0.06);
EXPECT_LT(res_mean, 0.06);
EXPECT_GT(res_std, 0.94);
EXPECT_LT(res_std, 1.06);
});
}
TEST_F(LazyOpsTest, TestNormalInPlace) {
at::Tensor a = at::zeros({10, 10, 10}, at::dtype(at::kFloat));
ForEachDevice([&](const torch::Device& device) {
at::Tensor lazy_a = CopyToDevice(a, device);
lazy_a.normal_(/*mean=*/0, /*std=*/1);
double res_mean = lazy_a.mean().item().toDouble();
double res_std = lazy_a.std().item().toDouble();
EXPECT_GT(res_mean, -0.06);
EXPECT_LT(res_mean, 0.06);
EXPECT_GT(res_std, 0.94);
EXPECT_LT(res_std, 1.06);
});
}
TEST_F(LazyOpsTest, TestUniformInPlace) {
const double eps = 1e-3;
at::Tensor a = at::zeros({10, 10, 10}, at::dtype(at::kFloat));
ForEachDevice([&](const torch::Device& device) {
at::Tensor lazy_a = CopyToDevice(a, device);
lazy_a.uniform_(/*from=*/0, /*to=*/1);
at::Tensor cpu_a = ToCpuTensor(lazy_a);
double res_min = cpu_a.min().item().toDouble();
double res_max = cpu_a.max().item().toDouble();
EXPECT_GT(res_min, 0.0 - eps);
EXPECT_LT(res_max, 1.0 + eps);
});
}
TEST_F(LazyOpsTest, TestRandomInPlace) {
for (auto dtype :
{torch::kFloat,
torch::kDouble,
torch::kByte,
torch::kChar,
torch::kShort,
torch::kInt,
torch::kLong}) {
const double eps = 0.2;
torch::Tensor a = torch::zeros({10, 10, 10}, torch::TensorOptions(dtype));
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
lazy_a.random_(/*from=*/0, /*to=*/10);
double res_mean = lazy_a.sum().item().toDouble() / a.numel();
double res_min = lazy_a.min().item().toDouble();
double res_max = lazy_a.max().item().toDouble();
EXPECT_GT(res_mean, 4.5 - eps);
EXPECT_LT(res_mean, 4.5 + eps);
EXPECT_EQ(res_min, 0.0);
EXPECT_EQ(res_max, 9.0);
});
}
}
TEST_F(LazyOpsTest, TestRandomInPlaceDefaultFrom) {
for (auto dtype :
{torch::kFloat,
torch::kDouble,
torch::kByte,
torch::kChar,
torch::kShort,
torch::kInt,
torch::kLong}) {
const double eps = 0.2;
torch::Tensor a = torch::zeros({10, 10, 10}, torch::TensorOptions(dtype));
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
lazy_a.random_(/*to=*/10);
double res_mean = lazy_a.sum().item().toDouble() / a.numel();
double res_min = lazy_a.min().item().toDouble();
double res_max = lazy_a.max().item().toDouble();
EXPECT_GT(res_mean, 4.5 - eps);
EXPECT_LT(res_mean, 4.5 + eps);
EXPECT_EQ(res_min, 0.0);
EXPECT_EQ(res_max, 9.0);
});
}
}
TEST_F(LazyOpsTest, TestRandomInPlaceDefault) {
for (auto dtype :
{torch::kFloat,
torch::kDouble,
torch::kByte,
torch::kChar,
torch::kShort,
torch::kInt,
torch::kLong}) {
auto input = torch::zeros({10}, torch::TensorOptions(dtype));
ForEachDevice([&](const torch::Device& device) {
auto lazyInput = CopyToDevice(input, device);
lazyInput.random_();
auto output = ToCpuTensor(lazyInput);
EXPECT_TRUE(torch::all(output.ne(input)).item<bool>());
});
}
}
TEST_F(LazyOpsTest, TestNormGeneral) {
torch::Tensor a = torch::randn(
{4, 3, 4}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor b = torch::norm(a, 3.5);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = torch::norm(lazy_a, 3.5);
AllClose(b, lazy_b);
});
}
TEST_F(LazyOpsTest, TestNormNuclear) {
torch::Tensor a = torch::rand(
{4, 3, 4}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor b = torch::norm(a, 1);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = torch::norm(lazy_a, 1);
AllClose(b, lazy_b);
});
}
TEST_F(LazyOpsTest, TestFrobeniusNormInDim) {
torch::Tensor a = torch::rand(
{4, 3, 4}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
for (int dim : {1, -2}) {
torch::Tensor b = torch::frobenius_norm(a, {dim}, /*keepdim=*/false);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b =
torch::frobenius_norm(lazy_a, {dim}, /*keepdim=*/false);
AllClose(b, lazy_b);
});
}
}
TEST_F(LazyOpsTest, TestFrobeniusNormInDims) {
torch::Tensor a = torch::rand(
{4, 3, 4}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
for (auto dims : std::vector<std::vector<int64_t>>{{1, 2}, {-2, -1}}) {
torch::Tensor b = torch::frobenius_norm(a, dims, /*keepdim=*/false);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b =
torch::frobenius_norm(lazy_a, dims, /*keepdim=*/false);
AllClose(b, lazy_b);
});
}
}
TEST_F(LazyOpsTest, TestGroupNorm) {
int num_channels = 6;
torch::Tensor input = torch::rand(
{20, num_channels, 10, 10},
torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor weight = torch::rand(
{num_channels},
torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor bias = torch::rand(
{num_channels},
torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
double eps = 1e-05;
for (int num_groups : {3, 6, 1}) {
torch::Tensor output = torch::group_norm(
input,
num_groups,
weight,
bias,
eps,
/*cudnn_enabled=*/false);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor lazy_weight = CopyToDevice(weight, device);
torch::Tensor lazy_bias = CopyToDevice(bias, device);
torch::Tensor lazy_output = torch::group_norm(
lazy_input,
num_groups,
lazy_weight,
lazy_bias,
eps,
/*cudnn_enabled=*/false);
AllClose(output, lazy_output, /*rtol=*/1e-3, /*atol=*/1e-5);
});
}
}
TEST_F(LazyOpsTest, TestGroupNormBackward) {
int num_channels = 6;
torch::Tensor input = torch::rand(
{2, num_channels, 5, 5},
torch::TensorOptions(torch::kFloat)
.device(DefaultDevice())
.requires_grad(true));
torch::Tensor weight = torch::rand(
{num_channels},
torch::TensorOptions(torch::kFloat)
.device(DefaultDevice())
.requires_grad(true));
torch::Tensor bias = torch::rand(
{num_channels},
torch::TensorOptions(torch::kFloat)
.device(DefaultDevice())
.requires_grad(true));
double eps = 1e-05;
for (bool undef_weight : {true, false}) {
for (int num_groups : {3, 6, 1}) {
auto testfn =
[&](const std::vector<torch::Tensor>& inputs) -> torch::Tensor {
return torch::group_norm(
/*input=*/inputs[0],
num_groups,
inputs[1],
inputs[2],
/*eps=*/eps,
/*cudnn_enabled=*/false);
};
torch::Tensor undef;
ForEachDevice([&](const torch::Device& device) {
TestBackward(
{input, undef_weight ? undef : weight, undef_weight ? undef : bias},
device,
testfn,
/*rtol=*/1e-3,
/*atol=*/1e-3,
/*derivative_level=*/2);
});
}
}
}
TEST_F(LazyOpsTest, TestInstanceNorm) {
int batch = 5;
int num_channels = 20;
torch::Tensor input = torch::rand(
{batch, num_channels, 10, 10},
torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor weight = torch::rand(
{num_channels},
torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor bias = torch::rand(
{num_channels},
torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor running_mean = torch::zeros(
{num_channels},
torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor running_var = torch::ones(
{num_channels},
torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
double momentum = 0.1;
double eps = 1e-05;
torch::Tensor output = torch::instance_norm(
input,
weight,
bias,
running_mean,
running_var,
/*use_input_stats=*/true,
momentum,
eps,
/*cudnn_enabled=*/false);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor lazy_weight = CopyToDevice(weight, device);
torch::Tensor lazy_bias = CopyToDevice(bias, device);
torch::Tensor lazy_running_mean = CopyToDevice(running_mean, device);
torch::Tensor lazy_running_var = CopyToDevice(running_var, device);
torch::Tensor lazy_output = torch::instance_norm(
lazy_input,
lazy_weight,
lazy_bias,
lazy_running_mean,
lazy_running_var,
/*use_input_stats=*/true,
momentum,
eps,
/*cudnn_enabled=*/false);
AllClose(output, lazy_output, /*rtol=*/1e-3, /*atol=*/1e-5);
});
}
TEST_F(LazyOpsTest, TestLayerNorm) {
torch::Tensor input = torch::rand(
{20, 10, 10, 10},
torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
double eps = 1e-05;
torch::Tensor undef;
for (bool undef_weight : {true, false}) {
for (int64_t normalized_size : {2, 3}) {
std::vector<int64_t> normalized_shape(normalized_size, 10);
torch::Tensor weight = torch::rand(
normalized_shape,
torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor bias = torch::rand(
normalized_shape,
torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor output = torch::layer_norm(
input,
normalized_shape,
undef_weight ? undef : weight,
undef_weight ? undef : bias,
eps,
/*cudnn_enabled=*/false);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor lazy_weight =
undef_weight ? undef : CopyToDevice(weight, device);
torch::Tensor lazy_bias =
undef_weight ? undef : CopyToDevice(bias, device);
torch::Tensor lazy_output = torch::layer_norm(
lazy_input,
normalized_shape,
lazy_weight,
lazy_bias,
eps,
/*cudnn_enabled=*/false);
AllClose(output, lazy_output, /*rtol=*/1e-3, /*atol=*/1e-5);
});
}
}
}
TEST_F(LazyOpsTest, TestLayerNormBackward) {
torch::Tensor input = torch::rand(
{2, 3, 3, 3},
torch::TensorOptions(torch::kFloat)
.device(DefaultDevice())
.requires_grad(true));
double eps = 1e-05;
for (bool undef_weight : {true, false}) {
for (int64_t normalized_size : {2, 3}) {
std::vector<int64_t> normalized_shape(normalized_size, 3);
auto testfn =
[&](const std::vector<torch::Tensor>& inputs) -> torch::Tensor {
return torch::layer_norm(
/*input=*/inputs[0],
normalized_shape,
inputs[1],
inputs[2],
/*eps=*/eps,
/*cudnn_enabled=*/false);
};
torch::Tensor weight = torch::rand(
normalized_shape,
torch::TensorOptions(torch::kFloat)
.device(DefaultDevice())
.requires_grad(true));
torch::Tensor bias = torch::rand(
normalized_shape,
torch::TensorOptions(torch::kFloat)
.device(DefaultDevice())
.requires_grad(true));
torch::Tensor undef;
ForEachDevice([&](const torch::Device& device) {
TestBackward(
{input, undef_weight ? undef : weight, undef_weight ? undef : bias},
device,
testfn,
/*rtol=*/1e-3,
/*atol=*/1e-4,
/*derivative_level=*/2);
});
}
}
}
TEST_F(LazyOpsTest, TestNuclearNorm) {
torch::Tensor a = torch::rand(
{4, 3}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor b = torch::nuclear_norm(a);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = torch::nuclear_norm(lazy_a);
AllClose(b, lazy_b);
});
}
TEST_F(LazyOpsTest, TestPairwiseDistance) {
torch::Tensor x1 = torch::rand(
{4, 3}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor x2 = torch::rand(
{4, 3}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
double eps = 1e-6;
for (bool keepdim : {false, true}) {
for (double p : {1, 2, 3, 4}) {
ForEachDevice([&](const torch::Device& device) {
torch::Tensor output =
torch::pairwise_distance(x1, x2, p, eps, keepdim);
torch::Tensor lazy_x1 = CopyToDevice(x1, device);
torch::Tensor lazy_x2 = CopyToDevice(x2, device);
torch::Tensor lazy_output =
torch::pairwise_distance(lazy_x1, lazy_x2, p, eps, keepdim);
AllClose(output, lazy_output, /*rtol=*/1e-5, /*atol=*/1e-5);
});
}
}
}
TEST_F(LazyOpsTest, TestCosineSimilarity) {
torch::Tensor x1 = torch::rand(
{4, 3}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor x2 = torch::rand(
{4, 3}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
double eps = 1e-8;
int rank = x1.dim();
for (int dim = -rank; dim < rank; ++dim) {
ForEachDevice([&](const torch::Device& device) {
torch::Tensor output = torch::cosine_similarity(x1, x2, dim, eps);
torch::Tensor lazy_x1 = CopyToDevice(x1, device);
torch::Tensor lazy_x2 = CopyToDevice(x2, device);
torch::Tensor lazy_output =
torch::cosine_similarity(lazy_x1, lazy_x2, dim, eps);
AllClose(output, lazy_output);
});
}
}
TEST_F(LazyOpsTest, TestCosineEmbeddingLoss) {
torch::Tensor input1 = torch::rand(
{4, 3}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor input2 = torch::rand(
{4, 3}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor target = torch::rand(
{4}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
for (torch::Reduction::Reduction reduction :
{torch::Reduction::Mean, torch::Reduction::Sum}) {
for (double margin : {0., 0.2}) {
ForEachDevice([&](const torch::Device& device) {
torch::Tensor output = torch::cosine_embedding_loss(
input1, input2, target, margin, reduction);
torch::Tensor lazy_input1 = CopyToDevice(input1, device);
torch::Tensor lazy_input2 = CopyToDevice(input2, device);
torch::Tensor lazy_target = CopyToDevice(target, device);
torch::Tensor lazy_output = torch::cosine_embedding_loss(
lazy_input1, lazy_input2, lazy_target, margin, reduction);
AllClose(output, lazy_output);
});
}
}
}
TEST_F(LazyOpsTest, TestHingeEmbeddingLoss) {
torch::Tensor input = torch::rand(
{4, 3}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor target = torch::rand(
{4, 3}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
for (torch::Reduction::Reduction reduction :
{torch::Reduction::Mean, torch::Reduction::Sum}) {
for (double margin : {0., 0.2}) {
ForEachDevice([&](const torch::Device& device) {
torch::Tensor output =
torch::hinge_embedding_loss(input, target, margin, reduction);
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor lazy_target = CopyToDevice(target, device);
torch::Tensor lazy_output = torch::hinge_embedding_loss(
lazy_input, lazy_target, margin, reduction);
AllClose(output, lazy_output);
});
}
}
}
TEST_F(LazyOpsTest, TestTripletMarginLoss) {
torch::Tensor anchor = torch::rand(
{4, 3}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor positive = torch::abs(torch::rand(
{4, 3}, torch::TensorOptions(torch::kFloat).device(DefaultDevice())));
torch::Tensor negative = torch::neg(torch::abs(torch::rand(
{4, 3}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()))));
double eps = 1e-6;
for (double margin : {0., 0.2}) {
for (double p : {1, 2, 3, 4}) {
for (bool swap : {false, true}) {
for (torch::Reduction::Reduction reduction :
{torch::Reduction::Mean, torch::Reduction::Sum}) {
ForEachDevice([&](const torch::Device& device) {
torch::Tensor output = torch::triplet_margin_loss(
anchor, positive, negative, margin, p, eps, swap, reduction);
torch::Tensor lazy_anchor = CopyToDevice(anchor, device);
torch::Tensor lazy_positive = CopyToDevice(positive, device);
torch::Tensor lazy_negative = CopyToDevice(negative, device);
torch::Tensor lazy_output = torch::triplet_margin_loss(
lazy_anchor,
lazy_positive,
lazy_negative,
margin,
p,
eps,
swap,
reduction);
AllClose(output, lazy_output);
});
}
}
}
}
}
TEST_F(LazyOpsTest, TestBinaryCrossEntropy) {
int batch = 10;
int classes = 5;
torch::Tensor input = torch::rand(
{batch, classes},
torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor target = torch::rand(
{batch, classes},
torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor weight = torch::rand(
{batch, classes},
torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor undef;
for (torch::Reduction::Reduction reduction :
{torch::Reduction::Mean,
torch::Reduction::Sum,
torch::Reduction::None}) {
for (bool undef_weight : {false, true}) {
ForEachDevice([&](const torch::Device& device) {
torch::Tensor output = torch::binary_cross_entropy(
input, target, undef_weight ? undef : weight, reduction);
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor lazy_target = CopyToDevice(target, device);
torch::Tensor lazy_weight =
undef_weight ? undef : CopyToDevice(weight, device);
torch::Tensor lazy_output = torch::binary_cross_entropy(
lazy_input, lazy_target, lazy_weight, reduction);
AllClose(output, lazy_output, /*rtol=*/1e-4, /*atol=*/1e-5);
});
}
}
}
TEST_F(LazyOpsTest, TestMarginRankingLoss) {
torch::Tensor input1 = torch::rand(
{4, 3}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor input2 = torch::rand(
{4, 3}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor target = torch::rand(
{4, 3}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
for (torch::Reduction::Reduction reduction :
{torch::Reduction::Mean, torch::Reduction::Sum}) {
for (double margin : {0., 0.2}) {
ForEachDevice([&](const torch::Device& device) {
torch::Tensor output = torch::margin_ranking_loss(
input1, input2, target, margin, reduction);
torch::Tensor lazy_input1 = CopyToDevice(input1, device);
torch::Tensor lazy_input2 = CopyToDevice(input2, device);
torch::Tensor lazy_target = CopyToDevice(target, device);
torch::Tensor lazy_output = torch::margin_ranking_loss(
lazy_input1, lazy_input2, lazy_target, margin, reduction);
AllClose(output, lazy_output);
});
}
}
}
TEST_F(LazyOpsTest, TestBCEWithLogits) {
int batch = 10;
int classes = 5;
torch::Tensor input = torch::rand(
{batch, classes},
torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor target = torch::rand(
{batch, classes},
torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor weight = torch::rand(
{classes}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor pos_weight = torch::rand(
{classes}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor undef;
for (torch::Reduction::Reduction reduction :
{torch::Reduction::Mean, torch::Reduction::Sum}) {
for (bool undef_weight : {false, true}) {
for (bool undef_pos_weight : {false, true}) {
ForEachDevice([&](const torch::Device& device) {
torch::Tensor output = torch::binary_cross_entropy_with_logits(
input,
target,
undef_weight ? undef : weight,
undef_pos_weight ? undef : pos_weight,
reduction);
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor lazy_target = CopyToDevice(target, device);
torch::Tensor lazy_weight =
undef_weight ? undef : CopyToDevice(weight, device);
torch::Tensor lazy_pos_weight =
undef_pos_weight ? undef : CopyToDevice(pos_weight, device);
torch::Tensor lazy_output = torch::binary_cross_entropy_with_logits(
lazy_input, lazy_target, lazy_weight, lazy_pos_weight, reduction);
});
}
}
}
}
TEST_F(LazyOpsTest, TestKlDiv) {
torch::Tensor input = torch::rand(
{4, 3}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor target = torch::rand(
{4, 3}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
for (bool log_target : {true, false}) {
for (torch::Reduction::Reduction reduction :
{torch::Reduction::Mean, torch::Reduction::Sum}) {
ForEachDevice([&](const torch::Device& device) {
torch::Tensor output =
torch::kl_div(input, target, reduction, log_target);
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor lazy_target = CopyToDevice(target, device);
torch::Tensor lazy_output =
torch::kl_div(lazy_input, lazy_target, reduction, log_target);
AllClose(output, lazy_output);
});
}
}
}
TEST_F(LazyOpsTest, TestProd) {
torch::Tensor a = torch::rand(
{4, 3, 4}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor b = torch::prod(a);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = torch::prod(lazy_a);
AllClose(b, lazy_b);
});
}
TEST_F(LazyOpsTest, TestProdCast) {
torch::Tensor a = torch::rand(
{4, 3, 4}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor b = torch::prod(a, torch::kDouble);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = torch::prod(lazy_a, torch::kDouble);
AllClose(b, lazy_b);
});
}
TEST_F(LazyOpsTest, TestProdInDim) {
torch::Tensor a = torch::rand(
{4, 3, 4}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
int rank = a.dim();
for (int dim = -rank; dim < rank; ++dim) {
torch::Tensor b = torch::prod(a, dim);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = torch::prod(lazy_a, dim);
AllClose(b, lazy_b);
});
}
}
TEST_F(LazyOpsTest, TestProdInDimKeepCast) {
torch::Tensor a = torch::rand(
{4, 3, 4}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
int rank = a.dim();
for (int dim = -rank; dim < rank; ++dim) {
torch::Tensor b = torch::prod(a, dim, /*keepdim=*/true, torch::kDouble);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b =
torch::prod(lazy_a, dim, /*keepdim=*/true, torch::kDouble);
AllClose(b, lazy_b);
});
}
}
TEST_F(LazyOpsTest, TestProdInDimKeep) {
torch::Tensor a = torch::rand(
{4, 3, 4}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
int rank = a.dim();
for (int dim = -rank; dim < rank; ++dim) {
torch::Tensor b = torch::prod(a, dim, /*keepdim=*/true);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = torch::prod(lazy_a, dim, /*keepdim=*/true);
AllClose(b, lazy_b);
});
}
}
TEST_F(LazyOpsTest, TestCumSum) {
torch::Tensor input = torch::rand(
{4, 3, 4}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
int rank = input.dim();
for (int dim = -rank; dim < rank; ++dim) {
torch::Tensor result = torch::cumsum(input, dim);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor lazy_result = torch::cumsum(lazy_input, dim);
AllClose(result, lazy_result);
});
}
}
TEST_F(LazyOpsTest, TestCumSumCast) {
torch::Tensor input = torch::rand(
{4, 3, 4}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
int rank = input.dim();
for (int dim = -rank; dim < rank; ++dim) {
torch::Tensor result = torch::cumsum(input, dim, torch::kDouble);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor lazy_result =
torch::cumsum(lazy_input, dim, torch::kDouble);
AllClose(result, lazy_result);
});
}
}
TEST_F(LazyOpsTest, TestCumSumLong) {
torch::Tensor input = torch::randint(
1000,
{4, 3, 4},
torch::TensorOptions(torch::kLong).device(DefaultDevice()));
int rank = input.dim();
for (int dim = -rank; dim < rank; ++dim) {
torch::Tensor result = torch::cumsum(input, dim);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor lazy_result = torch::cumsum(lazy_input, dim);
AllEqual(result, lazy_result);
});
}
}
TEST_F(LazyOpsTest, TestCumSumCastLong) {
torch::Tensor input = torch::rand(
{4, 3, 4}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
int rank = input.dim();
for (int dim = -rank; dim < rank; ++dim) {
torch::Tensor result = torch::cumsum(input, dim, torch::kLong);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor lazy_result = torch::cumsum(lazy_input, dim, torch::kLong);
AllEqual(result, lazy_result);
});
}
}
TEST_F(LazyOpsTest, TestCumProd) {
torch::Tensor input = torch::rand(
{4, 3, 4}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
int rank = input.dim();
for (int dim = -rank; dim < rank; ++dim) {
torch::Tensor result = torch::cumprod(input, dim);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor lazy_result = torch::cumprod(lazy_input, dim);
AllClose(result, lazy_result);
});
}
}
TEST_F(LazyOpsTest, TestCumProdCast) {
torch::Tensor input = torch::mul(
torch::rand(
{4, 3, 4},
torch::TensorOptions(torch::kFloat).device(DefaultDevice())),
10);
int rank = input.dim();
for (int dim = -rank; dim < rank; ++dim) {
torch::Tensor result = torch::cumprod(input, dim, torch::kDouble);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor lazy_result =
torch::cumprod(lazy_input, dim, torch::kDouble);
AllClose(result, lazy_result);
});
}
}
TEST_F(LazyOpsTest, TestCumProdLong) {
torch::Tensor input = torch::randint(
7, {2, 3}, torch::TensorOptions(torch::kLong).device(DefaultDevice()));
int rank = input.dim();
for (int dim = -rank; dim < rank; ++dim) {
torch::Tensor result = torch::cumsum(input, dim);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor lazy_result = torch::cumsum(lazy_input, dim);
AllEqual(result, lazy_result);
});
}
}
TEST_F(LazyOpsTest, TestCumProdCastLong) {
torch::Tensor input =
torch::rand(
{2, 3}, torch::TensorOptions(torch::kFloat).device(DefaultDevice())) *
7;
int rank = input.dim();
for (int dim = -rank; dim < rank; ++dim) {
torch::Tensor result = torch::cumsum(input, dim, torch::kLong);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor lazy_result = torch::cumsum(lazy_input, dim, torch::kLong);
AllEqual(result, lazy_result);
});
}
}
TEST_F(LazyOpsTest, TestArgMin) {
torch::Tensor a = torch::rand(
{4, 4, 4}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor b = torch::argmin(a, c10::nullopt, /*keepdim=*/false);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b =
torch::argmin(lazy_a, c10::nullopt, /*keepdim=*/false);
AllEqual(b, lazy_b);
});
}
TEST_F(LazyOpsTest, TestArgMinDim) {
torch::Tensor a = torch::rand(
{4, 4, 4}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
for (int dim : {1, -2}) {
torch::Tensor b = torch::argmin(a, dim, /*keepdim=*/false);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = torch::argmin(lazy_a, dim, /*keepdim=*/false);
AllEqual(b, lazy_b);
});
}
}
TEST_F(LazyOpsTest, TestArgMinDimKeep) {
torch::Tensor a = torch::rand(
{4, 4, 4}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
for (int dim : {1, -2}) {
torch::Tensor b = torch::argmin(a, dim, /*keepdim=*/true);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = torch::argmin(lazy_a, dim, /*keepdim=*/true);
AllEqual(b, lazy_b);
});
}
}
TEST_F(LazyOpsTest, TestArgMinSameValue) {
torch::Tensor a = torch::ones(
{4, 4, 4}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor b = torch::argmin(a);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = torch::argmin(lazy_a);
AllEqual(b, lazy_b);
});
}
TEST_F(LazyOpsTest, TestArgMinWrapper) {
torch::Tensor a = torch::rand(
{4, 4, 4}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
for (int dim : {1, -2}) {
torch::Tensor b = torch::argmin(a, dim, /*keepdim=*/false);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = torch::argmin(lazy_a, dim, /*keepdim=*/false);
AllEqual(b, lazy_b);
});
}
}
TEST_F(LazyOpsTest, TestArgMax) {
torch::Tensor a = torch::rand(
{4, 4, 4}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor b = torch::argmax(a, c10::nullopt, /*keepdim=*/false);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b =
torch::argmax(lazy_a, c10::nullopt, /*keepdim=*/false);
AllEqual(b, lazy_b);
});
}
TEST_F(LazyOpsTest, TestArgMaxDim) {
torch::Tensor a = torch::rand(
{4, 4, 4}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
for (int dim : {1, -2}) {
torch::Tensor b = torch::argmax(a, dim, /*keepdim=*/false);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = torch::argmax(lazy_a, dim, /*keepdim=*/false);
AllEqual(b, lazy_b);
});
}
}
TEST_F(LazyOpsTest, TestArgMaxDimKeep) {
torch::Tensor a = torch::rand(
{4, 4, 4}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
for (int dim : {1, -2}) {
torch::Tensor b = torch::argmax(a, dim, /*keepdim=*/true);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = torch::argmax(lazy_a, dim, /*keepdim=*/true);
AllEqual(b, lazy_b);
});
}
}
TEST_F(LazyOpsTest, TestArgMaxSameValue) {
torch::Tensor a = torch::ones(
{4, 4, 4}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor b = torch::argmax(a, c10::nullopt, /*keepdim=*/false);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b =
torch::argmax(lazy_a, c10::nullopt, /*keepdim=*/false);
AllEqual(b, lazy_b);
});
}
TEST_F(LazyOpsTest, TestArgMaxWrapper) {
torch::Tensor a = torch::rand(
{4, 4, 4}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
for (int dim : {1, -2}) {
torch::Tensor b = torch::argmax(a, dim, /*keepdim=*/false);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = torch::argmax(lazy_a, dim, /*keepdim=*/false);
AllEqual(b, lazy_b);
});
}
}
TEST_F(LazyOpsTest, TestAsin) {
torch::Tensor a = torch::rand(
{2, 2}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor b = torch::asin(a);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = torch::asin(lazy_a);
AllClose(b, lazy_b, /*rtol=*/1e-3, /*atol=*/1e-5);
});
}
TEST_F(LazyOpsTest, TestAsinh) {
torch::Tensor a = torch::rand(
{2, 2}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor b = torch::asinh(a);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = torch::asinh(lazy_a);
AllClose(b, lazy_b, /*rtol=*/1e-3, /*atol=*/1e-5);
});
}
TEST_F(LazyOpsTest, TestAsinhInPlace) {
torch::Tensor a = torch::rand(
{2, 2}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor b = torch::asinh_(a);
torch::Tensor lazy_b = torch::asinh_(lazy_a);
AllClose(a, lazy_a, /*rtol=*/1e-3, /*atol=*/1e-5);
AllClose(b, lazy_b, /*rtol=*/1e-3, /*atol=*/1e-5);
});
}
TEST_F(LazyOpsTest, TestSin) {
torch::Tensor a = torch::rand(
{2, 2}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor b = torch::sin(a);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = torch::sin(lazy_a);
AllClose(b, lazy_b, /*rtol=*/1e-3, /*atol=*/1e-5);
});
}
TEST_F(LazyOpsTest, TestSinh) {
torch::Tensor a = torch::rand(
{2, 2}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor b = torch::sinh(a);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = torch::sinh(lazy_a);
AllClose(b, lazy_b, /*rtol=*/1e-3, /*atol=*/1e-5);
});
}
TEST_F(LazyOpsTest, TestAcos) {
torch::Tensor a = torch::rand(
{2, 2}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor b = torch::acos(a);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = torch::acos(lazy_a);
AllClose(b, lazy_b, /*rtol=*/1e-3, /*atol=*/1e-5);
});
}
TEST_F(LazyOpsTest, TestAcosh) {
torch::Tensor a =
torch::rand(
{2, 2}, torch::TensorOptions(torch::kFloat).device(DefaultDevice())) *
100;
torch::Tensor b = torch::acosh(a);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = torch::acosh(lazy_a);
AllClose(b, lazy_b, /*rtol=*/1e-3, /*atol=*/1e-5);
});
}
TEST_F(LazyOpsTest, TestAcoshInPlace) {
torch::Tensor a =
torch::rand(
{2, 2}, torch::TensorOptions(torch::kFloat).device(DefaultDevice())) *
100;
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor b = torch::acosh_(a);
torch::Tensor lazy_b = torch::acosh_(lazy_a);
AllClose(a, lazy_a, /*rtol=*/1e-3, /*atol=*/1e-5);
AllClose(b, lazy_b, /*rtol=*/1e-3, /*atol=*/1e-5);
});
}
TEST_F(LazyOpsTest, TestCos) {
torch::Tensor a = torch::rand(
{2, 2}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor b = torch::cos(a);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = torch::cos(lazy_a);
AllClose(b, lazy_b, /*rtol=*/1e-3, /*atol=*/1e-5);
});
}
TEST_F(LazyOpsTest, TestCosh) {
torch::Tensor a = torch::rand(
{2, 2}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor b = torch::cosh(a);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = torch::cosh(lazy_a);
AllClose(b, lazy_b, /*rtol=*/1e-3, /*atol=*/1e-5);
});
}
TEST_F(LazyOpsTest, TestAtan) {
torch::Tensor a = torch::rand(
{2, 2}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor b = torch::atan(a);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = torch::atan(lazy_a);
AllClose(b, lazy_b, /*rtol=*/1e-3, /*atol=*/1e-5);
});
}
TEST_F(LazyOpsTest, TestAtanh) {
torch::Tensor a = torch::rand(
{2, 2}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor b = torch::atanh(a);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = torch::atanh(lazy_a);
AllClose(b, lazy_b, /*rtol=*/1e-3, /*atol=*/1e-5);
});
}
TEST_F(LazyOpsTest, TestAtanhInPlace) {
torch::Tensor a = torch::rand(
{2, 2}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor b = torch::atanh_(a);
torch::Tensor lazy_b = torch::atanh_(lazy_a);
AllClose(a, lazy_a, /*rtol=*/1e-3, /*atol=*/1e-5);
AllClose(b, lazy_b, /*rtol=*/1e-3, /*atol=*/1e-5);
});
}
TEST_F(LazyOpsTest, TestAtan2) {
torch::Tensor a = torch::randn(
{2, 2}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor b = torch::randn(
{2, 2}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor c = torch::atan2(a, b);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = CopyToDevice(b, device);
torch::Tensor lazy_c = torch::atan2(lazy_a, lazy_b);
AllClose(c, lazy_c, /*rtol=*/1e-3, /*atol=*/1e-5);
});
}
TEST_F(LazyOpsTest, TestTan) {
torch::Tensor a = torch::rand(
{2, 2}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor b = torch::tan(a);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = torch::tan(lazy_a);
AllClose(b, lazy_b, /*rtol=*/1e-3, /*atol=*/1e-5);
});
}
TEST_F(LazyOpsTest, TestTanh) {
torch::Tensor a = torch::rand(
{2, 2}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor b = torch::tanh(a);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = torch::tanh(lazy_a);
AllClose(b, lazy_b, /*rtol=*/1e-3, /*atol=*/1e-5);
});
}
TEST_F(LazyOpsTest, TestClampMinMax) {
torch::Tensor a = torch::rand(
{2, 2}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Scalar min_val(0.311);
torch::Scalar max_val(0.409);
torch::Tensor b = torch::clamp(a, min_val, max_val);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = torch::clamp(lazy_a, min_val, max_val);
AllClose(b, lazy_b);
});
}
TEST_F(LazyOpsTest, TestClampMin) {
torch::Tensor a = torch::rand(
{2, 2}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Scalar min_val(0.311);
torch::Tensor b = torch::clamp(a, min_val, c10::nullopt);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = torch::clamp(lazy_a, min_val, c10::nullopt);
AllClose(b, lazy_b);
});
}
TEST_F(LazyOpsTest, TestClampMax) {
torch::Tensor a = torch::rand(
{2, 2}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Scalar max_val(0.409);
torch::Tensor b = torch::clamp(a, c10::nullopt, max_val);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = torch::clamp(lazy_a, c10::nullopt, max_val);
AllClose(b, lazy_b);
});
}
TEST_F(LazyOpsTest, TestClampMinExplicit) {
torch::Tensor a = torch::rand(
{2, 2}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Scalar min_val(0.311);
torch::Tensor b = torch::clamp_min(a, min_val);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = torch::clamp_min(lazy_a, min_val);
AllClose(b, lazy_b);
});
}
TEST_F(LazyOpsTest, TestClampMaxExplicit) {
torch::Tensor a = torch::rand(
{2, 2}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Scalar max_val(0.409);
torch::Tensor b = torch::clamp_max(a, max_val);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = torch::clamp_max(lazy_a, max_val);
AllClose(b, lazy_b);
});
}
TEST_F(LazyOpsTest, TestClampMinExplicitInPlace) {
torch::Tensor a = torch::rand(
{2, 2}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Scalar min_val(0.311);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor b = torch::clamp_min_(a, min_val);
torch::Tensor lazy_b = torch::clamp_min_(lazy_a, min_val);
AllClose(a, lazy_a);
AllClose(b, lazy_b);
});
}
TEST_F(LazyOpsTest, TestClampMaxExplicitInPlace) {
torch::Tensor a = torch::rand(
{2, 2}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Scalar max_val(0.409);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor b = torch::clamp_max_(a, max_val);
torch::Tensor lazy_b = torch::clamp_max_(lazy_a, max_val);
AllClose(a, lazy_a);
AllClose(b, lazy_b);
});
}
TEST_F(LazyOpsTest, TestCeil) {
torch::Tensor a =
torch::randn(
{2, 2}, torch::TensorOptions(torch::kFloat).device(DefaultDevice())) *
100.0;
torch::Tensor b = torch::ceil(a);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = torch::ceil(lazy_a);
AllClose(b, lazy_b);
});
}
TEST_F(LazyOpsTest, TestFloor) {
torch::Tensor a =
torch::randn(
{2, 2}, torch::TensorOptions(torch::kFloat).device(DefaultDevice())) *
100.0;
torch::Tensor b = torch::floor(a);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = torch::floor(lazy_a);
AllClose(b, lazy_b);
});
}
TEST_F(LazyOpsTest, TestRound) {
torch::Tensor a = torch::cat(
{torch::randn(
{8}, torch::TensorOptions(torch::kFloat).device(DefaultDevice())) *
100.0,
// Special case: 0.5, -0.5. lazy::Round impl rounds to -1/1 whereas
// lazy::RoundToEven properly implements bankers rounding.
torch::tensor(
{-0.5, 0.5},
torch::TensorOptions(torch::kFloat).device(DefaultDevice()))},
0);
torch::Tensor b = torch::round(a);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = torch::round(lazy_a);
AllClose(b, lazy_b);
});
}
TEST_F(LazyOpsTest, TestTrunc) {
torch::Tensor a =
torch::randn(
{2, 2}, torch::TensorOptions(torch::kFloat).device(DefaultDevice())) *
100.0;
torch::Tensor b = torch::trunc(a);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = torch::trunc(lazy_a);
AllClose(b, lazy_b);
});
}
TEST_F(LazyOpsTest, TestFrac) {
torch::Tensor a =
torch::randn(
{2, 2}, torch::TensorOptions(torch::kFloat).device(DefaultDevice())) *
100.0;
torch::Tensor b = torch::frac(a);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = torch::frac(lazy_a);
AllClose(b, lazy_b);
});
}
TEST_F(LazyOpsTest, TestNeg) {
torch::Tensor a = torch::rand(
{2, 2}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor b = torch::neg(a);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = torch::neg(lazy_a);
AllClose(b, lazy_b);
});
}
TEST_F(LazyOpsTest, TestBitwiseNot) {
std::vector<torch::ScalarType> types(
{torch::kByte, torch::kChar, torch::kShort, torch::kInt, torch::kLong});
ForEachDevice([&](const torch::Device& device) {
for (auto type : types) {
torch::Tensor a =
torch::randint(0, 63, {2, 2}, torch::TensorOptions(type));
torch::Tensor b = torch::bitwise_not(a);
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = torch::bitwise_not(lazy_a);
AllEqual(b, lazy_b);
}
});
}
TEST_F(LazyOpsTest, TestBitwiseNotInPlace) {
std::vector<torch::ScalarType> types(
{torch::kByte, torch::kChar, torch::kShort, torch::kInt, torch::kLong});
ForEachDevice([&](const torch::Device& device) {
for (auto type : types) {
torch::Tensor a =
torch::randint(0, 63, {2, 2}, torch::TensorOptions(type));
torch::Tensor lazy_a = CopyToDevice(a, device);
a.bitwise_not_();
lazy_a.bitwise_not_();
AllEqual(a, lazy_a);
}
});
}
TEST_F(LazyOpsTest, TestSign) {
torch::Tensor a =
torch::randn(
{2, 2}, torch::TensorOptions(torch::kFloat).device(DefaultDevice())) *
100.0;
torch::Tensor b = torch::sign(a);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = torch::sign(lazy_a);
AllClose(b, lazy_b);
});
}
TEST_F(LazyOpsTest, TestSignByte) {
torch::Tensor a = torch::randint(
256, {2, 2}, torch::TensorOptions(torch::kByte).device(DefaultDevice()));
torch::Tensor b = torch::sign(a);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = torch::sign(lazy_a);
AllEqual(b, lazy_b);
});
}
TEST_F(LazyOpsTest, TestAbs) {
torch::Tensor a = torch::randn(
{2, 2}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor b = torch::abs(a);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = torch::abs(lazy_a);
AllClose(b, lazy_b);
});
}
TEST_F(LazyOpsTest, TestAbsByte) {
torch::Tensor a = torch::randint(
256, {2, 2}, torch::TensorOptions(torch::kByte).device(DefaultDevice()));
torch::Tensor b = torch::abs(a);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = torch::abs(lazy_a);
AllEqual(b, lazy_b);
});
}
TEST_F(LazyOpsTest, TestEmptyLike) {
torch::Tensor a = torch::rand(
{2, 2}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor b = torch::empty_like(a);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = torch::empty_like(lazy_a);
EXPECT_EQ(b.sizes(), lazy_b.sizes());
});
}
TEST_F(LazyOpsTest, TestEmptyLikeOptions) {
torch::Tensor a = torch::rand(
{2, 2}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor b = torch::empty_like(
a, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = torch::empty_like(
lazy_a, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
EXPECT_EQ(b.sizes(), lazy_b.sizes());
});
}
TEST_F(LazyOpsTest, TestEmpty) {
torch::Tensor a = torch::zeros(
{2, 2}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = torch::empty(
{2, 2}, torch::TensorOptions(torch::kFloat).device(device));
EXPECT_EQ(a.sizes(), lazy_a.sizes());
});
}
TEST_F(LazyOpsTest, TestZeroInPlace) {
torch::Tensor input = torch::ones(
{2, 2}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazyInput = CopyToDevice(input, device);
auto& output = torch::zero_(input);
auto& lazyOutput = torch::zero_(lazyInput);
AllClose(output, lazyOutput);
});
}
TEST_F(LazyOpsTest, TestZerosLike) {
torch::Tensor a = torch::rand(
{2, 2}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor b = torch::zeros_like(a);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = torch::zeros_like(lazy_a);
AllClose(a, lazy_a);
});
}
TEST_F(LazyOpsTest, TestZerosLikeOptions) {
torch::Tensor a = torch::rand(
{2, 2}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor b = torch::zeros_like(
a, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = torch::zeros_like(
lazy_a, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
AllClose(a, lazy_a);
});
}
TEST_F(LazyOpsTest, TestZeros) {
torch::Tensor a = torch::zeros(
{2, 2}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = torch::zeros(
{2, 2}, torch::TensorOptions(torch::kFloat).device(device));
AllClose(a, lazy_a);
});
}
TEST_F(LazyOpsTest, TestOnes) {
torch::Tensor a = torch::ones(
{2, 2}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a =
torch::ones({2, 2}, torch::TensorOptions(torch::kFloat).device(device));
AllClose(a, lazy_a);
});
}
TEST_F(LazyOpsTest, TestOnesLike) {
torch::Tensor a = torch::rand(
{2, 2}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor b = torch::ones_like(a);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = torch::ones_like(lazy_a);
AllClose(a, lazy_a);
});
}
TEST_F(LazyOpsTest, TestOnesLikeOptions) {
torch::Tensor a = torch::rand(
{2, 2}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor b = torch::ones_like(
a, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = torch::ones_like(
lazy_a, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
AllClose(a, lazy_a);
});
}
TEST_F(LazyOpsTest, TestFull) {
torch::Tensor a = torch::full(
{2, 2},
3.1165,
torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = torch::full(
{2, 2}, 3.1165, torch::TensorOptions(torch::kFloat).device(device));
AllClose(a, lazy_a);
});
}
TEST_F(LazyOpsTest, TestFullLike) {
torch::Tensor a = torch::rand(
{2, 2}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor b = torch::full_like(a, 3.1165);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = torch::full_like(lazy_a, 3.1165);
AllClose(a, lazy_a);
});
}
TEST_F(LazyOpsTest, TestFullLikeOptions) {
torch::Tensor a = torch::rand(
{2, 2}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor b = torch::full_like(
a, 3.1165, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = torch::full_like(
lazy_a,
3.1165,
torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
AllClose(a, lazy_a);
});
}
TEST_F(LazyOpsTest, TestARange) {
for (auto& ranges : std::vector<std::vector<float>>{
{0.0, 100.0, 0.5}, {0.0, -100.0, -0.5}}) {
torch::Tensor a = torch::arange(
ranges[0],
ranges[1],
ranges[2],
torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = torch::arange(
ranges[0],
ranges[1],
ranges[2],
torch::TensorOptions(torch::kFloat).device(device));
AllClose(a, lazy_a);
});
}
}
TEST_F(LazyOpsTest, TestARangeOut) {
torch::Tensor a = torch::randn(
{4}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
for (auto& ranges : std::vector<std::vector<float>>{
{0.0, 100.0, 0.5}, {0.0, -100.0, -0.5}}) {
torch::Tensor b = torch::arange_out(a, ranges[0], ranges[1], ranges[2]);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b =
torch::arange_out(lazy_a, ranges[0], ranges[1], ranges[2]);
AllClose(b, lazy_b);
});
}
}
TEST_F(LazyOpsTest, TestDimARange) {
torch::Tensor like = torch::rand(
{2, 2}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor a = torch::_dim_arange(like, 1);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_like = CopyToDevice(like, device);
torch::Tensor lazy_a = torch::_dim_arange(lazy_like, 1);
AllClose(a, lazy_a);
});
}
TEST_F(LazyOpsTest, TestBartlettWindow) {
int window_length = 10;
for (bool periodic : {false, true}) {
ForEachDevice([&](const torch::Device& device) {
torch::Tensor output = torch::bartlett_window(
window_length,
periodic,
torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor lazy_output = torch::bartlett_window(
window_length,
periodic,
torch::TensorOptions(torch::kFloat).device(device));
AllClose(output, lazy_output, /*rtol=*/1e-5, /*atol=*/1e-7);
});
}
}
TEST_F(LazyOpsTest, TestBlackmanWindow) {
int window_length = 10;
for (bool periodic : {false, true}) {
ForEachDevice([&](const torch::Device& device) {
torch::Tensor output = torch::blackman_window(
window_length,
periodic,
torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor lazy_output = torch::blackman_window(
window_length,
periodic,
torch::TensorOptions(torch::kFloat).device(device));
AllClose(output, lazy_output, /*rtol=*/1e-5, /*atol=*/1e-7);
});
}
}
TEST_F(LazyOpsTest, TestHammingWindow) {
double alpha = 0.54;
double beta = 0.46;
int window_length = 10;
for (bool periodic : {false, true}) {
ForEachDevice([&](const torch::Device& device) {
torch::Tensor output = torch::hamming_window(
window_length,
periodic,
alpha,
beta,
torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor lazy_output = torch::hamming_window(
window_length,
periodic,
alpha,
beta,
torch::TensorOptions(torch::kFloat).device(device));
AllClose(output, lazy_output);
});
}
}
TEST_F(LazyOpsTest, TestHannWindow) {
int window_length = 10;
for (bool periodic : {false, true}) {
ForEachDevice([&](const torch::Device& device) {
torch::Tensor output = torch::hann_window(
window_length,
periodic,
torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor lazy_output = torch::hann_window(
window_length,
periodic,
torch::TensorOptions(torch::kFloat).device(device));
AllClose(output, lazy_output);
});
}
}
TEST_F(LazyOpsTest, TestLogSigmoid) {
torch::Tensor a = torch::empty(
{2, 2}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
a.uniform_(-1.0, 1.0);
torch::Tensor b = torch::log_sigmoid(a);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = torch::log_sigmoid(lazy_a);
AllClose(b, lazy_b, /*rtol=*/1e-3, /*atol=*/1e-5);
});
}
TEST_F(LazyOpsTest, TestLogSigmoidForward) {
torch::Tensor a = torch::empty(
{2, 2}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
a.uniform_(-1.0, 1.0);
auto tuple = torch::log_sigmoid_forward(a);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
auto lazy_tuple = torch::log_sigmoid_forward(lazy_a);
AllClose(
std::get<0>(tuple),
std::get<0>(lazy_tuple),
/*rtol=*/1e-3,
/*atol=*/1e-5);
AllClose(
std::get<1>(tuple),
std::get<1>(lazy_tuple),
/*rtol=*/1e-3,
/*atol=*/1e-5);
});
}
TEST_F(LazyOpsTest, TestLogsumexp) {
torch::Tensor a = torch::rand(
{3, 4, 3}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
for (auto dims : std::vector<std::vector<int64_t>>{{0, 1}, {-3, -2}}) {
for (bool keepdim : {false, true}) {
torch::Tensor b = torch::logsumexp(a, dims, keepdim);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = torch::logsumexp(lazy_a, dims, keepdim);
AllClose(b, lazy_b);
});
}
}
}
TEST_F(LazyOpsTest, TestSiLU) {
torch::Tensor a = torch::rand(
{2, 2}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor b = torch::silu(a);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = torch::silu(lazy_a);
AllClose(b, lazy_b, /*rtol=*/1e-3, /*atol=*/1e-5);
});
ExpectCounterChanged("lazy::silu_out", GetIgnoredCounters());
}
TEST_F(LazyOpsTest, TestSigmoid) {
torch::Tensor a = torch::rand(
{2, 2}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor b = torch::sigmoid(a);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = torch::sigmoid(lazy_a);
AllClose(b, lazy_b, /*rtol=*/1e-3, /*atol=*/1e-5);
});
}
TEST_F(LazyOpsTest, TestMatmul_1x1) {
torch::Tensor a = torch::rand(
{4}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor b = torch::rand(
{4}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor c = torch::matmul(a, b);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = CopyToDevice(b, device);
torch::Tensor lazy_c = torch::matmul(lazy_a, lazy_b);
AllClose(c, lazy_c);
});
}
TEST_F(LazyOpsTest, TestMatmul_2x1) {
torch::Tensor a = torch::rand(
{3, 4}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor b = torch::rand(
{4}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor c = torch::matmul(a, b);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = CopyToDevice(b, device);
torch::Tensor lazy_c = torch::matmul(lazy_a, lazy_b);
AllClose(c, lazy_c);
});
}
TEST_F(LazyOpsTest, TestMatmul_1x2) {
torch::Tensor a = torch::rand(
{4}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor b = torch::rand(
{4, 3}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor c = torch::matmul(a, b);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = CopyToDevice(b, device);
torch::Tensor lazy_c = torch::matmul(lazy_a, lazy_b);
AllClose(c, lazy_c);
});
}
TEST_F(LazyOpsTest, TestMatmul_2x2) {
torch::Tensor a = torch::rand(
{2, 4}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor b = torch::rand(
{4, 3}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor c = torch::matmul(a, b);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = CopyToDevice(b, device);
torch::Tensor lazy_c = torch::matmul(lazy_a, lazy_b);
AllClose(c, lazy_c, /*rtol=*/1e-3, /*atol=*/1e-4);
});
}
TEST_F(LazyOpsTest, TestMatmulBcast) {
torch::Tensor a = torch::rand(
{4, 2, 3, 2, 4},
torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor b = torch::rand(
{2, 1, 4, 3},
torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor c = torch::matmul(a, b);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = CopyToDevice(b, device);
torch::Tensor lazy_c = torch::matmul(lazy_a, lazy_b);
AllClose(c, lazy_c);
});
}
TEST_F(LazyOpsTest, TestDot) {
torch::Tensor a = torch::rand(
{4}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor b = torch::rand(
{4}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor c = torch::dot(a, b);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = CopyToDevice(b, device);
torch::Tensor lazy_c = torch::dot(lazy_a, lazy_b);
AllClose(c, lazy_c);
});
}
TEST_F(LazyOpsTest, TestTensorDot) {
torch::Tensor a = torch::rand(
{6, 4, 8}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor b = torch::rand(
{4, 7, 8}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
std::vector<int64_t> dims_a = {1, 2};
std::vector<int64_t> dims_b = {0, 2};
torch::Tensor c = torch::tensordot(a, b, dims_a, dims_b);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = CopyToDevice(b, device);
torch::Tensor lazy_c = torch::tensordot(lazy_a, lazy_b, dims_a, dims_b);
AllClose(c, lazy_c);
});
}
TEST_F(LazyOpsTest, TestGer) {
torch::Tensor a = torch::rand(
{4}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor b = torch::rand(
{5}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor c = torch::ger(a, b);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = CopyToDevice(b, device);
torch::Tensor lazy_c = torch::ger(lazy_a, lazy_b);
AllClose(c, lazy_c);
});
}
TEST_F(LazyOpsTest, TestMv) {
torch::Tensor a = torch::rand(
{4, 3}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor b = torch::rand(
{3}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor c = torch::mv(a, b);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = CopyToDevice(b, device);
torch::Tensor lazy_c = torch::mv(lazy_a, lazy_b);
AllClose(c, lazy_c);
});
}
TEST_F(LazyOpsTest, TestMvOut) {
torch::Tensor a = torch::rand(
{4, 3}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor b = torch::rand(
{3}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor c = torch::empty(
{4}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::mv_out(c, a, b);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = CopyToDevice(b, device);
torch::Tensor lazy_c = torch::empty({4}, lazy_b.options());
torch::mv_out(lazy_c, lazy_a, lazy_b);
AllClose(c, lazy_c);
});
}
TEST_F(LazyOpsTest, TestBatchAddBatchMatMul) {
torch::Tensor a = torch::rand(
{3, 6, 5}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor b = torch::rand(
{3, 6, 4}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor c = torch::rand(
{3, 4, 5}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Scalar alpha = 0.5;
torch::Scalar beta = 1.5;
torch::Tensor d = torch::baddbmm(a, b, c, beta, alpha);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = CopyToDevice(b, device);
torch::Tensor lazy_c = CopyToDevice(c, device);
torch::Tensor lazy_d = torch::baddbmm(lazy_a, lazy_b, lazy_c, beta, alpha);
AllClose(d, lazy_d, /*rtol=*/1e-3, /*atol=*/1e-4);
});
}
TEST_F(LazyOpsTest, TestBatchAddBatchMatMulInPlace) {
torch::Tensor a = torch::rand(
{3, 6, 5}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor b = torch::rand(
{3, 6, 4}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor c = torch::rand(
{3, 4, 5}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Scalar alpha = 0.5;
torch::Scalar beta = 1.5;
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = CopyToDevice(b, device);
torch::Tensor lazy_c = CopyToDevice(c, device);
torch::Tensor d = a.baddbmm_(b, c, beta, alpha);
torch::Tensor lazy_d = lazy_a.baddbmm_(lazy_b, lazy_c, beta, alpha);
AllClose(d, lazy_d, /*rtol=*/1e-3, /*atol=*/1e-4);
AllClose(a, lazy_a, /*rtol=*/1e-3, /*atol=*/1e-4);
});
}
TEST_F(LazyOpsTest, TestBatchMatMul) {
torch::Tensor a = torch::rand(
{3, 6, 4}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor b = torch::rand(
{3, 4, 5}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor c = torch::bmm(a, b);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = CopyToDevice(b, device);
torch::Tensor lazy_c = torch::bmm(lazy_a, lazy_b);
AllClose(c, lazy_c, /*rtol=*/1e-3, /*atol=*/1e-4);
});
}
TEST_F(LazyOpsTest, TestChainMatMul) {
torch::Tensor a = torch::rand(
{5, 4}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor b = torch::rand(
{4, 6}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor c = torch::rand(
{6, 2}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor d = torch::rand(
{2, 7}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor result = torch::chain_matmul({a, b, c, d});
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = CopyToDevice(b, device);
torch::Tensor lazy_c = CopyToDevice(c, device);
torch::Tensor lazy_d = CopyToDevice(d, device);
torch::Tensor lazy_result =
torch::chain_matmul({lazy_a, lazy_b, lazy_c, lazy_d});
AllClose(result, lazy_result, /*rtol=*/1e-3, /*atol=*/1e-4);
});
}
TEST_F(LazyOpsTest, TestLinear) {
torch::Tensor input = torch::rand(
{2, 4}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor weight = torch::rand(
{3, 4}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor bias = torch::rand(
{3}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor result = torch::linear(input, weight);
torch::Tensor result_with_bias = torch::linear(input, weight, bias);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor lazy_weight = CopyToDevice(weight, device);
torch::Tensor lazy_bias = CopyToDevice(bias, device);
torch::Tensor lazy_result = torch::linear(lazy_input, lazy_weight);
torch::Tensor lazy_result_with_bias =
torch::linear(lazy_input, lazy_weight, lazy_bias);
AllClose(result, lazy_result, /*rtol=*/1e-2, /*atol=*/1e-4);
AllClose(
result_with_bias,
lazy_result_with_bias,
/*rtol=*/1e-2,
/*atol=*/1e-4);
});
}
TEST_F(LazyOpsTest, TestPinverse) {
torch::Tensor input = torch::rand(
{4, 6}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor result = torch::pinverse(input);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor lazy_result = torch::pinverse(lazy_input);
AllClose(result, lazy_result, /*rtol=*/1e-4);
});
}
TEST_F(LazyOpsTest, TestEinsumOuter) {
torch::Tensor a = torch::rand(
{5}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor b = torch::rand(
{5}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
std::string equation = "i,j->ij";
torch::Tensor c = torch::einsum(equation, {a, b});
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = CopyToDevice(b, device);
torch::Tensor lazy_c = torch::einsum(equation, {lazy_a, lazy_b});
AllClose(c, lazy_c);
});
}
TEST_F(LazyOpsTest, TestEinsumOuterBackward) {
torch::Tensor a = torch::rand(
{5},
torch::TensorOptions(torch::kFloat)
.device(DefaultDevice())
.requires_grad(true));
torch::Tensor b = torch::rand(
{5},
torch::TensorOptions(torch::kFloat)
.device(DefaultDevice())
.requires_grad(true));
std::string equation = "i,j->ij";
auto testfn = [&](const std::vector<torch::Tensor>& inputs) -> torch::Tensor {
return torch::einsum(equation, inputs);
};
ForEachDevice([&](const torch::Device& device) {
TestBackward({a, b}, device, testfn, /*rtol=*/1e-3, /*atol=*/1e-4);
});
}
TEST_F(LazyOpsTest, TestEinsumBatchMatMul) {
torch::Tensor a = torch::rand(
{3, 2, 5}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor b = torch::rand(
{3, 5, 4}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
std::string equation = "bij,bjk->bik";
torch::Tensor c = torch::einsum(equation, {a, b});
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = CopyToDevice(b, device);
torch::Tensor lazy_c = torch::einsum(equation, {lazy_a, lazy_b});
AllClose(c, lazy_c);
});
}
TEST_F(LazyOpsTest, TestEinsumPyTorchLowerBilinear) {
torch::Tensor a = torch::rand(
{3, 5, 4}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor l = torch::rand(
{2, 5}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor r = torch::rand(
{2, 4}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
std::string equation = "bn,anm,bm->ba";
torch::Tensor c = torch::einsum(equation, {l, a, r});
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_l = CopyToDevice(l, device);
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_r = CopyToDevice(r, device);
torch::Tensor lazy_c = torch::einsum(equation, {lazy_l, lazy_a, lazy_r});
AllClose(c, lazy_c);
});
}
TEST_F(LazyOpsTest, TestEinsumPyTorchLowerDiagonal) {
torch::Tensor input = torch::rand(
{3, 3}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
std::string equation = "ii->i";
torch::Tensor result = torch::einsum(equation, {input});
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor lazy_result = torch::einsum(equation, {lazy_input});
AllClose(result, lazy_result);
});
}
TEST_F(LazyOpsTest, TestEinsumPyTorchLowerBatchDiagonal) {
torch::Tensor input = torch::rand(
{4, 3, 3}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
std::string equation = "...ii->...i";
torch::Tensor result = torch::einsum(equation, {input});
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor lazy_result = torch::einsum(equation, {lazy_input});
AllClose(result, lazy_result);
});
}
TEST_F(LazyOpsTest, TestEinsumPyTorchLowerBatchPermute) {
torch::Tensor input = torch::rand(
{2, 3, 4, 5},
torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
std::string equation = "...ij->...ji";
torch::Tensor result = torch::einsum(equation, {input});
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor lazy_result = torch::einsum(equation, {lazy_input});
AllClose(result, lazy_result);
});
}
TEST_F(LazyOpsTest, TestEinsumPyTorchLowerRepeatedAxis) {
torch::Tensor x = torch::rand(
{2, 3, 3}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor y = torch::rand(
{4}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
std::string equation = "ijj,k->ik";
torch::Tensor result = torch::einsum(equation, {x, y});
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_x = CopyToDevice(x, device);
torch::Tensor lazy_y = CopyToDevice(y, device);
torch::Tensor lazy_result = torch::einsum(equation, {lazy_x, lazy_y});
AllClose(result, lazy_result);
});
}
TEST_F(LazyOpsTest, TestBilinear) {
int batch_size = 16;
int in1_features = 4;
int in2_features = 6;
int out_features = 8;
torch::Tensor input1 = torch::rand(
{batch_size, in1_features},
torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor input2 = torch::rand(
{batch_size, in2_features},
torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor weight = torch::rand(
{out_features, in1_features, in2_features},
torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor bias = torch::rand(
{out_features},
torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input1 = CopyToDevice(input1, device);
torch::Tensor lazy_input2 = CopyToDevice(input2, device);
torch::Tensor lazy_weight = CopyToDevice(weight, device);
torch::Tensor lazy_bias = CopyToDevice(bias, device);
torch::Tensor result = torch::bilinear(input1, input2, weight, bias);
torch::Tensor lazy_result =
torch::bilinear(lazy_input1, lazy_input2, lazy_weight, lazy_bias);
AllClose(result, lazy_result);
});
}
TEST_F(LazyOpsTest, TestUpsampleNearest2D) {
int batch_size = 2;
int h = 5;
int w = 5;
int uh = 8;
int uw = 8;
int chans = 2;
torch::Tensor input = torch::rand(
{batch_size, chans, h, w},
torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor result = torch::upsample_nearest2d(input, {uh, uw});
torch::Tensor lazy_result = torch::upsample_nearest2d(lazy_input, {uh, uw});
AllClose(result, lazy_result);
});
}
TEST_F(LazyOpsTest, TestUpsampleNearest2DBackward) {
int batch_size = 2;
int h = 5;
int w = 5;
int uh = 8;
int uw = 8;
int chans = 2;
auto testfn = [&](const std::vector<torch::Tensor>& inputs) -> torch::Tensor {
return torch::upsample_nearest2d(inputs[0], {uh, uw});
};
ForEachDevice([&](const torch::Device& device) {
TestBackward(
{torch::rand(
{batch_size, chans, h, w},
torch::TensorOptions(torch::kFloat)
.device(DefaultDevice())
.requires_grad(true))},
device,
testfn);
});
}
TEST_F(LazyOpsTest, TestUpsampleNearest2DWithScale) {
int batch_size = 2;
int h = 5;
int w = 5;
int chans = 2;
double scale_h = 2.5;
double scale_w = 3.4;
torch::Tensor input = torch::rand(
{batch_size, chans, h, w},
torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor result = torch::upsample_nearest2d(
input, c10::nullopt, at::ArrayRef<double>{scale_h, scale_w});
torch::Tensor lazy_result = torch::upsample_nearest2d(
lazy_input, c10::nullopt, at::ArrayRef<double>{scale_h, scale_w});
AllClose(result, lazy_result);
});
}
TEST_F(LazyOpsTest, TestUpsampleNearest2DBackwardWithScale) {
int batch_size = 2;
int h = 5;
int w = 5;
int chans = 2;
double scale_h = 2.5;
double scale_w = 3.4;
auto testfn = [&](const std::vector<torch::Tensor>& inputs) -> torch::Tensor {
return torch::upsample_nearest2d(
inputs[0], c10::nullopt, at::ArrayRef<double>{scale_h, scale_w});
};
ForEachDevice([&](const torch::Device& device) {
TestBackward(
{torch::rand(
{batch_size, chans, h, w},
torch::TensorOptions(torch::kFloat)
.device(DefaultDevice())
.requires_grad(true))},
device,
testfn);
});
}
TEST_F(LazyOpsTest, TestUpsampleBilinear2D) {
int batch_size = 2;
int h = 5;
int w = 5;
int uh = 8;
int uw = 8;
int chans = 2;
for (bool align_corners : {true, false}) {
torch::Tensor input = torch::rand(
{batch_size, chans, h, w},
torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor result =
torch::upsample_bilinear2d(input, {uh, uw}, align_corners);
torch::Tensor lazy_result =
torch::upsample_bilinear2d(lazy_input, {uh, uw}, align_corners);
AllClose(result, lazy_result);
});
}
}
TEST_F(LazyOpsTest, TestUpsampleBilinear2DBackward) {
int batch_size = 2;
int h = 5;
int w = 5;
int uh = 8;
int uw = 8;
int chans = 2;
for (bool align_corners : {true, false}) {
auto testfn =
[&](const std::vector<torch::Tensor>& inputs) -> torch::Tensor {
return torch::upsample_bilinear2d(inputs[0], {uh, uw}, align_corners);
};
ForEachDevice([&](const torch::Device& device) {
TestBackward(
{torch::rand(
{batch_size, chans, h, w},
torch::TensorOptions(torch::kFloat)
.device(DefaultDevice())
.requires_grad(true))},
device,
testfn);
});
}
}
TEST_F(LazyOpsTest, TestAddCMul) {
torch::Tensor a = torch::rand(
{2, 2}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor b = torch::rand(
{2, 2}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor c = torch::rand(
{2, 2}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor d = torch::addcmul(a, b, c, 3.1165);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = CopyToDevice(b, device);
torch::Tensor lazy_c = CopyToDevice(c, device);
torch::Tensor lazy_d = torch::addcmul(lazy_a, lazy_b, lazy_c, 3.1165);
AllClose(d, lazy_d);
});
}
TEST_F(LazyOpsTest, TestAddCDiv) {
torch::Tensor a = torch::rand(
{2, 2}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor b = torch::rand(
{2, 2}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor c =
torch::abs(torch::rand(
{2, 2},
torch::TensorOptions(torch::kFloat).device(DefaultDevice()))) +
1.0;
torch::Tensor d = torch::addcdiv(a, b, c, 3.1165);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = CopyToDevice(b, device);
torch::Tensor lazy_c = CopyToDevice(c, device);
torch::Tensor lazy_d = torch::addcdiv(lazy_a, lazy_b, lazy_c, 3.1165);
AllClose(d, lazy_d);
});
}
TEST_F(LazyOpsTest, TestAddCDivWithBroadcast) {
torch::Tensor a = torch::rand(
{1, 3}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor b = torch::rand(
{3, 1}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor c =
torch::abs(torch::rand(
{1, 3},
torch::TensorOptions(torch::kFloat).device(DefaultDevice()))) +
1.0;
torch::Tensor d = torch::addcdiv(a, b, c, 3.1165);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = CopyToDevice(b, device);
torch::Tensor lazy_c = CopyToDevice(c, device);
torch::Tensor lazy_d = torch::addcdiv(lazy_a, lazy_b, lazy_c, 3.1165);
AllClose(d, lazy_d);
});
}
TEST_F(LazyOpsTest, TestSize) {
torch::Tensor input = torch::rand(
{2, 1, 4, 6},
torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
int rank = input.dim();
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
for (int dim = -rank; dim < rank; ++dim) {
EXPECT_EQ(torch::size(input, dim), torch::size(lazy_input, dim));
}
});
}
TEST_F(LazyOpsTest, TestSelect) {
std::vector<int64_t> input_sizes = {14, 24, 8};
int rank = input_sizes.size();
for (int dim = -rank; dim < rank; ++dim) {
auto testfn =
[&](const std::vector<torch::Tensor>& inputs) -> torch::Tensor {
return torch::select(inputs[0], dim, 0);
};
ForEachDevice([&](const torch::Device& device) {
TestBackward(
{torch::rand(
input_sizes,
torch::TensorOptions(torch::kFloat).requires_grad(true))},
device,
testfn);
});
};
}
TEST_F(LazyOpsTest, TestBernoulliScalarProb) {
torch::Tensor input = torch::zeros(
1000, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor lazy_output = torch::bernoulli(lazy_input, 0.1);
double frac = lazy_output.sum().item().toDouble() / input.numel();
EXPECT_GT(frac, 0.06);
EXPECT_LT(frac, 0.14);
});
}
TEST_F(LazyOpsTest, TestBernoulliTensorProb) {
std::vector<float> prob_values(1000, 0.1);
torch::Tensor input = torch::tensor(
prob_values, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor lazy_output = torch::bernoulli(lazy_input);
double frac = lazy_output.sum().item().toDouble() / input.numel();
EXPECT_GT(frac, 0.06);
EXPECT_LT(frac, 0.14);
});
}
TEST_F(LazyOpsTest, TestBernoulliScalarProbInPlace) {
torch::Tensor input = torch::zeros(
1000, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
lazy_input.bernoulli_(0.1);
double frac = lazy_input.sum().item().toDouble() / input.numel();
EXPECT_GT(frac, 0.06);
EXPECT_LT(frac, 0.14);
});
}
TEST_F(LazyOpsTest, TestBernoulliTensorProbInPlace) {
torch::Tensor input = torch::zeros(
1000, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor prob = torch::scalar_tensor(
0.1, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor lazy_prob = CopyToDevice(prob, device);
lazy_input.bernoulli_(lazy_prob);
double frac = lazy_input.sum().item().toDouble() / input.numel();
EXPECT_GT(frac, 0.06);
EXPECT_LT(frac, 0.14);
});
}
TEST_F(LazyOpsTest, TestDropout) {
torch::Tensor a = torch::rand(
{17, 21}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = torch::dropout(lazy_a, 0.1, /*train=*/true);
double prob =
static_cast<double>(lazy_b.cpu().ne(0.0f).sum().item().toDouble()) /
a.numel();
EXPECT_GT(prob, 0.86);
EXPECT_LT(prob, 0.94);
});
}
TEST_F(LazyOpsTest, TestDropoutInPlace) {
torch::Tensor a = torch::rand(
{17, 21}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::dropout_(lazy_a, 0.1, /*train=*/true);
double prob =
static_cast<double>(lazy_a.cpu().ne(0.0f).sum().item().toDouble()) /
a.numel();
EXPECT_GT(prob, 0.85);
EXPECT_LT(prob, 0.94);
});
}
TEST_F(LazyOpsTest, TestRandperm) {
unsigned n = 5;
torch::Tensor shuffle = torch::randperm(
n, torch::TensorOptions(torch::kLong).device(torch::kLazy));
torch::Tensor shuffle_cpu = CopyToDevice(shuffle, torch::kCPU);
std::vector<int64_t> shuffle_data(
shuffle_cpu.data_ptr<int64_t>(), shuffle_cpu.data_ptr<int64_t>() + n);
EXPECT_TRUE(
shuffle_data.size() == n && torch::lazy::IsPermutation(shuffle_data));
}
TEST_F(LazyOpsTest, TestSlice) {
torch::Tensor a = torch::rand(
{32, 24, 16},
torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor b = torch::slice(a, 1, 0, 16, 1);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = torch::slice(lazy_a, 1, 0, 16, 1);
AllClose(b, lazy_b);
});
}
TEST_F(LazyOpsTest, TestTake) {
torch::Tensor a = torch::rand(
{4, 4}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor b = torch::randint(
16, {5}, torch::TensorOptions(torch::kLong).device(DefaultDevice()));
torch::Tensor c = torch::take(a, b);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = CopyToDevice(b, device);
torch::Tensor lazy_c = torch::take(lazy_a, lazy_b);
AllClose(c, lazy_c);
});
}
TEST_F(LazyOpsTest, TestTakeBackward) {
auto testfn = [&](const std::vector<torch::Tensor>& inputs) -> torch::Tensor {
return torch::take(inputs[0], inputs[1]);
};
ForEachDevice([&](const torch::Device& device) {
TestBackward(
{torch::rand(
{4, 4},
torch::TensorOptions(torch::kFloat)
.device(DefaultDevice())
.requires_grad(true)),
torch::randint(
16,
{5},
torch::TensorOptions(torch::kLong).device(DefaultDevice()))},
device,
testfn);
});
}
TEST_F(LazyOpsTest, TestStack) {
torch::Tensor a = torch::rand(
{2, 4, 3}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor b = torch::rand(
{2, 4, 3}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor c = torch::rand(
{2, 4, 3}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
int rank = a.dim() + 1;
for (int dim = -rank; dim < rank; ++dim) {
torch::Tensor d = torch::stack({a, b, c}, dim);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = CopyToDevice(b, device);
torch::Tensor lazy_c = CopyToDevice(c, device);
torch::Tensor lazy_d = torch::stack({lazy_a, lazy_b, lazy_c}, dim);
AllClose(d, lazy_d);
});
}
}
TEST_F(LazyOpsTest, TestCat) {
torch::Tensor a = torch::rand(
{2, 1, 3}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor b = torch::rand(
{2, 2, 3}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor c = torch::rand(
{2, 3, 3}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
for (int dim : {1, -2}) {
torch::Tensor d = torch::cat({a, b, c}, dim);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = CopyToDevice(b, device);
torch::Tensor lazy_c = CopyToDevice(c, device);
torch::Tensor lazy_d = torch::cat({lazy_a, lazy_b, lazy_c}, dim);
EXPECT_TRUE(d.sizes() == lazy_d.sizes() && d.dtype() == lazy_d.dtype());
AllClose(d, lazy_d);
});
}
}
TEST_F(LazyOpsTest, TestUnbind) {
torch::Tensor input = torch::rand(
{4, 3, 7}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
int rank = input.dim();
for (int dim = -rank; dim < rank; ++dim) {
std::vector<torch::Tensor> output = torch::unbind(input, dim);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
std::vector<torch::Tensor> lazy_output = torch::unbind(lazy_input, dim);
ASSERT_EQ(output.size(), lazy_output.size());
for (size_t i = 0; i < output.size(); ++i) {
AllClose(output[i], lazy_output[i]);
}
});
}
}
TEST_F(LazyOpsTest, TestRepeat) {
std::vector<std::vector<int64_t>> repeats_list = {{4, 2}, {4, 2, 3}};
std::vector<std::vector<int64_t>> input_size_list = {{3}, {2, 4}};
for (const auto& repeats : repeats_list) {
for (const auto& input_size : input_size_list) {
torch::Tensor input = torch::rand(
input_size,
torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor output = input.repeat(repeats);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor lazy_output = lazy_input.repeat(repeats);
AllClose(output, lazy_output);
});
}
}
}
TEST_F(LazyOpsTest, TestGather) {
torch::Tensor a = torch::rand(
{3, 3}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor b = torch::empty(
{3, 3}, torch::TensorOptions(torch::kLong).device(DefaultDevice()));
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
b[i][j] = (i + j) % 3;
}
}
for (bool sparse_grad : {false, true}) {
torch::Tensor c = torch::gather(a, 1, b, sparse_grad);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = CopyToDevice(b, device);
torch::Tensor lazy_c = torch::gather(lazy_a, 1, lazy_b, sparse_grad);
AllClose(c, lazy_c);
});
}
}
TEST_F(LazyOpsTest, TestScatter) {
torch::Tensor a = torch::rand(
{3, 5}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor b = torch::rand(
{3, 5}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor c = torch::empty(
{3, 5}, torch::TensorOptions(torch::kLong).device(DefaultDevice()));
for (int dim = 0; dim < 2; ++dim) {
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 5; j++) {
c[i][j] = (i + j) % c.sizes()[dim];
}
}
torch::Tensor d = torch::scatter(a, dim, c, b);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = CopyToDevice(b, device);
torch::Tensor lazy_c = CopyToDevice(c, device);
torch::Tensor lazy_d = torch::scatter(lazy_a, dim, lazy_c, lazy_b);
AllClose(d, lazy_d);
});
}
}
TEST_F(LazyOpsTest, TestScatterR1) {
torch::Tensor a = torch::rand(
{5}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor b = torch::rand(
{2}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor c = torch::empty(
{2}, torch::TensorOptions(torch::kLong).device(DefaultDevice()));
c[0] = 1;
c[1] = 3;
torch::Tensor d = torch::scatter(a, 0, c, b);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = CopyToDevice(b, device);
torch::Tensor lazy_c = CopyToDevice(c, device);
torch::Tensor lazy_d = torch::scatter(lazy_a, 0, lazy_c, lazy_b);
AllClose(d, lazy_d);
});
}
TEST_F(LazyOpsTest, TestScatterR3) {
torch::Tensor a = torch::rand(
{3, 5, 2}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor b = torch::rand(
{3, 4, 2}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor c = torch::empty(
{3, 4, 2}, torch::TensorOptions(torch::kLong).device(DefaultDevice()));
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 4; j++) {
for (int k = 0; k < 2; k++) {
c[i][j][k] = (i + j + k) % 4;
}
}
}
torch::Tensor d = torch::scatter(a, 1, c, b);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = CopyToDevice(b, device);
torch::Tensor lazy_c = CopyToDevice(c, device);
torch::Tensor lazy_d = torch::scatter(lazy_a, 1, lazy_c, lazy_b);
AllClose(d, lazy_d);
});
}
TEST_F(LazyOpsTest, TestScatterBiggerSource) {
torch::Tensor a = torch::rand(
{4, 4}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor b = torch::rand(
{8, 8}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor c = torch::empty(
{4, 4}, torch::TensorOptions(torch::kLong).device(DefaultDevice()));
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
c[i][j] = (i + j) % 4;
}
}
for (int dim = 0; dim < 2; ++dim) {
torch::Tensor d = torch::scatter(a, dim, c, b);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = CopyToDevice(b, device);
torch::Tensor lazy_c = CopyToDevice(c, device);
torch::Tensor lazy_d = torch::scatter(lazy_a, dim, lazy_c, lazy_b);
AllClose(d, lazy_d);
});
}
}
TEST_F(LazyOpsTest, TestScatterScalar) {
torch::Tensor a = torch::rand(
{4, 4}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Scalar b = 1.0f;
torch::Tensor c = torch::empty(
{4, 4}, torch::TensorOptions(torch::kLong).device(DefaultDevice()));
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
c[i][j] = (i + j) % 4;
}
}
for (int dim = 0; dim < 2; ++dim) {
torch::Tensor d = torch::scatter(a, dim, c, b);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_c = CopyToDevice(c, device);
torch::Tensor lazy_d = torch::scatter(lazy_a, dim, lazy_c, b);
AllClose(d, lazy_d);
});
}
}
TEST_F(LazyOpsTest, TestScatterReduceAdd) {
torch::Tensor a = torch::rand(
{3, 5}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor b = torch::rand(
{3, 5}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor c = torch::empty(
{3, 5}, torch::TensorOptions(torch::kLong).device(DefaultDevice()));
for (int dim = 0; dim < 2; ++dim) {
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 5; j++) {
c[i][j] = (i + j) % c.sizes()[dim];
}
}
torch::Tensor d = torch::scatter(a, dim, c, b, "add");
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = CopyToDevice(b, device);
torch::Tensor lazy_c = CopyToDevice(c, device);
torch::Tensor lazy_d = torch::scatter(lazy_a, dim, lazy_c, lazy_b, "add");
AllClose(d, lazy_d);
});
}
ExpectCounterNotChanged("aten::.*", GetIgnoredCounters());
ExpectCounterChanged("lazy::scatter_out", GetIgnoredCounters());
}
TEST_F(LazyOpsTest, TestScatterAdd) {
torch::Tensor a = torch::rand(
{3, 5}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor b = torch::rand(
{3, 5}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor c = torch::empty(
{3, 5}, torch::TensorOptions(torch::kLong).device(DefaultDevice()));
for (int dim = 0; dim < 2; ++dim) {
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 5; j++) {
c[i][j] = (i + j) % c.sizes()[dim];
}
}
torch::Tensor d = torch::scatter_add(a, dim, c, b);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = CopyToDevice(b, device);
torch::Tensor lazy_c = CopyToDevice(c, device);
torch::Tensor lazy_d = torch::scatter_add(lazy_a, dim, lazy_c, lazy_b);
AllClose(d, lazy_d);
});
}
}
TEST_F(LazyOpsTest, TestScatterAddInPlace) {
torch::Tensor b = torch::rand(
{4, 4}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor c = torch::empty(
{4, 4}, torch::TensorOptions(torch::kLong).device(DefaultDevice()));
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
c[i][j] = (i + j) % 4;
}
}
for (int dim = 0; dim < 2; ++dim) {
ForEachDevice([&](const torch::Device& device) {
torch::Tensor a = torch::rand(
{4, 4}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor d = a.scatter_add_(dim, c, b);
torch::Tensor lazy_b = CopyToDevice(b, device);
torch::Tensor lazy_c = CopyToDevice(c, device);
torch::Tensor lazy_d = lazy_a.scatter_add_(dim, lazy_c, lazy_b);
AllClose(d, lazy_d);
AllClose(a, lazy_a);
});
}
}
TEST_F(LazyOpsTest, TestIndexSelect) {
for (torch::ScalarType scalar_type :
{torch::kFloat,
torch::kByte,
torch::kChar,
torch::kShort,
torch::kInt,
torch::kLong}) {
torch::Tensor a = isFloatingType(scalar_type)
? torch::rand(
{3, 4}, torch::TensorOptions(scalar_type).device(DefaultDevice()))
: torch::randint(
100,
{3, 4},
torch::TensorOptions(scalar_type).device(DefaultDevice()));
for (torch::ScalarType index_scalar_type : {torch::kInt, torch::kLong}) {
torch::Tensor b = torch::empty(
{2}, torch::TensorOptions(index_scalar_type).device(DefaultDevice()));
b[0] = 0;
b[1] = 2;
for (auto offset : {-2, 0}) {
torch::Tensor c0 = torch::index_select(a, 0 + offset, b);
torch::Tensor c1 = torch::index_select(a, 1 + offset, b);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = CopyToDevice(b, device);
torch::Tensor lazy_c0 =
torch::index_select(lazy_a, 0 + offset, lazy_b);
torch::Tensor lazy_c1 =
torch::index_select(lazy_a, 1 + offset, lazy_b);
AllEqual(c0, lazy_c0);
AllEqual(c1, lazy_c1);
});
}
}
}
}
TEST_F(LazyOpsTest, TestIndexSelectRank0) {
for (torch::ScalarType scalar_type :
{torch::kFloat,
torch::kByte,
torch::kChar,
torch::kShort,
torch::kInt,
torch::kLong}) {
torch::Tensor a = isFloatingType(scalar_type)
? torch::rand(
{3, 4}, torch::TensorOptions(scalar_type).device(DefaultDevice()))
: torch::randint(
100,
{3, 4},
torch::TensorOptions(scalar_type).device(DefaultDevice()));
torch::Tensor b = torch::scalar_tensor(
2, torch::TensorOptions(torch::kLong).device(DefaultDevice()));
torch::Tensor c0 = torch::index_select(a, 0, b);
torch::Tensor c1 = torch::index_select(a, 1, b);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = CopyToDevice(b, device);
torch::Tensor lazy_c0 = torch::index_select(lazy_a, 0, lazy_b);
torch::Tensor lazy_c1 = torch::index_select(lazy_a, 1, lazy_b);
AllEqual(c0, lazy_c0);
AllEqual(c1, lazy_c1);
});
}
}
TEST_F(LazyOpsTest, TestInverse) {
if (IsCuda()) {
// TODO(whc) debug failure on cuda, lazy_b comes back transposed
GTEST_SKIP();
}
torch::Tensor a = torch::randn(
{5, 5}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor b = torch::inverse(a);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = torch::inverse(lazy_a);
AllClose(b, lazy_b, /*rtol=*/1e-3, /*atol=*/1e-4);
});
}
TEST_F(LazyOpsTest, TestIsnan) {
torch::Tensor a = torch::tensor(
{1.0, 2.0, std::nan("1"), 4.0},
torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor b = torch::isnan(a);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = torch::isnan(lazy_a);
AllEqual(b, lazy_b);
});
ExpectCounterNotChanged("aten::.*", GetIgnoredCounters());
ExpectCounterChanged("lazy::isnan", GetIgnoredCounters());
}
TEST_F(LazyOpsTest, TestExpand) {
torch::Tensor a = torch::rand(
{3, 4}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor b = a.expand({2, 3, 4}, /*implicit=*/false);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = lazy_a.expand({2, 3, 4}, /*implicit=*/false);
AllClose(b, lazy_b);
});
}
TEST_F(LazyOpsTest, TestExpandBack) {
torch::Tensor a = torch::rand(
{3, 1}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor b = a.expand({3, 4}, /*implicit=*/false);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = lazy_a.expand({3, 4}, /*implicit=*/false);
AllClose(b, lazy_b);
});
}
TEST_F(LazyOpsTest, TestExpandAs) {
torch::Tensor a = torch::rand(
{3, 4}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor b = torch::rand(
{2, 3, 4}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor c = torch::native::expand_as(a, b);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = CopyToDevice(b, device);
torch::Tensor lazy_c = torch::native::expand_as(lazy_a, lazy_b);
AllClose(c, lazy_c);
});
}
TEST_F(LazyOpsTest, TestEye) {
int n = 5;
ForEachDevice([&](const torch::Device& device) {
torch::Tensor out = torch::eye(
n, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor lazy_out =
torch::eye(n, torch::TensorOptions(torch::kFloat).device(device));
AllClose(out, lazy_out);
});
}
TEST_F(LazyOpsTest, TestEyeWide) {
int lines = 3;
int cols = 5;
ForEachDevice([&](const torch::Device& device) {
torch::Tensor out = torch::eye(
lines,
cols,
torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor lazy_out = torch::eye(
lines, cols, torch::TensorOptions(torch::kFloat).device(device));
AllClose(out, lazy_out);
});
}
TEST_F(LazyOpsTest, TestEyeNarrow) {
int lines = 5;
int cols = 3;
ForEachDevice([&](const torch::Device& device) {
torch::Tensor out = torch::eye(
lines,
cols,
torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor lazy_out = torch::eye(
lines, cols, torch::TensorOptions(torch::kFloat).device(device));
AllClose(out, lazy_out);
});
}
TEST_F(LazyOpsTest, TestBroadcastTensors) {
torch::Tensor a = torch::rand(
{2, 1, 1}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor b = torch::rand(
{2, 1}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
std::vector<torch::Tensor> c = torch::broadcast_tensors({a, b});
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = CopyToDevice(b, device);
std::vector<torch::Tensor> lazy_c =
torch::broadcast_tensors({lazy_a, lazy_b});
ASSERT_EQ(c.size(), lazy_c.size());
for (size_t i = 0; i < c.size(); ++i) {
AllClose(c[i], lazy_c[i]);
}
});
}
TEST_F(LazyOpsTest, TestOneIndex) {
for (torch::ScalarType scalar_type :
{torch::kFloat,
torch::kByte,
torch::kChar,
torch::kShort,
torch::kInt,
torch::kLong}) {
torch::Tensor params = isFloatingType(scalar_type)
? torch::rand(
{4, 3, 5, 6, 7},
torch::TensorOptions(scalar_type).device(DefaultDevice()))
: torch::randint(
100,
{4, 3, 5, 6, 7},
torch::TensorOptions(scalar_type).device(DefaultDevice()));
torch::Tensor indices = torch::randint(
-3,
3,
{2, 4, 3},
torch::TensorOptions(torch::kLong).device(DefaultDevice()));
torch::Tensor result = torch::index(params, {indices});
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_params = CopyToDevice(params, device);
torch::Tensor lazy_indices = CopyToDevice(indices, device);
torch::Tensor lazy_result = torch::index(lazy_params, {lazy_indices});
AllEqual(result, lazy_result);
});
}
}
TEST_F(LazyOpsTest, TestOneIndexTransfer) {
for (torch::ScalarType scalar_type :
{torch::kFloat,
torch::kByte,
torch::kChar,
torch::kShort,
torch::kInt,
torch::kLong}) {
torch::Tensor params = isFloatingType(scalar_type)
? torch::rand(
{4, 3, 5, 6, 7},
torch::TensorOptions(scalar_type).device(DefaultDevice()))
: torch::randint(
100,
{4, 3, 5, 6, 7},
torch::TensorOptions(scalar_type).device(DefaultDevice()));
torch::Tensor indices = torch::randint(
-3,
3,
{2, 4, 3},
torch::TensorOptions(torch::kLong).device(DefaultDevice()));
torch::Tensor result = torch::index(params, {indices});
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_params = CopyToDevice(params, device);
torch::Tensor lazy_result = torch::index(lazy_params, {indices.cpu()});
AllEqual(result, lazy_result);
});
}
}
TEST_F(LazyOpsTest, TestNonzero) {
torch::Tensor a = torch::zeros(
{4, 2}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
a[0][1] = 1.0;
a[1][0] = 2.0;
a[3][1] = 3.0;
torch::Tensor b = torch::nonzero(a);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = torch::nonzero(lazy_a);
AllClose(b, lazy_b);
if (DebugUtil::ExperimentEnabled("nonzero")) {
// If the nonzero support is enabled, we must not see any aten:: calls.
ExpectCounterNotChanged("aten::.*", GetIgnoredCounters());
}
ResetCounters();
});
}
TEST_F(LazyOpsTest, TestMaskedSelect) {
torch::Tensor a = torch::rand(
{3, 5}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor b = torch::randint(
0, 2, {5}, torch::TensorOptions(torch::kBool).device(DefaultDevice()));
torch::Tensor c = torch::masked_select(a, b);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = CopyToDevice(b, device);
torch::Tensor lazy_c = torch::masked_select(lazy_a, lazy_b);
AllClose(c, lazy_c);
if (DebugUtil::ExperimentEnabled("masked_select")) {
// If the masked_select support is enabled, we must not see any aten::
// calls.
ExpectCounterNotChanged("aten::.*", GetIgnoredCounters());
}
ResetCounters();
});
}
TEST_F(LazyOpsTest, TestMaskedScatter) {
torch::Tensor a = torch::rand(
{3, 5}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor b = torch::randint(
0, 2, {3, 5}, torch::TensorOptions(torch::kBool).device(DefaultDevice()));
torch::Tensor c = torch::rand(
{15}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor d = torch::masked_scatter(a, b, c);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = CopyToDevice(b, device);
torch::Tensor lazy_c = CopyToDevice(c, device);
torch::Tensor lazy_d = torch::masked_scatter(lazy_a, lazy_b, lazy_c);
AllClose(d, lazy_d);
if (DebugUtil::ExperimentEnabled("masked_scatter")) {
// If the masked_select support is enabled, we must not see any aten::
// calls.
ExpectCounterNotChanged("aten::.*", GetIgnoredCounters());
}
ResetCounters();
});
}
TEST_F(LazyOpsTest, TestMultiIndexHeadNull) {
for (torch::ScalarType scalar_type :
{torch::kFloat,
torch::kByte,
torch::kChar,
torch::kShort,
torch::kInt,
torch::kLong}) {
torch::Tensor params = isFloatingType(scalar_type)
? torch::rand(
{4, 3, 5, 6, 7},
torch::TensorOptions(scalar_type).device(DefaultDevice()))
: torch::randint(
100,
{4, 3, 5, 6, 7},
torch::TensorOptions(scalar_type).device(DefaultDevice()));
torch::Tensor indices_null;
torch::Tensor indices_0 = torch::randint(
-3,
3,
{2, 4, 3},
torch::TensorOptions(torch::kLong).device(DefaultDevice()));
torch::Tensor indices_1 = torch::randint(
-3,
3,
{2, 4, 3},
torch::TensorOptions(torch::kLong).device(DefaultDevice()));
torch::Tensor result =
torch::index(params, {indices_null, indices_0, indices_1});
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_params = CopyToDevice(params, device);
torch::Tensor lazy_indices_0 = CopyToDevice(indices_0, device);
torch::Tensor lazy_indices_1 = CopyToDevice(indices_1, device);
torch::Tensor lazy_result = torch::index(
lazy_params, {indices_null, lazy_indices_0, lazy_indices_1});
AllEqual(result, lazy_result);
});
}
}
TEST_F(LazyOpsTest, TestMultiIndexMiddleNull) {
for (torch::ScalarType scalar_type :
{torch::kFloat,
torch::kByte,
torch::kChar,
torch::kShort,
torch::kInt,
torch::kLong}) {
torch::Tensor params = isFloatingType(scalar_type)
? torch::rand(
{4, 3, 5, 6, 7},
torch::TensorOptions(scalar_type).device(DefaultDevice()))
: torch::randint(
100,
{4, 3, 5, 6, 7},
torch::TensorOptions(scalar_type).device(DefaultDevice()));
torch::Tensor indices_0 = torch::randint(
-3,
3,
{2, 4, 3},
torch::TensorOptions(torch::kLong).device(DefaultDevice()));
torch::Tensor indices_null;
torch::Tensor indices_1 = torch::randint(
-3,
3,
{2, 4, 3},
torch::TensorOptions(torch::kLong).device(DefaultDevice()));
torch::Tensor result =
torch::index(params, {indices_0, indices_null, indices_1});
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_params = CopyToDevice(params, device);
torch::Tensor lazy_indices_0 = CopyToDevice(indices_0, device);
torch::Tensor lazy_indices_1 = CopyToDevice(indices_1, device);
torch::Tensor lazy_result = torch::index(
lazy_params, {lazy_indices_0, indices_null, lazy_indices_1});
AllEqual(result, lazy_result);
});
}
}
TEST_F(LazyOpsTest, TestMultiIndexTailNull) {
for (torch::ScalarType scalar_type :
{torch::kFloat,
torch::kByte,
torch::kChar,
torch::kShort,
torch::kInt,
torch::kLong}) {
torch::Tensor params = isFloatingType(scalar_type)
? torch::rand(
{4, 3, 5, 6, 7},
torch::TensorOptions(scalar_type).device(DefaultDevice()))
: torch::randint(
100,
{4, 3, 5, 6, 7},
torch::TensorOptions(scalar_type).device(DefaultDevice()));
torch::Tensor indices_0 = torch::randint(
-3,
3,
{2, 4, 3},
torch::TensorOptions(torch::kLong).device(DefaultDevice()));
torch::Tensor indices_null;
torch::Tensor indices_1 = torch::randint(
-3,
3,
{2, 4, 3},
torch::TensorOptions(torch::kLong).device(DefaultDevice()));
torch::Tensor result =
torch::index(params, {indices_0, indices_1, indices_null});
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_params = CopyToDevice(params, device);
torch::Tensor lazy_indices_0 = CopyToDevice(indices_0, device);
torch::Tensor lazy_indices_1 = CopyToDevice(indices_1, device);
torch::Tensor lazy_result = torch::index(
lazy_params, {lazy_indices_0, lazy_indices_1, indices_null});
AllEqual(result, lazy_result);
});
}
}
TEST_F(LazyOpsTest, TestMultiIndexMiddleBroadcast) {
for (torch::ScalarType scalar_type :
{torch::kFloat,
torch::kByte,
torch::kChar,
torch::kShort,
torch::kInt,
torch::kLong}) {
torch::Tensor params = isFloatingType(scalar_type)
? torch::rand(
{4, 3, 5, 6, 7},
torch::TensorOptions(scalar_type).device(DefaultDevice()))
: torch::randint(
100,
{4, 3, 5, 6, 7},
torch::TensorOptions(scalar_type).device(DefaultDevice()));
torch::Tensor indices_0 = torch::randint(
-3,
3,
{2, 4, 3},
torch::TensorOptions(torch::kLong).device(DefaultDevice()));
torch::Tensor indices_1 = torch::randint(
-3,
3,
{2, 1, 3},
torch::TensorOptions(torch::kLong).device(DefaultDevice()));
torch::Tensor result = torch::index(params, {indices_0, indices_1});
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_params = CopyToDevice(params, device);
torch::Tensor lazy_indices_0 = CopyToDevice(indices_0, device);
torch::Tensor lazy_indices_1 = CopyToDevice(indices_1, device);
torch::Tensor lazy_result =
torch::index(lazy_params, {lazy_indices_0, lazy_indices_1});
AllEqual(result, lazy_result);
});
}
}
TEST_F(LazyOpsTest, TestMultiIndexTailBroadcast) {
for (torch::ScalarType scalar_type :
{torch::kFloat,
torch::kByte,
torch::kChar,
torch::kShort,
torch::kInt,
torch::kLong}) {
torch::Tensor params = isFloatingType(scalar_type)
? torch::rand(
{4, 3, 5, 6, 7},
torch::TensorOptions(scalar_type).device(DefaultDevice()))
: torch::randint(
100,
{4, 3, 5, 6, 7},
torch::TensorOptions(scalar_type).device(DefaultDevice()));
torch::Tensor indices_0 = torch::randint(
-3,
3,
{2, 1, 3},
torch::TensorOptions(torch::kLong).device(DefaultDevice()));
torch::Tensor indices_1 = torch::randint(
-3,
3,
{2, 1},
torch::TensorOptions(torch::kLong).device(DefaultDevice()));
torch::Tensor result = torch::index(params, {indices_0, indices_1});
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_params = CopyToDevice(params, device);
torch::Tensor lazy_indices_0 = CopyToDevice(indices_0, device);
torch::Tensor lazy_indices_1 = CopyToDevice(indices_1, device);
torch::Tensor lazy_result =
torch::index(lazy_params, {lazy_indices_0, lazy_indices_1});
AllEqual(result, lazy_result);
});
}
}
TEST_F(LazyOpsTest, TestMaskIndex) {
for (torch::ScalarType scalar_type :
{torch::kFloat,
torch::kByte,
torch::kChar,
torch::kShort,
torch::kInt,
torch::kLong}) {
torch::Tensor params = isFloatingType(scalar_type)
? torch::rand(
{2, 2}, torch::TensorOptions(scalar_type).device(DefaultDevice()))
: torch::randint(
100,
{2, 2},
torch::TensorOptions(scalar_type).device(DefaultDevice()));
torch::Tensor indices = torch::randint(
0,
2,
{2, 2},
torch::TensorOptions(torch::kBool).device(DefaultDevice()));
torch::Tensor result = torch::index(params, {indices});
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_params = CopyToDevice(params, device);
torch::Tensor lazy_indices = CopyToDevice(indices, device);
torch::Tensor lazy_result = torch::index(lazy_params, {lazy_indices});
AllEqual(result, lazy_result);
});
}
}
TEST_F(LazyOpsTest, TestOneIndexPut) {
for (torch::ScalarType scalar_type :
{torch::kFloat,
torch::kByte,
torch::kChar,
torch::kShort,
torch::kInt,
torch::kLong}) {
torch::Tensor params = isFloatingType(scalar_type)
? torch::rand(
{4, 3, 5, 6, 7},
torch::TensorOptions(scalar_type).device(DefaultDevice()))
: torch::randint(
100,
{4, 3, 5, 6, 7},
torch::TensorOptions(scalar_type).device(DefaultDevice()));
torch::Tensor indices = torch::randint(
-3,
3,
{2, 4, 3},
torch::TensorOptions(torch::kLong).device(DefaultDevice()));
torch::Tensor values = isFloatingType(scalar_type)
? torch::rand(
{3, 5, 6, 7},
torch::TensorOptions(scalar_type).device(DefaultDevice()))
: torch::randint(
100,
{3, 5, 6, 7},
torch::TensorOptions(scalar_type).device(DefaultDevice()));
for (bool accumulate : {false, true}) {
if (accumulate && IsCuda()) {
GTEST_SKIP();
}
torch::Tensor result =
torch::index_put(params, {indices}, values, accumulate);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_params = CopyToDevice(params, device);
torch::Tensor lazy_indices = CopyToDevice(indices, device);
torch::Tensor lazy_values = CopyToDevice(values, device);
torch::Tensor lazy_result = torch::index_put(
lazy_params, {lazy_indices}, lazy_values, accumulate);
AllEqual(result, lazy_result);
});
}
}
}
TEST_F(LazyOpsTest, TestOneIndexPutInPlace) {
torch::Tensor indices = torch::randint(
-3,
3,
{2, 4, 3},
torch::TensorOptions(torch::kLong).device(DefaultDevice()));
for (torch::ScalarType scalar_type :
{torch::kFloat,
torch::kByte,
torch::kChar,
torch::kShort,
torch::kInt,
torch::kLong}) {
torch::Tensor values = torch::ones(
{3, 5, 6, 7},
torch::TensorOptions(scalar_type).device(DefaultDevice()));
for (bool accumulate : {false, true}) {
if (accumulate && IsCuda()) {
GTEST_SKIP();
}
ForEachDevice([&](const torch::Device& device) {
torch::Tensor params = isFloatingType(scalar_type)
? torch::rand(
{4, 3, 5, 6, 7},
torch::TensorOptions(scalar_type).device(DefaultDevice()))
: torch::randint(
100,
{4, 3, 5, 6, 7},
torch::TensorOptions(scalar_type).device(DefaultDevice()));
torch::Tensor lazy_params = CopyToDevice(params.clone(), device);
torch::Tensor result =
torch::index_put_(params, {indices}, values, accumulate);
torch::Tensor lazy_indices = CopyToDevice(indices, device);
torch::Tensor lazy_values = CopyToDevice(values, device);
torch::Tensor lazy_result = torch::index_put_(
lazy_params, {lazy_indices}, lazy_values, accumulate);
AllEqual(result, lazy_result);
AllEqual(params, lazy_params);
});
}
}
}
TEST_F(LazyOpsTest, TestOneIndexPutTransfer) {
torch::Tensor indices = torch::randint(
-3,
3,
{2, 4, 3},
torch::TensorOptions(torch::kLong).device(DefaultDevice()));
for (torch::ScalarType scalar_type :
{torch::kFloat,
torch::kByte,
torch::kChar,
torch::kShort,
torch::kInt,
torch::kLong}) {
torch::Tensor params = isFloatingType(scalar_type)
? torch::rand(
{4, 3, 5, 6, 7},
torch::TensorOptions(scalar_type).device(DefaultDevice()))
: torch::randint(
100,
{4, 3, 5, 6, 7},
torch::TensorOptions(scalar_type).device(DefaultDevice()));
torch::Tensor values = torch::ones(
{3, 5, 6, 7},
torch::TensorOptions(scalar_type).device(DefaultDevice()));
for (bool accumulate : {false, true}) {
if (accumulate && IsCuda()) {
GTEST_SKIP();
}
torch::Tensor result =
torch::index_put(params, {indices}, values, accumulate);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_params = CopyToDevice(params, device);
torch::Tensor lazy_values = CopyToDevice(values, device);
torch::Tensor lazy_result =
torch::index_put(lazy_params, {indices}, lazy_values, accumulate);
AllEqual(result, lazy_result);
});
}
}
}
TEST_F(LazyOpsTest, TestMultiIndexPut) {
torch::Tensor indices_0 = torch::randint(
-3,
3,
{2, 4, 3},
torch::TensorOptions(torch::kLong).device(DefaultDevice()));
torch::Tensor indices_1 = torch::randint(
-3,
3,
{2, 4, 3},
torch::TensorOptions(torch::kLong).device(DefaultDevice()));
for (torch::ScalarType scalar_type :
{torch::kFloat,
torch::kByte,
torch::kChar,
torch::kShort,
torch::kInt,
torch::kLong}) {
torch::Tensor params = isFloatingType(scalar_type)
? torch::rand(
{4, 3, 5, 6, 7},
torch::TensorOptions(scalar_type).device(DefaultDevice()))
: torch::randint(
100,
{4, 3, 5, 6, 7},
torch::TensorOptions(scalar_type).device(DefaultDevice()));
torch::Tensor values = torch::ones(
{5, 6, 7}, torch::TensorOptions(scalar_type).device(DefaultDevice()));
for (bool accumulate : {false, true}) {
if (accumulate && IsCuda()) {
GTEST_SKIP();
}
torch::Tensor result =
torch::index_put(params, {indices_0, indices_1}, values, accumulate);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_params = CopyToDevice(params, device);
torch::Tensor lazy_indices_0 = CopyToDevice(indices_0, device);
torch::Tensor lazy_indices_1 = CopyToDevice(indices_1, device);
torch::Tensor lazy_values = CopyToDevice(values, device);
torch::Tensor lazy_result = torch::index_put(
lazy_params,
{lazy_indices_0, lazy_indices_1},
lazy_values,
accumulate);
AllEqual(result, lazy_result);
});
}
}
}
TEST_F(LazyOpsTest, TestMultiIndexPutHeadNull) {
torch::Tensor indices_0 = torch::randint(
-3,
3,
{2, 4, 3},
torch::TensorOptions(torch::kLong).device(DefaultDevice()));
torch::Tensor indices_null;
torch::Tensor indices_1 = torch::randint(
-3,
3,
{2, 4, 3},
torch::TensorOptions(torch::kLong).device(DefaultDevice()));
for (torch::ScalarType scalar_type :
{torch::kFloat,
torch::kByte,
torch::kChar,
torch::kShort,
torch::kInt,
torch::kLong}) {
torch::Tensor params = isFloatingType(scalar_type)
? torch::rand(
{4, 3, 3, 6, 7},
torch::TensorOptions(scalar_type).device(DefaultDevice()))
: torch::randint(
100,
{4, 3, 3, 6, 7},
torch::TensorOptions(scalar_type).device(DefaultDevice()));
torch::Tensor values = torch::ones(
{3, 6, 7}, torch::TensorOptions(scalar_type).device(DefaultDevice()));
for (bool accumulate : {false, true}) {
if (accumulate && IsCuda()) {
GTEST_SKIP();
}
torch::Tensor result = torch::index_put(
params, {indices_null, indices_0, indices_1}, values, accumulate);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_params = CopyToDevice(params, device);
torch::Tensor lazy_indices_0 = CopyToDevice(indices_0, device);
torch::Tensor lazy_indices_1 = CopyToDevice(indices_1, device);
torch::Tensor lazy_values = CopyToDevice(values, device);
torch::Tensor lazy_result = torch::index_put(
lazy_params,
{indices_null, lazy_indices_0, lazy_indices_1},
lazy_values,
accumulate);
AllEqual(result, lazy_result);
});
}
}
}
TEST_F(LazyOpsTest, TestMultiIndexPutMiddleNull) {
torch::Tensor indices_0 = torch::randint(
-3,
3,
{2, 4, 3},
torch::TensorOptions(torch::kLong).device(DefaultDevice()));
torch::Tensor indices_null;
torch::Tensor indices_1 = torch::randint(
-3,
3,
{2, 4, 3},
torch::TensorOptions(torch::kLong).device(DefaultDevice()));
for (torch::ScalarType scalar_type :
{torch::kFloat,
torch::kByte,
torch::kChar,
torch::kShort,
torch::kInt,
torch::kLong}) {
torch::Tensor params = isFloatingType(scalar_type)
? torch::rand(
{4, 3, 3, 6, 7},
torch::TensorOptions(scalar_type).device(DefaultDevice()))
: torch::randint(
100,
{4, 3, 3, 6, 7},
torch::TensorOptions(scalar_type).device(DefaultDevice()));
torch::Tensor values = torch::ones(
{3, 6, 7}, torch::TensorOptions(scalar_type).device(DefaultDevice()));
for (bool accumulate : {false, true}) {
if (accumulate && IsCuda()) {
GTEST_SKIP();
}
torch::Tensor result = torch::index_put(
params, {indices_0, indices_null, indices_1}, values, accumulate);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_params = CopyToDevice(params, device);
torch::Tensor lazy_indices_0 = CopyToDevice(indices_0, device);
torch::Tensor lazy_indices_1 = CopyToDevice(indices_1, device);
torch::Tensor lazy_values = CopyToDevice(values, device);
torch::Tensor lazy_result = torch::index_put(
lazy_params,
{lazy_indices_0, indices_null, lazy_indices_1},
lazy_values,
accumulate);
AllEqual(result, lazy_result);
});
}
}
}
TEST_F(LazyOpsTest, TestMultiIndexPutTailNull) {
torch::Tensor indices_0 = torch::randint(
-3,
3,
{2, 4, 3},
torch::TensorOptions(torch::kLong).device(DefaultDevice()));
torch::Tensor indices_1 = torch::randint(
-3,
3,
{2, 4, 3},
torch::TensorOptions(torch::kLong).device(DefaultDevice()));
torch::Tensor indices_null;
for (torch::ScalarType scalar_type :
{torch::kFloat,
torch::kByte,
torch::kChar,
torch::kShort,
torch::kInt,
torch::kLong}) {
torch::Tensor params = isFloatingType(scalar_type)
? torch::rand(
{4, 3, 3, 6, 7},
torch::TensorOptions(scalar_type).device(DefaultDevice()))
: torch::randint(
100,
{4, 3, 3, 6, 7},
torch::TensorOptions(scalar_type).device(DefaultDevice()));
torch::Tensor values = torch::ones(
{3, 6, 7}, torch::TensorOptions(scalar_type).device(DefaultDevice()));
for (bool accumulate : {false, true}) {
if (accumulate && IsCuda()) {
GTEST_SKIP();
}
torch::Tensor result = torch::index_put(
params, {indices_0, indices_1, indices_null}, values, accumulate);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_params = CopyToDevice(params, device);
torch::Tensor lazy_indices_0 = CopyToDevice(indices_0, device);
torch::Tensor lazy_indices_1 = CopyToDevice(indices_1, device);
torch::Tensor lazy_values = CopyToDevice(values, device);
torch::Tensor lazy_result = torch::index_put(
lazy_params,
{lazy_indices_0, lazy_indices_1, indices_null},
lazy_values,
accumulate);
AllEqual(result, lazy_result);
});
}
}
}
TEST_F(LazyOpsTest, TestMultiIndexPutMiddleBroadcast) {
torch::Tensor indices_0 = torch::randint(
-3,
3,
{2, 4, 3},
torch::TensorOptions(torch::kLong).device(DefaultDevice()));
torch::Tensor indices_1 = torch::randint(
-3,
3,
{2, 1, 3},
torch::TensorOptions(torch::kLong).device(DefaultDevice()));
for (torch::ScalarType scalar_type :
{torch::kFloat,
torch::kByte,
torch::kChar,
torch::kShort,
torch::kInt,
torch::kLong}) {
torch::Tensor params = isFloatingType(scalar_type)
? torch::rand(
{4, 3, 5, 6, 7},
torch::TensorOptions(scalar_type).device(DefaultDevice()))
: torch::randint(
100,
{4, 3, 5, 6, 7},
torch::TensorOptions(scalar_type).device(DefaultDevice()));
torch::Tensor values = torch::ones(
{5, 6, 7}, torch::TensorOptions(scalar_type).device(DefaultDevice()));
for (bool accumulate : {false, true}) {
if (accumulate && IsCuda()) {
GTEST_SKIP();
}
torch::Tensor result =
torch::index_put(params, {indices_0, indices_1}, values, accumulate);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_params = CopyToDevice(params, device);
torch::Tensor lazy_indices_0 = CopyToDevice(indices_0, device);
torch::Tensor lazy_indices_1 = CopyToDevice(indices_1, device);
torch::Tensor lazy_values = CopyToDevice(values, device);
torch::Tensor lazy_result = torch::index_put(
lazy_params,
{lazy_indices_0, lazy_indices_1},
lazy_values,
accumulate);
AllEqual(result, lazy_result);
});
}
}
}
TEST_F(LazyOpsTest, TestMultiIndexPutTailBroadcast) {
torch::Tensor indices_0 = torch::randint(
-3,
3,
{2, 1, 3},
torch::TensorOptions(torch::kLong).device(DefaultDevice()));
torch::Tensor indices_1 = torch::randint(
-3,
3,
{2, 1},
torch::TensorOptions(torch::kLong).device(DefaultDevice()));
for (torch::ScalarType scalar_type :
{torch::kFloat,
torch::kByte,
torch::kChar,
torch::kShort,
torch::kInt,
torch::kLong}) {
torch::Tensor params = isFloatingType(scalar_type)
? torch::rand(
{4, 3, 5, 6, 7},
torch::TensorOptions(scalar_type).device(DefaultDevice()))
: torch::randint(
100,
{4, 3, 5, 6, 7},
torch::TensorOptions(scalar_type).device(DefaultDevice()));
torch::Tensor values = torch::ones(
{5, 6, 7}, torch::TensorOptions(scalar_type).device(DefaultDevice()));
for (bool accumulate : {false, true}) {
if (accumulate && IsCuda()) {
GTEST_SKIP();
}
torch::Tensor result =
torch::index_put(params, {indices_0, indices_1}, values, accumulate);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_params = CopyToDevice(params, device);
torch::Tensor lazy_indices_0 = CopyToDevice(indices_0, device);
torch::Tensor lazy_indices_1 = CopyToDevice(indices_1, device);
torch::Tensor lazy_values = CopyToDevice(values, device);
torch::Tensor lazy_result = torch::index_put(
lazy_params,
{lazy_indices_0, lazy_indices_1},
lazy_values,
accumulate);
AllEqual(result, lazy_result);
});
}
}
}
TEST_F(LazyOpsTest, TestMaskIndexPut) {
torch::Tensor indices =
torch::tensor(
{0, 1}, torch::TensorOptions(torch::kByte).device(DefaultDevice()))
.to(torch::kBool);
for (torch::ScalarType scalar_type :
{torch::kFloat,
torch::kByte,
torch::kChar,
torch::kShort,
torch::kInt,
torch::kLong}) {
torch::Tensor params = isFloatingType(scalar_type)
? torch::rand(
{2, 2}, torch::TensorOptions(scalar_type).device(DefaultDevice()))
: torch::randint(
100,
{2, 2},
torch::TensorOptions(scalar_type).device(DefaultDevice()));
torch::Tensor values = torch::ones(
{2}, torch::TensorOptions(scalar_type).device(DefaultDevice()));
for (bool accumulate : {false, true}) {
torch::Tensor result =
torch::index_put(params, {indices}, values, accumulate);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_params = CopyToDevice(params, device);
torch::Tensor lazy_indices = CopyToDevice(indices, device);
torch::Tensor lazy_values = CopyToDevice(values, device);
torch::Tensor lazy_result = torch::index_put(
lazy_params, {lazy_indices}, lazy_values, accumulate);
AllEqual(result, lazy_result);
});
}
}
}
TEST_F(LazyOpsTest, TestIndexPutImpl) {
torch::Tensor indices = torch::randint(
-3,
3,
{2, 4, 3},
torch::TensorOptions(torch::kLong).device(DefaultDevice()));
for (torch::ScalarType scalar_type :
{torch::kFloat,
torch::kByte,
torch::kChar,
torch::kShort,
torch::kInt,
torch::kLong}) {
torch::Tensor values = torch::ones(
{3, 5, 6, 7},
torch::TensorOptions(scalar_type).device(DefaultDevice()));
for (bool accumulate : {false, true}) {
if (accumulate && IsCuda()) {
GTEST_SKIP();
}
ForEachDevice([&](const torch::Device& device) {
torch::Tensor params = isFloatingType(scalar_type)
? torch::rand(
{4, 3, 5, 6, 7},
torch::TensorOptions(scalar_type).device(DefaultDevice()))
: torch::randint(
100,
{4, 3, 5, 6, 7},
torch::TensorOptions(scalar_type).device(DefaultDevice()));
torch::Tensor lazy_params = CopyToDevice(params.clone(), device);
torch::Tensor result = torch::_index_put_impl_(
params, {indices}, values, accumulate, /*unsafe=*/true);
torch::Tensor lazy_indices = CopyToDevice(indices, device);
torch::Tensor lazy_values = CopyToDevice(values, device);
torch::Tensor lazy_result = torch::_index_put_impl_(
lazy_params,
{lazy_indices},
lazy_values,
accumulate,
/*unsafe=*/true);
AllEqual(result, lazy_result);
AllEqual(params, lazy_params);
});
}
}
}
TEST_F(LazyOpsTest, TestIndexFillWithScalar) {
torch::Tensor index = torch::tensor(
{0, 2}, torch::TensorOptions(torch::kLong).device(DefaultDevice()));
torch::Scalar value = 42;
for (torch::ScalarType scalar_type :
{torch::kFloat,
torch::kByte,
torch::kChar,
torch::kShort,
torch::kInt,
torch::kLong}) {
torch::Tensor base = isFloatingType(scalar_type)
? torch::rand(
{3, 4, 5},
torch::TensorOptions(scalar_type).device(DefaultDevice()))
: torch::randint(
100,
{3, 4, 5},
torch::TensorOptions(scalar_type).device(DefaultDevice()));
int rank = base.dim();
for (int dim = -rank; dim < rank; ++dim) {
torch::Tensor result = torch::index_fill(base, dim, index, value);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_base = CopyToDevice(base, device);
torch::Tensor lazy_index = CopyToDevice(index, device);
torch::Tensor lazy_result =
torch::index_fill(lazy_base, dim, lazy_index, value);
AllEqual(result, lazy_result);
});
}
}
}
TEST_F(LazyOpsTest, TestIndexFillWithScalarInPlace) {
torch::Tensor index = torch::tensor(
{0, 2}, torch::TensorOptions(torch::kLong).device(DefaultDevice()));
torch::Scalar value = 42;
int rank = 3;
for (torch::ScalarType scalar_type :
{torch::kFloat,
torch::kByte,
torch::kChar,
torch::kShort,
torch::kInt,
torch::kLong}) {
for (int dim = -rank; dim < rank; ++dim) {
ForEachDevice([&](const torch::Device& device) {
torch::Tensor base = isFloatingType(scalar_type)
? torch::rand(
{3, 4, 5},
torch::TensorOptions(scalar_type).device(DefaultDevice()))
: torch::randint(
100,
{3, 4, 5},
torch::TensorOptions(scalar_type).device(DefaultDevice()));
torch::Tensor lazy_base = CopyToDevice(base.clone(), device);
torch::Tensor result = base.index_fill_(dim, index, value);
torch::Tensor lazy_index = CopyToDevice(index, device);
torch::Tensor lazy_result =
lazy_base.index_fill_(dim, lazy_index, value);
AllEqual(result, lazy_result);
AllEqual(base, lazy_base);
});
}
}
}
TEST_F(LazyOpsTest, TestIndexFillWithTensor) {
torch::Tensor index = torch::tensor(
{0, 2}, torch::TensorOptions(torch::kLong).device(DefaultDevice()));
for (torch::ScalarType scalar_type :
{torch::kFloat,
torch::kByte,
torch::kChar,
torch::kShort,
torch::kInt,
torch::kLong}) {
torch::Tensor base = isFloatingType(scalar_type)
? torch::rand(
{3, 4, 5},
torch::TensorOptions(scalar_type).device(DefaultDevice()))
: torch::randint(
100,
{3, 4, 5},
torch::TensorOptions(scalar_type).device(DefaultDevice()));
torch::Tensor value = torch::scalar_tensor(
42, torch::TensorOptions(scalar_type).device(DefaultDevice()));
int rank = base.dim();
for (int dim = -rank; dim < rank; ++dim) {
torch::Tensor result = torch::index_fill(base, dim, index, value);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_base = CopyToDevice(base, device);
torch::Tensor lazy_index = CopyToDevice(index, device);
torch::Tensor lazy_value = CopyToDevice(value, device);
torch::Tensor lazy_result =
torch::index_fill(lazy_base, dim, lazy_index, lazy_value);
AllEqual(result, lazy_result);
});
}
}
}
TEST_F(LazyOpsTest, TestIndexFillWithTensorInPlace) {
torch::Tensor index = torch::tensor(
{0, 2}, torch::TensorOptions(torch::kLong).device(DefaultDevice()));
for (torch::ScalarType scalar_type :
{torch::kFloat,
torch::kByte,
torch::kChar,
torch::kShort,
torch::kInt,
torch::kLong}) {
torch::Tensor value = torch::scalar_tensor(
42, torch::TensorOptions(scalar_type).device(DefaultDevice()));
int rank = 3;
for (int dim = -rank; dim < rank; ++dim) {
ForEachDevice([&](const torch::Device& device) {
torch::Tensor base = isFloatingType(scalar_type)
? torch::rand(
{3, 4, 5},
torch::TensorOptions(scalar_type).device(DefaultDevice()))
: torch::randint(
100,
{3, 4, 5},
torch::TensorOptions(scalar_type).device(DefaultDevice()));
torch::Tensor lazy_base = CopyToDevice(base.clone(), device);
torch::Tensor result = base.index_fill_(dim, index, value);
torch::Tensor lazy_index = CopyToDevice(index, device);
torch::Tensor lazy_value = CopyToDevice(value, device);
torch::Tensor lazy_result =
lazy_base.index_fill_(dim, lazy_index, lazy_value);
AllEqual(result, lazy_result);
AllEqual(base, lazy_base);
});
}
}
}
TEST_F(LazyOpsTest, TestIndexFillRank0) {
torch::Tensor index = torch::scalar_tensor(
2, torch::TensorOptions(torch::kLong).device(DefaultDevice()));
for (torch::ScalarType scalar_type :
{torch::kFloat,
torch::kByte,
torch::kChar,
torch::kShort,
torch::kInt,
torch::kLong}) {
torch::Tensor base = isFloatingType(scalar_type)
? torch::rand(
{3, 4, 5},
torch::TensorOptions(scalar_type).device(DefaultDevice()))
: torch::randint(
100,
{3, 4, 5},
torch::TensorOptions(scalar_type).device(DefaultDevice()));
torch::Tensor value = torch::scalar_tensor(
42, torch::TensorOptions(scalar_type).device(DefaultDevice()));
int rank = base.dim();
for (int dim = -rank; dim < rank; ++dim) {
torch::Tensor result = torch::index_fill(base, dim, index, value);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_base = CopyToDevice(base, device);
torch::Tensor lazy_index = CopyToDevice(index, device);
torch::Tensor lazy_value = CopyToDevice(value, device);
torch::Tensor lazy_result =
torch::index_fill(lazy_base, dim, lazy_index, lazy_value);
AllEqual(result, lazy_result);
});
}
}
}
TEST_F(LazyOpsTest, TestIndexAdd) {
int index_size = 10;
for (torch::ScalarType scalar_type :
{torch::kFloat,
torch::kByte,
torch::kChar,
torch::kShort,
torch::kInt,
torch::kLong}) {
torch::Tensor base = isFloatingType(scalar_type)
? torch::rand(
{5, 3, 7},
torch::TensorOptions(scalar_type).device(DefaultDevice()))
: torch::randint(
100,
{5, 3, 7},
torch::TensorOptions(scalar_type).device(DefaultDevice()));
int rank = base.dim();
for (int dim = -rank; dim < rank; ++dim) {
for (torch::ScalarType index_scalar_type : {torch::kInt, torch::kLong}) {
torch::Tensor index = torch::randint(
0,
base.size(dim),
{index_size},
torch::TensorOptions(index_scalar_type).device(DefaultDevice()));
std::vector<int64_t> value_sizes(
base.sizes().begin(), base.sizes().end());
int canonical_dim = dim < 0 ? dim + rank : dim;
value_sizes[canonical_dim] = index_size;
torch::Tensor value = isFloatingType(scalar_type)
? torch::rand(
value_sizes,
torch::TensorOptions(scalar_type).device(DefaultDevice()))
: torch::randint(
100,
value_sizes,
torch::TensorOptions(scalar_type).device(DefaultDevice()));
torch::Tensor result = torch::index_add(base, dim, index, value);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_base = CopyToDevice(base, device);
torch::Tensor lazy_index = CopyToDevice(index, device);
torch::Tensor lazy_value = CopyToDevice(value, device);
torch::Tensor lazy_result =
torch::index_add(lazy_base, dim, lazy_index, lazy_value);
AllClose(result, lazy_result);
});
}
}
}
}
TEST_F(LazyOpsTest, TestIndexAddInPlace) {
int index_size = 10;
int rank = 3;
for (torch::ScalarType scalar_type :
{torch::kFloat,
torch::kByte,
torch::kChar,
torch::kShort,
torch::kInt,
torch::kLong}) {
for (int dim = -rank; dim < rank; ++dim) {
ForEachDevice([&](const torch::Device& device) {
torch::Tensor base = isFloatingType(scalar_type)
? torch::rand(
{5, 3, 7},
torch::TensorOptions(scalar_type).device(DefaultDevice()))
: torch::randint(
100,
{5, 3, 7},
torch::TensorOptions(scalar_type).device(DefaultDevice()));
torch::Tensor index = torch::randint(
0,
base.size(dim),
{index_size},
torch::TensorOptions(torch::kLong).device(DefaultDevice()));
std::vector<int64_t> value_sizes(
base.sizes().begin(), base.sizes().end());
int canonical_dim = dim < 0 ? dim + rank : dim;
value_sizes[canonical_dim] = index_size;
torch::Tensor value = isFloatingType(scalar_type)
? torch::rand(
value_sizes,
torch::TensorOptions(scalar_type).device(DefaultDevice()))
: torch::randint(
100,
value_sizes,
torch::TensorOptions(scalar_type).device(DefaultDevice()));
torch::Tensor lazy_base = CopyToDevice(base.clone(), device);
torch::Tensor result = base.index_add_(dim, index, value);
torch::Tensor lazy_index = CopyToDevice(index, device);
torch::Tensor lazy_value = CopyToDevice(value, device);
torch::Tensor lazy_result =
lazy_base.index_add_(dim, lazy_index, lazy_value);
AllClose(result, lazy_result);
AllClose(base, lazy_base);
});
}
}
}
TEST_F(LazyOpsTest, TestIndexAddRank0) {
for (torch::ScalarType scalar_type :
{torch::kFloat,
torch::kByte,
torch::kChar,
torch::kShort,
torch::kInt,
torch::kLong}) {
torch::Tensor base = isFloatingType(scalar_type)
? torch::rand(
{5, 3, 7},
torch::TensorOptions(scalar_type).device(DefaultDevice()))
: torch::randint(
100,
{5, 3, 7},
torch::TensorOptions(scalar_type).device(DefaultDevice()));
int rank = base.dim();
for (int dim = -rank; dim < rank; ++dim) {
torch::Tensor index = torch::randint(
0,
base.size(dim),
at::IntArrayRef{},
torch::TensorOptions(torch::kLong).device(DefaultDevice()));
std::vector<int64_t> value_sizes(
base.sizes().begin(), base.sizes().end());
int canonical_dim = dim < 0 ? dim + rank : dim;
value_sizes[canonical_dim] = 1;
torch::Tensor value = isFloatingType(scalar_type)
? torch::rand(
value_sizes,
torch::TensorOptions(scalar_type).device(DefaultDevice()))
: torch::randint(
100,
value_sizes,
torch::TensorOptions(scalar_type).device(DefaultDevice()));
torch::Tensor result = torch::index_add(base, dim, index, value);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_base = CopyToDevice(base, device);
torch::Tensor lazy_index = CopyToDevice(index, device);
torch::Tensor lazy_value = CopyToDevice(value, device);
torch::Tensor lazy_result =
torch::index_add(lazy_base, dim, lazy_index, lazy_value);
AllEqual(result, lazy_result);
});
}
}
}
TEST_F(LazyOpsTest, TestIndexCopy) {
for (torch::ScalarType scalar_type :
{torch::kFloat,
torch::kByte,
torch::kChar,
torch::kShort,
torch::kInt,
torch::kLong}) {
torch::Tensor base = isFloatingType(scalar_type)
? torch::rand(
{5, 3, 7},
torch::TensorOptions(scalar_type).device(DefaultDevice()))
: torch::randint(
100,
{5, 3, 7},
torch::TensorOptions(scalar_type).device(DefaultDevice()));
int rank = base.dim();
for (int dim = -rank; dim < rank; ++dim) {
torch::Tensor index = torch::randperm(
base.size(dim),
torch::TensorOptions(torch::kLong).device(DefaultDevice()));
torch::Tensor value = isFloatingType(scalar_type)
? torch::rand(
base.sizes(),
torch::TensorOptions(scalar_type).device(DefaultDevice()))
: torch::randint(
100,
base.sizes(),
torch::TensorOptions(scalar_type).device(DefaultDevice()));
torch::Tensor result = torch::index_copy(base, dim, index, value);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_base = CopyToDevice(base, device);
torch::Tensor lazy_index = CopyToDevice(index, device);
torch::Tensor lazy_value = CopyToDevice(value, device);
torch::Tensor lazy_result =
torch::index_copy(lazy_base, dim, lazy_index, lazy_value);
AllEqual(result, lazy_result);
});
}
}
}
TEST_F(LazyOpsTest, TestIndexCopyInPlace) {
if (IsCuda()) {
GTEST_SKIP();
}
int index_size = 10;
int rank = 3;
for (torch::ScalarType scalar_type :
{torch::kFloat,
torch::kByte,
torch::kChar,
torch::kShort,
torch::kInt,
torch::kLong}) {
for (int dim = -rank; dim < rank; ++dim) {
ForEachDevice([&](const torch::Device& device) {
torch::Tensor base = isFloatingType(scalar_type)
? torch::rand(
{5, 3, 7},
torch::TensorOptions(scalar_type).device(DefaultDevice()))
: torch::randint(
100,
{5, 3, 7},
torch::TensorOptions(scalar_type).device(DefaultDevice()));
torch::Tensor index = torch::randint(
0,
base.size(dim),
{index_size},
torch::TensorOptions(torch::kLong).device(DefaultDevice()));
std::vector<int64_t> value_sizes(
base.sizes().begin(), base.sizes().end());
int canonical_dim = dim < 0 ? dim + rank : dim;
value_sizes[canonical_dim] = index_size;
torch::Tensor value = isFloatingType(scalar_type)
? torch::rand(
value_sizes,
torch::TensorOptions(scalar_type).device(DefaultDevice()))
: torch::randint(
100,
value_sizes,
torch::TensorOptions(scalar_type).device(DefaultDevice()));
torch::Tensor lazy_base = CopyToDevice(base.clone(), device);
torch::Tensor result = base.index_copy_(dim, index, value);
torch::Tensor lazy_index = CopyToDevice(index, device);
torch::Tensor lazy_value = CopyToDevice(value, device);
torch::Tensor lazy_result =
lazy_base.index_copy_(dim, lazy_index, lazy_value);
AllEqual(result, lazy_result);
AllEqual(base, lazy_base);
});
}
}
}
TEST_F(LazyOpsTest, TestIndexCopyRank0) {
for (torch::ScalarType scalar_type :
{torch::kFloat,
torch::kByte,
torch::kChar,
torch::kShort,
torch::kInt,
torch::kLong}) {
torch::Tensor base = isFloatingType(scalar_type)
? torch::rand(
{5, 3, 7},
torch::TensorOptions(scalar_type).device(DefaultDevice()))
: torch::randint(
100,
{5, 3, 7},
torch::TensorOptions(scalar_type).device(DefaultDevice()));
int rank = base.dim();
for (int dim = -rank; dim < rank; ++dim) {
torch::Tensor index = torch::randint(
0,
base.size(dim),
at::IntArrayRef{},
torch::TensorOptions(torch::kLong).device(DefaultDevice()));
std::vector<int64_t> value_sizes(
base.sizes().begin(), base.sizes().end());
int canonical_dim = dim < 0 ? dim + rank : dim;
value_sizes[canonical_dim] = 1;
torch::Tensor value = isFloatingType(scalar_type)
? torch::rand(
value_sizes,
torch::TensorOptions(scalar_type).device(DefaultDevice()))
: torch::randint(
100,
value_sizes,
torch::TensorOptions(scalar_type).device(DefaultDevice()));
torch::Tensor result = torch::index_copy(base, dim, index, value);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_base = CopyToDevice(base, device);
torch::Tensor lazy_index = CopyToDevice(index, device);
torch::Tensor lazy_value = CopyToDevice(value, device);
torch::Tensor lazy_result =
torch::index_copy(lazy_base, dim, lazy_index, lazy_value);
AllEqual(result, lazy_result);
});
}
}
}
TEST_F(LazyOpsTest, TestRelu) {
torch::Tensor input = torch::rand(
{2, 1, 4, 6},
torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor output = torch::relu(input);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor lazy_output = torch::relu(lazy_input);
AllClose(output, lazy_output);
});
}
TEST_F(LazyOpsTest, TestReluInPlace) {
torch::Tensor input = torch::rand(
{2, 1, 4, 6},
torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor output = torch::relu_(input);
torch::Tensor lazy_output = torch::relu_(lazy_input);
AllClose(output, lazy_output);
AllClose(input, lazy_input);
});
}
TEST_F(LazyOpsTest, TestHardshrink) {
torch::Tensor input = torch::randn(
{10}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor output = torch::hardshrink(input);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor lazy_output = torch::hardshrink(lazy_input);
AllClose(output, lazy_output);
});
}
TEST_F(LazyOpsTest, TestHardSigmoid) {
torch::Tensor input = torch::randn(
{10}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor output = torch::hardsigmoid(input);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor lazy_output = torch::hardsigmoid(lazy_input);
AllClose(output, lazy_output);
});
}
TEST_F(LazyOpsTest, TestHardSigmoidInPlace) {
ForEachDevice([&](const torch::Device& device) {
torch::Tensor input = torch::randn(
{10}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor output = torch::hardsigmoid_(input);
torch::Tensor lazy_output = torch::hardsigmoid_(lazy_input);
AllClose(input, lazy_input);
AllClose(output, lazy_output);
});
}
TEST_F(LazyOpsTest, TestHardSigmoidBackward) {
auto testfn = [&](const std::vector<torch::Tensor>& inputs) -> torch::Tensor {
return torch::hardsigmoid(inputs[0]);
};
ForEachDevice([&](const torch::Device& device) {
TestBackward(
{torch::randn(
{10},
torch::TensorOptions(torch::kFloat)
.device(DefaultDevice())
.requires_grad(true))},
device,
testfn);
});
}
TEST_F(LazyOpsTest, TestSoftshrink) {
torch::Tensor input = torch::randn(
{10}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor output = torch::softshrink(input);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor lazy_output = torch::softshrink(lazy_input);
AllClose(output, lazy_output);
});
}
TEST_F(LazyOpsTest, TestHardtanh) {
torch::Tensor input = torch::randn(
{10}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor output = torch::hardtanh(input);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor lazy_output = torch::hardtanh(lazy_input);
AllClose(output, lazy_output);
});
}
TEST_F(LazyOpsTest, TestHardtanhInPlace) {
torch::Tensor input = torch::randn(
{10}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor output = torch::hardtanh_(input);
torch::Tensor lazy_output = torch::hardtanh_(lazy_input);
AllClose(output, lazy_output);
AllClose(input, lazy_input);
});
}
TEST_F(LazyOpsTest, TestLeakyRelu) {
torch::Tensor input = torch::rand(
{2, 1, 4, 6},
torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
double negative_slope = 0.01;
torch::Tensor output = torch::leaky_relu(input, negative_slope);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor lazy_output = torch::leaky_relu(lazy_input, negative_slope);
AllClose(output, lazy_output);
});
}
TEST_F(LazyOpsTest, TestLeakyReluInPlace) {
torch::Tensor input = torch::rand(
{2, 1, 4, 6},
torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
double negative_slope = 0.01;
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor output = torch::leaky_relu_(input, negative_slope);
torch::Tensor lazy_output = torch::leaky_relu_(lazy_input, negative_slope);
AllClose(output, lazy_output);
AllClose(input, lazy_input);
});
}
TEST_F(LazyOpsTest, TestExp) {
torch::Tensor a = torch::rand(
{2, 2}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor b = torch::exp(a);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = torch::exp(lazy_a);
AllClose(b, lazy_b, /*rtol=*/1e-3, /*atol=*/1e-5);
});
}
TEST_F(LazyOpsTest, TestExpm1) {
torch::Tensor a = torch::rand(
{2, 2}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor b = torch::expm1(a);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = torch::expm1(lazy_a);
AllClose(b, lazy_b, /*rtol=*/1e-3, /*atol=*/1e-5);
});
}
TEST_F(LazyOpsTest, TestLog) {
torch::Tensor a = torch::rand(
{2, 2}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor b = torch::log(a);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = torch::log(lazy_a);
AllClose(b, lazy_b, /*rtol=*/1e-3, /*atol=*/1e-5);
});
}
TEST_F(LazyOpsTest, TestLog2) {
torch::Tensor a = torch::rand(
{2, 2}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor b = torch::log2(a);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = torch::log2(lazy_a);
AllClose(b, lazy_b, /*rtol=*/1e-3, /*atol=*/1e-5);
});
}
TEST_F(LazyOpsTest, TestLog10) {
torch::Tensor a = torch::rand(
{2, 2}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor b = torch::log10(a);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = torch::log10(lazy_a);
AllClose(b, lazy_b, /*rtol=*/1e-3, /*atol=*/1e-5);
});
}
TEST_F(LazyOpsTest, TestLog1p) {
torch::Tensor a = torch::rand(
{2, 2}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor b = torch::log1p(a);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = torch::log1p(lazy_a);
AllClose(b, lazy_b, /*rtol=*/1e-3, /*atol=*/1e-5);
});
}
TEST_F(LazyOpsTest, TestErf) {
torch::Tensor a = torch::randn(
{2, 2}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor b = torch::erf(a);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = torch::erf(lazy_a);
AllClose(b, lazy_b, /*rtol=*/1e-3, /*atol=*/1e-5);
});
}
TEST_F(LazyOpsTest, TestErfc) {
torch::Tensor a = torch::randn(
{2, 2}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor b = torch::erfc(a);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = torch::erfc(lazy_a);
AllClose(b, lazy_b, /*rtol=*/1e-3, /*atol=*/1e-5);
});
}
TEST_F(LazyOpsTest, TestErfinv) {
torch::Tensor a = torch::rand(
{2, 2}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor b = torch::erfinv(a);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = torch::erfinv(lazy_a);
AllClose(b, lazy_b, /*rtol=*/1e-3, /*atol=*/1e-5);
});
}
TEST_F(LazyOpsTest, TestSqrt) {
torch::Tensor a = torch::abs(torch::rand(
{2, 2}, torch::TensorOptions(torch::kFloat).device(DefaultDevice())));
torch::Tensor b = torch::sqrt(a);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = torch::sqrt(lazy_a);
AllClose(b, lazy_b, /*rtol=*/1e-3, /*atol=*/1e-5);
});
}
TEST_F(LazyOpsTest, TestRsqrt) {
torch::Tensor a = torch::abs(torch::rand(
{2, 2}, torch::TensorOptions(torch::kFloat).device(DefaultDevice())));
torch::Tensor b = torch::rsqrt(a);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = torch::rsqrt(lazy_a);
AllClose(b, lazy_b, /*rtol=*/1e-3, /*atol=*/1e-5);
});
}
TEST_F(LazyOpsTest, TestReciprocal) {
torch::Tensor a = torch::randn(
{2, 2}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor b = torch::reciprocal(a);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = torch::reciprocal(lazy_a);
AllClose(b, lazy_b, /*rtol=*/1e-3, /*atol=*/1e-5);
});
}
TEST_F(LazyOpsTest, TestPowTensorScalar) {
torch::Tensor base = torch::rand(
{2, 2}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Scalar exponent = 4.09;
torch::Tensor result = torch::pow(base, exponent);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_base = CopyToDevice(base, device);
torch::Tensor lazy_result = torch::pow(lazy_base, exponent);
AllClose(result, lazy_result, /*rtol=*/1e-3, /*atol=*/1e-5);
});
}
TEST_F(LazyOpsTest, TestPowTensorScalarInPlace) {
torch::Tensor base = torch::rand(
{2, 2}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Scalar exponent = 4.09;
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_base = CopyToDevice(base.clone(), device);
torch::Tensor result = base.pow_(exponent);
torch::Tensor lazy_result = lazy_base.pow_(exponent);
AllClose(result, lazy_result, /*rtol=*/1e-3, /*atol=*/1e-5);
AllClose(base, lazy_base, /*rtol=*/1e-3, /*atol=*/1e-5);
});
}
TEST_F(LazyOpsTest, TestPowTensorTensor) {
torch::Tensor base = torch::abs(torch::rand(
{4, 2}, torch::TensorOptions(torch::kFloat).device(DefaultDevice())));
torch::Tensor exponent = torch::rand(
{4, 2}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor result = torch::pow(base, exponent);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_base = CopyToDevice(base, device);
torch::Tensor lazy_exponent = CopyToDevice(exponent, device);
torch::Tensor lazy_result = torch::pow(lazy_base, lazy_exponent);
AllClose(result, lazy_result, /*rtol=*/1e-3, /*atol=*/1e-5);
});
}
TEST_F(LazyOpsTest, TestPowTensorTensorInPlace) {
torch::Tensor base = torch::abs(torch::rand(
{4, 2}, torch::TensorOptions(torch::kFloat).device(DefaultDevice())));
torch::Tensor exponent = torch::rand(
{4, 2}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_base = CopyToDevice(base.clone(), device);
torch::Tensor result = base.pow_(exponent);
torch::Tensor lazy_exponent = CopyToDevice(exponent, device);
torch::Tensor lazy_result = lazy_base.pow_(lazy_exponent);
AllClose(result, lazy_result, /*rtol=*/1e-3, /*atol=*/1e-5);
AllClose(base, lazy_base, /*rtol=*/1e-3, /*atol=*/1e-5);
});
}
TEST_F(LazyOpsTest, TestPowTensorTensorBroadcast) {
torch::Tensor base = torch::abs(torch::rand(
{4, 2}, torch::TensorOptions(torch::kFloat).device(DefaultDevice())));
torch::Tensor exponent = torch::rand(
{4, 1}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor result = torch::pow(base, exponent);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_base = CopyToDevice(base, device);
torch::Tensor lazy_exponent = CopyToDevice(exponent, device);
torch::Tensor lazy_result = torch::pow(lazy_base, lazy_exponent);
AllClose(result, lazy_result, /*rtol=*/1e-3, /*atol=*/1e-5);
});
}
TEST_F(LazyOpsTest, TestPowScalarTensor) {
torch::Scalar base = 3.5;
torch::Tensor exponent = torch::rand({4, 2});
torch::Tensor result = torch::pow(base, exponent);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_exponent = CopyToDevice(exponent, device);
torch::Tensor lazy_result = torch::pow(base, lazy_exponent);
AllClose(result, lazy_result, /*rtol=*/1e-3, /*atol=*/1e-5);
});
}
TEST_F(LazyOpsTest, TestPowIntExponent) {
torch::Tensor base = torch::abs(torch::rand(
{4, 2}, torch::TensorOptions(torch::kFloat).device(DefaultDevice())));
torch::Scalar exponent = 3;
torch::Tensor result = torch::pow(base, exponent);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_base = CopyToDevice(base, device);
torch::Tensor lazy_result = torch::pow(lazy_base, exponent);
AllClose(result, lazy_result, /*rtol=*/1e-3, /*atol=*/1e-5);
});
}
TEST_F(LazyOpsTest, TestFmodScalar) {
torch::Tensor a =
torch::rand(
{2, 2}, torch::TensorOptions(torch::kFloat).device(DefaultDevice())) *
100.0;
torch::Scalar divisor = 2.0;
torch::Tensor b = torch::fmod(a, divisor);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = torch::fmod(lazy_a, divisor);
AllClose(b, lazy_b);
});
}
TEST_F(LazyOpsTest, TestFmodScalarInPlace) {
torch::Scalar divisor = 2.0;
ForEachDevice([&](const torch::Device& device) {
torch::Tensor a =
torch::rand(
{2, 2},
torch::TensorOptions(torch::kFloat).device(DefaultDevice())) *
100.0;
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor b = a.fmod_(divisor);
torch::Tensor lazy_b = lazy_a.fmod_(divisor);
AllClose(b, lazy_b);
AllClose(a, lazy_a);
});
}
TEST_F(LazyOpsTest, TestFmodTensor) {
torch::Tensor a =
torch::rand(
{2, 2}, torch::TensorOptions(torch::kFloat).device(DefaultDevice())) *
100.0;
torch::Tensor b =
torch::rand(
{2, 2}, torch::TensorOptions(torch::kFloat).device(DefaultDevice())) *
10.0;
torch::Tensor c = torch::fmod(a, b);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = CopyToDevice(b, device);
torch::Tensor lazy_c = torch::fmod(lazy_a, lazy_b);
AllClose(c, lazy_c);
});
}
TEST_F(LazyOpsTest, TestFmodTensorInPlace) {
torch::Tensor b =
torch::rand(
{2, 2}, torch::TensorOptions(torch::kFloat).device(DefaultDevice())) *
10.0;
ForEachDevice([&](const torch::Device& device) {
torch::Tensor a =
torch::rand(
{2, 2},
torch::TensorOptions(torch::kFloat).device(DefaultDevice())) *
100.0;
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor c = a.fmod_(b);
torch::Tensor lazy_b = CopyToDevice(b, device);
torch::Tensor lazy_c = lazy_a.fmod_(lazy_b);
AllClose(c, lazy_c);
AllClose(a, lazy_a);
});
}
TEST_F(LazyOpsTest, TestRemainderScalar) {
torch::Tensor a =
torch::randn(
{2, 2}, torch::TensorOptions(torch::kFloat).device(DefaultDevice())) *
100.0;
torch::Scalar divisor = -2.0;
torch::Tensor b = torch::remainder(a, divisor);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = torch::remainder(lazy_a, divisor);
AllClose(b, lazy_b);
});
}
TEST_F(LazyOpsTest, TestRemainderScalarInPlace) {
torch::Scalar divisor = -2.0;
ForEachDevice([&](const torch::Device& device) {
torch::Tensor a =
torch::randn(
{2, 2},
torch::TensorOptions(torch::kFloat).device(DefaultDevice())) *
100.0;
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor b = a.remainder_(divisor);
torch::Tensor lazy_b = lazy_a.remainder_(divisor);
AllClose(b, lazy_b);
AllClose(a, lazy_a);
});
}
TEST_F(LazyOpsTest, TestRemainderTensor) {
torch::Tensor a =
torch::randn(
{2, 2}, torch::TensorOptions(torch::kFloat).device(DefaultDevice())) *
100.0;
torch::Tensor b =
torch::randn(
{2, 2}, torch::TensorOptions(torch::kFloat).device(DefaultDevice())) *
10.0;
torch::Tensor c = torch::remainder(a, b);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = CopyToDevice(b, device);
torch::Tensor lazy_c = torch::remainder(lazy_a, lazy_b);
AllClose(c, lazy_c, /*rtol=*/1e-4, /*atol=*/1e-6);
});
}
TEST_F(LazyOpsTest, TestRemainderTensorInPlace) {
torch::Tensor b =
torch::randn(
{2, 2}, torch::TensorOptions(torch::kFloat).device(DefaultDevice())) *
10.0;
ForEachDevice([&](const torch::Device& device) {
torch::Tensor a =
torch::randn(
{2, 2},
torch::TensorOptions(torch::kFloat).device(DefaultDevice())) *
100.0;
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor c = a.remainder_(b);
torch::Tensor lazy_b = CopyToDevice(b, device);
torch::Tensor lazy_c = lazy_a.remainder_(lazy_b);
AllClose(c, lazy_c, /*rtol=*/1e-4, /*atol=*/1e-6);
AllClose(a, lazy_a, /*rtol=*/1e-4, /*atol=*/1e-6);
});
}
TEST_F(LazyOpsTest, TestWhere) {
torch::Tensor a = torch::rand(
{3, 3}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor b = torch::rand(
{3, 3}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor c = torch::empty(
{3, 3}, torch::TensorOptions(torch::kByte).device(DefaultDevice()));
for (int i = 0; i < 3; ++i) {
for (int j = 0; j < 3; ++j) {
c[i][j] = i == j;
}
}
torch::Tensor d = torch::where(c, a, b);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = CopyToDevice(b, device);
torch::Tensor lazy_c = CopyToDevice(c, device);
torch::Tensor lazy_d = torch::where(lazy_c, lazy_a, lazy_b);
AllClose(d, lazy_d);
});
}
TEST_F(LazyOpsTest, TestWhereBroadcast) {
torch::Tensor a = torch::rand(
{3, 3}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor b = torch::zeros(
{}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor c = torch::empty(
{3, 3}, torch::TensorOptions(torch::kByte).device(DefaultDevice()));
for (int i = 0; i < 3; ++i) {
for (int j = 0; j < 3; ++j) {
c[i][j] = i == j;
}
}
torch::Tensor d = torch::where(c, a, b);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = CopyToDevice(b, device);
torch::Tensor lazy_c = CopyToDevice(c, device);
torch::Tensor lazy_d = torch::where(lazy_c, lazy_a, lazy_b);
AllClose(d, lazy_d);
});
}
TEST_F(LazyOpsTest, TestThreshold) {
torch::Tensor input = torch::rand(
{2, 1, 4, 6},
torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
float threshold = 0.4;
float value = 20;
torch::Tensor output = torch::threshold(input, threshold, value);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor lazy_output = torch::threshold(lazy_input, threshold, value);
AllClose(output, lazy_output);
});
}
TEST_F(LazyOpsTest, TestThresholdBackward) {
float threshold = 0.4;
float value = 20;
auto testFunction =
[&](const std::vector<torch::Tensor>& inputs) -> torch::Tensor {
return torch::threshold(inputs[0], threshold, value);
};
ForEachDevice([&](const torch::Device& device) {
TestBackward(
{torch::rand(
{2, 1, 4, 6},
torch::TensorOptions(torch::kFloat)
.device(DefaultDevice())
.requires_grad(true))},
device,
testFunction);
});
}
TEST_F(LazyOpsTest, TestThresholdInPlace) {
torch::Tensor input = torch::rand(
{2, 1, 4, 6},
torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor output = input.clone();
float threshold = 0.4;
float value = 20;
torch::threshold_(output, threshold, value);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_output = CopyToDevice(input, device);
torch::threshold_(lazy_output, threshold, value);
AllClose(output, lazy_output);
});
}
TEST_F(LazyOpsTest, TestElu) {
torch::Tensor input = torch::rand(
{2, 1, 4, 6},
torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Scalar alpha = 0.5;
torch::Scalar scale = 2.5;
torch::Scalar input_scale = 1.5;
torch::Tensor output = torch::elu(input, alpha, scale, input_scale);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor lazy_output =
torch::elu(lazy_input, alpha, scale, input_scale);
AllClose(output, lazy_output);
});
}
TEST_F(LazyOpsTest, TestEluInPlace) {
torch::Tensor input = torch::rand(
{2, 1, 4, 6},
torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Scalar alpha = 0.5;
torch::Scalar scale = 2.5;
torch::Scalar input_scale = 1.5;
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor output = torch::elu_(input, alpha, scale, input_scale);
torch::Tensor lazy_output =
torch::elu_(lazy_input, alpha, scale, input_scale);
AllClose(output, lazy_output);
AllClose(input, lazy_input);
});
}
TEST_F(LazyOpsTest, TestSelu) {
torch::Tensor input = torch::rand(
{2, 1, 4, 6},
torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor output = torch::selu(input);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor lazy_output = torch::selu(lazy_input);
AllClose(output, lazy_output);
});
}
TEST_F(LazyOpsTest, TestSeluInPlace) {
torch::Tensor input = torch::rand(
{2, 1, 4, 6},
torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor output = torch::selu_(input);
torch::Tensor lazy_output = torch::selu_(lazy_input);
AllClose(output, lazy_output);
AllClose(input, lazy_input);
});
}
TEST_F(LazyOpsTest, TestCelu) {
torch::Tensor input = torch::rand(
{2, 1, 4, 6},
torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Scalar alpha = 2.5;
torch::Tensor output = torch::celu(input, alpha);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor lazy_output = torch::celu(lazy_input, alpha);
AllClose(output, lazy_output);
});
}
TEST_F(LazyOpsTest, TestCeluInPlace) {
torch::Tensor input = torch::rand(
{2, 1, 4, 6},
torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Scalar alpha = 2.5;
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor output = torch::celu_(input, alpha);
torch::Tensor lazy_output = torch::celu_(lazy_input, alpha);
AllClose(output, lazy_output);
AllClose(input, lazy_input);
});
}
TEST_F(LazyOpsTest, TestGelu) {
torch::Tensor input = torch::rand(
{2, 3}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor output = torch::gelu(input);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor lazy_output = torch::gelu(lazy_input);
AllClose(output, lazy_output);
});
}
TEST_F(LazyOpsTest, TestAddMatMul) {
int in_channels = 32;
int out_channels = 320;
int labels = 50;
torch::Tensor input = torch::rand(
{in_channels, out_channels},
torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor weight = torch::rand(
{out_channels, labels},
torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor bias = torch::rand(
{labels}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
// Test beta != 1. through the CPU interop.
for (double beta : {1., 2.}) {
torch::Tensor output = torch::addmm(bias, input, weight, /*beta=*/beta);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor lazy_weight = CopyToDevice(weight, device);
torch::Tensor lazy_bias = CopyToDevice(bias, device);
torch::Tensor lazy_output =
torch::addmm(lazy_bias, lazy_input, lazy_weight, /*beta=*/beta);
AllClose(output, lazy_output);
});
}
}
TEST_F(LazyOpsTest, TestEmbedding) {
torch::Tensor a = torch::rand(
{32, 4}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor i = torch::randint(
0,
31,
{3, 4},
torch::TensorOptions(torch::kLong).device(DefaultDevice()));
torch::Tensor b = torch::embedding(
a,
i,
/*padding_idx=*/0,
/*scale_grad_by_freq=*/false,
/*sparse=*/false);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_i = CopyToDevice(i, device);
torch::Tensor lazy_b = torch::embedding(
lazy_a,
lazy_i,
/*padding_idx=*/0,
/*scale_grad_by_freq=*/false,
/*sparse=*/false);
AllClose(b, lazy_b);
});
}
TEST_F(LazyOpsTest, TestOneHot) {
int num_classes = 5;
torch::Tensor input = torch::randint(
0,
num_classes,
{10},
torch::TensorOptions(torch::kLong).device(DefaultDevice()));
torch::Tensor output = torch::one_hot(input, num_classes);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor lazy_output = torch::one_hot(lazy_input, num_classes);
AllEqual(output, lazy_output);
});
}
TEST_F(LazyOpsTest, TestTranspose) {
torch::Tensor input = torch::rand(
{2, 3}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor output = torch::t(input);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor lazy_output = torch::t(lazy_input);
AllClose(output, lazy_output);
});
}
TEST_F(LazyOpsTest, TestTransposeInPlace) {
torch::Tensor input = torch::rand(
{2, 3}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor output = input.t_();
torch::Tensor lazy_output = lazy_input.t_();
EXPECT_EQ(lazy_output.sizes(), output.sizes());
AllClose(output, lazy_output);
AllClose(input, lazy_input);
});
}
TEST_F(LazyOpsTest, TestReshape) {
torch::Tensor input = torch::rand(
{32, 20, 4, 4},
torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor output = torch::reshape(input, {-1, 320});
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor lazy_output = torch::reshape(lazy_input, {-1, 320});
AllClose(output, lazy_output);
});
}
TEST_F(LazyOpsTest, TestResize) {
// Testing a resize_() with target size bigger than original size is not
// possible, as we fill with zeros, while pytorch fills with random garbage.
torch::Tensor input = torch::rand(
{2, 2, 4}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor saved_input = input.clone();
input.resize_({3, 3});
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(saved_input, device);
lazy_input.resize_({3, 3});
AllClose(input, lazy_input);
});
}
TEST_F(LazyOpsTest, TestViewResize) {
torch::Tensor input = torch::zeros(
{8, 2}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor saved_input = input.clone();
torch::Tensor output = input.view({4, 4});
output.resize_({3, 3});
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(saved_input, device);
torch::Tensor lazy_output = lazy_input.view({4, 4});
lazy_output.resize_({3, 3});
AllClose(input, lazy_input);
AllClose(output, lazy_output);
});
}
TEST_F(LazyOpsTest, TestView) {
torch::Tensor input = torch::rand(
{32, 20, 4, 4},
torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor output = input.view({-1, 320});
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor lazy_output = lazy_input.view({-1, 320});
AllClose(output, lazy_output);
});
}
TEST_F(LazyOpsTest, TestViewMod) {
torch::Tensor input = torch::zeros(
{32, 20, 4, 4},
torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor one = torch::tensor(
1.0, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor output = input.view({-1, 320});
output.add_(one, 1.0);
input.add_(one, 1.0);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor xinput = torch::zeros(
{32, 20, 4, 4},
torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor lazy_input = CopyToDevice(xinput, device);
torch::Tensor lazy_one = CopyToDevice(one, device);
torch::Tensor lazy_output = lazy_input.view({-1, 320});
lazy_output.add_(lazy_one, 1.0);
lazy_input.add_(lazy_one, 1.0);
AllClose(output, lazy_output);
AllClose(input, lazy_input);
});
}
TEST_F(LazyOpsTest, TestViewModComplex) {
torch::Tensor input = torch::zeros(
{32, 20, 4, 4},
torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor one = torch::tensor(
1.0, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor output1 = input.view({-1, 320});
output1.add_(one, 1.0);
torch::Tensor output2 = input.view({-1, 160});
output2.add_(one, 1.0);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor xinput = torch::zeros(
{32, 20, 4, 4},
torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor lazy_input = CopyToDevice(xinput, device);
torch::Tensor lazy_one = CopyToDevice(one, device);
torch::Tensor lazy_output1 = lazy_input.view({-1, 320});
lazy_output1.add_(lazy_one, 1.0);
torch::Tensor lazy_output2 = lazy_input.view({-1, 160});
lazy_output2.add_(lazy_one, 1.0);
AllClose(output1, lazy_output1);
AllClose(output2, lazy_output2);
});
}
TEST_F(LazyOpsTest, TestViewOfViewMod) {
torch::Tensor input = torch::zeros(
{32, 20, 4, 4},
torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor one = torch::tensor(
1.0, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor output1 = input.view({-1, 320});
output1.add_(one, 1.0);
torch::Tensor output2 = output1.view({-1, 160});
output2.add_(one, 1.0);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor xinput = torch::zeros(
{32, 20, 4, 4},
torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor lazy_input = CopyToDevice(xinput, device);
torch::Tensor lazy_one = CopyToDevice(one, device);
torch::Tensor lazy_output1 = lazy_input.view({-1, 320});
lazy_output1.add_(lazy_one, 1.0);
torch::Tensor lazy_output2 = lazy_output1.view({-1, 160});
lazy_output2.add_(lazy_one, 1.0);
AllClose(output1, lazy_output1);
AllClose(output2, lazy_output2);
});
}
TEST_F(LazyOpsTest, TestViewSqueezeAddInPlace) {
torch::Tensor input = torch::zeros(
{2, 3, 1}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
std::vector<int64_t> view_size = {2, 3, 1, 1};
int squeeze_dim = 2;
torch::Tensor one = torch::tensor(
1.0, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor output = input.view(view_size);
output.squeeze_(squeeze_dim);
output.add_(one, 1.0);
torch::Tensor lazy_one = CopyToDevice(one, device);
torch::Tensor lazy_output = lazy_input.view(view_size);
lazy_output.squeeze_(squeeze_dim);
lazy_output.add_(lazy_one, 1.0);
AllClose(output, lazy_output);
AllClose(input, lazy_input);
});
}
TEST_F(LazyOpsTest, TestUnsafeView) {
torch::Tensor input = torch::rand(
{32, 20, 4, 4},
torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor output = torch::_unsafe_view(input, {-1, 320});
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor lazy_output = torch::_unsafe_view(lazy_input, {-1, 320});
AllClose(output, lazy_output);
});
}
TEST_F(LazyOpsTest, TestNarrow) {
torch::Tensor a = torch::rand(
{8, 10, 4, 4},
torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
for (int64_t dim : {1, -3}) {
for (int64_t start : {2, -8}) {
torch::Tensor b = a.narrow(dim, start, 6);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = lazy_a.narrow(dim, start, 6);
AllClose(b, lazy_b);
});
}
}
}
TEST_F(LazyOpsTest, TestNarrowUpdate) {
for (int64_t dim : {1, -2}) {
for (int64_t start : {2, -6}) {
torch::Tensor a = torch::rand(
{3, 8, 3},
torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor a_copy = a.clone();
torch::Tensor b = torch::rand(
{3, 4, 3},
torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor c = a.narrow(dim, start, 4);
c.add_(b, 1.0);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a_copy, device);
torch::Tensor lazy_b = CopyToDevice(b, device);
torch::Tensor lazy_c = lazy_a.narrow(dim, start, 4);
lazy_c.add_(lazy_b, 1.0);
AllClose(c, lazy_c);
});
}
}
}
TEST_F(LazyOpsTest, TestNarrowUpdateBaseCheck) {
for (int64_t dim : {0, -2}) {
for (int64_t start : {2, -6}) {
torch::Tensor a = torch::zeros(
{8, 3}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor a_copy = a.clone();
torch::Tensor b = torch::ones(
{4, 3}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor c = a.narrow(dim, start, 4);
c.add_(b, 1.0);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a_copy, device);
torch::Tensor lazy_b = CopyToDevice(b, device);
torch::Tensor lazy_c = lazy_a.narrow(dim, start, 4);
lazy_c.add_(lazy_b, 1.0);
AllClose(a, lazy_a);
});
}
}
}
TEST_F(LazyOpsTest, TestNarrowUpdateTwoSlices) {
for (int64_t dim : {0, -2}) {
for (int64_t start0 : {2, -6}) {
for (int64_t start1 : {6, -2}) {
torch::Tensor a = torch::zeros(
{8, 3},
torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor a_copy = a.clone();
torch::Tensor b = torch::ones(
{2, 3},
torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor c = b + 1;
torch::Tensor d = a.narrow(dim, start0, 2);
torch::Tensor e = a.narrow(dim, start1, 2);
d.add_(b, 1.0);
e.add_(c, 1.0);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a_copy, device);
torch::Tensor lazy_b = CopyToDevice(b, device);
torch::Tensor lazy_c = CopyToDevice(c, device);
torch::Tensor lazy_d = lazy_a.narrow(dim, start0, 2);
torch::Tensor lazy_e = lazy_a.narrow(dim, start1, 2);
lazy_d.add_(lazy_b, 1.0);
lazy_e.add_(lazy_c, 1.0);
AllClose(d, lazy_d);
AllClose(e, lazy_e);
AllClose(a, lazy_a);
});
}
}
}
}
TEST_F(LazyOpsTest, TestNarrowUpdateView) {
for (int64_t dim : {0, -3}) {
for (int64_t start : {2, -6}) {
torch::Tensor a = torch::rand(
{8, 2, 3},
torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor a_copy = a.clone();
torch::Tensor b = torch::rand(
{4, 6}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor c = a.narrow(dim, start, 4);
torch::Tensor d = c.view({4, 6});
d.add_(b, 1.0);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a_copy, device);
torch::Tensor lazy_b = CopyToDevice(b, device);
torch::Tensor lazy_c = lazy_a.narrow(dim, start, 4);
torch::Tensor lazy_d = lazy_c.view({4, 6});
lazy_d.add_(lazy_b, 1.0);
AllClose(d, lazy_d);
});
}
}
}
TEST_F(LazyOpsTest, TestNarrowInNarrowUpdate) {
for (int64_t dim : {1, -2}) {
for (int64_t start0 : {1, -7}) {
for (int64_t start1 : {1, -5}) {
torch::Tensor a = torch::rand(
{3, 8, 3},
torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor a_copy = a.clone();
torch::Tensor b = torch::rand(
{3, 2, 3},
torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor c = a.narrow(dim, start0, 6);
torch::Tensor d = c.narrow(dim, start1, 2);
d.add_(b, 1.0);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a_copy, device);
torch::Tensor lazy_b = CopyToDevice(b, device);
torch::Tensor lazy_c = lazy_a.narrow(dim, start0, 6);
torch::Tensor lazy_d = lazy_c.narrow(dim, start1, 2);
lazy_d.add_(lazy_b, 1.0);
AllClose(a, lazy_a);
});
}
}
}
}
TEST_F(LazyOpsTest, TestNarrowCopy) {
for (int64_t dim : {1, -3}) {
for (int64_t start : {2, -8}) {
ForEachDevice([&](const torch::Device& device) {
torch::Tensor input = torch::rand(
{8, 10, 4, 4},
torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor result = input.narrow_copy(dim, start, 6);
input.add_(1);
torch::Tensor lazy_result = lazy_input.narrow_copy(dim, start, 6);
lazy_input.add_(1);
AllClose(result, lazy_result);
});
}
}
}
TEST_F(LazyOpsTest, TestViewAs) {
torch::Tensor input = torch::rand(
{32, 20, 4, 4},
torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor empty = torch::empty({32, 320});
torch::Tensor output = input.view_as(empty);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor lazy_empty = CopyToDevice(empty, device);
torch::Tensor lazy_output = lazy_input.view_as(lazy_empty);
AllClose(output, lazy_output);
});
}
TEST_F(LazyOpsTest, TestLogSoftmax) {
torch::Tensor input = torch::rand(
{5, 3, 4, 2},
torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
int rank = input.dim();
for (int dim = -rank; dim < rank; ++dim) {
torch::Tensor output = torch::log_softmax(input, dim);
torch::Tensor lazy_output = torch::log_softmax(lazy_input, dim);
AllClose(output, lazy_output, /*rtol=*/1e-3);
}
});
}
TEST_F(LazyOpsTest, TestLogSoftmaxCast) {
torch::Tensor input = torch::rand(
{5, 3, 4, 2},
torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
int rank = input.dim();
for (int dim = -rank; dim < rank; ++dim) {
torch::Tensor output = torch::log_softmax(input, dim, torch::kDouble);
torch::Tensor lazy_output =
torch::log_softmax(lazy_input, dim, torch::kDouble);
AllClose(output, lazy_output, /*rtol=*/1e-3);
}
});
}
TEST_F(LazyOpsTest, TestLogSoftmaxWrapper) {
torch::Tensor input = torch::rand(
{10, 2, 6, 4},
torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
int rank = input.dim();
for (int dim = -rank; dim < rank; ++dim) {
torch::Tensor output =
torch::_log_softmax(input, dim, /*half_to_float=*/false);
torch::Tensor lazy_output =
torch::_log_softmax(lazy_input, dim, /*half_to_float=*/false);
AllClose(output, lazy_output, /*rtol=*/1e-3);
}
});
}
TEST_F(LazyOpsTest, TestSoftmax) {
torch::Tensor input = torch::rand(
{10, 2, 6, 4},
torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
int rank = input.dim();
for (int dim = -rank; dim < rank; ++dim) {
torch::Tensor output = torch::softmax(input, dim);
torch::Tensor lazy_output = torch::softmax(lazy_input, dim);
AllClose(output, lazy_output, /*rtol=*/1e-3);
}
});
}
TEST_F(LazyOpsTest, TestSoftmaxCast) {
torch::Tensor input = torch::rand(
{10, 2, 6, 4},
torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
int rank = input.dim();
for (int dim = -rank; dim < rank; ++dim) {
torch::Tensor output = torch::softmax(input, dim, torch::kDouble);
torch::Tensor lazy_output =
torch::softmax(lazy_input, dim, torch::kDouble);
AllClose(output, lazy_output, /*rtol=*/1e-3);
}
});
}
TEST_F(LazyOpsTest, TestSoftmaxWrapper) {
torch::Tensor input = torch::rand(
{10, 2, 6, 4},
torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
int rank = input.dim();
for (int dim = -rank; dim < rank; ++dim) {
torch::Tensor output =
torch::_softmax(input, dim, /*half_to_float=*/false);
torch::Tensor lazy_output =
torch::_softmax(lazy_input, dim, /*half_to_float=*/false);
AllClose(output, lazy_output, /*rtol=*/1e-3);
}
});
}
TEST_F(LazyOpsTest, TestSoftplus) {
torch::Tensor input = torch::rand(
{2, 1, 4, 6},
torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor output = torch::softplus(input);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor lazy_output = torch::softplus(lazy_input);
AllClose(output, lazy_output, /*rtol=*/1e-4);
});
}
TEST_F(LazyOpsTest, TestMaxPool1D) {
torch::Tensor input = torch::rand(
{1, 16, 56}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
int kernel_size = 3;
for (int stride = 1; stride <= 2; ++stride) {
for (int padding = 0; padding <= 1; ++padding) {
// Test ceil_mode=true through the CPU interop.
for (bool ceil_mode : {false, true}) {
// Test dilation through the CPU interop.
for (int dilation = 1; dilation <= 2; ++dilation) {
torch::Tensor output = torch::max_pool1d(
input,
/*kernel_size=*/{kernel_size},
/*stride=*/{stride},
/*padding=*/{padding},
/*dilation=*/{dilation},
/*ceil_mode=*/ceil_mode);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor lazy_output = torch::max_pool1d(
lazy_input,
/*kernel_size=*/{kernel_size},
/*stride=*/{stride},
/*padding=*/{padding},
/*dilation=*/{dilation},
/*ceil_mode=*/ceil_mode);
AllClose(output, lazy_output);
});
}
}
}
}
}
TEST_F(LazyOpsTest, TestMaxPool2D) {
torch::Tensor input = torch::rand(
{1, 4, 14, 14},
torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
int kernel_size = 3;
for (int stride = 1; stride <= 2; ++stride) {
for (int padding = 0; padding <= 1; ++padding) {
// Test ceil_mode=true through the CPU interop.
for (bool ceil_mode : {false, true}) {
// Test dilation through the CPU interop.
for (int dilation = 1; dilation <= 2; ++dilation) {
torch::Tensor output = torch::max_pool2d(
input,
/*kernel_size=*/{kernel_size, kernel_size},
/*stride=*/{stride, stride},
/*padding=*/{padding, padding},
/*dilation=*/{dilation, dilation},
/*ceil_mode=*/ceil_mode);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor lazy_output = torch::max_pool2d(
lazy_input,
/*kernel_size=*/{kernel_size, kernel_size},
/*stride=*/{stride, stride},
/*padding=*/{padding, padding},
/*dilation=*/{dilation, dilation},
/*ceil_mode=*/ceil_mode);
AllClose(output, lazy_output);
});
}
}
}
}
}
TEST_F(LazyOpsTest, TestMaxPool2DWithIndices) {
torch::Tensor input = torch::rand(
{1, 4, 14, 14},
torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
int kernel_size = 3;
for (int stride = 1; stride <= 2; ++stride) {
for (int padding = 0; padding <= 1; ++padding) {
// Test ceil_mode=true through the CPU interop.
for (bool ceil_mode : {false, true}) {
// Test dilation through the CPU interop.
for (int dilation = 1; dilation <= 2; ++dilation) {
auto outputs = torch::max_pool2d_with_indices(
input,
/*kernel_size=*/{kernel_size, kernel_size},
/*stride=*/{stride, stride},
/*padding=*/{padding, padding},
/*dilation=*/{dilation, dilation},
/*ceil_mode=*/ceil_mode);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
auto lazy_outputs = torch::max_pool2d_with_indices(
lazy_input,
/*kernel_size=*/{kernel_size, kernel_size},
/*stride=*/{stride, stride},
/*padding=*/{padding, padding},
/*dilation=*/{dilation, dilation},
/*ceil_mode=*/ceil_mode);
AllClose(std::get<0>(outputs), std::get<0>(lazy_outputs));
AllClose(std::get<1>(outputs), std::get<1>(lazy_outputs));
});
}
}
}
}
}
TEST_F(LazyOpsTest, TestMaxPool2DNonSquare) {
torch::Tensor input = torch::rand(
{1, 4, 14, 14},
torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
int kernel_size = 4;
for (int stride = 1; stride <= 2; ++stride) {
for (int padding = 0; padding <= 1; ++padding) {
// Test ceil_mode=true through the CPU interop.
for (bool ceil_mode : {false, true}) {
// Test dilation through the CPU interop.
for (int dilation = 1; dilation <= 2; ++dilation) {
torch::Tensor output = torch::max_pool2d(
input,
/*kernel_size=*/{kernel_size, kernel_size + 1},
/*stride=*/{stride, stride + 1},
/*padding=*/{padding, padding + 1},
/*dilation=*/{dilation, dilation},
/*ceil_mode=*/ceil_mode);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor lazy_output = torch::max_pool2d(
lazy_input,
/*kernel_size=*/{kernel_size, kernel_size + 1},
/*stride=*/{stride, stride + 1},
/*padding=*/{padding, padding + 1},
/*dilation=*/{dilation, dilation},
/*ceil_mode=*/ceil_mode);
AllClose(output, lazy_output);
});
}
}
}
}
}
TEST_F(LazyOpsTest, TestMaxPool3D) {
torch::Tensor input = torch::rand(
{1, 1, 8, 8, 8},
torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
int kernel_size = 3;
for (int stride = 1; stride <= 2; ++stride) {
for (int padding = 0; padding <= 1; ++padding) {
// Test ceil_mode=true through the CPU interop.
for (bool ceil_mode : {false, true}) {
// Test dilation through the CPU interop.
for (int dilation = 1; dilation <= 2; ++dilation) {
torch::Tensor output = torch::max_pool3d(
input,
/*kernel_size=*/{kernel_size, kernel_size, kernel_size},
/*stride=*/{stride, stride, stride},
/*padding=*/{padding, padding, padding},
/*dilation=*/{dilation, dilation, dilation},
/*ceil_mode=*/ceil_mode);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor lazy_output = torch::max_pool3d(
lazy_input,
/*kernel_size=*/{kernel_size, kernel_size, kernel_size},
/*stride=*/{stride, stride, stride},
/*padding=*/{padding, padding, padding},
/*dilation=*/{dilation, dilation, dilation},
/*ceil_mode=*/ceil_mode);
AllClose(output, lazy_output);
});
}
}
}
}
}
TEST_F(LazyOpsTest, TestMaxPool3DWithIndices) {
torch::Tensor input = torch::rand(
{1, 1, 8, 8, 8},
torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
int kernel_size = 3;
for (int stride = 1; stride <= 2; ++stride) {
for (int padding = 0; padding <= 1; ++padding) {
// Test ceil_mode=true through the CPU interop.
for (bool ceil_mode : {false, true}) {
// Test dilation through the CPU interop.
for (int dilation = 1; dilation <= 2; ++dilation) {
auto outputs = torch::max_pool3d_with_indices(
input,
/*kernel_size=*/{kernel_size, kernel_size, kernel_size},
/*stride=*/{stride, stride, stride},
/*padding=*/{padding, padding, padding},
/*dilation=*/{dilation, dilation, dilation},
/*ceil_mode=*/ceil_mode);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
auto lazy_outputs = torch::max_pool3d_with_indices(
lazy_input,
/*kernel_size=*/{kernel_size, kernel_size, kernel_size},
/*stride=*/{stride, stride, stride},
/*padding=*/{padding, padding, padding},
/*dilation=*/{dilation, dilation, dilation},
/*ceil_mode=*/ceil_mode);
AllClose(std::get<0>(outputs), std::get<0>(lazy_outputs));
AllClose(std::get<1>(outputs), std::get<1>(lazy_outputs));
});
}
}
}
}
}
TEST_F(LazyOpsTest, TestMaxPool3DIncompleteAttributes) {
torch::Tensor input = torch::rand(
{1, 1, 8, 8, 8},
torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
int kernel_size = 3;
for (int stride = 1; stride <= 2; ++stride) {
for (int padding = 0; padding <= 1; ++padding) {
// Test ceil_mode=true through the CPU interop.
for (bool ceil_mode : {false, true}) {
// Test dilation through the CPU interop.
for (int dilation = 1; dilation <= 2; ++dilation) {
torch::Tensor output = torch::max_pool3d(
input,
/*kernel_size=*/{kernel_size, kernel_size, kernel_size},
/*stride=*/{},
/*padding=*/{padding},
/*dilation=*/{dilation, dilation, dilation},
/*ceil_mode=*/ceil_mode);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor lazy_output = torch::max_pool3d(
lazy_input,
/*kernel_size=*/{kernel_size, kernel_size, kernel_size},
/*stride=*/{},
/*padding=*/{padding},
/*dilation=*/{dilation, dilation, dilation},
/*ceil_mode=*/ceil_mode);
AllClose(output, lazy_output);
});
}
}
}
}
}
TEST_F(LazyOpsTest, TestMaxPool3DNonSquare) {
torch::Tensor input = torch::rand(
{1, 1, 8, 8, 8},
torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
int kernel_size = 4;
for (int stride = 1; stride <= 2; ++stride) {
for (int padding = 0; padding <= 1; ++padding) {
// Test ceil_mode=true through the CPU interop.
for (bool ceil_mode : {false, true}) {
// Test dilation through the CPU interop.
for (int dilation = 1; dilation <= 2; ++dilation) {
torch::Tensor output = torch::max_pool3d(
input,
/*kernel_size=*/{kernel_size, kernel_size + 1, kernel_size},
/*stride=*/{stride, stride + 1, stride},
/*padding=*/{padding, padding + 1, padding},
/*dilation=*/{dilation, dilation, dilation},
/*ceil_mode=*/ceil_mode);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor lazy_output = torch::max_pool3d(
lazy_input,
/*kernel_size=*/{kernel_size, kernel_size + 1, kernel_size},
/*stride=*/{stride, stride + 1, stride},
/*padding=*/{padding, padding + 1, padding},
/*dilation=*/{dilation, dilation, dilation},
/*ceil_mode=*/ceil_mode);
AllClose(output, lazy_output);
});
}
}
}
}
}
TEST_F(LazyOpsTest, TestMaxPool2DNoBatch) {
torch::Tensor input = torch::rand(
{4, 14, 14}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
int kernel_size = 3;
for (int stride = 1; stride <= 2; ++stride) {
for (int padding = 0; padding <= 1; ++padding) {
// Test ceil_mode=true through the CPU interop.
for (bool ceil_mode : {false, true}) {
// Test dilation through the CPU interop.
for (int dilation = 1; dilation <= 2; ++dilation) {
torch::Tensor output = torch::max_pool2d(
input,
/*kernel_size=*/{kernel_size, kernel_size},
/*stride=*/{stride, stride},
/*padding=*/{padding, padding},
/*dilation=*/{dilation, dilation},
/*ceil_mode=*/ceil_mode);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor lazy_output = torch::max_pool2d(
lazy_input,
/*kernel_size=*/{kernel_size, kernel_size},
/*stride=*/{stride, stride},
/*padding=*/{padding, padding},
/*dilation=*/{dilation, dilation},
/*ceil_mode=*/ceil_mode);
AllClose(output, lazy_output);
});
}
}
}
}
}
TEST_F(LazyOpsTest, TestMaxPool3DNoBatch) {
torch::Tensor input = torch::rand(
{1, 8, 8, 8},
torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
int kernel_size = 3;
for (int stride = 1; stride <= 2; ++stride) {
for (int padding = 0; padding <= 1; ++padding) {
// Test ceil_mode=true through the CPU interop.
for (bool ceil_mode : {false, true}) {
// Test dilation through the CPU interop.
for (int dilation = 1; dilation <= 2; ++dilation) {
torch::Tensor output = torch::max_pool3d(
input,
/*kernel_size=*/{kernel_size, kernel_size, kernel_size},
/*stride=*/{stride, stride, stride},
/*padding=*/{padding, padding, padding},
/*dilation=*/{dilation, dilation, dilation},
/*ceil_mode=*/ceil_mode);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor lazy_output = torch::max_pool3d(
lazy_input,
/*kernel_size=*/{kernel_size, kernel_size, kernel_size},
/*stride=*/{stride, stride, stride},
/*padding=*/{padding, padding, padding},
/*dilation=*/{dilation, dilation, dilation},
/*ceil_mode=*/ceil_mode);
AllClose(output, lazy_output);
});
}
}
}
}
}
TEST_F(LazyOpsTest, TestAvgPool1D) {
torch::Tensor input = torch::rand(
{4, 1, 28}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
int kernel_size = 2;
for (int stride = 1; stride <= 2; ++stride) {
for (int padding = 0; padding <= 1; ++padding) {
for (bool count_include_pad : {true, false}) {
// Test ceil_mode=true through the CPU interop.
for (bool ceil_mode : {false, true}) {
torch::Tensor output = torch::avg_pool1d(
input,
/*kernel_size=*/{kernel_size},
/*stride=*/{stride},
/*padding=*/{padding},
/*ceil_mode=*/ceil_mode,
/*count_include_pad=*/count_include_pad);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor lazy_output = torch::avg_pool1d(
lazy_input,
/*kernel_size=*/{kernel_size},
/*stride=*/{stride},
/*padding=*/{padding},
/*ceil_mode=*/ceil_mode,
/*count_include_pad=*/count_include_pad);
AllClose(output, lazy_output);
});
}
}
}
}
}
TEST_F(LazyOpsTest, TestAvgPool2D) {
torch::Tensor input = torch::rand(
{2, 1, 14, 14},
torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
int kernel_size = 2;
for (int stride = 1; stride <= 2; ++stride) {
for (int padding = 0; padding <= 1; ++padding) {
for (bool count_include_pad : {true, false}) {
// Test ceil_mode=true through the CPU interop.
for (bool ceil_mode : {false, true}) {
torch::Tensor output = torch::avg_pool2d(
input,
/*kernel_size=*/{kernel_size, kernel_size},
/*stride=*/{stride, stride},
/*padding=*/{padding, padding},
/*ceil_mode=*/ceil_mode,
/*count_include_pad=*/count_include_pad);
ForEachDevice([&](const torch::Device& device) {
// torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor lazy_output = torch::avg_pool2d(
lazy_input,
/*kernel_size=*/{kernel_size, kernel_size},
/*stride=*/{stride, stride},
/*padding=*/{padding, padding},
/*ceil_mode=*/ceil_mode,
/*count_include_pad=*/count_include_pad);
AllClose(output, lazy_output.to(torch::kCPU));
});
}
}
}
}
}
TEST_F(LazyOpsTest, TestAvgPool2DNonSquare) {
torch::Tensor input = torch::rand(
{2, 1, 14, 14},
torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
int kernel_size = 4;
for (int stride = 1; stride <= 2; ++stride) {
for (int padding = 0; padding <= 1; ++padding) {
for (bool count_include_pad : {true, false}) {
// Test ceil_mode=true through the CPU interop.
for (bool ceil_mode : {false, true}) {
torch::Tensor output = torch::avg_pool2d(
input,
/*kernel_size=*/{kernel_size, kernel_size + 1},
/*stride=*/{stride, stride + 1},
/*padding=*/{padding, padding + 1},
/*ceil_mode=*/ceil_mode,
/*count_include_pad=*/count_include_pad);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor lazy_output = torch::avg_pool2d(
lazy_input,
/*kernel_size=*/{kernel_size, kernel_size + 1},
/*stride=*/{stride, stride + 1},
/*padding=*/{padding, padding + 1},
/*ceil_mode=*/ceil_mode,
/*count_include_pad=*/count_include_pad);
AllClose(output, lazy_output);
});
}
}
}
}
}
TEST_F(LazyOpsTest, TestAvgPool3D) {
torch::Tensor input = torch::rand(
{1, 1, 7, 7, 7},
torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
int kernel_size = 2;
for (int stride = 1; stride <= 2; ++stride) {
for (int padding = 0; padding <= 1; ++padding) {
for (bool count_include_pad : {true, false}) {
// Test ceil_mode=true through the CPU interop.
for (bool ceil_mode : {false, true}) {
torch::Tensor output = torch::avg_pool3d(
input,
/*kernel_size=*/{kernel_size, kernel_size, kernel_size},
/*stride=*/{stride, stride, stride},
/*padding=*/{padding, padding, padding},
/*ceil_mode=*/ceil_mode,
/*count_include_pad=*/count_include_pad);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor lazy_output = torch::avg_pool3d(
lazy_input,
/*kernel_size=*/{kernel_size, kernel_size, kernel_size},
/*stride=*/{stride, stride, stride},
/*padding=*/{padding, padding, padding},
/*ceil_mode=*/ceil_mode,
/*count_include_pad=*/count_include_pad);
AllClose(output, lazy_output);
});
}
}
}
}
}
TEST_F(LazyOpsTest, TestAvgPool3DIncompleteAttributes) {
torch::Tensor input = torch::rand(
{1, 1, 7, 7, 7},
torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
int kernel_size = 2;
for (int stride = 1; stride <= 2; ++stride) {
for (int padding = 0; padding <= 1; ++padding) {
for (bool count_include_pad : {true, false}) {
// Test ceil_mode=true through the CPU interop.
for (bool ceil_mode : {false, true}) {
torch::Tensor output = torch::avg_pool3d(
input,
/*kernel_size=*/{kernel_size, kernel_size, kernel_size},
/*stride=*/{},
/*padding=*/{padding, padding, padding},
/*ceil_mode=*/ceil_mode,
/*count_include_pad=*/count_include_pad);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor lazy_output = torch::avg_pool3d(
lazy_input,
/*kernel_size=*/{kernel_size, kernel_size, kernel_size},
/*stride=*/{},
/*padding=*/{padding, padding, padding},
/*ceil_mode=*/ceil_mode,
/*count_include_pad=*/count_include_pad);
AllClose(output, lazy_output);
});
}
}
}
}
}
TEST_F(LazyOpsTest, TestAvgPool3DNonSquare) {
torch::Tensor input = torch::rand(
{1, 1, 7, 7, 7},
torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
int kernel_size = 4;
for (int stride = 1; stride <= 2; ++stride) {
for (int padding = 0; padding <= 1; ++padding) {
for (bool count_include_pad : {true, false}) {
// Test ceil_mode=true through the CPU interop.
for (bool ceil_mode : {false, true}) {
torch::Tensor output = torch::avg_pool3d(
input,
/*kernel_size=*/{kernel_size, kernel_size + 1, kernel_size},
/*stride=*/{stride, stride + 1, stride},
/*padding=*/{padding, padding + 1, padding},
/*ceil_mode=*/ceil_mode,
/*count_include_pad=*/count_include_pad);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor lazy_output = torch::avg_pool3d(
lazy_input,
/*kernel_size=*/{kernel_size, kernel_size + 1, kernel_size},
/*stride=*/{stride, stride + 1, stride},
/*padding=*/{padding, padding + 1, padding},
/*ceil_mode=*/ceil_mode,
/*count_include_pad=*/count_include_pad);
AllClose(output, lazy_output);
});
}
}
}
}
}
TEST_F(LazyOpsTest, TestAvgPool2DNoBatch) {
torch::Tensor input = torch::rand(
{1, 7, 7}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
int kernel_size = 2;
for (int stride = 1; stride <= 2; ++stride) {
for (int padding = 0; padding <= 1; ++padding) {
for (bool count_include_pad : {true, false}) {
// Test ceil_mode=true through the CPU interop.
for (bool ceil_mode : {false, true}) {
torch::Tensor output = torch::avg_pool2d(
input,
/*kernel_size=*/{kernel_size, kernel_size},
/*stride=*/{stride, stride},
/*padding=*/{padding, padding},
/*ceil_mode=*/ceil_mode,
/*count_include_pad=*/count_include_pad);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor lazy_output = torch::avg_pool2d(
lazy_input,
/*kernel_size=*/{kernel_size, kernel_size},
/*stride=*/{stride, stride},
/*padding=*/{padding, padding},
/*ceil_mode=*/ceil_mode,
/*count_include_pad=*/count_include_pad);
AllClose(output, lazy_output);
});
}
}
}
}
}
TEST_F(LazyOpsTest, TestAvgPool3DNoBatch) {
torch::Tensor input = torch::rand(
{1, 7, 7, 7},
torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
int kernel_size = 2;
for (int stride = 1; stride <= 2; ++stride) {
for (int padding = 0; padding <= 1; ++padding) {
for (bool count_include_pad : {true, false}) {
// Test ceil_mode=true through the CPU interop.
for (bool ceil_mode : {false, true}) {
torch::Tensor output = torch::avg_pool3d(
input,
/*kernel_size=*/{kernel_size, kernel_size, kernel_size},
/*stride=*/{stride, stride, stride},
/*padding=*/{padding, padding, padding},
/*ceil_mode=*/ceil_mode,
/*count_include_pad=*/count_include_pad);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor lazy_output = torch::avg_pool3d(
lazy_input,
/*kernel_size=*/{kernel_size, kernel_size, kernel_size},
/*stride=*/{stride, stride, stride},
/*padding=*/{padding, padding, padding},
/*ceil_mode=*/ceil_mode,
/*count_include_pad=*/count_include_pad);
AllClose(output, lazy_output);
});
}
}
}
}
}
TEST_F(LazyOpsTest, TestAdaptiveAvgPool2D) {
torch::Tensor input = torch::rand(
{4, 1, 28, 28},
torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
for (int64_t output_size : {7, 4}) {
torch::Tensor output =
torch::adaptive_avg_pool2d(input, {output_size, output_size});
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor lazy_output =
torch::adaptive_avg_pool2d(lazy_input, {output_size, output_size});
AllClose(output, lazy_output);
});
}
}
TEST_F(LazyOpsTest, TestAdaptiveAvgPool3D) {
torch::Tensor input = torch::rand(
{9, 4, 56, 28, 28},
torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
for (int64_t output_size : {7, 4}) {
torch::Tensor output = torch::adaptive_avg_pool3d(
input, {output_size, output_size, output_size});
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor lazy_output = torch::adaptive_avg_pool3d(
lazy_input, {output_size, output_size, output_size});
AllClose(output, lazy_output);
});
}
}
TEST_F(LazyOpsTest, TestAdaptiveAvgPool3DNoBatch) {
torch::Tensor input = torch::rand(
{3, 56, 28, 28},
torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
for (int64_t output_size : {7, 4}) {
torch::Tensor output = torch::adaptive_avg_pool3d(
input, {output_size, output_size, output_size});
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor lazy_output = torch::adaptive_avg_pool3d(
lazy_input, {output_size, output_size, output_size});
AllClose(output, lazy_output);
});
}
}
TEST_F(LazyOpsTest, TestAdaptiveAvgPool2DNoBatch) {
torch::Tensor input = torch::rand(
{1, 56, 56}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
for (int64_t output_size : {7, 8}) {
torch::Tensor output =
torch::adaptive_avg_pool2d(input, {output_size, output_size});
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor lazy_output =
torch::adaptive_avg_pool2d(lazy_input, {output_size, output_size});
AllClose(output, lazy_output);
});
}
}
TEST_F(LazyOpsTest, TestMaxUnpool2D) {
int kernel_size = 2;
torch::Tensor input = torch::rand(
{2, 2, 8, 8},
torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
for (int stride = 1; stride <= 2; ++stride) {
for (int padding = 0; padding <= 1; ++padding) {
// Test ceil_mode=true through the CPU interop.
for (bool ceil_mode : {false, true}) {
// Test dilation through the CPU interop.
for (int dilation = 1; dilation <= 2; ++dilation) {
torch::Tensor output;
torch::Tensor indices;
std::tie(output, indices) = torch::max_pool2d_with_indices(
input,
/*kernel_size=*/{kernel_size, kernel_size},
/*stride=*/{stride, stride},
/*padding=*/{padding, padding},
/*dilation=*/{dilation, dilation},
/*ceil_mode=*/ceil_mode);
std::vector<int64_t> output_size({input.size(2), input.size(3)});
at::Tensor utensor =
torch::max_unpool2d(output, indices, output_size);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_output = CopyToDevice(output, device);
torch::Tensor lazy_indices = CopyToDevice(indices, device);
at::Tensor lazy_utensor =
torch::max_unpool2d(lazy_output, lazy_indices, output_size);
AllClose(utensor, lazy_utensor);
});
}
}
}
}
}
TEST_F(LazyOpsTest, TestMaxUnpool3D) {
int kernel_size = 2;
torch::Tensor input = torch::rand(
{1, 1, 4, 4, 4},
torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
for (int stride = 1; stride <= 2; ++stride) {
for (int padding = 0; padding <= 1; ++padding) {
// Test ceil_mode=true through the CPU interop.
for (bool ceil_mode : {false, true}) {
// Test dilation through the CPU interop.
for (int dilation = 1; dilation <= 2; ++dilation) {
torch::Tensor output;
torch::Tensor indices;
std::tie(output, indices) = torch::max_pool3d_with_indices(
input,
/*kernel_size=*/{kernel_size, kernel_size, kernel_size},
/*stride=*/{stride, stride, stride},
/*padding=*/{padding, padding, padding},
/*dilation=*/{dilation, dilation, dilation},
/*ceil_mode=*/ceil_mode);
std::vector<int64_t> output_size(
{input.size(2), input.size(3), input.size(4)});
at::Tensor utensor = torch::max_unpool3d(
output,
indices,
output_size,
/*stride=*/{stride, stride, stride},
/*padding=*/{padding, padding, padding});
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_output = CopyToDevice(output, device);
torch::Tensor lazy_indices = CopyToDevice(indices, device);
at::Tensor lazy_utensor = torch::max_unpool3d(
lazy_output,
lazy_indices,
output_size,
/*stride=*/{stride, stride, stride},
/*padding=*/{padding, padding, padding});
AllClose(utensor, lazy_utensor);
});
}
}
}
}
}
TEST_F(LazyOpsTest, TestNllLoss) {
// TODO(whc) debug divide-by-zero failure under ASAN
GTEST_SKIP();
int batch = 6;
int classes = 2;
// TODO(asuhan): Fix the torch::kDouble case.
for (auto dtype : {torch::kFloat}) {
for (int ignore_index : {-1, 0, 1, 5}) {
for (bool def_weight : {false, true}) {
torch::Tensor input = torch::rand(
{batch, classes},
torch::TensorOptions(dtype).device(DefaultDevice()));
torch::Tensor target = torch::randint(
std::min(ignore_index, 0),
classes,
{batch},
torch::TensorOptions(torch::kLong).device(DefaultDevice()));
torch::Tensor weight;
if (def_weight) {
weight = torch::rand(
{classes}, torch::TensorOptions(dtype).device(DefaultDevice()));
}
for (torch::Reduction::Reduction reduction :
{torch::Reduction::Mean,
torch::Reduction::Sum,
torch::Reduction::None}) {
torch::Tensor output = torch::nll_loss(
/*self=*/input,
/*target=*/target,
/*weight=*/weight,
/*reduction=*/reduction,
/*ignore_index=*/ignore_index);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor lazy_target = CopyToDevice(target, device);
torch::Tensor lazy_weight =
def_weight ? CopyToDevice(weight, device) : torch::Tensor();
torch::Tensor lazy_output = torch::nll_loss(
/*self=*/lazy_input,
/*target=*/lazy_target,
/*weight=*/lazy_weight,
/*reduction=*/reduction,
/*ignore_index=*/ignore_index);
AllClose(output, lazy_output);
});
}
}
}
}
}
TEST_F(LazyOpsTest, TestNllLoss2d) {
int batch = 6;
int classes = 2;
int height = 3;
int width = 3;
// TODO(asuhan): Fix the torch::kDouble case.
for (auto dtype : {torch::kFloat}) {
for (int ignore_index : {-1, 0, 1, 5}) {
for (bool def_weight : {false, true}) {
torch::Tensor input = torch::rand(
{batch, classes, height, width},
torch::TensorOptions(dtype).device(DefaultDevice()));
torch::Tensor target = torch::randint(
std::min(ignore_index, 0),
classes,
{batch, height, width},
torch::TensorOptions(torch::kLong).device(DefaultDevice()));
torch::Tensor weight;
if (def_weight) {
weight = torch::rand(
{classes}, torch::TensorOptions(dtype).device(DefaultDevice()));
}
for (torch::Reduction::Reduction reduction :
{torch::Reduction::Mean,
torch::Reduction::Sum,
torch::Reduction::None}) {
torch::Tensor output = torch::nll_loss2d(
/*self=*/input,
/*target=*/target,
/*weight=*/weight,
/*reduction=*/reduction,
/*ignore_index=*/ignore_index);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor lazy_target = CopyToDevice(target, device);
torch::Tensor lazy_weight =
def_weight ? CopyToDevice(weight, device) : torch::Tensor();
torch::Tensor lazy_output = torch::nll_loss2d(
/*self=*/lazy_input,
/*target=*/lazy_target,
/*weight=*/lazy_weight,
/*reduction=*/reduction,
/*ignore_index=*/ignore_index);
AllClose(output, lazy_output);
});
}
}
}
}
}
TEST_F(LazyOpsTest, TestSmoothL1Loss) {
torch::Tensor input = torch::randn(
{2, 4}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor target = torch::randn(
{2, 4}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
for (torch::Reduction::Reduction reduction :
{torch::Reduction::None,
torch::Reduction::Mean,
torch::Reduction::Sum}) {
for (double beta : {0.25, 1.}) {
torch::Tensor output =
torch::smooth_l1_loss(input, target, reduction, beta);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor lazy_target = CopyToDevice(target, device);
torch::Tensor lazy_output =
torch::smooth_l1_loss(lazy_input, lazy_target, reduction, beta);
AllClose(output, lazy_output);
});
}
}
}
TEST_F(LazyOpsTest, TestL1Loss) {
torch::Tensor input = torch::randn(
{2, 4}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor target = torch::randn(
{2, 4}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
for (torch::Reduction::Reduction reduction :
{torch::Reduction::None,
torch::Reduction::Mean,
torch::Reduction::Sum}) {
torch::Tensor output = torch::l1_loss(input, target, reduction);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor lazy_target = CopyToDevice(target, device);
torch::Tensor lazy_output =
torch::l1_loss(lazy_input, lazy_target, reduction);
AllClose(output, lazy_output);
});
}
}
TEST_F(LazyOpsTest, TestL1LossBackward) {
for (torch::Reduction::Reduction reduction :
{torch::Reduction::None,
torch::Reduction::Mean,
torch::Reduction::Sum}) {
auto testfn =
[&](const std::vector<torch::Tensor>& inputs) -> torch::Tensor {
return torch::l1_loss(inputs[0], inputs[1], reduction);
};
ForEachDevice([&](const torch::Device& device) {
TestBackward(
{torch::rand(
{2, 4},
torch::TensorOptions(torch::kFloat)
.device(DefaultDevice())
.requires_grad(true)),
torch::rand(
{2, 4},
torch::TensorOptions(torch::kFloat).device(DefaultDevice()))},
device,
testfn);
});
}
}
TEST_F(LazyOpsTest, TestMseLoss) {
torch::Tensor input = torch::randn(
{2, 4}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor target = torch::randn(
{2, 4}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
for (torch::Reduction::Reduction reduction :
{torch::Reduction::None,
torch::Reduction::Mean,
torch::Reduction::Sum}) {
torch::Tensor output = torch::mse_loss(input, target, reduction);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor lazy_target = CopyToDevice(target, device);
torch::Tensor lazy_output =
torch::mse_loss(lazy_input, lazy_target, reduction);
AllClose(output, lazy_output);
});
}
}
TEST_F(LazyOpsTest, TestMseLossBackward) {
for (torch::Reduction::Reduction reduction :
{torch::Reduction::None,
torch::Reduction::Mean,
torch::Reduction::Sum}) {
auto testfn =
[&](const std::vector<torch::Tensor>& inputs) -> torch::Tensor {
return torch::mse_loss(inputs[0], inputs[1], reduction);
};
ForEachDevice([&](const torch::Device& device) {
TestBackward(
{torch::rand(
{2, 4},
torch::TensorOptions(torch::kFloat)
.device(DefaultDevice())
.requires_grad(true)),
torch::rand(
{2, 4},
torch::TensorOptions(torch::kFloat).device(DefaultDevice()))},
device,
testfn);
});
}
}
TEST_F(LazyOpsTest, TestBatchNorm1D) {
int num_features = 3;
torch::Tensor input = torch::rand(
{2, num_features, 4},
torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor weight = torch::rand(
{num_features},
torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor bias = torch::rand(
{num_features},
torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor running_mean = torch::zeros(
{num_features},
torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor running_var = torch::ones(
{num_features},
torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
double momentum = 0.1;
double eps = 0.5;
torch::Tensor undef;
for (bool training : {true, false}) {
for (bool undef_weight_bias : {false, true}) {
torch::Tensor output = torch::batch_norm(
/*input=*/input,
/*weight=*/undef_weight_bias ? undef : weight,
/*bias=*/undef_weight_bias ? undef : bias,
/*running_mean=*/running_mean,
/*running_var=*/running_var,
/*training=*/training,
/*momentum=*/momentum,
/*eps=*/eps,
/*cudnn_enabled=*/false);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor lazy_weight =
undef_weight_bias ? undef : CopyToDevice(weight, device);
torch::Tensor lazy_bias =
undef_weight_bias ? undef : CopyToDevice(bias, device);
torch::Tensor lazy_running_mean = CopyToDevice(running_mean, device);
torch::Tensor lazy_running_var = CopyToDevice(running_var, device);
torch::Tensor lazy_output = torch::batch_norm(
/*input=*/lazy_input,
/*weight=*/lazy_weight,
/*bias=*/lazy_bias,
/*running_mean=*/lazy_running_mean,
/*running_var=*/lazy_running_var,
/*training=*/training,
/*momentum=*/momentum,
/*eps=*/eps,
/*cudnn_enabled=*/false);
AllClose(output, lazy_output, /*rtol=*/1e-3, /*atol=*/1e-5);
});
}
}
}
TEST_F(LazyOpsTest, TestBatchNorm2D) {
int num_features = 3;
torch::Tensor input = torch::rand(
{2, num_features, 4, 4},
torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor weight = torch::rand(
{num_features},
torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor bias = torch::rand(
{num_features},
torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor running_mean = torch::zeros(
{num_features},
torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor running_var = torch::ones(
{num_features},
torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
double momentum = 0.1;
double eps = 0.5;
torch::Tensor undef;
for (bool training : {true, false}) {
for (bool undef_weight_bias : {false, true}) {
torch::Tensor output = torch::batch_norm(
/*input=*/input,
/*weight=*/undef_weight_bias ? undef : weight,
/*bias=*/undef_weight_bias ? undef : bias,
/*running_mean=*/running_mean,
/*running_var=*/running_var,
/*training=*/training,
/*momentum=*/momentum,
/*eps=*/eps,
/*cudnn_enabled=*/false);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor lazy_weight =
undef_weight_bias ? undef : CopyToDevice(weight, device);
torch::Tensor lazy_bias =
undef_weight_bias ? undef : CopyToDevice(bias, device);
torch::Tensor lazy_running_mean = CopyToDevice(running_mean, device);
torch::Tensor lazy_running_var = CopyToDevice(running_var, device);
torch::Tensor lazy_output = torch::batch_norm(
/*input=*/lazy_input,
/*weight=*/lazy_weight,
/*bias=*/lazy_bias,
/*running_mean=*/lazy_running_mean,
/*running_var=*/lazy_running_var,
/*training=*/training,
/*momentum=*/momentum,
/*eps=*/eps,
/*cudnn_enabled=*/false);
AllClose(output, lazy_output, /*rtol=*/1e-3, /*atol=*/1e-5);
});
}
}
}
TEST_F(LazyOpsTest, TestDim) {
torch::Tensor input = torch::rand(
{2, 3}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
EXPECT_EQ(input.dim(), lazy_input.dim());
});
}
TEST_F(LazyOpsTest, TestContiguous) {
torch::Tensor input = torch::rand(
{2, 3}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor output = torch::native::contiguous(input);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor lazy_output = torch::native::contiguous(lazy_input);
AllClose(output, lazy_output);
});
}
TEST_F(LazyOpsTest, TestSqueezeAll) {
torch::Tensor input = torch::rand(
{2, 1, 3, 1},
torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor output = torch::squeeze(input);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor lazy_output = torch::squeeze(lazy_input);
AllClose(output, lazy_output);
});
}
TEST_F(LazyOpsTest, TestSqueezeAllInPlace) {
ForEachDevice([&](const torch::Device& device) {
torch::Tensor input = torch::rand(
{2, 1, 3, 1},
torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor output = input.squeeze_();
torch::Tensor lazy_output = lazy_input.squeeze_();
AllClose(output, lazy_output);
AllClose(input, lazy_input);
ASSERT_EQ(input.dim(), lazy_input.dim());
for (int64_t dim_idx = 0; dim_idx < input.dim(); ++dim_idx) {
ASSERT_EQ(input.size(dim_idx), lazy_input.size(dim_idx));
}
});
}
TEST_F(LazyOpsTest, TestSqueezeOne) {
torch::Tensor input = torch::rand(
{2, 1, 3, 1},
torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
int rank = input.dim();
for (int dim = -rank; dim < rank; ++dim) {
torch::Tensor output = torch::squeeze(input, dim);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor lazy_output = torch::squeeze(lazy_input, dim);
AllClose(output, lazy_output);
});
}
}
TEST_F(LazyOpsTest, TestSqueezeOneInPlace) {
int rank = 4;
for (int dim = -rank; dim < rank; ++dim) {
ForEachDevice([&](const torch::Device& device) {
torch::Tensor input = torch::rand(
{2, 1, 3, 1},
torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor output = input.squeeze_(dim);
torch::Tensor lazy_output = lazy_input.squeeze_(dim);
AllClose(output, lazy_output);
AllClose(input, lazy_input);
ASSERT_EQ(input.dim(), lazy_input.dim());
for (int64_t dim_idx = 0; dim_idx < input.dim(); ++dim_idx) {
ASSERT_EQ(input.size(dim_idx), lazy_input.size(dim_idx));
}
});
}
}
TEST_F(LazyOpsTest, TestUnsqueeze) {
torch::Tensor input = torch::rand(
{2, 3}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
int rank = input.dim() + 1;
for (int dim = -rank; dim < rank; ++dim) {
torch::Tensor output = torch::unsqueeze(input, dim);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor lazy_output = torch::unsqueeze(lazy_input, dim);
AllClose(output, lazy_output);
});
}
}
TEST_F(LazyOpsTest, TestUnsqueezeInPlace) {
torch::Tensor input = torch::rand(
{2, 3}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
int rank = input.dim() + 1;
for (int dim = -rank; dim < rank; ++dim) {
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor output = input.unsqueeze_(dim);
torch::Tensor lazy_output = lazy_input.unsqueeze_(dim);
AllClose(output, lazy_output);
AllClose(input, lazy_input);
ASSERT_EQ(input.dim(), lazy_input.dim());
for (int64_t dim_idx = 0; dim_idx < input.dim(); ++dim_idx) {
ASSERT_EQ(input.size(dim_idx), lazy_input.size(dim_idx));
}
});
}
}
TEST_F(LazyOpsTest, TestMaskedFill) {
torch::Tensor input = torch::rand(
{2, 3}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor mask = torch::randint(
0, 2, {2, 3}, torch::TensorOptions(torch::kBool).device(DefaultDevice()));
torch::Scalar value(42);
torch::Tensor result = torch::masked_fill(input, mask, value);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor lazy_mask = CopyToDevice(mask, device);
torch::Tensor lazy_result =
torch::masked_fill(lazy_input, lazy_mask, value);
AllClose(result, lazy_result);
});
}
TEST_F(LazyOpsTest, TestMaskedFillInPlace) {
torch::Scalar value(42);
torch::Tensor mask = torch::randint(
0, 2, {2, 3}, torch::TensorOptions(torch::kBool).device(DefaultDevice()));
ForEachDevice([&](const torch::Device& device) {
torch::Tensor input = torch::rand(
{2, 3}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor lazy_mask = CopyToDevice(mask, device);
torch::Tensor result = input.masked_fill_(mask, value);
torch::Tensor lazy_result = lazy_input.masked_fill_(lazy_mask, value);
AllClose(result, lazy_result);
AllClose(input, lazy_input);
});
}
TEST_F(LazyOpsTest, TestMaskedFillBroadcast) {
torch::Tensor input = torch::rand(
{2, 5, 4, 3},
torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor mask = torch::randint(
0, 2, {4, 1}, torch::TensorOptions(torch::kBool).device(DefaultDevice()));
torch::Scalar value(42);
torch::Tensor result = torch::masked_fill(input, mask, value);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor lazy_mask = CopyToDevice(mask, device);
torch::Tensor lazy_result =
torch::masked_fill(lazy_input, lazy_mask, value);
AllClose(result, lazy_result);
});
}
TEST_F(LazyOpsTest, TestFill) {
torch::Scalar value(42);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor input = torch::empty(
{2, 3}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor result = torch::fill_(input, value);
torch::Tensor lazy_result = torch::fill_(lazy_input, value);
AllClose(result, lazy_result);
AllClose(input, lazy_input);
});
}
TEST_F(LazyOpsTest, TestFillWithRank0) {
torch::Tensor value = torch::scalar_tensor(42);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor input = torch::empty(
{2, 3}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor result = torch::fill_(input, value);
torch::Tensor lazy_value = CopyToDevice(value, device);
torch::Tensor lazy_result = torch::fill_(lazy_input, value);
AllClose(result, lazy_result);
AllClose(input, lazy_input);
});
}
TEST_F(LazyOpsTest, TestPermute) {
torch::Tensor input = torch::rand(
{2, 3, 4}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
std::vector<std::vector<int64_t>> dims_permutations = {
{0, 1, 2}, {0, 2, 1}, {1, 0, 2}, {1, 2, 0}, {2, 0, 1}, {2, 1, 0}};
int rank = input.dim();
for (std::vector<int64_t> dims_permutation : dims_permutations) {
for (bool negative_dims : {false, true}) {
if (negative_dims) {
std::for_each(
dims_permutation.begin(),
dims_permutation.end(),
[rank](int64_t& dim) { dim -= rank; });
}
torch::Tensor output = input.permute(dims_permutation);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor lazy_output = lazy_input.permute(dims_permutation);
AllClose(output, lazy_output);
});
}
}
}
TEST_F(LazyOpsTest, TestPermuteMod) {
std::vector<std::vector<int64_t>> dims_permutations = {
{0, 1, 2}, {0, 2, 1}, {1, 0, 2}, {1, 2, 0}, {2, 0, 1}, {2, 1, 0}};
std::vector<int64_t> input_sizes = {2, 3, 4};
int rank = input_sizes.size();
for (std::vector<int64_t> dims_permutation : dims_permutations) {
for (bool negative_dims : {false, true}) {
if (negative_dims) {
std::for_each(
dims_permutation.begin(),
dims_permutation.end(),
[rank](int64_t& dim) { dim -= rank; });
}
torch::Tensor input = torch::zeros(
input_sizes,
torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor one = torch::tensor(
1.0, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor output = input.permute(dims_permutation);
output.add_(one, 1.0);
input.add_(one, 1.0);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor xinput = torch::zeros(
input_sizes,
torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor lazy_input = CopyToDevice(xinput, device);
torch::Tensor lazy_one = CopyToDevice(one, device);
torch::Tensor lazy_output = lazy_input.permute(dims_permutation);
lazy_output.add_(lazy_one, 1.0);
lazy_input.add_(lazy_one, 1.0);
AllClose(output, lazy_output);
AllClose(input, lazy_input);
});
}
}
}
TEST_F(LazyOpsTest, TestFlip) {
torch::Tensor input = torch::rand(
{2, 3, 4}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
std::vector<std::vector<int64_t>> dim_powerset = {
{0}, {1}, {2}, {0, 1}, {1, 2}, {2, 0}, {0, 1, 2}};
for (std::vector<int64_t> flip_dims : dim_powerset) {
for (bool negative_dims : {false, true}) {
if (negative_dims) {
std::for_each(
flip_dims.begin(), flip_dims.end(), [](int64_t& dim) { dim -= 3; });
}
torch::Tensor output = torch::flip(input, flip_dims);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor lazy_output = torch::flip(lazy_input, flip_dims);
AllClose(output, lazy_output);
});
}
}
}
TEST_F(LazyOpsTest, TestPixelShuffle) {
torch::Tensor input = torch::rand(
{5, 18, 4, 4},
torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
int upscale_factor = 3;
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor output = torch::pixel_shuffle(input, upscale_factor);
torch::Tensor lazy_output =
torch::pixel_shuffle(lazy_input, upscale_factor);
AllClose(output, lazy_output);
});
}
TEST_F(LazyOpsTest, TestSumToSize) {
torch::Tensor input = torch::rand(
{4, 6, 3, 7},
torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
std::vector<int64_t> out_size = {4, 1, 1, 7};
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor output = input.sum_to_size(out_size);
torch::Tensor lazy_output = lazy_input.sum_to_size(out_size);
AllClose(output, lazy_output);
});
}
TEST_F(LazyOpsTest, TestTransposeDims) {
torch::Tensor input = torch::rand(
{2, 3, 4}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
int dim0 = 0;
int dim1 = 2;
torch::Tensor output = torch::transpose(input, dim0, dim1);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor lazy_output = torch::transpose(lazy_input, dim0, dim1);
AllClose(output, lazy_output);
});
}
TEST_F(LazyOpsTest, TestTransposeDimsMod) {
std::vector<int64_t> input_sizes = {2, 3, 4};
int dim0 = 0;
int dim1 = 2;
torch::Tensor input = torch::zeros(
input_sizes, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor one = torch::tensor(
1.0, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor output = torch::transpose(input, dim0, dim1);
output.add_(one, 1.0);
input.add_(one, 1.0);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor xinput = torch::zeros(
input_sizes,
torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor lazy_input = CopyToDevice(xinput, device);
torch::Tensor lazy_one = CopyToDevice(one, device);
torch::Tensor lazy_output = torch::transpose(lazy_input, dim0, dim1);
lazy_output.add_(lazy_one, 1.0);
lazy_input.add_(lazy_one, 1.0);
AllClose(output, lazy_output);
AllClose(input, lazy_input);
});
}
TEST_F(LazyOpsTest, TestTransposeDimsInPlace) {
torch::Tensor input = torch::rand(
{2, 3, 4}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
int dim0 = 0;
int dim1 = 2;
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor output = input.transpose_(dim0, dim1);
torch::Tensor lazy_output = lazy_input.transpose_(dim0, dim1);
AllClose(output, lazy_output);
AllClose(input, lazy_input);
});
}
TEST_F(LazyOpsTest, TestSplit) {
torch::Tensor input = torch::rand(
{7, 8, 9}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
int rank = input.dim();
for (int split_size : {2, 3}) {
for (int dim = -rank; dim < rank; ++dim) {
std::vector<torch::Tensor> outputs = torch::split(input, split_size, dim);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
std::vector<torch::Tensor> lazy_outputs =
torch::split(lazy_input, split_size, dim);
ASSERT_EQ(outputs.size(), lazy_outputs.size());
for (size_t i = 0; i < outputs.size(); ++i) {
AllClose(outputs[i], lazy_outputs[i]);
}
});
}
}
}
TEST_F(LazyOpsTest, TestSplitEmpty) {
torch::Tensor input = torch::rand(
{0}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
int split_size = 0;
int dim = 0;
std::vector<torch::Tensor> outputs = torch::split(input, split_size, dim);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
std::vector<torch::Tensor> lazy_outputs =
torch::split(lazy_input, split_size, dim);
ASSERT_EQ(outputs.size(), lazy_outputs.size());
for (size_t i = 0; i < outputs.size(); ++i) {
AllClose(outputs[i], lazy_outputs[i]);
}
});
}
TEST_F(LazyOpsTest, TestSplitWithSizes) {
torch::Tensor input = torch::rand(
{15, 15, 15},
torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
int rank = input.dim();
for (int dim = -rank; dim < rank; ++dim) {
std::vector<torch::Tensor> outputs =
torch::split_with_sizes(input, {4, 5, 6}, dim);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
std::vector<torch::Tensor> lazy_outputs =
torch::split_with_sizes(lazy_input, {4, 5, 6}, dim);
ASSERT_EQ(outputs.size(), lazy_outputs.size());
for (size_t i = 0; i < outputs.size(); ++i) {
AllClose(outputs[i], lazy_outputs[i]);
}
});
}
}
TEST_F(LazyOpsTest, TestCrossImplicitDim) {
std::vector<std::vector<int64_t>> dim_sizes = {
{4, 5, 3}, {4, 3, 5}, {3, 4, 5}};
for (auto dim_size : dim_sizes) {
torch::Tensor input = torch::rand(
dim_size, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor other = torch::rand(
dim_size, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor result = torch::cross(input, other);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor lazy_other = CopyToDevice(other, device);
torch::Tensor lazy_result = torch::cross(lazy_input, lazy_other);
AllClose(result, lazy_result);
});
}
}
TEST_F(LazyOpsTest, TestCrossExplicitDim) {
std::vector<int64_t> dim_size = {3, 3};
torch::Tensor input = torch::rand(
dim_size, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor other = torch::rand(
dim_size, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
int rank = dim_size.size();
for (int dim = -rank; dim < rank; ++dim) {
torch::Tensor result = torch::cross(input, other, dim);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor lazy_other = CopyToDevice(other, device);
torch::Tensor lazy_result = torch::cross(lazy_input, lazy_other, dim);
AllClose(result, lazy_result);
});
}
}
TEST_F(LazyOpsTest, TestCrossZeroDim) {
torch::Tensor input = torch::rand(
{0, 1, 3, 0},
torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor result = torch::cross(input, input);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor lazy_result = torch::cross(lazy_input, lazy_input);
AllClose(result, lazy_result);
});
}
TEST_F(LazyOpsTest, TestTriu) {
int size = 5;
torch::Tensor input = torch::rand(
{size, size},
torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
// Test all diagonals and out of bounds (must be no-op).
for (int diagonal = -size; diagonal <= size; ++diagonal) {
torch::Tensor output = torch::triu(input, diagonal);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor lazy_output = torch::triu(lazy_input, diagonal);
AllClose(output, lazy_output);
});
}
}
TEST_F(LazyOpsTest, TestTriuNonSquare) {
int size = 5;
torch::Tensor input = torch::rand(
{size, size + 1},
torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
// Test all diagonals and out of bounds (must be no-op).
for (int diagonal = -size; diagonal <= size; ++diagonal) {
torch::Tensor output = torch::triu(input, diagonal);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor lazy_output = torch::triu(lazy_input, diagonal);
AllClose(output, lazy_output);
});
}
}
TEST_F(LazyOpsTest, TestTriuBatch) {
int size = 5;
int batch_size = 3;
torch::Tensor input = torch::rand(
{batch_size, size, size},
torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
// Test all diagonals and out of bounds (must be no-op).
for (int diagonal = -size; diagonal <= size; ++diagonal) {
torch::Tensor output = torch::triu(input, diagonal);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor lazy_output = torch::triu(lazy_input, diagonal);
AllClose(output, lazy_output);
});
}
}
TEST_F(LazyOpsTest, TestTril) {
int size = 5;
torch::Tensor input = torch::rand(
{size, size},
torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
// Test all diagonals and out of bounds (must be no-op).
for (int diagonal = -size; diagonal <= size; ++diagonal) {
torch::Tensor output = torch::tril(input, diagonal);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor lazy_output = torch::tril(lazy_input, diagonal);
AllClose(output, lazy_output);
});
}
}
TEST_F(LazyOpsTest, TestTrilNonSquare) {
int size = 5;
torch::Tensor input = torch::rand(
{size, size + 1},
torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
// Test all diagonals and out of bounds (must be no-op).
for (int diagonal = -size; diagonal <= size; ++diagonal) {
torch::Tensor output = torch::tril(input, diagonal);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor lazy_output = torch::tril(lazy_input, diagonal);
AllClose(output, lazy_output);
});
}
}
TEST_F(LazyOpsTest, TestTrilBatch) {
int size = 5;
int batch_size = 3;
torch::Tensor input = torch::rand(
{batch_size, size, size},
torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
// Test all diagonals and out of bounds (must be no-op).
for (int diagonal = -size; diagonal <= size; ++diagonal) {
torch::Tensor output = torch::tril(input, diagonal);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor lazy_output = torch::tril(lazy_input, diagonal);
AllClose(output, lazy_output);
});
}
}
TEST_F(LazyOpsTest, TestTriuInPlace) {
int size = 5;
// Test all diagonals and out of bounds (must be no-op).
for (int diagonal = -size; diagonal <= size; ++diagonal) {
ForEachDevice([&](const torch::Device& device) {
torch::Tensor input = torch::rand(
{size, size},
torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor output = input.triu_(diagonal);
torch::Tensor lazy_output = lazy_input.triu_(diagonal);
AllClose(output, lazy_output);
AllClose(input, lazy_input);
});
}
}
TEST_F(LazyOpsTest, TestTrilInPlace) {
int size = 5;
// Test all diagonals and out of bounds (must be no-op).
for (int diagonal = -size; diagonal <= size; ++diagonal) {
ForEachDevice([&](const torch::Device& device) {
torch::Tensor input = torch::rand(
{size, size},
torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor output = input.tril_(diagonal);
torch::Tensor lazy_output = lazy_input.tril_(diagonal);
AllClose(output, lazy_output);
AllClose(input, lazy_input);
});
}
}
TEST_F(LazyOpsTest, TestTrace) {
int n = 5;
torch::Tensor input = torch::rand(
{n, n}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor output = torch::trace(input);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor lazy_output = torch::trace(lazy_input);
AllClose(output, lazy_output);
});
}
TEST_F(LazyOpsTest, TestTraceWide) {
int lines = 3;
int cols = 5;
torch::Tensor input = torch::rand(
{lines, cols},
torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor output = torch::trace(input);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor lazy_output = torch::trace(lazy_input);
AllClose(output, lazy_output);
});
}
TEST_F(LazyOpsTest, TestTraceNarrow) {
int lines = 5;
int cols = 3;
torch::Tensor input = torch::rand(
{lines, cols},
torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor output = torch::trace(input);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor lazy_output = torch::trace(lazy_input);
AllClose(output, lazy_output);
});
}
TEST_F(LazyOpsTest, TestDiagRank1) {
int size = 7;
torch::Tensor input = torch::rand(
{size}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
// Test all diagonals and out of bounds (must be no-op).
for (int diagonal = -2 * size; diagonal <= 2 * size; ++diagonal) {
torch::Tensor output = torch::diag(input, diagonal);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor lazy_output = torch::diag(lazy_input, diagonal);
AllClose(output, lazy_output);
});
}
}
TEST_F(LazyOpsTest, TestDiagRank2) {
int size = 7;
torch::Tensor input = torch::rand(
{size, size},
torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
// Test all diagonals and out of bounds (must be no-op).
for (int diagonal = -size; diagonal <= size; ++diagonal) {
torch::Tensor output = torch::diag(input, diagonal);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor lazy_output = torch::diag(lazy_input, diagonal);
AllClose(output, lazy_output);
});
}
}
TEST_F(LazyOpsTest, TestDiagFlat) {
torch::Tensor input = torch::rand(
{4, 3, 6, 7},
torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
for (int diagonal = -10; diagonal < 10; ++diagonal) {
torch::Tensor output = torch::diagflat(input, diagonal);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor lazy_output = torch::diagflat(lazy_input, diagonal);
AllClose(output, lazy_output);
});
}
}
TEST_F(LazyOpsTest, TestDiagonal) {
int size = 5;
torch::Tensor input = torch::rand(
{size, size},
torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
// Test all diagonals and out of bounds (must be no-op).
for (int diagonal = -size; diagonal <= size; ++diagonal) {
torch::Tensor output = torch::diagonal(input, diagonal);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor lazy_output = torch::diagonal(lazy_input, diagonal);
AllClose(output, lazy_output);
});
}
}
TEST_F(LazyOpsTest, TestDiagonalUpdate) {
int size = 5;
// Test all diagonals and out of bounds (must be no-op).
for (int diagonal = -size; diagonal <= size; ++diagonal) {
auto input = torch::rand(
{size, size},
torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
auto input_clone = input.clone();
auto output = torch::diagonal(input, diagonal);
output.add_(1);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input_clone, device);
torch::Tensor lazy_output = torch::diagonal(lazy_input, diagonal);
lazy_output.add_(1);
AllClose(output, lazy_output);
AllClose(input, lazy_input);
});
}
}
TEST_F(LazyOpsTest, TestDiagonalNonSquare) {
int size = 5;
torch::Tensor input = torch::rand(
{size, size + 1},
torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
// Test all diagonals and out of bounds (must be no-op).
for (int diagonal = -size; diagonal <= size; ++diagonal) {
torch::Tensor output = torch::diagonal(input, diagonal);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor lazy_output = torch::diagonal(lazy_input, diagonal);
AllClose(output, lazy_output);
});
}
}
TEST_F(LazyOpsTest, TestDiagonalBatch) {
int size = 5;
int batch_size = 3;
int dim1 = 1;
int dim2 = 2;
torch::Tensor input = torch::rand(
{batch_size, size, size},
torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
// Test all diagonals and out of bounds (must be no-op).
for (int diagonal = -size; diagonal <= size; ++diagonal) {
torch::Tensor output =
torch::diagonal(input, diagonal, /*dim1=*/dim1, /*dim1=*/dim2);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor lazy_output =
torch::diagonal(lazy_input, diagonal, /*dim1=*/dim1, /*dim1=*/dim2);
AllClose(output, lazy_output);
});
}
}
TEST_F(LazyOpsTest, TestFlatten) {
torch::Tensor input = torch::rand({4, 7, 5, 3});
int rank = input.dim();
for (int pos_start_dim = 0; pos_start_dim < rank; ++pos_start_dim) {
for (int pos_end_dim = pos_start_dim; pos_end_dim < rank; ++pos_end_dim) {
for (bool negative_start_dim : {false, true}) {
for (bool negative_end_dim : {false, true}) {
int start_dim =
negative_start_dim ? pos_start_dim - rank : pos_start_dim;
int end_dim = negative_end_dim ? pos_end_dim - rank : pos_end_dim;
torch::Tensor output = torch::flatten(input, start_dim, end_dim);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor lazy_output =
torch::flatten(lazy_input, start_dim, end_dim);
AllClose(output, lazy_output);
});
}
}
}
}
}
TEST_F(LazyOpsTest, TestLogicalAnd) {
for (torch::ScalarType scalar_type1 :
{torch::kFloat,
torch::kByte,
torch::kChar,
torch::kShort,
torch::kInt,
torch::kLong}) {
torch::Tensor lhs = isFloatingType(scalar_type1)
? torch::rand({3, 4}, torch::TensorOptions(scalar_type1))
: torch::randint(0, 100, {3, 4}, torch::TensorOptions(scalar_type1));
for (torch::ScalarType scalar_type2 :
{torch::kFloat,
torch::kByte,
torch::kChar,
torch::kShort,
torch::kInt,
torch::kLong}) {
torch::Tensor rhs = isFloatingType(scalar_type2)
? torch::rand({3, 4}, torch::TensorOptions(scalar_type2))
: torch::randint(1, 100, {3, 4}, torch::TensorOptions(scalar_type2));
torch::Tensor result = torch::logical_and(lhs, rhs);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_lhs = CopyToDevice(lhs, device);
torch::Tensor lazy_rhs = CopyToDevice(rhs, device);
torch::Tensor lazy_result = torch::logical_and(lazy_lhs, lazy_rhs);
AllEqual(result, lazy_result);
});
}
}
ExpectCounterNotChanged("aten::.*", GetIgnoredCounters());
ExpectCounterChanged("xla::logical_and_out", GetIgnoredCounters());
}
TEST_F(LazyOpsTest, TestBitwiseAnd) {
torch::Tensor lhs = torch::randint(
0,
std::numeric_limits<int32_t>::max(),
{4, 2},
torch::TensorOptions(torch::kInt));
torch::Tensor rhs = torch::randint(
0,
std::numeric_limits<int32_t>::max(),
{4, 2},
torch::TensorOptions(torch::kInt));
torch::Tensor result = lhs.__and__(rhs);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_lhs = CopyToDevice(lhs, device);
torch::Tensor lazy_rhs = CopyToDevice(rhs, device);
torch::Tensor lazy_result = lazy_lhs.__and__(lazy_rhs);
AllEqual(result, lazy_result);
});
}
TEST_F(LazyOpsTest, TestBitwiseAndInPlace) {
torch::Tensor lhs = torch::randint(
0,
std::numeric_limits<int32_t>::max(),
{4, 2},
torch::TensorOptions(torch::kInt));
torch::Tensor rhs = torch::randint(
0,
std::numeric_limits<int32_t>::max(),
{4, 2},
torch::TensorOptions(torch::kInt));
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_lhs = CopyToDevice(lhs, device);
torch::Tensor result = lhs.__iand__(rhs);
torch::Tensor lazy_rhs = CopyToDevice(rhs, device);
torch::Tensor lazy_result = lazy_lhs.__iand__(lazy_rhs);
AllEqual(result, lazy_result);
AllEqual(lhs, lazy_lhs);
});
}
TEST_F(LazyOpsTest, TestBitwiseAndScalar) {
torch::Tensor lhs = torch::randint(
0,
std::numeric_limits<int32_t>::max(),
{4, 2},
torch::TensorOptions(torch::kInt));
torch::Scalar rhs(123456789);
torch::Tensor result = lhs.__and__(rhs);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_lhs = CopyToDevice(lhs, device);
torch::Tensor lazy_result = lazy_lhs.__and__(rhs);
AllEqual(result, lazy_result);
});
}
TEST_F(LazyOpsTest, TestBitwiseAndScalarInPlace) {
torch::Tensor lhs = torch::randint(
0,
std::numeric_limits<int32_t>::max(),
{4, 2},
torch::TensorOptions(torch::kInt));
torch::Scalar rhs(123456789);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_lhs = CopyToDevice(lhs, device);
torch::Tensor result = lhs.__iand__(rhs);
torch::Tensor lazy_result = lazy_lhs.__iand__(rhs);
AllEqual(result, lazy_result);
AllEqual(lhs, lazy_lhs);
});
}
TEST_F(LazyOpsTest, TestBitwiseAndPromotion) {
torch::Tensor input = torch::rand(
{4, 2}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor view = input.reshape(-1);
torch::Tensor result = torch::__and__(view.gt(0), view.ne(0));
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor lazy_view = lazy_input.reshape(-1);
torch::Tensor lazy_result =
torch::__and__(lazy_view.gt(0), lazy_view.ne(0));
AllEqual(result, lazy_result);
});
}
TEST_F(LazyOpsTest, TestBitwiseOr) {
torch::Tensor lhs = torch::randint(
0,
std::numeric_limits<int32_t>::max(),
{4, 2},
torch::TensorOptions(torch::kInt));
torch::Tensor rhs = torch::randint(
0,
std::numeric_limits<int32_t>::max(),
{4, 2},
torch::TensorOptions(torch::kInt));
torch::Tensor result = lhs.__or__(rhs);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_lhs = CopyToDevice(lhs, device);
torch::Tensor lazy_rhs = CopyToDevice(rhs, device);
torch::Tensor lazy_result = lazy_lhs.__or__(lazy_rhs);
AllEqual(result, lazy_result);
});
}
TEST_F(LazyOpsTest, TestBitwiseOrInPlace) {
torch::Tensor lhs = torch::randint(
0,
std::numeric_limits<int32_t>::max(),
{4, 2},
torch::TensorOptions(torch::kInt));
torch::Tensor rhs = torch::randint(
0,
std::numeric_limits<int32_t>::max(),
{4, 2},
torch::TensorOptions(torch::kInt));
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_lhs = CopyToDevice(lhs, device);
torch::Tensor result = lhs.__ior__(rhs);
torch::Tensor lazy_rhs = CopyToDevice(rhs, device);
torch::Tensor lazy_result = lazy_lhs.__ior__(lazy_rhs);
AllEqual(result, lazy_result);
AllEqual(lhs, lazy_lhs);
});
}
TEST_F(LazyOpsTest, TestBitwiseOrScalar) {
torch::Tensor lhs = torch::randint(
0,
std::numeric_limits<int32_t>::max(),
{4, 2},
torch::TensorOptions(torch::kInt));
torch::Scalar rhs(123456789);
torch::Tensor result = lhs.__or__(rhs);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_lhs = CopyToDevice(lhs, device);
torch::Tensor lazy_result = lazy_lhs.__or__(rhs);
AllEqual(result, lazy_result);
});
}
TEST_F(LazyOpsTest, TestBitwiseOrScalarInPlace) {
torch::Tensor lhs = torch::randint(
0,
std::numeric_limits<int32_t>::max(),
{4, 2},
torch::TensorOptions(torch::kInt));
torch::Scalar rhs(123456789);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_lhs = CopyToDevice(lhs, device);
torch::Tensor result = lhs.__ior__(rhs);
torch::Tensor lazy_result = lazy_lhs.__ior__(rhs);
AllEqual(result, lazy_result);
AllEqual(lhs, lazy_lhs);
});
}
TEST_F(LazyOpsTest, TestBitwiseXor) {
torch::Tensor lhs = torch::randint(
0,
std::numeric_limits<int32_t>::max(),
{4, 2},
torch::TensorOptions(torch::kInt));
torch::Tensor rhs = torch::randint(
0,
std::numeric_limits<int32_t>::max(),
{4, 2},
torch::TensorOptions(torch::kInt));
torch::Tensor result = lhs.__xor__(rhs);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_lhs = CopyToDevice(lhs, device);
torch::Tensor lazy_rhs = CopyToDevice(rhs, device);
torch::Tensor lazy_result = lazy_lhs.__xor__(lazy_rhs);
AllEqual(result, lazy_result);
});
}
TEST_F(LazyOpsTest, TestBitwiseXorInPlace) {
torch::Tensor lhs = torch::randint(
0,
std::numeric_limits<int32_t>::max(),
{4, 2},
torch::TensorOptions(torch::kInt));
torch::Tensor rhs = torch::randint(
0,
std::numeric_limits<int32_t>::max(),
{4, 2},
torch::TensorOptions(torch::kInt));
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_lhs = CopyToDevice(lhs, device);
torch::Tensor result = lhs.__ixor__(rhs);
torch::Tensor lazy_rhs = CopyToDevice(rhs, device);
torch::Tensor lazy_result = lazy_lhs.__ixor__(lazy_rhs);
AllEqual(result, lazy_result);
AllEqual(lhs, lazy_lhs);
});
}
TEST_F(LazyOpsTest, TestBitwiseXorScalar) {
torch::Tensor lhs = torch::randint(
0,
std::numeric_limits<int32_t>::max(),
{4, 2},
torch::TensorOptions(torch::kInt));
torch::Scalar rhs(123456789);
torch::Tensor result = lhs.__xor__(rhs);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_lhs = CopyToDevice(lhs, device);
torch::Tensor lazy_result = lazy_lhs.__xor__(rhs);
AllEqual(result, lazy_result);
});
}
TEST_F(LazyOpsTest, TestBitwiseXorScalarInPlace) {
torch::Tensor lhs = torch::randint(
0,
std::numeric_limits<int32_t>::max(),
{4, 2},
torch::TensorOptions(torch::kInt));
torch::Scalar rhs(123456789);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_lhs = CopyToDevice(lhs, device);
torch::Tensor result = lhs.__ixor__(rhs);
torch::Tensor lazy_result = lazy_lhs.__ixor__(rhs);
AllEqual(result, lazy_result);
AllEqual(lhs, lazy_lhs);
});
}
TEST_F(LazyOpsTest, TestLshift) {
torch::Tensor input = torch::ones(
{4, 2}, torch::TensorOptions(torch::kInt32).device(DefaultDevice()));
torch::Tensor shift_amount = torch::randint(
16,
input.sizes(),
torch::TensorOptions(torch::kInt32).device(DefaultDevice()));
torch::Tensor result = torch::__lshift__(input, shift_amount);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor lazy_shift_amount = CopyToDevice(shift_amount, device);
torch::Tensor lazy_result =
torch::__lshift__(lazy_input, lazy_shift_amount);
AllClose(result, lazy_result);
});
}
TEST_F(LazyOpsTest, TestLshiftInPlace) {
torch::Tensor input = torch::ones(
{4, 2}, torch::TensorOptions(torch::kInt32).device(DefaultDevice()));
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor shift_amount = torch::randint(
16,
input.sizes(),
torch::TensorOptions(torch::kInt32).device(DefaultDevice()));
torch::Tensor result = input.__ilshift__(shift_amount);
torch::Tensor lazy_shift_amount = CopyToDevice(shift_amount, device);
torch::Tensor lazy_result = lazy_input.__ilshift__(lazy_shift_amount);
AllClose(result, lazy_result);
AllClose(input, lazy_input);
});
}
TEST_F(LazyOpsTest, TestLshiftScalar) {
torch::Tensor input = torch::ones(
{4, 2}, torch::TensorOptions(torch::kInt32).device(DefaultDevice()));
torch::Scalar shift_amount = 3;
torch::Tensor result = torch::__lshift__(input, shift_amount);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor lazy_result = torch::__lshift__(lazy_input, shift_amount);
AllClose(result, lazy_result);
});
}
TEST_F(LazyOpsTest, TestLshiftScalarInPlace) {
torch::Tensor input = torch::ones(
{4, 2}, torch::TensorOptions(torch::kInt32).device(DefaultDevice()));
torch::Scalar shift_amount = 3;
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor result = input.__ilshift__(shift_amount);
torch::Tensor lazy_result = lazy_input.__ilshift__(shift_amount);
AllClose(result, lazy_result);
AllClose(input, lazy_input);
});
}
TEST_F(LazyOpsTest, TestRshift) {
torch::Tensor input = torch::ones(
{4, 2}, torch::TensorOptions(torch::kInt32).device(DefaultDevice()));
torch::Tensor shift_amount = torch::randint(
16,
input.sizes(),
torch::TensorOptions(torch::kInt32).device(DefaultDevice()));
torch::Tensor result = torch::__rshift__(input, shift_amount);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor lazy_shift_amount = CopyToDevice(shift_amount, device);
torch::Tensor lazy_result =
torch::__rshift__(lazy_input, lazy_shift_amount);
AllClose(result, lazy_result);
});
}
TEST_F(LazyOpsTest, TestRshiftInPlace) {
torch::Tensor input = torch::ones(
{4, 2}, torch::TensorOptions(torch::kInt32).device(DefaultDevice()));
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor shift_amount = torch::randint(
16,
input.sizes(),
torch::TensorOptions(torch::kInt32).device(DefaultDevice()));
torch::Tensor result = input.__irshift__(shift_amount);
torch::Tensor lazy_shift_amount = CopyToDevice(shift_amount, device);
torch::Tensor lazy_result = lazy_input.__irshift__(lazy_shift_amount);
AllClose(result, lazy_result);
AllClose(input, lazy_input);
});
}
TEST_F(LazyOpsTest, TestRshiftScalar) {
torch::Tensor input = torch::ones(
{4, 2}, torch::TensorOptions(torch::kInt32).device(DefaultDevice()));
torch::Scalar shift_amount = 3;
torch::Tensor result = torch::__rshift__(input, shift_amount);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor lazy_result = torch::__rshift__(lazy_input, shift_amount);
AllClose(result, lazy_result);
});
}
TEST_F(LazyOpsTest, TestRshiftScalarInPlace) {
torch::Tensor input = torch::ones(
{4, 2}, torch::TensorOptions(torch::kInt32).device(DefaultDevice()));
torch::Scalar shift_amount = 3;
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor result = input.__irshift__(shift_amount);
torch::Tensor lazy_result = lazy_input.__irshift__(shift_amount);
AllClose(result, lazy_result);
AllClose(input, lazy_input);
});
}
TEST_F(LazyOpsTest, TestMeshgrid) {
torch::Tensor a = torch::rand(
{3}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor b = torch::rand(
{2}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor c = torch::rand(
{4}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
auto d = torch::meshgrid({a, b, c});
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_a = CopyToDevice(a, device);
torch::Tensor lazy_b = CopyToDevice(b, device);
torch::Tensor lazy_c = CopyToDevice(c, device);
auto lazy_d = torch::meshgrid({lazy_a, lazy_b, lazy_c});
EXPECT_EQ(d.size(), lazy_d.size());
for (size_t i = 0; i < d.size(); ++i) {
AllClose(d[i], lazy_d[i]);
}
});
}
TEST_F(LazyOpsTest, TestConstantPad) {
torch::Tensor input = torch::rand(
{4, 2, 5}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
std::vector<int64_t> pad{1, 2, 3, 4, 5, 6};
float pad_value = 5;
torch::Tensor output = torch::constant_pad_nd(input, pad, pad_value);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor lazy_output =
torch::constant_pad_nd(lazy_input, pad, pad_value);
AllClose(output, lazy_output);
});
}
TEST_F(LazyOpsTest, TestConstantPadIncomplete) {
torch::Tensor input = torch::rand(
{4, 2, 5}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
std::vector<int64_t> pad{1, 2};
float pad_value = 5;
torch::Tensor output = torch::constant_pad_nd(input, pad, pad_value);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor lazy_output =
torch::constant_pad_nd(lazy_input, pad, pad_value);
AllClose(output, lazy_output);
});
}
TEST_F(LazyOpsTest, TestReflectionPad2dRank3) {
torch::Tensor input = torch::rand(
{2, 3, 4}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
std::vector<int64_t> pad{2, 2, 2, 2};
torch::Tensor output = torch::reflection_pad2d(input, pad);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor lazy_output = torch::reflection_pad2d(lazy_input, pad);
AllClose(output, lazy_output);
});
}
TEST_F(LazyOpsTest, TestReflectionPad2dRank4) {
torch::Tensor input = torch::rand(
{2, 2, 3, 4},
torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
std::vector<int64_t> pad{2, 2, 2, 2};
torch::Tensor output = torch::reflection_pad2d(input, pad);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor lazy_output = torch::reflection_pad2d(lazy_input, pad);
AllClose(output, lazy_output);
});
}
TEST_F(LazyOpsTest, TestReflectionPad2dBackward) {
std::vector<int64_t> pad{2, 3, 1, 2};
auto testfn = [&](const std::vector<torch::Tensor>& inputs) -> torch::Tensor {
return torch::reflection_pad2d(inputs[0], pad);
};
ForEachDevice([&](const torch::Device& device) {
TestBackward(
{torch::rand(
{1, 2, 4, 4},
torch::TensorOptions(torch::kFloat)
.device(DefaultDevice())
.requires_grad(true))},
device,
testfn);
});
}
TEST_F(LazyOpsTest, TestReplicationPad1d) {
torch::Tensor input = torch::rand(
{1, 4}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
std::vector<int64_t> pad{1, 2};
torch::Tensor output = torch::replication_pad1d(input, pad);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor lazy_output = torch::replication_pad1d(lazy_input, pad);
AllClose(output, lazy_output);
});
}
TEST_F(LazyOpsTest, TestReplicationPad1dZeroPad) {
torch::Tensor input = torch::rand(
{1, 4}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
std::vector<int64_t> pad{1, 0};
torch::Tensor output = torch::replication_pad1d(input, pad);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor lazy_output = torch::replication_pad1d(lazy_input, pad);
AllClose(output, lazy_output);
});
}
TEST_F(LazyOpsTest, TestReplicationPad1dBackward) {
std::vector<int64_t> pad{2, 3};
auto testfn = [&](const std::vector<torch::Tensor>& inputs) -> torch::Tensor {
return torch::replication_pad1d(inputs[0], pad);
};
ForEachDevice([&](const torch::Device& device) {
TestBackward(
{torch::rand(
{2, 4},
torch::TensorOptions(torch::kFloat)
.device(DefaultDevice())
.requires_grad(true))},
device,
testfn);
});
}
TEST_F(LazyOpsTest, TestReplicationPad2d) {
torch::Tensor input = torch::rand(
{1, 3, 4}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
std::vector<int64_t> pad{1, 2, 2, 1};
torch::Tensor output = torch::replication_pad2d(input, pad);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor lazy_output = torch::replication_pad2d(lazy_input, pad);
AllClose(output, lazy_output);
});
}
TEST_F(LazyOpsTest, TestReplicationPad2dZeroPad) {
torch::Tensor input = torch::rand(
{1, 3, 4}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
std::vector<int64_t> pad{1, 0, 0, 1};
torch::Tensor output = torch::replication_pad2d(input, pad);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor lazy_output = torch::replication_pad2d(lazy_input, pad);
AllClose(output, lazy_output);
});
}
TEST_F(LazyOpsTest, TestReplicationPad2dBackward) {
std::vector<int64_t> pad{2, 3, 1, 1};
auto testfn = [&](const std::vector<torch::Tensor>& inputs) -> torch::Tensor {
return torch::replication_pad2d(inputs[0], pad);
};
ForEachDevice([&](const torch::Device& device) {
TestBackward(
{torch::rand(
{2, 3, 4},
torch::TensorOptions(torch::kFloat)
.device(DefaultDevice())
.requires_grad(true))},
device,
testfn);
});
}
TEST_F(LazyOpsTest, TestAsStrided) {
torch::Tensor input = torch::rand(
{128, 320}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
std::vector<int64_t> size = {128, 20, 4, 4};
std::vector<int64_t> stride = {320, 16, 4, 1};
torch::Tensor output =
torch::as_strided(input, /*size=*/size, /*stride=*/stride);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor lazy_output =
torch::as_strided(lazy_input, /*size=*/size, /*stride=*/stride);
AllClose(output, lazy_output);
});
}
TEST_F(LazyOpsTest, TestAsStridedInPlace) {
torch::Tensor input = torch::rand(
{128, 320}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
std::vector<int64_t> size = {128, 20, 4, 4};
std::vector<int64_t> stride = {320, 16, 4, 1};
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor output =
torch::as_strided_(input, /*size=*/size, /*stride=*/stride);
torch::Tensor lazy_output =
torch::as_strided_(lazy_input, /*size=*/size, /*stride=*/stride);
AllClose(output, lazy_output);
AllClose(input, lazy_input);
});
}
TEST_F(LazyOpsTest, TestAsStridedWithOffset) {
torch::Tensor input = torch::rand(
{4, 8, 2}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
std::vector<int64_t> size = {4, 4, 2};
std::vector<int64_t> stride = {8, 2, 1};
int64_t storage_offset = 4;
torch::Tensor output = torch::as_strided(
input,
/*size=*/size,
/*stride=*/stride,
/*storage_offset=*/storage_offset);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor lazy_output = torch::as_strided(
lazy_input,
/*size=*/size,
/*stride=*/stride,
/*storage_offset=*/storage_offset);
AllClose(output, lazy_output);
});
}
TEST_F(LazyOpsTest, TestAsStridedWithInplaceCopy) {
torch::Tensor grad = torch::ones(
{4}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
std::vector<int64_t> size = {4};
std::vector<int64_t> stride = {1};
torch::Tensor output = torch::zeros({4}, grad.options());
output.as_strided(size, stride).copy_(grad);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_grad = CopyToDevice(grad, device);
torch::Tensor lazy_output = torch::zeros({4}, lazy_grad.options());
lazy_output.as_strided(size, stride).copy_(lazy_grad);
AllClose(output, lazy_output);
});
}
TEST_F(LazyOpsTest, TestEmptyStrided) {
std::vector<int64_t> size = {4, 4, 2};
std::vector<int64_t> stride = {8, 2, 1};
torch::Tensor output = torch::empty_strided(/*size=*/size, /*stride=*/stride);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_output =
torch::empty_strided(/*size=*/size, /*stride=*/stride);
EXPECT_EQ(output.sizes(), lazy_output.sizes());
EXPECT_EQ(output.strides(), lazy_output.strides());
});
}
TEST_F(LazyOpsTest, TestAvgPool2DBackward) {
int kernel_size = 2;
for (int stride = 1; stride <= 2; ++stride) {
for (int padding = 0; padding <= 1; ++padding) {
for (bool count_include_pad : {true, false}) {
// Test ceil_mode=true through the CPU interop.
for (bool ceil_mode : {false, true}) {
auto testfn =
[&](const std::vector<torch::Tensor>& inputs) -> torch::Tensor {
return torch::avg_pool2d(
inputs[0],
/*kernel_size=*/{kernel_size, kernel_size},
/*stride=*/{stride, stride},
/*padding=*/{padding, padding},
/*ceil_mode=*/ceil_mode,
/*count_include_pad=*/count_include_pad);
};
ForEachDevice([&](const torch::Device& device) {
TestBackward(
{torch::rand(
{1, 1, 7, 7},
torch::TensorOptions(torch::kFloat)
.device(DefaultDevice())
.requires_grad(true))},
device,
testfn);
});
}
}
}
}
}
TEST_F(LazyOpsTest, TestAvgPool3DBackward) {
int kernel_size = 2;
for (int stride = 1; stride <= 2; ++stride) {
for (int padding = 0; padding <= 1; ++padding) {
for (bool count_include_pad : {true, false}) {
// Test ceil_mode=true through the CPU interop.
for (bool ceil_mode : {false, true}) {
auto testfn =
[&](const std::vector<torch::Tensor>& inputs) -> torch::Tensor {
return torch::avg_pool3d(
inputs[0],
/*kernel_size=*/{kernel_size, kernel_size, kernel_size},
/*stride=*/{stride, stride, stride},
/*padding=*/{padding, padding, padding},
/*ceil_mode=*/ceil_mode,
/*count_include_pad=*/count_include_pad);
};
ForEachDevice([&](const torch::Device& device) {
TestBackward(
{torch::rand(
{1, 1, 7, 7, 7},
torch::TensorOptions(torch::kFloat)
.device(DefaultDevice())
.requires_grad(true))},
device,
testfn);
});
}
}
}
}
}
TEST_F(LazyOpsTest, TestAvgPool2DNoBatchBackward) {
int kernel_size = 2;
for (int stride = 1; stride <= 2; ++stride) {
for (int padding = 0; padding <= 1; ++padding) {
for (bool count_include_pad : {true, false}) {
// Test ceil_mode=true through the CPU interop.
for (bool ceil_mode : {false, true}) {
auto testfn =
[&](const std::vector<torch::Tensor>& inputs) -> torch::Tensor {
return torch::avg_pool2d(
inputs[0],
/*kernel_size=*/{kernel_size, kernel_size},
/*stride=*/{stride, stride},
/*padding=*/{padding, padding},
/*ceil_mode=*/ceil_mode,
/*count_include_pad=*/count_include_pad);
};
ForEachDevice([&](const torch::Device& device) {
TestBackward(
{torch::rand(
{1, 7, 7},
torch::TensorOptions(torch::kFloat)
.device(DefaultDevice())
.requires_grad(true))},
device,
testfn);
});
}
}
}
}
}
TEST_F(LazyOpsTest, TestAvgPool3DNoBatchBackward) {
int kernel_size = 2;
for (int stride = 1; stride <= 2; ++stride) {
for (int padding = 0; padding <= 1; ++padding) {
for (bool count_include_pad : {true, false}) {
// Test ceil_mode=true through the CPU interop.
for (bool ceil_mode : {false, true}) {
auto testfn =
[&](const std::vector<torch::Tensor>& inputs) -> torch::Tensor {
return torch::avg_pool3d(
inputs[0],
/*kernel_size=*/{kernel_size, kernel_size, kernel_size},
/*stride=*/{stride, stride, stride},
/*padding=*/{padding, padding, padding},
/*ceil_mode=*/ceil_mode,
/*count_include_pad=*/count_include_pad);
};
ForEachDevice([&](const torch::Device& device) {
TestBackward(
{torch::rand(
{1, 7, 7, 7},
torch::TensorOptions(torch::kFloat)
.device(DefaultDevice())
.requires_grad(true))},
device,
testfn);
});
}
}
}
}
}
TEST_F(LazyOpsTest, TestAdaptiveAvgPool3DNoBatchBackward) {
if (IsCuda()) {
GTEST_SKIP();
}
for (int64_t output_size : {7, 4}) {
auto testfn =
[&](const std::vector<torch::Tensor>& inputs) -> torch::Tensor {
return torch::adaptive_avg_pool3d(
inputs[0], {output_size, output_size, output_size});
};
ForEachDevice([&](const torch::Device& device) {
TestBackward(
{torch::rand(
{1, 56, 28, 28},
torch::TensorOptions(torch::kFloat)
.device(DefaultDevice())
.requires_grad(true))},
device,
testfn);
});
}
}
TEST_F(LazyOpsTest, TestAdaptiveAvgPool3DBackward) {
if (IsCuda()) {
GTEST_SKIP();
}
for (int64_t output_size : {7, 4}) {
auto testfn =
[&](const std::vector<torch::Tensor>& inputs) -> torch::Tensor {
return torch::adaptive_avg_pool3d(
inputs[0], {output_size, output_size, output_size});
};
ForEachDevice([&](const torch::Device& device) {
TestBackward(
{torch::rand(
{4, 1, 56, 28, 28},
torch::TensorOptions(torch::kFloat)
.device(DefaultDevice())
.requires_grad(true))},
device,
testfn);
});
}
}
TEST_F(LazyOpsTest, TestAdaptiveAvgPool2DBackward) {
for (int64_t output_size : {7, 8}) {
auto testfn =
[&](const std::vector<torch::Tensor>& inputs) -> torch::Tensor {
return torch::adaptive_avg_pool2d(inputs[0], {output_size, output_size});
};
ForEachDevice([&](const torch::Device& device) {
TestBackward(
{torch::rand(
{4, 1, 56, 56},
torch::TensorOptions(torch::kFloat)
.device(DefaultDevice())
.requires_grad(true))},
device,
testfn);
});
}
}
TEST_F(LazyOpsTest, TestAdaptiveAvgPool2DNoBatchBackward) {
for (int64_t output_size : {7, 8}) {
auto testfn =
[&](const std::vector<torch::Tensor>& inputs) -> torch::Tensor {
return torch::adaptive_avg_pool2d(inputs[0], {output_size, output_size});
};
ForEachDevice([&](const torch::Device& device) {
TestBackward(
{torch::rand(
{1, 56, 56},
torch::TensorOptions(torch::kFloat).requires_grad(true))},
device,
testfn);
});
}
}
TEST_F(LazyOpsTest, TestConv2D) {
int in_channels = 4;
int out_channels = 4;
int kernel_size = 3;
for (int stride = 1; stride <= 3; ++stride) {
for (int padding = 0; padding <= 2; ++padding) {
for (bool with_bias : {true, false}) {
for (int dilation = 1; dilation <= 3; ++dilation) {
for (int groups :
{1, 2, 4}) { // covers normal, grouped, depthwise conv.
ForEachDevice([&](const torch::Device& device) {
torch::Tensor input = torch::rand(
{1, in_channels, 7, 7},
torch::TensorOptions(torch::kDouble).device(DefaultDevice()));
torch::Tensor weight = torch::rand(
{out_channels,
in_channels / groups,
kernel_size,
kernel_size},
torch::TensorOptions(torch::kDouble).device(DefaultDevice()));
torch::Tensor bias = with_bias
? torch::rand(
{out_channels},
torch::TensorOptions(torch::kDouble)
.device(DefaultDevice()))
: torch::Tensor();
torch::Tensor lazy_input = CopyToDevice(input, device);
torch::Tensor lazy_weight = CopyToDevice(weight, device);
torch::Tensor lazy_bias =
with_bias ? CopyToDevice(bias, device) : torch::Tensor();
torch::Tensor output = torch::conv2d(
input,
weight,
bias,
/*stride=*/{stride, stride},
/*padding=*/{padding, padding},
/*dilation=*/{dilation, dilation},
groups);
torch::Tensor lazy_output = torch::conv2d(
lazy_input,
lazy_weight,
lazy_bias,
/*stride=*/{stride, stride},
/*padding=*/{padding, padding},
/*dilation=*/{dilation, dilation},
groups);
AllClose(output, lazy_output);
});
}
}
}
}
}
}
TEST_F(LazyOpsTest, TestConv2DBackward) {
int in_channels = 4;
int out_channels = 4;
int kernel_size = 3;
for (int stride = 1; stride <= 3; ++stride) {
for (int padding = 0; padding <= 2; ++padding) {
for (bool with_bias : {true, false}) {
for (int dilation = 1; dilation <= 3; ++dilation) {
for (int groups :
{1, 2, 4}) { // covers normal, grouped, depthwise conv.
auto testfn =
[&](const std::vector<torch::Tensor>& inputs) -> torch::Tensor {
return torch::conv2d(
inputs[0],
inputs[1],
inputs[2],
/*stride=*/{stride, stride},
/*padding=*/{padding, padding},
/*dilation=*/{dilation, dilation},
groups);
};
ForEachDevice([&](const torch::Device& device) {
torch::Tensor bias = with_bias
? torch::rand(
{out_channels},
torch::TensorOptions(torch::kDouble)
.device(DefaultDevice()))
: torch::Tensor();
TestBackward(
{torch::rand(
{1, in_channels, 7, 7},
torch::TensorOptions(torch::kDouble)
.device(DefaultDevice())
.requires_grad(true)),
torch::rand(
{out_channels,
in_channels / groups,
kernel_size,
kernel_size},
torch::TensorOptions(torch::kDouble)
.device(DefaultDevice())
.requires_grad(true)),
bias},
device,
testfn);
});
}
};
}
}
}
}
TEST_F(LazyOpsTest, TestTransposedConv2DBackward) {
int in_channels = 4;
int out_channels = 4;
int kernel_size = 3;
for (int stride = 1; stride <= 2; ++stride) {
for (int padding = 0; padding <= 1; ++padding) {
for (int dilation = 1; dilation <= 2; ++dilation) {
for (int output_padding = 0;
output_padding < std::max(stride, dilation);
++output_padding) {
for (bool with_bias : {true, false}) {
for (int groups :
{1, 2, 4}) { // covers normal, grouped, depthwise conv.
auto testfn = [&](const std::vector<torch::Tensor>& inputs)
-> torch::Tensor {
return torch::conv_transpose2d(
inputs[0],
inputs[1],
inputs[2],
/*stride=*/{stride, stride + 1},
/*padding=*/{padding, padding + 1},
/*output_padding=*/output_padding,
/*groups=*/groups,
/*dilation=*/{dilation, dilation + 1});
};
ForEachDevice([&](const torch::Device& device) {
torch::Tensor input = torch::rand(
{4, out_channels, 7, 7},
torch::TensorOptions(torch::kFloat)
.device(DefaultDevice())
.requires_grad(true));
torch::Tensor weight = torch::rand(
{out_channels,
in_channels / groups,
kernel_size,
kernel_size},
torch::TensorOptions(torch::kFloat)
.device(DefaultDevice())
.requires_grad(true));
torch::Tensor bias = with_bias
? torch::rand(
{in_channels},
torch::TensorOptions(torch::kFloat)
.device(DefaultDevice())
.requires_grad(true))
: torch::Tensor();
TestBackward(
{input, weight, bias},
device,
testfn,
/*rtol=*/1e-5,
/*atol=*/1e-5);
});
}
};
}
}
}
}
}
TEST_F(LazyOpsTest, TestConv3DBackward) {
int in_channels = 4;
int out_channels = 4;
int kernel_size = 3;
for (int stride = 1; stride <= 3; ++stride) {
for (int padding = 1; padding <= 2; ++padding) {
for (bool with_bias : {true, false}) {
for (int dilation = 1; dilation <= 2; ++dilation) {
for (int groups :
{1, 2, 4}) { // covers normal, grouped, depthwise conv.
auto testfn =
[&](const std::vector<torch::Tensor>& inputs) -> torch::Tensor {
return torch::conv3d(
inputs[0],
inputs[1],
inputs[2],
/*stride=*/{stride, stride, stride},
/*padding=*/{padding, padding, padding},
/*dilation=*/{dilation, dilation, dilation},
groups);
};
ForEachDevice([&](const torch::Device& device) {
torch::Tensor bias = with_bias
? torch::rand(
{out_channels},
torch::TensorOptions(torch::kDouble)
.device(DefaultDevice()))
: torch::Tensor();
TestBackward(
{torch::rand(
{4, in_channels, 7, 7, 7},
torch::TensorOptions(torch::kDouble)
.device(DefaultDevice())
.requires_grad(true)),
torch::rand(
{out_channels,
in_channels / groups,
kernel_size,
kernel_size,
kernel_size},
torch::TensorOptions(torch::kDouble)
.device(DefaultDevice())
.requires_grad(true)),
bias},
device,
testfn);
});
}
};
}
}
}
}
TEST_F(LazyOpsTest, TestTransposedConv3DBackward) {
int in_channels = 4;
int out_channels = 4;
int kernel_size = 3;
for (int stride = 1; stride <= 2; ++stride) {
for (int padding = 0; padding <= 1; ++padding) {
for (int dilation = 1; dilation <= 2; ++dilation) {
for (int output_padding = 0;
output_padding < std::max(stride, dilation);
++output_padding) {
for (bool with_bias : {true, false}) {
for (int groups :
{1, 2, 4}) { // covers normal, grouped, depthwise conv.
auto testfn = [&](const std::vector<torch::Tensor>& inputs)
-> torch::Tensor {
return torch::conv_transpose3d(
inputs[0],
inputs[1],
inputs[2],
/*stride=*/{stride, stride + 1, stride},
/*padding=*/{padding, padding + 1, stride},
/*output_padding=*/output_padding,
/*groups=*/groups,
/*dilation=*/{dilation, dilation + 1, dilation});
};
ForEachDevice([&](const torch::Device& device) {
torch::Tensor input = torch::rand(
{4, out_channels, 7, 7, 7},
torch::TensorOptions(torch::kDouble)
.device(DefaultDevice())
.requires_grad(true));
torch::Tensor weight = torch::rand(
{out_channels,
in_channels / groups,
kernel_size,
kernel_size,
kernel_size},
torch::TensorOptions(torch::kDouble)
.device(DefaultDevice())
.requires_grad(true));
torch::Tensor bias = with_bias
? torch::rand(
{in_channels},
torch::TensorOptions(torch::kDouble)
.device(DefaultDevice())
.requires_grad(true))
: torch::Tensor();
TestBackward({input, weight, bias}, device, testfn);
});
}
};
}
}
}
}
}
TEST_F(LazyOpsTest, TestMaxPool2DBackward) {
int kernel_size = 3;
for (int stride = 1; stride <= 2; ++stride) {
for (int padding = 0; padding <= 1; ++padding) {
// Test ceil_mode=true through the CPU interop.
for (bool ceil_mode : {false, true}) {
auto testfn =
[&](const std::vector<torch::Tensor>& inputs) -> torch::Tensor {
return torch::max_pool2d(
inputs[0],
/*kernel_size=*/{kernel_size, kernel_size},
/*stride=*/{stride, stride},
/*padding=*/{padding, padding},
/*dilation=*/{1, 1},
/*ceil_mode=*/ceil_mode);
};
ForEachDevice([&](const torch::Device& device) {
TestBackward(
{torch::rand(
{1, 2, 8, 8},
torch::TensorOptions(torch::kFloat)
.device(DefaultDevice())
.requires_grad(true))},
device,
testfn);
});
}
}
}
}
TEST_F(LazyOpsTest, TestMaxPool3DBackward) {
int kernel_size = 3;
for (int stride = 1; stride <= 2; ++stride) {
for (int padding = 0; padding <= 1; ++padding) {
// Test ceil_mode=true through the CPU interop.
for (bool ceil_mode : {false, true}) {
auto testfn =
[&](const std::vector<torch::Tensor>& inputs) -> torch::Tensor {
return torch::max_pool3d(
inputs[0],
/*kernel_size=*/{kernel_size, kernel_size, kernel_size},
/*stride=*/{stride, stride, stride},
/*padding=*/{padding, padding, padding},
/*dilation=*/{1, 1, 1},
/*ceil_mode=*/ceil_mode);
};
ForEachDevice([&](const torch::Device& device) {
TestBackward(
{torch::rand(
{1, 2, 4, 4, 4},
torch::TensorOptions(torch::kFloat)
.device(DefaultDevice())
.requires_grad(true))},
device,
testfn);
});
}
}
}
}
TEST_F(LazyOpsTest, TestMaxPool2DNoBatchBackward) {
int kernel_size = 3;
for (int stride = 1; stride <= 2; ++stride) {
for (int padding = 0; padding <= 1; ++padding) {
// Test ceil_mode=true through the CPU interop.
for (bool ceil_mode : {false, true}) {
auto testfn =
[&](const std::vector<torch::Tensor>& inputs) -> torch::Tensor {
return torch::max_pool2d(
inputs[0],
/*kernel_size=*/{kernel_size, kernel_size},
/*stride=*/{stride, stride},
/*padding=*/{padding, padding},
/*dilation=*/{1, 1},
/*ceil_mode=*/ceil_mode);
};
ForEachDevice([&](const torch::Device& device) {
TestBackward(
{torch::rand(
{2, 8, 8},
torch::TensorOptions(torch::kFloat)
.device(DefaultDevice())
.requires_grad(true))},
device,
testfn);
});
}
}
}
}
TEST_F(LazyOpsTest, TestMaxPool3DNoBatchBackward) {
int kernel_size = 3;
for (int stride = 1; stride <= 2; ++stride) {
for (int padding = 0; padding <= 1; ++padding) {
// Test ceil_mode=true through the CPU interop.
for (bool ceil_mode : {false, true}) {
auto testfn =
[&](const std::vector<torch::Tensor>& inputs) -> torch::Tensor {
return torch::max_pool3d(
inputs[0],
/*kernel_size=*/{kernel_size, kernel_size, kernel_size},
/*stride=*/{stride, stride, stride},
/*padding=*/{padding, padding, padding},
/*dilation=*/{1, 1, 1},
/*ceil_mode=*/ceil_mode);
};
ForEachDevice([&](const torch::Device& device) {
TestBackward(
{torch::rand(
{2, 4, 4, 4},
torch::TensorOptions(torch::kFloat)
.device(DefaultDevice())
.requires_grad(true))},
device,
testfn);
});
}
}
}
}
TEST_F(LazyOpsTest, TestMaxUnpool2DBackward) {
int kernel_size = 2;
torch::Tensor input = torch::rand(
{2, 2, 8, 8},
torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
for (int stride = 1; stride <= 2; ++stride) {
for (int padding = 0; padding <= 1; ++padding) {
// Test ceil_mode=true through the CPU interop.
for (bool ceil_mode : {false, true}) {
for (int dilation = 1; dilation <= 2; ++dilation) {
torch::Tensor output;
torch::Tensor indices;
std::tie(output, indices) = torch::max_pool2d_with_indices(
input,
/*kernel_size=*/{kernel_size, kernel_size},
/*stride=*/{stride, stride},
/*padding=*/{padding, padding},
/*dilation=*/{dilation, dilation},
/*ceil_mode=*/ceil_mode);
std::vector<int64_t> output_size({input.size(2), input.size(3)});
auto testfn =
[&](const std::vector<torch::Tensor>& inputs) -> torch::Tensor {
return torch::max_unpool2d(inputs[0], inputs[1], output_size);
};
ForEachDevice([&](const torch::Device& device) {
TestBackward(
{output.requires_grad_(true), indices}, device, testfn);
});
}
}
}
}
}
TEST_F(LazyOpsTest, TestMaxUnpool3DBackward) {
int kernel_size = 2;
torch::Tensor input = torch::rand(
{1, 1, 4, 4, 4},
torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
for (int stride = 1; stride <= 2; ++stride) {
for (int padding = 0; padding <= 1; ++padding) {
// Test ceil_mode=true through the CPU interop.
for (bool ceil_mode : {false, true}) {
for (int dilation = 1; dilation <= 2; ++dilation) {
torch::Tensor output;
torch::Tensor indices;
std::tie(output, indices) = torch::max_pool3d_with_indices(
input,
/*kernel_size=*/{kernel_size, kernel_size, kernel_size},
/*stride=*/{stride, stride, stride},
/*padding=*/{padding, padding, padding},
/*dilation=*/{dilation, dilation, dilation},
/*ceil_mode=*/ceil_mode);
std::vector<int64_t> output_size(
{input.size(2), input.size(3), input.size(4)});
auto testfn =
[&](const std::vector<torch::Tensor>& inputs) -> torch::Tensor {
return torch::max_unpool3d(
inputs[0],
inputs[1],
output_size,
/*stride=*/{stride, stride, stride},
/*padding=*/{padding, padding, padding});
};
ForEachDevice([&](const torch::Device& device) {
TestBackward(
{output.requires_grad_(true), indices}, device, testfn);
});
}
}
}
}
}
TEST_F(LazyOpsTest, TestTanhBackward) {
auto testfn = [&](const std::vector<torch::Tensor>& inputs) -> torch::Tensor {
return torch::tanh(inputs[0]);
};
ForEachDevice([&](const torch::Device& device) {
TestBackward(
{torch::rand(
{2, 2},
torch::TensorOptions(torch::kFloat)
.device(DefaultDevice())
.requires_grad(true))},
device,
testfn,
/*rtol=*/1e-3,
/*atol=*/1e-5);
});
}
TEST_F(LazyOpsTest, TestSigmoidBackward) {
auto testfn = [&](const std::vector<torch::Tensor>& inputs) -> torch::Tensor {
return torch::sigmoid(inputs[0]);
};
ForEachDevice([&](const torch::Device& device) {
TestBackward(
{torch::rand(
{2, 2},
torch::TensorOptions(torch::kFloat)
.device(DefaultDevice())
.requires_grad(true))},
device,
testfn);
});
}
TEST_F(LazyOpsTest, TestLogSigmoidBackward) {
auto testfn = [&](const std::vector<torch::Tensor>& inputs) -> torch::Tensor {
return torch::log_sigmoid(inputs[0]);
};
ForEachDevice([&](const torch::Device& device) {
TestBackward(
{torch::rand(
{2, 2},
torch::TensorOptions(torch::kFloat)
.device(DefaultDevice())
.requires_grad(true))},
device,
testfn,
/*rtol=*/1e-3,
/*atol=*/1e-5);
});
}
TEST_F(LazyOpsTest, TestLogSoftmaxBackward) {
for (int dim = -4; dim < 4; ++dim) {
auto testfn =
[&](const std::vector<torch::Tensor>& inputs) -> torch::Tensor {
return torch::log_softmax(inputs[0], dim);
};
ForEachDevice([&](const torch::Device& device) {
TestBackward(
{torch::rand(
{5, 3, 4, 2},
torch::TensorOptions(torch::kFloat)
.device(DefaultDevice())
.requires_grad(true))},
device,
testfn,
/*rtol=*/1e-3,
/*atol=*/1e-4);
});
}
}
TEST_F(LazyOpsTest, TestSoftmaxBackward) {
for (int dim = -4; dim < 4; ++dim) {
auto testfn =
[&](const std::vector<torch::Tensor>& inputs) -> torch::Tensor {
return torch::softmax(inputs[0], dim);
};
ForEachDevice([&](const torch::Device& device) {
TestBackward(
{torch::rand(
{5, 3, 4, 2},
torch::TensorOptions(torch::kFloat)
.device(DefaultDevice())
.requires_grad(true))},
device,
testfn,
/*rtol=*/1e-3,
/*atol=*/1e-4);
});
}
}
TEST_F(LazyOpsTest, TestSoftplusBackward) {
auto testfn = [&](const std::vector<torch::Tensor>& inputs) -> torch::Tensor {
return torch::softplus(inputs[0]);
};
ForEachDevice([&](const torch::Device& device) {
TestBackward(
{torch::rand(
{2, 1, 4, 6},
torch::TensorOptions(torch::kFloat)
.device(DefaultDevice())
.requires_grad(true))},
device,
testfn,
/*rtol=*/1e-4);
});
}
TEST_F(LazyOpsTest, TestReluBackward) {
auto testfn = [&](const std::vector<torch::Tensor>& inputs) -> torch::Tensor {
return torch::relu(inputs[0]);
};
ForEachDevice([&](const torch::Device& device) {
TestBackward(
{torch::rand(
{2, 1, 4, 6},
torch::TensorOptions(torch::kFloat)
.device(DefaultDevice())
.requires_grad(true))},
device,
testfn);
});
}
TEST_F(LazyOpsTest, TestRreluBackward) {
auto testfn = [&](const std::vector<torch::Tensor>& inputs) -> torch::Tensor {
return torch::rrelu(inputs[0]);
};
ForEachDevice([&](const torch::Device& device) {
TestBackward(
{torch::rand(
{2, 1, 4, 6},
torch::TensorOptions(torch::kFloat)
.device(DefaultDevice())
.requires_grad(true))},
device,
testfn);
});
}
TEST_F(LazyOpsTest, TestHardshrinkBackward) {
auto testfn = [&](const std::vector<torch::Tensor>& inputs) -> torch::Tensor {
return torch::hardshrink(inputs[0]);
};
ForEachDevice([&](const torch::Device& device) {
TestBackward(
{torch::randn(
{100},
torch::TensorOptions(torch::kFloat)
.device(DefaultDevice())
.requires_grad(true))},
device,
testfn);
});
}
TEST_F(LazyOpsTest, TestSoftshrinkBackward) {
auto testfn = [&](const std::vector<torch::Tensor>& inputs) -> torch::Tensor {
return torch::softshrink(inputs[0]);
};
ForEachDevice([&](const torch::Device& device) {
TestBackward(
{torch::randn(
{100},
torch::TensorOptions(torch::kFloat)
.device(DefaultDevice())
.requires_grad(true))},
device,
testfn);
});
}
TEST_F(LazyOpsTest, TestHardtanhBackward) {
auto testfn = [&](const std::vector<torch::Tensor>& inputs) -> torch::Tensor {
return torch::hardtanh(inputs[0]);
};
ForEachDevice([&](const torch::Device& device) {
TestBackward(
{torch::randn(
{100},
torch::TensorOptions(torch::kFloat)
.device(DefaultDevice())
.requires_grad(true))},
device,
testfn);
});
}
TEST_F(LazyOpsTest, TestEluBackward) {
torch::Scalar alpha = 0.5;
torch::Scalar scale = 2.5;
torch::Scalar input_scale = 1.5;
auto testfn = [&](const std::vector<torch::Tensor>& inputs) -> torch::Tensor {
return torch::elu(inputs[0], alpha, scale, input_scale);
};
ForEachDevice([&](const torch::Device& device) {
TestBackward(
{torch::rand(
{2, 1, 4, 6},
torch::TensorOptions(torch::kFloat)
.device(DefaultDevice())
.requires_grad(true))},
device,
testfn);
});
}
TEST_F(LazyOpsTest, TestGeluBackward) {
auto testfn = [&](const std::vector<torch::Tensor>& inputs) -> torch::Tensor {
return torch::gelu(inputs[0]);
};
ForEachDevice([&](const torch::Device& device) {
TestBackward(
{torch::rand(
{2, 3},
torch::TensorOptions(torch::kFloat)
.device(DefaultDevice())
.requires_grad(true))},
device,
testfn);
});
ExpectCounterChanged("lazy::gelu_backward", GetIgnoredCounters());
}
TEST_F(LazyOpsTest, TestLeakyReluBackward) {
double negative_slope = 0.01;
auto testfn = [=](const std::vector<torch::Tensor>& inputs) -> torch::Tensor {
return torch::leaky_relu(inputs[0], negative_slope);
};
ForEachDevice([&](const torch::Device& device) {
TestBackward(
{torch::rand(
{2, 1, 4, 6},
torch::TensorOptions(torch::kFloat)
.device(DefaultDevice())
.requires_grad(true))},
device,
testfn);
});
}
TEST_F(LazyOpsTest, TestTransposeBackward) {
auto testfn = [&](const std::vector<torch::Tensor>& inputs) -> torch::Tensor {
return torch::t(inputs[0]);
};
ForEachDevice([&](const torch::Device& device) {
TestBackward(
{torch::rand(
{2, 3},
torch::TensorOptions(torch::kFloat)
.device(DefaultDevice())
.requires_grad(true))},
device,
testfn);
});
}
TEST_F(LazyOpsTest, TestAddMatMulBackward) {
int in_channels = 32;
int out_channels = 320;
int labels = 50;
// Test beta != 1. through the CPU interop.
for (double beta : {1., 2.}) {
auto testfn =
[&](const std::vector<torch::Tensor>& inputs) -> torch::Tensor {
return torch::addmm(inputs[0], inputs[1], inputs[2], /*beta=*/beta);
};
ForEachDevice([&](const torch::Device& device) {
TestBackward(
{torch::rand(
{labels},
torch::TensorOptions(torch::kFloat)
.device(DefaultDevice())
.requires_grad(true)),
torch::rand(
{in_channels, out_channels},
torch::TensorOptions(torch::kFloat)
.device(DefaultDevice())
.requires_grad(true)),
torch::rand(
{out_channels, labels},
torch::TensorOptions(torch::kFloat)
.device(DefaultDevice())
.requires_grad(true))},
device,
testfn);
});
}
}
TEST_F(LazyOpsTest, TestBinaryCrossEntropyBackward) {
int batch = 6;
int classes = 2;
// TODO(asuhan): Fix the torch::kDouble case.
for (auto dtype : {torch::kFloat}) {
for (bool def_weight : {false, true}) {
torch::Tensor input = torch::rand(
{batch, classes}, torch::TensorOptions(dtype).requires_grad(true));
torch::Tensor target =
torch::rand({batch, classes}, torch::TensorOptions(dtype));
torch::Tensor weight;
if (def_weight) {
weight = torch::rand({batch, classes}, torch::TensorOptions(dtype));
}
for (torch::Reduction::Reduction reduction :
{torch::Reduction::Mean,
torch::Reduction::Sum,
torch::Reduction::None}) {
auto testfn =
[&](const std::vector<torch::Tensor>& inputs) -> torch::Tensor {
return torch::binary_cross_entropy(
/*self=*/inputs[0],
/*target=*/inputs[1],
/*weight=*/inputs[2],
/*reduction=*/reduction);
};
ForEachDevice([&](const torch::Device& device) {
TestBackward(
{input, target, weight},
device,
testfn,
/*rtol=*/1e-4,
/*atol=*/1e-7);
});
}
}
}
}
TEST_F(LazyOpsTest, TestNllLossBackward) {
// TODO(whc) debug divide-by-zero failure under ASAN
GTEST_SKIP();
int batch = 6;
int classes = 2;
// TODO(asuhan): Fix the torch::kDouble case.
for (auto dtype : {torch::kFloat}) {
for (int ignore_index : {-1, 0, 1, 5}) {
for (bool def_weight : {false, true}) {
torch::Tensor input = torch::rand(
{batch, classes},
torch::TensorOptions(dtype)
.device(DefaultDevice())
.requires_grad(true));
torch::Tensor target = torch::randint(
std::min(ignore_index, 0),
classes,
{batch},
torch::TensorOptions(torch::kLong).device(DefaultDevice()));
torch::Tensor weight;
if (def_weight) {
weight = torch::rand(
{classes}, torch::TensorOptions(dtype).device(DefaultDevice()));
}
for (torch::Reduction::Reduction reduction :
{torch::Reduction::Mean,
torch::Reduction::Sum,
torch::Reduction::None}) {
auto testfn =
[&](const std::vector<torch::Tensor>& inputs) -> torch::Tensor {
return torch::nll_loss(
/*self=*/inputs[0],
/*target=*/inputs[1],
/*weight=*/inputs[2],
/*reduction=*/reduction,
/*ignore_index=*/ignore_index);
};
ForEachDevice([&](const torch::Device& device) {
TestBackward(
{input, target, weight},
device,
testfn,
/*rtol=*/1e-5,
/*atol=*/1e-8);
});
}
}
}
}
}
TEST_F(LazyOpsTest, TestNllLoss2dBackward) {
int batch = 6;
int classes = 2;
int height = 3;
int width = 3;
// TODO(asuhan): Fix the torch::kDouble case.
for (auto dtype : {torch::kFloat}) {
for (int ignore_index : {-1, 0, 1, 5}) {
for (bool def_weight : {false, true}) {
torch::Tensor input = torch::rand(
{batch, classes, height, width},
torch::TensorOptions(dtype)
.device(DefaultDevice())
.requires_grad(true));
torch::Tensor target = torch::randint(
std::min(ignore_index, 0),
classes,
{batch, height, width},
torch::TensorOptions(torch::kLong).device(DefaultDevice()));
torch::Tensor weight;
if (def_weight) {
weight = torch::rand(
{classes}, torch::TensorOptions(dtype).device(DefaultDevice()));
}
for (torch::Reduction::Reduction reduction :
{torch::Reduction::Mean,
torch::Reduction::Sum,
torch::Reduction::None}) {
auto testfn =
[&](const std::vector<torch::Tensor>& inputs) -> torch::Tensor {
return torch::nll_loss2d(
/*self=*/inputs[0],
/*target=*/inputs[1],
/*weight=*/inputs[2],
/*reduction=*/reduction,
/*ignore_index=*/ignore_index);
};
ForEachDevice([&](const torch::Device& device) {
TestBackward(
{input, target, weight},
device,
testfn,
/*rtol=*/1e-5,
/*atol=*/1e-8);
});
}
}
}
}
}
TEST_F(LazyOpsTest, TestSmoothL1LossBackward) {
torch::Tensor input = torch::randn(
{2, 4},
torch::TensorOptions(torch::kFloat)
.device(DefaultDevice())
.requires_grad(true));
torch::Tensor target = torch::randn(
{2, 4}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
for (torch::Reduction::Reduction reduction :
{torch::Reduction::None,
torch::Reduction::Mean,
torch::Reduction::Sum}) {
for (double beta : {0.25, 1.}) {
auto testfn =
[&](const std::vector<torch::Tensor>& inputs) -> torch::Tensor {
return torch::smooth_l1_loss(
/*input=*/inputs[0],
/*target=*/inputs[1],
/*reduction=*/reduction,
/*beta=*/beta);
};
ForEachDevice([&](const torch::Device& device) {
TestBackward(
{input, target},
device,
testfn,
/*rtol=*/1e-5,
/*atol=*/1e-8);
});
}
}
}
TEST_F(LazyOpsTest, TestViewBackward) {
auto testfn = [&](const std::vector<torch::Tensor>& inputs) -> torch::Tensor {
return inputs[0].view({-1, 320});
};
ForEachDevice([&](const torch::Device& device) {
TestBackward(
{torch::rand(
{32, 20, 4, 4},
torch::TensorOptions(torch::kFloat)
.device(DefaultDevice())
.requires_grad(true))},
device,
testfn);
});
}
TEST_F(LazyOpsTest, TestBatchNorm2DBackward) {
double momentum = 0.1;
double eps = 0.5;
auto testfn = [&](const std::vector<torch::Tensor>& inputs) -> torch::Tensor {
return torch::batch_norm(
/*input=*/inputs[0],
/*weight=*/inputs[1],
/*bias=*/inputs[2],
/*running_mean=*/inputs[3],
/*running_var=*/inputs[4],
/*training=*/true,
/*momentum=*/momentum,
/*eps=*/eps,
/*cudnn_enabled=*/false);
};
int num_features = 3;
torch::Tensor undef;
for (bool undef_weight_bias : {false, true}) {
ForEachDevice([&](const torch::Device& device) {
torch::Tensor input = torch::rand(
{2, num_features, 4, 4},
torch::TensorOptions(torch::kFloat)
.device(DefaultDevice())
.requires_grad(true));
torch::Tensor weight = undef_weight_bias
? undef
: torch::rand(
{num_features},
torch::TensorOptions(torch::kFloat)
.device(DefaultDevice())
.requires_grad(true));
torch::Tensor bias = undef_weight_bias
? undef
: torch::rand(
{num_features},
torch::TensorOptions(torch::kFloat)
.device(DefaultDevice())
.requires_grad(true));
torch::Tensor running_mean = torch::zeros(
{num_features},
torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor running_var = torch::ones(
{num_features},
torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
TestBackward(
{input, weight, bias, running_mean, running_var},
device,
testfn,
/*rtol=*/1e-3,
/*atol=*/1e-4);
});
}
}
TEST_F(LazyOpsTest, TestBatchNorm3DBackward) {
double momentum = 0.1;
double eps = 0.5;
auto testfn = [&](const std::vector<torch::Tensor>& inputs) -> torch::Tensor {
return torch::batch_norm(
/*input=*/inputs[0],
/*weight=*/inputs[1],
/*bias=*/inputs[2],
/*running_mean=*/inputs[3],
/*running_var=*/inputs[4],
/*training=*/true,
/*momentum=*/momentum,
/*eps=*/eps,
/*cudnn_enabled=*/false);
};
int num_features = 3;
torch::Tensor undef;
for (bool undef_weight_bias : {false, true}) {
ForEachDevice([&](const torch::Device& device) {
torch::Tensor input = torch::rand(
{2, num_features, 4, 4, 2},
torch::TensorOptions(torch::kFloat)
.device(DefaultDevice())
.requires_grad(true));
torch::Tensor weight = undef_weight_bias
? undef
: torch::rand(
{num_features},
torch::TensorOptions(torch::kFloat)
.device(DefaultDevice())
.requires_grad(true));
torch::Tensor bias = undef_weight_bias
? undef
: torch::rand(
{num_features},
torch::TensorOptions(torch::kFloat)
.device(DefaultDevice())
.requires_grad(true));
torch::Tensor running_mean = torch::zeros(
{num_features},
torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor running_var = torch::ones(
{num_features},
torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
TestBackward(
{input, weight, bias, running_mean, running_var},
device,
testfn,
/*rtol=*/1e-3,
/*atol=*/1e-3);
});
}
}
TEST_F(LazyOpsTest, TestBCEWithLogitsBackward) {
int batch = 10;
int classes = 5;
torch::Tensor undef;
for (torch::Reduction::Reduction reduction :
{torch::Reduction::None,
torch::Reduction::Mean,
torch::Reduction::Sum}) {
auto testfn =
[&](const std::vector<torch::Tensor>& inputs) -> torch::Tensor {
return torch::binary_cross_entropy_with_logits(
/*input=*/inputs[0],
/*target=*/inputs[1],
/*weight=*/inputs[2],
/*pos_weight=*/inputs[3],
/*reduction=*/reduction);
};
for (bool undef_weight : {false, true}) {
for (bool undef_pos_weight : {false, true}) {
torch::Tensor input = torch::rand(
{batch, classes},
torch::TensorOptions(torch::kFloat)
.device(DefaultDevice())
.requires_grad(true));
torch::Tensor target = torch::rand(
{batch, classes},
torch::TensorOptions(torch::kFloat)
.device(DefaultDevice())
.requires_grad(true));
torch::Tensor weight = undef_weight
? undef
: torch::rand(
{classes},
torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor pos_weight = undef_pos_weight
? undef
: torch::rand(
{classes},
torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
ForEachDevice([&](const torch::Device& device) {
TestBackward(
{input, target, weight, pos_weight},
device,
testfn,
/*rtol=*/1e-3,
/*atol=*/1e-5);
});
}
}
}
}
TEST_F(LazyOpsTest, TestKlDivBackward) {
torch::Tensor input = torch::rand(
{4, 3},
torch::TensorOptions(torch::kFloat)
.device(DefaultDevice())
.requires_grad(true));
torch::Tensor target = torch::rand(
{4, 3},
torch::TensorOptions(torch::kFloat)
.device(DefaultDevice())
.requires_grad(true));
for (torch::Reduction::Reduction reduction :
{torch::Reduction::Mean,
torch::Reduction::Sum,
torch::Reduction::None}) {
auto testfn =
[&](const std::vector<torch::Tensor>& inputs) -> torch::Tensor {
return torch::kl_div(/*self=*/inputs[0], /*target=*/inputs[1], reduction);
};
ForEachDevice([&](const torch::Device& device) {
TestBackward(
{input, target},
device,
testfn,
/*rtol=*/1e-4,
/*atol=*/1e-5);
});
}
}
TEST_F(LazyOpsTest, TestEmbeddingBackward) {
int num_weights = 32;
for (int padding_idx = -1; padding_idx < num_weights; ++padding_idx) {
for (bool scale_grad_by_freq : {false, true}) {
auto testfn =
[&](const std::vector<torch::Tensor>& inputs) -> torch::Tensor {
return torch::embedding(
inputs[0],
inputs[1],
/*padding_idx=*/padding_idx,
/*scale_grad_by_freq=*/scale_grad_by_freq,
/*sparse=*/false);
};
ForEachDevice([&](const torch::Device& device) {
torch::Tensor weight = torch::rand(
{num_weights, 7},
torch::TensorOptions(torch::kFloat)
.device(DefaultDevice())
.requires_grad(true));
torch::Tensor indices = torch::randint(
num_weights,
{3, 9, 4},
torch::TensorOptions(torch::kLong).device(DefaultDevice()));
TestBackward(
{weight, indices},
device,
testfn,
/*rtol=*/1e-5,
/*atol=*/1e-8);
});
}
}
}
TEST_F(LazyOpsTest, TestAmpForeachNonFiniteCheckAndUnscale) {
if (IsCuda()) {
// TODO(whc) debug failure on cuda
GTEST_SKIP();
}
torch::Tensor grads0 = torch::tensor(
{1, 2, 3, 4},
torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor grads1 = torch::tensor(
{1.0, 2.0, std::nan("1"), 4.0},
torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor inv_scale = torch::scalar_tensor(
0.2, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor found_inf = torch::scalar_tensor(
0, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor grads_output0 = grads0 * inv_scale;
torch::Tensor found_inf_output0 = torch::scalar_tensor(
0, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor found_inf_output1 = torch::scalar_tensor(
1, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
ForEachDevice([&](const torch::Device& device) {
if (grads0.device() == at::kCPU) {
GTEST_SKIP();
}
torch::Tensor lazy_grads0 = CopyToDevice(grads0, device);
torch::Tensor lazy_inv_scale = CopyToDevice(inv_scale, device);
torch::Tensor lazy_found_inf = CopyToDevice(found_inf, device);
torch::_amp_foreach_non_finite_check_and_unscale_(
lazy_grads0, lazy_found_inf, lazy_inv_scale);
AllClose(grads_output0, lazy_grads0, /*rtol=*/1e-2, /*atol=*/1e-4);
AllEqual(found_inf_output0, lazy_found_inf);
torch::Tensor lazy_grads1 = CopyToDevice(grads1, device);
torch::_amp_foreach_non_finite_check_and_unscale_(
lazy_grads1, lazy_found_inf, lazy_inv_scale);
AllEqual(found_inf_output1, lazy_found_inf);
});
}
TEST_F(LazyOpsTest, TestAmpUpdateScale) {
torch::Tensor growth_tracker = torch::scalar_tensor(
0, torch::TensorOptions(torch::kInt32).device(DefaultDevice()));
torch::Tensor current_scale = torch::scalar_tensor(
4, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor found_inf = torch::scalar_tensor(
1, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor not_found_inf = torch::scalar_tensor(
0, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
float scale_growth_factor = 2.0;
float scale_backoff_factor = 0.5;
int growth_interval = 3;
torch::Tensor growth_tracker_result0 = torch::scalar_tensor(
1, torch::TensorOptions(torch::kInt32).device(DefaultDevice()));
torch::Tensor current_scale_result0 = torch::scalar_tensor(
4, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor growth_tracker_result1 = torch::scalar_tensor(
2, torch::TensorOptions(torch::kInt32).device(DefaultDevice()));
torch::Tensor current_scale_result1 = torch::scalar_tensor(
4, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor growth_tracker_result2 = torch::scalar_tensor(
0, torch::TensorOptions(torch::kInt32).device(DefaultDevice()));
torch::Tensor current_scale_result2 = torch::scalar_tensor(
8, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor growth_tracker_result3 = torch::scalar_tensor(
0, torch::TensorOptions(torch::kInt32).device(DefaultDevice()));
torch::Tensor current_scale_result3 = torch::scalar_tensor(
4, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
ForEachDevice([&](const torch::Device& device) {
if (growth_tracker.device() == at::kCPU) {
GTEST_SKIP();
}
torch::Tensor lazy_growth_tracker = CopyToDevice(growth_tracker, device);
torch::Tensor lazy_current_scale = CopyToDevice(current_scale, device);
torch::Tensor lazy_found_inf = CopyToDevice(found_inf, device);
torch::Tensor lazy_not_found_inf = CopyToDevice(not_found_inf, device);
torch::_amp_update_scale_(
lazy_current_scale,
lazy_growth_tracker,
lazy_not_found_inf,
scale_growth_factor,
scale_backoff_factor,
growth_interval);
AllClose(
current_scale_result0,
lazy_current_scale,
/*rtol=*/1e-2,
/*atol=*/1e-4);
AllEqual(growth_tracker_result0, lazy_growth_tracker);
torch::_amp_update_scale_(
lazy_current_scale,
lazy_growth_tracker,
lazy_not_found_inf,
scale_growth_factor,
scale_backoff_factor,
growth_interval);
AllClose(
current_scale_result1,
lazy_current_scale,
/*rtol=*/1e-2,
/*atol=*/1e-4);
AllEqual(growth_tracker_result1, lazy_growth_tracker);
// torch::_amp_update_scale_ returns the reference of current_scale
lazy_current_scale = torch::_amp_update_scale_(
lazy_current_scale,
lazy_growth_tracker,
lazy_not_found_inf,
scale_growth_factor,
scale_backoff_factor,
growth_interval);
AllClose(
current_scale_result2,
lazy_current_scale,
/*rtol=*/1e-2,
/*atol=*/1e-4);
AllEqual(growth_tracker_result2, lazy_growth_tracker);
lazy_current_scale = torch::_amp_update_scale_(
lazy_current_scale,
lazy_growth_tracker,
lazy_found_inf,
scale_growth_factor,
scale_backoff_factor,
growth_interval);
AllClose(
current_scale_result3,
lazy_current_scale,
/*rtol=*/1e-2,
/*atol=*/1e-4);
AllEqual(growth_tracker_result3, lazy_growth_tracker);
});
ExpectCounterNotChanged("aten::.*", GetIgnoredCounters());
ExpectCounterChanged("lazy::_amp_update_scale_", GetIgnoredCounters());
}
TEST_F(LazyOpsTest, TestEarlySyncLiveTensors) {
torch::Tensor scalar_tensor = torch::scalar_tensor(
1., torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Scalar scalar1 = scalar_tensor.item();
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_scalar_tensor = CopyToDevice(scalar_tensor, device);
torch::Scalar scalar2 = lazy_scalar_tensor.item();
ASSERT_EQ(scalar1.to<float>(), scalar2.to<float>());
});
if (DebugUtil::ExperimentEnabled("early_sync")) {
ExpectCounterChanged("EarlySyncLiveTensorsCount", GetIgnoredCounters());
} else {
ExpectCounterNotChanged("EarlySyncLiveTensorsCount", GetIgnoredCounters());
}
ExpectCounterChanged("aten::_local_scalar_dense", GetIgnoredCounters());
}
TEST_F(LazyOpsTest, TestLerp) {
torch::Tensor start = torch::rand(
{3, 4}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor end = torch::rand(
{3, 4}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor weight = torch::rand(
{3, 4}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor res = torch::lerp(start, end, weight);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_start = CopyToDevice(start, device);
torch::Tensor lazy_end = CopyToDevice(end, device);
torch::Tensor lazy_weight = CopyToDevice(weight, device);
torch::Tensor lazy_res = torch::lerp(lazy_start, lazy_end, lazy_weight);
AllClose(res, lazy_res);
});
ExpectCounterNotChanged("aten::.*", GetIgnoredCounters());
ExpectCounterChanged("lazy::lerp", GetIgnoredCounters());
}
TEST_F(LazyOpsTest, TestLerpScalar) {
torch::Tensor start = torch::rand(
{3, 4}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor end = torch::rand(
{3, 4}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Scalar weight = torch::Scalar(3.0);
torch::Tensor res = torch::lerp(start, end, weight);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_start = CopyToDevice(start, device);
torch::Tensor lazy_end = CopyToDevice(end, device);
torch::Tensor lazy_res = torch::lerp(lazy_start, lazy_end, weight);
AllClose(res, lazy_res);
});
ExpectCounterNotChanged("aten::.*", GetIgnoredCounters());
ExpectCounterChanged("lazy::lerp", GetIgnoredCounters());
}
TEST_F(LazyOpsTest, TestLerpInplace) {
torch::Tensor input = torch::rand(
{3, 4}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor end = torch::rand(
{3, 4}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor weight = torch::rand(
{3, 4}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor input_copy = input.clone();
input.lerp_(end, weight);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input_copy, device);
torch::Tensor lazy_end = CopyToDevice(end, device);
torch::Tensor lazy_weight = CopyToDevice(weight, device);
lazy_input.lerp_(lazy_end, lazy_weight);
AllClose(lazy_input, input);
});
ExpectCounterNotChanged("aten::.*", GetIgnoredCounters());
ExpectCounterChanged("lazy::lerp", GetIgnoredCounters());
}
TEST_F(LazyOpsTest, TestLerpScalarInplace) {
torch::Tensor input = torch::rand(
{3, 4}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor end = torch::rand(
{3, 4}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Scalar weight = torch::Scalar(3.0);
torch::Tensor input_copy = input.clone();
input.lerp_(end, weight);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_input = CopyToDevice(input_copy, device);
torch::Tensor lazy_end = CopyToDevice(end, device);
lazy_input.lerp_(lazy_end, weight);
AllClose(lazy_input, input);
});
ExpectCounterNotChanged("aten::.*", GetIgnoredCounters());
ExpectCounterChanged("lazy::lerp", GetIgnoredCounters());
}
TEST_F(LazyOpsTest, TestLerpOut) {
torch::Tensor start = torch::rand(
{3, 4}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor end = torch::rand(
{3, 4}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor weight = torch::rand(
{3, 4}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor res = torch::empty(
{3, 4}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
;
torch::lerp_out(res, start, end, weight);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_start = CopyToDevice(start, device);
torch::Tensor lazy_end = CopyToDevice(end, device);
torch::Tensor lazy_weight = CopyToDevice(weight, device);
torch::Tensor lazy_res = torch::empty({3, 4}, lazy_start.options());
torch::lerp_out(lazy_res, lazy_start, lazy_end, lazy_weight);
AllClose(res, lazy_res);
});
ExpectCounterNotChanged("aten::.*", GetIgnoredCounters());
ExpectCounterChanged("lazy::lerp", GetIgnoredCounters());
}
TEST_F(LazyOpsTest, TestLerpScalarOut) {
torch::Tensor start = torch::rand(
{3, 4}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Tensor end = torch::rand(
{3, 4}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::Scalar weight = torch::Scalar(3.0);
torch::Tensor res = torch::empty(
{3, 4}, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
torch::lerp_out(res, start, end, weight);
ForEachDevice([&](const torch::Device& device) {
torch::Tensor lazy_start = CopyToDevice(start, device);
torch::Tensor lazy_end = CopyToDevice(end, device);
torch::Tensor lazy_res = torch::empty({3, 4}, lazy_start.options());
torch::lerp_out(lazy_res, lazy_start, lazy_end, weight);
AllClose(res, lazy_res);
});
ExpectCounterNotChanged("aten::.*", GetIgnoredCounters());
ExpectCounterChanged("lazy::lerp", GetIgnoredCounters());
}
TEST_F(LazyOpsTest, IsAliasOf) {
auto a = torch::empty(
4, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
auto b = torch::empty(
4, torch::TensorOptions(torch::kFloat).device(DefaultDevice()));
ForEachDevice([&](const torch::Device& device) {
auto lazy_a = CopyToDevice(a, device);
auto lazy_b = CopyToDevice(b, device);
EXPECT_EQ(!a.is_alias_of(b), !lazy_a.is_alias_of(lazy_b));
auto c = a.view({2, 2});
auto lazy_c = lazy_a.view({2, 2});
EXPECT_EQ(a.is_alias_of(c), lazy_a.is_alias_of(lazy_c));
auto d = c.view({1, 4});
auto lazy_d = lazy_c.view({1, 4});
EXPECT_EQ(d.is_alias_of(c), lazy_d.is_alias_of(lazy_c));
EXPECT_EQ(d.is_alias_of(a), lazy_d.is_alias_of(lazy_a));
});
}
#endif // FBCODE_CAFFE2
} // namespace lazy
} // namespace torch