Orfeo Toolbox  3.16
itkSPSAOptimizer.cxx
Go to the documentation of this file.
1 /*=========================================================================
2 
3  Program: Insight Segmentation & Registration Toolkit
4  Module: $RCSfile: itkSPSAOptimizer.cxx,v $
5  Language: C++
6  Date: $Date: 2009-10-27 16:05:45 $
7  Version: $Revision: 1.16 $
8 
9  Copyright (c) Insight Software Consortium. All rights reserved.
10  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
11 
12  This software is distributed WITHOUT ANY WARRANTY; without even
13  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
14  PURPOSE. See the above copyright notices for more information.
15 
16 =========================================================================*/
17 #ifndef __itkSPSAOptimizer_cxx
18 #define __itkSPSAOptimizer_cxx
19 
20 #include "itkSPSAOptimizer.h"
21 #include "itkCommand.h"
22 #include "itkEventObject.h"
23 #include "itkExceptionObject.h"
24 #include "itkMath.h"
25 
26 #include "itkMath.h"
27 
28 
29 namespace itk
30 {
31 
37 {
38  itkDebugMacro( "Constructor" );
39 
40  m_CurrentIteration = 0;
41  m_Maximize = false;
42  m_StopCondition = Unknown;
43  m_StateOfConvergenceDecayRate = 0.9;
44  m_Tolerance=1e-06;
45  m_StateOfConvergence = 0;
46  m_MaximumNumberOfIterations = 100;
47  m_MinimumNumberOfIterations = 10;
48  m_GradientMagnitude = 0.0;
49  m_NumberOfPerturbations = 1;
50  m_LearningRate = 0.0;
51  m_Sa = 1.0;
52  m_Sc = 1.0;
53  m_A = m_MaximumNumberOfIterations / 10;
54  m_Alpha = 0.602;
55  m_Gamma = 0.101;
57 
58 } // end Constructor
59 
63 void
65 ::PrintSelf( std::ostream& os, Indent indent ) const
66 {
67  Superclass::PrintSelf( os, indent );
68 
69  os << indent << "a: " << m_Sa << std::endl;
70  os << indent << "A: " << m_A << std::endl;
71  os << indent << "Alpha: " << m_Alpha << std::endl;
72  os << indent << "c: " << m_Sc << std::endl;
73  os << indent << "Gamma: " << m_Gamma << std::endl;
74  os << indent << "Tolerance: " << m_Tolerance << std::endl;
75  os << indent << "GradientMagnitude: " << m_GradientMagnitude << std::endl;
76  os << indent << "StateOfConvergenceDecayRate: " << m_StateOfConvergenceDecayRate << std::endl;
77  os << indent << "Gradient: " << m_Gradient << std::endl;
78  os << indent << "StateOfConvergence: " << m_StateOfConvergence << std::endl;
79 
80  os << indent << "NumberOfPerturbations: " << m_NumberOfPerturbations << std::endl;
81 
82  os << indent << "LearningRate: "
83  << m_LearningRate << std::endl;
84 
85  os << indent << "MaximumNumberOfIterations: "
86  << m_MaximumNumberOfIterations << std::endl;
87  os << indent << "MinimumNumberOfIterations: "
88  << m_MinimumNumberOfIterations << std::endl;
89 
90  os << indent << "Maximize: "
91  << m_Maximize << std::endl;
92 
93  os << indent << "CurrentIteration: "
94  << m_CurrentIteration;
95  if ( m_CostFunction )
96  {
97  os << indent << "CostFunction: "
98  << m_CostFunction;
99  }
100  os << indent << "StopCondition: "
101  << m_StopCondition;
102  os << std::endl;
103 
104 } // end PrintSelf
105 
112 ::GetValue( const ParametersType & parameters ) const
113 {
119  return this->Superclass::GetValue( parameters );
120 }
121 
122 
129 ::GetValue( void ) const
130 {
136  return this->GetValue( this->GetCurrentPosition() );
137 }
138 
142 void
145 {
146  itkDebugMacro( "StartOptimization" );
147 
148  if (!m_CostFunction)
149  {
150  itkExceptionMacro(<<"No objective function defined! ");
151  }
152 
154  const unsigned int spaceDimension =
155  m_CostFunction->GetNumberOfParameters();
156  if ( spaceDimension != this->GetInitialPosition().GetSize() )
157  {
158  itkExceptionMacro(<<"Number of parameters not correct!");
159  }
160 
161  m_CurrentIteration = 0;
162  m_StopCondition = Unknown;
163  m_StateOfConvergence = 0.0;
164 
165  this->SetCurrentPosition( this->GetInitialPosition() );
166  this->ResumeOptimization();
167 
168 } // end StartOptimization
169 
170 
175 void
178 {
179  itkDebugMacro( "ResumeOptimization" );
180 
181  m_Stop = false;
182 
183  InvokeEvent( StartEvent() );
184  while( !m_Stop )
185  {
186 
187  AdvanceOneStep();
188  this->InvokeEvent( IterationEvent() );
189 
190  if (m_Stop)
191  {
192  break;
193  }
194 
195  m_CurrentIteration++;
196 
197  if( m_CurrentIteration >= m_MaximumNumberOfIterations )
198  {
199  m_StopCondition = MaximumNumberOfIterations;
200  StopOptimization();
201  break;
202  }
203 
205  if ( (m_StateOfConvergence < m_Tolerance)
206  && (m_CurrentIteration >= m_MinimumNumberOfIterations) )
207  {
208  m_StopCondition = BelowTolerance;
209  StopOptimization();
210  break;
211  }
212  m_StateOfConvergence *= m_StateOfConvergenceDecayRate;
213  } // while !m_stop
214 } // end ResumeOptimization
215 
216 
220 void
223 {
224  itkDebugMacro( "StopOptimization" );
225  m_Stop = true;
226  InvokeEvent( EndEvent() );
227 } // end StopOptimization
228 
229 
233 void
236 {
237  itkDebugMacro( "AdvanceOneStep" );
238 
240  double direction;
241  if( this->m_Maximize )
242  {
243  direction = 1.0;
244  }
245  else
246  {
247  direction = -1.0;
248  }
249 
251  const unsigned int spaceDimension =
252  m_CostFunction->GetNumberOfParameters();
253 
256  ParametersType newPosition( spaceDimension );
257  const ParametersType & currentPosition = this->GetCurrentPosition();
258 
262  try
263  {
264  this->ComputeGradient(currentPosition, m_Gradient);
265  }
266  catch( ExceptionObject& err )
267  {
268  // An exception has occurred.
269  // Terminate immediately.
270  m_StopCondition = MetricError;
271  StopOptimization();
272  // Pass exception to caller
273  throw err;
274  }
275 
277  const double ak = this->Compute_a( m_CurrentIteration );
279  m_LearningRate = ak;
280 
284  newPosition = currentPosition + (direction * ak) * m_Gradient;
285  this->SetCurrentPosition( newPosition );
286 
288  m_GradientMagnitude = m_Gradient.magnitude();
289 
291  m_StateOfConvergence += ak * m_GradientMagnitude;
292 
293 } // end AdvanceOneStep
294 
302 double SPSAOptimizer
303 ::Compute_a( unsigned long k ) const
304 {
305  return static_cast<double>(
306  m_Sa / vcl_pow( m_A + k + 1, m_Alpha ) );
307 
308 } // end Compute_a
309 
317 double SPSAOptimizer
318 ::Compute_c( unsigned long k ) const
319 {
320  return static_cast<double>(
321  m_Sc / vcl_pow( k + 1, m_Gamma ) );
322 
323 } // end Compute_c
324 
333 void SPSAOptimizer
334 ::GenerateDelta( const unsigned int spaceDimension )
335 {
336  m_Delta = DerivativeType( spaceDimension );
337 
338  const ScalesType & scales = this->GetScales();
339 
340  // Make sure the scales have been set properly
341  if (scales.size() != spaceDimension)
342  {
343  itkExceptionMacro(<< "The size of Scales is "
344  << scales.size()
345  << ", but the NumberOfParameters for the CostFunction is "
346  << spaceDimension
347  << ".");
348  }
349 
350  for ( unsigned int j = 0; j < spaceDimension; j++ )
351  {
353  m_Delta[ j ] = 2 * Math::Round<int>( this->m_Generator->GetUniformVariate (0.0f, 1.0f) ) - 1;
354 
360  m_Delta[j] /= scales[j];
361  }
362 
363 } // end GenerateDelta
364 
368 void
371  const ParametersType & parameters,
372  DerivativeType & gradient)
373 {
374 
375  const unsigned int spaceDimension = parameters.GetSize();
376 
378  const double ck = this->Compute_c( m_CurrentIteration );
379 
383  ParametersType thetaplus( spaceDimension );
384  ParametersType thetamin( spaceDimension );
385  gradient = DerivativeType( spaceDimension );
386  gradient.Fill(0.0);
387  const ScalesType & scales = this->GetScales();
388 
392  for (unsigned long perturbation = 1;
393  perturbation <= this->GetNumberOfPerturbations();
394  ++perturbation)
395  {
397  this->GenerateDelta( spaceDimension );
398 
400  for ( unsigned int j = 0; j < spaceDimension; j++ )
401  {
402  thetaplus[j] = parameters[ j ] + ck * m_Delta[ j ];
403  thetamin[j] = parameters[ j ] - ck * m_Delta[ j ];
404  }
405 
407  const double valueplus = this->GetValue( thetaplus );
408 
410  const double valuemin = this->GetValue( thetamin );
411 
413  const double valuediff = ( valueplus - valuemin ) / ( 2 * ck );
414  for ( unsigned int j = 0; j < spaceDimension; j++ )
415  {
416  // remember to divide the gradient by the NumberOfPerturbations!
417  gradient[ j ] += valuediff / m_Delta[j];
418  }
419  } //end for ++perturbation
420 
422  for ( unsigned int j = 0; j < spaceDimension; j++ )
423  {
424  gradient[j] /= ( vnl_math_sqr(scales[j]) * static_cast<double>(m_NumberOfPerturbations) );
425  }
466 } //end ComputeGradient
467 
468 
472 void
475  unsigned long numberOfGradientEstimates,
476  double initialStepSize)
477 {
479  this->SetA( static_cast<double>(this->GetMaximumNumberOfIterations()) / 10.0 );
480 
481  if (!m_CostFunction)
482  {
483  itkExceptionMacro(<<"No objective function defined! ");
484  }
485 
487  const unsigned int spaceDimension =
488  m_CostFunction->GetNumberOfParameters();
489 
491  const ParametersType & initialPosition = this->GetInitialPosition();
492  if ( spaceDimension != initialPosition.GetSize() )
493  {
494  itkExceptionMacro(<<"Number of parameters not correct!");
495  }
496 
498  DerivativeType averageAbsoluteGradient(spaceDimension);
499  averageAbsoluteGradient.Fill(0.0);
500  m_CurrentIteration = 0;
501  for (unsigned long n=1; n<= numberOfGradientEstimates; ++n)
502  {
503  this->ComputeGradient(initialPosition, m_Gradient);
504  for ( unsigned int j = 0; j < spaceDimension; j++ )
505  {
506  averageAbsoluteGradient[j] += vcl_fabs(m_Gradient[j]);
507  }
508  } // end for ++n
509  averageAbsoluteGradient /= static_cast<double>(numberOfGradientEstimates);
510 
512  this->SetSa( initialStepSize * vcl_pow(m_A + 1.0, m_Alpha) /
513  averageAbsoluteGradient.max_value() );
514 
515 } //end GuessParameters
516 
517 
518 const std::string
521 {
522  ::itk::OStringStream reason;
523  reason << this->GetNameOfClass() << ": ";
524  switch( m_StopCondition )
525  {
526  case Unknown:
527  reason << "Unknown stop condition";
528  break;
530  reason << "Maximum number of iterations exceeded. Number of iterations is "
532  break;
533  case BelowTolerance:
534  reason << "Below tolerance. " << "Tolerance is " << m_Tolerance;
535  break;
536  case MetricError:
537  reason << "Metric error";
538  break;
539  default:
540  reason << " No reason given for termination ";
541  break;
542  }
543  return reason.str();
544 }
545 
546 } // end namespace itk
547 
548 
549 #endif // end #ifndef __itkSPSAOptimizer_cxx

Generated at Sun Feb 3 2013 00:08:31 for Orfeo Toolbox with doxygen 1.8.1.1