StandardScalerTests.cpp 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  1. /*
  2. * Copyright (c) Contributors to the Open 3D Engine Project.
  3. * For complete copyright and license terms please see the LICENSE at the root of this distribution.
  4. *
  5. * SPDX-License-Identifier: Apache-2.0 OR MIT
  6. *
  7. */
  8. #include <FeatureMatrixStandardScaler.h>
  9. #include <Fixture.h>
  10. namespace EMotionFX::MotionMatching
  11. {
  12. /*
  13. # ground truth test data generated in python using the StandardScaler from scikit-learn
  14. from sklearn.preprocessing import StandardScaler
  15. import numpy as np
  16. data = [[0, -1],
  17. [0, -1],
  18. [1, 1],
  19. [1, 1]]
  20. print("data")
  21. print(data)
  22. scaler = StandardScaler()
  23. print(scaler.fit(data))
  24. print("means")
  25. print(scaler.mean_)
  26. print("standard deviations")
  27. print(np.sqrt(scaler.var_))
  28. print("transformed data")
  29. print(scaler.transform(data))
  30. print("transform -> inverse_transform roundtrip")
  31. print(scaler.inverse_transform(scaler.transform(data)))
  32. print("transformed test sample")
  33. print(scaler.transform([[2, 2]]))
  34. */
  35. class StandardScalerFixture : public Fixture
  36. {
  37. public:
  38. static constexpr float s_testEpsilon = 1e-6f;
  39. // First transforms and then inverse-transforms the data and compares the roundtrip to the original data.
  40. void RoundtripTest(const FeatureMatrix& data, const FeatureMatrixTransformer& scaler, float epsilon = s_testEpsilon)
  41. {
  42. FeatureMatrix roundTrip = scaler.InverseTransform(scaler.Transform(data));
  43. const FeatureMatrix::Index numRows = data.rows();
  44. const FeatureMatrix::Index numColumns = data.cols();
  45. for (FeatureMatrix::Index column = 0; column < numColumns; ++column)
  46. {
  47. for (FeatureMatrix::Index row = 0; row < numRows; ++row)
  48. {
  49. EXPECT_NEAR(data(row, column), roundTrip(row, column), epsilon)
  50. << "Value at (" << row << ", " << column << ") does not match roundtrip value.";
  51. }
  52. }
  53. }
  54. };
  55. TEST_F(StandardScalerFixture, BasicTransform1)
  56. {
  57. FeatureMatrix m;
  58. m.resize(4, 2);
  59. m(0, 0) = 0.0f;
  60. m(0, 1) = -1.0f;
  61. m(1, 0) = 0.0f;
  62. m(1, 1) = -1.0f;
  63. m(2, 0) = 1.0f;
  64. m(2, 1) = 1.0f;
  65. m(3, 0) = 1.0f;
  66. m(3, 1) = 1.0f;
  67. StandardScaler scaler;
  68. EXPECT_TRUE(scaler.Fit(m));
  69. // Test mean and standard deviations
  70. const AZStd::vector<float>& means = scaler.GetMeans();
  71. const AZStd::vector<float>& standardDeviations = scaler.GetStandardDeviations();
  72. EXPECT_NEAR(means[0], 0.5f, s_testEpsilon);
  73. EXPECT_NEAR(means[1], 0.0f, s_testEpsilon);
  74. EXPECT_NEAR(standardDeviations[0], 0.5f, s_testEpsilon);
  75. EXPECT_NEAR(standardDeviations[1], 1.0f, s_testEpsilon);
  76. // Test transform
  77. EXPECT_NEAR(scaler.Transform(2.0f, 0), 3.0f, s_testEpsilon);
  78. EXPECT_NEAR(scaler.Transform(2.0f, 1), 2.0f, s_testEpsilon);
  79. RoundtripTest(m, scaler);
  80. }
  81. TEST_F(StandardScalerFixture, BasicTransform2)
  82. {
  83. FeatureMatrix m;
  84. m.resize(4, 2);
  85. m(0, 0) = 1.0f;
  86. m(0, 1) = -1.0f;
  87. m(1, 0) = 2.0f;
  88. m(1, 1) = -4.0f;
  89. m(2, 0) = 3.0f;
  90. m(2, 1) = 2.0f;
  91. m(3, 0) = 4.0f;
  92. m(3, 1) = 0.5f;
  93. StandardScaler scaler;
  94. EXPECT_TRUE(scaler.Fit(m));
  95. // Test mean and standard deviations
  96. const AZStd::vector<float>& means = scaler.GetMeans();
  97. const AZStd::vector<float>& standardDeviations = scaler.GetStandardDeviations();
  98. EXPECT_NEAR(means[0], 2.5f, s_testEpsilon);
  99. EXPECT_NEAR(means[1], -0.625f, s_testEpsilon);
  100. EXPECT_NEAR(standardDeviations[0], 1.11803399f, s_testEpsilon);
  101. EXPECT_NEAR(standardDeviations[1], 2.21852992f, s_testEpsilon);
  102. // Test transform
  103. EXPECT_NEAR(scaler.Transform(2.0f, 0), -0.4472136f, s_testEpsilon);
  104. EXPECT_NEAR(scaler.Transform(2.0f, 1), 1.18321596f, s_testEpsilon);
  105. RoundtripTest(m, scaler);
  106. }
  107. TEST_F(StandardScalerFixture, LargeValues)
  108. {
  109. const float largeValueTestEpsilon = 0.001f;
  110. FeatureMatrix m;
  111. m.resize(4, 2);
  112. m(0, 0) = 10000.0f;
  113. m(0, 1) = 4242.0f;
  114. m(1, 0) = -10000.0f;
  115. m(1, 1) = -4242.0f;
  116. m(2, 0) = 300.0f;
  117. m(2, 1) = 4242.0f;
  118. m(3, 0) = -250.0f;
  119. m(3, 1) = 4242.0f;
  120. StandardScaler scaler;
  121. EXPECT_TRUE(scaler.Fit(m));
  122. // Test mean and standard deviations
  123. const AZStd::vector<float>& means = scaler.GetMeans();
  124. const AZStd::vector<float>& standardDeviations = scaler.GetStandardDeviations();
  125. EXPECT_NEAR(means[0], 12.5f, largeValueTestEpsilon);
  126. EXPECT_NEAR(means[1], 2121.0f, largeValueTestEpsilon);
  127. EXPECT_NEAR(standardDeviations[0], 7073.75209843f, largeValueTestEpsilon);
  128. EXPECT_NEAR(standardDeviations[1], 3673.67976285f, largeValueTestEpsilon);
  129. // Test transform
  130. EXPECT_NEAR(scaler.Transform(2.0f, 0), -0.00148436f, s_testEpsilon);
  131. EXPECT_NEAR(scaler.Transform(2.0f, 1), -0.57680586, s_testEpsilon);
  132. RoundtripTest(m, scaler, largeValueTestEpsilon);
  133. }
  134. TEST_F(StandardScalerFixture, ClosebyValues1)
  135. {
  136. const float closebyValueTestEpsilon = 0.001f;
  137. FeatureMatrix m;
  138. m.resize(4, 2);
  139. m(0, 0) = 1.0f;
  140. m(0, 1) = 1.01f;
  141. m(1, 0) = 1.0f;
  142. m(1, 1) = 1.0f;
  143. m(2, 0) = 1.0f;
  144. m(2, 1) = 1.0f;
  145. m(3, 0) = 1.0f;
  146. m(3, 1) = 1.0f;
  147. StandardScaler scaler;
  148. EXPECT_TRUE(scaler.Fit(m));
  149. // Test mean and standard deviations
  150. const AZStd::vector<float>& means = scaler.GetMeans();
  151. const AZStd::vector<float>& standardDeviations = scaler.GetStandardDeviations();
  152. EXPECT_NEAR(means[0], 1.0f, s_testEpsilon);
  153. EXPECT_NEAR(means[1], 1.0025f, s_testEpsilon);
  154. EXPECT_NEAR(standardDeviations[0], 0.0f, s_testEpsilon);
  155. EXPECT_NEAR(standardDeviations[1], 0.00433013f, s_testEpsilon);
  156. // Test transform
  157. EXPECT_NEAR(scaler.Transform(2.0f, 0), 1.0, s_testEpsilon);
  158. EXPECT_NEAR(scaler.Transform(2.0f, 1), 230.36275741f, closebyValueTestEpsilon);
  159. RoundtripTest(m, scaler, closebyValueTestEpsilon);
  160. }
  161. TEST_F(StandardScalerFixture, ClosebyValues2)
  162. {
  163. const float closebyValueTestEpsilon = 0.001f;
  164. FeatureMatrix m;
  165. m.resize(4, 2);
  166. m(0, 0) = 100000.0f;
  167. m(0, 1) = 1.001f;
  168. m(1, 0) = 100000.0f;
  169. m(1, 1) = 1.0f;
  170. m(2, 0) = 100000.0f;
  171. m(2, 1) = 1.0f;
  172. m(3, 0) = 100000.0f;
  173. m(3, 1) = 1.0f;
  174. StandardScaler scaler;
  175. EXPECT_TRUE(scaler.Fit(m));
  176. // Test mean and standard deviations
  177. const AZStd::vector<float>& means = scaler.GetMeans();
  178. const AZStd::vector<float>& standardDeviations = scaler.GetStandardDeviations();
  179. EXPECT_NEAR(means[0], 1.00000e+05f, s_testEpsilon);
  180. EXPECT_NEAR(means[1], 1.00025e+00f, s_testEpsilon);
  181. EXPECT_NEAR(standardDeviations[0], 0.0f, s_testEpsilon);
  182. EXPECT_NEAR(standardDeviations[1], 0.00043301f, s_testEpsilon);
  183. // Test transform
  184. const float floatPrecisionErrorEpsilon = 0.2f;
  185. EXPECT_NEAR(scaler.Transform(2.0f, 0), -99998.0f, floatPrecisionErrorEpsilon);
  186. EXPECT_NEAR(scaler.Transform(2.0f, 1), 2308.82372649f, floatPrecisionErrorEpsilon);
  187. RoundtripTest(m, scaler, closebyValueTestEpsilon);
  188. }
  189. } // namespace EMotionFX::MotionMatching