Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
NeuralNet.icc
Go to the documentation of this file.
1#ifndef TMVA_NEURAL_NET_I
2#define TMVA_NEURAL_NET_I
3
4#ifndef TMVA_NEURAL_NET
5#error "Do not use NeuralNet.icc directly. #include \"NeuralNet.h\" instead."
6#endif // TMVA_NEURAL_NET
7#pragma once
8#ifndef _MSC_VER
9#pragma GCC diagnostic ignored "-Wunused-variable"
10#endif
11
12#include "Math/Util.h"
13
14#include "TMVA/Pattern.h"
15#include "TMVA/MethodBase.h"
16
17#include <tuple>
18#include <future>
19#include <random>
20
21namespace TMVA
22{
23 namespace DNN
24 {
25
26
27
28
29
30
31
32
33 template <typename T>
34 T uniformFromTo (T from, T to)
35 {
36 return from + (rand ()* (to - from)/RAND_MAX);
37 }
38
39
40
41 template <typename Container, typename T>
43 {
44 for (auto it = begin (container), itEnd = end (container); it != itEnd; ++it)
45 {
46// (*it) = uniformFromTo (-1.0*maxValue, 1.0*maxValue);
47 (*it) = TMVA::DNN::uniformFromTo (-1.0*maxValue, 1.0*maxValue);
48 }
49 }
50
51
52 extern std::shared_ptr<std::function<double(double)>> ZeroFnc;
53
54
55 extern std::shared_ptr<std::function<double(double)>> Sigmoid;
56 extern std::shared_ptr<std::function<double(double)>> InvSigmoid;
57
58 extern std::shared_ptr<std::function<double(double)>> Tanh;
59 extern std::shared_ptr<std::function<double(double)>> InvTanh;
60
61 extern std::shared_ptr<std::function<double(double)>> Linear;
62 extern std::shared_ptr<std::function<double(double)>> InvLinear;
63
64 extern std::shared_ptr<std::function<double(double)>> SymmReLU;
65 extern std::shared_ptr<std::function<double(double)>> InvSymmReLU;
66
67 extern std::shared_ptr<std::function<double(double)>> ReLU;
68 extern std::shared_ptr<std::function<double(double)>> InvReLU;
69
70 extern std::shared_ptr<std::function<double(double)>> SoftPlus;
71 extern std::shared_ptr<std::function<double(double)>> InvSoftPlus;
72
73 extern std::shared_ptr<std::function<double(double)>> TanhShift;
74 extern std::shared_ptr<std::function<double(double)>> InvTanhShift;
75
76 extern std::shared_ptr<std::function<double(double)>> SoftSign;
77 extern std::shared_ptr<std::function<double(double)>> InvSoftSign;
78
79 extern std::shared_ptr<std::function<double(double)>> Gauss;
80 extern std::shared_ptr<std::function<double(double)>> InvGauss;
81
82 extern std::shared_ptr<std::function<double(double)>> GaussComplement;
83 extern std::shared_ptr<std::function<double(double)>> InvGaussComplement;
84
85
86/*! \brief apply weights using drop-out; for no drop out, provide (&bool = true) to itDrop such that *itDrop becomes "true"
87 *
88 * itDrop correlates with itSourceBegin
89 */
90template <bool HasDropOut, typename ItSource, typename ItWeight, typename ItTarget, typename ItDrop>
95 {
97 {
99 {
100 if (!HasDropOut || *itDrop)
101 (*itTarget) += (*itSource) * (*itWeight);
102 ++itWeight;
103 }
104 if (HasDropOut) ++itDrop;
105 }
106 }
107
108
109
110
111
112
113/*! \brief apply weights backwards (for backprop); for no drop out, provide (&bool = true) to itDrop such that *itDrop becomes "true"
114 *
115 * itDrop correlates with itPrev (to be in agreement with "applyWeights" where it correlates with itSources (same node as itTarget here in applyBackwards)
116 */
117template <bool HasDropOut, typename ItSource, typename ItWeight, typename ItPrev, typename ItDrop>
122 {
123 for (auto itPrev = itPrevBegin; itPrev != itPrevEnd; ++itPrev)
124 {
125 for (auto itCurr = itCurrBegin; itCurr != itCurrEnd; ++itCurr)
126 {
127 if (!HasDropOut || *itDrop)
128 (*itPrev) += (*itCurr) * (*itWeight);
129 ++itWeight;
130 }
131 if (HasDropOut) ++itDrop;
132 }
133 }
134
135
136
137
138
139
140
141/*! \brief apply the activation functions
142 *
143 *
144 */
145
146 template <typename ItValue, typename Fnc>
148 {
149 while (itValue != itValueEnd)
150 {
151 auto& value = (*itValue);
152 value = (*fnc.get ()) (value);
153
154 ++itValue;
155 }
156 }
157
158
159/*! \brief apply the activation functions and compute the gradient
160 *
161 *
162 */
163 template <typename ItValue, typename Fnc, typename InvFnc, typename ItGradient>
165 {
166 while (itValue != itValueEnd)
167 {
168 auto& value = (*itValue);
169 value = (*fnc.get ()) (value);
170 (*itGradient) = (*invFnc.get ()) (value);
171
172 ++itValue; ++itGradient;
173 }
174 }
175
176
177
178/*! \brief update the gradients
179 *
180 *
181 */
182 template <typename ItSource, typename ItDelta, typename ItTargetGradient, typename ItGradient>
187 {
188 while (itSource != itSourceEnd)
189 {
193 {
194 (*itGradient) -= (*itTargetDelta) * (*itSource) * (*itTargetGradient);
196 }
197 ++itSource;
198 }
199 }
200
201
202
203
204/*! \brief compute the regularization (L1, L2)
205 *
206 *
207 */
208 template <EnumRegularization Regularization>
209 inline double computeRegularization (double weight, const double& factorWeightDecay)
210 {
211 MATH_UNUSED(weight);
212 MATH_UNUSED(factorWeightDecay);
213
214 return 0;
215 }
216
217// L1 regularization
218 template <>
219 inline double computeRegularization<EnumRegularization::L1> (double weight, const double& factorWeightDecay)
220 {
221 return weight == 0.0 ? 0.0 : std::copysign (factorWeightDecay, weight);
222 }
223
224// L2 regularization
225 template <>
226 inline double computeRegularization<EnumRegularization::L2> (double weight, const double& factorWeightDecay)
227 {
228 return factorWeightDecay * weight;
229 }
230
231
232/*! \brief update the gradients, using regularization
233 *
234 *
235 */
236 template <EnumRegularization Regularization, typename ItSource, typename ItDelta, typename ItTargetGradient, typename ItGradient, typename ItWeight>
242 {
243 // ! the factor weightDecay has to be already scaled by 1/n where n is the number of weights
244 while (itSource != itSourceEnd)
245 {
249 {
250 (*itGradient) -= + (*itTargetDelta) * (*itSource) * (*itTargetGradient) + computeRegularization<Regularization>(*itWeight,weightDecay);
252 }
253 ++itSource;
254 }
255 }
256
257
258
259
260
261
262#define USELOCALWEIGHTS 1
263
264
265
266/*! \brief implementation of the steepest gradient descent algorithm
267 *
268 * Can be used with multithreading (i.e. "HogWild!" style); see call in trainCycle
269 */
270 template <typename Function, typename Weights, typename PassThrough>
271 double Steepest::operator() (Function& fitnessFunction, Weights& weights, PassThrough& passThrough)
272 {
273 size_t numWeights = weights.size ();
274 // std::vector<double> gradients (numWeights, 0.0);
275 m_localGradients.assign (numWeights, 0.0);
276 // std::vector<double> localWeights (begin (weights), end (weights));
277 // m_localWeights.reserve (numWeights);
278 m_localWeights.assign (begin (weights), end (weights));
279
280 double E = 1e10;
281 if (m_prevGradients.size () != numWeights)
282 {
283 m_prevGradients.clear ();
284 m_prevGradients.assign (weights.size (), 0);
285 }
286
287 bool success = true;
288 size_t currentRepetition = 0;
289 while (success)
290 {
292 break;
293
294 m_localGradients.assign (numWeights, 0.0);
295
296 // --- nesterov momentum ---
297 // apply momentum before computing the new gradient
298 auto itPrevG = begin (m_prevGradients);
299 auto itPrevGEnd = end (m_prevGradients);
300 auto itLocWeight = begin (m_localWeights);
301 for (; itPrevG != itPrevGEnd; ++itPrevG, ++itLocWeight)
302 {
303 (*itPrevG) *= m_beta;
304 (*itLocWeight) += (*itPrevG);
305 }
306
308// plotGradients (gradients);
309// plotWeights (localWeights);
310
311 double alpha = gaussDouble (m_alpha, m_alpha/2.0);
312// double alpha = m_alpha;
313
314 auto itG = begin (m_localGradients);
315 auto itGEnd = end (m_localGradients);
316 itPrevG = begin (m_prevGradients);
317 double maxGrad = 0.0;
318 for (; itG != itGEnd; ++itG, ++itPrevG)
319 {
320 double currGrad = (*itG);
321 double prevGrad = (*itPrevG);
322 currGrad *= alpha;
323
324 //(*itPrevG) = m_beta * (prevGrad + currGrad);
326 (*itG) = currGrad;
327 (*itPrevG) = currGrad;
328
329 if (std::fabs (currGrad) > maxGrad)
331 }
332
333 if (maxGrad > 1)
334 {
335 m_alpha /= 2;
336 std::cout << "\nlearning rate reduced to " << m_alpha << std::endl;
337 std::for_each (weights.begin (), weights.end (), [maxGrad](double& w)
338 {
339 w /= maxGrad;
340 });
341 m_prevGradients.clear ();
342 }
343 else
344 {
345 auto itW = std::begin (weights);
346 std::for_each (std::begin (m_localGradients), std::end (m_localGradients), [&itW](double& g)
347 {
348 *itW += g;
349 ++itW;
350 });
351 }
352
354 }
355 return E;
356 }
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377/*! \brief sum of squares error function
378 *
379 *
380 */
381 template <typename ItOutput, typename ItTruth, typename ItDelta, typename InvFnc>
383 {
384 double errorSum = 0.0;
385
386 // output - truth
388 bool hasDeltas = (itDelta != itDeltaEnd);
390 {
391// assert (itTruth != itTruthEnd);
392 double output = (*itOutput);
393 double error = output - (*itTruth);
394 if (hasDeltas)
395 {
396 (*itDelta) = (*invFnc.get ()) (output) * error * patternWeight;
397 ++itDelta;
398 }
399 errorSum += error*error * patternWeight;
400 }
401
402 return 0.5*errorSum;
403 }
404
405
406
407/*! \brief cross entropy error function
408 *
409 *
410 */
411 template <typename ItProbability, typename ItTruth, typename ItDelta, typename ItInvActFnc>
413 {
414 bool hasDeltas = (itDelta != itDeltaEnd);
415
416 double errorSum = 0.0;
418 {
419 double probability = *itProbability;
420 double truth = *itTruthBegin;
421 /* truth = truth < 0.1 ? 0.1 : truth; */
422 /* truth = truth > 0.9 ? 0.9 : truth; */
423 truth = truth < 0.5 ? 0.1 : 0.9;
424 if (hasDeltas)
425 {
426 double delta = probability - truth;
427 (*itDelta) = delta*patternWeight;
428// (*itDelta) = (*itInvActFnc)(probability) * delta * patternWeight;
429 ++itDelta;
430 }
431 double error (0);
432 if (probability == 0) // protection against log (0)
433 {
434 if (truth >= 0.5)
435 error += 1.0;
436 }
437 else if (probability == 1)
438 {
439 if (truth < 0.5)
440 error += 1.0;
441 }
442 else
443 error += - (truth * log (probability) + (1.0-truth) * log (1.0-probability)); // cross entropy function
444 errorSum += error * patternWeight;
445
446 }
447 return errorSum;
448 }
449
450
451
452
453/*! \brief soft-max-cross-entropy error function (for mutual exclusive cross-entropy)
454 *
455 *
456 */
457 template <typename ItOutput, typename ItTruth, typename ItDelta, typename ItInvActFnc>
459 {
460 double errorSum = 0.0;
461
462 bool hasDeltas = (itDelta != itDeltaEnd);
463 // output - truth
466 {
467// assert (itTruth != itTruthEnd);
468 double probability = (*itProbability);
469 double truth = (*itTruth);
470 if (hasDeltas)
471 {
472 (*itDelta) = probability - truth;
473// (*itDelta) = (*itInvActFnc)(sm) * delta * patternWeight;
474 ++itDelta; //++itInvActFnc;
475 }
476 double error (0);
477
478 error += truth * log (probability);
479 errorSum += error;
480 }
481
482 return -errorSum * patternWeight;
483 }
484
485
486
487
488
489
490
491
492
493/*! \brief compute the weight decay for regularization (L1 or L2)
494 *
495 *
496 */
497 template <typename ItWeight>
498 double weightDecay (double error, ItWeight itWeight, ItWeight itWeightEnd, double factorWeightDecay, EnumRegularization eRegularization)
499 {
501 {
502 // weight decay (regularization)
503 double w = 0;
504 size_t n = 0;
505 for (; itWeight != itWeightEnd; ++itWeight, ++n)
506 {
507 double weight = (*itWeight);
508 w += std::fabs (weight);
509 }
510 return error + 0.5 * w * factorWeightDecay / n;
511 }
513 {
514 // weight decay (regularization)
515 double w = 0;
516 size_t n = 0;
517 for (; itWeight != itWeightEnd; ++itWeight, ++n)
518 {
519 double weight = (*itWeight);
520 w += weight*weight;
521 }
522 return error + 0.5 * w * factorWeightDecay / n;
523 }
524 else
525 return error;
526 }
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541/*! \brief apply the weights (and functions) in forward direction of the DNN
542 *
543 *
544 */
545 template <typename LAYERDATA>
547 {
548 if (prevLayerData.hasDropOut ())
549 {
550 applyWeights<true> (prevLayerData.valuesBegin (), prevLayerData.valuesEnd (),
551 currLayerData.weightsBegin (),
552 currLayerData.valuesBegin (), currLayerData.valuesEnd (),
553 prevLayerData.dropOut ());
554 }
555 else
556 {
557 bool dummy = true;
558 applyWeights<false> (prevLayerData.valuesBegin (), prevLayerData.valuesEnd (),
559 currLayerData.weightsBegin (),
560 currLayerData.valuesBegin (), currLayerData.valuesEnd (),
561 &dummy); // dummy to turn on all nodes (no drop out)
562 }
563 }
564
565
566
567/*! \brief backward application of the weights (back-propagation of the error)
568 *
569 *
570 */
571template <typename LAYERDATA>
573{
574 if (prevLayerData.hasDropOut ())
575 {
576 applyWeightsBackwards<true> (currLayerData.deltasBegin (), currLayerData.deltasEnd (),
577 currLayerData.weightsBegin (),
578 prevLayerData.deltasBegin (), prevLayerData.deltasEnd (),
579 prevLayerData.dropOut ());
580 }
581 else
582 {
583 bool dummy = true;
584 applyWeightsBackwards<false> (currLayerData.deltasBegin (), currLayerData.deltasEnd (),
585 currLayerData.weightsBegin (),
586 prevLayerData.deltasBegin (), prevLayerData.deltasEnd (),
587 &dummy); // dummy to use all nodes (no drop out)
588 }
589}
590
591
592
593
594
595/*! \brief update the node values
596 *
597 *
598 */
599 template <typename LAYERDATA>
601 {
602 // ! the "factorWeightDecay" has already to be scaled by 1/n where n is the number of weights
603 if (factorWeightDecay != 0.0) // has weight regularization
604 if (regularization == EnumRegularization::L1) // L1 regularization ( sum(|w|) )
605 {
606 update<EnumRegularization::L1> (prevLayerData.valuesBegin (), prevLayerData.valuesEnd (),
607 currLayerData.deltasBegin (), currLayerData.deltasEnd (),
608 currLayerData.valueGradientsBegin (), currLayerData.gradientsBegin (),
609 currLayerData.weightsBegin (), factorWeightDecay);
610 }
611 else if (regularization == EnumRegularization::L2) // L2 regularization ( sum(w^2) )
612 {
613 update<EnumRegularization::L2> (prevLayerData.valuesBegin (), prevLayerData.valuesEnd (),
614 currLayerData.deltasBegin (), currLayerData.deltasEnd (),
615 currLayerData.valueGradientsBegin (), currLayerData.gradientsBegin (),
616 currLayerData.weightsBegin (), factorWeightDecay);
617 }
618 else
619 {
620 update (prevLayerData.valuesBegin (), prevLayerData.valuesEnd (),
621 currLayerData.deltasBegin (), currLayerData.deltasEnd (),
622 currLayerData.valueGradientsBegin (), currLayerData.gradientsBegin ());
623 }
624
625 else
626 { // no weight regularization
627 update (prevLayerData.valuesBegin (), prevLayerData.valuesEnd (),
628 currLayerData.deltasBegin (), currLayerData.deltasEnd (),
629 currLayerData.valueGradientsBegin (), currLayerData.gradientsBegin ());
630 }
631 }
632
633
634
635
636
637
638
639
640
641
642
643
644/*! \brief compute the drop-out-weight factor
645 *
646 * when using drop-out a fraction of the nodes is turned off at each cycle of the computation
647 * once all nodes are turned on again (for instances when the test samples are evaluated),
648 * the weights have to be adjusted to account for the different number of active nodes
649 * this function computes the factor and applies it to the weights
650 */
651 template <typename WeightsType, typename DropProbabilities>
654 bool inverse)
655 {
656 if (drops.empty () || weights.empty ())
657 return;
658
659 auto itWeight = std::begin (weights);
660 auto itWeightEnd = std::end (weights);
661 auto itDrop = std::begin (drops);
662 auto itDropEnd = std::end (drops);
663 size_t numNodesPrev = inputSize ();
664 double dropFractionPrev = *itDrop;
665 ++itDrop;
666
667 for (auto& layer : layers ())
668 {
669 if (itDrop == itDropEnd)
670 break;
671
672 size_t _numNodes = layer.numNodes ();
673
674 double dropFraction = *itDrop;
675 double pPrev = 1.0 - dropFractionPrev;
676 double p = 1.0 - dropFraction;
677 p *= pPrev;
678
679 if (inverse)
680 {
681 p = 1.0/p;
682 }
683 size_t _numWeights = layer.numWeights (numNodesPrev);
684 for (size_t iWeight = 0; iWeight < _numWeights; ++iWeight)
685 {
686 if (itWeight == itWeightEnd)
687 break;
688
689 *itWeight *= p;
690 ++itWeight;
691 }
694 ++itDrop;
695 }
696 }
697
698
699
700
701
702
703/*! \brief execute the training until convergence emerges
704 *
705 * \param weights the container with the weights (synapses)
706 * \param trainPattern the pattern for the training
707 * \param testPattern the pattern for the testing
708 * \param minimizer the minimizer (e.g. steepest gradient descent) to be used
709 * \param settings the settings for the training (e.g. multithreading or not, regularization etc.)
710 */
711 template <typename Minimizer>
712 double Net::train (std::vector<double>& weights,
713 std::vector<Pattern>& trainPattern,
714 const std::vector<Pattern>& testPattern,
715 Minimizer& minimizer,
717 {
718// std::cout << "START TRAINING" << std::endl;
719 settings.startTrainCycle ();
720
721 settings.pads (4);
722 settings.create ("trainErrors", 100, 0, 100, 100, 0,1);
723 settings.create ("testErrors", 100, 0, 100, 100, 0,1);
724
725 size_t cycleCount = 0;
726 size_t testCycleCount = 0;
727 double testError = 1e20;
728 double trainError = 1e20;
729 size_t dropOutChangeCount = 0;
730
733 const std::vector<double>& dropFractions = settings.dropFractions ();
734 bool isWeightsForDrop = false;
735
736
737 // until convergence
738 do
739 {
740 ++cycleCount;
741
742 // if dropOut enabled
743 size_t dropIndex = 0;
744 if (!dropFractions.empty () && dropOutChangeCount % settings.dropRepetitions () == 0)
745 {
746 // fill the dropOut-container
747 dropContainer.clear ();
748 size_t _numNodes = inputSize ();
749 double dropFraction = 0.0;
750 dropFraction = dropFractions.at (dropIndex);
751 ++dropIndex;
753 for (auto itLayer = begin (m_layers), itLayerEnd = end (m_layers); itLayer != itLayerEnd; ++itLayer, ++dropIndex)
754 {
755 auto& layer = *itLayer;
756 _numNodes = layer.numNodes ();
757 // how many nodes have to be dropped
758 dropFraction = 0.0;
759 if (dropFractions.size () > dropIndex)
760 dropFraction = dropFractions.at (dropIndex);
761
763 }
764 isWeightsForDrop = true;
765 }
766
767 // execute training cycle
768 trainError = trainCycle (minimizer, weights, begin (trainPattern), end (trainPattern), settings, dropContainer);
769
770
771 // ------ check if we have to execute a test ------------------
772 bool hasConverged = false;
773 if (testCycleCount % settings.testRepetitions () == 0) // we test only everye "testRepetitions" repetition
774 {
776 {
777 dropOutWeightFactor (weights, dropFractions);
778 isWeightsForDrop = false;
779 }
780
781
782 testError = 0;
783 //double weightSum = 0;
784 settings.startTestCycle ();
785 if (settings.useMultithreading ())
786 {
787 size_t numThreads = std::thread::hardware_concurrency ();
788 size_t patternPerThread = testPattern.size () / numThreads;
789 std::vector<Batch> batches;
790 auto itPat = testPattern.begin ();
791 // auto itPatEnd = testPattern.end ();
792 for (size_t idxThread = 0; idxThread < numThreads-1; ++idxThread)
793 {
794 batches.push_back (Batch (itPat, itPat + patternPerThread));
796 }
797 if (itPat != testPattern.end ())
798 batches.push_back (Batch (itPat, testPattern.end ()));
799
800 std::vector<std::future<std::tuple<double,std::vector<double>>>> futures;
801 for (auto& batch : batches)
802 {
803 // -------------------- execute each of the batch ranges on a different thread -------------------------------
804 futures.push_back (
805 std::async (std::launch::async, [&]()
806 {
807 std::vector<double> localOutput;
809 double testBatchError = (*this) (passThrough, weights, ModeOutput::FETCH, localOutput);
810 return std::make_tuple (testBatchError, localOutput);
811 })
812 );
813 }
814
815 auto itBatch = batches.begin ();
816 for (auto& f : futures)
817 {
818 std::tuple<double,std::vector<double>> result = f.get ();
819 testError += std::get<0>(result) / batches.size ();
820 std::vector<double> output = std::get<1>(result);
821 if (output.size() == (outputSize() - 1) * itBatch->size())
822 {
823 auto output_iterator = output.begin();
824 for (auto pattern_it = itBatch->begin(); pattern_it != itBatch->end(); ++pattern_it)
825 {
826 for (size_t output_index = 1; output_index < outputSize(); ++output_index)
827 {
828 settings.testSample (0, *output_iterator, (*pattern_it).output ().at (0),
829 (*pattern_it).weight ());
831 }
832 }
833 }
834 ++itBatch;
835 }
836
837 }
838 else
839 {
840 std::vector<double> output;
841 //for (auto it = begin (testPattern), itEnd = end (testPattern); it != itEnd; ++it)
842 {
843 //const Pattern& p = (*it);
844 //double weight = p.weight ();
845 //Batch batch (it, it+1);
846 Batch batch (begin (testPattern), end (testPattern));
847 output.clear ();
849 double testPatternError = (*this) (passThrough, weights, ModeOutput::FETCH, output);
850 if (output.size() == (outputSize() - 1) * batch.size())
851 {
852 auto output_iterator = output.begin();
853 for (auto pattern_it = batch.begin(); pattern_it != batch.end(); ++pattern_it)
854 {
855 for (size_t output_index = 1; output_index < outputSize(); ++output_index)
856 {
857 settings.testSample (0, *output_iterator, (*pattern_it).output ().at (0),
858 (*pattern_it).weight ());
860 }
861 }
862 }
863 testError += testPatternError; /// batch.size ();
864 }
865 // testError /= testPattern.size ();
866 }
867 settings.endTestCycle ();
868// testError /= weightSum;
869
870 settings.computeResult (*this, weights);
871
872 hasConverged = settings.hasConverged (testError);
873 if (!hasConverged && !isWeightsForDrop)
874 {
875 dropOutWeightFactor (weights, dropFractions, true); // inverse
876 isWeightsForDrop = true;
877 }
878 }
881
882
883// settings.resetPlot ("errors");
884 settings.addPoint ("trainErrors", cycleCount, trainError);
885 settings.addPoint ("testErrors", cycleCount, testError);
886 settings.plot ("trainErrors", "C", 1, kBlue);
887 settings.plot ("testErrors", "C", 1, kMagenta);
888
889
890 if (hasConverged)
891 break;
892
893 if ((int)cycleCount % 10 == 0) {
894
895 TString convText = TString::Format( "(train/test/epo/conv/maxco): %.3g/%.3g/%d/%d/%d",
897 testError,
898 (int)cycleCount,
899 (int)settings.convergenceCount (),
900 (int)settings.maxConvergenceCount ());
901 double progress = 100*(double)settings.maxConvergenceCount () /(double)settings.convergenceSteps ();
902 settings.cycle (progress, convText);
903 }
904 }
905 while (true);
906 settings.endTrainCycle (trainError);
907
908 TString convText = TString::Format( "(train/test/epoch): %.4g/%.4g/%d", trainError, testError, (int)cycleCount);
909 double progress = 100*(double)settings.maxConvergenceCount() /(double)settings.convergenceSteps ();
910 settings.cycle (progress, convText);
911
912 return testError;
913 }
914
915
916
917/*! \brief execute a single training cycle
918 *
919 * uses multithreading if turned on
920 *
921 * \param minimizer the minimizer to be used (e.g. SGD)
922 * \param weights the weight container with all the synapse weights
923 * \param itPatternBegin begin of the pattern container
924 * \param itPatternEnd the end of the pattern container
925 * \param settings the settings for this training (e.g. multithreading or not, regularization, etc.)
926 * \param dropContainer the data for dropping-out nodes (regularization technique)
927 */
928 template <typename Iterator, typename Minimizer>
929 inline double Net::trainCycle (Minimizer& minimizer, std::vector<double>& weights,
931 {
932 double error = 0.0;
933 size_t numPattern = std::distance (itPatternBegin, itPatternEnd);
934 size_t numBatches = numPattern/settings.batchSize ();
936
937 std::shuffle(itPatternBegin, itPatternEnd, std::default_random_engine{});
940
941 // create batches
942 std::vector<Batch> batches;
943 while (numBatches > 0)
944 {
945 std::advance (itPatternBatchEnd, settings.batchSize ());
948 --numBatches;
949 }
950
951 // add the last pattern to the last batch
954
955
956 ///< turn on multithreading if requested
957 if (settings.useMultithreading ())
958 {
959 // -------------------- divide the batches into bunches for each thread --------------
960 size_t numThreads = std::thread::hardware_concurrency ();
961 size_t batchesPerThread = batches.size () / numThreads;
962 typedef std::vector<Batch>::iterator batch_iterator;
963 std::vector<std::pair<batch_iterator,batch_iterator>> batchVec;
964 batch_iterator itBatchBegin = std::begin (batches);
966 batch_iterator itBatchEnd = std::end (batches);
967 for (size_t iT = 0; iT < numThreads; ++iT)
968 {
969 if (iT == numThreads-1)
971 else
972 std::advance (itBatchCurrEnd, batchesPerThread);
973 batchVec.push_back (std::make_pair (itBatchBegin, itBatchCurrEnd));
975 }
976
977 // -------------------- loop over batches -------------------------------------------
978 std::vector<std::future<double>> futures;
979 for (auto& batchRange : batchVec)
980 {
981 // -------------------- execute each of the batch ranges on a different thread -------------------------------
982 futures.push_back (
983 std::async (std::launch::async, [&]()
984 {
985 double localError = 0.0;
986 for (auto it = batchRange.first, itEnd = batchRange.second; it != itEnd; ++it)
987 {
988 Batch& batch = *it;
990 Minimizer minimizerClone (minimizer);
991 localError += minimizerClone ((*this), weights, settingsAndBatch); /// call the minimizer
992 }
993 return localError;
994 })
995 );
996 }
997
998 for (auto& f : futures)
999 error += f.get ();
1000 }
1001 else
1002 {
1003 for (auto& batch : batches)
1004 {
1005 std::tuple<Settings&, Batch&, DropContainer&> settingsAndBatch (settings, batch, dropContainer);
1006 error += minimizer ((*this), weights, settingsAndBatch);
1007 }
1008 }
1009
1010 numBatches_stored = std::max (numBatches_stored, size_t(1)); /// normalize the error
1011 error /= numBatches_stored;
1012 settings.testIteration ();
1013
1014 return error;
1015 }
1016
1017
1018
1019
1020
1021/*! \brief compute the neural net
1022 *
1023 * \param input the input data
1024 * \param weights the weight data
1025 */
1026 template <typename Weights>
1027 std::vector<double> Net::compute (const std::vector<double>& input, const Weights& weights) const
1028 {
1029 std::vector<LayerData> layerData;
1030 layerData.reserve (m_layers.size ()+1);
1031 auto itWeight = begin (weights);
1032 auto itInputBegin = begin (input);
1033 auto itInputEnd = end (input);
1035 size_t numNodesPrev = input.size ();
1036
1037 // -------------------- prepare layer data with one pattern -------------------------------
1038 for (auto& layer: m_layers)
1039 {
1040 layerData.push_back (LayerData (layer.numNodes (), itWeight,
1041 layer.activationFunction (),
1042 layer.modeOutputValues ()));
1043 size_t _numWeights = layer.numWeights (numNodesPrev);
1045 numNodesPrev = layer.numNodes ();
1046 }
1047
1048
1049 // --------- forward -------------
1051
1052 // ------------- fetch output ------------------
1053 std::vector<double> output;
1054 fetchOutput (layerData.back (), output);
1055 return output;
1056 }
1057
1058
1059 template <typename Weights, typename PassThrough>
1060 double Net::operator() (PassThrough& settingsAndBatch, const Weights& weights) const
1061 {
1062 std::vector<double> nothing; // empty gradients; no backpropagation is done, just forward
1063 assert (numWeights () == weights.size ());
1064 double error = forward_backward(m_layers, settingsAndBatch, std::begin (weights), std::end (weights), std::begin (nothing), std::end (nothing), 10000, nothing, false);
1065 return error;
1066 }
1067
1068 template <typename Weights, typename PassThrough, typename OutContainer>
1069 double Net::operator() (PassThrough& settingsAndBatch, const Weights& weights, ModeOutput /*eFetch*/, OutContainer& outputContainer) const
1070 {
1071 std::vector<double> nothing; // empty gradients; no backpropagation is done, just forward
1072 assert (numWeights () == weights.size ());
1073 double error = forward_backward(m_layers, settingsAndBatch, std::begin (weights), std::end (weights), std::begin (nothing), std::end (nothing), 10000, outputContainer, true);
1074 return error;
1075 }
1076
1077
1078 template <typename Weights, typename Gradients, typename PassThrough>
1079 double Net::operator() (PassThrough& settingsAndBatch, Weights& weights, Gradients& gradients) const
1080 {
1081 std::vector<double> nothing;
1082 assert (numWeights () == weights.size ());
1083 assert (weights.size () == gradients.size ());
1084 double error = forward_backward(m_layers, settingsAndBatch, std::begin (weights), std::end (weights), std::begin (gradients), std::end (gradients), 0, nothing, false);
1085 return error;
1086 }
1087
1088 template <typename Weights, typename Gradients, typename PassThrough, typename OutContainer>
1090 {
1092 assert (numWeights () == weights.size ());
1093 assert (weights.size () == gradients.size ());
1094 double error = forward_backward(m_layers, settingsAndBatch, std::begin (weights), std::end (weights), std::begin (gradients), std::end (gradients), 0, outputContainer, true);
1095 return error;
1096 }
1097
1098
1099
1100 template <typename LayerContainer, typename DropContainer, typename ItWeight, typename ItGradient>
1101 std::vector<std::vector<LayerData>> Net::prepareLayerData (LayerContainer& _layers,
1102 Batch& batch,
1105 ItWeight /*itWeightEnd*/,
1108 size_t& totalNumWeights) const
1109 {
1111 bool usesDropOut = !dropContainer.empty ();
1112 if (usesDropOut)
1113 itDropOut = std::begin (dropContainer);
1114
1115 if (_layers.empty ())
1116 throw std::string ("no layers in this net");
1117
1118
1119 // ----------- create layer data -------------------------------------------------------
1120 //LM- This assert not needed anymore (outputsize is actually numNodes+1)
1121 //assert (_layers.back ().numNodes () == outputSize ());
1122 totalNumWeights = 0;
1123 std::vector<std::vector<LayerData>> layerPatternData;
1124 layerPatternData.reserve (_layers.size ()+1);
1127 size_t numNodesPrev = inputSize ();
1130
1131 // ItWeight itGammaBegin = itWeightBegin + numWeights ();
1132 // ItWeight itBetaBegin = itWeightBegin + numWeights () + numNodes ();
1133 // ItGradient itGradGammaBegin = itGradientBegin + numWeights ();
1134 // ItGradient itGradBetaBegin = itGradientBegin + numWeights () + numNodes ();
1135
1136
1137 // --------------------- prepare layer data for input layer ----------------------------
1138 layerPatternData.push_back (std::vector<LayerData>());
1139 for (const Pattern& _pattern : batch)
1140 {
1141 std::vector<LayerData>& layerData = layerPatternData.back ();
1142 layerData.push_back (LayerData (numNodesPrev));
1143
1144 itInputBegin = _pattern.beginInput ();
1145 itInputEnd = _pattern.endInput ();
1146 layerData.back ().setInput (itInputBegin, itInputEnd);
1147
1148 if (usesDropOut)
1149 layerData.back ().setDropOut (itDropOut);
1150
1151 }
1152
1153
1154 if (usesDropOut)
1155 itDropOut += _layers.back ().numNodes ();
1156
1157 // ---------------- prepare subsequent layers ---------------------------------------------
1158 // for each of the layers
1159 for (auto itLayer = begin (_layers), itLayerEnd = end (_layers); itLayer != itLayerEnd; ++itLayer)
1160 {
1161 bool isOutputLayer = (itLayer+1 == itLayerEnd);
1162 bool isFirstHiddenLayer = (itLayer == begin (_layers));
1163
1164 auto& layer = *itLayer;
1165 layerPatternData.push_back (std::vector<LayerData>());
1166 // for each pattern, prepare a layerData
1167 for (const Pattern& _pattern : batch)
1168 {
1169 std::vector<LayerData>& layerData = layerPatternData.back ();
1170 //layerData.push_back (LayerData (numNodesPrev));
1171
1173 {
1174 layerData.push_back (LayerData (layer.numNodes (), itWeight,
1175 layer.activationFunction (),
1176 layer.modeOutputValues ()));
1177 }
1178 else
1179 {
1180 layerData.push_back (LayerData (layer.numNodes (), itWeight, itGradient,
1181 layer.activationFunction (),
1182 layer.inverseActivationFunction (),
1183 layer.modeOutputValues ()));
1184 }
1185
1186 if (usesDropOut)
1187 {
1188 layerData.back ().setDropOut (itDropOut);
1189 }
1190
1191 }
1192
1193 if (usesDropOut)
1194 {
1195 itDropOut += layer.numNodes ();
1196 }
1197 size_t _numWeights = layer.numWeights (numNodesPrev);
1201 numNodesPrev = layer.numNodes ();
1202
1203 }
1204 assert (totalNumWeights > 0);
1205 return layerPatternData;
1206}
1207
1208
1209
1210 template <typename LayerContainer>
1212 std::vector<LayerData>& layerData) const
1213 {
1214 size_t idxLayer = 0, idxLayerEnd = _layers.size ();
1215 for (; idxLayer < idxLayerEnd; ++idxLayer)
1216 {
1219
1221
1222 applyFunctions (currLayerData.valuesBegin (), currLayerData.valuesEnd (), currLayerData.activationFunction ());
1223 }
1224 }
1225
1226
1227
1228
1229 template <typename LayerContainer, typename LayerPatternContainer>
1232 std::vector<double>& valuesMean,
1233 std::vector<double>& valuesStdDev,
1234 size_t trainFromLayer) const
1235 {
1236 valuesMean.clear ();
1237 valuesStdDev.clear ();
1238
1239 // ---------------------------------- loop over layers and pattern -------------------------------------------------------
1240 for (size_t idxLayer = 0, idxLayerEnd = layerPatternData.size (); idxLayer < idxLayerEnd-1; ++idxLayer)
1241 {
1243
1244 // get layer-pattern data for this and the corresponding one from the next layer
1245 std::vector<LayerData>& prevLayerPatternData = layerPatternData.at (idxLayer);
1246 std::vector<LayerData>& currLayerPatternData = layerPatternData.at (idxLayer+1);
1247
1248 size_t numPattern = prevLayerPatternData.size ();
1249 size_t numNodesLayer = _layers.at (idxLayer).numNodes ();
1250
1251 std::vector<MeanVariance> means (numNodesLayer);
1252 // ---------------- loop over layerDatas of pattern compute forward ----------------------------
1253 for (size_t idxPattern = 0; idxPattern < numPattern; ++idxPattern)
1254 {
1257
1258
1259 forward (prevLayerData, currLayerData); // feed forward
1260 }
1261
1262 // ---------------- loop over layerDatas of pattern apply non-linearities ----------------------------
1263 for (size_t idxPattern = 0; idxPattern < numPattern; ++idxPattern)
1264 {
1265 //const LayerData& prevLayerData = prevLayerPatternData.at (idxPattern);
1267
1268 if (doTraining)
1269 applyFunctions (currLayerData.valuesBegin (), currLayerData.valuesEnd (), currLayerData.activationFunction (),
1270 currLayerData.inverseActivationFunction (), currLayerData.valueGradientsBegin ());
1271 else
1272 applyFunctions (currLayerData.valuesBegin (), currLayerData.valuesEnd (), currLayerData.activationFunction ());
1273 }
1274 }
1275}
1276
1277
1278
1279
1280 template <typename OutputContainer>
1282 {
1285 {
1286 outputContainer.insert (outputContainer.end (), lastLayerData.valuesBegin (), lastLayerData.valuesEnd ());
1287 }
1290 {
1291 const auto& prob = lastLayerData.probabilities ();
1292 outputContainer.insert (outputContainer.end (), prob.begin (), prob.end ()) ;
1293 }
1294 else
1295 assert (false);
1296 }
1297
1298
1299
1300
1301 template <typename OutputContainer>
1307
1308
1309
1310 template <typename ItWeight>
1311 std::tuple</*sumError*/double,/*sumWeights*/double> Net::computeError (const Settings& settings,
1312 std::vector<LayerData>& lastLayerData,
1313 Batch& batch,
1315 ItWeight itWeightEnd) const
1316 {
1317 typename std::vector<LayerData>::iterator itLayerData = lastLayerData.begin ();
1318// typename std::vector<LayerData>::iterator itLayerDataEnd = lastLayerData.end ();
1319
1320 typename std::vector<Pattern>::const_iterator itPattern = batch.begin ();
1321 typename std::vector<Pattern>::const_iterator itPatternEnd = batch.end ();
1322
1323 double sumWeights (0.0);
1324 double sumError (0.0);
1325
1326// FIXME: check that iteration doesn't go beyond itLayerDataEnd!
1328 {
1329 // compute E and the deltas of the computed output and the true output
1330 LayerData& layerData = (*itLayerData);
1331 const Pattern& _pattern = (*itPattern);
1332 double error = errorFunction (layerData, _pattern.output (),
1334 _pattern.weight (), settings.factorWeightDecay (),
1335 settings.regularization ());
1336 sumWeights += fabs (_pattern.weight ());
1337 sumError += error;
1338 }
1339 return std::make_tuple (sumError, sumWeights);
1340 }
1341
1342
1343
1344 template <typename Settings>
1345 void Net::backPropagate (std::vector<std::vector<LayerData>>& layerPatternData,
1346 const Settings& settings,
1347 size_t trainFromLayer,
1348 size_t totalNumWeights) const
1349 {
1351 if (doTraining) // training
1352 {
1353 // ------------- backpropagation -------------
1354 size_t idxLayer = layerPatternData.size ();
1357 {
1358 --idxLayer;
1359 if (idxLayer <= trainFromLayer) // no training
1360 break;
1361
1362 std::vector<LayerData>& currLayerDataColl = *(itLayerPatternData);
1363 std::vector<LayerData>& prevLayerDataColl = *(itLayerPatternData+1);
1364
1365// FIXME: check that itPrevLayerData doesn't go beyond itPrevLayerDataEnd!
1366 for (typename std::vector<LayerData>::iterator itCurrLayerData = begin (currLayerDataColl), itCurrLayerDataEnd = end (currLayerDataColl),
1367 itPrevLayerData = begin (prevLayerDataColl) /*, itPrevLayerDataEnd = end (prevLayerDataColl)*/;
1369 {
1370 LayerData& currLayerData = (*itCurrLayerData);
1372
1374
1375 // the factorWeightDecay has to be scaled by 1/n where n is the number of weights (synapses)
1376 // because L1 and L2 regularization
1377 //
1378 // http://neuralnetworksanddeeplearning.com/chap3.html#overfitting_and_regularization
1379 //
1380 // L1 : -factorWeightDecay*sgn(w)/numWeights
1381 // L2 : -factorWeightDecay/numWeights
1382 update (prevLayerData, currLayerData, settings.factorWeightDecay ()/totalNumWeights, settings.regularization ());
1383 }
1384 }
1385 }
1386 }
1387
1388
1389
1390/*! \brief forward propagation and backward propagation
1391 *
1392 *
1393 */
1394 template <typename LayerContainer, typename PassThrough, typename ItWeight, typename ItGradient, typename OutContainer>
1398 size_t trainFromLayer,
1400 {
1401 Settings& settings = std::get<0>(settingsAndBatch);
1402 Batch& batch = std::get<1>(settingsAndBatch);
1404
1405 double sumError = 0.0;
1406 double sumWeights = 0.0; // -------------
1407
1408
1409 // ----------------------------- prepare layer data -------------------------------------
1410 size_t totalNumWeights (0);
1411 std::vector<std::vector<LayerData>> layerPatternData = prepareLayerData (_layers,
1412 batch,
1419
1420
1421
1422 // ---------------------------------- propagate forward ------------------------------------------------------------------
1423 std::vector<double> valuesMean;
1424 std::vector<double> valuesStdDev;
1426
1427
1428 // ------------- fetch output ------------------
1429 if (doFetchOutput)
1430 {
1432 }
1433
1434
1435 // ------------- error computation -------------
1437
1438
1439 // ------------- backpropagation -------------
1441
1442
1443 // --- compile the measures
1444 double batchSize = std::distance (std::begin (batch), std::end (batch));
1445 for (auto it = itGradientBegin; it != itGradientEnd; ++it)
1446 (*it) /= batchSize;
1447
1448
1450 return sumError;
1451 }
1452
1453
1454
1455/*! \brief initialization of the weights
1456 *
1457 *
1458 */
1459 template <typename OutIterator>
1461 {
1463 {
1464 // input and output properties
1465 int numInput = inputSize ();
1466
1467 // compute variance and mean of input and output
1468 //...
1469
1470
1471 // compute the weights
1472 for (auto& layer: layers ())
1473 {
1474 double nIn = numInput;
1475 double stdDev = sqrt (2.0/nIn);
1476 for (size_t iWeight = 0, iWeightEnd = layer.numWeights (numInput); iWeight < iWeightEnd; ++iWeight)
1477 {
1478 (*itWeight) = DNN::gaussDouble (0.0, stdDev); // factor 2.0 for ReLU
1479 ++itWeight;
1480 }
1481 numInput = layer.numNodes ();
1482 }
1483 return;
1484 }
1485
1487 {
1488 // input and output properties
1489 int numInput = inputSize ();
1490
1491 // compute variance and mean of input and output
1492 //...
1493
1494
1495 // compute the weights
1496 for (auto& layer: layers ())
1497 {
1498 double nIn = numInput;
1499 double minVal = -sqrt(2.0/nIn);
1500 double maxVal = sqrt (2.0/nIn);
1501 for (size_t iWeight = 0, iWeightEnd = layer.numWeights (numInput); iWeight < iWeightEnd; ++iWeight)
1502 {
1503
1504 (*itWeight) = DNN::uniformDouble (minVal, maxVal); // factor 2.0 for ReLU
1505 ++itWeight;
1506 }
1507 numInput = layer.numNodes ();
1508 }
1509 return;
1510 }
1511
1513 {
1514 // input and output properties
1515 int numInput = inputSize ();
1516
1517 // compute variance and mean of input and output
1518 //...
1519
1520
1521 // compute the weights
1522 for (auto& layer: layers ())
1523 {
1524// double nIn = numInput;
1525 for (size_t iWeight = 0, iWeightEnd = layer.numWeights (numInput); iWeight < iWeightEnd; ++iWeight)
1526 {
1527 (*itWeight) = DNN::gaussDouble (0.0, 0.1);
1528 ++itWeight;
1529 }
1530 numInput = layer.numNodes ();
1531 }
1532 return;
1533 }
1534
1536 {
1537 // input and output properties
1538 int numInput = inputSize ();
1539
1540 // compute variance and mean of input and output
1541 //...
1542
1543
1544 // compute the weights
1545 for (auto& layer: layers ())
1546 {
1547 double nIn = numInput;
1548 for (size_t iWeight = 0, iWeightEnd = layer.numWeights (numInput); iWeight < iWeightEnd; ++iWeight)
1549 {
1550 (*itWeight) = DNN::gaussDouble (0.0, sqrt (layer.numWeights (nIn))); // factor 2.0 for ReLU
1551 ++itWeight;
1552 }
1553 numInput = layer.numNodes ();
1554 }
1555 return;
1556 }
1557
1558 }
1559
1560
1561
1562
1563
1564/*! \brief compute the error function
1565 *
1566 *
1567 */
1568 template <typename Container, typename ItWeight>
1573 double patternWeight,
1574 double factorWeightDecay,
1576 {
1577 double error (0);
1578 switch (m_eErrorFunction)
1579 {
1581 {
1582 error = sumOfSquares (layerData.valuesBegin (), layerData.valuesEnd (), begin (truth), end (truth),
1583 layerData.deltasBegin (), layerData.deltasEnd (),
1584 layerData.inverseActivationFunction (),
1586 break;
1587 }
1589 {
1591 std::vector<double> probabilities = layerData.probabilities ();
1592 error = crossEntropy (begin (probabilities), end (probabilities),
1593 begin (truth), end (truth),
1594 layerData.deltasBegin (), layerData.deltasEnd (),
1595 layerData.inverseActivationFunction (),
1597 break;
1598 }
1600 {
1601 std::cout << "softmax." << std::endl;
1603 std::vector<double> probabilities = layerData.probabilities ();
1604 error = softMaxCrossEntropy (begin (probabilities), end (probabilities),
1605 begin (truth), end (truth),
1606 layerData.deltasBegin (), layerData.deltasEnd (),
1607 layerData.inverseActivationFunction (),
1609 break;
1610 }
1611 }
1612 if (factorWeightDecay != 0 && eRegularization != EnumRegularization::NONE)
1613 {
1614 error = weightDecay (error, itWeight, itWeightEnd, factorWeightDecay, eRegularization);
1615 }
1616 return error;
1617 }
1618
1619
1620
1621
1622
1623
1624
1625// /*! \brief pre-training
1626// *
1627// * in development
1628// */
1629// template <typename Minimizer>
1630// void Net::preTrain (std::vector<double>& weights,
1631// std::vector<Pattern>& trainPattern,
1632// const std::vector<Pattern>& testPattern,
1633// Minimizer& minimizer, Settings& settings)
1634// {
1635// auto itWeightGeneral = std::begin (weights);
1636// std::vector<Pattern> prePatternTrain (trainPattern.size ());
1637// std::vector<Pattern> prePatternTest (testPattern.size ());
1638
1639// size_t _inputSize = inputSize ();
1640
1641// // transform pattern using the created preNet
1642// auto initializePrePattern = [&](const std::vector<Pattern>& pttrnInput, std::vector<Pattern>& pttrnOutput)
1643// {
1644// pttrnOutput.clear ();
1645// std::transform (std::begin (pttrnInput), std::end (pttrnInput),
1646// std::back_inserter (pttrnOutput),
1647// [](const Pattern& p)
1648// {
1649// Pattern pat (p.input (), p.input (), p.weight ());
1650// return pat;
1651// });
1652// };
1653
1654// initializePrePattern (trainPattern, prePatternTrain);
1655// initializePrePattern (testPattern, prePatternTest);
1656
1657// std::vector<double> originalDropFractions = settings.dropFractions ();
1658
1659// for (auto& _layer : layers ())
1660// {
1661// // compute number of weights (as a function of the number of incoming nodes)
1662// // fetch number of nodes
1663// size_t numNodes = _layer.numNodes ();
1664// size_t _numWeights = _layer.numWeights (_inputSize);
1665
1666// // ------------------
1667// DNN::Net preNet;
1668// if (!originalDropFractions.empty ())
1669// {
1670// originalDropFractions.erase (originalDropFractions.begin ());
1671// settings.setDropOut (originalDropFractions.begin (), originalDropFractions.end (), settings.dropRepetitions ());
1672// }
1673// std::vector<double> preWeights;
1674
1675// // define the preNet (pretraining-net) for this layer
1676// // outputSize == inputSize, because this is an autoencoder;
1677// preNet.setInputSize (_inputSize);
1678// preNet.addLayer (DNN::Layer (numNodes, _layer.activationFunctionType ()));
1679// preNet.addLayer (DNN::Layer (_inputSize, DNN::EnumFunction::LINEAR, DNN::ModeOutputValues::DIRECT));
1680// preNet.setErrorFunction (DNN::ModeErrorFunction::SUMOFSQUARES);
1681// preNet.setOutputSize (_inputSize); // outputSize is the inputSize (autoencoder)
1682
1683// // initialize weights
1684// preNet.initializeWeights (DNN::WeightInitializationStrategy::XAVIERUNIFORM,
1685// std::back_inserter (preWeights));
1686
1687// // overwrite already existing weights from the "general" weights
1688// std::copy (itWeightGeneral, itWeightGeneral+_numWeights, preWeights.begin ());
1689// std::copy (itWeightGeneral, itWeightGeneral+_numWeights, preWeights.begin ()+_numWeights); // set identical weights for the temporary output layer
1690
1691
1692// // train the "preNet"
1693// preNet.train (preWeights, prePatternTrain, prePatternTest, minimizer, settings);
1694
1695// // fetch the pre-trained weights (without the output part of the autoencoder)
1696// std::copy (std::begin (preWeights), std::begin (preWeights) + _numWeights, itWeightGeneral);
1697
1698// // advance the iterator on the incoming weights
1699// itWeightGeneral += _numWeights;
1700
1701// // remove the weights of the output layer of the preNet
1702// preWeights.erase (preWeights.begin () + _numWeights, preWeights.end ());
1703
1704// // remove the outputLayer of the preNet
1705// preNet.removeLayer ();
1706
1707// // set the output size to the number of nodes in the new output layer (== last hidden layer)
1708// preNet.setOutputSize (numNodes);
1709
1710// // transform pattern using the created preNet
1711// auto proceedPattern = [&](std::vector<Pattern>& pttrn)
1712// {
1713// std::vector<Pattern> newPttrn;
1714// std::for_each (std::begin (pttrn), std::end (pttrn),
1715// [&preNet,&preWeights,&newPttrn](Pattern& p)
1716// {
1717// std::vector<double> output = preNet.compute (p.input (), preWeights);
1718// Pattern pat (output, output, p.weight ());
1719// newPttrn.push_back (pat);
1720// // p = pat;
1721// });
1722// return newPttrn;
1723// };
1724
1725
1726// prePatternTrain = proceedPattern (prePatternTrain);
1727// prePatternTest = proceedPattern (prePatternTest);
1728
1729
1730// // the new input size is the output size of the already reduced preNet
1731// _inputSize = preNet.layers ().back ().numNodes ();
1732// }
1733// }
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750 } // namespace DNN
1751} // namespace TMVA
1752
1753#endif
#define f(i)
Definition RSha256.hxx:104
#define g(i)
Definition RSha256.hxx:105
@ kMagenta
Definition Rtypes.h:67
@ kBlue
Definition Rtypes.h:67
ROOT::Detail::TRangeCast< T, true > TRangeDynCast
TRangeDynCast is an adapter class that allows the typed iteration through a TCollection.
winID h TVirtualViewer3D TVirtualGLPainter p
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void input
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t result
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void value
#define MATH_UNUSED(var)
Definition Util.h:35
std::vector< double >::const_iterator const_iterator
Definition Pattern.h:13
const_iterator begin() const
const_iterator end() const
The Batch class encapsulates one mini-batch.
Definition NeuralNet.h:233
LayerData holds the data of one layer.
Definition NeuralNet.h:435
DropContainer::const_iterator const_dropout_iterator
Definition NeuralNet.h:446
void forwardBatch(const LayerContainer &_layers, LayerPatternContainer &layerPatternData, std::vector< double > &valuesMean, std::vector< double > &valuesStdDev, size_t trainFromLayer) const
std::vector< Layer > m_layers
layer-structure-data
Definition NeuralNet.h:1270
std::vector< double > compute(const std::vector< double > &input, const Weights &weights) const
compute the net with the given input and the given weights
void fetchOutput(const LayerData &lastLayerData, OutputContainer &outputContainer) const
size_t inputSize() const
input size of the DNN
Definition NeuralNet.h:1096
ModeErrorFunction m_eErrorFunction
denotes the error function
Definition NeuralNet.h:1267
double train(std::vector< double > &weights, std::vector< Pattern > &trainPattern, const std::vector< Pattern > &testPattern, Minimizer &minimizer, Settings &settings)
start the training
const std::vector< Layer > & layers() const
returns the layers (structure)
Definition NeuralNet.h:1243
std::vector< std::vector< LayerData > > prepareLayerData(LayerContainer &layers, Batch &batch, const DropContainer &dropContainer, ItWeight itWeightBegin, ItWeight itWeightEnd, ItGradient itGradientBegin, ItGradient itGradientEnd, size_t &totalNumWeights) const
void initializeWeights(WeightInitializationStrategy eInitStrategy, OutIterator itWeight)
initialize the weights with the given strategy
size_t outputSize() const
output size of the DNN
Definition NeuralNet.h:1097
double errorFunction(LayerData &layerData, Container truth, ItWeight itWeight, ItWeight itWeightEnd, double patternWeight, double factorWeightDecay, EnumRegularization eRegularization) const
computes the error of the DNN
double forward_backward(LayerContainer &layers, PassThrough &settingsAndBatch, ItWeight itWeightBegin, ItWeight itWeightEnd, ItGradient itGradientBegin, ItGradient itGradientEnd, size_t trainFromLayer, OutContainer &outputContainer, bool fetchOutput) const
main NN computation function
double trainCycle(Minimizer &minimizer, std::vector< double > &weights, Iterator itPatternBegin, Iterator itPatternEnd, Settings &settings, DropContainer &dropContainer)
executes one training cycle
double operator()(PassThrough &settingsAndBatch, const Weights &weights) const
execute computation of the DNN for one mini-batch (used by the minimizer); no computation of gradient...
void dropOutWeightFactor(WeightsType &weights, const DropProbabilities &drops, bool inverse=false)
set the drop out configuration
void fillDropContainer(DropContainer &dropContainer, double dropFraction, size_t numNodes) const
prepare the drop-out-container (select the nodes which are to be dropped out)
size_t numWeights(size_t trainingStartLayer=0) const
returns the number of weights in this net
std::tuple< double, double > computeError(const Settings &settings, std::vector< LayerData > &lastLayerData, Batch &batch, ItWeight itWeightBegin, ItWeight itWeightEnd) const
void forwardPattern(const LayerContainer &_layers, std::vector< LayerData > &layerData) const
void backPropagate(std::vector< std::vector< LayerData > > &layerPatternData, const Settings &settings, size_t trainFromLayer, size_t totalNumWeights) const
Settings for the training of the neural net.
Definition NeuralNet.h:728
double m_beta
internal parameter (momentum)
Definition NeuralNet.h:370
std::vector< double > m_localGradients
local gradients for reuse in thread.
Definition NeuralNet.h:374
std::vector< double > m_prevGradients
vector remembers the gradients of the previous step
Definition NeuralNet.h:371
double m_alpha
internal parameter (learningRate)
Definition NeuralNet.h:369
std::vector< double > m_localWeights
local weights for reuse in thread.
Definition NeuralNet.h:373
double operator()(Function &fitnessFunction, Weights &weights, PassThrough &passThrough)
operator to call the steepest gradient descent algorithm
Basic string class.
Definition TString.h:138
static TString Format(const char *fmt,...)
Static method which formats a string using a printf style format descriptor and return a TString.
Definition TString.cxx:2459
const Int_t n
Definition legend1.C:16
std::shared_ptr< std::function< double(double)> > InvGauss
Definition NeuralNet.cxx:14
double sumOfSquares(ItOutput itOutputBegin, ItOutput itOutputEnd, ItTruth itTruthBegin, ItTruth itTruthEnd, ItDelta itDelta, ItDelta itDeltaEnd, ItInvActFnc itInvActFnc, double patternWeight)
double uniformDouble(double minValue, double maxValue)
Definition NeuralNet.cxx:43
std::shared_ptr< std::function< double(double)> > SymmReLU
Definition NeuralNet.cxx:30
std::shared_ptr< std::function< double(double)> > TanhShift
Definition NeuralNet.cxx:31
std::shared_ptr< std::function< double(double)> > Tanh
Definition NeuralNet.cxx:29
std::shared_ptr< std::function< double(double)> > InvSigmoid
Definition NeuralNet.cxx:18
void forward(const LAYERDATA &prevLayerData, LAYERDATA &currLayerData)
apply the weights (and functions) in forward direction of the DNN
void applyFunctions(ItValue itValue, ItValue itValueEnd, ItFunction itFunction)
T uniformFromTo(T from, T to)
Definition NeuralNet.icc:34
double computeRegularization< EnumRegularization::L1 >(double weight, const double &factorWeightDecay)
std::shared_ptr< std::function< double(double)> > SoftPlus
Definition NeuralNet.cxx:27
double crossEntropy(ItProbability itProbabilityBegin, ItProbability itProbabilityEnd, ItTruth itTruthBegin, ItTruth itTruthEnd, ItDelta itDelta, ItDelta itDeltaEnd, ItInvActFnc itInvActFnc, double patternWeight)
cross entropy error function
void backward(LAYERDATA &prevLayerData, LAYERDATA &currLayerData)
backward application of the weights (back-propagation of the error)
std::shared_ptr< std::function< double(double)> > ZeroFnc
Definition NeuralNet.cxx:28
double weightDecay(double error, ItWeight itWeight, ItWeight itWeightEnd, double factorWeightDecay, EnumRegularization eRegularization)
compute the weight decay for regularization (L1 or L2)
std::shared_ptr< std::function< double(double)> > InvSoftSign
Definition NeuralNet.cxx:20
std::shared_ptr< std::function< double(double)> > InvGaussComplement
Definition NeuralNet.cxx:15
double computeRegularization< EnumRegularization::L2 >(double weight, const double &factorWeightDecay)
auto regularization(const typename Architecture_t::Matrix_t &A, ERegularization R) -> decltype(Architecture_t::L1Regularization(A))
Evaluate the regularization functional for a given weight matrix.
Definition Functions.h:238
double softMaxCrossEntropy(ItOutput itProbabilityBegin, ItOutput itProbabilityEnd, ItTruth itTruthBegin, ItTruth itTruthEnd, ItDelta itDelta, ItDelta itDeltaEnd, ItInvActFnc itInvActFnc, double patternWeight)
soft-max-cross-entropy error function (for mutual exclusive cross-entropy)
std::shared_ptr< std::function< double(double)> > InvTanh
Definition NeuralNet.cxx:22
std::shared_ptr< std::function< double(double)> > Linear
Definition NeuralNet.cxx:24
WeightInitializationStrategy
weight initialization strategies to be chosen from
Definition NeuralNet.h:1048
std::shared_ptr< std::function< double(double)> > InvReLU
Definition NeuralNet.cxx:17
std::shared_ptr< std::function< double(double)> > GaussComplement
Definition NeuralNet.cxx:13
std::shared_ptr< std::function< double(double)> > Gauss
Definition NeuralNet.cxx:12
std::shared_ptr< std::function< double(double)> > Sigmoid
Definition NeuralNet.cxx:26
double gaussDouble(double mean, double sigma)
Definition NeuralNet.cxx:35
std::shared_ptr< std::function< double(double)> > SoftSign
Definition NeuralNet.cxx:32
std::shared_ptr< std::function< double(double)> > InvSoftPlus
Definition NeuralNet.cxx:19
std::shared_ptr< std::function< double(double)> > ReLU
Definition NeuralNet.cxx:25
double computeRegularization(double weight, const double &factorWeightDecay)
compute the regularization (L1, L2)
void applyWeights(ItSource itSourceBegin, ItSource itSourceEnd, ItWeight itWeight, ItTarget itTargetBegin, ItTarget itTargetEnd)
std::tuple< Settings &, Batch &, DropContainer & > pass_through_type
Definition NeuralNet.h:1276
bool isFlagSet(T flag, T value)
Definition NeuralNet.h:210
std::shared_ptr< std::function< double(double)> > InvTanhShift
Definition NeuralNet.cxx:23
void update(ItSource itSource, ItSource itSourceEnd, ItDelta itTargetDeltaBegin, ItDelta itTargetDeltaEnd, ItTargetGradient itTargetGradientBegin, ItGradient itGradient)
update the gradients
std::vector< char > DropContainer
Definition NeuralNet.h:225
void applyWeightsBackwards(ItSource itCurrBegin, ItSource itCurrEnd, ItWeight itWeight, ItPrev itPrevBegin, ItPrev itPrevEnd)
std::shared_ptr< std::function< double(double)> > InvSymmReLU
Definition NeuralNet.cxx:21
std::shared_ptr< std::function< double(double)> > InvLinear
Definition NeuralNet.cxx:16
create variable transformations