From 600d61b94335de6b580c7791eb143887da1915fd Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?C=C3=A9dric=20Traizet?= <traizetc@cesbio.cnes.fr>
Date: Tue, 16 May 2017 08:59:01 +0200
Subject: [PATCH] Shark pca and autoencoders DoPredict's method (ie without
 using batches) is now working, it shouldn't be used thought, as using batches
 is more efficient with Shark

---
 app/cbDimensionalityReduction.cxx             |  1 -
 include/AutoencoderModel.txx                  | 20 ++++---
 .../ImageDimensionalityReductionFilter.txx    | 59 ++-----------------
 include/PCAModel.h                            |  2 +-
 include/PCAModel.txx                          | 49 +++++++--------
 include/PCAModelFactory.txx                   | 12 ++--
 include/cbLearningApplicationBaseDR.h         |  5 ++
 include/cbLearningApplicationBaseDR.txx       | 10 ++++
 include/cbTrainPCA.txx                        | 50 ++++++++++++++++
 otb-module.cmake                              |  1 +
 10 files changed, 115 insertions(+), 94 deletions(-)
 create mode 100644 include/cbTrainPCA.txx

diff --git a/app/cbDimensionalityReduction.cxx b/app/cbDimensionalityReduction.cxx
index abe3875264..5a019b3989 100644
--- a/app/cbDimensionalityReduction.cxx
+++ b/app/cbDimensionalityReduction.cxx
@@ -28,7 +28,6 @@
 #include "otbImageToVectorImageCastFilter.h"
 #include "DimensionalityReductionModelFactory.h"
 
-#include "PCAModel.h"
 
 namespace otb
 {
diff --git a/include/AutoencoderModel.txx b/include/AutoencoderModel.txx
index 8ae6e58b9d..b0e206532f 100644
--- a/include/AutoencoderModel.txx
+++ b/include/AutoencoderModel.txx
@@ -122,18 +122,20 @@ AutoencoderModel<TInputValue,AutoencoderType>::DoPredict(const InputSampleType &
 	shark::RealVector samples(value.Size());
 	for(size_t i = 0; i < value.Size();i++)
     {
-		samples.push_back(value[i]);
+		samples[i]=value[i];
     }
-    shark::Data<shark::RealVector> data;
-    data.element(0)=samples;
-    data = m_net.encode(data);
     
+    std::vector<shark::RealVector> features;
+    features.push_back(samples);
+   
+    shark::Data<shark::RealVector> data = shark::createDataFromRange(features);
+     
+    data = m_net.encode(data);
     TargetSampleType target;
-    
-    //target.SetSize(m_NumberOfHiddenNeurons);
+    target.SetSize(m_NumberOfHiddenNeurons);
+	
 	for(unsigned int a = 0; a < m_NumberOfHiddenNeurons; ++a){
-		//target[a]=data.element(0)[a];
-		target=data.element(0)[a];
+		target[a]=data.element(0)[a];
 	}
 	return target;
 }
@@ -143,7 +145,7 @@ template <class TInputValue, class AutoencoderType>
 void AutoencoderModel<TInputValue,AutoencoderType>
 ::DoPredictBatch(const InputListSampleType *input, const unsigned int & startIndex, const unsigned int & size, TargetListSampleType * targets, ConfidenceListSampleType * quality) const
 {
-	
+	std::cout << "BATCH" << std::endl;
 	std::vector<shark::RealVector> features;
 	Shark::ListSampleRangeToSharkVector(input, features,startIndex,size);
 	shark::Data<shark::RealVector> data = shark::createDataFromRange(features);
diff --git a/include/ImageDimensionalityReductionFilter.txx b/include/ImageDimensionalityReductionFilter.txx
index 9d6f8d7085..9f5b34cab2 100644
--- a/include/ImageDimensionalityReductionFilter.txx
+++ b/include/ImageDimensionalityReductionFilter.txx
@@ -40,7 +40,7 @@ ImageDimensionalityReductionFilter<TInputImage, TOutputImage, TMaskImage>
   this->SetNthOutput(0,TOutputImage::New());
   this->SetNthOutput(1,ConfidenceImageType::New());
   m_UseConfidenceMap = false;
-  m_BatchMode = true;
+  m_BatchMode = false;
 }
 
 template <class TInputImage, class TOutputImage, class TMaskImage>
@@ -99,7 +99,7 @@ template <class TInputImage, class TOutputImage, class TMaskImage>
 void
 ImageDimensionalityReductionFilter<TInputImage, TOutputImage, TMaskImage>
 ::ClassicThreadedGenerateData(const OutputImageRegionType& outputRegionForThread, itk::ThreadIdType threadId)
-{/*
+{
   // Get the input pointers
   InputImageConstPointerType inputPtr     = this->GetInput();
   MaskImageConstPointerType  inputMaskPtr  = this->GetInputMask();
@@ -118,61 +118,14 @@ ImageDimensionalityReductionFilter<TInputImage, TOutputImage, TMaskImage>
   InputIteratorType inIt(inputPtr, outputRegionForThread);
   OutputIteratorType outIt(outputPtr, outputRegionForThread);
 
-  // Eventually iterate on masks
-  MaskIteratorType maskIt;
-  if (inputMaskPtr)
-    {
-    maskIt = MaskIteratorType(inputMaskPtr, outputRegionForThread);
-    maskIt.GoToBegin();
-    }
-
-  // setup iterator for confidence map
-  bool computeConfidenceMap(m_UseConfidenceMap && m_Model->HasConfidenceIndex() && !m_Model->GetRegressionMode());
-  ConfidenceMapIteratorType confidenceIt;
-  if (computeConfidenceMap)
-    {
-    confidenceIt = ConfidenceMapIteratorType(confidencePtr,outputRegionForThread);
-    confidenceIt.GoToBegin();
-    }
-
-  bool validPoint = true;
-  double confidenceIndex = 0.0;
-
   // Walk the part of the image
   for (inIt.GoToBegin(), outIt.GoToBegin(); !inIt.IsAtEnd() && !outIt.IsAtEnd(); ++inIt, ++outIt)
     {
-    // Check pixel validity
-    if (inputMaskPtr)
-      {
-      validPoint = maskIt.Get() > 0;
-      ++maskIt;
-      }
-    // If point is valid
-    if (validPoint)
-      {
-      // Classifify
-      if (computeConfidenceMap)
-        {
-        outIt.Set(m_Model->Predict(inIt.Get(),&confidenceIndex)[0]);
-        }
-      else
-        {
-        outIt.Set(m_Model->Predict(inIt.Get())[0]);
-        }
-      }
-    else
-      {
-      // else, set default value
-      outIt.Set(m_DefaultLabel);
-      confidenceIndex = 0.0;
-      }
-    if (computeConfidenceMap)
-      {
-      confidenceIt.Set(confidenceIndex);
-      ++confidenceIt;
-      }
+	// Classifify
+
+	outIt.Set(m_Model->Predict(inIt.Get()));
     progress.CompletedPixel();
-    }*/
+    }
 
 }
 
