LCOV - code coverage report
Current view: top level - ml/tests - test_Loss.cpp (source / functions) Hit Total Coverage
Test: test_coverage.info.cleaned Lines: 106 106 100.0 %
Date: 2022-02-28 03:37:41 Functions: 12 12 100.0 %

          Line data    Source code
       1             : #include "doctest/doctest.h"
       2             : #include "DataContainer.h"
       3             : #include "VolumeDescriptor.h"
       4             : #include "Loss.h"
       5             : 
       6             : using namespace elsa;
       7             : using namespace doctest;
       8             : 
       9             : TEST_SUITE_BEGIN("ml");
      10             : 
      11             : // TODO(dfrank): remove and replace with proper doctest usage of test cases
      12             : #define SECTION(name) DOCTEST_SUBCASE(name)
      13             : 
      14          12 : TEST_CASE_TEMPLATE("BinaryCrossentropy", TestType, float)
      15             : {
      16           8 :     IndexVector_t dims{{2, 4}};
      17           8 :     VolumeDescriptor dd(dims);
      18             : 
      19             :     // predictions
      20           8 :     Eigen::VectorX<TestType> data_x{{0.6f, 0.4f, 0.4f, 0.6f, 1.f, 0.f, 0.3f, 0.7f}};
      21           8 :     DataContainer<TestType> x(dd, data_x);
      22             : 
      23             :     // labels
      24           8 :     Eigen::VectorX<TestType> data_y{{0.f, 1.f, 0.f, 0.f, 1.f, 0.f, 1.f, 1.f}};
      25           8 :     DataContainer<TestType> y(dd, data_y);
      26             : 
      27           5 :     SECTION("Unweighted SumOverBatchSize")
      28             :     {
      29           1 :         auto bce = ml::BinaryCrossentropy(ml::LossReduction::SumOverBatchSize);
      30           1 :         REQUIRE(bce(x, y) == Approx(0.602543f));
      31             :     }
      32             : 
      33           5 :     SECTION("Unweighted Sum")
      34             :     {
      35           1 :         auto bce = ml::BinaryCrossentropy(ml::LossReduction::Sum);
      36           1 :         REQUIRE(bce(x, y) == Approx(2.410172f));
      37             :     }
      38           5 :     SECTION("Gradient Sum")
      39             :     {
      40           2 :         auto bce = ml::BinaryCrossentropy(ml::LossReduction::Sum);
      41             : 
      42           2 :         Eigen::VectorXf ref_gradient{{-1.f / 0.8f, -1.f / 0.8f, -1.f / 1.2f, -1.f / 0.8f,
      43             :                                       -1.f / 2.f, -1.f / 2.f, -1.f / 0.6f, -1.f / 1.4f}};
      44           2 :         auto gradient = bce.getLossGradient(x, y);
      45             : 
      46           9 :         for (int i = 0; i < gradient.getSize(); ++i)
      47           8 :             REQUIRE(gradient[i] == Approx(ref_gradient[i]));
      48             :     }
      49             : 
      50           5 :     SECTION("Gradient SumOverBatchSize")
      51             :     {
      52           2 :         auto bce = ml::BinaryCrossentropy(ml::LossReduction::SumOverBatchSize);
      53             : 
      54           2 :         Eigen::VectorXf ref_gradient{{-1.f / 3.2f, -1.f / 3.2f, -1.f / 4.8f, -1.f / 3.2f,
      55             :                                       -1.f / 8.f, -1.f / 8.f, -1.f / 2.4f, -1.f / 5.6f}};
      56           2 :         auto gradient = bce.getLossGradient(x, y);
      57             : 
      58           9 :         for (int i = 0; i < gradient.getSize(); ++i)
      59           8 :             REQUIRE(gradient[i] == Approx(ref_gradient[i]));
      60             :     }
      61           4 : }
      62             : 
      63          12 : TEST_CASE_TEMPLATE("CategoricalCrossentropy", TestType, float)
      64             : {
      65           8 :     IndexVector_t dims{{3, 4}};
      66           8 :     VolumeDescriptor dd(dims);
      67             : 
      68             :     // predictions
      69             :     // clang-format off
      70           8 :     Eigen::VectorX<TestType> data_x{{
      71             :       // first batch
      72             :       0.05f, 0.95f, 0.f,
      73             :       // second batch
      74             :       0.1f, 0.8f, 0.1f,
      75             :       // third batch
      76             :       0.2f, 0.3f, 0.5f,
      77             :       // fourth batch
      78             :       0.0f, 0.2f, 0.8f}};
      79             :     // clang-format on
      80           8 :     DataContainer<TestType> x(dd, data_x);
      81             : 
      82             :     // labels in one-hot encoding
      83             :     // clang-format off
      84           8 :     Eigen::VectorX<TestType> data_y{{
      85             :       // label 1: 1
      86             :       0.f, 1.f, 0.f,
      87             :       // label 2: 2
      88             :       0.f, 0.f, 1.f,
      89             :       // label 3: 0
      90             :       1.f, 0.f, 0.f, 
      91             :       // label 4: 1
      92             :       0.f, 1.f, 0.f}};
      93             :     // clang-format on
      94             : 
      95           8 :     DataContainer<TestType> y(dd, data_y);
      96             : 
      97           5 :     SECTION("Unweighted SumOverBatchSize")
      98             :     {
      99           1 :         auto cce = ml::CategoricalCrossentropy(ml::LossReduction::SumOverBatchSize);
     100           1 :         REQUIRE(cce(x, y) == Approx(1.3931886f));
     101             :     }
     102             : 
     103           5 :     SECTION("Unweighted Sum")
     104             :     {
     105           1 :         auto cce = ml::CategoricalCrossentropy(ml::LossReduction::Sum);
     106           1 :         REQUIRE(cce(x, y) == Approx(5.5727544f));
     107             :     }
     108             : 
     109           5 :     SECTION("Gradient Sum")
     110             :     {
     111           2 :         auto cce = ml::CategoricalCrossentropy(ml::LossReduction::Sum);
     112             : 
     113           2 :         Eigen::VectorXf ref_gradient{{0, -1.f / .95f, 0, 0, 0, -10.f, -5.f, 0, 0, 0, -5.f, 0}};
     114           2 :         auto gradient = cce.getLossGradient(x, y);
     115             : 
     116          13 :         for (int i = 0; i < gradient.getSize(); ++i)
     117          12 :             REQUIRE(gradient[i] == Approx(ref_gradient[i]));
     118             :     }
     119             : 
     120           5 :     SECTION("Gradient SumOverBatchSize")
     121             :     {
     122           2 :         auto cce = ml::CategoricalCrossentropy(ml::LossReduction::SumOverBatchSize);
     123             : 
     124           2 :         Eigen::VectorXf ref_gradient{
     125             :             {0, -1.f / 3.8f, 0, 0, 0, -10.f / 4.f, -5.f / 4.f, 0, 0, 0, -5.f / 4.f, 0}};
     126           2 :         auto gradient = cce.getLossGradient(x, y);
     127             : 
     128          13 :         for (int i = 0; i < gradient.getSize(); ++i)
     129          12 :             REQUIRE(gradient[i] == Approx(ref_gradient[i]));
     130             :     }
     131           4 : }
     132             : 
     133          12 : TEST_CASE_TEMPLATE("SparseCategoricalCrossentropy", TestType, float)
     134             : {
     135           8 :     IndexVector_t predictionDims{{3, 4}};
     136           8 :     VolumeDescriptor predictionDesc(predictionDims);
     137             : 
     138             :     // predictions
     139           8 :     Eigen::VectorX<TestType> data_x{
     140             :         {0.05f, 0.95f, 0.f, 0.1f, 0.8f, 0.1f, 0.2f, 0.3f, 0.5f, 0.0f, 0.2f, 0.8f}};
     141           8 :     DataContainer<TestType> x(predictionDesc, data_x);
     142             : 
     143           8 :     IndexVector_t labelDims{{4}};
     144           8 :     VolumeDescriptor labelDesc(labelDims);
     145             : 
     146             :     // labels
     147           8 :     Eigen::VectorX<TestType> data_y{{1.f, 2.f, 0.f, 1.f}};
     148           8 :     DataContainer<TestType> y(labelDesc, data_y);
     149             : 
     150           5 :     SECTION("Unweighted SumOverBatchSize")
     151             :     {
     152           1 :         auto scce = ml::SparseCategoricalCrossentropy(ml::LossReduction::SumOverBatchSize);
     153           1 :         REQUIRE(scce(x, y) == Approx(1.3931886f));
     154             :     }
     155             : 
     156           5 :     SECTION("Unweighted Sum")
     157             :     {
     158           1 :         auto scce = ml::SparseCategoricalCrossentropy(ml::LossReduction::Sum);
     159           1 :         REQUIRE(scce(x, y) == Approx(5.5727544f));
     160             :     }
     161           5 :     SECTION("Gradient Sum")
     162             :     {
     163           2 :         auto scce = ml::SparseCategoricalCrossentropy(ml::LossReduction::Sum);
     164             : 
     165           2 :         Eigen::VectorXf ref_gradient{{0, -1.f / .95f, 0, 0, 0, -10.f, -5.f, 0, 0, 0, -5.f, 0}};
     166           2 :         auto gradient = scce.getLossGradient(x, y);
     167             : 
     168          13 :         for (int i = 0; i < gradient.getSize(); ++i)
     169          12 :             REQUIRE(gradient[i] == Approx(ref_gradient[i]));
     170             :     }
     171             : 
     172           5 :     SECTION("Gradient SumOverBatchSize")
     173             :     {
     174           2 :         auto scce = ml::SparseCategoricalCrossentropy(ml::LossReduction::SumOverBatchSize);
     175             : 
     176           2 :         Eigen::VectorXf ref_gradient{
     177             :             {0, -1.f / 3.8f, 0, 0, 0, -10.f / 4.f, -5.f / 4.f, 0, 0, 0, -5.f / 4.f, 0}};
     178           2 :         auto gradient = scce.getLossGradient(x, y);
     179             : 
     180          13 :         for (int i = 0; i < gradient.getSize(); ++i)
     181          12 :             REQUIRE(gradient[i] == Approx(ref_gradient[i]));
     182             :     }
     183           4 : }
     184             : 
     185          12 : TEST_CASE_TEMPLATE("MeanSquaredError", TestType, float)
     186             : {
     187           8 :     IndexVector_t dims{{3, 2}};
     188           8 :     VolumeDescriptor dd(dims);
     189             : 
     190             :     // predictions
     191           8 :     Eigen::VectorX<TestType> data_x{{1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f}};
     192           8 :     DataContainer<TestType> x(dd, data_x);
     193             : 
     194             :     // labels
     195           8 :     Eigen::VectorX<TestType> data_y{{0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f}};
     196           8 :     DataContainer<TestType> y(dd, data_y);
     197             : 
     198           5 :     SECTION("Unweighted SumOverBatchSize")
     199             :     {
     200           1 :         auto mse = ml::MeanSquaredError(ml::LossReduction::SumOverBatchSize);
     201           1 :         REQUIRE(mse(x, y) == Approx(0.33333334f));
     202             :     }
     203             : 
     204           5 :     SECTION("Unweighted Sum")
     205             :     {
     206           1 :         auto mse = ml::MeanSquaredError(ml::LossReduction::Sum);
     207           1 :         REQUIRE(mse(x, y) == Approx(0.6666667f));
     208             :     }
     209             : 
     210           5 :     SECTION("Gradient Sum")
     211             :     {
     212           2 :         auto mse = ml::MeanSquaredError(ml::LossReduction::Sum);
     213           2 :         Eigen::VectorXf refDerivative{{-2.f / 3.f, 0, 0, -2.f / 3.f, 0, 0}};
     214           2 :         auto derivative = mse.getLossGradient(x, y);
     215             : 
     216           7 :         for (int i = 0; i < derivative.getSize(); ++i)
     217           6 :             REQUIRE(derivative[i] == Approx(refDerivative[i]));
     218             :     }
     219             : 
     220           5 :     SECTION("Gradient SumOverBatchSize")
     221             :     {
     222           2 :         auto mse = ml::MeanSquaredError(ml::LossReduction::SumOverBatchSize);
     223           2 :         Eigen::VectorXf refDerivative{{-2.f / 6.f, 0, 0, -2.f / 6.f, 0, 0}};
     224           2 :         auto derivative = mse.getLossGradient(x, y);
     225             : 
     226           7 :         for (int i = 0; i < derivative.getSize(); ++i)
     227           6 :             REQUIRE(derivative[i] == Approx(refDerivative[i]));
     228             :     }
     229           4 : }
     230             : TEST_SUITE_END();

Generated by: LCOV version 1.15