1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131
|
#include <gtest/gtest.h>
#include <c10/util/irange.h>
#include <torch/torch.h>
#include <test/cpp/api/init_baseline.h>
#include <test/cpp/api/support.h>
#include <functional>
#include <vector>
void check_exact_values(
const std::vector<torch::Tensor>& parameters,
const std::vector<std::vector<torch::Tensor>>& expected_parameters) {
ASSERT_EQ(parameters.size(), expected_parameters.size());
for (const auto i : c10::irange(parameters.size())) {
auto layerParameters = parameters[i];
auto expectedLayerParameters = expected_parameters[i];
if (static_cast<size_t>(layerParameters.size(0)) !=
expectedLayerParameters.size()) {
std::cout << "layer #" << i
<< " layerParameters size: " << layerParameters.size(0)
<< " != "
<< " expectedLayerParameters size: "
<< expectedLayerParameters.size() << std::endl;
ASSERT_TRUE(false);
}
for (const auto p : c10::irange(layerParameters.size(0))) {
// Always compare using double dtype, regardless of the original dtype of
// the tensors
auto tensor = layerParameters[p].to(torch::kFloat64);
auto expectedTensor = expectedLayerParameters[p].to(torch::kFloat64);
if (!tensor.allclose(expectedTensor, /*rtol=*/1e-3, /*atol=*/5e-4)) {
std::cout << "layer " << i << ": " << tensor << " != " << expectedTensor
<< " (parameter " << p << ")" << std::endl;
ASSERT_TRUE(false);
}
}
}
}
void check_initializer_against_baseline(
std::function<void(torch::Tensor)> initializer,
std::vector<std::vector<torch::Tensor>> expected) {
torch::manual_seed(0);
auto layer1 = torch::nn::Linear(7, 15);
initializer(layer1->weight);
layer1->to(torch::kFloat64);
auto layer2 = torch::nn::Linear(15, 15);
initializer(layer2->weight);
layer2->to(torch::kFloat64);
auto layer3 = torch::nn::Linear(15, 2);
initializer(layer3->weight);
layer3->to(torch::kFloat64);
auto parameters = std::vector<torch::Tensor>{
layer1->weight,
layer2->weight,
layer3->weight,
};
check_exact_values(parameters, expected);
}
TEST(InitTest, ProducesPyTorchValues_XavierUniform) {
auto expected = expected_parameters::Xavier_Uniform();
auto initializer = [](torch::Tensor tensor) {
torch::nn::init::xavier_uniform_(tensor);
};
check_initializer_against_baseline(initializer, expected);
}
TEST(InitTest, ProducesPyTorchValues_XavierNormal) {
auto expected = expected_parameters::Xavier_Normal();
auto initializer = [](torch::Tensor tensor) {
torch::nn::init::xavier_normal_(tensor);
};
check_initializer_against_baseline(initializer, expected);
}
TEST(InitTest, ProducesPyTorchValues_KaimingNormal) {
auto expected = expected_parameters::Kaiming_Normal();
auto initializer = [](torch::Tensor tensor) {
torch::nn::init::kaiming_normal_(tensor);
};
check_initializer_against_baseline(initializer, expected);
}
TEST(InitTest, ProducesPyTorchValues_KaimingUniform) {
auto expected = expected_parameters::Kaiming_Uniform();
auto initializer = [](torch::Tensor tensor) {
torch::nn::init::kaiming_uniform_(tensor);
};
check_initializer_against_baseline(initializer, expected);
}
TEST(InitTest, CanInitializeTensorThatRequiresGrad) {
auto tensor = torch::empty({3, 4}, torch::requires_grad());
ASSERT_THROWS_WITH(
tensor.fill_(1),
"a leaf Variable that requires grad "
"is being used in an in-place operation");
ASSERT_EQ(torch::nn::init::ones_(tensor).sum().item<int32_t>(), 12);
}
TEST(InitTest, CalculateGainWithTanh) {
double gain = torch::nn::init::calculate_gain(torch::kTanh);
ASSERT_DOUBLE_EQ(gain, 5.0 / 3.0);
}
TEST(InitTest, CalculateGainWithRelu) {
double gain = torch::nn::init::calculate_gain(torch::kReLU);
ASSERT_DOUBLE_EQ(gain, std::sqrt(2.0));
}
TEST(InitTest, CalculateGainWithLeakyRelu) {
double gain = torch::nn::init::calculate_gain(torch::kLeakyReLU);
ASSERT_DOUBLE_EQ(gain, std::sqrt(2.0 / (1 + pow(0.01, 2))));
}
TEST(InitTest, CanInitializeCnnWithOrthogonal) {
torch::nn::Conv2d conv_layer(torch::nn::Conv2dOptions(3, 2, 3).stride(2));
torch::nn::init::orthogonal_(conv_layer->named_parameters()["weight"]);
}
|