weighted_squared_error.cpp
1// OpenNN: Open Neural Networks Library
2// www.opennn.net
3//
4// W E I G T H E D S Q U A R E D E R R O R C L A S S
5//
6// Artificial Intelligence Techniques SL
7// artelnics@artelnics.com
8
9#include "weighted_squared_error.h"
10
11namespace OpenNN
12{
13
18
20{
22}
23
24
31
32WeightedSquaredError::WeightedSquaredError(NeuralNetwork* new_neural_network_pointer, DataSet* new_data_set_pointer)
33 : LossIndex(new_neural_network_pointer, new_data_set_pointer)
34{
36}
37
38
40
42{
43}
44
45
47
49{
50 return positives_weight;
51}
52
53
55
57{
58 return negatives_weight;
59}
60
61
62type WeightedSquaredError::get_normalizaton_coefficient() const
63{
65}
66
67
69
71{
73 {
75
77 }
78 else
79 {
80 negatives_weight = type(-1.0);
81 positives_weight = type(-1.0);
82
83 normalization_coefficient = type(-1.0);
84 }
85}
86
87
90
91void WeightedSquaredError::set_positives_weight(const type& new_positives_weight)
92{
93 positives_weight = new_positives_weight;
94}
95
96
99
100void WeightedSquaredError::set_negatives_weight(const type& new_negatives_weight)
101{
102 negatives_weight = new_negatives_weight;
103}
104
105
109
110void WeightedSquaredError::set_weights(const type& new_positives_weight, const type& new_negatives_weight)
111{
112 positives_weight = new_positives_weight;
113 negatives_weight = new_negatives_weight;
114}
115
116
118
120{
121 // Control sentence
122
123#ifdef OPENNN_DEBUG
124
125 // check();
126
127#endif
128
130 {
131 positives_weight = type(1);
132 negatives_weight = type(1);
133 }
134 else if(data_set_pointer && data_set_pointer->get_target_columns()(0).type == DataSet::ColumnType::Binary)
135 {
136 const Tensor<Index, 1> target_distribution = data_set_pointer->calculate_target_distribution();
137
138 const Index negatives = target_distribution[0];
139 const Index positives = target_distribution[1];
140
141 if(positives == 0 || negatives == 0)
142 {
143 positives_weight = type(1);
144 negatives_weight = type(1);
145
146 return;
147 }
148
149 negatives_weight = type(1);
150 positives_weight = static_cast<type>(negatives)/static_cast<type>(positives);
151 }
152 else
153 {
154 positives_weight = type(1);
155 negatives_weight = type(1);
156 }
157}
158
159
161
163{
164 // Control sentence
165
166#ifdef OPENNN_DEBUG
167
168 check();
169
170#endif
171
172 if(data_set_pointer->get_target_columns().size()==0)
173 {
174 normalization_coefficient = static_cast<type>(1);
175 }
176 else if(data_set_pointer && data_set_pointer->get_target_columns()(0).type == DataSet::ColumnType::Binary)
177 {
178 const Tensor<Index, 1> target_variables_indices = data_set_pointer->get_target_variables_indices();
179
180 const Index negatives = data_set_pointer->calculate_used_negatives(target_variables_indices[0]);
181
182 normalization_coefficient = type(negatives)*negatives_weight*static_cast<type>(0.5);
183 }
184 else
185 {
186 normalization_coefficient = static_cast<type>(1);
187 }
188}
189
190
191
194
196{
197 data_set_pointer = new_data_set_pointer;
198
199 set_weights();
200
202}
203
204
205void WeightedSquaredError::calculate_error(const DataSetBatch& batch,
206 const NeuralNetworkForwardPropagation& forward_propagation,
207 LossIndexBackPropagation& back_propagation) const
208{
209 const Index trainable_layers_number = neural_network_pointer->get_trainable_layers_number();
210
211 LayerForwardPropagation* output_layer_forward_propagation = forward_propagation.layers(trainable_layers_number-1);
212
213 ProbabilisticLayerForwardPropagation* probabilistic_layer_back_propagation
214 = static_cast<ProbabilisticLayerForwardPropagation*>(output_layer_forward_propagation);
215
216 const Tensor<type, 2>& targets = batch.targets_2d;
217 const Tensor<type, 2>& outputs = probabilistic_layer_back_propagation->activations;
218
219 const Tensor<bool, 2> if_sentence = targets == targets.constant(type(1));
220 const Tensor<bool, 2> else_sentence = targets == targets.constant(type(0));
221
222 Tensor<type, 2> f_1(targets.dimension(0), targets.dimension(1));
223 f_1 = back_propagation.errors.square()*positives_weight;
224
225 Tensor<type, 2> f_2(targets.dimension(0), targets.dimension(1));
226 f_2 = back_propagation.errors.square()*negatives_weight;
227
228 Tensor<type, 2> f_3(targets.dimension(0), targets.dimension(1));
229 f_3 = outputs.constant(type(0));
230
231 const Tensor<type, 0> weighted_sum_squared_error = (if_sentence.select(f_1, else_sentence.select(f_2, f_3))).sum();
232
233 const Index batch_samples_number = batch.get_samples_number();
234 const Index total_samples_number = data_set_pointer->get_samples_number();
235
236 const type coefficient = (static_cast<type>(batch_samples_number)/static_cast<type>(total_samples_number))*normalization_coefficient;
237
238 back_propagation.error = weighted_sum_squared_error(0)/coefficient;
239}
240
241
242void WeightedSquaredError::calculate_error_lm(const DataSetBatch& batch,
243 const NeuralNetworkForwardPropagation&,
244 LossIndexBackPropagationLM &back_propagation) const
245{
246 Tensor<type, 0> error;
247 error.device(*thread_pool_device) = (back_propagation.squared_errors*back_propagation.squared_errors).sum();
248
249 const Index batch_samples_number = batch.get_samples_number();
250 const Index total_samples_number = data_set_pointer->get_samples_number();
251
252 const type coefficient = (static_cast<type>(batch_samples_number)/static_cast<type>(total_samples_number))*normalization_coefficient;
253
254 back_propagation.error = error()/coefficient;
255}
256
257
258void WeightedSquaredError::calculate_output_delta(const DataSetBatch& batch,
259 NeuralNetworkForwardPropagation& ,
260 LossIndexBackPropagation& back_propagation) const
261{
262#ifdef OPENNN_DEBUG
263
264 check();
265
266#endif
267
268 const Index trainable_layers_number = neural_network_pointer->get_trainable_layers_number();
269
270 LayerBackPropagation* output_layer_back_propagation = back_propagation.neural_network.layers(trainable_layers_number-1);
271
272 ProbabilisticLayerBackPropagation* probabilistic_layer_back_propagation
273 = static_cast<ProbabilisticLayerBackPropagation*>(output_layer_back_propagation);
274
275 const Tensor<type, 2>& targets = batch.targets_2d;
276
277 const Index batch_samples_number = batch.targets_2d.size();
278 const Index total_samples_number = data_set_pointer->get_samples_number();
279
280 const type coefficient = static_cast<type>(2.0)/((static_cast<type>(batch_samples_number)/static_cast<type>(total_samples_number))*normalization_coefficient);
281
282 const Tensor<bool, 2> if_sentence = targets == targets.constant(type(1));
283 const Tensor<bool, 2> else_sentence = targets == targets.constant(type(0));
284
285 Tensor<type, 2> f_1(targets.dimension(0), targets.dimension(1));
286 f_1 = (coefficient*positives_weight)*back_propagation.errors;
287
288 Tensor<type, 2> f_2(targets.dimension(0), targets.dimension(1));
289 f_2 = coefficient*negatives_weight*back_propagation.errors;
290
291 Tensor<type, 2> f_3(targets.dimension(0), targets.dimension(1));
292 f_3 = targets.constant(type(0));
293
294 probabilistic_layer_back_propagation->delta.device(*thread_pool_device) = if_sentence.select(f_1, else_sentence.select(f_2, f_3));
295}
296
297
299
301 LossIndexBackPropagationLM& loss_index_back_propagation_lm) const
302{
303#ifdef OPENNN_DEBUG
304
305 check();
306
307#endif
308
309 const Index batch_samples_number = batch.get_samples_number();
310 const Index total_samples_number = data_set_pointer->get_samples_number();
311
312 const type coefficient = type(2)/((static_cast<type>(batch_samples_number)/static_cast<type>(total_samples_number))*normalization_coefficient);
313
314 loss_index_back_propagation_lm.gradient.device(*thread_pool_device)
315 = loss_index_back_propagation_lm.squared_errors_jacobian.contract(loss_index_back_propagation_lm.squared_errors, AT_B);
316
317 loss_index_back_propagation_lm.gradient.device(*thread_pool_device) = coefficient * loss_index_back_propagation_lm.gradient;
318}
319
320
321void WeightedSquaredError::calculate_error_hessian_lm(const DataSetBatch& batch,
322 LossIndexBackPropagationLM& loss_index_back_propagation_lm) const
323{
324#ifdef OPENNN_DEBUG
325
326 check();
327
328#endif
329
330 const Index batch_samples_number = batch.get_samples_number();
331 const Index total_samples_number = data_set_pointer->get_samples_number();
332
333 const type coefficient = type(2)/((static_cast<type>(batch_samples_number)/static_cast<type>(total_samples_number))*normalization_coefficient);
334
335 loss_index_back_propagation_lm.hessian.device(*thread_pool_device)
336 = loss_index_back_propagation_lm.squared_errors_jacobian.contract(loss_index_back_propagation_lm.squared_errors_jacobian, AT_B);
337
338 loss_index_back_propagation_lm.hessian.device(*thread_pool_device) = coefficient*loss_index_back_propagation_lm.hessian;
339}
340
341
343
345{
346 return "WEIGHTED_SQUARED_ERROR";
347}
348
349
351
353{
354 return "Weighted squared error";
355}
356
357
361
363{
364 ostringstream buffer;
365
366 // Error type
367
368 file_stream.OpenElement("WeightedSquaredError");
369
370 // Positives weight
371
372 file_stream.OpenElement("PositivesWeight");
373
374 buffer.str("");
375 buffer << positives_weight;
376
377 file_stream.PushText(buffer.str().c_str());
378
379 file_stream.CloseElement();
380
381 // Negatives weight
382
383 file_stream.OpenElement("NegativesWeight");
384
385 buffer.str("");
386 buffer << negatives_weight;
387
388 file_stream.PushText(buffer.str().c_str());
389
390 file_stream.CloseElement();
391
392 // Close error
393
394 file_stream.CloseElement();
395}
396
397
400
402{
403 const tinyxml2::XMLElement* root_element = document.FirstChildElement("WeightedSquaredError");
404
405 if(!root_element)
406 {
407 ostringstream buffer;
408
409 buffer << "OpenNN Exception: WeightedSquaredError class.\n"
410 << "void from_XML(const tinyxml2::XMLDocument&) method.\n"
411 << "Weighted squared element is nullptr.\n";
412
413 throw logic_error(buffer.str());
414 }
415
416 // Positives weight
417
418 const tinyxml2::XMLElement* positives_weight_element = root_element->FirstChildElement("PositivesWeight");
419
420 if(positives_weight_element)
421 {
422 const string string = positives_weight_element->GetText();
423
424 try
425 {
426 set_positives_weight(static_cast<type>(atof(string.c_str())));
427 }
428 catch(const logic_error& e)
429 {
430 cerr << e.what() << endl;
431 }
432 }
433
434 // Negatives weight
435
436 const tinyxml2::XMLElement* negatives_weight_element = root_element->FirstChildElement("NegativesWeight");
437
438 if(negatives_weight_element)
439 {
440 const string string = negatives_weight_element->GetText();
441
442 try
443 {
444 set_negatives_weight(static_cast<type>(atof(string.c_str())));
445 }
446 catch(const logic_error& e)
447 {
448 cerr << e.what() << endl;
449 }
450 }
451}
452
453
454type WeightedSquaredError::weighted_sum_squared_error(const Tensor<type, 2>& x, const Tensor<type, 2>& y) const
455{
456#ifdef __OPENNN_DEBUG__
457
458 const Index rows_number = x.dimension(0);
459 const Index columns_number = x.dimension(1);
460
461 const Index other_rows_number = y.dimension(0);
462
463 if(other_rows_number != rows_number)
464 {
465 ostringstream buffer;
466
467 buffer << "OpenNN Exception: Metrics functions.\n"
468 << "double minkowski_error(const Matrix<double>&, const double&) method.\n"
469 << "Other number of rows must be equal to this number of rows.\n";
470
471 throw logic_error(buffer.str());
472 }
473
474 const Index other_columns_number = y.dimension(1);
475
476 if(other_columns_number != columns_number)
477 {
478 ostringstream buffer;
479
480 buffer << "OpenNN Exception: Metrics functions.\n"
481 << "double minkowski_error(const Matrix<double>&, const double&) method.\n"
482 << "Other number of columns must be equal to this number of columns.\n";
483
484 throw logic_error(buffer.str());
485 }
486
487#endif
488
489 const Tensor<bool, 2> if_sentence = y == y.constant(type(1));
490 const Tensor<bool, 2> else_sentence = y == y.constant(type(0));
491
492 Tensor<type, 2> f_1(x.dimension(0), x.dimension(1));
493
494 Tensor<type, 2> f_2(x.dimension(0), x.dimension(1));
495
496 Tensor<type, 2> f_3(x.dimension(0), x.dimension(1));
497
498 f_1 = (x - y).square()*positives_weight;
499
500 f_2 = (x - y).square()*negatives_weight;
501
502 f_3 = x.constant(type(0));
503
504 const Tensor<type, 0> weighted_sum_squared_error = (if_sentence.select(f_1, else_sentence.select(f_2, f_3))).sum();
505
506 return weighted_sum_squared_error(0);
507}
508
509
510void WeightedSquaredError::calculate_squared_errors_lm(const DataSetBatch& batch,
511 const NeuralNetworkForwardPropagation& forward_propagation,
512 LossIndexBackPropagationLM& loss_index_back_propagation_lm) const
513{
514 const Index trainable_layers_number = neural_network_pointer->get_trainable_layers_number();
515
516 LayerForwardPropagation* output_layer_forward_propagation = forward_propagation.layers(trainable_layers_number-1);
517
518 const Tensor<type, 2>& targets = batch.targets_2d;
519
520 ProbabilisticLayerForwardPropagation* probabilistic_layer_forward_propagation
521 = static_cast<ProbabilisticLayerForwardPropagation*>(output_layer_forward_propagation);
522
523 const Tensor<type, 2>& outputs = probabilistic_layer_forward_propagation->activations;
524
525 const Tensor<bool, 2> if_sentence = outputs == outputs.constant(type(1));
526
527 Tensor<type, 2> f_1(outputs.dimension(0), outputs.dimension(1));
528 f_1 = (outputs - targets)*positives_weight;
529
530 Tensor<type, 2> f_2(outputs.dimension(0), outputs.dimension(1));
531 f_2 = (outputs - targets)*negatives_weight;
532
533 loss_index_back_propagation_lm.squared_errors = ((if_sentence.select(f_1, f_2)).sum(rows_sum).square()).sqrt();
534}
535
536}
537
538// OpenNN: Open Neural Networks Library.
539// Copyright(C) 2005-2021 Artificial Intelligence Techniques, SL.
540//
541// This library is free software; you can redistribute it and/or
542// modify it under the terms of the GNU Lesser General Public
543// License as published by the Free Software Foundation; either
544// version 2.1 of the License, or any later version.
545//
546// This library is distributed in the hope that it will be useful,
547// but WITHOUT ANY WARRANTY; without even the implied warranty of
548// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
549// Lesser General Public License for more details.
550
551// You should have received a copy of the GNU Lesser General Public
552// License along with this library; if not, write to the Free Software
553// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
This class represents the concept of data set for data modelling problems, such as approximation,...
Definition: data_set.h:57
Index get_target_variables_number() const
Returns the number of target variables of the data set.
Definition: data_set.cpp:2884
bool is_empty() const
Returns true if the data matrix is empty, and false otherwise.
Definition: data_set.cpp:3658
Tensor< Index, 1 > calculate_target_distribution() const
Definition: data_set.cpp:8480
Tensor< Index, 1 > get_target_variables_indices() const
Returns the indices of the target variables.
Definition: data_set.cpp:3094
Index calculate_used_negatives(const Index &) const
Definition: data_set.cpp:5363
Tensor< Column, 1 > get_target_columns() const
Returns the target columns of the data set.
Definition: data_set.cpp:2759
This abstract class represents the concept of loss index composed of an error term and a regularizati...
Definition: loss_index.h:48
DataSet * data_set_pointer
Pointer to a data set object.
Definition: loss_index.h:258
NeuralNetwork * neural_network_pointer
Pointer to a neural network object.
Definition: loss_index.h:254
void check() const
Definition: loss_index.cpp:295
bool has_data_set() const
Definition: loss_index.cpp:86
type positives_weight
Weight for the positives for the calculation of the error.
void set_weights()
Calculates of the weights for the positives and negatives values with the data of the data set.
type normalization_coefficient
Coefficient of normalization.
void set_data_set_pointer(DataSet *)
set_data_set_pointer
void set_normalization_coefficient()
Calculates of the normalization coefficient with the data of the data set.
void from_XML(const tinyxml2::XMLDocument &)
void set_default()
Set the default values for the object.
type get_positives_weight() const
Returns the weight of the positives.
type negatives_weight
Weight for the negatives for the calculation of the error.
string get_error_type() const
Returns a string with the name of the weighted squared error loss type, "WEIGHTED_SQUARED_ERROR".
void calculate_error_gradient_lm(const DataSetBatch &, LossIndexBackPropagationLM &) const
void write_XML(tinyxml2::XMLPrinter &) const
string get_error_type_text() const
Returns a string with the name of the weighted squared error loss type in text format.
type get_negatives_weight() const
Returns the weight of the negatives.
virtual ~WeightedSquaredError()
Destructor.
void PushText(const char *text, bool cdata=false)
Add a text node.
Definition: tinyxml2.cpp:2878
virtual void CloseElement(bool compactMode=false)
If streaming, close the Element.
Definition: tinyxml2.cpp:2834
uint32 sqrt(uint32 &r, int &exp)
Definition: half.hpp:1480
A loss index composed of several terms, this structure represent the First Order for this function.
Definition: loss_index.h:383