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