SparseAETutorial.cpp
Go to the documentation of this file.
1 
2 #include <shark/Data/Pgm.h> //for exporting the learned filters
3 #include <shark/Data/Csv.h>//for reading in the images as csv
4 #include <shark/Data/Statistics.h> //for normalization
5 #include <shark/ObjectiveFunctions/SparseAutoencoderError.h>//the error function performing the regularisation of the hidden neurons
6 #include <shark/Algorithms/GradientDescent/LBFGS.h>// the L-BFGS optimization algorithm
7 #include <shark/ObjectiveFunctions/Loss/SquaredLoss.h> // squared loss used for regression
8 #include <shark/ObjectiveFunctions/Regularizer.h> //L2 regulariziation
9 #include <shark/Core/Timer.h> //measures elapsed time
10 
11 using namespace std;
12 using namespace shark;
13 
14 // Image info. The images are stored as w*h vectors, so we cannot derive
15 // w and h from the data.
16 const unsigned int numsamples = 10000; //number of generated patches
17 const std::size_t w = 512;//width of loaded image
18 const std::size_t h = 512;//height of loaded image
19 const std::size_t psize = 8;//size of a patch
20 
21 // FFNet parameters
22 const unsigned int numhidden = 25;
23 const double rho = 0.01; // Sparsity parameter
24 const double beta = 6.0; // Regularization parameter
25 const double lambda = 0.0002; // Weight decay paramater
26 
27 // Optimizer parameters
28 const unsigned int maxIter = 400;
29 
31 {
32  // Read images
34  importCSV(images, "data/images.csv");
35  unsigned int n = images.numberOfElements(); // number of images
36  cout << "Found " << n << " images of size " << w << "x" << h << endl;
37 
38  // Create the samples at random
39  // Important notes: Since the images are in csv format, the width and
40  // height is hardcoded. Because width = height we only have one integer
41  // distribution below.
42 
43  // Sample equal amount of patches per image
44  size_t patchesPerImg = numsamples / n;
46 
47  // Create patches
48  vector<RealVector> patches;
49  for (ElRef it = images.elements().begin(); it != images.elements().end(); ++it) {
50  for (size_t i = 0; i < patchesPerImg; ++i) {
51  // Upper left corner of image
52  unsigned int ulx = random::discrete(random::globalRng, std::size_t(0),w-psize-1);
53  unsigned int uly = random::discrete(random::globalRng, std::size_t(0),w-psize-1);
54  // Transform 2d coordinate into 1d coordinate and get the sample
55  unsigned int ul = ulx * h + uly;
56  RealVector sample(psize * psize);
57  const RealVector& img = *it;
58  for (size_t j = 0; j < psize; ++j)
59  for (size_t k = 0; k < psize; ++k)
60  sample(j * psize + k) = img(ul + k + j * h);
61  patches.push_back(sample);
62  }
63  }
64 
66 
67  // zero mean
68  RealVector meanvec = mean(samples);
69  samples = transform(samples, Shift(-meanvec));
70 
71  // Remove outliers outside of +/- 3 standard deviations
72  // and normalize to [0.1, 0.9]
73  RealVector pstd = 3 * sqrt(variance(samples));
74  samples = transform(samples, TruncateAndRescale(-pstd, pstd, 0.1, 0.9));
75 
76  return samples;
77 }
78 
79 void initializeFFNet(Autoencoder<LogisticNeuron, LogisticNeuron>& model){
80  // Set the starting point for the optimizer. This is 0 for all bias
81  // weights and in the interval [-r, r] for non-bias weights.
82  double r = std::sqrt(6.0) / std::sqrt(model.numberOfHiddenNeurons() + model.inputSize() + 1.0);
83  RealVector params(model.numberOfParameters(),0);
84  //we use here, that the weights of the layers are the first in the vectors
85  std::size_t hiddenWeights = model.inputSize()+model.outputSize();
86  hiddenWeights *= model.numberOfHiddenNeurons();
87  for(std::size_t i = 0; i != hiddenWeights;++i){
88  params(i) = random::uni(random::globalRng, -r,r);
89  }
90  model.setParameterVector(params);
91 }
92 
93 int main()
94 {
95  // Rng needs a seed
96  random::globalRng.seed(42);
97 
98  // Read the data
100  RegressionDataset data(samples, samples);
101  cout << "Generated : " << samples.numberOfElements() << " patches." << endl;
102 
103 
104  // Prepare the sparse network error function
105  Autoencoder<LogisticNeuron, LogisticNeuron> model;
106  model.setStructure(psize * psize, numhidden);
107  initializeFFNet(model);
109  SparseAutoencoderError error(data,&model, &loss, rho, beta);
110  // Add weight regularization
111  TwoNormRegularizer regularizer(error.numberOfVariables());
112  error.setRegularizer(lambda,&regularizer);
113 
114  cout << "Model has: " << model.numberOfParameters() << " params." << endl;
115  cout << "Model has: " << model.numberOfHiddenNeurons() << "hidden neurons." << endl;
116  cout << "Model has: " << model.inputSize() << " inputs." << endl;
117  cout << "Model has: " << model.outputSize() << " outputs." << endl;
118 
119  // Train it.
120  LBFGS optimizer;
121  error.init();
122  optimizer.init(error);
123  Timer timer;
124  for (unsigned int i = 0; i < maxIter; ++i) {
125  optimizer.step(error);
126  cout << "Error: " << optimizer.solution().value << endl;
127  }
128  cout << "Elapsed time: " << timer.stop() << endl;
129  cout << "Function evaluations: " << error.evaluationCounter() << endl;
130 
131  exportFiltersToPGMGrid("features",model.encoderMatrix(),psize,psize);
132 }