~ubuntu-branches/ubuntu/wily/vowpal-wabbit/wily

« back to all changes in this revision

Viewing changes to loss_functions.cc

  • Committer: Bazaar Package Importer
  • Author(s): Yaroslav Halchenko
  • Date: 2010-12-05 09:50:55 UTC
  • mfrom: (1.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20101205095055-o8f7gb0kg145tmst
Tags: 5.0-1
* New upstream release
* DEP-5 copyright file
* Boosted policy to 3.9.1 -- removed reference to BSD-3 file from copyright
* Explicitly build vw.1 target

Show diffs side-by-side

added added

removed removed

Lines of Context:
9
9
using namespace std;
10
10
 
11
11
#include "loss_functions.h"
 
12
#include "global_data.h"
12
13
 
13
14
class squaredloss : public loss_function {
14
15
public:
15
 
        squaredloss() {
16
 
 
17
 
        }
18
 
 
19
 
        double getLoss(double prediction, double label) {
20
 
                double example_loss = (prediction - label) * (prediction - label);
21
 
                return example_loss;
22
 
        }
23
 
 
24
 
        double getUpdate(double prediction, double label) {
25
 
                return (label - prediction);
26
 
        }
27
 
};
 
16
  squaredloss() {
 
17
    
 
18
  }
 
19
  
 
20
  float getLoss(float prediction, float label) {
 
21
    float example_loss = (prediction - label) * (prediction - label);
 
22
    return example_loss;
 
23
  }
 
24
  
 
25
  float getUpdate(float prediction, float label,float eta_t, float norm) {
 
26
    if (eta_t < 1e-6){ 
 
27
      /* When exp(-eta_t)~= 1 we replace 1-exp(-eta_t) 
 
28
       * with its first order Taylor expansion around 0
 
29
       * to avoid catastrophic cancellation.
 
30
       */
 
31
      return (label - prediction)*eta_t/norm;
 
32
    }
 
33
    return (label - prediction)*(1-exp(-eta_t))/norm;
 
34
  }
 
35
  
 
36
  float getRevertingWeight(float prediction, float eta_t){
 
37
    float t = 0.5*(global.min_label+global.max_label);
 
38
    float alternative = (prediction > t) ? global.min_label : global.max_label;
 
39
    return log((alternative-prediction)/(alternative-t))/eta_t;
 
40
  }
 
41
  
 
42
  float getSquareGrad(float prediction, float label) {
 
43
    return (prediction - label) * (prediction - label);
 
44
  }
 
45
  float first_derivative(float prediction, float label)
 
46
  {
 
47
    return 2. * (prediction-label);
 
48
  }
 
49
  float second_derivative(float prediction, float label)
 
50
  {
 
51
    return 2.;
 
52
  } 
 
53
};
 
54
 
 
55
class classic_squaredloss : public loss_function {
 
56
public:
 
57
  classic_squaredloss() {
 
58
    
 
59
  }
 
60
  
 
61
  float getLoss(float prediction, float label) {
 
62
    float example_loss = (prediction - label) * (prediction - label);
 
63
    return example_loss;
 
64
  }
 
65
  
 
66
  float getUpdate(float prediction, float label,float eta_t, float norm) {
 
67
    return eta_t*(label - prediction)/norm;
 
68
  }
 
69
  
 
70
  float getRevertingWeight(float prediction, float eta_t){
 
71
    float t = 0.5*(global.min_label+global.max_label);
 
72
    float alternative = (prediction > t) ? global.min_label : global.max_label;
 
73
    return (t-prediction)/((alternative-prediction)*eta_t);
 
74
  }
 
75
 
 
76
  float getSquareGrad(float prediction, float label) {
 
77
    return (prediction - label) * (prediction - label);
 
78
  }
 
79
  float first_derivative(float prediction, float label)
 
80
  {
 
81
    return 2. * (prediction-label);
 
82
  }
 
83
  float second_derivative(float prediction, float label)
 
84
  {
 
85
    return 2.;
 
86
  }
 
87
};
 
88
 
28
89
 
29
90
class hingeloss : public loss_function {
30
91
public:
31
 
        hingeloss() {
32
 
 
33
 
        }
34
 
 
35
 
        double getLoss(double prediction, double label) {
36
 
                double e = 1 - label*prediction;
37
 
                return (e > 0) ? e : 0;
38
 
        }
39
 
 
40
 
