cross_entropy_error.cpp
1// OpenNN: Open Neural Networks Library
2// www.opennn.net
3//
4// C R O S S E N T R O P Y E R R O R C L A S S
5//
6// Artificial Intelligence Techniques SL
7// artelnics@artelnics.com
8
9#include "cross_entropy_error.h"
10
11namespace OpenNN
12{
13
18
20{
21}
22
23
29
30CrossEntropyError::CrossEntropyError(NeuralNetwork* new_neural_network_pointer, DataSet* new_data_set_pointer)
31 : LossIndex(new_neural_network_pointer, new_data_set_pointer)
32{
33}
34
35
37
39{
40}
41
42
43// \brief CrossEntropyError::calculate_error.
44// \param batch
45// \param forward_propagation
46// \param back_propagation
47
48void CrossEntropyError::calculate_error(const DataSetBatch& batch,
49 const NeuralNetworkForwardPropagation& forward_propagation,
50 LossIndexBackPropagation& back_propagation) const
51{
52#ifdef OPENNN_DEBUG
53
54 Layer* last_trainable_layer_pointer = forward_propagation.neural_network_pointer->get_last_trainable_layer_pointer();
55
56 if(last_trainable_layer_pointer->get_type() != Layer::Probabilistic)
57 {
58 ostringstream buffer;
59
60 buffer << "OpenNN Exception: CrossEntropyError class.\n"
61 << "calculate_error() method.\n"
62 << "Last trainable layer is not probabilistic: " << last_trainable_layer_pointer->get_type_string() << endl;
63
64 throw logic_error(buffer.str());
65 }
66
67#endif
68
69 const Index outputs_number = neural_network_pointer->get_outputs_number();
70
71 if(outputs_number == 1)
72 {
73 calculate_binary_error(batch, forward_propagation, back_propagation);
74 }
75 else
76 {
77 calculate_multiple_error(batch, forward_propagation, back_propagation);
78 }
79}
80
81
82
83void CrossEntropyError::calculate_binary_error(const DataSetBatch& batch,
84 const NeuralNetworkForwardPropagation& forward_propagation,
85 LossIndexBackPropagation& back_propagation) const
86{
87 const Index batch_samples_number = batch.inputs_2d.dimension(0);
88
89 const Index trainable_layers_number = neural_network_pointer->get_trainable_layers_number();
90
91 const Tensor<type, 2>& outputs =
92 static_cast<ProbabilisticLayerForwardPropagation*>(forward_propagation.layers(trainable_layers_number-1))->activations;
93
94 const Tensor<type, 2>& targets = batch.targets_2d;
95
96 Tensor<type, 0> cross_entropy_error;
97
98 cross_entropy_error.device(*thread_pool_device) = -(targets*(outputs.log())).sum() - ((type(1)-targets)*((type(1)-outputs).log())).sum();
99
100 back_propagation.error = cross_entropy_error()/static_cast<type>(batch_samples_number);
101}
102
103
104void CrossEntropyError::calculate_multiple_error(const DataSetBatch& batch,
105 const NeuralNetworkForwardPropagation& forward_propagation,
106 LossIndexBackPropagation& back_propagation) const
107{
108 const Index batch_samples_number = batch.inputs_2d.dimension(0);
109
110 const Index trainable_layers_number = neural_network_pointer->get_trainable_layers_number();
111
112 const Tensor<type, 2>& outputs =
113 static_cast<ProbabilisticLayerForwardPropagation*>(forward_propagation.layers(trainable_layers_number-1))->activations;
114
115 const Tensor<type, 2>& targets = batch.targets_2d;
116
117 Tensor<type, 0> cross_entropy_error;
118 cross_entropy_error.device(*thread_pool_device) = -(targets*(outputs.log())).sum();
119
120 back_propagation.error = cross_entropy_error()/static_cast<type>(batch_samples_number);
121}
122
123
124void CrossEntropyError::calculate_output_delta(const DataSetBatch& batch,
125 NeuralNetworkForwardPropagation& forward_propagation,
126 LossIndexBackPropagation& back_propagation) const
127{
128 #ifdef OPENNN_DEBUG
129
130 check();
131
132 #endif
133
134 const Index outputs_number = neural_network_pointer->get_outputs_number();
135
136 if(outputs_number == 1)
137 {
138 calculate_binary_output_delta(batch, forward_propagation, back_propagation);
139 }
140 else
141 {
142 calculate_multiple_output_delta(batch, forward_propagation, back_propagation);
143 }
144}
145
146
147void CrossEntropyError::calculate_binary_output_delta(const DataSetBatch& batch,
148 NeuralNetworkForwardPropagation& forward_propagation,
149 LossIndexBackPropagation& back_propagation) const
150{
151 const Index trainable_layers_number = neural_network_pointer->get_trainable_layers_number();
152
153 ProbabilisticLayerForwardPropagation* probabilistic_layer_forward_propagation
154 = static_cast<ProbabilisticLayerForwardPropagation*>(forward_propagation.layers(trainable_layers_number-1));
155
156 ProbabilisticLayerBackPropagation* probabilistic_layer_back_propagation
157 = static_cast<ProbabilisticLayerBackPropagation*>(back_propagation.neural_network.layers(trainable_layers_number-1));
158
159 const Index batch_samples_number = batch.inputs_2d.dimension(0);
160
161 const Tensor<type, 2>& targets = batch.targets_2d;
162
163 const Tensor<type, 2>& outputs = probabilistic_layer_forward_propagation->activations;
164
165 probabilistic_layer_back_propagation->delta.device(*thread_pool_device)
166 = static_cast<type>(1)/static_cast<type>(batch_samples_number) *
167 (static_cast<type>(-1)*(targets/outputs) + (static_cast<type>(1) - targets)/(static_cast<type>(1) - outputs));
168}
169
170
171void CrossEntropyError::calculate_multiple_output_delta(const DataSetBatch& batch,
172 NeuralNetworkForwardPropagation& forward_propagation,
173 LossIndexBackPropagation& back_propagation) const
174{
175 const Index trainable_layers_number = neural_network_pointer->get_trainable_layers_number();
176
177 ProbabilisticLayerBackPropagation* probabilistic_layer_back_propagation
178 = static_cast<ProbabilisticLayerBackPropagation*>(back_propagation.neural_network.layers(trainable_layers_number-1));
179
180 const Index batch_samples_number = batch.inputs_2d.dimension(0);
181
182 const Tensor<type, 2>& targets = batch.targets_2d;
183
184 const Tensor<type, 2>& outputs =
185 static_cast<ProbabilisticLayerForwardPropagation*>(forward_propagation.layers(trainable_layers_number-1))->activations;
186
187 probabilistic_layer_back_propagation->delta.device(*thread_pool_device)
188 = static_cast<type>(1)/static_cast<type>(batch_samples_number) *(-targets/outputs);
189}
190
191
193
195{
196 return "CROSS_ENTROPY_ERROR";
197}
198
199
201
203{
204 return "Cross entropy error";
205}
206
207
210
212{
213 // Error type
214
215 file_stream.OpenElement("CrossEntropyError");
216
217 file_stream.CloseElement();
218}
219
220
223
225{
226 const tinyxml2::XMLElement* root_element = document.FirstChildElement("CrossEntropyError");
227
228 if(!root_element)
229 {
230 ostringstream buffer;
231
232 buffer << "OpenNN Exception: CrossEntropyError class.\n"
233 << "void from_XML(const tinyxml2::XMLDocument&) method.\n"
234 << "Cross entropy error element is nullptr.\n";
235
236 throw logic_error(buffer.str());
237 }
238
239 // Regularization
240
241 tinyxml2::XMLDocument regularization_document;
242 tinyxml2::XMLNode* element_clone;
243
244 const tinyxml2::XMLElement* regularization_element = root_element->FirstChildElement("Regularization");
245
246 element_clone = regularization_element->DeepClone(&regularization_document);
247
248 regularization_document.InsertFirstChild(element_clone);
249
250 regularization_from_XML(regularization_document);
251}
252
253}
254
255// OpenNN: Open Neural Networks Library.
256// Copyright(C) 2005-2021 Artificial Intelligence Techniques, SL.
257//
258// This library is free software; you can redistribute it and/or
259// modify it under the terms of the GNU Lesser General Public
260// License as published by the Free Software Foundation; either
261// version 2.1 of the License, or any later version.
262//
263// This library is distributed in the hope that it will be useful,
264// but WITHOUT ANY WARRANTY; without even the implied warranty of
265// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
266// Lesser General Public License for more details.
267
268// You should have received a copy of the GNU Lesser General Public
269// License along with this library; if not, write to the Free Software
270// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
void from_XML(const tinyxml2::XMLDocument &)
string get_error_type() const
Returns a string with the name of the cross entropy error loss type, "CROSS_ENTROPY_ERROR".
virtual ~CrossEntropyError()
Destructor.
void write_XML(tinyxml2::XMLPrinter &) const
string get_error_type_text() const
Returns a string with the name of the cross entropy error loss type in text format.
This class represents the concept of data set for data modelling problems, such as approximation,...
Definition: data_set.h:57
This abstract class represents the concept of layer of neurons in OpenNN.
Definition: layer.h:53
Type get_type() const
Definition: layer.cpp:25
string get_type_string() const
Takes the type of layer used by the model.
Definition: layer.cpp:33
This abstract class represents the concept of loss index composed of an error term and a regularizati...
Definition: loss_index.h:48
NeuralNetwork * neural_network_pointer
Pointer to a neural network object.
Definition: loss_index.h:254
void check() const
Definition: loss_index.cpp:295
virtual void CloseElement(bool compactMode=false)
If streaming, close the Element.
Definition: tinyxml2.cpp:2834