slope 6.2.1
Loading...
Searching...
No Matches
pgd.h
Go to the documentation of this file.
1
6#pragma once
7
8#include "../eigen_compat.h"
9#include "../losses/loss.h"
10#include "../math.h"
11#include "../sorted_l1_norm.h"
12#include "solver.h"
13#include <Eigen/Dense>
14#include <Eigen/SparseCore>
15#include <memory>
16
17namespace slope {
18
19using slope::all;
20
28class PGD : public SolverBase
29{
30public:
38 bool intercept,
39 const std::string& update_type)
41 , learning_rate(1.0)
42 , learning_rate_decr(0.5)
43 , update_type{ update_type }
44 , t(1.0)
45 {
46 }
47
49 void run(Eigen::VectorXd& beta0,
50 Eigen::VectorXd& beta,
51 Eigen::MatrixXd& eta,
52 const Eigen::ArrayXd& lambda,
53 const std::unique_ptr<Loss>& loss,
54 const SortedL1Norm& penalty,
55 const Eigen::VectorXd& gradient,
56 const std::vector<int>& working_set,
57 const Eigen::MatrixXd& x,
58 const Eigen::VectorXd& x_centers,
59 const Eigen::VectorXd& x_scales,
60 const Eigen::MatrixXd& y) override;
61
63 void run(Eigen::VectorXd& beta0,
64 Eigen::VectorXd& beta,
65 Eigen::MatrixXd& eta,
66 const Eigen::ArrayXd& lambda,
67 const std::unique_ptr<Loss>& loss,
68 const SortedL1Norm& penalty,
69 const Eigen::VectorXd& gradient,
70 const std::vector<int>& working_set,
71 const Eigen::SparseMatrix<double>& x,
72 const Eigen::VectorXd& x_centers,
73 const Eigen::VectorXd& x_scales,
74 const Eigen::MatrixXd& y) override;
75
77 void run(Eigen::VectorXd& beta0,
78 Eigen::VectorXd& beta,
79 Eigen::MatrixXd& eta,
80 const Eigen::ArrayXd& lambda,
81 const std::unique_ptr<Loss>& loss,
82 const SortedL1Norm& penalty,
83 const Eigen::VectorXd& gradient,
84 const std::vector<int>& working_set,
85 const Eigen::Map<Eigen::MatrixXd>& x,
86 const Eigen::VectorXd& x_centers,
87 const Eigen::VectorXd& x_scales,
88 const Eigen::MatrixXd& y) override;
89
91 void run(Eigen::VectorXd& beta0,
92 Eigen::VectorXd& beta,
93 Eigen::MatrixXd& eta,
94 const Eigen::ArrayXd& lambda,
95 const std::unique_ptr<Loss>& loss,
96 const SortedL1Norm& penalty,
97 const Eigen::VectorXd& gradient,
98 const std::vector<int>& working_set,
99 const Eigen::Map<Eigen::SparseMatrix<double>>& x,
100 const Eigen::VectorXd& x_centers,
101 const Eigen::VectorXd& x_scales,
102 const Eigen::MatrixXd& y) override;
103
104private:
105 template<typename MatrixType>
106 void runImpl(Eigen::VectorXd& beta0,
107 Eigen::VectorXd& beta,
108 Eigen::MatrixXd& eta,
109 const Eigen::ArrayXd& lambda,
110 const std::unique_ptr<Loss>& loss,
111 const SortedL1Norm& penalty,
112 const Eigen::VectorXd& gradient,
113 const std::vector<int>& working_set,
114 const MatrixType& x,
115 const Eigen::VectorXd& x_centers,
116 const Eigen::VectorXd& x_scales,
117 const Eigen::MatrixXd& y)
118 {
119 using Eigen::MatrixXd;
120 using Eigen::VectorXd;
121
122 int n_working = working_set.size();
123
124 Eigen::VectorXd beta_old = beta(working_set);
125 Eigen::VectorXd beta_diff(n_working);
126 Eigen::VectorXd beta0_old = beta0;
127
128 double g_old = loss->loss(eta, y);
129 double t_old = t;
130
131 Eigen::MatrixXd residual = loss->residual(eta, y);
132 Eigen::VectorXd intercept_grad = residual.colwise().mean();
133 Eigen::VectorXd grad_working = gradient(working_set);
134
135 int line_search_iter = 0;
136 const int max_line_search_iter = 100; // maximum iterations before exit
137
138 while (true) {
139 if (intercept) {
140 beta0 = beta0_old - this->learning_rate * intercept_grad;
141 }
142
143 beta(working_set) =
144 penalty.prox(beta_old - this->learning_rate * grad_working,
145 this->learning_rate * lambda.head(n_working));
146
147 beta_diff = beta(working_set) - beta_old;
148 double beta_diff_norm =
149 beta_diff.dot(grad_working) +
150 (1.0 / (2 * this->learning_rate)) * beta_diff.squaredNorm();
151
152 if (intercept) {
153 Eigen::VectorXd beta0_diff = beta0 - beta0_old;
154
155 beta_diff_norm +=
156 intercept_grad.dot(beta0_diff) +
157 (1.0 / (2 * this->learning_rate)) * beta0_diff.squaredNorm();
158 }
159
160 eta = linearPredictor(x,
161 working_set,
162 beta0,
163 beta,
164 x_centers,
165 x_scales,
167 intercept);
168
169 double g = loss->loss(eta, y);
170 double q = g_old + beta_diff_norm;
171
172 if (q >= g * (1 - 1e-12) || this->learning_rate < 1e-12) {
173 this->learning_rate *= 1.1;
174 break;
175 } else {
176 this->learning_rate *= this->learning_rate_decr;
177 }
178
179 line_search_iter++;
180 if (line_search_iter >= max_line_search_iter) {
181 break;
182 }
183 }
184
185 if (update_type == "fista") {
186 if (beta_prev.size() == 0) {
187 beta_prev = beta;
188 }
189
190 this->t = 0.5 * (1.0 + std::sqrt(1.0 + 4.0 * t_old * t_old));
191 Eigen::VectorXd beta_current = beta(working_set);
192
193 beta(working_set) +=
194 (beta_current - beta_prev(working_set)) * (t_old - 1.0) / this->t;
195 beta_prev(working_set) = beta_current;
196
197 eta = linearPredictor(x,
198 working_set,
199 beta0,
200 beta,
201 x_centers,
202 x_scales,
204 intercept);
205 }
206 }
207
208 double learning_rate;
209 double learning_rate_decr;
210 std::string update_type;
211 double t;
212 Eigen::VectorXd beta_prev;
213};
214
215} // namespace slope
Proximal Gradient Descent solver for SLOPE optimization.
Definition pgd.h:29
void run(Eigen::VectorXd &beta0, Eigen::VectorXd &beta, Eigen::MatrixXd &eta, const Eigen::ArrayXd &lambda, const std::unique_ptr< Loss > &loss, const SortedL1Norm &penalty, const Eigen::VectorXd &gradient, const std::vector< int > &working_set, const Eigen::Map< Eigen::MatrixXd > &x, const Eigen::VectorXd &x_centers, const Eigen::VectorXd &x_scales, const Eigen::MatrixXd &y) override
Pure virtual function defining the solver's optimization routine.
void run(Eigen::VectorXd &beta0, Eigen::VectorXd &beta, Eigen::MatrixXd &eta, const Eigen::ArrayXd &lambda, const std::unique_ptr< Loss > &loss, const SortedL1Norm &penalty, const Eigen::VectorXd &gradient, const std::vector< int > &working_set, const Eigen::SparseMatrix< double > &x, const Eigen::VectorXd &x_centers, const Eigen::VectorXd &x_scales, const Eigen::MatrixXd &y) override
Pure virtual function defining the solver's optimization routine.
void run(Eigen::VectorXd &beta0, Eigen::VectorXd &beta, Eigen::MatrixXd &eta, const Eigen::ArrayXd &lambda, const std::unique_ptr< Loss > &loss, const SortedL1Norm &penalty, const Eigen::VectorXd &gradient, const std::vector< int > &working_set, const Eigen::MatrixXd &x, const Eigen::VectorXd &x_centers, const Eigen::VectorXd &x_scales, const Eigen::MatrixXd &y) override
Pure virtual function defining the solver's optimization routine.
PGD(JitNormalization jit_normalization, bool intercept, const std::string &update_type)
Constructs Proximal Gradient Descent solver for SLOPE optimization.
Definition pgd.h:37
void run(Eigen::VectorXd &beta0, Eigen::VectorXd &beta, Eigen::MatrixXd &eta, const Eigen::ArrayXd &lambda, const std::unique_ptr< Loss > &loss, const SortedL1Norm &penalty, const Eigen::VectorXd &gradient, const std::vector< int > &working_set, const Eigen::Map< Eigen::SparseMatrix< double > > &x, const Eigen::VectorXd &x_centers, const Eigen::VectorXd &x_scales, const Eigen::MatrixXd &y) override
Pure virtual function defining the solver's optimization routine.
Abstract base class for SLOPE optimization solvers.
Definition solver.h:30
JitNormalization jit_normalization
JIT feature normalization strategy.
Definition solver.h:165
bool intercept
If true, fits intercept term.
Definition solver.h:166
Class representing the Sorted L1 Norm.
Eigen::MatrixXd prox(const Eigen::VectorXd &beta, const Eigen::ArrayXd &lambda) const
Computes the proximal operator of the Sorted L1 Norm.
Namespace containing SLOPE regression implementation.
Definition clusters.h:11
JitNormalization
Enums to control predictor standardization behavior.
Eigen::MatrixXd linearPredictor(const T &x, const std::vector< int > &active_set, const Eigen::VectorXd &beta0, const Eigen::VectorXd &beta, const Eigen::VectorXd &x_centers, const Eigen::VectorXd &x_scales, const JitNormalization jit_normalization, const bool intercept)
Definition math.h:153
Numerical solver class for SLOPE (Sorted L-One Penalized Estimation)