1 // OpenNN: Open Neural Networks Library
2 // www.opennn.net
3 //
4 // N O R M A L I Z 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 "normalized_squared_error.h"
10
11 namespace OpenNN
12 {
13
14 /// Default constructor.
15 /// It creates a normalized squared error term object not associated to any
16 /// neural network and not measured on any data set.
17 /// It also initializes all the rest of class members to their default values.
18
NormalizedSquaredError()19 NormalizedSquaredError::NormalizedSquaredError() : LossIndex()
20 {
21 set_default();
22 }
23
24
25 /// Neural network and data set constructor.
26 /// It creates a normalized squared error term associated to a neural network and measured on a data set.
27 /// It also initializes all the rest of class members to their default values.
28 /// @param new_neural_network_pointer Pointer to a neural network object.
29 /// @param new_data_set_pointer Pointer to a data set object.
30
NormalizedSquaredError(NeuralNetwork * new_neural_network_pointer,DataSet * new_data_set_pointer)31 NormalizedSquaredError::NormalizedSquaredError(NeuralNetwork* new_neural_network_pointer, DataSet* new_data_set_pointer)
32 : LossIndex(new_neural_network_pointer, new_data_set_pointer)
33 {
34 set_default();
35 }
36
37
38 /// Destructor.
39
~NormalizedSquaredError()40 NormalizedSquaredError::~NormalizedSquaredError()
41 {
42 }
43
44
45 /// Returns the normalization coefficient.
46
get_normalization_coefficient() const47 type NormalizedSquaredError::get_normalization_coefficient() const
48 {
49 return normalization_coefficient;
50 }
51
52
53 /// Returns the selection normalization coefficient.
54
get_selection_normalization_coefficient() const55 type NormalizedSquaredError::get_selection_normalization_coefficient() const
56 {
57 return selection_normalization_coefficient;
58 }
59
60
61 ///
62 /// \brief set_data_set_pointer
63 /// \param new_data_set_pointer
64
set_data_set_pointer(DataSet * new_data_set_pointer)65 void NormalizedSquaredError::set_data_set_pointer(DataSet* new_data_set_pointer)
66 {
67 data_set_pointer = new_data_set_pointer;
68
69 set_normalization_coefficient();
70 }
71
72 /// Sets the normalization coefficient from training samples.
73 /// This method calculates the normalization coefficient of the dataset.
74
set_normalization_coefficient()75 void NormalizedSquaredError::set_normalization_coefficient()
76 {
77 // Data set
78
79 const Tensor<type, 1> targets_mean = data_set_pointer->calculate_used_targets_mean();
80
81 //Targets matrix
82
83 const Tensor<type, 2> targets = data_set_pointer->get_target_data();
84
85 //Normalization coefficient
86
87 normalization_coefficient = calculate_normalization_coefficient(targets, targets_mean);
88
89 }
90
91 /// Sets the normalization coefficient.
92 /// @param new_normalization_coefficient New normalization coefficient to be set.
93
set_normalization_coefficient(const type & new_normalization_coefficient)94 void NormalizedSquaredError::set_normalization_coefficient(const type& new_normalization_coefficient)
95 {
96 normalization_coefficient = new_normalization_coefficient;
97 }
98
99
100 /// Sets the normalization coefficient from selection samples.
101 /// This method calculates the normalization coefficient of the dataset.
102
set_selection_normalization_coefficient()103 void NormalizedSquaredError::set_selection_normalization_coefficient()
104 {
105 // Data set
106
107 const Tensor<Index, 1> selection_indices = data_set_pointer->get_selection_samples_indices();
108
109 const Index selection_samples_number = selection_indices.size();
110
111 if(selection_samples_number == 0) return;
112
113 const Tensor<type, 1> selection_targets_mean = data_set_pointer->calculate_selection_targets_mean();
114
115 const Tensor<type, 2> targets = data_set_pointer->get_selection_target_data();
116
117 // Normalization coefficient
118
119 selection_normalization_coefficient = calculate_normalization_coefficient(targets, selection_targets_mean);
120 }
121
122
123 /// Sets the normalization coefficient from selection samples.
124 /// @param new_normalization_coefficient New normalization coefficient to be set.
125
set_selection_normalization_coefficient(const type & new_selection_normalization_coefficient)126 void NormalizedSquaredError::set_selection_normalization_coefficient(const type& new_selection_normalization_coefficient)
127 {
128 selection_normalization_coefficient = new_selection_normalization_coefficient;
129 }
130
131
132 /// Sets the default values.
133
set_default()134 void NormalizedSquaredError::set_default()
135 {
136 if(has_neural_network() && has_data_set() && data_set_pointer->has_data())
137 {
138 set_normalization_coefficient();
139 set_selection_normalization_coefficient();
140 }
141 else
142 {
143 normalization_coefficient = -1;
144 selection_normalization_coefficient = -1;
145 }
146 }
147
148 /// Returns the normalization coefficient to be used for the loss of the error.
149 /// This is measured on the training samples of the data set.
150 /// @param targets Matrix with the targets values from dataset.
151 /// @param targets_mean Vector with the means of the given targets.
152
calculate_normalization_coefficient(const Tensor<type,2> & targets,const Tensor<type,1> & targets_mean) const153 type NormalizedSquaredError::calculate_normalization_coefficient(const Tensor<type, 2>& targets, const Tensor<type, 1>& targets_mean) const
154 {
155
156 #ifdef __OPENNN_DEBUG__
157
158 // check();
159
160 const Index means_number = targets_mean.dimension(0);
161 const Index targets_number = targets.dimension(1);
162
163 if(targets_number != means_number)
164 {
165 ostringstream buffer;
166
167 buffer << "OpenNN Exception: NormalizedquaredError function.\n"
168 << "type calculate_normalization_coefficient(const Tensor<type, 2>& targets, const Tensor<type, 1>& targets_mean) function.\n"
169 << " The columns number of targets("<< targets_number <<") must be equal("<< means_number<<").\n";
170
171 throw logic_error(buffer.str());
172 }
173 #endif
174
175 const Index size = targets.dimension(0);
176
177 type normalization_coefficient = 0;
178
179 for(Index i = 0; i < size; i++)
180 {
181 Tensor<type, 0> norm_1 = (targets.chip(i,0) - targets_mean).square().sum();
182
183 normalization_coefficient += norm_1(0);
184 }
185
186 return normalization_coefficient;
187 }
188
189
190
191 ///
192 ////// \brief NormalizedSquaredError::calculate_error
193 ////// \param batch
194 ////// \param forward_propagation
195 ////// \param back_propagation
calculate_error(const DataSet::Batch & batch,const NeuralNetwork::ForwardPropagation & forward_propagation,LossIndex::BackPropagation & back_propagation) const196 void NormalizedSquaredError::calculate_error(const DataSet::Batch& batch,
197 const NeuralNetwork::ForwardPropagation& forward_propagation,
198 LossIndex::BackPropagation& back_propagation) const
199 {
200 Tensor<type, 0> sum_squared_error;
201
202 const Index trainable_layers_number = neural_network_pointer->get_trainable_layers_number();
203
204 const Tensor<type, 2>& outputs = forward_propagation.layers(trainable_layers_number-1).activations_2d;
205 const Tensor<type, 2>& targets = batch.targets_2d;
206
207 back_propagation.errors.device(*thread_pool_device) = outputs - targets;
208
209 sum_squared_error.device(*thread_pool_device) = back_propagation.errors.contract(back_propagation.errors, SSE);
210
211 const Index batch_samples_number = batch.get_samples_number();
212 const Index total_samples_number = data_set_pointer->get_samples_number();
213
214 back_propagation.error = sum_squared_error(0)/((static_cast<type>(batch_samples_number)/static_cast<type>(total_samples_number))*normalization_coefficient);
215
216 return;
217 }
218
219
220 ///
221 ////// \brief NormalizedSquaredError::calculate_error_terms
222 ////// \param batch
223 ////// \param forward_propagation
224 ////// \param second_order_loss
calculate_error_terms(const DataSet::Batch & batch,const NeuralNetwork::ForwardPropagation & forward_propagation,SecondOrderLoss & second_order_loss) const225 void NormalizedSquaredError::calculate_error_terms(const DataSet::Batch& batch,
226 const NeuralNetwork::ForwardPropagation& forward_propagation,
227 SecondOrderLoss& second_order_loss) const
228 {
229 const Index trainable_layers_number = neural_network_pointer->get_trainable_layers_number();
230
231 const Index batch_samples_number = batch.get_samples_number();
232 const Index total_samples_number = data_set_pointer->get_samples_number();
233
234 const Tensor<type, 2>& outputs = forward_propagation.layers(trainable_layers_number-1).activations_2d;
235 const Tensor<type, 2>& targets = batch.targets_2d;
236
237 second_order_loss.error_terms.resize(outputs.dimension(0));
238 const Eigen::array<int, 1> rows_sum = {Eigen::array<int, 1>({1})};
239
240 second_order_loss.error_terms.device(*thread_pool_device) = ((outputs - targets).square().sum(rows_sum)).sqrt();
241
242 Tensor<type, 0> error;
243 error.device(*thread_pool_device) = second_order_loss.error_terms.contract(second_order_loss.error_terms, AT_B);
244
245 const type coefficient = ((static_cast<type>(batch_samples_number)/static_cast<type>(total_samples_number))*normalization_coefficient);
246
247 second_order_loss.error = error()/coefficient;
248 }
249
250
calculate_output_gradient(const DataSet::Batch & batch,const NeuralNetwork::ForwardPropagation & forward_propagation,BackPropagation & back_propagation) const251 void NormalizedSquaredError::calculate_output_gradient(const DataSet::Batch& batch,
252 const NeuralNetwork::ForwardPropagation& forward_propagation,
253 BackPropagation& back_propagation) const
254 {
255 #ifdef __OPENNN_DEBUG__
256
257 check();
258
259 #endif
260
261 const Index batch_samples_number = batch.get_samples_number();
262 const Index total_samples_number = data_set_pointer->get_samples_number();
263
264 const Index trainable_layers_number = neural_network_pointer->get_trainable_layers_number();
265
266 const Tensor<type, 2>& outputs = forward_propagation.layers(trainable_layers_number-1).activations_2d;
267 const Tensor<type, 2>& targets = batch.targets_2d;
268
269 const type coefficient = static_cast<type>(2.0)/(static_cast<type>(batch_samples_number)/static_cast<type>(total_samples_number)*normalization_coefficient);
270
271 back_propagation.errors.device(*thread_pool_device) = outputs - targets;
272
273 back_propagation.output_gradient.device(*thread_pool_device) = coefficient*back_propagation.errors;
274 }
275
276
calculate_Jacobian_gradient(const DataSet::Batch & batch,LossIndex::SecondOrderLoss & second_order_loss) const277 void NormalizedSquaredError::calculate_Jacobian_gradient(const DataSet::Batch& batch,
278 LossIndex::SecondOrderLoss& second_order_loss) const
279 {
280 #ifdef __OPENNN_DEBUG__
281
282 check();
283
284 #endif
285
286 const Index batch_samples_number = batch.get_samples_number();
287 const Index total_samples_number = data_set_pointer->get_samples_number();
288
289 const type coefficient = 2/((static_cast<type>(batch_samples_number)/static_cast<type>(total_samples_number))*normalization_coefficient);
290
291 second_order_loss.gradient.device(*thread_pool_device) = second_order_loss.error_terms_Jacobian.contract(second_order_loss.error_terms, AT_B);
292
293 second_order_loss.gradient.device(*thread_pool_device) = coefficient*second_order_loss.gradient;
294 }
295
296
calculate_hessian_approximation(const DataSet::Batch & batch,LossIndex::SecondOrderLoss & second_order_loss) const297 void NormalizedSquaredError::calculate_hessian_approximation(const DataSet::Batch& batch,
298 LossIndex::SecondOrderLoss& second_order_loss) const
299 {
300 #ifdef __OPENNN_DEBUG__
301
302 check();
303
304 #endif
305
306 const Index batch_samples_number = batch.get_samples_number();
307 const Index total_samples_number = data_set_pointer->get_samples_number();
308
309 const type coefficient = 2/((static_cast<type>(batch_samples_number)/static_cast<type>(total_samples_number))*normalization_coefficient);
310
311 second_order_loss.hessian.device(*thread_pool_device) = second_order_loss.error_terms_Jacobian.contract(second_order_loss.error_terms_Jacobian, AT_B);
312
313 second_order_loss.hessian.device(*thread_pool_device) = coefficient*second_order_loss.hessian;
314 }
315
316
317 /// Returns a string with the name of the normalized squared error loss type, "NORMALIZED_SQUARED_ERROR".
318
get_error_type() const319 string NormalizedSquaredError::get_error_type() const
320 {
321 return "NORMALIZED_SQUARED_ERROR";
322 }
323
324
325 /// Returns a string with the name of the normalized squared error loss type in text format.
326
get_error_type_text() const327 string NormalizedSquaredError::get_error_type_text() const
328 {
329 return "Normalized squared error";
330 }
331
332
333 /// Serializes the cross entropy error object into a XML document of the TinyXML library without keep the DOM tree in memory.
334 /// See the OpenNN manual for more information about the format of this document
335
write_XML(tinyxml2::XMLPrinter & file_stream) const336 void NormalizedSquaredError::write_XML(tinyxml2::XMLPrinter& file_stream) const
337 {
338 // Error type
339
340 file_stream.OpenElement("NormalizedSquaredError");
341
342 file_stream.CloseElement();
343 }
344
345
346 /// Loads a root mean squared error object from a XML document.
347 /// @param document Pointer to a TinyXML document with the object data.
348
from_XML(const tinyxml2::XMLDocument & document)349 void NormalizedSquaredError::from_XML(const tinyxml2::XMLDocument& document)
350 {
351 const tinyxml2::XMLElement* root_element = document.FirstChildElement("NormalizedSquaredError");
352
353 if(!root_element)
354 {
355 ostringstream buffer;
356
357 buffer << "OpenNN Exception: NormalizedSquaredError class.\n"
358 << "void from_XML(const tinyxml2::XMLDocument&) method.\n"
359 << "Normalized squared element is nullptr.\n";
360
361 throw logic_error(buffer.str());
362 }
363 }
364
365 }
366
367 // OpenNN: Open Neural Networks Library.
368 // Copyright(C) 2005-2020 Artificial Intelligence Techniques, SL.
369 //
370 // This library is free software; you can redistribute it and/or
371 // modify it under the terms of the GNU Lesser General Public
372 // License as published by the Free Software Foundation; either
373 // version 2.1 of the License, or any later version.
374 //
375 // This library is distributed in the hope that it will be useful,
376 // but WITHOUT ANY WARRANTY; without even the implied warranty of
377 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
378 // Lesser General Public License for more details.
379
380 // You should have received a copy of the GNU Lesser General Public
381 // License along with this library; if not, write to the Free Software
382 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
383