        double getUpdate(double prediction, double label) {
41
 
                if(prediction == label) return 0;
42
 
                return label;
43
 
 
44
 
        }
 
92
  hingeloss() {
 
93
    
 
94
  }
 
95
  
 
96
  float getLoss(float prediction, float label) {
 
97
    float e = 1 - label*prediction;
 
98
    return (e > 0) ? e : 0;
 
99
  }
 
100
  
 
101
  float getUpdate(float prediction, float label,float eta_t, float norm) {
 
102
    if(label*prediction >= label*label) return 0;
 
103
    float s1=(label*label-label*prediction)/(label*label);
 
104
    float s2=eta_t;
 
105
    return label * (s1<s2 ? s1 : s2)/norm;
 
106
  }
 
107
  
 
108
  float getRevertingWeight(float prediction, float eta_t){
 
109
    return fabs(prediction)/eta_t;
 
110
  }
 
111
 
 
112
  float getSquareGrad(float prediction, float label) {
 
113
    return first_derivative(prediction,label);
 
114
  }
 
115
 
 
116
  float first_derivative(float prediction, float label)
 
117
  {
 
118
    return (label*prediction >= label*label) ? 0 : -label;
 
119
  }
 
120
 
 
121
  float second_derivative(float prediction, float label)
 
122
  {
 
123
    return 0.;
 
124
  }
45
125
};
46
126
 
47
127
class logloss : public loss_function {
48
128
public:
49
 
        logloss() {
50
 
 
51
 
        }
52
 
 
53
 
        double getLoss(double prediction, double label) {
54
 
                return log(1 + exp(-label * prediction));
55
 
        }
56
 
 
57
 
        double getUpdate(double prediction, double label) {
58
 
                double d = exp(-label * prediction);
59
 
                return label * d / (1 + d);
60
 
        }
 
129
  logloss() {
 
130
    
 
131
  }
 
132
  
 
133
  float getLoss(float prediction, float label) {
 
134
    return log(1 + exp(-label * prediction));
 
135
  }
 
136
  
 
137
  float getUpdate(float prediction, float label, float eta_t, float norm) {
 
138
    float w,x;
 
139
    float d = exp(label * prediction);
 
140
    if(eta_t < 1e-6){
 
141
      /* As with squared loss, for small eta_t we replace the update
 
142
       * with its first order Taylor expansion to avoid numerical problems
 
143
       */
 
144
      return label*eta_t/((1+d)*norm);
 
145
    }
 
146
    x = eta_t + label*prediction + d;
 
147
    w = wexpmx(x);
 
148
    return -(label*w+prediction)/norm;
 
149
  }
 
150
  
 
151
  inline float wexpmx(float x){
 
152
    /* This piece of code is approximating W(exp(x))-x. 
 
153
     * W is the Lambert W function: W(z)*exp(W(z))=z.
 
154
     * The absolute error of this approximation is less than 9e-5.
 
155
     * Faster/better approximations can be substituted here.
 
156
     */
 
157
    double w = x>=1. ? 0.86*x+0.01 : exp(0.8*x-0.65); //initial guess
 
158
    double r = x>=1. ? x-log(w)-w : 0.2*x+0.65-w; //residual
 
159
    double t = 1.+w;
 
160
    double u = 2.*t*(t+2.*r/3.); //magic
 
161
    return w*(1.+r/t*(u-r)/(u-2.*r))-x; //more magic
 
162
  }
 
163
  
 
164
  float getRevertingWeight(float prediction, float eta_t){
 
165
    float z = -fabs(prediction);
 
166
    return (1-z-exp(z))/eta_t;
 
167
  }
 
168
 
 
169
  float first_derivative(float prediction, float label)
 
170
  {
 
171
    float v = - label/(1+exp(label * prediction));
 
172
    return v;
 
173
  }
 
174
 
 
175
  float getSquareGrad(float prediction, float label) {
 
176
    float d = first_derivative(prediction,label);
 
177
    return d*d;
 
178
  }
 
179
 
 
180
  float second_derivative(float prediction, float label)
 
181
  {
 
182
    float e = exp(label*prediction);
 
183
    
 
184
    return label*label*e/((1+e)*(1+e));
 
185
  }
61
186
};
62
187
 
