diff --git a/app/cbDimensionalityReductionVector.cxx b/app/cbDimensionalityReductionVector.cxx
index b4a8999a026a6c1c8c916dd278d0853cb1cddc2d..90927c56c44e6103dd4ec665dd7eb7627607de64 100644
--- a/app/cbDimensionalityReductionVector.cxx
+++ b/app/cbDimensionalityReductionVector.cxx
@@ -29,6 +29,7 @@
 #include "DimensionalityReductionModelFactory.h"
 #include "DimensionalityReductionModel.h"
 #include <time.h>
+
 namespace otb
 {
 namespace Wrapper
@@ -115,7 +116,7 @@ class CbDimensionalityReductionVector : public Application
 		SetDocExampleParameterValue("featout", "perimeter area width");
 		//SetOfficialDocLink(); 
 		}
-		
+		//   
 		void DoUpdateParameters() ITK_OVERRIDE
 		{
 			
@@ -271,7 +272,7 @@ class CbDimensionalityReductionVector : public Application
 			
 			otb::ogr::Layer outLayer = output->GetLayer(0);
 			OGRErr errStart = outLayer.ogr().StartTransaction();
-			/*
+			
 			if (errStart != OGRERR_NONE)
 			{
 				itkExceptionMacro(<< "Unable to start transaction for OGR layer " << outLayer.ogr().GetName() << ".");
@@ -279,25 +280,28 @@ class CbDimensionalityReductionVector : public Application
 			
 			// Add the field of prediction in the output layer if field not exist
 			
-			OGRFeatureDefn &layerDefn = layer.GetLayerDefn();
-			int idx = layerDefn.GetFieldIndex(GetParameterStringList("featout").c_str());
-			
-			if (idx >= 0)
+			for (int i=0; i<GetParameterStringList("featout").size() ;i++)
 			{
-				if (layerDefn.GetFieldDefn(idx)->GetType() != OFTInteger)
-				itkExceptionMacro("Field name "<< GetParameterStringList("featout") << " already exists with a different type!");
-			}
-			else
-			{
-				OGRFieldDefn predictedField(GetParameterStringList("featout").c_str(), OFTInteger);
-				ogr::FieldDefn predictedFieldDef(predictedField);
-				outLayer.CreateField(predictedFieldDef);
+				OGRFeatureDefn &layerDefn = outLayer.GetLayerDefn();
+				int idx = layerDefn.GetFieldIndex(GetParameterStringList("featout")[i].c_str());
+				
+				if (idx >= 0)
+				{
+					if (layerDefn.GetFieldDefn(idx)->GetType() != OFTReal)
+					itkExceptionMacro("Field name "<< GetParameterStringList("featout")[i] << " already exists with a different type!");
+				}
+				else
+				{
+					OGRFieldDefn predictedField(GetParameterStringList("featout")[i].c_str(), OFTReal);
+					ogr::FieldDefn predictedFieldDef(predictedField);
+					outLayer.CreateField(predictedFieldDef);
+				}
 			}
 			
 			// Fill output layer
 			
 			unsigned int count=0;
-			std::string classfieldname = GetParameterStringList("featout");
+			auto classfieldname = GetParameterStringList("featout");
 			it = layer.cbegin();
 			itEnd = layer.cend();
 			for( ; it!=itEnd ; ++it, ++count)
@@ -305,8 +309,9 @@ class CbDimensionalityReductionVector : public Application
 				ogr::Feature dstFeature(outLayer.GetLayerDefn());
 				dstFeature.SetFrom( *it , TRUE);
 				dstFeature.SetFID(it->GetFID());
-				dstFeature[classfieldname].SetValue<int>(target->GetMeasurementVector(count)[0]);
-				
+				for (std::size_t i=0; i<classfieldname.size(); ++i){
+					dstFeature[classfieldname[i]].SetValue<ValueType>(target->GetMeasurementVector(count)[i]);
+				}
 				if (updateMode)
 				{
 					outLayer.SetFeature(dstFeature);
@@ -316,6 +321,7 @@ class CbDimensionalityReductionVector : public Application
 					outLayer.CreateFeature(dstFeature);
 				}
 			}
+			
 			if(outLayer.ogr().TestCapability("Transactions"))
 			{
 				const OGRErr errCommitX = outLayer.ogr().CommitTransaction();
@@ -326,7 +332,7 @@ class CbDimensionalityReductionVector : public Application
 			}
 			output->SyncToDisk();
 			clock_t toc = clock();
-			otbAppLogINFO( "Elapsed: "<< ((double)(toc - tic) / CLOCKS_PER_SEC)<<" seconds.");*/
+			otbAppLogINFO( "Elapsed: "<< ((double)(toc - tic) / CLOCKS_PER_SEC)<<" seconds.");
 		}
 		
 		ModelPointerType m_Model;
