loss_function.h 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433
  1. // Ceres Solver - A fast non-linear least squares minimizer
  2. // Copyright 2019 Google Inc. All rights reserved.
  3. // http://ceres-solver.org/
  4. //
  5. // Redistribution and use in source and binary forms, with or without
  6. // modification, are permitted provided that the following conditions are met:
  7. //
  8. // * Redistributions of source code must retain the above copyright notice,
  9. // this list of conditions and the following disclaimer.
  10. // * Redistributions in binary form must reproduce the above copyright notice,
  11. // this list of conditions and the following disclaimer in the documentation
  12. // and/or other materials provided with the distribution.
  13. // * Neither the name of Google Inc. nor the names of its contributors may be
  14. // used to endorse or promote products derived from this software without
  15. // specific prior written permission.
  16. //
  17. // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  18. // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  19. // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  20. // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  21. // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  22. // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  23. // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  24. // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  25. // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  26. // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  27. // POSSIBILITY OF SUCH DAMAGE.
  28. //
  29. // Author: sameeragarwal@google.com (Sameer Agarwal)
  30. //
  31. // The LossFunction interface is the way users describe how residuals
  32. // are converted to cost terms for the overall problem cost function.
  33. // For the exact manner in which loss functions are converted to the
  34. // overall cost for a problem, see problem.h.
  35. //
  36. // For least squares problem where there are no outliers and standard
  37. // squared loss is expected, it is not necessary to create a loss
  38. // function; instead passing a nullptr to the problem when adding
  39. // residuals implies a standard squared loss.
  40. //
  41. // For least squares problems where the minimization may encounter
  42. // input terms that contain outliers, that is, completely bogus
  43. // measurements, it is important to use a loss function that reduces
  44. // their associated penalty.
  45. //
  46. // Consider a structure from motion problem. The unknowns are 3D
  47. // points and camera parameters, and the measurements are image
  48. // coordinates describing the expected reprojected position for a
  49. // point in a camera. For example, we want to model the geometry of a
  50. // street scene with fire hydrants and cars, observed by a moving
  51. // camera with unknown parameters, and the only 3D points we care
  52. // about are the pointy tippy-tops of the fire hydrants. Our magic
  53. // image processing algorithm, which is responsible for producing the
  54. // measurements that are input to Ceres, has found and matched all
  55. // such tippy-tops in all image frames, except that in one of the
  56. // frame it mistook a car's headlight for a hydrant. If we didn't do
  57. // anything special (i.e. if we used a basic quadratic loss), the
  58. // residual for the erroneous measurement will result in extreme error
  59. // due to the quadratic nature of squared loss. This results in the
  60. // entire solution getting pulled away from the optimum to reduce
  61. // the large error that would otherwise be attributed to the wrong
  62. // measurement.
  63. //
  64. // Using a robust loss function, the cost for large residuals is
  65. // reduced. In the example above, this leads to outlier terms getting
  66. // downweighted so they do not overly influence the final solution.
  67. //
  68. // What cost function is best?
  69. //
  70. // In general, there isn't a principled way to select a robust loss
  71. // function. The authors suggest starting with a non-robust cost, then
  72. // only experimenting with robust loss functions if standard squared
  73. // loss doesn't work.
  74. #ifndef CERES_PUBLIC_LOSS_FUNCTION_H_
  75. #define CERES_PUBLIC_LOSS_FUNCTION_H_
  76. #include <memory>
  77. #include "ceres/internal/disable_warnings.h"
  78. #include "ceres/internal/export.h"
  79. #include "ceres/types.h"
  80. #include "glog/logging.h"
  81. namespace ceres {
  82. class CERES_EXPORT LossFunction {
  83. public:
  84. virtual ~LossFunction();
  85. // For a residual vector with squared 2-norm 'sq_norm', this method
  86. // is required to fill in the value and derivatives of the loss
  87. // function (rho in this example):
  88. //
  89. // out[0] = rho(sq_norm),
  90. // out[1] = rho'(sq_norm),
  91. // out[2] = rho''(sq_norm),
  92. //
  93. // Here the convention is that the contribution of a term to the
  94. // cost function is given by 1/2 rho(s), where
  95. //
  96. // s = ||residuals||^2.
  97. //
  98. // Calling the method with a negative value of 's' is an error and
  99. // the implementations are not required to handle that case.
  100. //
  101. // Most sane choices of rho() satisfy:
  102. //
  103. // rho(0) = 0,
  104. // rho'(0) = 1,
  105. // rho'(s) < 1 in outlier region,
  106. // rho''(s) < 0 in outlier region,
  107. //
  108. // so that they mimic the least squares cost for small residuals.
  109. virtual void Evaluate(double sq_norm, double out[3]) const = 0;
  110. };
  111. // Some common implementations follow below.
  112. //
  113. // Note: in the region of interest (i.e. s < 3) we have:
  114. // TrivialLoss >= HuberLoss >= SoftLOneLoss >= CauchyLoss
  115. // This corresponds to no robustification.
  116. //
  117. // rho(s) = s
  118. //
  119. // At s = 0: rho = [0, 1, 0].
  120. //
  121. // It is not normally necessary to use this, as passing nullptr for the
  122. // loss function when building the problem accomplishes the same
  123. // thing.
  124. class CERES_EXPORT TrivialLoss final : public LossFunction {
  125. public:
  126. void Evaluate(double, double*) const override;
  127. };
  128. // Scaling
  129. // -------
  130. // Given one robustifier
  131. // s -> rho(s)
  132. // one can change the length scale at which robustification takes
  133. // place, by adding a scale factor 'a' as follows:
  134. //
  135. // s -> a^2 rho(s / a^2).
  136. //
  137. // The first and second derivatives are:
  138. //
  139. // s -> rho'(s / a^2),
  140. // s -> (1 / a^2) rho''(s / a^2),
  141. //
  142. // but the behaviour near s = 0 is the same as the original function,
  143. // i.e.
  144. //
  145. // rho(s) = s + higher order terms,
  146. // a^2 rho(s / a^2) = s + higher order terms.
  147. //
  148. // The scalar 'a' should be positive.
  149. //
  150. // The reason for the appearance of squaring is that 'a' is in the
  151. // units of the residual vector norm whereas 's' is a squared
  152. // norm. For applications it is more convenient to specify 'a' than
  153. // its square. The commonly used robustifiers below are described in
  154. // un-scaled format (a = 1) but their implementations work for any
  155. // non-zero value of 'a'.
  156. // Huber.
  157. //
  158. // rho(s) = s for s <= 1,
  159. // rho(s) = 2 sqrt(s) - 1 for s >= 1.
  160. //
  161. // At s = 0: rho = [0, 1, 0].
  162. //
  163. // The scaling parameter 'a' corresponds to 'delta' on this page:
  164. // http://en.wikipedia.org/wiki/Huber_Loss_Function
  165. class CERES_EXPORT HuberLoss final : public LossFunction {
  166. public:
  167. explicit HuberLoss(double a) : a_(a), b_(a * a) {}
  168. void Evaluate(double, double*) const override;
  169. private:
  170. const double a_;
  171. // b = a^2.
  172. const double b_;
  173. };
  174. // Soft L1, similar to Huber but smooth.
  175. //
  176. // rho(s) = 2 (sqrt(1 + s) - 1).
  177. //
  178. // At s = 0: rho = [0, 1, -1 / (2 * a^2)].
  179. class CERES_EXPORT SoftLOneLoss final : public LossFunction {
  180. public:
  181. explicit SoftLOneLoss(double a) : b_(a * a), c_(1 / b_) {}
  182. void Evaluate(double, double*) const override;
  183. private:
  184. // b = a^2.
  185. const double b_;
  186. // c = 1 / a^2.
  187. const double c_;
  188. };
  189. // Inspired by the Cauchy distribution
  190. //
  191. // rho(s) = log(1 + s).
  192. //
  193. // At s = 0: rho = [0, 1, -1 / a^2].
  194. class CERES_EXPORT CauchyLoss final : public LossFunction {
  195. public:
  196. explicit CauchyLoss(double a) : b_(a * a), c_(1 / b_) {}
  197. void Evaluate(double, double*) const override;
  198. private:
  199. // b = a^2.
  200. const double b_;
  201. // c = 1 / a^2.
  202. const double c_;
  203. };
  204. // Loss that is capped beyond a certain level using the arc-tangent function.
  205. // The scaling parameter 'a' determines the level where falloff occurs.
  206. // For costs much smaller than 'a', the loss function is linear and behaves like
  207. // TrivialLoss, and for values much larger than 'a' the value asymptotically
  208. // approaches the constant value of a * PI / 2.
  209. //
  210. // rho(s) = a atan(s / a).
  211. //
  212. // At s = 0: rho = [0, 1, 0].
  213. class CERES_EXPORT ArctanLoss final : public LossFunction {
  214. public:
  215. explicit ArctanLoss(double a) : a_(a), b_(1 / (a * a)) {}
  216. void Evaluate(double, double*) const override;
  217. private:
  218. const double a_;
  219. // b = 1 / a^2.
  220. const double b_;
  221. };
  222. // Loss function that maps to approximately zero cost in a range around the
  223. // origin, and reverts to linear in error (quadratic in cost) beyond this range.
  224. // The tolerance parameter 'a' sets the nominal point at which the
  225. // transition occurs, and the transition size parameter 'b' sets the nominal
  226. // distance over which most of the transition occurs. Both a and b must be
  227. // greater than zero, and typically b will be set to a fraction of a.
  228. // The slope rho'[s] varies smoothly from about 0 at s <= a - b to
  229. // about 1 at s >= a + b.
  230. //
  231. // The term is computed as:
  232. //
  233. // rho(s) = b log(1 + exp((s - a) / b)) - c0.
  234. //
  235. // where c0 is chosen so that rho(0) == 0
  236. //
  237. // c0 = b log(1 + exp(-a / b)
  238. //
  239. // This has the following useful properties:
  240. //
  241. // rho(s) == 0 for s = 0
  242. // rho'(s) ~= 0 for s << a - b
  243. // rho'(s) ~= 1 for s >> a + b
  244. // rho''(s) > 0 for all s
  245. //
  246. // In addition, all derivatives are continuous, and the curvature is
  247. // concentrated in the range a - b to a + b.
  248. //
  249. // At s = 0: rho = [0, ~0, ~0].
  250. class CERES_EXPORT TolerantLoss final : public LossFunction {
  251. public:
  252. explicit TolerantLoss(double a, double b);
  253. void Evaluate(double, double*) const override;
  254. private:
  255. const double a_, b_, c_;
  256. };
  257. // This is the Tukey biweight loss function which aggressively
  258. // attempts to suppress large errors.
  259. //
  260. // The term is computed as follows where the equations are scaled by a
  261. // factor of 2 because the cost function is given by 1/2 rho(s):
  262. //
  263. // rho(s) = a^2 / 3 * (1 - (1 - s / a^2)^3 ) for s <= a^2,
  264. // rho(s) = a^2 / 3 for s > a^2.
  265. //
  266. // At s = 0: rho = [0, 1, -2 / a^2]
  267. class CERES_EXPORT TukeyLoss final : public ceres::LossFunction {
  268. public:
  269. explicit TukeyLoss(double a) : a_squared_(a * a) {}
  270. void Evaluate(double, double*) const override;
  271. private:
  272. const double a_squared_;
  273. };
  274. // Composition of two loss functions. The error is the result of first
  275. // evaluating g followed by f to yield the composition f(g(s)).
  276. // The loss functions must not be nullptr.
  277. class CERES_EXPORT ComposedLoss final : public LossFunction {
  278. public:
  279. explicit ComposedLoss(const LossFunction* f,
  280. Ownership ownership_f,
  281. const LossFunction* g,
  282. Ownership ownership_g);
  283. ~ComposedLoss() override;
  284. void Evaluate(double, double*) const override;
  285. private:
  286. std::unique_ptr<const LossFunction> f_, g_;
  287. const Ownership ownership_f_, ownership_g_;
  288. };
  289. // The discussion above has to do with length scaling: it affects the space
  290. // in which s is measured. Sometimes you want to simply scale the output
  291. // value of the robustifier. For example, you might want to weight
  292. // different error terms differently (e.g., weight pixel reprojection
  293. // errors differently from terrain errors).
  294. //
  295. // If rho is the wrapped robustifier, then this simply outputs
  296. // s -> a * rho(s)
  297. //
  298. // The first and second derivatives are, not surprisingly
  299. // s -> a * rho'(s)
  300. // s -> a * rho''(s)
  301. //
  302. // Since we treat the a nullptr Loss function as the Identity loss
  303. // function, rho = nullptr is a valid input and will result in the input
  304. // being scaled by a. This provides a simple way of implementing a
  305. // scaled ResidualBlock.
  306. class CERES_EXPORT ScaledLoss final : public LossFunction {
  307. public:
  308. // Constructs a ScaledLoss wrapping another loss function. Takes
  309. // ownership of the wrapped loss function or not depending on the
  310. // ownership parameter.
  311. ScaledLoss(const LossFunction* rho, double a, Ownership ownership)
  312. : rho_(rho), a_(a), ownership_(ownership) {}
  313. ScaledLoss(const ScaledLoss&) = delete;
  314. void operator=(const ScaledLoss&) = delete;
  315. ~ScaledLoss() override {
  316. if (ownership_ == DO_NOT_TAKE_OWNERSHIP) {
  317. rho_.release();
  318. }
  319. }
  320. void Evaluate(double, double*) const override;
  321. private:
  322. std::unique_ptr<const LossFunction> rho_;
  323. const double a_;
  324. const Ownership ownership_;
  325. };
  326. // Sometimes after the optimization problem has been constructed, we
  327. // wish to mutate the scale of the loss function. For example, when
  328. // performing estimation from data which has substantial outliers,
  329. // convergence can be improved by starting out with a large scale,
  330. // optimizing the problem and then reducing the scale. This can have
  331. // better convergence behaviour than just using a loss function with a
  332. // small scale.
  333. //
  334. // This templated class allows the user to implement a loss function
  335. // whose scale can be mutated after an optimization problem has been
  336. // constructed.
  337. //
  338. // Since we treat the a nullptr Loss function as the Identity loss
  339. // function, rho = nullptr is a valid input.
  340. //
  341. // Example usage
  342. //
  343. // Problem problem;
  344. //
  345. // // Add parameter blocks
  346. //
  347. // CostFunction* cost_function =
  348. // new AutoDiffCostFunction < UW_Camera_Mapper, 2, 9, 3>(
  349. // new UW_Camera_Mapper(feature_x, feature_y));
  350. //
  351. // LossFunctionWrapper* loss_function = new LossFunctionWrapper(
  352. // new HuberLoss(1.0), TAKE_OWNERSHIP);
  353. //
  354. // problem.AddResidualBlock(cost_function, loss_function, parameters);
  355. //
  356. // Solver::Options options;
  357. // Solger::Summary summary;
  358. //
  359. // Solve(options, &problem, &summary)
  360. //
  361. // loss_function->Reset(new HuberLoss(1.0), TAKE_OWNERSHIP);
  362. //
  363. // Solve(options, &problem, &summary)
  364. //
  365. class CERES_EXPORT LossFunctionWrapper final : public LossFunction {
  366. public:
  367. LossFunctionWrapper(LossFunction* rho, Ownership ownership)
  368. : rho_(rho), ownership_(ownership) {}
  369. LossFunctionWrapper(const LossFunctionWrapper&) = delete;
  370. void operator=(const LossFunctionWrapper&) = delete;
  371. ~LossFunctionWrapper() override {
  372. if (ownership_ == DO_NOT_TAKE_OWNERSHIP) {
  373. rho_.release();
  374. }
  375. }
  376. void Evaluate(double sq_norm, double out[3]) const override {
  377. if (rho_.get() == nullptr) {
  378. out[0] = sq_norm;
  379. out[1] = 1.0;
  380. out[2] = 0.0;
  381. } else {
  382. rho_->Evaluate(sq_norm, out);
  383. }
  384. }
  385. void Reset(LossFunction* rho, Ownership ownership) {
  386. if (ownership_ == DO_NOT_TAKE_OWNERSHIP) {
  387. rho_.release();
  388. }
  389. rho_.reset(rho);
  390. ownership_ = ownership;
  391. }
  392. private:
  393. std::unique_ptr<const LossFunction> rho_;
  394. Ownership ownership_;
  395. };
  396. } // namespace ceres
  397. #include "ceres/internal/reenable_warnings.h"
  398. #endif // CERES_PUBLIC_LOSS_FUNCTION_H_