diff --git a/include/DimensionalityReductionModelFactory.txx b/include/DimensionalityReductionModelFactory.txx
index 240d68ad7136e85d004c200134ab4d823f24f7f6..5195605a894a19da3ddfebe8724e6e004ad2a2e5 100644
--- a/include/DimensionalityReductionModelFactory.txx
+++ b/include/DimensionalityReductionModelFactory.txx
@@ -48,6 +48,12 @@ using SOM2DModelFactory = SOMModelFactory<TInputValue, TTargetValue, 2>  ;
 template <class TInputValue, class TTargetValue>
 using SOM3DModelFactory = SOMModelFactory<TInputValue, TTargetValue, 3>  ;
 
+template <class TInputValue, class TTargetValue>
+using SOM4DModelFactory = SOMModelFactory<TInputValue, TTargetValue, 4>  ;
+
+template <class TInputValue, class TTargetValue>
+using SOM5DModelFactory = SOMModelFactory<TInputValue, TTargetValue, 5>  ;
+
 template <class TInputValue, class TOutputValue>
 typename DimensionalityReductionModel<TInputValue,TOutputValue>::Pointer
 DimensionalityReductionModelFactory<TInputValue,TOutputValue>
@@ -104,9 +110,10 @@ DimensionalityReductionModelFactory<TInputValue,TOutputValue>
   
   
 
-
-  RegisterFactory(SOM3DModelFactory<TInputValue,TOutputValue>::New());
   RegisterFactory(SOM2DModelFactory<TInputValue,TOutputValue>::New());
+  RegisterFactory(SOM3DModelFactory<TInputValue,TOutputValue>::New());
+  RegisterFactory(SOM4DModelFactory<TInputValue,TOutputValue>::New());
+  RegisterFactory(SOM5DModelFactory<TInputValue,TOutputValue>::New());
   
 #ifdef OTB_USE_SHARK
   RegisterFactory(PCAModelFactory<TInputValue,TOutputValue>::New());
@@ -142,6 +149,23 @@ DimensionalityReductionModelFactory<TInputValue,TOutputValue>
     {
 
 	// SOM
+	
+	SOM5DModelFactory<TInputValue,TOutputValue> *som5dFactory =
+      dynamic_cast<SOM5DModelFactory<TInputValue,TOutputValue> *>(*itFac);
+    if (som5dFactory)
+      {
+      itk::ObjectFactoryBase::UnRegisterFactory(som5dFactory);
+      continue;
+      }
+    
+    SOM4DModelFactory<TInputValue,TOutputValue> *som4dFactory =
+      dynamic_cast<SOM4DModelFactory<TInputValue,TOutputValue> *>(*itFac);
+    if (som4dFactory)
+      {
+      itk::ObjectFactoryBase::UnRegisterFactory(som4dFactory);
+      continue;
+      }
+      
     SOM3DModelFactory<TInputValue,TOutputValue> *som3dFactory =
       dynamic_cast<SOM3DModelFactory<TInputValue,TOutputValue> *>(*itFac);
     if (som3dFactory)
diff --git a/include/SOMModel.txx b/include/SOMModel.txx
index 983e5f62a6a92d2e4894e9eb2fad29927a2320e2..d6c9f02c45cdcdd6a3f3d22b43ea5ef62bce3062 100644
--- a/include/SOMModel.txx
+++ b/include/SOMModel.txx
@@ -54,6 +54,7 @@ void SOMModel<TInputValue,  MapDimension>::Train()
 }
 
 