63
188
class quantileloss : public loss_function {
64
189
public:
65
 
        quantileloss(double &tau_) : tau(tau_) {
66
 
        }
67
 
 
68
 
        double getLoss(double prediction, double label) {
69
 
                double e = label - prediction;
70
 
                if(e > 0) {
71
 
                        return tau * e;
72
 
                } else {
73
 
                        return -(1 - tau) * e;
74
 
                }
75
 
                
76
 
        }
77
 
 
78
 
        double getUpdate(double prediction, double label) {
79
 
                double e = label - prediction;
80
 
                if(e == 0) return 0;
81
 
                if(e > 0) {
82
 
                        return tau;
83
 
                } else {
84
 
                        return -(1 - tau);
85
 
                }
86
 
        }
87
 
 
88
 
        double tau;
 
190
  quantileloss(double &tau_) : tau(tau_) {
 
191
  }
 
192
  
 
193
  float getLoss(float prediction, float label) {
 
194
    float e = label - prediction;
 
195
    if(e > 0) {
 
196
      return tau * e;
 
197
    } else {
 
198
      return -(1 - tau) * e;
 
199
    }
 
200
    
 
201
  }
 
202
  
 
203
  float getUpdate(float prediction, float label, float eta_t, float norm) {
 
204
    float s2;
 
205
    float e = label - prediction;
 
206
    if(e == 0) return 0;
 
207
    float s1=eta_t;
 
208
    if(e > 0) {
 
209
      s2=e/tau;
 
210
      return tau*(s1<s2?s1:s2)/norm;
 
211
    } else {
 
212
      s2=-e/(1-tau);
 
213
      return -(1 - tau)*(s1<s2?s1:s2)/norm;
 
214
    }
 
215
  }
 
216
  
 
217
  float getRevertingWeight(float prediction, float eta_t){
 
218
    float v,t;
 
219
    t = 0.5*(global.min_label+global.max_label);
 
220
    if(prediction > t)
 
221
      v = -(1-tau);
 
222
     else
 
223
      v = tau;
 
224
    return (t - prediction)/(eta_t*v);
 
225
  }
 
226
 
 
227
  float first_derivative(float prediction, float label)
 
228
  {
 
229
    float e = label - prediction; 
 
230
    if(e == 0) return 0;
 
231
    return e > 0 ? -tau : (1-tau);
 
232
  }
 
233
 
 
234
  float getSquareGrad(float prediction, float label) {
 
235
    float fd = first_derivative(prediction,label);
 
236
    return fd*fd;
 
237
  }
 
238
 
 
239
  float second_derivative(float prediction, float label)
 
240
  {
 
241
    return 0.;
 
242
  }
 
243
 
 
244
  double tau;
89
245
};
90
246
 
91
247
loss_function* getLossFunction(string funcName, double function_parameter) {
92
 
        if(funcName.compare("squared") == 0) {
93
 
                return new squaredloss();
94
 
        } else if(funcName.compare("hinge") == 0) {
95
 
                return new hingeloss();
96
 
        } else if(funcName.compare("logistic") == 0) {
97
 
                return new logloss();
98
 
        } else if(funcName.compare("quantile") == 0 || funcName.compare("pinball") == 0 || funcName.compare("absolute") == 0) {
99
 
                return new quantileloss(function_parameter);
100
 
        } else {
101
 
          cout << "Invalid loss function name: " << funcName << " Bailing!" << endl;
102
 
          exit(1);
103
 
        }
 
248
  if(funcName.compare("squared") == 0) {
 
249
    return new squaredloss();
 
250
  } else if(funcName.compare("classic") == 0){
 
251
    return new classic_squaredloss();
 
252
  } else if(funcName.compare("hinge") == 0) {
 
253
    return new hingeloss();
 
254
  } else if(funcName.compare("logistic") == 0) {
 
255
    global.min_label = -100;
 
256
    global.max_label = 100;
 
257
    return new logloss();
 
258
  } else if(funcName.compare("quantile") == 0 || funcName.compare("pinball") == 0 || funcName.compare("absolute") == 0) {
 
259
    return new quantileloss(function_parameter);
 
260
  } else {
 
261
    cout << "Invalid loss function name: \'" << funcName << "\' Bailing!" << endl;
 
262
    exit(1);
 
263
  }
104
264
  cout << "end getLossFunction" << endl;
105
265
}