@@ -151,7 +151,7 @@ struct LevenbergMarquardtOptimizer<DTable, OptimizerType::Eigen> final : public
151
151
Operon::Interpreter<Operon::Scalar, DTable> interpreter{dtable, dataset, tree};
152
152
Operon::LMCostFunction<Operon::Scalar> cf{interpreter, target, range};
153
153
Eigen::LevenbergMarquardt<decltype (cf)> lm (cf);
154
- lm.setMaxfev (static_cast <int >(iterations+ 1 ));
154
+ lm.setMaxfev (static_cast <int >(iterations));
155
155
156
156
auto x0 = tree.GetCoefficients ();
157
157
OptimizerSummary summary;
@@ -195,50 +195,71 @@ struct LevenbergMarquardtOptimizer<DTable, OptimizerType::Eigen> final : public
195
195
};
196
196
197
197
#if defined(HAVE_CERES)
198
- template <typename T = Operon::Scalar >
199
- struct NonlinearLeastSquaresOptimizer <T , OptimizerType::Ceres> : public OptimizerBase<T> {
200
- explicit NonlinearLeastSquaresOptimizer (InterpreterBase<T>& interpreter )
201
- : OptimizerBase<T>{interpreter }
198
+ template <typename DTable >
199
+ struct LevenbergMarquardtOptimizer <DTable , OptimizerType::Ceres> final : public OptimizerBase {
200
+ explicit LevenbergMarquardtOptimizer (DTable const & dtable, Problem const & problem )
201
+ : OptimizerBase{problem}, dtable_{dtable }
202
202
{
203
203
}
204
204
205
- auto Optimize (Operon::Span< Operon::Scalar const > target, Range range, size_t iterations, OptimizerSummary& summary) -> std::vector<Operon::Scalar> final
205
+ [[nodiscard]] auto Optimize (Operon::RandomGenerator& /* unused */ , Operon::Tree const & tree) const -> OptimizerSummary final
206
206
{
207
- auto const & tree = this ->GetTree ();
208
- auto const & ds = this ->GetDataset ();
209
- auto const & dt = this ->GetDispatchTable ();
210
-
211
- auto x0 = tree.GetCoefficients ();
207
+ auto const & dtable = this ->GetDispatchTable ();
208
+ auto const & problem = this ->GetProblem ();
209
+ auto const & dataset = problem.GetDataset ();
210
+ auto range = problem.TrainingRange ();
211
+ auto target = problem.TargetValues (range);
212
+ auto iterations = this ->Iterations ();;
212
213
213
- Operon::CostFunction<DTable, Eigen::RowMajor> cf (tree, ds, target, range, dt );
214
- auto costFunction = new Operon::DynamicCostFunction (cf); // NOLINT
214
+ auto initialParameters = tree. GetCoefficients ( );
215
+ auto finalParameters = initialParameters;
215
216
217
+ Operon::Interpreter<Operon::Scalar, DTable> interpreter{dtable, dataset, tree};
218
+ Operon::LMCostFunction<Operon::Scalar, Eigen::RowMajor> cf{interpreter, target, range};
219
+ auto * dynamicCostFunction = new Operon::DynamicCostFunction{cf};
216
220
ceres::Solver::Summary s;
217
- if (!x0 .empty ()) {
218
- Eigen::Map<Eigen::Matrix<Operon::Scalar, - 1 , 1 >> m0 (x0. data (), std::ssize (x0) );
219
- auto sz = static_cast <Eigen::Index>(x0. size () );
220
- Eigen::VectorXd params = Eigen::Map<Eigen::Matrix<Operon::Scalar, - 1 , 1 >>(x0. data (), sz) .template cast <double >();
221
+ if (!initialParameters .empty ()) {
222
+ auto sz = std::ssize (finalParameters );
223
+ Eigen::Map <Eigen::Matrix<Operon::Scalar, - 1 , 1 >> m0 (finalParameters. data (), sz );
224
+ Eigen::VectorXd params = m0 .template cast <double >();
221
225
ceres::Problem problem;
222
- problem.AddResidualBlock (costFunction , nullptr , params.data ());
226
+ problem.AddResidualBlock (dynamicCostFunction , nullptr , params.data ());
223
227
ceres::Solver::Options options;
224
228
options.linear_solver_type = ceres::DENSE_QR;
225
229
options.logging_type = ceres::LoggingType::SILENT;
226
- options.max_num_iterations = static_cast <int >(iterations - 1 ); // workaround since for some reason ceres sometimes does 1 more iteration
230
+ options.max_num_iterations = static_cast <int >(iterations);
227
231
options.minimizer_progress_to_stdout = false ;
228
232
options.num_threads = 1 ;
229
233
options.trust_region_strategy_type = ceres::LEVENBERG_MARQUARDT;
230
234
options.use_inner_iterations = false ;
231
235
Solve (options, &problem, &s);
232
236
m0 = params.cast <Operon::Scalar>();
233
237
}
234
- summary.InitialCost = s.initial_cost ;
235
- summary.FinalCost = s.final_cost ;
236
- summary.Iterations = static_cast <int >(s.iterations .size ());
237
- summary.FunctionEvaluations = s.num_residual_evaluations ;
238
- summary.JacobianEvaluations = s.num_jacobian_evaluations ;
239
- summary.Success = detail::CheckSuccess (summary.InitialCost , summary.FinalCost );
240
- return x0;
238
+ return Operon::OptimizerSummary {
239
+ .InitialParameters = initialParameters,
240
+ .FinalParameters = finalParameters,
241
+ .InitialCost = static_cast <Operon::Scalar>(s.initial_cost ),
242
+ .FinalCost = static_cast <Operon::Scalar>(s.final_cost ),
243
+ .Iterations = static_cast <int >(s.iterations .size ()),
244
+ .FunctionEvaluations = s.num_residual_evaluations ,
245
+ .JacobianEvaluations = s.num_jacobian_evaluations ,
246
+ .Success = detail::CheckSuccess (s.initial_cost , s.final_cost )
247
+ };
241
248
}
249
+
250
+ auto GetDispatchTable () const -> DTable const & { return dtable_.get (); }
251
+
252
+ [[nodiscard]] auto ComputeLikelihood (Operon::Span<Operon::Scalar const > x, Operon::Span<Operon::Scalar const > y, Operon::Span<Operon::Scalar const > w) const -> Operon::Scalar final
253
+ {
254
+ return GaussianLikelihood<Operon::Scalar>::ComputeLikelihood (x, y, w);
255
+ }
256
+
257
+ [[nodiscard]] auto ComputeFisherMatrix (Operon::Span<Operon::Scalar const > pred, Operon::Span<Operon::Scalar const > jac, Operon::Span<Operon::Scalar const > sigma) const -> Eigen::Matrix<Operon::Scalar, -1, -1> final {
258
+ return GaussianLikelihood<Operon::Scalar>::ComputeFisherMatrix (pred, jac, sigma);
259
+ }
260
+
261
+ private:
262
+ std::reference_wrapper<DTable const > dtable_;
242
263
};
243
264
#endif
244
265
@@ -298,12 +319,12 @@ struct LBFGSOptimizer final : public OptimizerBase {
298
319
299
320
auto GetDispatchTable () const -> DTable const & { return dtable_.get (); }
300
321
301
- [[nodiscard]] virtual auto ComputeLikelihood (Operon::Span<Operon::Scalar const > x, Operon::Span<Operon::Scalar const > y, Operon::Span<Operon::Scalar const > w) const -> Operon::Scalar
322
+ [[nodiscard]] auto ComputeLikelihood (Operon::Span<Operon::Scalar const > x, Operon::Span<Operon::Scalar const > y, Operon::Span<Operon::Scalar const > w) const -> Operon::Scalar override
302
323
{
303
324
return LossFunction::ComputeLikelihood (x, y, w);
304
325
}
305
326
306
- [[nodiscard]] virtual auto ComputeFisherMatrix (Operon::Span<Operon::Scalar const > pred, Operon::Span<Operon::Scalar const > jac, Operon::Span<Operon::Scalar const > sigma) const -> Eigen::Matrix<Operon::Scalar, -1, -1> final {
327
+ [[nodiscard]] auto ComputeFisherMatrix (Operon::Span<Operon::Scalar const > pred, Operon::Span<Operon::Scalar const > jac, Operon::Span<Operon::Scalar const > sigma) const -> Eigen::Matrix<Operon::Scalar, -1, -1> final {
307
328
return LossFunction::ComputeFisherMatrix (pred, jac, sigma);
308
329
}
309
330
@@ -371,12 +392,12 @@ struct SGDOptimizer final : public OptimizerBase {
371
392
return summary;
372
393
}
373
394
374
- [[nodiscard]] virtual auto ComputeLikelihood (Operon::Span<Operon::Scalar const > x, Operon::Span<Operon::Scalar const > y, Operon::Span<Operon::Scalar const > w) const -> Operon::Scalar
395
+ [[nodiscard]] auto ComputeLikelihood (Operon::Span<Operon::Scalar const > x, Operon::Span<Operon::Scalar const > y, Operon::Span<Operon::Scalar const > w) const -> Operon::Scalar override
375
396
{
376
397
return LossFunction::ComputeLikelihood (x, y, w);
377
398
}
378
399
379
- [[nodiscard]] virtual auto ComputeFisherMatrix (Operon::Span<Operon::Scalar const > pred, Operon::Span<Operon::Scalar const > jac, Operon::Span<Operon::Scalar const > sigma) const -> Eigen::Matrix<Operon::Scalar, -1, -1> final {
400
+ [[nodiscard]] auto ComputeFisherMatrix (Operon::Span<Operon::Scalar const > pred, Operon::Span<Operon::Scalar const > jac, Operon::Span<Operon::Scalar const > sigma) const -> Eigen::Matrix<Operon::Scalar, -1, -1> final {
380
401
return LossFunction::ComputeFisherMatrix (pred, jac, sigma);
381
402
}
382
403
0 commit comments