package hex.deeplearning;

import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Ignore;
import org.junit.Test;
import water.*;
import water.fvec.Frame;
import water.fvec.NFSFileVec;
import water.parser.ParseDataset;
import water.util.Log;

import java.io.File;

import static hex.deeplearning.DeepLearningModel.DeepLearningParameters;

/**
 * Simple Deep Neural Network on MNIST with ~12M parameters
 * ~50MB model size, won't fit in L3 cache -> main memory bandwidth (fprop) and latency (bprop) limited
 * Note: requires './gradlew syncBigDataLaptop'
 */
public class DeepLearningMNIST extends TestUtil {
  @BeforeClass() public static void setup() { stall_till_cloudsize(1); }

  @Test @Ignore public void run() {
    Scope.enter();
    try {
      File file = find_test_file("bigdata/laptop/mnist/train.csv.gz");
      if (file != null) {
        NFSFileVec trainfv = NFSFileVec.make(file);
        Frame frame = ParseDataset.parse(Key.make(), trainfv._key);
        DeepLearningParameters p = new DeepLearningParameters();

        // populate model parameters
        p._model_id = Key.make("dl_mnist_model");
        p._train = frame._key;
        p._response_column = "C785"; // last column is the response
        p._activation = DeepLearningParameters.Activation.Tanh;
        p._hidden = new int[]{2500, 2000, 1500, 1000, 500};
        p._train_samples_per_iteration = 1500 * H2O.getCloudSize(); //process 1500 rows per node per map-reduce step
        p._epochs = 1.8 * (float) p._train_samples_per_iteration / frame.numRows(); //train long enough to do 2 map-reduce passes (with scoring each time)

        // Convert response 'C785' to categorical (digits 1 to 10)
        int ci = frame.find("C785");
        Scope.track(frame.replace(ci, frame.vecs()[ci].toEnum())._key);
        DKV.put(frame);

        // speed up training
        p._adaptive_rate = false; //disable adaptive per-weight learning rate -> default settings for learning rate and momentum are probably not ideal (slow convergence)
        p._replicate_training_data = false; //avoid extra communication cost upfront, got enough data on each node for load balancing
        p._overwrite_with_best_model = false; //no need to keep the best model around
        p._diagnostics = false; //no need to compute statistics during training
        p._score_interval = 20; //score and print progress report (only) every 20 seconds
        p._score_training_samples = 50; //only score on a small sample of the training set -> don't want to spend too much time scoring (note: there will be at least 1 row per chunk)

        DeepLearning dl = new DeepLearning(p);
        DeepLearningModel model = null;
        try {
          model = dl.trainModel().get();
          if (model != null) {
            Assert.assertTrue(1000. * model.model_info().get_processed_total() / model.run_time > 20); //we expect at least a training speed of 20 samples/second (MacBook Pro: ~50 samples/second)
          }
        } catch (Throwable t) {
          t.printStackTrace();
          throw new RuntimeException(t);
        } finally {
          dl.remove();
          if (model != null) {
            model.delete_xval_models();
            model.delete();
          }
        }
      } else {
        Log.info("Please run ./gradlew syncBigDataLaptop in the top-level directory of h2o-dev.");
      }
    } catch (Throwable t) {
      t.printStackTrace();
      throw new RuntimeException(t);
    } finally {
      Scope.exit();
    }
  }
}

@@ -824,24 +824,95 @@
 n.csv.gz%22);%0A
+      File valid = find_test_file(%22bigdata/laptop/mnist/test.csv.gz%22);%0A
       if (fi
@@ -1037,32 +1037,154 @@
  trainfv._key);%0A
+        NFSFileVec validfv = NFSFileVec.make(valid);%0A        Frame vframe = ParseDataset.parse(Key.make(), validfv._key);%0A
         DeepLear
@@ -1351,16 +1351,48 @@
 e._key;%0A
+        p._valid = vframe._key;%0A
         
@@ -1513,12 +1513,28 @@
 ion.
-Tanh
+RectifierWithDropout
 ;%0A  
@@ -1565,35 +1565,24 @@
 t%5B%5D%7B
-2500, 2000, 1500, 1000, 500
+1024, 1024, 2048
 %7D;%0A 
@@ -1625,238 +1625,119 @@
 n = 
-1500 * H2O.getCloudSize(); //process 1500 rows per node per map-reduce step%0A        p._epochs = 1.8 * (float) p._train_samples_per_iteration / frame.numRows(); //train long enough to do 2 map-reduce passes (with scoring each time)
+-2;%0A        p._input_dropout_ratio = 0.2;%0A        p._l1= 1e-5;%0A        p._max_w2= 10;%0A        p._epochs = 1000;
 %0A%0A  
@@ -1922,16 +1922,115 @@
     
-DKV.put(
+Scope.track(vframe.replace(ci, vframe.vecs()%5Bci%5D.toEnum())._key);%0A        DKV.put(frame);%0A        DKV.put(v
 fram
@@ -2090,20 +2090,19 @@
 _rate = 
-fals
+tru
 e; //dis
@@ -2270,20 +2270,19 @@
 _data = 
-fals
+tru
 e; //avo
@@ -2405,20 +2405,19 @@
 model = 
-fals
+tru
 e; //no 
@@ -2523,32 +2523,69 @@
 during training%0A
+        p._classification_stop = -1;%0A
         p._score
@@ -2596,17 +2596,17 @@
 erval = 
-2
+6
 0; //sco
@@ -2694,17 +2694,20 @@
 mples = 
-5
+1000
 0; //onl
@@ -2991,247 +2991,8 @@
 ();%0A
-          if (model != null) %7B%0A            Assert.assertTrue(1000. * model.model_info().get_processed_total() / model.run_time %3E 20); //we expect at least a training speed of 20 samples/second (MacBook Pro: ~50 samples/second)%0A          %7D%0A
     

Use world-record MNIST parameters for JUnit (ignored).