/** @copybrief getAnnealItePerStep @see getAnnealItePerStep */
CV_WRAP void setAnnealItePerStep(int val);
+ /** @brief Set/initialize anneal RNG */
+ void setAnnealEnergyRNG(const RNG& rng);
+
/** possible activation functions */
enum ActivationFunctions {
/** Identity function: \f$f(x)=x\f$ */
{
public:
/** @see setAnnealInitialT */
- CV_WRAP virtual double getAnnealInitialT() const;
+ CV_WRAP virtual double getAnnealInitialT() const = 0;
/** @copybrief getAnnealInitialT @see getAnnealInitialT */
- CV_WRAP virtual void setAnnealInitialT(double val);
+ CV_WRAP virtual void setAnnealInitialT(double val) = 0;
/** ANNEAL: Update final temperature.
It must be \>=0 and less than initialT. Default value is 0.1.*/
/** @see setAnnealFinalT */
- CV_WRAP virtual double getAnnealFinalT() const;
+ CV_WRAP virtual double getAnnealFinalT() const = 0;
/** @copybrief getAnnealFinalT @see getAnnealFinalT */
- CV_WRAP virtual void setAnnealFinalT(double val);
+ CV_WRAP virtual void setAnnealFinalT(double val) = 0;
/** ANNEAL: Update cooling ratio.
It must be \>0 and less than 1. Default value is 0.95.*/
/** @see setAnnealCoolingRatio */
- CV_WRAP virtual double getAnnealCoolingRatio() const;
+ CV_WRAP virtual double getAnnealCoolingRatio() const = 0;
/** @copybrief getAnnealCoolingRatio @see getAnnealCoolingRatio */
- CV_WRAP virtual void setAnnealCoolingRatio(double val);
+ CV_WRAP virtual void setAnnealCoolingRatio(double val) = 0;
/** ANNEAL: Update iteration per step.
It must be \>0 . Default value is 10.*/
/** @see setAnnealItePerStep */
- CV_WRAP virtual int getAnnealItePerStep() const;
+ CV_WRAP virtual int getAnnealItePerStep() const = 0;
/** @copybrief getAnnealItePerStep @see getAnnealItePerStep */
- CV_WRAP virtual void setAnnealItePerStep(int val);
-
-
- /** @brief Creates empty model
-
- Use StatModel::train to train the model, Algorithm::load\<ANN_MLP\>(filename) to load the pre-trained model.
- Note that the train method has optional flags: ANN_MLP::TrainFlags.
- */
-// CV_WRAP static Ptr<ANN_MLP> create();
+ CV_WRAP virtual void setAnnealItePerStep(int val) = 0;
+ /** @brief Set/initialize anneal RNG */
+ virtual void setAnnealEnergyRNG(const RNG& rng) = 0;
};
+
/****************************************************************************************\
* Simulated annealing solver *
\****************************************************************************************/
+/** @brief The class defines interface for system state used in simulated annealing optimization algorithm.
+
+@cite Kirkpatrick83 for details
+*/
+class CV_EXPORTS SimulatedAnnealingSolverSystem
+{
+protected:
+ inline SimulatedAnnealingSolverSystem() {}
+public:
+ virtual ~SimulatedAnnealingSolverSystem() {}
+
+ /** Give energy value for a state of system.*/
+ virtual double energy() const = 0;
+ /** Function which change the state of system (random pertubation).*/
+ virtual void changeState() = 0;
+ /** Function to reverse to the previous state. Can be called once only after changeState(). */
+ virtual void reverseState() = 0;
+};
+
/** @brief The class implements simulated annealing for optimization.
+ *
@cite Kirkpatrick83 for details
*/
class CV_EXPORTS SimulatedAnnealingSolver : public Algorithm
{
public:
- SimulatedAnnealingSolver() { init(); }
- ~SimulatedAnnealingSolver();
- /** Give energy value for a state of system.*/
- virtual double energy() =0;
- /** Function which change the state of system (random pertubation).*/
- virtual void changedState() = 0;
- /** Function to reverse to the previous state.*/
- virtual void reverseChangedState() = 0;
- /** Simulated annealing procedure. */
+ SimulatedAnnealingSolver(const Ptr<SimulatedAnnealingSolverSystem>& system);
+ inline ~SimulatedAnnealingSolver() { release(); }
+
+ /** Simulated annealing procedure. */
int run();
- /** Set intial temperature of simulated annealing procedure.
- *@param x new initial temperature. x\>0
+ /** 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
+ @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
+ @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
+ @param ite number of iteration per temperature step ite \> 0
*/
void setIterPerStep(int ite);
-protected:
- void init();
+ void release();
+ SimulatedAnnealingSolver(const SimulatedAnnealingSolver&);
+ SimulatedAnnealingSolver& operator=(const SimulatedAnnealingSolver&);
-private:
- struct Impl;
+ struct Impl; friend struct Impl;
+protected:
Impl* impl;
};
+
+
//! @} ml
}
struct SimulatedAnnealingSolver::Impl
{
+ int refcount;
+
+ const Ptr<SimulatedAnnealingSolverSystem> systemPtr;
+ SimulatedAnnealingSolverSystem& system;
RNG rEnergy;
double coolingRatio;
double initialT;
double finalT;
int iterPerStep;
- Impl()
+
+ 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;
- refcount = 1;
}
- int refcount;
- ~Impl() { refcount--;CV_Assert(refcount==0); }
+
+ 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
rpDW0 = 0.1; rpDWPlus = 1.2; rpDWMinus = 0.5;
rpDWMin = FLT_EPSILON; rpDWMax = 50.;
initialT=10;finalT=0.1,coolingRatio=0.95;itePerStep=10;
-
+ rEnergy = cv::RNG(12345);
}
TermCriteria termCrit;
double finalT;
double coolingRatio;
int itePerStep;
+ RNG rEnergy;
};
template <typename T>
return std::min(std::max(val, min_val), max_val);
}
-SimulatedAnnealingSolver::~SimulatedAnnealingSolver()
+SimulatedAnnealingSolver::SimulatedAnnealingSolver(const Ptr<SimulatedAnnealingSolverSystem>& system)
+{
+ impl = new Impl(system);
+}
+
+SimulatedAnnealingSolver::SimulatedAnnealingSolver(const SimulatedAnnealingSolver& b)
{
- if (impl) delete impl;
+ if (b.impl) b.impl->addref();
+ release();
+ impl = b.impl;
}
-void SimulatedAnnealingSolver::init()
+void SimulatedAnnealingSolver::release()
{
- impl = new SimulatedAnnealingSolver::Impl();
+ 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 = energy();
+ double previousEnergy = impl->energy();
int exchange = 0;
while (Ti > impl->finalT)
{
for (int i = 0; i < impl->iterPerStep; i++)
{
- changedState();
- double newEnergy = energy();
+ impl->changeState();
+ double newEnergy = impl->energy();
if (newEnergy < previousEnergy)
{
previousEnergy = newEnergy;
+ //??? exchange++;
}
else
{
- double r = impl->rEnergy.uniform(double(0.0), double(1.0));
- if (r < exp(-(newEnergy - previousEnergy) / Ti))
+ double r = impl->rEnergy.uniform(0.0, 1.0);
+ if (r < std::exp(-(newEnergy - previousEnergy) / Ti))
{
previousEnergy = newEnergy;
exchange++;
}
else
- reverseChangedState();
+ {
+ impl->reverseState();
+ }
}
}
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 ml::SimulatedAnnealingSolver
+class SimulatedAnnealingANN_MLP : public SimulatedAnnealingSolverSystem
{
-public:
- ml::ANN_MLP *nn;
+protected:
+ ml::ANN_MLP& nn;
Ptr<ml::TrainData> data;
int nbVariables;
vector<double*> adrVariables;
RNG rIndex;
double varTmp;
int index;
-
- SimulatedAnnealingANN_MLP(ml::ANN_MLP *x, Ptr<ml::TrainData> d) : nn(x), data(d)
+public:
+ SimulatedAnnealingANN_MLP(ml::ANN_MLP& x, const Ptr<ml::TrainData>& d) : nn(x), data(d)
{
initVarMap();
}
-
- void changedState()
+ ~SimulatedAnnealingANN_MLP() {}
+protected:
+ void changeState()
{
index = rIndex.uniform(0, nbVariables);
double dv = rVar.uniform(-1.0, 1.0);
*adrVariables[index] = dv;
}
- void reverseChangedState()
+ void reverseState()
{
*adrVariables[index] = varTmp;
}
- double energy() { return nn->calcError(data, false, noArray()); }
+ double energy() const { return nn.calcError(data, false, noArray()); }
protected:
void initVarMap()
{
- Mat l = nn->getLayerSizes();
+ Mat l = nn.getLayerSizes();
nbVariables = 0;
adrVariables.clear();
for (int i = 1; i < l.rows-1; i++)
{
- Mat w = nn->getWeights(i);
+ Mat w = nn.getWeights(i);
for (int j = 0; j < w.rows; j++)
{
for (int k = 0; k < w.cols; k++, nbVariables++)
this_->setAnnealItePerStep(val);
}
+void ANN_MLP::setAnnealEnergyRNG(const RNG& rng)
+{
+ ANN_MLP_ANNEAL* this_ = dynamic_cast<ANN_MLP_ANNEAL*>(this);
+ if (!this_)
+ CV_Error(Error::StsNotImplemented, "the class is not ANN_MLP_ANNEAL");
+ this_->setAnnealEnergyRNG(rng);
+}
class ANN_MLPImpl : public ANN_MLP_ANNEAL
{
CV_IMPL_PROPERTY(double, AnnealCoolingRatio, params.coolingRatio)
CV_IMPL_PROPERTY(int, AnnealItePerStep, params.itePerStep)
+ //CV_IMPL_PROPERTY(RNG, AnnealEnergyRNG, params.rEnergy)
+ inline void setAnnealEnergyRNG(const RNG& val) { params.rEnergy = val; }
+
void clear()
{
min_val = max_val = min_val1 = max_val1 = 0.;
}
int train_anneal(const Ptr<TrainData>& trainData)
{
- SimulatedAnnealingANN_MLP t(this, trainData);
+ SimulatedAnnealingSolver t(Ptr<SimulatedAnnealingANN_MLP>(new SimulatedAnnealingANN_MLP(*this, trainData)));
+ t.setEnergyRNG(params.rEnergy);
t.setFinalTemperature(params.finalT);
t.setInitialTemperature(params.initialT);
t.setCoolingRatio(params.coolingRatio);
return ann;
}
-double ANN_MLP_ANNEAL::getAnnealInitialT() const
-{
- const ANN_MLPImpl* this_ = dynamic_cast<const ANN_MLPImpl*>(this);
- if (!this_)
- CV_Error(Error::StsNotImplemented, "the class is not ANN_MLP_ANNEAL");
- return this_->getAnnealInitialT();
-}
-
-void ANN_MLP_ANNEAL::setAnnealInitialT(double val)
-{
- ANN_MLPImpl* this_ = dynamic_cast< ANN_MLPImpl*>(this);
- if (!this_)
- CV_Error(Error::StsNotImplemented, "the class is not ANN_MLP_ANNEAL");
- this_->setAnnealInitialT(val);
-}
-
-double ANN_MLP_ANNEAL::getAnnealFinalT() const
-{
- const ANN_MLPImpl* this_ = dynamic_cast<const ANN_MLPImpl*>(this);
- if (!this_)
- CV_Error(Error::StsNotImplemented, "the class is not ANN_MLP_ANNEAL");
- return this_->getAnnealFinalT();
-}
-
-void ANN_MLP_ANNEAL::setAnnealFinalT(double val)
-{
- ANN_MLPImpl* this_ = dynamic_cast<ANN_MLPImpl*>(this);
- if (!this_)
- CV_Error(Error::StsNotImplemented, "the class is not ANN_MLP_ANNEAL");
- this_->setAnnealFinalT(val);
-}
-
-double ANN_MLP_ANNEAL::getAnnealCoolingRatio() const
-{
- const ANN_MLPImpl* this_ = dynamic_cast<const ANN_MLPImpl*>(this);
- if (!this_)
- CV_Error(Error::StsNotImplemented, "the class is not ANN_MLP_ANNEAL");
- return this_->getAnnealCoolingRatio();
-}
-
-void ANN_MLP_ANNEAL::setAnnealCoolingRatio(double val)
-{
- ANN_MLPImpl* this_ = dynamic_cast< ANN_MLPImpl*>(this);
- if (!this_)
- CV_Error(Error::StsNotImplemented, "the class is not ANN_MLP_ANNEAL");
- this_->setAnnealInitialT(val);
-}
-
-int ANN_MLP_ANNEAL::getAnnealItePerStep() const
-{
- const ANN_MLPImpl* this_ = dynamic_cast<const ANN_MLPImpl*>(this);
- if (!this_)
- CV_Error(Error::StsNotImplemented, "the class is not ANN_MLP_ANNEAL");
- return this_->getAnnealItePerStep();
-}
-
-void ANN_MLP_ANNEAL::setAnnealItePerStep(int val)
-{
- ANN_MLPImpl* this_ = dynamic_cast<ANN_MLPImpl*>(this);
- if (!this_)
- CV_Error(Error::StsNotImplemented, "the class is not ANN_MLP_ANNEAL");
- this_->setAnnealInitialT(val);
-}
-
}}
/* End of file. */
#include "test_precomp.hpp"
+//#define GENERATE_TESTDATA
+
using namespace cv;
using namespace std;
#endif
}
}
-//#define GENERATE_TESTDATA
+
TEST(ML_ANN, Method)
{
String folder = string(cvtest::TS::ptr()->get_data_path());
methodName.push_back("_anneal");
// methodName.push_back("_backprop"); -----> NO BACKPROP TEST
#ifdef GENERATE_TESTDATA
+ {
Ptr<ml::ANN_MLP> xx = ml::ANN_MLP_ANNEAL::create();
Mat_<int> layerSizesXX(1, 4);
layerSizesXX(0, 0) = tdata->getNVars();
fs.open(dataname + "_init_weight.yml.gz", FileStorage::WRITE + FileStorage::BASE64);
xx->write(fs);
fs.release();
+ }
#endif
for (size_t i = 0; i < methodType.size(); i++)
{
x->setTrainMethod(methodType[i]);
if (methodType[i] == ml::ANN_MLP::ANNEAL)
{
+ x->setAnnealEnergyRNG(RNG(CV_BIG_INT(0xffffffff)));
x->setAnnealInitialT(12);
x->setAnnealFinalT(0.15);
x->setAnnealCoolingRatio(0.96);
#include <opencv2/opencv.hpp>
-using namespace std;
using namespace cv;
-void DrawTravelMap(Mat &img, vector<Point> &p, vector<int> &n);
-
-class TravelSalesman : public ml::SimulatedAnnealingSolver
+class TravelSalesman : public ml::SimulatedAnnealingSolverSystem
{
private :
- vector<Point> &posCity;
- vector<int> &next;
+ const std::vector<Point>& posCity;
+ std::vector<int>& next;
RNG rng;
int d0,d1,d2,d3;
public:
-
- TravelSalesman(vector<Point> &p,vector<int> &n):posCity(p),next(n)
+ TravelSalesman(std::vector<Point> &p, std::vector<int> &n) :
+ posCity(p), next(n)
{
rng = theRNG();
- };
+ }
/** Give energy value for a state of system.*/
- virtual double energy();
+ /*virtual*/ double energy() const;
/** Function which change the state of system (random pertubation).*/
- virtual void changedState();
+ /*virtual*/ void changeState();
/** Function to reverse to the previous state.*/
- virtual void reverseChangedState();
+ /*virtual*/ void reverseState();
};
-void TravelSalesman::changedState()
+void TravelSalesman::changeState()
{
d0 = rng.uniform(0,static_cast<int>(posCity.size()));
d1 = next[d0];
d2 = next[d1];
d3 = next[d2];
- int d0Tmp = d0;
- int d1Tmp = d1;
- int d2Tmp = d2;
- next[d0Tmp] = d2;
- next[d2Tmp] = d1;
- next[d1Tmp] = d3;
+ next[d0] = d2;
+ next[d2] = d1;
+ next[d1] = d3;
}
-void TravelSalesman::reverseChangedState()
+void TravelSalesman::reverseState()
{
next[d0] = d1;
next[d1] = d2;
next[d2] = d3;
}
-double TravelSalesman::energy()
+double TravelSalesman::energy() const
{
- double e=0;
+ double e = 0;
for (size_t i = 0; i < next.size(); i++)
{
- e += norm(posCity[i]-posCity[next[i]]);
+ e += norm(posCity[i]-posCity[next[i]]);
}
return e;
}
-void DrawTravelMap(Mat &img, vector<Point> &p, vector<int> &n)
+static void DrawTravelMap(Mat &img, std::vector<Point> &p, std::vector<int> &n)
{
for (size_t i = 0; i < n.size(); i++)
{
{
int nbCity=40;
Mat img(500,500,CV_8UC3,Scalar::all(0));
- RNG &rng=theRNG();
+ RNG rng(123456);
int radius=static_cast<int>(img.cols*0.45);
Point center(img.cols/2,img.rows/2);
- vector<Point> posCity(nbCity);
- vector<int> next(nbCity);
+ std::vector<Point> posCity(nbCity);
+ std::vector<int> next(nbCity);
for (size_t i = 0; i < posCity.size(); i++)
{
double theta = rng.uniform(0., 2 * CV_PI);
posCity[i].y = static_cast<int>(radius*sin(theta)) + center.y;
next[i]=(i+1)%nbCity;
}
- TravelSalesman ts(posCity,next);
+ Ptr<TravelSalesman> ts_system(new TravelSalesman(posCity, next));
+ ml::SimulatedAnnealingSolver ts(ts_system);
+
+ ts.setIterPerStep(10000*nbCity);
ts.setCoolingRatio(0.99);
ts.setInitialTemperature(100);
- ts.setIterPerStep(10000*nbCity);
ts.setFinalTemperature(100*0.97);
DrawTravelMap(img,posCity,next);
imshow("Map",img);
waitKey(10);
- for (int i = 0; i < 100; i++)
+ for (int i = 0, zeroChanges = 0; zeroChanges < 10; i++)
{
- ts.run();
+ int changesApplied = ts.run();
img = Mat::zeros(img.size(),CV_8UC3);
DrawTravelMap(img, posCity, next);
imshow("Map", img);
- waitKey(10);
+ int k = waitKey(10);
double ti=ts.getFinalTemperature();
- cout<<ti <<" -> "<<ts.energy()<<"\n";
+ std::cout << "i=" << i << " changesApplied=" << changesApplied << " temp=" << ti << " result=" << ts_system->energy() << std::endl;
+ if (k == 27 || k == 'q' || k == 'Q')
+ return 0;
+ if (changesApplied == 0)
+ zeroChanges++;
ts.setInitialTemperature(ti);
ts.setFinalTemperature(ti*0.97);
}
+ std::cout << "Done" << std::endl;
+ waitKey(0);
return 0;
}