+
 template <class TInputValue, unsigned int MapDimension>
 bool SOMModel<TInputValue, MapDimension>::CanReadFile(const std::string & filename)
 {
@@ -75,11 +76,27 @@ bool SOMModel<TInputValue, MapDimension>::CanWriteFile(const std::string & filen
 	return true;
 }
 
+template<typename T>
+std::ostream& binary_write(std::ostream& stream, const T& value){
+    return stream.write(reinterpret_cast<const char*>(&value), sizeof(T));
+}
+
+
+std::ostream& binary_write_string(std::ofstream& stream, const std::string& value){
+    return stream.write(value.c_str(), value.length());
+}
+
+template<typename T>
+std::istream & binary_read(std::istream& stream, T& value){
+    return stream.read(reinterpret_cast<char*>(&value), sizeof(T));
+}
+
+
+
 template <class TInputValue, unsigned int MapDimension>
 void SOMModel<TInputValue, MapDimension>::Save(const std::string & filename, const std::string & name)
 {
-  std::cout << m_SOMMap->GetNumberOfComponentsPerPixel() << std::endl;
-  
+
 //Ecriture
   auto kwl = m_SOMMap->GetImageKeywordlist();
   kwl.AddKey("MachineLearningModelType", "SOM"+std::to_string(MapDimension));
@@ -92,22 +109,21 @@ void SOMModel<TInputValue, MapDimension>::Save(const std::string & filename, con
 
  // test text
   itk::ImageRegionConstIterator<MapType> inputIterator(m_SOMMap,m_SOMMap->GetLargestPossibleRegion());
-  std::ofstream ofs(filename+"2");
-  ofs << "SOM" << std::endl; 
-  ofs << MapDimension << std::endl;
+  inputIterator.GoToBegin();
+  std::ofstream ofs(filename+"2", std::ios::binary);
+  binary_write_string(ofs,"som"); 
+  binary_write(ofs,static_cast<int>(MapDimension));
   SizeType size = m_SOMMap->GetLargestPossibleRegion().GetSize() ;
-  //ofs << m_SOMMap->GetLargestPossibleRegion().GetSize() << std::endl;
   for (size_t i=0;i<MapDimension;i++){
-		ofs << size[i] << " " ;
+		binary_write(ofs,size[i]);
   }
-  ofs << std::endl;	
-  ofs << inputIterator.Get().GetNumberOfElements() << std::endl;;
+  
+  binary_write(ofs,inputIterator.Get().GetNumberOfElements());
   while(!inputIterator.IsAtEnd()){
 	InputSampleType vect = inputIterator.Get();
 	for (size_t i=0;i<vect.GetNumberOfElements();i++){
-		ofs << vect[i] << " " ;
+		binary_write(ofs,vect[i]);
 	}
-		
 	++inputIterator;
   }
   ofs.close();
@@ -117,113 +133,58 @@ void SOMModel<TInputValue, MapDimension>::Save(const std::string & filename, con
 template <class TInputValue, unsigned int MapDimension>
 void SOMModel<TInputValue, MapDimension>::Load(const std::string & filename, const std::string & name)
 {
-	/*
-	auto reader = otb::ImageFileReader<MapType>::New();
-	reader->SetFileName(filename);
-	reader->Update();
-	if (reader->GetOutput()->GetImageKeywordlist().GetMetadataByKey("MachineLearningModelType") != "SOM"+std::to_string(MapDimension)){
-		itkExceptionMacro(<< "Error opening " << filename.c_str() );
-    }
-	m_SOMMap = reader->GetOutput();
-	*/
-	// test text
-	
-	
 	
+	std::ifstream ifs(filename+"2", std::ios::binary);
 	
+	/**  Read the model key (should be som) */
+	char s[]="   ";
+	for (int i=0; i<3; i++){	
+		binary_read(ifs,s[i]);
+	}
+	std::string modelType(s);
 	
+	/** Read the dimension of the map (should be equal to MapDimension) */
 	
-	std::ifstream ifs(filename+"2");
-	std::string model_type_str;
-	std::string dimension_str;
-	std::string size_str;
-	std::string number_of_elements_str;
+	int dimension;
+	binary_read(ifs,dimension);
 	
-	std::getline(ifs,model_type_str); 
-	std::getline(ifs,dimension_str); 
-	if (model_type_str+dimension_str != "SOM"+std::to_string(MapDimension)){
+	if (modelType != "som" || dimension != MapDimension){
 		itkExceptionMacro(<< "Error opening " << filename.c_str() );
     }
     
-	std::cout << "bug-1?" << std::endl;
 	SizeType size;
-	itk::Point<double, MapDimension> origin;
-	SpacingType spacing;
 	itk::Index< MapDimension > index;
 	for (int i=0 ; i<MapDimension; i++)
 	{
-		std::getline(ifs,size_str , ' '); 
-		size[i] = stof(size_str);
-		origin[i] = 0;
-		spacing[i]=0;
+		binary_read(ifs,size[i]);
 		index[i]=0;
 	}
 	
+	unsigned int numberOfElements;
+	binary_read(ifs,numberOfElements);
 	
-	std::getline(ifs,number_of_elements_str); 
-	std::getline(ifs,number_of_elements_str); 
-	std::cout << "bug0?" <<  number_of_elements_str << std::endl;
-	auto number_of_elements = stof(number_of_elements_str);
-	
-	//typedef itk::Image< unsigned char, 3 > ImageType;
-	//typename MapType::Pointer image = MapType::New();
 	m_SOMMap = MapType::New();
 	typename MapType::RegionType region;
 	region.SetSize( size );
-	m_SOMMap->SetNumberOfComponentsPerPixel(number_of_elements);
+	m_SOMMap->SetNumberOfComponentsPerPixel(numberOfElements);
 	region.SetIndex( index );
 	m_SOMMap->SetRegions( region );
 	m_SOMMap->Allocate();
 
-	std::cout << m_SOMMap << std::endl;
-/*
-	
-	std::cout << "bug1?" << number_of_elements << std::endl;
-	itk::ImageRegion<MapDimension> outputRegion;
-	
-	
-	std::cout << "bugoriggin?" << origin << std::endl;
-	m_SOMMap->SetNumberOfComponentsPerPixel(number_of_elements);
-	outputRegion.SetIndex(index);
-		std::cout << "setindex?" << index << std::endl;
-	outputRegion.SetSize(size);
-	std::cout << origin << size << std::endl;
-	m_SOMMap->SetLargestPossibleRegion(outputRegion);
-	std::cout << "setRegion" << origin << std::endl;
-	
-	m_SOMMap->Allocate();
-	std::cout << "bug2?" << std::endl;
-	
-	*/
 	itk::ImageRegionIterator<MapType> outputIterator(m_SOMMap,region);
-    
+    outputIterator.GoToBegin();
 	std::string value;
-	size_t j=0;
 	while(!outputIterator.IsAtEnd()){
-		std::cout << j << std::endl;
-		std::getline(ifs,value, ' ');
-		itk::VariableLengthVector<float>  vect(number_of_elements);
-		for (int i=0 ; i<number_of_elements; i++)
+		InputSampleType  vect(numberOfElements);
+		for (int i=0 ; i<numberOfElements; i++)
 		{
-			std::getline(ifs,value , ' '); 
-			//std::cout << value << " ";
-			std::cout << stof(value) << " ";
-			vect[i]=std::stof(value);
+			binary_read(ifs,vect[i]);
 		}
-		std::cout << vect << std::endl;
 		outputIterator.Set(vect);
 		++outputIterator;
-		j++;
-		std::cout << j << "end" << std::endl;
-		//std::cout << value << std::endl;
-    //std::string line;
-    //std::getline(ifs, line);
 	}
-	std::cout << j << std::endl;
+
 	ifs.close();
-	std::cout << "model type " << model_type_str << std::endl;
-	std::cout << "dimension " << dimension_str << std::endl;
-	std::cout << "size " << size_str << std::endl;
 }
 
 
@@ -236,8 +197,6 @@ SOMModel<TInputValue, MapDimension>::DoPredict(const InputSampleType & value) co
     target.SetSize(dimension);
 	
     auto winner =m_SOMMap->GetWinner(value);
-    // std::cout <<  winner << std::endl;
-    
     for (int i=0; i< dimension ;i++) {
 		target[i] = winner.GetElement(i); 
 	}
diff --git a/include/cbLearningApplicationBaseDR.h b/include/cbLearningApplicationBaseDR.h
index f78dc01e272b4a136e964e42767f39a6e3a48f7c..328373b24f9b1ae99bb002d787298dc779160786 100644
--- a/include/cbLearningApplicationBaseDR.h
+++ b/include/cbLearningApplicationBaseDR.h
@@ -86,12 +86,19 @@ public:
 	typedef typename ModelType::InputListSampleType ListSampleType;
 	  
 	// Dimensionality reduction models
+
+	typedef SOMMap<itk::VariableLengthVector<TInputValue>,itk::Statistics::EuclideanDistanceMetric<itk::VariableLengthVector<TInputValue>>, 2> Map2DType;
+	typedef otb::SOMModel<InputValueType, 2> SOM2DModelType;
 	
 	typedef SOMMap<itk::VariableLengthVector<TInputValue>,itk::Statistics::EuclideanDistanceMetric<itk::VariableLengthVector<TInputValue>>, 3> Map3DType;
 	typedef otb::SOMModel<InputValueType, 3> SOM3DModelType;
 	
-	typedef SOMMap<itk::VariableLengthVector<TInputValue>,itk::Statistics::EuclideanDistanceMetric<itk::VariableLengthVector<TInputValue>>, 2> Map2DType;
-	typedef otb::SOMModel<InputValueType, 2> SOM2DModelType;
+	typedef SOMMap<itk::VariableLengthVector<TInputValue>,itk::Statistics::EuclideanDistanceMetric<itk::VariableLengthVector<TInputValue>>, 4> Map4DType;
+	typedef otb::SOMModel<InputValueType, 4> SOM4DModelType;
+	
+	typedef SOMMap<itk::VariableLengthVector<TInputValue>,itk::Statistics::EuclideanDistanceMetric<itk::VariableLengthVector<TInputValue>>, 5> Map5DType;
+	typedef otb::SOMModel<InputValueType, 5> SOM5DModelType;
+	
 
 #ifdef OTB_USE_SHARK
 	typedef shark::Autoencoder< shark::TanhNeuron, shark::LinearNeuron> AutoencoderType;
@@ -134,6 +141,7 @@ private:
   void TrainPCA(typename ListSampleType::Pointer trainingListSample, std::string modelPath);
   template <class somchoice>
   void TrainSOM(typename ListSampleType::Pointer trainingListSample, std::string modelPath);
+  void BeforeTrainSOM(typename ListSampleType::Pointer trainingListSample, std::string modelPath);
 #endif
   //@}
 };
diff --git a/include/cbLearningApplicationBaseDR.txx b/include/cbLearningApplicationBaseDR.txx
index 12f8d69d9cf5acdb0e93c1348c51bc1f73cf96a9..916d7d6f8247b85300593999687ce9a219173d90 100644
--- a/include/cbLearningApplicationBaseDR.txx
+++ b/include/cbLearningApplicationBaseDR.txx
@@ -44,9 +44,10 @@ cbLearningApplicationBaseDR<TInputValue,TOutputValue>
 {
   AddDocTag(Tags::Learning);
 
-  // main choice parameter that will contain all machine learning options
+  // main choice parameter that will contain all dimensionality reduction options
   AddParameter(ParameterType_Choice, "model", "moddel to use for the training");
   SetParameterDescription("model", "Choice of the dimensionality reduction model to use for the training.");
+  
 
   InitSOMParams();
 #ifdef OTB_USE_SHARK
@@ -60,32 +61,7 @@ template <class TInputValue, class TOutputValue>
 void
 cbLearningApplicationBaseDR<TInputValue,TOutputValue>
 ::Reduce(typename ListSampleType::Pointer validationListSample,std::string modelPath)
-{/*
-  // Setup fake reporter
-  RGBAPixelConverter<int,int>::Pointer dummyFilter =
-    RGBAPixelConverter<int,int>::New();
-  dummyFilter->SetProgress(0.0f);
-  this->AddProcess(dummyFilter,"Classify...");
-  dummyFilter->InvokeEvent(itk::StartEvent());
-
-  // load a machine learning model from file and predict the input sample list
-  ModelPointerType model = ModelFactoryType::CreateMachineLearningModel(modelPath,
-                                                                        ModelFactoryType::ReadMode);
-
-  if (model.IsNull())
-    {
-    otbAppLogFATAL(<< "Error when loading model " << modelPath);
-    }
-
-  model->Load(modelPath);
-  model->SetRegressionMode(this->m_RegressionFlag);
-  model->SetInputListSample(validationListSample);
-  model->SetTargetListSample(predictedList);
-  model->PredictAll();
-
-  // update reporter
-  dummyFilter->UpdateProgress(1.0f);
-  dummyFilter->InvokeEvent(itk::EndEvent());*/
+{
 }
 
 template <class TInputValue, class TOutputValue>
@@ -95,20 +71,15 @@ cbLearningApplicationBaseDR<TInputValue,TOutputValue>
         std::string modelPath)
 {
  
-  // get the name of the chosen machine learning model
-  const std::string modelName = GetParameterString("model");
-  // call specific train function
+ // get the name of the chosen machine learning model
+ const std::string modelName = GetParameterString("model");
+ // call specific train function
  
  if(modelName == "som")
-    {
-    TrainSOM<SOM2DModelType >(trainingListSample,modelPath);
-    }
-    
- if(modelName == "som3d")
-    {
-    TrainSOM<SOM3DModelType >(trainingListSample,modelPath);
-    }
-      
+	{
+		BeforeTrainSOM(trainingListSample,modelPath);
+	}
+ 
  if(modelName == "autoencoder")
     {
     #ifdef OTB_USE_SHARK
diff --git a/include/cbTrainSOM.txx b/include/cbTrainSOM.txx
index 10d62fb80b30e009ec9aab478de162da485c3e5f..539504b92b71490cc25f10732e2f7d6a1eeba488 100644
--- a/include/cbTrainSOM.txx
+++ b/include/cbTrainSOM.txx
@@ -24,6 +24,20 @@ cbLearningApplicationBaseDR<TInputValue,TOutputValue>
                           "This group of parameters allows setting SOM parameters. "
                           );
   
+  AddChoice("model.som4d", "OTB SOM");
+  SetParameterDescription("model.som4d",
+                          "This group of parameters allows setting SOM parameters. "
+                          );
+  
+  AddChoice("model.som5d", "OTB SOM");
+  SetParameterDescription("model.som5d",
+                          "This group of parameters allows setting SOM parameters. "
+                          );
+  
+
+	AddParameter(ParameterType_Int, "model.som.dim","Dimension of the map");
+	SetParameterDescription("model.som.dim","Dimension of the SOM map.");
+  
 	AddParameter(ParameterType_StringList ,  "model.som.s",   "Size");
     SetParameterDescription("model.som.s", "Size of the SOM map");
     MandatoryOff("model.som.s");
@@ -63,7 +77,7 @@ cbLearningApplicationBaseDR<TInputValue,TOutputValue>
     AddParameter(ParameterType_Float,  "model.som.iv",   "InitialValue");
     SetParameterDescription("model.som.iv", "Maximum initial neuron weight");
     MandatoryOff("model.som.iv");
-    ;
+    
     SetDefaultParameterInt("model.som.sx", 32);
     SetDefaultParameterInt("model.som.sy", 32);
     SetDefaultParameterInt("model.som.nx", 10);
@@ -76,6 +90,41 @@ cbLearningApplicationBaseDR<TInputValue,TOutputValue>
  
 }
 
+template <class TInputValue, class TOutputValue>
+void
+cbLearningApplicationBaseDR<TInputValue,TOutputValue>
+::BeforeTrainSOM(typename ListSampleType::Pointer trainingListSample,
+        std::string modelPath)
+{		
+	int SomDim = GetParameterInt("model.som.dim");
+	std::cout << SomDim << std::endl;
+		
+	if(SomDim == 2)
+		{
+		TrainSOM<SOM2DModelType >(trainingListSample,modelPath);
+		}
+		
+	if(SomDim == 3)
+		{
+		TrainSOM<SOM3DModelType >(trainingListSample,modelPath);
+		}
+	 
+	if(SomDim == 4)
+		{
+		TrainSOM<SOM4DModelType >(trainingListSample,modelPath);
+		}
+	 
+	if(SomDim == 5)
+		{
+		TrainSOM<SOM5DModelType >(trainingListSample,modelPath);
+		}   
+	if(SomDim > 5 || SomDim < 2)
+		{
+			std::cerr << "invalid dimension" << std::endl;
+		}
+}
+
+
 template <class TInputValue, class TOutputValue>
 template <typename somchoice>
 void cbLearningApplicationBaseDR<TInputValue,TOutputValue>