DiSMEC++
reg_sg_hinge_test.cpp
Go to the documentation of this file.
1 // Copyright (c) 2021, Aalto University, developed by Erik Schultheis
2 // All rights reserved.
3 //
4 // SPDX-License-Identifier: MIT
5 
6 #include "reg_sq_hinge_detail.h"
7 #include "reg_sq_hinge.h"
8 #include "doctest.h"
9 #include "utils/test_utils.h"
10 #include "regularizers_imp.h"
11 
12 using namespace dismec;
13 using namespace dismec::l2_reg_sq_hinge_detail;
15 
16 TEST_CASE("hessian_times_direction_sum") {
17  int num_ftr = 1000;
18  int num_rows = 500;
19 
20  std::vector<int> indices = {1, 5, 34, 54, 125, 499};
21 
22  SparseFeatures features = make_uniform_sparse_matrix(num_rows, num_ftr, 5);
23 
24  DenseRealVector direction = DenseRealVector::Random(num_ftr);
25  DenseRealVector costs = DenseRealVector::Random(num_ftr);
26 
27  // simple reference implementation
28  DenseRealVector reference(num_ftr);
29  reference.setZero();
30  htd_sum_naive(indices, reference, features, costs, direction);
31 
32  DenseRealVector output(num_ftr);
33  output.setZero();
34 
35  htd_sum(indices, output, features, costs, direction);
36 
37  if(output != reference) {
38  for(int i = 0; i < num_ftr; ++i) {
39  DOCTEST_CAPTURE(i);
40  REQUIRE(output.coeff(i) == reference.coeff(i));
41  }
42  }
43 }
44 
45 /*
46 TEST_CASE("line restriction") {
47  Eigen::SparseMatrix<real_t> x(3, 5);
48  x.insert(0, 3) = 1.0;
49  x.insert(1, 0) = 2.0;
50  x.insert(2, 1) = 1.0;
51  x.insert(2, 2) = 1.0;
52 
53  BinaryLabelVector y(3);
54  y << -1, 1, -1;
55 
56 
57  auto loss = Regularized_SquaredHingeSVC(std::make_shared<SparseFeatures>(x), std::make_unique<objective::SquaredNormRegularizer>());
58  loss.get_label_ref() = y;
59 
60  DenseRealVector weights = DenseRealVector::Random(5);
61  DenseRealVector dir = DenseRealVector::Random(5);
62 
63  loss.project_to_line(HashVector{weights}, dir);
64 
65  for(real_t a = 0; a < 2.0; a += 0.1) {
66  real_t ground_truth = loss.value(HashVector{weights + a*dir});
67  real_t fast_approx = loss.lookup_on_line(a);
68  CHECK(fast_approx == doctest::Approx(ground_truth));
69  }
70 }
71 
72 
73 TEST_CASE("L2 regularized squared hinge") {
74  Eigen::SparseMatrix<real_t> x(3, 5);
75  x.insert(0, 3) = 1.0;
76  x.insert(1, 0) = 2.0;
77  x.insert(2, 1) = 1.0;
78  x.insert(2, 2) = 1.0;
79 
80  Eigen::Matrix<std::int8_t, Eigen::Dynamic, 1> y(3);
81  y << -1, 1, -1;
82 
83 
84  auto loss = Regularized_SquaredHingeSVC(std::make_shared<SparseFeatures>(x), std::make_unique<objective::SquaredNormRegularizer>());
85  loss.get_label_ref() = y;
86 
87  DenseRealVector weights(5);
88  weights << 1.0, 2.0, 0.0, -1.0, 2.0;
89 
90  auto do_check = [&](real_t factor){
91  // z = (-1, 2, 2)
92  // 1 - yz = 0, -1, 3
93  CHECK_MESSAGE(loss.value(HashVector{weights}) == doctest::Approx(factor * 9.0 + 5), "wrong value");
94 
95  //
96  DenseRealVector grad(5);
97  loss.gradient(HashVector{weights}, grad);
98  // dl/dz = 0, 0, 2*3
99  // dl/dx = 6*(0.0, 1.0, 1.0, 0.0, 0.0) + 0.5*weights
100  DenseRealVector i(5);
101  i << 0.0, 1.0, 1.0, 0.0, 0.0;
102  DenseRealVector r = factor * 6 * i + weights;
103  CHECK_MESSAGE(grad == r, "wrong gradient");
104 
105  // also check numerically
106  real_t old_val = loss.value(HashVector{weights});
107  DenseRealVector nw = weights + grad * 1e-4;
108  real_t new_val = loss.value(HashVector{nw});
109  CHECK (new_val - old_val == doctest::Approx(grad.squaredNorm() * 1e-4).epsilon(1e-4));
110  };
111 
112  // since the positive example is correct with margin,
113  // re-weighting positives does not change the outcome,
114  // whereas negatives change the result by a constant factor
115  SUBCASE("unweighted") {
116  do_check(1.0);
117  }
118  SUBCASE("positive-reweighted") {
119  loss.set_positive_cost(2.0);
120  do_check(1.0);
121  }
122  SUBCASE("negative-reweighted") {
123  loss.set_negative_cost(2.0);
124  do_check(2.0);
125  }
126 }
127 
128  */
129 
void htd_sum_naive(const std::vector< int > &indices, Eigen::Ref< DenseRealVector > output, const Eigen::EigenBase< Derived > &features, const DenseRealVector &costs, const DenseRealVector &direction)
void htd_sum(const std::vector< int > &indices, Eigen::Ref< DenseRealVector > output, const SparseFeatures &features, const DenseRealVector &costs, const DenseRealVector &direction)
Main namespace in which all types, classes, and functions are defined.
Definition: app.h:15
SparseFeatures make_uniform_sparse_matrix(int rows, int cols, int non_zeros_per_row)
Creates a sparse matrix with the given number of rows and columns.
Definition: test_utils.cpp:8
types::DenseVector< real_t > DenseRealVector
Any dense, real values vector.
Definition: matrix_types.h:40
types::SparseRowMajor< real_t > SparseFeatures
Sparse Feature Matrix in Row Major format.
Definition: matrix_types.h:50
TEST_CASE("hessian_times_direction_sum")