diff --git a/include/AutoencoderModel.h b/include/AutoencoderModel.h
index 927e552b88b11ceac7ed0446d73bf3548a767e58..0ca282afc04d0f9ca2e0b47d4a2e752007676a58 100644
--- a/include/AutoencoderModel.h
+++ b/include/AutoencoderModel.h
@@ -34,17 +34,17 @@ public:
 	itkGetMacro(NumberOfIterations,unsigned int);
 	itkSetMacro(NumberOfIterations,unsigned int);
 
-	itkGetMacro(Regularization,double);
-	itkSetMacro(Regularization,double);
+	itkGetMacro(Regularization,itk::Array<double>);
+	itkSetMacro(Regularization,itk::Array<double>);
 
-	itkGetMacro(Noise,double);
-	itkSetMacro(Noise,double);
+	itkGetMacro(Noise,itk::Array<double>);
+	itkSetMacro(Noise,itk::Array<double>);
 
-	itkGetMacro(rho,double);
-	itkSetMacro(rho,double);
+	itkGetMacro(Rho,itk::Array<double>);
+	itkSetMacro(Rho,itk::Array<double>);
 
-	itkGetMacro(beta,double);
-	itkSetMacro(beta,double);
+	itkGetMacro(Beta,itk::Array<double>);
+	itkSetMacro(Beta,itk::Array<double>);
 
 	bool CanReadFile(const std::string & filename);
 	bool CanWriteFile(const std::string & filename);
@@ -53,7 +53,8 @@ public:
 	void Load(const std::string & filename, const std::string & name="")  ITK_OVERRIDE;
 
 	void Train() ITK_OVERRIDE;
-	void TrainOneLayer(unsigned int, shark::Data<shark::RealVector> &);
+	void TrainOneLayer(unsigned int,double, double, shark::Data<shark::RealVector> &);
+	void TrainOneSparseLayer(unsigned int,double, double,double, shark::Data<shark::RealVector> &);
 	
 protected:
 	AutoencoderModel();	
@@ -71,10 +72,10 @@ private:
 	itk::Array<unsigned int> m_NumberOfHiddenNeurons;
 	/** Training parameters */
 	unsigned int m_NumberOfIterations;
-	double m_Regularization;  // L2 Regularization parameter
-	double m_Noise;  // probability for an input to be set to 0 (denosing autoencoder)
-	double m_rho; // Sparsity parameter
-	double m_beta; // Sparsity regularization parameter
+	itk::Array<double> m_Regularization;  // L2 Regularization parameter
+	itk::Array<double> m_Noise;  // probability for an input to be set to 0 (denosing autoencoder)
+	itk::Array<double> m_Rho; // Sparsity parameter
+	itk::Array<double> m_Beta; // Sparsity regularization parameter
 };
 } // end namespace otb
 