diff --git a/include/PCAModel.h b/include/PCAModel.h
index 529d2fa9bb..96d0e235c0 100644
--- a/include/PCAModel.h
+++ b/include/PCAModel.h
@@ -31,7 +31,7 @@ public:
 	itkTypeMacro(AutoencoderModel, DimensionalityReductionModel);
 
 	unsigned int GetDimension() {return m_Dimension;}; 
-	//itkGetMacro(Dimension,unsigned int);
+	itkSetMacro(Dimension,unsigned int);
 	
 	bool CanReadFile(const std::string & filename);
 	bool CanWriteFile(const std::string & filename);
diff --git a/include/PCAModel.txx b/include/PCAModel.txx
index 329b2558cf..c7625e661e 100644
--- a/include/PCAModel.txx
+++ b/include/PCAModel.txx
@@ -1,6 +1,6 @@
 
-#ifndef AutoencoderModel_txx
-#define AutoencoderModel_txx
+#ifndef PCAModel_txx
+#define PCAModel_txx
 
 #include <fstream>
 #include <shark/Data/Dataset.h>
@@ -24,7 +24,7 @@ PCAModel<TInputValue>::PCAModel()
 
 
 template <class TInputValue>
-PCAModel<TInputValue,AutoencoderType>::~PCAModel()
+PCAModel<TInputValue>::~PCAModel()
 {
 }
 
@@ -38,10 +38,10 @@ void PCAModel<TInputValue>::Train()
 	Shark::ListSampleToSharkVector(this->GetInputListSample(), features);
 	
 	shark::Data<shark::RealVector> inputSamples = shark::createDataFromRange( features );
-	
-	m_pca(inputSamples);
-	pca.encoder(m_encoder, m_Dimension);
-	pca.decoder(m_decoder, m_Dimension);
+	//m_pca.train(m_encoder,inputSamples);
+	m_pca.setData(inputSamples);
+	m_pca.encoder(m_encoder, m_Dimension);
+	m_pca.decoder(m_decoder, m_Dimension);
 	
 }
 
