singa-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From wan...@apache.org
Subject [2/4] incubator-singa git commit: SINGA-85 Add functions for extracting features and test new data
Date Sun, 11 Oct 2015 10:19:08 GMT
SINGA-85 Add functions for extracting features and test new data

* to test pre-trained model,
  1. add checkpoint_path in job configuration to the checkpoint files
  2. setup input layer properly to read test data
  3. run singa with -test argument (e.g., ./bin/singa-run.sh -conf JOB_CONF  -test

* to extract features of new data,
  1. add checkpoint_path in job configuration to the checkpoint files
  2. setup input layer properly to read raw data
  3. add outputl layers (e.g., RecordOutputLayer or CSVOutputLayer) after the layer whose data you want to extract.
  4. run singa with -test argument (e.g., ./bin/singa-run.sh -conf JOB_CONF  -test

A test net (i.e., kTest phase is passed to creat the net)  will be create to test performance and extract features.
job.conf of cifar10 example contains instructions for extracting features and testing performance with checkpoint files.

Rename ProtoRecordLayer and CSVRecordLayer to RecordInputLayer and CSVInputLayer respectively.
Add RecordOutputLayer and CSVOutpuLayer for outputing data as RecordProto and CSV format.


Project: http://git-wip-us.apache.org/repos/asf/incubator-singa/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-singa/commit/e928ebba
Tree: http://git-wip-us.apache.org/repos/asf/incubator-singa/tree/e928ebba
Diff: http://git-wip-us.apache.org/repos/asf/incubator-singa/diff/e928ebba

Branch: refs/heads/master
Commit: e928ebba551cb6a452b0df3909677845ce151296
Parents: f90e4dc
Author: Wei Wang <wangwei@comp.nus.edu.sg>
Authored: Thu Oct 8 23:49:36 2015 +0800
Committer: Wei Wang <wangwei@comp.nus.edu.sg>
Committed: Sat Oct 10 21:06:11 2015 +0800

----------------------------------------------------------------------
 Makefile.am                                     | 108 ++++++++--------
 examples/cifar10/job.conf                       |  16 ++-
 examples/mnist/conv.conf                        |   4 +-
 examples/mnist/job.conf                         |   4 +-
 examples/rbm/autoencoder.conf                   |   4 +-
 examples/rbm/rbm1.conf                          |   4 +-
 examples/rbm/rbm2.conf                          |   4 +-
 examples/rbm/rbm3.conf                          |   4 +-
 examples/rbm/rbm4.conf                          |   4 +-
 examples/rnnlm/Makefile.example                 |   2 +-
 examples/rnnlm/create_data.cc                   |   6 +-
 examples/rnnlm/main.cc                          |   2 +-
 examples/rnnlm/rnnlm.h                          |   6 +-
 include/singa/driver.h                          |  17 ++-
 include/singa/neuralnet/input_layer/csv.h       |  53 ++++++++
 .../singa/neuralnet/input_layer/csv_record.h    |  57 ---------
 .../singa/neuralnet/input_layer/deprecated.h    |   4 -
 .../singa/neuralnet/input_layer/proto_record.h  |  58 ---------
 include/singa/neuralnet/input_layer/record.h    |  54 ++++++++
 include/singa/neuralnet/input_layer/store.h     |  86 +++++++++++++
 .../singa/neuralnet/input_layer/store_input.h   |  91 --------------
 include/singa/neuralnet/layer.h                 |   8 +-
 include/singa/neuralnet/neuralnet.h             |  28 ++++-
 include/singa/neuralnet/output_layer/csv.h      |  41 ++++++
 .../singa/neuralnet/output_layer/output_layer.h |  27 ----
 include/singa/neuralnet/output_layer/record.h   |  38 ++++++
 include/singa/server.h                          |   6 +-
 include/singa/singa.h                           |   6 +-
 include/singa/stub.h                            |   6 +-
 include/singa/worker.h                          |  15 ++-
 src/driver.cc                                   |  32 +++--
 src/io/kvfile.cc                                |   1 +
 src/main.cc                                     |  23 +++-
 src/neuralnet/input_layer/csv.cc                |  67 ++++++++++
 src/neuralnet/input_layer/csv_record.cc         |  69 ----------
 src/neuralnet/input_layer/proto_record.cc       |  73 -----------
 src/neuralnet/input_layer/record.cc             |  73 +++++++++++
 src/neuralnet/input_layer/store.cc              | 122 ++++++++++++++++++
 src/neuralnet/input_layer/store_input.cc        | 125 -------------------
 src/neuralnet/neuralnet.cc                      |  22 ++++
 src/neuralnet/output_layer/csv.cc               |  58 +++++++++
 src/neuralnet/output_layer/output_layer.cc      |  26 ----
 src/neuralnet/output_layer/record.cc            |  56 +++++++++
 src/proto/common.proto                          |   9 +-
 src/proto/job.proto                             |  14 ++-
 src/test/test_csv_input_layer.cc                |  92 ++++++++++++++
 src/test/test_csv_record_layer.cc               |  92 --------------
 src/test/test_kvfile.cc                         |  53 ++++----
 src/test/test_proto_record_layer.cc             | 122 ------------------
 src/test/test_record_input_layer.cc             | 122 ++++++++++++++++++
 src/worker.cc                                   |  56 ++++-----
 51 files changed, 1146 insertions(+), 924 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-singa/blob/e928ebba/Makefile.am
----------------------------------------------------------------------
diff --git a/Makefile.am b/Makefile.am
index 2639368..b3e0418 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -27,14 +27,6 @@ PROTO_PYS := tool/pb2/singa_pb2.py \
              tool/pb2/common_pb2.py
 
 SINGA_SRCS := src/driver.cc \
-              src/utils/cluster.cc \
-              src/utils/cluster_rt.cc \
-              src/utils/graph.cc \
-              src/utils/common.cc \
-              src/utils/param.cc \
-              src/utils/updater.cc \
-              src/utils/blob.cc \
-              src/utils/image_transform.cc \
               src/server.cc \
               src/worker.cc \
               src/stub.cc \
@@ -43,12 +35,14 @@ SINGA_SRCS := src/driver.cc \
               src/neuralnet/connection_layer/concate.cc \
               src/neuralnet/connection_layer/slice.cc \
               src/neuralnet/connection_layer/split.cc \
-              src/neuralnet/input_layer/csv_record.cc \
+              src/neuralnet/input_layer/csv.cc \
               src/neuralnet/input_layer/image_preprocess.cc \
               src/neuralnet/input_layer/prefetch.cc \
-              src/neuralnet/input_layer/proto_record.cc \
+              src/neuralnet/input_layer/record.cc \
               src/neuralnet/input_layer/deprecated.cc \
-              src/neuralnet/input_layer/store_input.cc \
+              src/neuralnet/input_layer/store.cc \
+              src/neuralnet/output_layer/csv.cc \
+              src/neuralnet/output_layer/record.cc \
               src/neuralnet/loss_layer/euclidean.cc \
               src/neuralnet/loss_layer/softmax.cc \
               src/neuralnet/neuron_layer/convolution.cc \
@@ -66,31 +60,43 @@ SINGA_SRCS := src/driver.cc \
               src/io/kvfile.cc \
               src/io/kvfile_store.cc \
               src/io/textfile_store.cc \
-              src/io/store.cc
-
-SINGA_HDRS := include/singa/singa.h \
-              include/singa/utils/cluster.h \
-              include/singa/utils/cluster_rt.h \
-              include/singa/utils/param.h \
-              include/singa/utils/common.h \
-              include/singa/utils/factory.h \
-              include/singa/utils/singleton.h \
-              include/singa/utils/graph.h \
-              include/singa/utils/blob.h \
-              include/singa/utils/updater.h \
-              include/singa/utils/tinydir.h \
-              include/singa/utils/tokenizer.h \
-              include/singa/utils/image_transform.h \
-              include/singa/server.h \
-              include/singa/worker.h \
-              include/singa/stub.h \
-              include/singa/neuralnet/layer.h \
-              include/singa/neuralnet/connection_layer.h \
-              include/singa/neuralnet/input_layer.h \
-              include/singa/neuralnet/loss_layer.h \
-              include/singa/neuralnet/neuron_layer.h \
-              include/singa/neuralnet/output_layer.h \
-              include/singa/neuralnet/neuralnet.h \
+              src/io/store.cc \
+              src/utils/cluster.cc \
+              src/utils/cluster_rt.cc \
+              src/utils/graph.cc \
+              src/utils/common.cc \
+              src/utils/param.cc \
+              src/utils/updater.cc \
+              src/utils/blob.cc \
+              src/utils/image_transform.cc
+
+SINGA_HDRS := include/singa.h \
+              include/utils/cluster.h \
+              include/utils/cluster_rt.h \
+              include/utils/param.h \
+              include/utils/common.h \
+              include/utils/factory.h \
+              include/utils/data_shard.h \
+              include/utils/singleton.h \
+              include/utils/graph.h \
+              include/utils/blob.h \
+              include/utils/updater.h \
+              include/utils/tinydir.h \
+              include/utils/tokenizer.h \
+              include/utils/image_transform.h \
+              include/server.h \
+              include/worker.h \
+              include/stub.h \
+              include/neuralnet/layer.h \
+              include/neuralnet/output_layer/csv.h \
+              include/neuralnet/output_layer/record.h \
+              include/neuralnet/neuralnet.h \
+              include/singa/comm/msg.h \
+              include/singa/comm/socket.h \
+              include/singa/io/store.h \
+              include/singa/io/kvfile.h \
+              include/singa/io/kvfile_store.h \
+              include/singa/io/textfile_store.h \
               include/mshadow/tensor_expr.h \
               include/mshadow/tensor_container.h \
               include/mshadow/tensor_expr_ext.h \
@@ -98,26 +104,20 @@ SINGA_HDRS := include/singa/singa.h \
               include/mshadow/tensor_io.h \
               include/mshadow/cxxnet_op.h \
               include/mshadow/tensor_base.h \
-              include/mshadow/tensor_random.h \
-              include/singa/comm/msg.h \
-              include/singa/comm/socket.h \
-              include/singa/io/store.h \
-              include/singa/io/kvfile.h \
-              include/singa/io/kvfile_store.h \
-              include/singa/io/textfile_store.h
+              include/mshadow/tensor_random.h
 
 GTEST_SRCS := include/gtest/gtest-all.cc
 GTEST_HRDS := include/gtest/gtest.h
 TEST_SRCS := include/gtest/gtest_main.cc \
-			 src/test/test_cluster.cc \
-             src/test/test_common.cc \
-			 src/test/test_msg.cc \
-			 src/test/test_neuralnet.cc \
-			 src/test/test_paramslicer.cc \
-			 src/test/test_kvfile.cc \
-			 src/test/test_store.cc \
-			 src/test/test_proto_record_layer.cc \
-			 src/test/test_csv_record_layer.cc
+						 src/test/test_cluster.cc \
+						 src/test/test_common.cc \
+						 src/test/test_msg.cc \
+						 src/test/test_neuralnet.cc \
+						 src/test/test_paramslicer.cc \
+						 src/test/test_kvfile.cc \
+						 src/test/test_store.cc \
+						 src/test/test_record_input_layer.cc \
+						 src/test/test_csv_input_layer.cc
 
 #EXTRA_PROGRAMS = $(PROGS)
 EXTRA_PROGRAMS = singatest
@@ -128,7 +128,7 @@ lib_LTLIBRARIES = libsinga.la $(LTLIBS)
 bin_PROGRAMS = singa singatool $(PROGS)
 
 #lib_LTLIBRARIES = libsinga.la
-libsinga_la_SOURCES = $(PROTO_HDRS) $(PROTO_SRCS) $(SINGA_HDRS) $(SINGA_SRCS)
+libsinga_la_SOURCES = $(PROTO_SRCS) $(SINGA_SRCS)
 libsinga_la_CXXFLAGS = $(DEFAULT_FLAGS) -msse3 -fpermissive
 if LMDB
 libsinga_la_CXXFLAGS += -DUSE_LMDB
@@ -183,7 +183,7 @@ singatest_LDFLAGS = -I./include \
                 -lzmq \
                 -lczmq \
                 -lzookeeper_mt \
-				-lgtest
+								-lgtest
 if LMDB
 singatest_LDFLAGS += -llmdb
 endif

http://git-wip-us.apache.org/repos/asf/incubator-singa/blob/e928ebba/examples/cifar10/job.conf
----------------------------------------------------------------------
diff --git a/examples/cifar10/job.conf b/examples/cifar10/job.conf
index 57f4b36..cce647a 100644
--- a/examples/cifar10/job.conf
+++ b/examples/cifar10/job.conf
@@ -1,8 +1,9 @@
 name: "cifar10-convnet"
 train_steps: 1000
-test_steps: 100
+test_steps: 10
 test_freq: 300
 disp_freq: 30
+checkpoint_path: "examples/cifar10/checkpoint/step50000-worker0"
 train_one_batch {
   alg: kBP
 }
@@ -24,7 +25,7 @@ updater{
 neuralnet {
   layer{
     name: "data"
-    type: kProtoRecord
+    type: kRecordInput
     store_conf {
       backend: "kvfile"
       path: "examples/cifar10/train_data.bin"
@@ -39,7 +40,7 @@ neuralnet {
   }
   layer{
     name: "data"
-    type: kProtoRecord
+    type: kRecordInput
     store_conf {
       backend: "kvfile"
       path: "examples/cifar10/test_data.bin"
@@ -229,6 +230,15 @@ neuralnet {
     srclayers:"ip1"
     srclayers: "data"
   }
+# uncomment "output" layer and comment "loss" layer to extract features from ip1
+#  layer {
+#    name : "output"
+#    type: kCSVOutput
+#    srclayers: "ip1"
+#    store_conf {
+#      path: "examples/cifar10/out.csv"
+#    }
+#  }
 }
 cluster {
   nworker_groups: 1

http://git-wip-us.apache.org/repos/asf/incubator-singa/blob/e928ebba/examples/mnist/conv.conf
----------------------------------------------------------------------
diff --git a/examples/mnist/conv.conf b/examples/mnist/conv.conf
index ba631c1..f655cc9 100644
--- a/examples/mnist/conv.conf
+++ b/examples/mnist/conv.conf
@@ -22,7 +22,7 @@ updater {
 neuralnet {
   layer {
     name: "data"
-    type: kProtoRecord
+    type: kRecordInput
     store_conf {
       backend: "kvfile"
       path: "examples/mnist/train_data.bin"
@@ -38,7 +38,7 @@ neuralnet {
 
   layer {
     name: "data"
-    type: kProtoRecord
+    type: kRecordInput
     store_conf {
       backend: "kvfile"
       path: "examples/mnist/test_data.bin"

http://git-wip-us.apache.org/repos/asf/incubator-singa/blob/e928ebba/examples/mnist/job.conf
----------------------------------------------------------------------
diff --git a/examples/mnist/job.conf b/examples/mnist/job.conf
index bfbf17d..63f59d2 100644
--- a/examples/mnist/job.conf
+++ b/examples/mnist/job.conf
@@ -21,7 +21,7 @@ updater{
 neuralnet {
   layer {
     name: "data"
-    type: kProtoRecord
+    type: kRecordInput
     store_conf {
       backend: "kvfile"
       path: "examples/mnist/train_data.bin"
@@ -36,7 +36,7 @@ neuralnet {
 
   layer {
     name: "data"
-    type: kProtoRecord
+    type: kRecordInput
     store_conf {
       backend: "kvfile"
       path: "examples/mnist/test_data.bin"

http://git-wip-us.apache.org/repos/asf/incubator-singa/blob/e928ebba/examples/rbm/autoencoder.conf
----------------------------------------------------------------------
diff --git a/examples/rbm/autoencoder.conf b/examples/rbm/autoencoder.conf
index 5799adf..87f10f0 100644
--- a/examples/rbm/autoencoder.conf
+++ b/examples/rbm/autoencoder.conf
@@ -21,7 +21,7 @@ updater{
 neuralnet {
   layer {
     name: "data"
-    type: kProtoRecord
+    type: kRecordInput
     store_conf {
       backend: "kvfile"
       path: "examples/mnist/train_data.bin"
@@ -34,7 +34,7 @@ neuralnet {
 
   layer {
     name: "data"
-    type: kProtoRecord
+    type: kRecordInput
     store_conf {
       backend: "kvfile"
       path: "examples/mnist/test_data.bin"

http://git-wip-us.apache.org/repos/asf/incubator-singa/blob/e928ebba/examples/rbm/rbm1.conf
----------------------------------------------------------------------
diff --git a/examples/rbm/rbm1.conf b/examples/rbm/rbm1.conf
index 1c23d47..ef7b875 100644
--- a/examples/rbm/rbm1.conf
+++ b/examples/rbm/rbm1.conf
@@ -19,7 +19,7 @@ updater{
 neuralnet {
   layer {
     name: "data"
-    type: kProtoRecord
+    type: kRecordInput
     store_conf {
       backend: "kvfile"
       path: "examples/mnist/train_data.bin"
@@ -32,7 +32,7 @@ neuralnet {
 
   layer {
     name: "data"
-    type: kProtoRecord
+    type: kRecordInput
     store_conf {
       backend: "kvfile"
       path: "examples/mnist/test_data.bin"

http://git-wip-us.apache.org/repos/asf/incubator-singa/blob/e928ebba/examples/rbm/rbm2.conf
----------------------------------------------------------------------
diff --git a/examples/rbm/rbm2.conf b/examples/rbm/rbm2.conf
index 2f51208..c5e9f2e 100644
--- a/examples/rbm/rbm2.conf
+++ b/examples/rbm/rbm2.conf
@@ -20,7 +20,7 @@ updater{
 neuralnet {
   layer {
     name: "data"
-    type: kProtoRecord
+    type: kRecordInput
     store_conf {
       backend: "kvfile"
       path: "examples/mnist/train_data.bin"
@@ -33,7 +33,7 @@ neuralnet {
 
   layer {
     name: "data"
-    type: kProtoRecord
+    type: kRecordInput
     store_conf {
       backend: "kvfile"
       path: "examples/mnist/test_data.bin"

http://git-wip-us.apache.org/repos/asf/incubator-singa/blob/e928ebba/examples/rbm/rbm3.conf
----------------------------------------------------------------------
diff --git a/examples/rbm/rbm3.conf b/examples/rbm/rbm3.conf
index 5df9ae3..798cf02 100644
--- a/examples/rbm/rbm3.conf
+++ b/examples/rbm/rbm3.conf
@@ -22,7 +22,7 @@ updater{
 neuralnet {
   layer {
     name: "data"
-    type: kProtoRecord
+    type: kRecordInput
     store_conf {
       backend: "kvfile"
       path: "examples/mnist/train_data.bin"
@@ -35,7 +35,7 @@ neuralnet {
 
   layer {
     name: "data"
-    type: kProtoRecord
+    type: kRecordInput
     store_conf {
       backend: "kvfile"
       path: "examples/mnist/test_data.bin"

http://git-wip-us.apache.org/repos/asf/incubator-singa/blob/e928ebba/examples/rbm/rbm4.conf
----------------------------------------------------------------------
diff --git a/examples/rbm/rbm4.conf b/examples/rbm/rbm4.conf
index a34a75c..ae64648 100644
--- a/examples/rbm/rbm4.conf
+++ b/examples/rbm/rbm4.conf
@@ -20,7 +20,7 @@ updater{
 neuralnet {
   layer {
     name: "data"
-    type: kProtoRecord
+    type: kRecordInput
     store_conf {
       backend: "kvfile"
       path: "examples/mnist/train_data.bin"
@@ -33,7 +33,7 @@ neuralnet {
 
   layer {
     name: "data"
-    type: kProtoRecord
+    type: kRecordInput
     store_conf {
       backend: "kvfile"
       path: "examples/mnist/test_data.bin"

http://git-wip-us.apache.org/repos/asf/incubator-singa/blob/e928ebba/examples/rnnlm/Makefile.example
----------------------------------------------------------------------
diff --git a/examples/rnnlm/Makefile.example b/examples/rnnlm/Makefile.example
index 5c5ef97..0a5a9ce 100644
--- a/examples/rnnlm/Makefile.example
+++ b/examples/rnnlm/Makefile.example
@@ -47,6 +47,6 @@ create:
 
 rnnlm:
 	protoc --proto_path=../../src/proto --proto_path=. --cpp_out=. rnnlm.proto
-	$(CXX) main.cc rnnlm.cc rnnlm.pb.cc $(MSHADOW_FLAGS) -msse3 -std=c++11 -lsinga -lglog -lprotobuf -lopenblas -I../../include -I../../include/proto \
+	$(CXX) main.cc rnnlm.cc rnnlm.pb.cc $(MSHADOW_FLAGS) -msse3 -std=c++11 -lsinga -lglog -lprotobuf -lopenblas -I../../include -I../../include/singa/proto \
 		-L../../.libs/ -L/usr/local  -Wl,-unresolved-symbols=ignore-in-shared-libs -Wl,-rpath=../../.libs/\
 		-o rnnlm.bin

http://git-wip-us.apache.org/repos/asf/incubator-singa/blob/e928ebba/examples/rnnlm/create_data.cc
----------------------------------------------------------------------
diff --git a/examples/rnnlm/create_data.cc b/examples/rnnlm/create_data.cc
index d63a8df..a5cd186 100644
--- a/examples/rnnlm/create_data.cc
+++ b/examples/rnnlm/create_data.cc
@@ -70,9 +70,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <algorithm>
 #include <fstream>
 
-#include "io/store.h"
-#include "utils/common.h"
-#include "proto/common.pb.h"
+#include "singa/io/store.h"
+#include "singa/utils/common.h"
+#include "singa/proto/common.pb.h"
 #include "./rnnlm.pb.h"
 
 #define MAX_STRING 100

http://git-wip-us.apache.org/repos/asf/incubator-singa/blob/e928ebba/examples/rnnlm/main.cc
----------------------------------------------------------------------
diff --git a/examples/rnnlm/main.cc b/examples/rnnlm/main.cc
index ceb8eb7..eb264cd 100644
--- a/examples/rnnlm/main.cc
+++ b/examples/rnnlm/main.cc
@@ -19,7 +19,7 @@
 *
 *************************************************************/
 #include <string>
-#include "singa.h"
+#include "singa/singa.h"
 #include "rnnlm.h"
 #include "rnnlm.pb.h"
 

http://git-wip-us.apache.org/repos/asf/incubator-singa/blob/e928ebba/examples/rnnlm/rnnlm.h
----------------------------------------------------------------------
diff --git a/examples/rnnlm/rnnlm.h b/examples/rnnlm/rnnlm.h
index cb3198e..0e415e3 100644
--- a/examples/rnnlm/rnnlm.h
+++ b/examples/rnnlm/rnnlm.h
@@ -24,7 +24,7 @@
 
 #include <string>
 #include <vector>
-#include "./singa.h"
+#include "singa/singa.h"
 #include "./rnnlm.pb.h"
 
 namespace rnnlm {
@@ -37,7 +37,7 @@ using singa::Metric;
 /**
  * Base RNN layer. May make it a base layer of SINGA.
  */
-class RNNLayer : virtual public Layer {
+class RNNLayer : virtual public singa::Layer {
  public:
   /**
    * The recurrent layers may be unrolled different times for different
@@ -58,7 +58,7 @@ class RNNLayer : virtual public Layer {
 /**
  * Input layer that get read records from data shard
  */
-class DataLayer : public RNNLayer, public singa::DataLayer {
+class DataLayer : public RNNLayer, public singa::InputLayer {
  public:
   ~DataLayer();
   void Setup(const LayerProto& conf, const vector<Layer*>& srclayers) override;

http://git-wip-us.apache.org/repos/asf/incubator-singa/blob/e928ebba/include/singa/driver.h
----------------------------------------------------------------------
diff --git a/include/singa/driver.h b/include/singa/driver.h
index 7796884..48c2c02 100644
--- a/include/singa/driver.h
+++ b/include/singa/driver.h
@@ -18,9 +18,8 @@
 * under the License.
 *
 *************************************************************/
-
-#ifndef SINGA_DRIVER_H_ 
-#define SINGA_DRIVER_H_
+#ifndef SINGA_SINGA_DRIVER_H_
+#define SINGA_SINGA_DRIVER_H_
 
 #include <vector>
 #include "singa/proto/job.pb.h"
@@ -66,6 +65,16 @@ class Driver {
    */
   void Train(const JobProto& job_conf);
   /**
+   * Test the pre-trained model by loading parameters from checkpoint files.
+   *
+   * It can be used for both computing accuracy of test data, and extracting
+   * features (predicting label) of new data.
+   * @param[in] job_conf job configuration, which should include the checkpoint
+   * files and test settings (e.g., test steps). To extract features, the output
+   * layers should be added.
+   */
+  void Test(const JobProto& job_conf);
+  /**
    * Setting the checkpoint field of the job configuration to resume training.
    *
    * The checkpoint folder will be searched to get the files for the latest
@@ -223,4 +232,4 @@ int Driver::RegisterWorker(const Type& type) {
 
 }  // namespace singa
 
-#endif  // SINGA_DRIVER_H_
+#endif  // SINGA_SINGA_DRIVER_H_

http://git-wip-us.apache.org/repos/asf/incubator-singa/blob/e928ebba/include/singa/neuralnet/input_layer/csv.h
----------------------------------------------------------------------
diff --git a/include/singa/neuralnet/input_layer/csv.h b/include/singa/neuralnet/input_layer/csv.h
new file mode 100644
index 0000000..a6f19a6
--- /dev/null
+++ b/include/singa/neuralnet/input_layer/csv.h
@@ -0,0 +1,53 @@
+/************************************************************
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements.  See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership.  The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License.  You may obtain a copy of the License at
+*
+*   http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied.  See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*************************************************************/
+
+#ifndef SINGA_NEURALNET_INPUT_LAYER_CSV_H_
+#define SINGA_NEURALNET_INPUT_LAYER_CSV_H_
+
+#include "./store.h"
+
+namespace singa {
+
+/**
+ * Specific layer that parses the value string loaded by Store as a line from
+ * a CSV file.
+ *
+ * It assumes the first column is the label except that has_label_ is configured
+ * to false. Or the data is used in deploy mode.
+ */
+class CSVInputLayer : public SingleLabelRecordLayer {
+ public:
+  void Setup(const LayerProto& proto, const vector<Layer*>& srclayers) override;
+
+ protected:
+  bool Parse(int k, int flag, const string& key, const string& val) override;
+  void LoadRecord(const string& backend,
+                  const string& path,
+                  Blob<float>* to) override;
+
+ private:
+  std::string sep_;
+  bool has_label_;
+};
+
+}  // namespace singa
+
+#endif  // SINGA_NEURALNET_INPUT_LAYER_CSV_RECORD_H_

http://git-wip-us.apache.org/repos/asf/incubator-singa/blob/e928ebba/include/singa/neuralnet/input_layer/csv_record.h
----------------------------------------------------------------------
diff --git a/include/singa/neuralnet/input_layer/csv_record.h b/include/singa/neuralnet/input_layer/csv_record.h
deleted file mode 100644
index 2653b63..0000000
--- a/include/singa/neuralnet/input_layer/csv_record.h
+++ /dev/null
@@ -1,57 +0,0 @@
-/************************************************************
-*
-* Licensed to the Apache Software Foundation (ASF) under one
-* or more contributor license agreements.  See the NOTICE file
-* distributed with this work for additional information
-* regarding copyright ownership.  The ASF licenses this file
-* to you under the Apache License, Version 2.0 (the
-* "License"); you may not use this file except in compliance
-* with the License.  You may obtain a copy of the License at
-*
-*   http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing,
-* software distributed under the License is distributed on an
-* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-* KIND, either express or implied.  See the License for the
-* specific language governing permissions and limitations
-* under the License.
-*
-*************************************************************/
-
-#ifndef SINGA_NEURALNET_INPUT_LAYER_CSV_RECORD_H_
-#define SINGA_NEURALNET_INPUT_LAYER_CSV_RECORD_H_
-
-#include <string>
-#include <vector>
-#include "singa/neuralnet/input_layer/store_input.h"
-
-namespace singa {
-using std::string;
-using std::vector;
-
-/**
- * Specific layer that parses the value string loaded by Store as a line from
- * a CSV file.
- *
- * It assumes the first column is the label except that has_label_ is configured
- * to false. Or the data is used in deploy mode.
- */
-class CSVRecordLayer : public SingleLabelRecordLayer {
- public:
-  void Setup(const LayerProto& proto, const vector<Layer*>& srclayers) override;
-
- protected:
-  bool Parse(int k, int flag, const string& key, const string& val) override;
-  void LoadRecord(const string& backend,
-                  const string& path,
-                  Blob<float>* to) override;
-
- private:
-  std::string sep_;
-  bool has_label_;
-};
-
-}  // namespace singa
-
-#endif  // SINGA_NEURALNET_INPUT_LAYER_CSV_RECORD_H_

http://git-wip-us.apache.org/repos/asf/incubator-singa/blob/e928ebba/include/singa/neuralnet/input_layer/deprecated.h
----------------------------------------------------------------------
diff --git a/include/singa/neuralnet/input_layer/deprecated.h b/include/singa/neuralnet/input_layer/deprecated.h
index bd2f60c..fdea8cf 100644
--- a/include/singa/neuralnet/input_layer/deprecated.h
+++ b/include/singa/neuralnet/input_layer/deprecated.h
@@ -22,13 +22,9 @@
 #ifndef SINGA_NEURALNET_INPUT_LAYER_DEPRECATED_H_
 #define SINGA_NEURALNET_INPUT_LAYER_DEPRECATED_H_
 
-#include <string>
-#include <vector>
 #include "singa/neuralnet/layer.h"
 #include "singa/io/kvfile.h"
 namespace singa {
-using std::string;
-using std::vector;
 /**
  * @deprecated please use the StoreInputLayer.
  *

http://git-wip-us.apache.org/repos/asf/incubator-singa/blob/e928ebba/include/singa/neuralnet/input_layer/proto_record.h
----------------------------------------------------------------------
diff --git a/include/singa/neuralnet/input_layer/proto_record.h b/include/singa/neuralnet/input_layer/proto_record.h
deleted file mode 100644
index 6a4ad0c..0000000
--- a/include/singa/neuralnet/input_layer/proto_record.h
+++ /dev/null
@@ -1,58 +0,0 @@
-/************************************************************
-*
-* Licensed to the Apache Software Foundation (ASF) under one
-* or more contributor license agreements.  See the NOTICE file
-* distributed with this work for additional information
-* regarding copyright ownership.  The ASF licenses this file
-* to you under the Apache License, Version 2.0 (the
-* "License"); you may not use this file except in compliance
-* with the License.  You may obtain a copy of the License at
-*
-*   http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing,
-* software distributed under the License is distributed on an
-* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-* KIND, either express or implied.  See the License for the
-* specific language governing permissions and limitations
-* under the License.
-*
-*************************************************************/
-
-#ifndef SINGA_NEURALNET_INPUT_LAYER_PROTO_RECORD_H_
-#define SINGA_NEURALNET_INPUT_LAYER_PROTO_RECORD_H_
-
-#include <string>
-#include <vector>
-#include "singa/io/store.h"
-#include "singa/neuralnet/input_layer/store_input.h"
-namespace singa {
-using std::string;
-using std::vector;
-
-/**
- * Specific layer that parses the value string loaded by Store into a
- * SingleLabelImageRecord.
- */
-class ProtoRecordLayer : public SingleLabelRecordLayer {
- public:
-  void Setup(const LayerProto& proto, const vector<Layer*>& srclayers) override;
-
- protected:
-  /**
-   * Parse key as instance ID and val into SingleLabelImageRecord.
-   * @copydetails StoreInputLayer::Parse()
-   */
-  bool Parse(int k, int flag, const string& key, const string& val) override;
-  void LoadRecord(const string& backend,
-                  const string& path,
-                  Blob<float>* to) override;
-
- private:
-  // TODO(wangwei) decode the image
-  bool encoded_;
-};
-
-}  // namespace singa
-
-#endif  // SINGA_NEURALNET_INPUT_LAYER_PROTO_RECORD_H_

http://git-wip-us.apache.org/repos/asf/incubator-singa/blob/e928ebba/include/singa/neuralnet/input_layer/record.h
----------------------------------------------------------------------
diff --git a/include/singa/neuralnet/input_layer/record.h b/include/singa/neuralnet/input_layer/record.h
new file mode 100644
index 0000000..5e1dce8
--- /dev/null
+++ b/include/singa/neuralnet/input_layer/record.h
@@ -0,0 +1,54 @@
+/************************************************************
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements.  See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership.  The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License.  You may obtain a copy of the License at
+*
+*   http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied.  See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*************************************************************/
+
+#ifndef SINGA_NEURALNET_INPUT_LAYER_PROTO_H_
+#define SINGA_NEURALNET_INPUT_LAYER_PROTO_H_
+
+#include "./store.h"
+
+namespace singa {
+
+/**
+ * Specific layer that parses the value string loaded by Store into a
+ * RecordProto.
+ */
+class RecordInputLayer : public SingleLabelRecordLayer {
+ public:
+  void Setup(const LayerProto& proto, const vector<Layer*>& srclayers) override;
+
+ protected:
+  /**
+   * Parse key as instance ID and val into RecordProto.
+   * @copydetails StoreInputLayer::Parse()
+   */
+  bool Parse(int k, int flag, const string& key, const string& val) override;
+  void LoadRecord(const string& backend,
+                  const string& path,
+                  Blob<float>* to) override;
+
+ private:
+  // TODO(wangwei) decode the image
+  bool encoded_;
+};
+
+}  // namespace singa
+
+#endif  // SINGA_NEURALNET_INPUT_LAYER_PROTO_RECORD_H_

http://git-wip-us.apache.org/repos/asf/incubator-singa/blob/e928ebba/include/singa/neuralnet/input_layer/store.h
----------------------------------------------------------------------
diff --git a/include/singa/neuralnet/input_layer/store.h b/include/singa/neuralnet/input_layer/store.h
new file mode 100644
index 0000000..44d67c8
--- /dev/null
+++ b/include/singa/neuralnet/input_layer/store.h
@@ -0,0 +1,86 @@
+/************************************************************
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements.  See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership.  The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License.  You may obtain a copy of the License at
+*
+*   http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied.  See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*************************************************************/
+
+#ifndef SINGA_NEURALNET_INPUT_LAYER_STORE_H_
+#define SINGA_NEURALNET_INPUT_LAYER_STORE_H_
+
+#include "singa/io/store.h"
+#include "singa/neuralnet/layer.h"
+namespace singa {
+
+/**
+ * Base class for loading data from Store.
+ */
+class StoreInputLayer : virtual public InputLayer {
+ public:
+  ~StoreInputLayer();
+  void Setup(const LayerProto& proto, const vector<Layer*>& srclayers) override;
+  void ComputeFeature(int flag, const vector<Layer*>& srclayers) override;
+
+
+ protected:
+  /**
+   * Parsing the (key, val) tuple to get feature (and label).
+   * Subclasses must implment this function.
+   * @param[in] k parse this tuple as the k-th instance of one mini-batch.
+   * @param[in] flag used to guide the parsing, e.g., kDeploy phase should not
+   * parse labels from the tuple.
+   * @param[in] key
+   * @param[in] val
+   */
+  virtual bool Parse(int k, int flag, const string& key, const string& val) = 0;
+
+ protected:
+  int batchsize_ = 1;
+  int random_skip_ = 0;
+  io::Store* store_ = nullptr;
+};
+
+/**
+ * Base layer for parsing a key-value tuple as a feature vector with fixed
+ * length. The feature shape is indicated by users in the configuration.
+ * Each tuple may has a label.
+ */
+class SingleLabelRecordLayer : public StoreInputLayer {
+ public:
+  void Setup(const LayerProto& proto, const vector<Layer*>& srclayers) override;
+  void ComputeFeature(int flag, const vector<Layer*>& srclayers) override;
+
+ protected:
+  /**
+   * Load a single record (tuple), e.g., the mean or standard variance vector.
+   */
+  virtual void LoadRecord(const string& backend, const string& path,
+      Blob<float>* to) = 0;
+
+ protected:
+  /**
+   * Feature standardization by processing each feature dimension via
+   * @f$ y = (x - mu)/ std @f$
+   * <a href= "http://ufldl.stanford.edu/wiki/index.php/Data_Preprocessing">
+   * UFLDL</a>
+   */
+  Blob<float> mean_, std_;
+};
+
+}  // namespace singa
+
+#endif  // SINGA_NEURALNET_INPUT_LAYER_STORE_INPUT_H_

http://git-wip-us.apache.org/repos/asf/incubator-singa/blob/e928ebba/include/singa/neuralnet/input_layer/store_input.h
----------------------------------------------------------------------
diff --git a/include/singa/neuralnet/input_layer/store_input.h b/include/singa/neuralnet/input_layer/store_input.h
deleted file mode 100644
index 86fbaf2..0000000
--- a/include/singa/neuralnet/input_layer/store_input.h
+++ /dev/null
@@ -1,91 +0,0 @@
-/************************************************************
-*
-* Licensed to the Apache Software Foundation (ASF) under one
-* or more contributor license agreements.  See the NOTICE file
-* distributed with this work for additional information
-* regarding copyright ownership.  The ASF licenses this file
-* to you under the Apache License, Version 2.0 (the
-* "License"); you may not use this file except in compliance
-* with the License.  You may obtain a copy of the License at
-*
-*   http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing,
-* software distributed under the License is distributed on an
-* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-* KIND, either express or implied.  See the License for the
-* specific language governing permissions and limitations
-* under the License.
-*
-*************************************************************/
-
-#ifndef SINGA_NEURALNET_INPUT_LAYER_STORE_INPUT_H_
-#define SINGA_NEURALNET_INPUT_LAYER_STORE_INPUT_H_
-
-#include <string>
-#include <vector>
-#include "singa/io/store.h"
-#include "singa/neuralnet/layer.h"
-namespace singa {
-using std::string;
-using std::vector;
-
-/**
- * Base class for loading data from Store.
- */
-class StoreInputLayer : virtual public InputLayer {
- public:
-  ~StoreInputLayer();
-  void Setup(const LayerProto& proto, const vector<Layer*>& srclayers) override;
-  void ComputeFeature(int flag, const vector<Layer*>& srclayers) override;
-
-  ConnectionType dst_layer_connection() const override { return kOneToMany; }
-
- protected:
-  /**
-   * Parsing the (key, val) tuple to get feature (and label).
-   * Subclasses must implment this function.
-   * @param[in] k parse this tuple as the k-th instance of one mini-batch.
-   * @param[in] flag used to guide the parsing, e.g., kDeploy phase should not
-   * parse labels from the tuple.
-   * @param[in] key
-   * @param[in] val
-   */
-  virtual bool Parse(int k, int flag, const string& key, const string& val) = 0;
-
- protected:
-  int batchsize_ = 1;
-  int random_skip_ = 0;
-  io::Store* store_ = nullptr;
-};
-
-/**
- * Base layer for parsing a key-value tuple as a feature vector with fixed
- * length. The feature shape is indicated by users in the configuration.
- * Each tuple may has a label.
- */
-class SingleLabelRecordLayer : public StoreInputLayer {
- public:
-  void Setup(const LayerProto& proto, const vector<Layer*>& srclayers) override;
-  void ComputeFeature(int flag, const vector<Layer*>& srclayers) override;
-
- protected:
-  /**
-   * Load a single record (tuple), e.g., the mean or standard variance vector.
-   */
-  virtual void LoadRecord(const string& backend, const string& path,
-      Blob<float>* to) = 0;
-
- protected:
-  /**
-   * Feature standardization by processing each feature dimension via
-   * @f$ y = (x - mu)/ std @f$
-   * <a href= "http://ufldl.stanford.edu/wiki/index.php/Data_Preprocessing">
-   * UFLDL</a>
-   */
-  Blob<float> mean_, std_;
-};
-
-}  // namespace singa
-
-#endif  // SINGA_NEURALNET_INPUT_LAYER_STORE_INPUT_H_

http://git-wip-us.apache.org/repos/asf/incubator-singa/blob/e928ebba/include/singa/neuralnet/layer.h
----------------------------------------------------------------------
diff --git a/include/singa/neuralnet/layer.h b/include/singa/neuralnet/layer.h
index 5bdeb6f..019678f 100644
--- a/include/singa/neuralnet/layer.h
+++ b/include/singa/neuralnet/layer.h
@@ -34,6 +34,8 @@
 
 namespace singa {
 using std::vector;
+using std::string;
+
 // TODO(wangwei) make AuxType a template argument for Layer.
 using AuxType = int;
 /**
@@ -230,6 +232,7 @@ class ConnectionLayer : virtual public Layer {
 class InputLayer : virtual public Layer {
  public:
   void ComputeGradient(int flag, const vector<Layer*>& srclayers) override {}
+  ConnectionType dst_layer_connection() const override { return kOneToMany; }
   Blob<float>* mutable_grad(const Layer* layer) override {
     // LOG(FATAL) << "Loss layer has no gradient blob";
     return nullptr;
@@ -240,6 +243,8 @@ class InputLayer : virtual public Layer {
   }
 };
 
+using SingleLabelImageRecord = RecordProto;
+
 
 /**
  * Base layer for calculating loss and doing BackPropagation.
@@ -270,7 +275,7 @@ class NeuronLayer : virtual public Layer {
 /**
  * Base layer for collecting features into disk file, HTTP stream, etc.
  */
-class OutpuLayer : virtual public Layer {
+class OutputLayer : virtual public Layer {
  public:
   void ComputeGradient(int flag, const vector<Layer*>& srclayers) override {}
   Blob<float>* mutable_grad(const Layer* layer) override {
@@ -284,5 +289,4 @@ class OutpuLayer : virtual public Layer {
 };
 
 }  // namespace singa
-
 #endif  // SINGA_NEURALNET_LAYER_H_

http://git-wip-us.apache.org/repos/asf/incubator-singa/blob/e928ebba/include/singa/neuralnet/neuralnet.h
----------------------------------------------------------------------
diff --git a/include/singa/neuralnet/neuralnet.h b/include/singa/neuralnet/neuralnet.h
index c3ddb95..b9a58fe 100644
--- a/include/singa/neuralnet/neuralnet.h
+++ b/include/singa/neuralnet/neuralnet.h
@@ -32,6 +32,9 @@
 #include "singa/utils/graph.h"
 
 namespace singa {
+using std::unordered_map;
+using std::string;
+using std::vector;
 /**
  * The neural network is constructed from user configurations in NetProto.
  *
@@ -63,6 +66,25 @@ class NeuralNet {
   NeuralNet(NetProto net_conf, int num_partitions);
   ~NeuralNet();
   /**
+   * Load net params from checkpoint fiels.
+   * @param path checkpoint files
+   */
+  void Load(const vector<string>& path);
+  /**
+   * load specified Param objects from from checkpoint files.
+   *
+   * Param objects and blobs are matched based on name.
+   * The param from previous checkpoint files will be overwritten by
+   * the param with the same name in later checkpoint files.
+   *
+   * @param[in] path
+   * @param[in,out] params load Blobs with the same name as the Params in this
+   * this dictionary. The Param values are copied into the corresponding Param
+   * objects.
+   */
+  static void Load(const vector<string>& path,
+                   const unordered_map<string, Param*>& params);
+  /**
    * To display the adjacency layers
   std::string ToAdjacency();
    */
@@ -108,9 +130,9 @@ class NeuralNet {
   std::vector<Layer*> layers_;
   std::vector<Param*> params_;
 
-  std::unordered_map<std::string, Layer*> name2layer_;
-  std::unordered_map<int, Param*> paramid2param_;
-  std::unordered_map<const Layer*, std::vector<Layer*>> src_map_;
+  unordered_map<std::string, Layer*> name2layer_;
+  unordered_map<int, Param*> paramid2param_;
+  unordered_map<const Layer*, std::vector<Layer*>> src_map_;
 };
 
 }  // namespace singa

http://git-wip-us.apache.org/repos/asf/incubator-singa/blob/e928ebba/include/singa/neuralnet/output_layer/csv.h
----------------------------------------------------------------------
diff --git a/include/singa/neuralnet/output_layer/csv.h b/include/singa/neuralnet/output_layer/csv.h
new file mode 100644
index 0000000..974e9be
--- /dev/null
+++ b/include/singa/neuralnet/output_layer/csv.h
@@ -0,0 +1,41 @@
+/************************************************************
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements.  See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership.  The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License.  You may obtain a copy of the License at
+*
+*   http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied.  See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*************************************************************/
+#ifndef SINGA_NEURALNET_OUTPUT_LAYER_CSV_H_
+#define SINGA_NEURALNET_OUTPUT_LAYER_CSV_H_
+
+#include "singa/neuralnet/layer.h"
+#include "singa/io/store.h"
+namespace singa {
+/**
+ * Output data (and label) for its source layer.
+ */
+class CSVOutputLayer : public OutputLayer {
+ public:
+  ~CSVOutputLayer() { delete store_; }
+  void Setup(const LayerProto& proto, const vector<Layer*>& srclayers) override;
+  void ComputeFeature(int flag, const vector<Layer*>& srclayers) override;
+
+ private:
+  int inst_ = 0;
+  io::Store* store_;
+};
+} /* singa */
+#endif  // SINGA_NEURALNET_OUTPUT_LAYER_CSV_OUTPUT_H_

http://git-wip-us.apache.org/repos/asf/incubator-singa/blob/e928ebba/include/singa/neuralnet/output_layer/output_layer.h
----------------------------------------------------------------------
diff --git a/include/singa/neuralnet/output_layer/output_layer.h b/include/singa/neuralnet/output_layer/output_layer.h
deleted file mode 100644
index d48d805..0000000
--- a/include/singa/neuralnet/output_layer/output_layer.h
+++ /dev/null
@@ -1,27 +0,0 @@
-/************************************************************
-*
-* Licensed to the Apache Software Foundation (ASF) under one
-* or more contributor license agreements.  See the NOTICE file
-* distributed with this work for additional information
-* regarding copyright ownership.  The ASF licenses this file
-* to you under the Apache License, Version 2.0 (the
-* "License"); you may not use this file except in compliance
-* with the License.  You may obtain a copy of the License at
-* 
-*   http://www.apache.org/licenses/LICENSE-2.0
-* 
-* Unless required by applicable law or agreed to in writing,
-* software distributed under the License is distributed on an
-* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-* KIND, either express or implied.  See the License for the
-* specific language governing permissions and limitations
-* under the License.
-*
-*************************************************************/
-
-#ifndef SINGA_NEURALNET_OUTPUT_LAYER_H_
-#define SINGA_NEURALNET_OUTPUT_LAYER_H_
-
-// currently no output sub-classes are defined
-
-#endif  // SINGA_NEURALNET_OUTPUT_LAYER_H_

http://git-wip-us.apache.org/repos/asf/incubator-singa/blob/e928ebba/include/singa/neuralnet/output_layer/record.h
----------------------------------------------------------------------
diff --git a/include/singa/neuralnet/output_layer/record.h b/include/singa/neuralnet/output_layer/record.h
new file mode 100644
index 0000000..3519ff5
--- /dev/null
+++ b/include/singa/neuralnet/output_layer/record.h
@@ -0,0 +1,38 @@
+/************************************************************
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements.  See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership.  The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License.  You may obtain a copy of the License at
+*
+*   http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied.  See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*************************************************************/
+#ifndef SINGA_NEURALNET_OUTPUT_LAYER_RECORD_H_
+#define SINGA_NEURALNET_OUTPUT_LAYER_RECORD_H_
+#include "singa/neuralnet/layer.h"
+#include "singa/io/store.h"
+namespace singa {
+
+class RecordOutputLayer : public OutputLayer {
+ public:
+  ~RecordOutputLayer() { delete store_; }
+  void Setup(const LayerProto& proto, const vector<Layer*>& srclayers) override;
+  void ComputeFeature(int flag, const vector<Layer*>& srclayers) override;
+
+ private:
+  io::Store* store_;
+  int inst_ = 0;  //!< instance No.
+};
+} /* singa */
+#endif  // SINGA_NEURALNET_OUTPUT_LAYER_RECORD_H_

http://git-wip-us.apache.org/repos/asf/incubator-singa/blob/e928ebba/include/singa/server.h
----------------------------------------------------------------------
diff --git a/include/singa/server.h b/include/singa/server.h
index 4bffeae..055820f 100644
--- a/include/singa/server.h
+++ b/include/singa/server.h
@@ -19,8 +19,8 @@
 *
 *************************************************************/
 
-#ifndef SINGA_SERVER_H_
-#define SINGA_SERVER_H_
+#ifndef SINGA_SINGA_SERVER_H_
+#define SINGA_SINGA_SERVER_H_
 
 #include <unordered_map>
 #include <vector>
@@ -130,4 +130,4 @@ class Server {
 
 }  // namespace singa
 
-#endif  // SINGA_SERVER_H_
+#endif  // SINGA_SINGA_SERVER_H_

http://git-wip-us.apache.org/repos/asf/incubator-singa/blob/e928ebba/include/singa/singa.h
----------------------------------------------------------------------
diff --git a/include/singa/singa.h b/include/singa/singa.h
index 9bc5ba5..3b8184f 100644
--- a/include/singa/singa.h
+++ b/include/singa/singa.h
@@ -19,8 +19,8 @@
 *
 *************************************************************/
 
-#ifndef SINGA_SINGA_H_
-#define SINGA_SINGA_H_
+#ifndef SINGA_SINGA_SINGA_H_
+#define SINGA_SINGA_SINGA_H_
 
 #include "singa/comm/socket.h"
 #include "singa/io/store.h"
@@ -34,4 +34,4 @@
 #include "singa/utils/factory.h"
 #include "singa/driver.h"
 
-#endif  // SINGA_SINGA_H_
+#endif  // SINGA_SINGA_SINGA_H_

http://git-wip-us.apache.org/repos/asf/incubator-singa/blob/e928ebba/include/singa/stub.h
----------------------------------------------------------------------
diff --git a/include/singa/stub.h b/include/singa/stub.h
index 0ab6fd4..730a516 100644
--- a/include/singa/stub.h
+++ b/include/singa/stub.h
@@ -19,8 +19,8 @@
 *
 *************************************************************/
 
-#ifndef SINGA_STUB_H_
-#define SINGA_STUB_H_
+#ifndef SINGA_SINGA_STUB_H_
+#define SINGA_SINGA_STUB_H_
 
 #include <queue>
 #include <unordered_map>
@@ -106,4 +106,4 @@ class Stub {
 
 }  // namespace singa
 
-#endif  // SINGA_STUB_H_
+#endif  // SINGA_SINGA_STUB_H_

http://git-wip-us.apache.org/repos/asf/incubator-singa/blob/e928ebba/include/singa/worker.h
----------------------------------------------------------------------
diff --git a/include/singa/worker.h b/include/singa/worker.h
index d8ab61c..03cd7f7 100644
--- a/include/singa/worker.h
+++ b/include/singa/worker.h
@@ -19,8 +19,8 @@
 *
 *************************************************************/
 
-#ifndef SINGA_WORKER_H_
-#define SINGA_WORKER_H_
+#ifndef SINGA_SINGA_WORKER_H_
+#define SINGA_SINGA_WORKER_H_
 
 #include <string>
 #include <vector>
@@ -85,7 +85,14 @@ class Worker {
    * Train the neuralnet step by step, test/validation is done periodically.
    */
   void Run();
-
+  /**
+   * Run TestOneBatch() over the a neural net for a total number of steps.
+   *
+   * @param[in] steps total number of test iterations.
+   * @param[in] phase kVal or kTest
+   * @param[in] net run test over the passed in neural net
+   */
+  void Test(int steps, Phase phase, NeuralNet* net);
   /**
    * Init values of Param instances assocaited with local layers (i.e., layers
    * dispatched to this worker).
@@ -310,4 +317,4 @@ inline int BlobLayer(int blob_trgt) {
 
 }  // namespace singa
 
-#endif  // SINGA_WORKER_H_
+#endif  // SINGA_SINGA_WORKER_H_

http://git-wip-us.apache.org/repos/asf/incubator-singa/blob/e928ebba/src/driver.cc
----------------------------------------------------------------------
diff --git a/src/driver.cc b/src/driver.cc
index 90d7bde..35d1f38 100644
--- a/src/driver.cc
+++ b/src/driver.cc
@@ -38,11 +38,11 @@
 #include "singa/neuralnet/connection_layer/slice.h"
 #include "singa/neuralnet/connection_layer/split.h"
 #include "singa/neuralnet/input_layer/deprecated.h"
-#include "singa/neuralnet/input_layer/csv_record.h"
+#include "singa/neuralnet/input_layer/csv.h"
 #include "singa/neuralnet/input_layer/image_preprocess.h"
 #include "singa/neuralnet/input_layer/prefetch.h"
-#include "singa/neuralnet/input_layer/proto_record.h"
-#include "singa/neuralnet/input_layer/store_input.h"
+#include "singa/neuralnet/input_layer/record.h"
+#include "singa/neuralnet/input_layer/store.h"
 #include "singa/neuralnet/loss_layer/euclidean.h"
 #include "singa/neuralnet/loss_layer/softmax.h"
 #include "singa/neuralnet/neuron_layer/convolution.h"
@@ -54,8 +54,8 @@
 #include "singa/neuralnet/neuron_layer/relu.h"
 #include "singa/neuralnet/neuron_layer/sigmoid.h"
 #include "singa/neuralnet/neuron_layer/stanh.h"
-#include "singa/neuralnet/output_layer/output_layer.h"
-
+#include "singa/neuralnet/output_layer/record.h"
+#include "singa/neuralnet/output_layer/csv.h"
 
 extern "C" void openblas_set_num_threads(int num);
 
@@ -79,9 +79,12 @@ void Driver::Init(int argc, char **argv) {
 
   // register layers
 
-  RegisterLayer<ProtoRecordLayer, int>(kProtoRecord);
-  RegisterLayer<CSVRecordLayer, int>(kCSVRecord);
+  // input and output layers
+  RegisterLayer<RecordInputLayer, int>(kRecordInput);
+  RegisterLayer<CSVInputLayer, int>(kCSVInput);
   RegisterLayer<ImagePreprocessLayer, int>(kImagePreprocess);
+  RegisterLayer<RecordOutputLayer, int>(kRecordOutput);
+  RegisterLayer<CSVOutputLayer, int>(kCSVOutput);
 
   RegisterLayer<BridgeDstLayer, int>(kBridgeDst);
   RegisterLayer<BridgeSrcLayer, int>(kBridgeSrc);
@@ -163,6 +166,20 @@ void Driver::Train(bool resume, const JobProto& job_conf) {
   Train(job);
 }
 
+void Driver::Test(const JobProto& job_conf) {
+  Cluster::Setup(job_id_, singa_conf_, job_conf.cluster());
+  Cluster::Get()->Register(getpid(), "localhost");
+  // TODO(wangwei) extend to a group with multiple workers
+  auto worker = Worker::Create(job_conf.train_one_batch());
+  worker->Setup(0, 0, job_conf, nullptr, nullptr, nullptr);
+  auto net = NeuralNet::Create(job_conf.neuralnet(), kTest, 1);
+  vector<string> paths;
+  for (const auto& p : job_conf.checkpoint_path())
+    paths.push_back(p);
+  net->Load(paths);
+  worker->Test(job_conf.test_steps(), kTest,  net);
+}
+
 void Driver::Train(const JobProto& job_conf) {
   auto cluster = Cluster::Get();
   int nserver_grps = cluster->nserver_groups();
@@ -330,4 +347,5 @@ const vector<Server*> Driver::CreateServers(const JobProto& job_conf,
   }
   return servers;
 }
+
 }  // namespace singa

http://git-wip-us.apache.org/repos/asf/incubator-singa/blob/e928ebba/src/io/kvfile.cc
----------------------------------------------------------------------
diff --git a/src/io/kvfile.cc b/src/io/kvfile.cc
index f090ccf..08f7fed 100644
--- a/src/io/kvfile.cc
+++ b/src/io/kvfile.cc
@@ -51,6 +51,7 @@ path_(path), mode_(mode), capacity_(capacity) {
         fdat_.open(path_, std::ios::in | std::ios::binary);
       }
       CHECK(fdat_.is_open()) << "Cannot open file " << path_;
+      fdat_.close();
       {
         int last_tuple = PrepareForAppend(path_);
         fdat_.open(path_, std::ios::binary | std::ios::out

http://git-wip-us.apache.org/repos/asf/incubator-singa/blob/e928ebba/src/main.cc
----------------------------------------------------------------------
diff --git a/src/main.cc b/src/main.cc
index f45a379..53b3a4c 100644
--- a/src/main.cc
+++ b/src/main.cc
@@ -19,6 +19,7 @@
 *
 *************************************************************/
 
+#include <iostream>
 #include "singa/singa.h"
 /**
  * \file main.cc provides an example main function.
@@ -43,20 +44,30 @@
  * easily, e.g., MLP(layer1_size, layer2_size, tanh, loss);
  */
 int main(int argc, char **argv) {
+  if (argc < 4) {
+    std::cout << "Args: -conf JOB_CONF -singa SINGA_CONF -job_id JOB_ID "
+              << " [-resume|-test]\n"
+              << "-resume\t resume training from latest checkpoint files\n"
+              << "-test\t test performance or extract features\n";
+    return 0;
+  }
   // must create driver at the beginning and call its Init method.
   singa::Driver driver;
   driver.Init(argc, argv);
 
-  // if -resume in argument list, set resume to true; otherwise false
-  int resume_pos = singa::ArgPos(argc, argv, "-resume");
-  bool resume = (resume_pos != -1);
-
   // users can register new subclasses of layer, updater, etc.
 
   // get the job conf, and custmize it if need
   singa::JobProto jobConf = driver.job_conf();
 
-  // submit the job for training
-  driver.Train(resume, jobConf);
+  if (singa::ArgPos(argc, argv, "-test") != -1) {
+    driver.Test(jobConf);
+  } else {
+    // if -resume in argument list, set resume to true; otherwise false
+    int resume_pos = singa::ArgPos(argc, argv, "-resume");
+    bool resume = (resume_pos != -1);
+    // submit the job for training
+    driver.Train(resume, jobConf);
+  }
   return 0;
 }

http://git-wip-us.apache.org/repos/asf/incubator-singa/blob/e928ebba/src/neuralnet/input_layer/csv.cc
----------------------------------------------------------------------
diff --git a/src/neuralnet/input_layer/csv.cc b/src/neuralnet/input_layer/csv.cc
new file mode 100644
index 0000000..297d05f
--- /dev/null
+++ b/src/neuralnet/input_layer/csv.cc
@@ -0,0 +1,67 @@
+/************************************************************
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements.  See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership.  The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License.  You may obtain a copy of the License at
+*
+*   http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied.  See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*************************************************************/
+
+#include "singa/neuralnet/input_layer/csv.h"
+#include "singa/utils/tokenizer.h"
+
+namespace singa {
+
+void CSVInputLayer::Setup(const LayerProto& conf,
+    const vector<Layer*>& srclayers) {
+  SingleLabelRecordLayer::Setup(conf, srclayers);
+  sep_ = conf.store_conf().separator();
+}
+
+void CSVInputLayer::LoadRecord(const string& backend,
+    const string&path, Blob<float>* to) {
+  io::Store* store = io::OpenStore(backend, path, io::kRead);
+  string key, val;
+  CHECK(store->Read(&key, &val));
+  float* ptr = to->mutable_cpu_data();
+  Tokenizer t(val, sep_);
+  string x;
+  for (int i = 0; i< to->count(); i++) {
+    t >> x;
+    ptr[i] = stof(x);
+  }
+  CHECK(!t.Valid());
+  delete store;
+}
+
+bool CSVInputLayer::Parse(int k, int flag, const string& key,
+    const string& value) {
+  float* ptr = data_.mutable_cpu_data() + k * data_.count() / batchsize_;
+  Tokenizer t(value, sep_);
+  string x;
+  // parse label if not deploy phase and has_label is set.
+  if ((flag & kDeploy) == 0 && layer_conf_.store_conf().has_label()) {
+    t >> x;
+    aux_data_[k] = stoi(x);
+  }
+  for (int i = 0; i< data_.count() / batchsize_; i++) {
+    t >> x;
+    ptr[i] = stof(x);
+  }
+  CHECK(!t.Valid());
+  return true;
+}
+
+}  // namespace singa

http://git-wip-us.apache.org/repos/asf/incubator-singa/blob/e928ebba/src/neuralnet/input_layer/csv_record.cc
----------------------------------------------------------------------
diff --git a/src/neuralnet/input_layer/csv_record.cc b/src/neuralnet/input_layer/csv_record.cc
deleted file mode 100644
index f755de9..0000000
--- a/src/neuralnet/input_layer/csv_record.cc
+++ /dev/null
@@ -1,69 +0,0 @@
-/************************************************************
-*
-* Licensed to the Apache Software Foundation (ASF) under one
-* or more contributor license agreements.  See the NOTICE file
-* distributed with this work for additional information
-* regarding copyright ownership.  The ASF licenses this file
-* to you under the Apache License, Version 2.0 (the
-* "License"); you may not use this file except in compliance
-* with the License.  You may obtain a copy of the License at
-*
-*   http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing,
-* software distributed under the License is distributed on an
-* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-* KIND, either express or implied.  See the License for the
-* specific language governing permissions and limitations
-* under the License.
-*
-*************************************************************/
-
-#include "singa/neuralnet/input_layer/csv_record.h"
-#include "singa/utils/tokenizer.h"
-namespace singa {
-
-using std::string;
-using std::vector;
-
-void CSVRecordLayer::Setup(const LayerProto& conf,
-    const vector<Layer*>& srclayers) {
-  SingleLabelRecordLayer::Setup(conf, srclayers);
-  sep_ = conf.store_conf().separator();
-}
-
-void CSVRecordLayer::LoadRecord(const string& backend,
-    const string&path, Blob<float>* to) {
-  io::Store* store = io::OpenStore(backend, path, io::kRead);
-  string key, val;
-  CHECK(store->Read(&key, &val));
-  float* ptr = to->mutable_cpu_data();
-  Tokenizer t(val, sep_);
-  string x;
-  for (int i = 0; i< to->count(); i++) {
-    t >> x;
-    ptr[i] = stof(x);
-  }
-  CHECK(!t.Valid());
-  delete store;
-}
-
-bool CSVRecordLayer::Parse(int k, int flag, const string& key,
-    const string& value) {
-  float* ptr = data_.mutable_cpu_data() + k * data_.count() / batchsize_;
-  Tokenizer t(value, sep_);
-  string x;
-  // parse label if not deploy phase and has_label is set.
-  if ((flag & kDeploy) == 0 && layer_conf_.store_conf().has_label()) {
-    t >> x;
-    aux_data_[k] = stoi(x);
-  }
-  for (int i = 0; i< data_.count() / batchsize_; i++) {
-    t >> x;
-    ptr[i] = stof(x);
-  }
-  CHECK(!t.Valid());
-  return true;
-}
-
-}  // namespace singa

http://git-wip-us.apache.org/repos/asf/incubator-singa/blob/e928ebba/src/neuralnet/input_layer/proto_record.cc
----------------------------------------------------------------------
diff --git a/src/neuralnet/input_layer/proto_record.cc b/src/neuralnet/input_layer/proto_record.cc
deleted file mode 100644
index 34457b2..0000000
--- a/src/neuralnet/input_layer/proto_record.cc
+++ /dev/null
@@ -1,73 +0,0 @@
-/************************************************************
-*
-* Licensed to the Apache Software Foundation (ASF) under one
-* or more contributor license agreements.  See the NOTICE file
-* distributed with this work for additional information
-* regarding copyright ownership.  The ASF licenses this file
-* to you under the Apache License, Version 2.0 (the
-* "License"); you may not use this file except in compliance
-* with the License.  You may obtain a copy of the License at
-*
-*   http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing,
-* software distributed under the License is distributed on an
-* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-* KIND, either express or implied.  See the License for the
-* specific language governing permissions and limitations
-* under the License.
-*
-*************************************************************/
-
-#include "singa/neuralnet/input_layer/proto_record.h"
-namespace singa {
-
-using std::string;
-using std::vector;
-
-void ProtoRecordLayer::Setup(const LayerProto& conf,
-    const vector<Layer*>& srclayers) {
-  SingleLabelRecordLayer::Setup(conf, srclayers);
-  encoded_ = conf.store_conf().encoded();
-}
-
-void ProtoRecordLayer::LoadRecord(const string& backend,
-    const string&path, Blob<float>* to) {
-  io::Store* store = io::OpenStore(backend, path, io::kRead);
-  string key, val;
-  CHECK(store->Read(&key, &val));
-  SingleLabelImageRecord image;
-  image.ParseFromString(val);
-  CHECK_EQ(to->count(), image.data_size());
-  float* ptr = to->mutable_cpu_data();
-  for (int i = 0; i< to->count(); i++)
-    ptr[i] = image.data(i);
-  delete store;
-}
-
-bool ProtoRecordLayer::Parse(int k, int flag, const string& key,
-    const string& value) {
-  SingleLabelImageRecord image;
-  image.ParseFromString(value);
-  int size = data_.count() / batchsize_;
-  if (image.data_size()) {
-    CHECK_EQ(size, image.data_size());
-    float* ptr = data_.mutable_cpu_data() + k * size;
-    for (int i = 0; i< size; i++)
-      ptr[i] = image.data(i);
-  } else if (image.pixel().size()) {
-    CHECK_EQ(size, image.pixel().size());
-    float* ptr = data_.mutable_cpu_data() + k * size;
-    string pixel = image.pixel();
-    for (int i = 0; i < size; i++)
-      ptr[i] =  static_cast<float>(static_cast<uint8_t>(pixel[i]));
-  } else {
-    LOG(ERROR) << "not pixel nor pixel";
-  }
-  if ((flag & kDeploy) == 0) {  // deploy mode does not have label
-    aux_data_.at(k) = image.label();
-  }
-  return true;
-}
-
-}  // namespace singa

http://git-wip-us.apache.org/repos/asf/incubator-singa/blob/e928ebba/src/neuralnet/input_layer/record.cc
----------------------------------------------------------------------
diff --git a/src/neuralnet/input_layer/record.cc b/src/neuralnet/input_layer/record.cc
new file mode 100644
index 0000000..1983e7b
--- /dev/null
+++ b/src/neuralnet/input_layer/record.cc
@@ -0,0 +1,73 @@
+/************************************************************
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements.  See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership.  The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License.  You may obtain a copy of the License at
+*
+*   http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied.  See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*************************************************************/
+
+#include "singa/neuralnet/input_layer/record.h"
+namespace singa {
+
+using std::string;
+using std::vector;
+
+void RecordInputLayer::Setup(const LayerProto& conf,
+    const vector<Layer*>& srclayers) {
+  SingleLabelRecordLayer::Setup(conf, srclayers);
+  encoded_ = conf.store_conf().encoded();
+}
+
+void RecordInputLayer::LoadRecord(const string& backend,
+    const string&path, Blob<float>* to) {
+  io::Store* store = io::OpenStore(backend, path, io::kRead);
+  string key, val;
+  CHECK(store->Read(&key, &val));
+  RecordProto image;
+  image.ParseFromString(val);
+  CHECK_EQ(to->count(), image.data_size());
+  float* ptr = to->mutable_cpu_data();
+  for (int i = 0; i< to->count(); i++)
+    ptr[i] = image.data(i);
+  delete store;
+}
+
+bool RecordInputLayer::Parse(int k, int flag, const string& key,
+    const string& value) {
+  RecordProto image;
+  image.ParseFromString(value);
+  int size = data_.count() / batchsize_;
+  if (image.data_size()) {
+    CHECK_EQ(size, image.data_size());
+    float* ptr = data_.mutable_cpu_data() + k * size;
+    for (int i = 0; i< size; i++)
+      ptr[i] = image.data(i);
+  } else if (image.pixel().size()) {
+    CHECK_EQ(size, image.pixel().size());
+    float* ptr = data_.mutable_cpu_data() + k * size;
+    string pixel = image.pixel();
+    for (int i = 0; i < size; i++)
+      ptr[i] =  static_cast<float>(static_cast<uint8_t>(pixel[i]));
+  } else {
+    LOG(ERROR) << "not pixel nor pixel";
+  }
+  if ((flag & kDeploy) == 0) {  // deploy mode does not have label
+    aux_data_.at(k) = image.label();
+  }
+  return true;
+}
+
+}  // namespace singa

http://git-wip-us.apache.org/repos/asf/incubator-singa/blob/e928ebba/src/neuralnet/input_layer/store.cc
----------------------------------------------------------------------
diff --git a/src/neuralnet/input_layer/store.cc b/src/neuralnet/input_layer/store.cc
new file mode 100644
index 0000000..0355c13
--- /dev/null
+++ b/src/neuralnet/input_layer/store.cc
@@ -0,0 +1,122 @@
+/************************************************************
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements.  See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership.  The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License.  You may obtain a copy of the License at
+*
+*   http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied.  See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*************************************************************/
+
+#include "singa/neuralnet/input_layer/store.h"
+namespace singa {
+
+StoreInputLayer::~StoreInputLayer() {
+  if (store_ != nullptr) {
+    delete store_;
+  }
+}
+
+void StoreInputLayer::Setup(const LayerProto& conf,
+    const vector<Layer*>& srclayers) {
+  InputLayer::Setup(conf, srclayers);
+  batchsize_ = conf.store_conf().batchsize();
+  if (conf.partition_dim() == 0) {
+    batchsize_ /= conf.num_partitions();
+  }
+  if (conf.store_conf().random_skip() > 0)
+    random_skip_ = rand() % conf.store_conf().random_skip();
+}
+
+void StoreInputLayer::ComputeFeature(int flag,
+    const vector<Layer*>& srclayers) {
+  string key, val;
+  if (store_ == nullptr) {
+    store_ = io::OpenStore(layer_conf_.store_conf().backend(),
+                             layer_conf_.store_conf().path(),
+                             io::kRead);
+    while (random_skip_ > 0) {
+      if (!store_->Read(&key, &val)) {
+        store_->SeekToFirst();
+        CHECK(store_->Read(&key, &val));
+      }
+      random_skip_--;
+    }
+  }
+  for (int k = 0; k < batchsize_; k++) {
+    if (!store_->Read(&key, &val)) {
+      store_->SeekToFirst();
+      CHECK(store_->Read(&key, &val));
+    }
+    // TODO(wangwei) random skip and shuffle among this mini-batch
+    Parse(k, flag, key, val);
+  }
+}
+
+void SingleLabelRecordLayer::Setup(const LayerProto& conf,
+    const vector<Layer*>& srclayers) {
+  StoreInputLayer::Setup(conf, srclayers);
+
+  vector<int> shape {batchsize_};
+  for (int s : conf.store_conf().shape())
+    shape.push_back(s);
+  data_.Reshape(shape);
+  aux_data_.resize(batchsize_);
+}
+void SingleLabelRecordLayer::ComputeFeature(int flag,
+    const vector<Layer*>& srclayers) {
+  StoreInputLayer::ComputeFeature(flag, srclayers);
+
+  auto& store_conf = layer_conf_.store_conf();
+  if (store_conf.has_mean_file() && mean_.count() == 0) {
+    mean_.Reshape(vector<int>{data_.count() / batchsize_});
+    LoadRecord(store_conf.backend(), store_conf.mean_file(), &mean_);
+  } else if (store_conf.has_mean_value() && mean_.count() == 0) {
+    mean_.Reshape(vector<int>{data_.count() / batchsize_});
+    for (int i = 0; i < data_.count() / batchsize_; i++)
+      mean_.mutable_cpu_data()[i] = store_conf.mean_value();
+  }
+  if (store_conf.has_std_file() && std_.count() == 0) {
+    std_.Reshape(vector<int>{data_.count() / batchsize_});
+    LoadRecord(store_conf.backend(), store_conf.std_file(), &std_);
+    // TODO(wangwei) check std[i] != 0
+  } else if (store_conf.has_std_value() && std_.count() == 0) {
+    std_.Reshape(vector<int>{data_.count() / batchsize_});
+    CHECK_NE(store_conf.std_value(), 0);
+    for (int i = 0; i < data_.count() / batchsize_; i++)
+      std_.mutable_cpu_data()[i] = store_conf.std_value();
+  }
+
+  if (mean_.count()) {
+    const float* mean = mean_.cpu_data();
+    for (int k = 0; k < batchsize_; k++) {
+      float* dptr = data_.mutable_cpu_data() + k * mean_.count();
+      for (int i = 0; i < mean_.count(); i++) {
+        dptr[i] -= mean[i];
+      }
+    }
+  }
+  if (std_.count()) {
+    const float* std = std_.cpu_data();
+    for (int k = 0; k < batchsize_; k++) {
+      float* dptr = data_.mutable_cpu_data() + k * std_.count();
+      for (int i = 0; i < std_.count(); i++) {
+        dptr[i] /= std[i];
+      }
+    }
+  }
+}
+
+
+}  // namespace singa

http://git-wip-us.apache.org/repos/asf/incubator-singa/blob/e928ebba/src/neuralnet/input_layer/store_input.cc
----------------------------------------------------------------------
diff --git a/src/neuralnet/input_layer/store_input.cc b/src/neuralnet/input_layer/store_input.cc
deleted file mode 100644
index 6d040e9..0000000
--- a/src/neuralnet/input_layer/store_input.cc
+++ /dev/null
@@ -1,125 +0,0 @@
-/************************************************************
-*
-* Licensed to the Apache Software Foundation (ASF) under one
-* or more contributor license agreements.  See the NOTICE file
-* distributed with this work for additional information
-* regarding copyright ownership.  The ASF licenses this file
-* to you under the Apache License, Version 2.0 (the
-* "License"); you may not use this file except in compliance
-* with the License.  You may obtain a copy of the License at
-*
-*   http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing,
-* software distributed under the License is distributed on an
-* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-* KIND, either express or implied.  See the License for the
-* specific language governing permissions and limitations
-* under the License.
-*
-*************************************************************/
-
-#include "singa/neuralnet/input_layer/store_input.h"
-namespace singa {
-
-using std::string;
-using std::vector;
-
-StoreInputLayer::~StoreInputLayer() {
-  if (store_ != nullptr) {
-    delete store_;
-  }
-}
-
-void StoreInputLayer::Setup(const LayerProto& conf,
-    const vector<Layer*>& srclayers) {
-  InputLayer::Setup(conf, srclayers);
-  batchsize_ = conf.store_conf().batchsize();
-  if (conf.partition_dim() == 0) {
-    batchsize_ /= conf.num_partitions();
-  }
-  if (conf.store_conf().random_skip() > 0)
-    random_skip_ = rand() % conf.store_conf().random_skip();
-}
-
-void StoreInputLayer::ComputeFeature(int flag,
-    const vector<Layer*>& srclayers) {
-  string key, val;
-  if (store_ == nullptr) {
-    store_ = io::OpenStore(layer_conf_.store_conf().backend(),
-                             layer_conf_.store_conf().path(),
-                             io::kRead);
-    while (random_skip_ > 0) {
-      if (!store_->Read(&key, &val)) {
-        store_->SeekToFirst();
-        CHECK(store_->Read(&key, &val));
-      }
-      random_skip_--;
-    }
-  }
-  for (int k = 0; k < batchsize_; k++) {
-    if (!store_->Read(&key, &val)) {
-      store_->SeekToFirst();
-      CHECK(store_->Read(&key, &val));
-    }
-    // TODO(wangwei) random skip and shuffle among this mini-batch
-    Parse(k, flag, key, val);
-  }
-}
-
-void SingleLabelRecordLayer::Setup(const LayerProto& conf,
-    const vector<Layer*>& srclayers) {
-  StoreInputLayer::Setup(conf, srclayers);
-
-  vector<int> shape {batchsize_};
-  for (int s : conf.store_conf().shape())
-    shape.push_back(s);
-  data_.Reshape(shape);
-  aux_data_.resize(batchsize_);
-}
-void SingleLabelRecordLayer::ComputeFeature(int flag,
-    const vector<Layer*>& srclayers) {
-  StoreInputLayer::ComputeFeature(flag, srclayers);
-
-  auto& store_conf = layer_conf_.store_conf();
-  if (store_conf.has_mean_file() && mean_.count() == 0) {
-    mean_.Reshape(vector<int>{data_.count() / batchsize_});
-    LoadRecord(store_conf.backend(), store_conf.mean_file(), &mean_);
-  } else if (store_conf.has_mean_value() && mean_.count() == 0) {
-    mean_.Reshape(vector<int>{data_.count() / batchsize_});
-    for (int i = 0; i < data_.count() / batchsize_; i++)
-      mean_.mutable_cpu_data()[i] = store_conf.mean_value();
-  }
-  if (store_conf.has_std_file() && std_.count() == 0) {
-    std_.Reshape(vector<int>{data_.count() / batchsize_});
-    LoadRecord(store_conf.backend(), store_conf.std_file(), &std_);
-    // TODO(wangwei) check std[i] != 0
-  } else if (store_conf.has_std_value() && std_.count() == 0) {
-    std_.Reshape(vector<int>{data_.count() / batchsize_});
-    CHECK_NE(store_conf.std_value(), 0);
-    for (int i = 0; i < data_.count() / batchsize_; i++)
-      std_.mutable_cpu_data()[i] = store_conf.std_value();
-  }
-
-  if (mean_.count()) {
-    const float* mean = mean_.cpu_data();
-    for (int k = 0; k < batchsize_; k++) {
-      float* dptr = data_.mutable_cpu_data() + k * mean_.count();
-      for (int i = 0; i < mean_.count(); i++) {
-        dptr[i] -= mean[i];
-      }
-    }
-  }
-  if (std_.count()) {
-    const float* std = std_.cpu_data();
-    for (int k = 0; k < batchsize_; k++) {
-      float* dptr = data_.mutable_cpu_data() + k * std_.count();
-      for (int i = 0; i < std_.count(); i++) {
-        dptr[i] /= std[i];
-      }
-    }
-  }
-}
-
-
-}  // namespace singa

http://git-wip-us.apache.org/repos/asf/incubator-singa/blob/e928ebba/src/neuralnet/neuralnet.cc
----------------------------------------------------------------------
diff --git a/src/neuralnet/neuralnet.cc b/src/neuralnet/neuralnet.cc
index eb35ed9..dc85674 100644
--- a/src/neuralnet/neuralnet.cc
+++ b/src/neuralnet/neuralnet.cc
@@ -93,6 +93,28 @@ NeuralNet::~NeuralNet() {
   for (auto layer : layers_)
     delete layer;
 }
+void NeuralNet::Load(const vector<string>& paths) {
+  unordered_map<string, Param*> params;
+  for (auto p : params_) {
+    params[p->name()] = p;
+  }
+  Load(paths, params);
+}
+void NeuralNet::Load(const vector<string>& paths,
+    const unordered_map<string, Param*>& params) {
+  for (const auto path : paths) {
+    LOG(ERROR) << "Load from checkpoint file " << path;
+    BlobProtos bps;
+    // TODO(wangwei) extend to read checkpoint from HDFS
+    ReadProtoFromBinaryFile(path.c_str(), &bps);
+    for (int i = 0; i < bps.name_size(); i++) {
+      if (params.find(bps.name(i)) != params.end()) {
+        params.at(bps.name(i))->FromProto(bps.blob(i));
+        params.at(bps.name(i))->set_version(bps.version(i));
+      }
+    }
+  }
+}
 
 /*
 std::string NeuralNet::ToAdjacency() {

http://git-wip-us.apache.org/repos/asf/incubator-singa/blob/e928ebba/src/neuralnet/output_layer/csv.cc
----------------------------------------------------------------------
diff --git a/src/neuralnet/output_layer/csv.cc b/src/neuralnet/output_layer/csv.cc
new file mode 100644
index 0000000..2f22727
--- /dev/null
+++ b/src/neuralnet/output_layer/csv.cc
@@ -0,0 +1,58 @@
+/************************************************************
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements.  See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership.  The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License.  You may obtain a copy of the License at
+*
+*   http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied.  See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*************************************************************/
+#include "singa/neuralnet/output_layer/csv.h"
+
+namespace singa {
+
+void CSVOutputLayer::Setup(const LayerProto& conf,
+    const vector<Layer*>& srclayers) {
+  OutputLayer::Setup(conf, srclayers);
+  CHECK_EQ(srclayers.size(), 1);
+}
+
+void CSVOutputLayer::ComputeFeature(int flag, const vector<Layer*>& srclayers) {
+  if (store_ == nullptr) {
+    string backend = "textfile";
+    const auto& conf = layer_conf_.store_conf();
+    if (conf.has_backend())
+      backend = conf.has_backend();
+    store_ = io::OpenStore(backend, conf.path(), io::kCreate);
+  }
+  const auto& data = srclayers.at(0)->data(this);
+  const auto& label = srclayers.at(0)->aux_data();
+  int batchsize = data.shape()[0];
+  CHECK_GT(batchsize, 0);
+  int dim = data.count() / batchsize;
+  if (label.size())
+    CHECK_EQ(label.size(), batchsize);
+  CHECK_GT(dim, 0);
+  for (int k = 0; k < batchsize; k++) {
+    std::ostringstream record;
+    if (label.size())
+      record << std::to_string(label[k]) << ",";
+    auto* dptr = data.cpu_data() + k * dim;
+    for (int i = 0; i < dim - 1; i++)
+      record << std::to_string(dptr[i]) << ",";
+    record << std::to_string(dptr[dim - 1]);
+    store_->Write(std::to_string(inst_++), record.str());
+  }
+}
+} /* singa */

http://git-wip-us.apache.org/repos/asf/incubator-singa/blob/e928ebba/src/neuralnet/output_layer/output_layer.cc
----------------------------------------------------------------------
diff --git a/src/neuralnet/output_layer/output_layer.cc b/src/neuralnet/output_layer/output_layer.cc
deleted file mode 100644
index 40b2559..0000000
--- a/src/neuralnet/output_layer/output_layer.cc
+++ /dev/null
@@ -1,26 +0,0 @@
-/************************************************************
-*
-* Licensed to the Apache Software Foundation (ASF) under one
-* or more contributor license agreements.  See the NOTICE file
-* distributed with this work for additional information
-* regarding copyright ownership.  The ASF licenses this file
-* to you under the Apache License, Version 2.0 (the
-* "License"); you may not use this file except in compliance
-* with the License.  You may obtain a copy of the License at
-* 
-*   http://www.apache.org/licenses/LICENSE-2.0
-* 
-* Unless required by applicable law or agreed to in writing,
-* software distributed under the License is distributed on an
-* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-* KIND, either express or implied.  See the License for the
-* specific language governing permissions and limitations
-* under the License.
-*
-*************************************************************/
-
-#include "singa/neuralnet/output_layer/output_layer.h"
-
-namespace singa {
-
-}  // namespace singa

http://git-wip-us.apache.org/repos/asf/incubator-singa/blob/e928ebba/src/neuralnet/output_layer/record.cc
----------------------------------------------------------------------
diff --git a/src/neuralnet/output_layer/record.cc b/src/neuralnet/output_layer/record.cc
new file mode 100644
index 0000000..759a321
--- /dev/null
+++ b/src/neuralnet/output_layer/record.cc
@@ -0,0 +1,56 @@
+/************************************************************
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements.  See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership.  The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License.  You may obtain a copy of the License at
+*
+*   http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied.  See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*************************************************************/
+#include "singa/neuralnet/output_layer/record.h"
+#include "singa/proto/common.pb.h"
+namespace singa {
+
+void RecordOutputLayer::Setup(const LayerProto& conf,
+    const vector<Layer*>& srclayers) {
+  OutputLayer::Setup(conf, srclayers);
+  CHECK_EQ(srclayers.size(), 1);
+}
+
+void RecordOutputLayer::ComputeFeature(int flag,
+    const vector<Layer*>& srclayers) {
+  if (store_ == nullptr)
+    store_ = io::OpenStore(layer_conf_.store_conf().backend(),
+        layer_conf_.store_conf().path(), io::kCreate);
+  const auto& data = srclayers.at(0)->data(this);
+  const auto& label = srclayers.at(0)->aux_data();
+  int batchsize = data.shape()[0];
+  CHECK_GT(batchsize, 0);
+  int dim = data.count() / batchsize;
+  if (label.size())
+    CHECK_EQ(label.size(), batchsize);
+  for (int k = 0; k < batchsize; k++){
+    SingleLabelImageRecord image;
+    if (label.size())
+      image.set_label(label[k]);
+    auto* dptr = data.cpu_data() + k * dim;
+    for (int i = 0; i < dim; i++)
+      image.add_data(dptr[i]);
+    std::string val;
+    image.SerializeToString(&val);
+    store_->Write(std::to_string(inst_++), val);
+  }
+  store_->Flush();
+}
+} /* singa */

http://git-wip-us.apache.org/repos/asf/incubator-singa/blob/e928ebba/src/proto/common.proto
----------------------------------------------------------------------
diff --git a/src/proto/common.proto b/src/proto/common.proto
index dd2b04c..b1ba1b6 100644
--- a/src/proto/common.proto
+++ b/src/proto/common.proto
@@ -7,9 +7,9 @@
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
-* 
+*
 *   http://www.apache.org/licenses/LICENSE-2.0
-* 
+*
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -94,12 +94,13 @@ message Record {
   optional Type type = 1 [default = kSingleLabelImage];
   optional string user_type =2;
   // configuration for
-  optional SingleLabelImageRecord image = 5;
+  optional RecordProto image = 5;
 
   extensions 101 to 200;
 }
 
-message SingleLabelImageRecord {
+// rename SingleLabelImageRecord to RecordProto
+message RecordProto {
   repeated int32 shape = 1;
   optional int32 label = 2;
   optional bytes pixel = 3;

http://git-wip-us.apache.org/repos/asf/incubator-singa/blob/e928ebba/src/proto/job.proto
----------------------------------------------------------------------
diff --git a/src/proto/job.proto b/src/proto/job.proto
index 2d6dfbe..2ccd674 100644
--- a/src/proto/job.proto
+++ b/src/proto/job.proto
@@ -318,7 +318,7 @@ message SplitProto {
 }
 
 message StoreProto {
-  required string backend = 1;
+  optional string backend = 1;
   optional string path = 2;
   optional string separator = 3 [default = ","];
   optional string mean_file = 4;
@@ -535,13 +535,17 @@ enum InitMethod {
 }
 
 enum LayerType {
-  // Data layers
+  // Input/Output layers
   //  - Load records from file, database
-  kProtoRecord = 29;
-  kCSVRecord = 30;
+  kRecordInput = 29;
+  kCSVInput = 30;
+  kCSVOutput = 32;
+  kRecordOutput = 33;
   kImagePreprocess = 31;
-  kLMDBData = 17;
   kPrefetch = 19;
+
+  // deprecated input layers
+  kLMDBData = 17;
   kShardData = 3;
   kLabel = 18;
   kMnist = 7;


Mime
View raw message