mirror of
https://github.com/opencv/opencv.git
synced 2025-07-20 19:17:36 +08:00
Merge pull request #10398 from alalek:ml_simplify_simulated_annealing
This commit is contained in:
commit
eba176c299
@ -1912,75 +1912,49 @@ public:
|
|||||||
* Simulated annealing solver *
|
* Simulated annealing solver *
|
||||||
\****************************************************************************************/
|
\****************************************************************************************/
|
||||||
|
|
||||||
/** @brief The class defines interface for system state used in simulated annealing optimization algorithm.
|
#ifdef CV_DOXYGEN
|
||||||
|
/** @brief This class declares example interface for system state used in simulated annealing optimization algorithm.
|
||||||
|
|
||||||
@cite Kirkpatrick83 for details
|
@note This class is not defined in C++ code and can't be use directly - you need your own implementation with the same methods.
|
||||||
*/
|
*/
|
||||||
class CV_EXPORTS SimulatedAnnealingSolverSystem
|
struct SimulatedAnnealingSolverSystem
|
||||||
{
|
{
|
||||||
protected:
|
|
||||||
inline SimulatedAnnealingSolverSystem() {}
|
|
||||||
public:
|
|
||||||
virtual ~SimulatedAnnealingSolverSystem() {}
|
|
||||||
|
|
||||||
/** Give energy value for a state of system.*/
|
/** Give energy value for a state of system.*/
|
||||||
virtual double energy() const = 0;
|
double energy() const;
|
||||||
/** Function which change the state of system (random pertubation).*/
|
/** Function which change the state of system (random pertubation).*/
|
||||||
virtual void changeState() = 0;
|
void changeState();
|
||||||
/** Function to reverse to the previous state. Can be called once only after changeState(). */
|
/** Function to reverse to the previous state. Can be called once only after changeState(). */
|
||||||
virtual void reverseState() = 0;
|
void reverseState();
|
||||||
};
|
};
|
||||||
|
#endif // CV_DOXYGEN
|
||||||
|
|
||||||
/** @brief The class implements simulated annealing for optimization.
|
/** @brief The class implements simulated annealing for optimization.
|
||||||
*
|
|
||||||
@cite Kirkpatrick83 for details
|
@cite Kirkpatrick83 for details
|
||||||
|
|
||||||
|
@param solverSystem optimization system (see SimulatedAnnealingSolverSystem)
|
||||||
|
@param initialTemperature initial temperature
|
||||||
|
@param finalTemperature final temperature
|
||||||
|
@param coolingRatio temperature step multiplies
|
||||||
|
@param iterationsPerStep number of iterations per temperature changing step
|
||||||
|
@param lastTemperature optional output for last used temperature
|
||||||
|
@param rngEnergy specify custom random numbers generator (cv::theRNG() by default)
|
||||||
*/
|
*/
|
||||||
class CV_EXPORTS SimulatedAnnealingSolver : public Algorithm
|
template<class SimulatedAnnealingSolverSystem>
|
||||||
{
|
int simulatedAnnealingSolver(SimulatedAnnealingSolverSystem& solverSystem,
|
||||||
public:
|
double initialTemperature, double finalTemperature, double coolingRatio,
|
||||||
SimulatedAnnealingSolver(const Ptr<SimulatedAnnealingSolverSystem>& system);
|
size_t iterationsPerStep,
|
||||||
inline ~SimulatedAnnealingSolver() { release(); }
|
CV_OUT double* lastTemperature = NULL,
|
||||||
|
cv::RNG& rngEnergy = cv::theRNG()
|
||||||
/** Simulated annealing procedure. */
|
);
|
||||||
int run();
|
|
||||||
/** Set/initialize RNG (energy).
|
|
||||||
@param rng new RNG
|
|
||||||
*/
|
|
||||||
void setEnergyRNG(const RNG& rng);
|
|
||||||
/** Set initial temperature of simulated annealing procedure.
|
|
||||||
@param x new initial temperature. x\>0
|
|
||||||
*/
|
|
||||||
void setInitialTemperature(double x);
|
|
||||||
/** Set final temperature of simulated annealing procedure.
|
|
||||||
@param x new final temperature value. 0\<x\<initial temperature
|
|
||||||
*/
|
|
||||||
void setFinalTemperature(double x);
|
|
||||||
/** Get final temperature of simulated annealing procedure. */
|
|
||||||
double getFinalTemperature();
|
|
||||||
/** Set setCoolingRatio of simulated annealing procedure : T(t) = coolingRatio * T(t-1).
|
|
||||||
@param x new cooling ratio value. 0\<x\<1
|
|
||||||
*/
|
|
||||||
void setCoolingRatio(double x);
|
|
||||||
/** Set number iteration per temperature step.
|
|
||||||
@param ite number of iteration per temperature step ite \> 0
|
|
||||||
*/
|
|
||||||
void setIterPerStep(int ite);
|
|
||||||
|
|
||||||
void release();
|
|
||||||
SimulatedAnnealingSolver(const SimulatedAnnealingSolver&);
|
|
||||||
SimulatedAnnealingSolver& operator=(const SimulatedAnnealingSolver&);
|
|
||||||
|
|
||||||
struct Impl; friend struct Impl;
|
|
||||||
protected:
|
|
||||||
Impl* impl;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
//! @} ml
|
//! @} ml
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#include <opencv2/ml/ml.inl.hpp>
|
||||||
|
|
||||||
#endif // __cplusplus
|
#endif // __cplusplus
|
||||||
#endif // OPENCV_ML_HPP
|
#endif // OPENCV_ML_HPP
|
||||||
|
|
||||||
|
60
modules/ml/include/opencv2/ml/ml.inl.hpp
Normal file
60
modules/ml/include/opencv2/ml/ml.inl.hpp
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
// This file is part of OpenCV project.
|
||||||
|
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||||
|
// of this distribution and at http://opencv.org/license.html.
|
||||||
|
|
||||||
|
#ifndef OPENCV_ML_INL_HPP
|
||||||
|
#define OPENCV_ML_INL_HPP
|
||||||
|
|
||||||
|
namespace cv { namespace ml {
|
||||||
|
|
||||||
|
// declared in ml.hpp
|
||||||
|
template<class SimulatedAnnealingSolverSystem>
|
||||||
|
int simulatedAnnealingSolver(SimulatedAnnealingSolverSystem& solverSystem,
|
||||||
|
double initialTemperature, double finalTemperature, double coolingRatio,
|
||||||
|
size_t iterationsPerStep,
|
||||||
|
CV_OUT double* lastTemperature,
|
||||||
|
cv::RNG& rngEnergy
|
||||||
|
)
|
||||||
|
{
|
||||||
|
CV_Assert(finalTemperature > 0);
|
||||||
|
CV_Assert(initialTemperature > finalTemperature);
|
||||||
|
CV_Assert(iterationsPerStep > 0);
|
||||||
|
CV_Assert(coolingRatio < 1.0f);
|
||||||
|
double Ti = initialTemperature;
|
||||||
|
double previousEnergy = solverSystem.energy();
|
||||||
|
int exchange = 0;
|
||||||
|
while (Ti > finalTemperature)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < iterationsPerStep; i++)
|
||||||
|
{
|
||||||
|
solverSystem.changeState();
|
||||||
|
double newEnergy = solverSystem.energy();
|
||||||
|
if (newEnergy < previousEnergy)
|
||||||
|
{
|
||||||
|
previousEnergy = newEnergy;
|
||||||
|
exchange++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
double r = rngEnergy.uniform(0.0, 1.0);
|
||||||
|
if (r < std::exp(-(newEnergy - previousEnergy) / Ti))
|
||||||
|
{
|
||||||
|
previousEnergy = newEnergy;
|
||||||
|
exchange++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
solverSystem.reverseState();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ti *= coolingRatio;
|
||||||
|
}
|
||||||
|
if (lastTemperature)
|
||||||
|
*lastTemperature = Ti;
|
||||||
|
return exchange;
|
||||||
|
}
|
||||||
|
|
||||||
|
}} //namespace
|
||||||
|
|
||||||
|
#endif // OPENCV_ML_INL_HPP
|
@ -42,41 +42,6 @@
|
|||||||
|
|
||||||
namespace cv { namespace ml {
|
namespace cv { namespace ml {
|
||||||
|
|
||||||
struct SimulatedAnnealingSolver::Impl
|
|
||||||
{
|
|
||||||
int refcount;
|
|
||||||
|
|
||||||
const Ptr<SimulatedAnnealingSolverSystem> systemPtr;
|
|
||||||
SimulatedAnnealingSolverSystem& system;
|
|
||||||
RNG rEnergy;
|
|
||||||
double coolingRatio;
|
|
||||||
double initialT;
|
|
||||||
double finalT;
|
|
||||||
int iterPerStep;
|
|
||||||
|
|
||||||
Impl(const Ptr<SimulatedAnnealingSolverSystem>& s) :
|
|
||||||
refcount(1),
|
|
||||||
systemPtr(s),
|
|
||||||
system(*(s.get())),
|
|
||||||
rEnergy(12345)
|
|
||||||
{
|
|
||||||
CV_Assert(!systemPtr.empty());
|
|
||||||
initialT = 2;
|
|
||||||
finalT = 0.1;
|
|
||||||
coolingRatio = 0.95;
|
|
||||||
iterPerStep = 100;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline double energy() { return system.energy(); }
|
|
||||||
inline void changeState() { system.changeState(); }
|
|
||||||
inline void reverseState() { system.reverseState(); }
|
|
||||||
|
|
||||||
void addref() { CV_XADD(&refcount, 1); }
|
|
||||||
void release() { if (CV_XADD(&refcount, -1) == 1) delete this; }
|
|
||||||
protected:
|
|
||||||
virtual ~Impl() { CV_Assert(refcount==0); }
|
|
||||||
};
|
|
||||||
|
|
||||||
struct AnnParams
|
struct AnnParams
|
||||||
{
|
{
|
||||||
AnnParams()
|
AnnParams()
|
||||||
@ -115,103 +80,7 @@ inline T inBounds(T val, T min_val, T max_val)
|
|||||||
return std::min(std::max(val, min_val), max_val);
|
return std::min(std::max(val, min_val), max_val);
|
||||||
}
|
}
|
||||||
|
|
||||||
SimulatedAnnealingSolver::SimulatedAnnealingSolver(const Ptr<SimulatedAnnealingSolverSystem>& system)
|
class SimulatedAnnealingANN_MLP
|
||||||
{
|
|
||||||
impl = new Impl(system);
|
|
||||||
}
|
|
||||||
|
|
||||||
SimulatedAnnealingSolver::SimulatedAnnealingSolver(const SimulatedAnnealingSolver& b)
|
|
||||||
{
|
|
||||||
if (b.impl) b.impl->addref();
|
|
||||||
release();
|
|
||||||
impl = b.impl;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SimulatedAnnealingSolver::release()
|
|
||||||
{
|
|
||||||
if (impl) { impl->release(); impl = NULL; }
|
|
||||||
}
|
|
||||||
|
|
||||||
void SimulatedAnnealingSolver::setIterPerStep(int ite)
|
|
||||||
{
|
|
||||||
CV_Assert(impl);
|
|
||||||
CV_Assert(ite>0);
|
|
||||||
impl->iterPerStep = ite;
|
|
||||||
}
|
|
||||||
|
|
||||||
int SimulatedAnnealingSolver::run()
|
|
||||||
{
|
|
||||||
CV_Assert(impl);
|
|
||||||
CV_Assert(impl->initialT>impl->finalT);
|
|
||||||
double Ti = impl->initialT;
|
|
||||||
double previousEnergy = impl->energy();
|
|
||||||
int exchange = 0;
|
|
||||||
while (Ti > impl->finalT)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < impl->iterPerStep; i++)
|
|
||||||
{
|
|
||||||
impl->changeState();
|
|
||||||
double newEnergy = impl->energy();
|
|
||||||
if (newEnergy < previousEnergy)
|
|
||||||
{
|
|
||||||
previousEnergy = newEnergy;
|
|
||||||
exchange++;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
double r = impl->rEnergy.uniform(0.0, 1.0);
|
|
||||||
if (r < std::exp(-(newEnergy - previousEnergy) / Ti))
|
|
||||||
{
|
|
||||||
previousEnergy = newEnergy;
|
|
||||||
exchange++;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
impl->reverseState();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
Ti *= impl->coolingRatio;
|
|
||||||
}
|
|
||||||
impl->finalT = Ti;
|
|
||||||
return exchange;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SimulatedAnnealingSolver::setEnergyRNG(const RNG& rng)
|
|
||||||
{
|
|
||||||
CV_Assert(impl);
|
|
||||||
impl->rEnergy = rng;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SimulatedAnnealingSolver::setInitialTemperature(double x)
|
|
||||||
{
|
|
||||||
CV_Assert(impl);
|
|
||||||
CV_Assert(x>0);
|
|
||||||
impl->initialT = x;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SimulatedAnnealingSolver::setFinalTemperature(double x)
|
|
||||||
{
|
|
||||||
CV_Assert(impl);
|
|
||||||
CV_Assert(x>0);
|
|
||||||
impl->finalT = x;
|
|
||||||
}
|
|
||||||
|
|
||||||
double SimulatedAnnealingSolver::getFinalTemperature()
|
|
||||||
{
|
|
||||||
CV_Assert(impl);
|
|
||||||
return impl->finalT;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SimulatedAnnealingSolver::setCoolingRatio(double x)
|
|
||||||
{
|
|
||||||
CV_Assert(impl);
|
|
||||||
CV_Assert(x>0 && x<1);
|
|
||||||
impl->coolingRatio = x;
|
|
||||||
}
|
|
||||||
|
|
||||||
class SimulatedAnnealingANN_MLP : public SimulatedAnnealingSolverSystem
|
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
ml::ANN_MLP& nn;
|
ml::ANN_MLP& nn;
|
||||||
@ -228,7 +97,7 @@ public:
|
|||||||
initVarMap();
|
initVarMap();
|
||||||
}
|
}
|
||||||
~SimulatedAnnealingANN_MLP() {}
|
~SimulatedAnnealingANN_MLP() {}
|
||||||
protected:
|
|
||||||
void changeState()
|
void changeState()
|
||||||
{
|
{
|
||||||
index = rIndex.uniform(0, nbVariables);
|
index = rIndex.uniform(0, nbVariables);
|
||||||
@ -1075,16 +944,11 @@ public:
|
|||||||
}
|
}
|
||||||
int train_anneal(const Ptr<TrainData>& trainData)
|
int train_anneal(const Ptr<TrainData>& trainData)
|
||||||
{
|
{
|
||||||
SimulatedAnnealingSolver t(Ptr<SimulatedAnnealingANN_MLP>(new SimulatedAnnealingANN_MLP(*this, trainData)));
|
SimulatedAnnealingANN_MLP s(*this, trainData);
|
||||||
t.setEnergyRNG(params.rEnergy);
|
|
||||||
t.setFinalTemperature(params.finalT);
|
|
||||||
t.setInitialTemperature(params.initialT);
|
|
||||||
t.setCoolingRatio(params.coolingRatio);
|
|
||||||
t.setIterPerStep(params.itePerStep);
|
|
||||||
trained = true; // Enable call to CalcError
|
trained = true; // Enable call to CalcError
|
||||||
int iter = t.run();
|
int iter = simulatedAnnealingSolver(s, params.initialT, params.finalT, params.coolingRatio, params.itePerStep, NULL, params.rEnergy);
|
||||||
trained =false;
|
trained =false;
|
||||||
return iter;
|
return iter + 1; // ensure that 'train()' call is always successful
|
||||||
}
|
}
|
||||||
|
|
||||||
int train_backprop( const Mat& inputs, const Mat& outputs, const Mat& _sw, TermCriteria termCrit )
|
int train_backprop( const Mat& inputs, const Mat& outputs, const Mat& _sw, TermCriteria termCrit )
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
using namespace cv;
|
using namespace cv;
|
||||||
|
|
||||||
class TravelSalesman : public ml::SimulatedAnnealingSolverSystem
|
class TravelSalesman
|
||||||
{
|
{
|
||||||
private :
|
private :
|
||||||
const std::vector<Point>& posCity;
|
const std::vector<Point>& posCity;
|
||||||
@ -17,11 +17,11 @@ public:
|
|||||||
rng = theRNG();
|
rng = theRNG();
|
||||||
}
|
}
|
||||||
/** Give energy value for a state of system.*/
|
/** Give energy value for a state of system.*/
|
||||||
/*virtual*/ double energy() const;
|
double energy() const;
|
||||||
/** Function which change the state of system (random pertubation).*/
|
/** Function which change the state of system (random pertubation).*/
|
||||||
/*virtual*/ void changeState();
|
void changeState();
|
||||||
/** Function to reverse to the previous state.*/
|
/** Function to reverse to the previous state.*/
|
||||||
/*virtual*/ void reverseState();
|
void reverseState();
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -81,31 +81,24 @@ int main(void)
|
|||||||
posCity[i].y = static_cast<int>(radius*sin(theta)) + center.y;
|
posCity[i].y = static_cast<int>(radius*sin(theta)) + center.y;
|
||||||
next[i]=(i+1)%nbCity;
|
next[i]=(i+1)%nbCity;
|
||||||
}
|
}
|
||||||
Ptr<TravelSalesman> ts_system(new TravelSalesman(posCity, next));
|
TravelSalesman ts_system(posCity, next);
|
||||||
ml::SimulatedAnnealingSolver ts(ts_system);
|
|
||||||
|
|
||||||
ts.setIterPerStep(10000*nbCity);
|
|
||||||
ts.setCoolingRatio(0.99);
|
|
||||||
ts.setInitialTemperature(100);
|
|
||||||
ts.setFinalTemperature(100*0.97);
|
|
||||||
DrawTravelMap(img,posCity,next);
|
DrawTravelMap(img,posCity,next);
|
||||||
imshow("Map",img);
|
imshow("Map",img);
|
||||||
waitKey(10);
|
waitKey(10);
|
||||||
|
double currentTemperature = 100.0;
|
||||||
for (int i = 0, zeroChanges = 0; zeroChanges < 10; i++)
|
for (int i = 0, zeroChanges = 0; zeroChanges < 10; i++)
|
||||||
{
|
{
|
||||||
int changesApplied = ts.run();
|
int changesApplied = ml::simulatedAnnealingSolver(ts_system, currentTemperature, currentTemperature*0.97, 0.99, 10000*nbCity, ¤tTemperature, rng);
|
||||||
img = Mat::zeros(img.size(),CV_8UC3);
|
img.setTo(Scalar::all(0));
|
||||||
DrawTravelMap(img, posCity, next);
|
DrawTravelMap(img, posCity, next);
|
||||||
imshow("Map", img);
|
imshow("Map", img);
|
||||||
int k = waitKey(10);
|
int k = waitKey(10);
|
||||||
double ti=ts.getFinalTemperature();
|
std::cout << "i=" << i << " changesApplied=" << changesApplied << " temp=" << currentTemperature << " result=" << ts_system.energy() << std::endl;
|
||||||
std::cout << "i=" << i << " changesApplied=" << changesApplied << " temp=" << ti << " result=" << ts_system->energy() << std::endl;
|
|
||||||
if (k == 27 || k == 'q' || k == 'Q')
|
if (k == 27 || k == 'q' || k == 'Q')
|
||||||
return 0;
|
return 0;
|
||||||
if (changesApplied == 0)
|
if (changesApplied == 0)
|
||||||
zeroChanges++;
|
zeroChanges++;
|
||||||
ts.setInitialTemperature(ti);
|
|
||||||
ts.setFinalTemperature(ti*0.97);
|
|
||||||
}
|
}
|
||||||
std::cout << "Done" << std::endl;
|
std::cout << "Done" << std::endl;
|
||||||
waitKey(0);
|
waitKey(0);
|
||||||
|
Loading…
Reference in New Issue
Block a user