diff --git a/include/AutoencoderModel.txx b/include/AutoencoderModel.txx
index 909356bb1c5de136a7b01ea41cfbae768367e43b..b55b5da7d4af12dffa4f4cace626ec33130b245d 100644
--- a/include/AutoencoderModel.txx
+++ b/include/AutoencoderModel.txx
@@ -20,7 +20,6 @@
 namespace otb
 {
 
-
 template <class TInputValue, class AutoencoderType>
 AutoencoderModel<TInputValue,AutoencoderType>::AutoencoderModel()
 {
@@ -42,31 +41,34 @@ void AutoencoderModel<TInputValue,AutoencoderType>::Train()
 	
 	for (unsigned int i = 0 ; i < m_NumberOfHiddenNeurons.Size(); ++i)
 	{
-		TrainOneLayer( m_NumberOfHiddenNeurons[i], inputSamples);
+		if (m_Noise[i] != 0)   // Shark doesn't allow to train a layer using a sparsity term AND a noisy input. (shark::SparseAutoencoderError takes an autoen
+		{
+			TrainOneLayer( m_NumberOfHiddenNeurons[i],m_Noise[i],m_Regularization[i], inputSamples);
+		}
+		else
+		{
+			TrainOneSparseLayer( m_NumberOfHiddenNeurons[i],m_Rho[i],m_Beta[i],m_Regularization[i], inputSamples);
+		}
 	}
 }
 
 template <class TInputValue, class AutoencoderType>
-void AutoencoderModel<TInputValue,AutoencoderType>::TrainOneLayer(unsigned int nbneuron, shark::Data<shark::RealVector> &samples)
+void AutoencoderModel<TInputValue,AutoencoderType>::TrainOneLayer(unsigned int nbneuron,double noise_strength,double regularization, shark::Data<shark::RealVector> &samples)
 {
 	AutoencoderType net;
-	/*std::vector<shark::RealVector> features;
-	
-	Shark::ListSampleToSharkVector(this->GetInputListSample(), features);
-	
-	shark::Data<shark::RealVector> inputSamples = shark::createDataFromRange( features );
-		*/ //in Train()  now
+
 	std::size_t inputs = dataDimension(samples);
 	net.setStructure(inputs, nbneuron);
 	initRandomUniform(net,-0.1*std::sqrt(1.0/inputs),0.1*std::sqrt(1.0/inputs));
-	shark::ImpulseNoiseModel noise(m_Noise,0.0); //set an input pixel with probability m_Noise to 0
+	shark::ImpulseNoiseModel noise(noise_strength,0.0); //set an input pixel with probability m_Noise to 0
 	shark::ConcatenatedModel<shark::RealVector,shark::RealVector> model = noise>> net;
 	shark::LabeledData<shark::RealVector,shark::RealVector> trainSet(samples,samples);//labels identical to inputs
 	shark::SquaredLoss<shark::RealVector> loss;
 	shark::ErrorFunction error(trainSet, &model, &loss);
-	//shark::SparseAutoencoderError error(data,&model, &loss, m_rho, m_beta);
+	//shark::SparseAutoencoderError error(trainSet,&model, &loss, m_Rho, m_Beta);
+	//shark::SparseAutoencoderError error(trainSet,&net, &loss, 0.1, 0.1);
 	shark::TwoNormRegularizer regularizer(error.numberOfVariables());
-	error.setRegularizer(m_Regularization,&regularizer);
+	error.setRegularizer(regularization,&regularizer);
 
 	shark::IRpropPlusFull optimizer;
 	error.init();
@@ -82,6 +84,35 @@ void AutoencoderModel<TInputValue,AutoencoderType>::TrainOneLayer(unsigned int n
 }
 
 
+template <class TInputValue, class AutoencoderType>
+void AutoencoderModel<TInputValue,AutoencoderType>::TrainOneSparseLayer(unsigned int nbneuron,double rho,double beta, double regularization, shark::Data<shark::RealVector> &samples)
+{
+	AutoencoderType net;
+
+	std::size_t inputs = dataDimension(samples);
+	net.setStructure(inputs, nbneuron);
+	initRandomUniform(net,-0.1*std::sqrt(1.0/inputs),0.1*std::sqrt(1.0/inputs));
+
+	shark::LabeledData<shark::RealVector,shark::RealVector> trainSet(samples,samples);//labels identical to inputs
+	shark::SquaredLoss<shark::RealVector> loss;
+	shark::SparseAutoencoderError error(trainSet,&net, &loss, rho, beta);
+	
+	shark::TwoNormRegularizer regularizer(error.numberOfVariables());
+	error.setRegularizer(regularization,&regularizer);
+
+	shark::IRpropPlusFull optimizer;
+	error.init();
+	optimizer.init(error);
+	std::cout<<"Optimizing model: "+net.name()<<std::endl;
+	for(std::size_t i = 0; i != m_NumberOfIterations; ++i){
+		optimizer.step(error);
+		std::cout<<i<<" "<<optimizer.solution().value<<std::endl;
+	}
+	net.setParameterVector(optimizer.solution().point);
+	m_net.push_back(net);
+	samples = net.encode(samples);
+}
+
 template <class TInputValue, class AutoencoderType>
 bool AutoencoderModel<TInputValue,AutoencoderType>::CanReadFile(const std::string & filename)
 {
diff --git a/include/cbTrainAutoencoder.txx b/include/cbTrainAutoencoder.txx
index 998fe3b947d740ab82c430db016fbd0a9978b42b..dce0efbe70c493c725fe42930d24a6c51eea586f 100644
--- a/include/cbTrainAutoencoder.txx
+++ b/include/cbTrainAutoencoder.txx
@@ -55,16 +55,24 @@ cbLearningApplicationBaseDR<TInputValue,TOutputValue>
     "The number of neurons in each hidden layer.");
   
   //Regularization
-  AddParameter(ParameterType_Float, "model.autoencoder.regularization", "Strength of the regularization");
-  SetParameterFloat("model.autoencoder.regularization",0, false);
+  AddParameter(ParameterType_StringList, "model.autoencoder.regularization", "Strength of the regularization");
   SetParameterDescription("model.autoencoder.regularization", 
                          "Strength of the L2 regularization used during training");
                          
   //Noise strength
-  AddParameter(ParameterType_Float, "model.autoencoder.noise", "Strength of the noise");
-  SetParameterFloat("model.autoencoder.noise",0, false);
+  AddParameter(ParameterType_StringList, "model.autoencoder.noise", "Strength of the noise");
   SetParameterDescription("model.autoencoder.noise", 
                          "Strength of the noise");
+  
+  // Sparsity parameter
+  AddParameter(ParameterType_StringList, "model.autoencoder.rho", "Sparsity parameter");
+  SetParameterDescription("model.autoencoder.rho", 
+                         "Sparsity parameter");
+  
+  // Sparsity regularization strength
+  AddParameter(ParameterType_StringList, "model.autoencoder.beta", "Sparsity regularization strength");
+  SetParameterDescription("model.autoencoder.beta", 
+                         "Sparsity regularization strength");
 }
 
 
@@ -102,16 +110,34 @@ void cbLearningApplicationBaseDR<TInputValue,TOutputValue>
 {
 		typename autoencoderchoice::Pointer dimredTrainer = autoencoderchoice::New();
 		itk::Array<unsigned int> nb_neuron;
-		std::vector<std::basic_string<char>> s= GetParameterStringList("model.autoencoder.nbneuron");
-		nb_neuron.SetSize(s.size());
-		for (int i=0; i<s.size(); i++){ // This will be templated later (the 3)
-			nb_neuron[i]=std::stoi(s[i]);
+		itk::Array<float> noise;
+		itk::Array<float> regularization;
+		itk::Array<float> rho;
+		itk::Array<float> beta;
+		std::vector<std::basic_string<char>> s_nbneuron= GetParameterStringList("model.autoencoder.nbneuron");
+		std::vector<std::basic_string<char>> s_noise= GetParameterStringList("model.autoencoder.noise");
+		std::vector<std::basic_string<char>> s_regularization= GetParameterStringList("model.autoencoder.regularization");
+		std::vector<std::basic_string<char>> s_rho= GetParameterStringList("model.autoencoder.rho");
+		std::vector<std::basic_string<char>> s_beta= GetParameterStringList("model.autoencoder.beta");
+		nb_neuron.SetSize(s_nbneuron.size());
+		noise.SetSize(s_nbneuron.size());
+		regularization.SetSize(s_nbneuron.size());
+		rho.SetSize(s_nbneuron.size());
+		beta.SetSize(s_nbneuron.size());
+		for (int i=0; i<s_nbneuron.size(); i++){ 
+			nb_neuron[i]=std::stoi(s_nbneuron[i]);
+			noise[i]=std::stof(s_noise[i]);
+			regularization[i]=std::stof(s_regularization[i]);
+			rho[i]=std::stof(s_rho[i]);
+			beta[i]=std::stof(s_beta[i]);
 		}
 		std::cout << nb_neuron << std::endl;
 		dimredTrainer->SetNumberOfHiddenNeurons(nb_neuron);
 		dimredTrainer->SetNumberOfIterations(GetParameterInt("model.autoencoder.nbiter"));
-		dimredTrainer->SetRegularization(GetParameterFloat("model.autoencoder.regularization"));
-		dimredTrainer->SetNoise(GetParameterFloat("model.autoencoder.noise"));
+		dimredTrainer->SetRegularization(regularization);
+		dimredTrainer->SetNoise(noise);
+		dimredTrainer->SetRho(rho);
+		dimredTrainer->SetBeta(beta);
 		dimredTrainer->SetInputListSample(trainingListSample);
 		std::cout << "before train" << std::endl;
 		dimredTrainer->Train();