@@ -72,7 +72,8 @@ template <class TInputValue>
 void PCAModel<TInputValue>::Save(const std::string & filename, const std::string & name)
 {
 	std::ofstream ofs(filename);
-	ofs << m_encoder.name() << std::endl; //first line
+	//ofs << m_encoder.name() << std::endl; //first line
+	ofs << "pca" << std::endl; //first line
 	boost::archive::polymorphic_text_oarchive oa(ofs);
 	m_encoder.write(oa);
 	ofs.close();
@@ -86,11 +87,12 @@ void PCAModel<TInputValue>::Load(const std::string & filename, const std::string
 	ifs.getline(encoder,256); 
 	std::string encoderstr(encoder);
 	
-	if (autoencoderstr != m_encoder.name()){
+	//if (encoderstr != m_encoder.name()){
+	if (encoderstr != "pca"){
 		itkExceptionMacro(<< "Error opening " << filename.c_str() );
     }
 	boost::archive::polymorphic_text_iarchive ia(ifs);
-	m_net.read(ia);
+	m_encoder.read(ia);
 	ifs.close();
 	m_Dimension = m_encoder.outputSize();
 	//this->m_Size = m_NumberOfHiddenNeurons;
@@ -104,22 +106,20 @@ PCAModel<TInputValue>::DoPredict(const InputSampleType & value, ConfidenceValueT
 	shark::RealVector samples(value.Size());
 	for(size_t i = 0; i < value.Size();i++)
     {
-		samples.push_back(value[i]);
+		samples[i]=value[i];
     }
-    shark::Data<shark::RealVector> data;
-    data.element(0)=samples;
-    data = m_encoder(data);
     
+    std::vector<shark::RealVector> features;
+    features.push_back(samples);
+   
+    shark::Data<shark::RealVector> data = shark::createDataFromRange(features);
+     
+	data = m_encoder(data);
     TargetSampleType target;
-    
-    //target.SetSize(m_NumberOfHiddenNeurons);
+    target.SetSize(m_Dimension);
 	
-	for(unsigned int a = 0; a < m_NumberOfHiddenNeurons; ++a){
-		target[a]=p[a];
-		
-			//target.SetElement(a,p[a]);
-			
-			
+	for(unsigned int a = 0; a < m_Dimension; ++a){
+		target[a]=data.element(0)[a];
 	}
 	return target;
 }
@@ -136,11 +136,12 @@ void PCAModel<TInputValue>
 	TargetSampleType target;
 	data = m_encoder(data);
 	unsigned int id = startIndex;
-	target.SetSize(m_NumberOfHiddenNeurons);
+	target.SetSize(m_Dimension);
 	for(const auto& p : data.elements()){
 		
-		for(unsigned int a = 0; a < m_NumberOfHiddenNeurons; ++a){
+		for(unsigned int a = 0; a < m_Dimension; ++a){
 			target[a]=p[a];
+			//target[a]=1;
 		
 			//target.SetElement(a,p[a]);
 			
diff --git a/include/PCAModelFactory.txx b/include/PCAModelFactory.txx
index 2a0ff98b44..bfaa4f6f62 100644
--- a/include/PCAModelFactory.txx
+++ b/include/PCAModelFactory.txx
@@ -15,15 +15,15 @@
      PURPOSE.  See the above copyright notices for more information.
 
 =========================================================================*/
-#ifndef AutoencoderModelFactory_txx
-#define AutoencoderModelFactory_txx
+#ifndef PCAFactory_txx
+#define PCAFactory_txx
 
 
-#include "AutoencoderModelFactory.h"
+#include "PCAModelFactory.h"
 
 #include "itkCreateObjectFunction.h"
-#include "AutoencoderModel.h"
-#include <shark/Algorithms/Trainers/PCA.h>
+#include "PCAModel.h"
+//#include <shark/Algorithms/Trainers/PCA.h>
 #include "itkVersion.h"
 
 namespace otb
@@ -40,7 +40,7 @@ PCAModelFactory<TInputValue,TOutputValue>::PCAModelFactory()
                          "Shark PCA ML Model",
                          1,
                       //   itk::CreateObjectFunction<AutoencoderModel<TInputValue,TOutputValue> >::New());
-						itk::CreateObjectFunction<PCAModel<TInputValue,shark::LinearModel<> > >::New());
+						itk::CreateObjectFunction<PCAModel<TInputValue>>::New());
 }
 
 template <class TInputValue, class TOutputValue>
diff --git a/include/cbLearningApplicationBaseDR.h b/include/cbLearningApplicationBaseDR.h
index abd8cfc55f..7a467e242e 100644
--- a/include/cbLearningApplicationBaseDR.h
+++ b/include/cbLearningApplicationBaseDR.h
@@ -91,6 +91,8 @@ public:
 	
 	typedef shark::TiedAutoencoder< shark::TanhNeuron, shark::LinearNeuron> TiedAutoencoderType;
 	typedef otb::AutoencoderModel<InputValueType, TiedAutoencoderType> TiedAutoencoderModelType;
+	
+	typedef otb::PCAModel<InputValueType> PCAModelType;
 #endif
   
 protected:
@@ -117,8 +119,10 @@ private:
 
 #ifdef OTB_USE_SHARK
   void InitAutoencoderParams();
+  void InitPCAParams();
   template <class autoencoderchoice>
   void TrainAutoencoder(typename ListSampleType::Pointer trainingListSample, std::string modelPath);
+  void TrainPCA(typename ListSampleType::Pointer trainingListSample, std::string modelPath);
 #endif
   //@}
 };
@@ -130,6 +134,7 @@ private:
 #include "cbLearningApplicationBaseDR.txx"
 #ifdef OTB_USE_SHARK
 #include "cbTrainAutoencoder.txx"
+#include "cbTrainPCA.txx"
 #endif
 #endif
 
diff --git a/include/cbLearningApplicationBaseDR.txx b/include/cbLearningApplicationBaseDR.txx
index 344b6eccfc..562b5e395b 100644
--- a/include/cbLearningApplicationBaseDR.txx
+++ b/include/cbLearningApplicationBaseDR.txx
@@ -51,6 +51,7 @@ cbLearningApplicationBaseDR<TInputValue,TOutputValue>
 
 #ifdef OTB_USE_SHARK
   InitAutoencoderParams();
+  InitPCAParams();
 #endif
   
 }
@@ -114,6 +115,15 @@ cbLearningApplicationBaseDR<TInputValue,TOutputValue>
     otbAppLogFATAL("Module SharkLearning is not installed. You should consider turning OTB_USE_SHARK on during cmake configuration.");
     #endif
     }
+    
+  if(modelName == "pca")
+    {
+    #ifdef OTB_USE_SHARK
+    TrainPCA(trainingListSample,modelPath);
+    #else
+    otbAppLogFATAL("Module SharkLearning is not installed. You should consider turning OTB_USE_SHARK on during cmake configuration.");
+    #endif
+    }
 }
 
 }
