1 | /* Copyright 2016 The TensorFlow Authors. All Rights Reserved. |
2 | |
3 | Licensed under the Apache License, Version 2.0 (the "License"); |
4 | you may not use this file except in compliance with the License. |
5 | You may obtain a copy of the License at |
6 | |
7 | http://www.apache.org/licenses/LICENSE-2.0 |
8 | |
9 | Unless required by applicable law or agreed to in writing, software |
10 | distributed under the License is distributed on an "AS IS" BASIS, |
11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
12 | See the License for the specific language governing permissions and |
13 | limitations under the License. |
14 | ==============================================================================*/ |
15 | |
16 | #ifndef TENSORFLOW_CORE_KERNELS_POISSON_LOSS_H_ |
17 | #define TENSORFLOW_CORE_KERNELS_POISSON_LOSS_H_ |
18 | |
19 | #include <cmath> |
20 | |
21 | #include "tensorflow/core/kernels/loss.h" |
22 | #include "tensorflow/core/lib/core/errors.h" |
23 | |
24 | namespace tensorflow { |
25 | |
26 | class PoissonLossUpdater : public DualLossUpdater { |
27 | public: |
28 | // Update is found by a Newton algorithm (see readme.md). |
29 | double ComputeUpdatedDual(const int num_loss_partitions, const double label, |
30 | const double example_weight, |
31 | const double current_dual, const double wx, |
32 | const double weighted_example_norm) const final { |
33 | // Newton algorithm converges quadratically so 10 steps will be largely |
34 | // enough to achieve a very good precision |
35 | static const int newton_total_steps = 10; |
36 | // Initialize the Newton optimization at x such that |
37 | // exp(x) = label - current_dual |
38 | const double y_minus_a = label - current_dual; |
39 | double x = (y_minus_a > 0) ? log(y_minus_a) : 0; |
40 | for (int i = 0; i < newton_total_steps; ++i) { |
41 | x = NewtonStep(x, num_loss_partitions, label, wx, example_weight, |
42 | weighted_example_norm, current_dual); |
43 | } |
44 | return label - exp(x); |
45 | } |
46 | |
47 | // Dual of poisson loss function. |
48 | // https://en.wikipedia.org/wiki/Convex_conjugate |
49 | double ComputeDualLoss(const double current_dual, const double example_label, |
50 | const double example_weight) const final { |
51 | // Dual of the poisson loss function is |
52 | // (y-a)*(log(y-a)-1), where a is the dual variable. |
53 | // It is defined only for a<y. |
54 | const double y_minus_a = example_label - current_dual; |
55 | if (y_minus_a == 0.0) { |
56 | // (y-a)*(log(y-a)-1) approaches 0 as y-a approaches 0. |
57 | return 0.0; |
58 | } |
59 | if (y_minus_a < 0.0) { |
60 | return std::numeric_limits<double>::max(); |
61 | } |
62 | return y_minus_a * (log(y_minus_a) - 1) * example_weight; |
63 | } |
64 | |
65 | double ComputePrimalLoss(const double wx, const double example_label, |
66 | const double example_weight) const final { |
67 | return (exp(wx) - wx * example_label) * example_weight; |
68 | } |
69 | |
70 | double PrimalLossDerivative(const double wx, const double label, |
71 | const double example_weight) const final { |
72 | return (exp(wx) - label) * example_weight; |
73 | } |
74 | |
75 | // TODO(chapelle): We need to introduce a maximum_prediction parameter, |
76 | // expose that parameter to the user and have this method return |
77 | // 1.0/maximum_prediction. |
78 | // Setting this at 1 for now, it only impacts the adaptive sampling. |
79 | double SmoothnessConstant() const final { return 1; } |
80 | |
81 | Status ConvertLabel(float* const example_label) const final { |
82 | if (*example_label < 0.0) { |
83 | return errors::InvalidArgument( |
84 | "Only non-negative labels can be used with the Poisson log loss. " |
85 | "Found example with label: " , *example_label); |
86 | } |
87 | return OkStatus(); |
88 | } |
89 | |
90 | private: |
91 | // One Newton step (see readme.md). |
92 | double NewtonStep(const double x, const int num_loss_partitions, |
93 | const double label, const double wx, |
94 | const double example_weight, |
95 | const double weighted_example_norm, |
96 | const double current_dual) const { |
97 | const double expx = exp(x); |
98 | const double numerator = |
99 | x - wx - num_loss_partitions * weighted_example_norm * |
100 | example_weight * (label - current_dual - expx); |
101 | const double denominator = |
102 | 1 + num_loss_partitions * weighted_example_norm * example_weight * expx; |
103 | return x - numerator / denominator; |
104 | } |
105 | }; |
106 | |
107 | } // namespace tensorflow |
108 | |
109 | #endif // TENSORFLOW_CORE_KERNELS_LOGISTIC_LOSS_H_ |
110 | |