performanceTester.cpp
Go to the documentation of this file.
1 
2 #include <ros/package.h>
3 
4 #include <boost/filesystem/path.hpp>
5 #include <boost/date_time/posix_time/posix_time.hpp>
6 
7 #include <ISM/utility/TableHelper.hpp>
8 
11 
12 #include <sys/time.h>
13 #include <string>
14 #include <chrono>
15 #include <vector>
16 #include <string>
17 
18 #include <random>
19 #include <algorithm>
20 
21 using boost::posix_time::ptime;
22 using boost::posix_time::time_duration;
23 using boost::filesystem::path;
24 using namespace ISM;
25 using namespace ProbabilisticSceneRecognition;
26 using namespace boost::posix_time;
27 
28 std::vector<unsigned> objectCounts = {
29  3, 4, 5
30 };
31 
32 std::vector<unsigned> timestepCounts = {
33  100, 200, 300, 400
34 };
35 
36 std::string testSetFolder = "ValidationSets";
37 std::string testSetFolderNoRefs = "TestSetsNoRefs";
38 
39 std::string validTestSetPref = "validValidationSets_";
40 std::string invalidTestSetPref = "invalidValidationSets_";
41 std::string outputPath;
42 
43 std::vector<std::string> testSets;
44 std::vector<std::string> testSetsNoRefs;
45 
46 std::vector<std::string> demoRecordings;
47 std::vector<std::string> demoRecordingsNames;
48 
49 double recognitionThreshold = 1.0e-04;
50 // overwritten in training, used for performance tests:
51 std::string inferenceAlgorithm = "maximum";
52 std::string treeAlgorithm = "fullymeshed";
53 std::string optimizationAlgorithm = "RecordHunt";
54 
55 bool train = false;
56 bool test = !train; // recognition runtime
57 
58 double scale, sigma;
59 std::string frameId;
60 
62 {
63  ros::NodeHandle nh("~");
64 
65  nh.setParam("scene_model_type", "ocm");
66 
67  nh.setParam("workspace_volume", 8.0);
68  nh.setParam("static_break_ratio", 1.01);
69  nh.setParam("together_ratio", 0.90);
70  nh.setParam("intermediate_results", false);
71  nh.setParam("timestamps", false);
72  nh.setParam("kernels_min", 1);
73  nh.setParam("kernels_max", 5);
74  nh.setParam("runs_per_kernel", 3);
75  nh.setParam("synthetic_samples", 10);
76  nh.setParam("interval_position", 0.25);
77  nh.setParam("interval_orientation", 10);
78  nh.setParam("orientation_plot_path", "UNDEFINED");
79  nh.setParam("max_angle_deviation", 45);
80  frameId = "/PTU";
81  nh.setParam("base_frame_id", frameId);
82  scale = 1.0;
83  nh.setParam("scale_factor", scale);
84  sigma = 3.0;
85  nh.setParam("sigma_multiplicator", sigma);
86  nh.setParam("attempts_per_run", 10);
87 
88  //SHARED PARAMETERS:
89  nh.setParam("targeting_help", false);
90  nh.setParam("inference_algorithm", inferenceAlgorithm);
91 
92  // COMBINATORIAL OPTIMIZATION PARAMETERS:
93  nh.setParam("starting_topologies_type", "BestStarOrFullyMeshed");
94  nh.setParam("number_of_starting_topologies", 1);
95  nh.setParam("neighbourhood_function", "TopologyManager");
96  nh.setParam("remove_relations", true);
97  nh.setParam("swap_relations", true);
98  nh.setParam("maximum_neighbour_count", 100);
99 
100  nh.setParam("cost_function", "WeightedSum");
101  nh.setParam("false_positives_weight", 5);
102  nh.setParam("avg_recognition_time_weight", 1);
103  nh.setParam("false_negatives_weight", 5);
104 
105  nh.setParam("test_set_generator_type", "relative");
106  nh.setParam("test_set_count", 1000);
107  nh.setParam("object_missing_in_test_set_probability", 0);
108  nh.setParam("recognition_threshold", recognitionThreshold);
109  nh.setParam("loaded_test_set_count", 1000);
110  nh.setParam("write_valid_test_sets_filename", "");
111  nh.setParam("write_invalid_test_sets_filename", "");
112 
113  nh.setParam("conditional_probability_algorithm", "minimum");
114  nh.setParam("revisit_topologies", true);
115  nh.setParam("flexible_recognition_threshold", false);
116  nh.setParam("quit_after_test_set_evaluation", false);
117  nh.setParam("get_worst_star_topology", false);
118 
119  nh.setParam("hill_climbing_random_walk_probability", 0);
120  nh.setParam("hill_climbing_random_restart_probability", 0.2);
121 
122  nh.setParam("record_hunt_initial_acceptable_cost_delta", 0.02);
123  nh.setParam("record_hunt_cost_delta_decrease_factor", 0.01);
124 
125  nh.setParam("simulated_annealing_start_temperature", 1);
126  nh.setParam("simulated_annealing_end_temperature", 0.005);
127  nh.setParam("simulated_annealing_repetitions_before_update", 8);
128  nh.setParam("simulated_annealing_temperature_factor", 0.9);
129 
130  nh.setParam("xml_output", "file");
131  nh.setParam("optimization_history_output", "txt");
132  nh.setParam("create_runtime_log", false);
133  nh.setParam("log_file_name", "");
134  nh.setParam("visualize_inference", false);
135 
136  //INFERENCE PARAMETERS:
137  nh.setParam("plot", false);
138  nh.setParam("object_topic", "/stereo/objects");
139  nh.setParam("scene_graph_topic", "/scene_graphs");
140  nh.setParam("evidence_timeout", 100);
141 }
142 
143 void writeFile(const std::string & directoryPath, const std::string & filenName, std::ostringstream & content)
144 {
145  std::string filePath = directoryPath + "/" + filenName;
146  std::ofstream file;
147  std::ios_base::iostate exceptionMask = file.exceptions() | std::ios::failbit | std::ios::badbit;
148  file.exceptions(exceptionMask);
149  try
150  {
151  file.open(filePath);
152  file << content.str();
153  file.flush();
154  file.close();
155  }
156  catch (std::ios_base::failure& e)
157  {
158  std::cerr << "std::ios_base::failure" << std::endl;
159  std::cerr << e.what() << "\n";
160  }
161 }
162 
163 double calculateStandardDeviation(const std::vector<double>& values, const double& average)
164 {
165  double sumSquares = 0;
166  for (double value : values)
167  {
168  sumSquares += (value - average) * (value - average);
169  }
170 
171  double variance = sumSquares / values.size();
172 
173  return std::sqrt(variance);
174 }
175 
176 void createHistogram(const std::vector<double>& values, const unsigned int intervals, const std::string & fileName)
177 {
178  double minValue = std::numeric_limits<double>::max();
179  double maxValue = std::numeric_limits<double>::min();
180 
181  for (double value : values)
182  {
183  minValue = std::min(minValue, value);
184  maxValue = std::max(maxValue, value);
185  }
186 
187  double diff = maxValue - minValue;
188  double factor = intervals / diff;
189 
190  std::vector<unsigned int> histogram(intervals, 0);
191 
192  for (double value : values)
193  {
194  histogram[std::min((unsigned int) std::floor((value - minValue) * factor), intervals)]++;
195  }
196 
197  std::ostringstream oss;
198  oss << "Intervall in seconds, Number Testsets" << std::endl;
199  for (unsigned int i = 0; i < intervals; ++i)
200  {
201  double lower = minValue + (i * 1 / factor);
202  double upper = lower + 1 / factor;
203 
204  oss << lower << "-" << upper << ", " << histogram[i] << std::endl;
205  }
206 
207  writeFile(outputPath, fileName, oss);
208 }
209 
210 void runOptimization(std::ostringstream & os)
211 {
212  std::stringstream error;
213  error << "";
214  time_duration td;
215  try
216  {
217  ptime t1(boost::posix_time::microsec_clock::local_time());
218 
220  sceneLearningEngine->readLearnerInput();
221  sceneLearningEngine->generateSceneModel();
222  sceneLearningEngine->saveSceneModel();
223 
224  ptime t2(boost::posix_time::microsec_clock::local_time());
225  td = t2 - t1;
226  }
227  catch (std::exception& e)
228  {
229  std::cerr << e.what() << std::endl;
230  error << ", Error: " << e.what();
231  td = minutes(0);
232  }
233 
234  long secs = td.total_seconds() % 60;
235  long mins = std::floor(td.total_seconds() / 60.);
236 
237  os << ", " << mins << "." << secs << error.str() << std::endl;
238 }
239 
241 {
242  for (unsigned int i = 0; i < objectCounts.size(); ++i)
243  {
244  for (unsigned int j = 0; j < timestepCounts.size(); ++j)
245  {
246  std::string demoName = "demoRecording_" + std::to_string(objectCounts[i]) + "_" + std::to_string(timestepCounts[j]) + ".sqlite";
247  std::string demoRecordingPath = outputPath + "/" + demoName;
248 
249  demoRecordings.push_back(demoRecordingPath);
250  demoRecordingsNames.push_back(demoName);
251  }
252  }
253 }
254 
256 {
257  std::string testSetFolderPath = outputPath + "/" + testSetFolder;
258 
259  if(!boost::filesystem::exists(testSetFolderPath))
260  boost::filesystem::create_directories(testSetFolderPath);
261 
262  for (unsigned int i = 0; i < demoRecordings.size(); ++i) {
263 
264  path validTestSetsPath(testSetFolderPath + "/" + validTestSetPref + demoRecordingsNames[i]);
265  path invalidTestSetsPath(testSetFolderPath + "/" + invalidTestSetPref + demoRecordingsNames[i]);
266 
267  testSets.push_back(validTestSetsPath.string());
268  testSets.push_back(invalidTestSetsPath.string());
269  }
270 }
271 
272 void trainScenes(unsigned int run)
273 {
274  std::ostringstream os;
275  os << "Scene, Training duration" << std::endl;
276  for (unsigned int i = 0; i < demoRecordings.size(); ++i) {
277  ros::NodeHandle nh("~");
278  nh.setParam("relation_tree_trainer_type", treeAlgorithm);
279  nh.setParam("optimization_algorithm", optimizationAlgorithm);
280 
281  std::cout << "Learner input: " << demoRecordings[i] << std::endl;
282  nh.setParam("input_db_file", demoRecordings[i]);
283  std::string additionalInfo = "";
284  if (treeAlgorithm == "combinatorial_optimization") additionalInfo = "_" + optimizationAlgorithm;
285  std::string demoName = demoRecordingsNames[i].substr(0, demoRecordingsNames[i].find("."));
286  std::string sceneModelName = demoName + "_" + treeAlgorithm + additionalInfo;
287  std::cout << "Learning model " << outputPath << "/" << run << "/" << sceneModelName << ".xml" << std::endl;
288  nh.setParam("scene_model_name", sceneModelName);
289  nh.setParam("scene_model_directory", outputPath + "/" + std::to_string(run));
290 
291  nh.setParam("valid_test_set_db_filename", testSets[i * 2]);
292  nh.setParam("invalid_test_set_db_filename", testSets[i * 2 + 1]);
293 
294  std::string subfolder = outputPath + "/" + std::to_string(run) + "/" + demoName + "/";
295  nh.setParam("xml_file_path", subfolder);
296  nh.setParam("optimization_history_file_path", subfolder);
297  std::cout << "Writing partial models and optimization histories into folder " << subfolder << "/" << demoName << std::endl;
298 
299  os << demoRecordings[i] << ", ";
300  runOptimization(os);
301  }
302  writeFile(outputPath + "/" + std::to_string(run), treeAlgorithm + "_" + optimizationAlgorithm + "_d" + std::to_string(run) + "_" + "trainingTime.csv", os);
303 
304 }
305 
306 std::vector<ObjectSetPtr> loadTestSetsFromDB(std::string fileName, std::string patternName)
307 {
308  try
309  {
310  TableHelperPtr localTableHelper(new TableHelper(fileName));
311  std::vector<ObjectSetPtr> testSet;
312  if (!localTableHelper)
313  throw std::runtime_error("No local table helper!");
314  if (!localTableHelper->getRecordedPattern(patternName))
315  throw std::runtime_error("No recorded pattern for pattern name " + patternName);
316  testSet = localTableHelper->getRecordedPattern(patternName)->objectSets;
317  std::cout << "Read test sets for pattern " << patternName << std::endl;
318  return testSet;
319  }
320  catch (soci::soci_error& se)
321  {
322  std::cerr << "Soci error " << se.what() << std::endl;
323  throw se;
324  }
325 }
326 
328 {
329  unsigned int falsePositives;
330  unsigned int falseNegatives;
332  std::vector<std::pair<std::string, double>> recognitionRuntimes;
333  std::string getDescription()
334  {
335  std::stringstream out;
336  out << falsePositives << " false positives, " << falseNegatives << ", falseNegatives, " << averageRecognitionRuntime << "s average recognition runtime";
337  return out.str();
338  }
339 };
340 
341 PerformanceEvaluationResult evaluate(const std::vector<ObjectSetPtr>& ts, bool valid, const std::string& patternName, const std::string& trainedScenePath)
342 {
344  er.falseNegatives = 0;
345  er.falsePositives = 0;
346  er.recognitionRuntimes = std::vector<std::pair<std::string, double>>();
347 
348  double fullRecognitionRuntime = 0;
349 
350  std::string in = "";
351  if (!valid) in = "in";
352  std::cout << "Evaluating " << ts.size() << " " << in << "valid test sets for pattern " << patternName << std::endl;
353 
355  boost::shared_ptr<Visualization::ProbabilisticSceneModelVisualization> mVisualizer(new Visualization::ProbabilisticSceneModelVisualization());
356  model->loadModelFromFile(trainedScenePath, inferenceAlgorithm);
357  model->initializeVisualizer(mVisualizer);
358  mVisualizer->setDrawingParameters(scale, sigma, frameId);
359 
360  for (unsigned int testSetNumber = 0; testSetNumber < ts.size(); testSetNumber++)
361  {
362  ObjectSetPtr testSet = ts[testSetNumber];
363  if (!testSet)
364  throw std::runtime_error("Test set pointer invalid");
365  std::vector<SceneIdentifier> sceneList;
366  double actualRecognitionThreshold = 0.5;
367 
368  time_duration td;
369 
370  ros::Time start = ros::Time::now();
371 
372  for (unsigned int i = 0; i < testSet->objects.size(); i++)
373  {
374  boost::shared_ptr<Object> object(new Object(*(testSet->objects[i])));
375  model->integrateEvidence(object);
376  }
377  model->updateModel();
378  model->getSceneListWithProbabilities(sceneList);
379 
380  ros::Time end = ros::Time::now();
381  double recognitionRuntime = end.toSec() - start.toSec();
382 
383  std::string validity = "v";
384  if (!valid) validity = "i";
385  std::string testSetName = patternName + "_" + validity + "_" + std::to_string(testSetNumber);
386 
387  std::pair<std::string, double> result(testSetName, -1);
388  er.recognitionRuntimes.push_back(result);
389  fullRecognitionRuntime += recognitionRuntime;
390 
391  double probability = -1;
392  for (SceneIdentifier sceneIdentifier: sceneList)
393  {
394  if (sceneIdentifier.mType == "ocm")
395  {
396  probability = sceneIdentifier.mLikelihood;
397  break;
398  }
399  }
400  if (probability == -1)
401  throw std::runtime_error("Could not find probability for scene ocm in list of scene probabilities.");
402 
403  if (valid && probability <= actualRecognitionThreshold)
404  er.falseNegatives++;
405  if (!valid && probability > actualRecognitionThreshold)
406  er.falsePositives++;
407  }
408 
409  er.averageRecognitionRuntime = fullRecognitionRuntime / ((double) er.recognitionRuntimes.size());
410 
411  return er;
412 }
413 
414 // recognition performance
416 {
417 
418  std::ostringstream os;
419  os << "Scene, Average Recognition Runtime, Standard Deviation of Recognition Runtime" << std::endl;
420 
421  unsigned index = 0;
422  for (unsigned int i = 0; i < objectCounts.size(); ++i)
423  {
424  for (unsigned int j = 0; j < timestepCounts.size(); ++j)
425  {
426  std::cout << "index = " << index << std::endl;
427  path demoRecording(demoRecordings[index]);
428  std::cout << "demo recording: " << demoRecording.string() << std::endl;
429 
430  std::string sceneModelNameSuffix = "_" + treeAlgorithm;
431  if (treeAlgorithm == "combinatorial_optimization") sceneModelNameSuffix += "_" + optimizationAlgorithm;
432  std::string trainedScenePath = outputPath + "/ProbabilisticSceneModels/" + demoRecording.stem().string() + sceneModelNameSuffix + ".xml" ;
433 
434  std::cout << "Using model " << trainedScenePath << std::endl;
435  std::string sceneName = "demo_recording_" + std::to_string(objectCounts[i]) + "_" + std::to_string(timestepCounts[j]);
436 
437  std::cout << sceneName << std::endl;
438 
439  std::string validTestSets = testSets[index * 2];
440  std::string invalidTestSets = testSets[index * 2 + 1];
441 
442  std::cout << "Loading test sets from " << validTestSets << ", " << invalidTestSets << std::endl;
443 
444  std::vector<ObjectSetPtr> validSets = loadTestSetsFromDB(validTestSets, sceneName);
445  std::vector<ObjectSetPtr> invalidSets = loadTestSetsFromDB(invalidTestSets, sceneName);
446 
447  std::cout << "Test set loading complete." << std::endl;
448  std::cout << "Model initialized." << std::endl;
449 
450  PerformanceEvaluationResult validER = evaluate(validSets, true, sceneName, trainedScenePath);
451  PerformanceEvaluationResult invalidER = evaluate(invalidSets, false, sceneName, trainedScenePath);
452 
454  er.falseNegatives = validER.falseNegatives + invalidER.falseNegatives;
455  er.falsePositives = validER.falsePositives + invalidER.falsePositives;
456 
457  double fullRecognitionRuntime = 0;
458  for (std::pair<std::string, double> validRt: validER.recognitionRuntimes)
459  {
460  er.recognitionRuntimes.push_back(validRt);
461  fullRecognitionRuntime += validRt.second;
462  }
463  for (std::pair<std::string, double> invalidRt: invalidER.recognitionRuntimes)
464  {
465  er.recognitionRuntimes.push_back(invalidRt);
466  fullRecognitionRuntime += invalidRt.second;
467  }
468  er.averageRecognitionRuntime = fullRecognitionRuntime / ((double) (validER.recognitionRuntimes.size() + invalidER.recognitionRuntimes.size()));
469 
470  // To manuever around a weird issue where, if the actual recognition runtime gets assigned to the pair, there is an munmap_chunk() invalid pointer error:
472  + invalidER.averageRecognitionRuntime * invalidER.recognitionRuntimes.size())
473  / (validER.recognitionRuntimes.size() + invalidER.recognitionRuntimes.size());
474 
475  std::cout << "Evaluation complete." << std::endl;
476 
477  std::vector<std::pair<std::string, double>> recognitionRuntimes = er.recognitionRuntimes;
478  std::vector<double> runtimes;
479 
480  std::ostringstream runtimesPerSetStream;
481  runtimesPerSetStream << "Testset name, Average recognition runtime" << std::endl;
482  for (std::pair<std::string, double> valuePair : recognitionRuntimes)
483  {
484  runtimes.push_back(valuePair.second);
485  runtimesPerSetStream << valuePair.first << ", " << valuePair.second << std::endl;
486  }
487 
488  writeFile(outputPath, sceneName + "_runtimes_per_testset.csv", runtimesPerSetStream);
489 
490  std::cout << er.getDescription() << std::endl;
491 
492  std::ostringstream falserec;
493  falserec << "scene; false positives; false negatives; sum; average recognition runtime" << std::endl;
494  falserec << sceneName << "; " << er.falsePositives << "; " << er.falseNegatives << "; " << er.falsePositives + er.falseNegatives << "; " << er.averageRecognitionRuntime << std::endl;
495  writeFile(outputPath, sceneName + "_false_recognitions.csv", falserec);
496 
497  os << objectCounts[i] << "-" << timestepCounts[j] << ", " << er.averageRecognitionRuntime <<
498  ", " << calculateStandardDeviation(runtimes, er.averageRecognitionRuntime) << std::endl;
499 
500  createHistogram(runtimes, 10, sceneName + "_histogram.csv");
501  std::cout << "Histogram created." << std::endl;
502 
503  index++;
504  std::cout << "timestepCounts.size() = " << timestepCounts.size() << ", j = " << j << std::endl;
505  }
506  }
507  writeFile(outputPath, "runtimes.csv", os);
508 }
509 
518 int main(int argc, char *argv[])
519 {
520  std::string packagePath = ros::package::getPath("asr_psm");
521  outputPath = packagePath + "/data/test/performanceTestRessources";
522 
523  if(!boost::filesystem::exists(outputPath))
524  boost::filesystem::create_directories(outputPath);
525 
526  ros::init(argc, argv, "performance_test" + treeAlgorithm + "_" + optimizationAlgorithm);
527  ros::NodeHandle nh; // necessary to show ros streams
528 
530 
532  initTestSets();
533 
534  std::vector<std::string> methods = {
535  "tree",
536  "fullymeshed",
537  "combinatorial_optimization",
538  "combinatorial_optimization",
539  "combinatorial_optimization"
540  };
541  std::vector<std::string> algos = {
542  "HillClimbing",
543  "HillClimbing",
544  "HillClimbing",
545  "RecordHunt",
546  "SimulatedAnnealing"
547  };
548  unsigned int i = 0;
549  while (train && i < 1000)
550  {
551  treeAlgorithm = methods[i % methods.size()];
552  optimizationAlgorithm = algos[i % algos.size()];
553 
554  std::string subfolder = outputPath + "/" + std::to_string(i);
555  if (!boost::filesystem::exists(subfolder))
556  boost::filesystem::create_directories(subfolder);
557  for (path demoRecording: demoRecordingsNames)
558  {
559  std::string demofolder = subfolder + "/" + demoRecording.stem().string();
560  if (!boost::filesystem::exists(demofolder))
561  boost::filesystem::create_directories(demofolder);
562  }
563  try
564  {
565  trainScenes(i);
566  }
567  catch (std::exception& e)
568  {
569  std::ofstream errorfile;
570  errorfile.open(subfolder + "/error.txt");
571  if (errorfile.is_open())
572  {
573  errorfile << e.what();
574  errorfile.close();
575  }
576  std::cerr << e.what();
577  }
578  i++;
579  }
580 
581  //Set up LogHelper
582  std::string logFileName = "Log_x.txt";
583  path logFilePath = outputPath + "/Logfile/" + logFileName;
584  LogHelper::init(logFilePath, LOG_INFO);
585 
586  if (test) testPerformance();
587 }
588 
589 
double sigma
std::vector< ObjectSetPtr > loadTestSetsFromDB(std::string fileName, std::string patternName)
std::vector< std::string > demoRecordings
std::string testSetFolder
bool train
ROSCPP_DECL void init(int &argc, char **argv, const std::string &name, uint32_t options=0)
std::vector< std::string > demoRecordingsNames
std::string testSetFolderNoRefs
std::vector< std::pair< std::string, double > > recognitionRuntimes
bool find(const std::vector< double > &in, double toFind)
Definition: validator.cpp:128
void trainScenes(unsigned int run)
void writeFile(const std::string &directoryPath, const std::string &filenName, std::ostringstream &content)
void createHistogram(const std::vector< double > &values, const unsigned int intervals, const std::string &fileName)
void setDefaultParameters()
std::vector< std::string > testSetsNoRefs
std::string frameId
void runOptimization(std::ostringstream &os)
std::string outputPath
double calculateStandardDeviation(const std::vector< double > &values, const double &average)
std::string inferenceAlgorithm
double recognitionThreshold
ROSLIB_DECL std::string getPath(const std::string &package_name)
void initTestSets()
std::vector< unsigned > timestepCounts
std::string treeAlgorithm
std::vector< std::string > testSets
std::string optimizationAlgorithm
static Time now()
std::vector< unsigned > objectCounts
int main(int argc, char *argv[])
double scale
void initRandomScenes()
std::string validTestSetPref
void setParam(const std::string &key, const XmlRpc::XmlRpcValue &v) const
void testPerformance()
PerformanceEvaluationResult evaluate(const std::vector< ObjectSetPtr > &ts, bool valid, const std::string &patternName, const std::string &trainedScenePath)
std::string invalidTestSetPref


asr_psm
Author(s): Braun Kai, Gehrung Joachim, Heizmann Heinrich, Meißner Pascal
autogenerated on Fri Nov 15 2019 03:57:54