diff --git a/include/cbTrainPCA.txx b/include/cbTrainPCA.txx
new file mode 100644
index 0000000000..9c02c566cd
--- /dev/null
+++ b/include/cbTrainPCA.txx
@@ -0,0 +1,50 @@
+
+#ifndef cbTrainPCA_txx
+#define cbTrainPCA_txx
+
+#include "cbLearningApplicationBaseDR.h"
+
+namespace otb
+{
+namespace Wrapper
+{
+
+template <class TInputValue, class TOutputValue>
+void
+cbLearningApplicationBaseDR<TInputValue,TOutputValue>
+::InitPCAParams()
+{
+
+
+  AddChoice("model.pca", "Shark PCA");
+  SetParameterDescription("model.pca",
+                          "This group of parameters allows setting Shark PCA parameters. "
+                          );
+  
+  
+   //Output Dimension
+  AddParameter(ParameterType_Int, "model.pca.dim",
+               "Dimension of the output of the pca transformation");
+  SetParameterInt("model.pca.dim",10, false);
+  SetParameterDescription(
+    "model.pca.dim",
+    "Dimension of the output of the pca transformation.");
+  
+ 
+}
+
+template <class TInputValue, class TOutputValue>
+void cbLearningApplicationBaseDR<TInputValue,TOutputValue>
+::TrainPCA(typename ListSampleType::Pointer trainingListSample,std::string modelPath)
+{
+		typename PCAModelType::Pointer dimredTrainer = PCAModelType::New();
+		dimredTrainer->SetDimension(GetParameterInt("model.pca.dim"));
+		dimredTrainer->SetInputListSample(trainingListSample);
+		dimredTrainer->Train();
+		dimredTrainer->Save(modelPath);
+}
+
+} //end namespace wrapper
+} //end namespace otb
+
+#endif
diff --git a/otb-module.cmake b/otb-module.cmake
index 8b1eb2c05c..f4a7c8f8ca 100644
--- a/otb-module.cmake
+++ b/otb-module.cmake
@@ -8,6 +8,7 @@ otb_module(CbDimensionalityReduction
 		OTBBoost
 		OTBSupervised
 		OTBAppClassification
+		OTBSOM
 	DESCRIPTION 
 		"${DOCUMENTATION}"
 )
-- 
GitLab