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