changed the test structure
authorYangqing Jia <jiayq84@gmail.com>
Thu, 19 Sep 2013 22:19:50 +0000 (15:19 -0700)
committerYangqing Jia <jiayq84@gmail.com>
Thu, 19 Sep 2013 22:19:50 +0000 (15:19 -0700)
16 files changed:
.gitignore
src/Makefile
src/caffeine/test/test_blob.cpp
src/caffeine/test/test_caffeine_main.hpp [new file with mode: 0644]
src/caffeine/test/test_common.cpp
src/caffeine/test/test_filler.cpp
src/caffeine/test/test_gradient_check_util.cpp [deleted file]
src/caffeine/test/test_gradient_check_util.hpp
src/caffeine/test/test_im2col_layer.cpp
src/caffeine/test/test_innerproduct_layer.cpp
src/caffeine/test/test_lrn_layer.cpp
src/caffeine/test/test_neuron_layer.cpp
src/caffeine/test/test_padding_layer.cpp
src/caffeine/test/test_platform.cpp [moved from src/caffeine/test/test_caffeine_main.cpp with 71% similarity]
src/caffeine/test/test_syncedmem.cpp
src/caffeine/test/test_util_blas.cpp

index 792fb9c..f4489a6 100644 (file)
@@ -18,7 +18,7 @@
 *_pb2.py
 
 # test files
-src/test_caffeine
+*.testbin
 
 # vim swp files
 *.swp
index 3633c71..22734be 100644 (file)
@@ -10,7 +10,8 @@ NAME := lib$(PROJECT).so
 TEST_NAME := test_$(PROJECT)
 CXX_SRCS := $(shell find caffeine ! -name "test_*.cpp" -name "*.cpp")
 CU_SRCS := $(shell find caffeine -name "*.cu")
-TEST_SRCS := $(shell find caffeine -name "test_*.cpp") gtest/gtest-all.cpp
+TEST_SRCS := $(shell find caffeine -name "test_*.cpp")
+GTEST_SRC := gtest/gtest-all.cpp
 PROTO_SRCS := $(wildcard caffeine/proto/*.proto)
 PROTO_GEN_HEADER := ${PROTO_SRCS:.proto=.pb.h}
 PROTO_GEN_CC := ${PROTO_SRCS:.proto=.pb.cc}
@@ -20,6 +21,8 @@ CU_OBJS := ${CU_SRCS:.cu=.o}
 PROTO_OBJS := ${PROTO_SRCS:.proto=.pb.o}
 OBJS := $(PROTO_OBJS) $(CXX_OBJS) $(CU_OBJS)
 TEST_OBJS := ${TEST_SRCS:.cpp=.o}
+GTEST_OBJ := ${GTEST_SRC:.cpp=.o}
+TEST_BINS := ${TEST_OBJS:.o=.testbin}
 
 CUDA_DIR := /usr/local/cuda
 CUDA_ARCH := -arch=sm_20
@@ -49,10 +52,10 @@ all: $(NAME)
 linecount: clean
        cloc --read-lang-def=caffeine.cloc caffeine/
 
-test: $(TEST_NAME)
-  
-$(TEST_NAME): $(OBJS) $(TEST_OBJS)
-       $(CXX) $(OBJS) $(TEST_OBJS) -o $(TEST_NAME) $(LDFLAGS) $(WARNINGS)
+test: $(OBJS) $(GTEST_OBJ) $(TEST_BINS)
+
+$(TEST_BINS): %.test : %.o
+       $(CXX) $< $(OBJS) $(GTEST_OBJ) -o $@ $(LDFLAGS) $(WARNINGS)
 
 $(NAME): $(PROTO_GEN_CC) $(OBJS)
        $(LINK) -shared $(OBJS) -o $(NAME)
@@ -64,8 +67,8 @@ $(PROTO_GEN_CC): $(PROTO_SRCS)
        protoc $(PROTO_SRCS) --cpp_out=. --python_out=.
 
 clean:
-       @- $(RM) $(NAME) $(TEST_NAME)
-       @- $(RM) $(OBJS) $(TEST_OBJS)
+       @- $(RM) $(NAME) $(TEST_BINS)
+       @- $(RM) $(OBJS) $(TEST_OBJS) 
        @- $(RM) $(PROTO_GEN_HEADER) $(PROTO_GEN_CC) $(PROTO_GEN_PY)
 
 distclean: clean
index 308d6bd..e2daec5 100644 (file)
@@ -6,6 +6,8 @@
 #include "caffeine/blob.hpp"
 #include "caffeine/filler.hpp"
 
+#include "caffeine/test/test_caffeine_main.hpp"
+
 namespace caffeine {
   
 template <typename Dtype>
diff --git a/src/caffeine/test/test_caffeine_main.hpp b/src/caffeine/test/test_caffeine_main.hpp
new file mode 100644 (file)
index 0000000..536dca9
--- /dev/null
@@ -0,0 +1,43 @@
+// The main caffeine test code. Your test cpp code should include this hpp
+// to allow a main function to be compiled into the binary.
+#ifndef CAFFEINE_TEST_TEST_CAFFEINE_MAIN_HPP_
+#define CAFFEINE_TEST_TEST_CAFFEINE_MAIN_HPP_
+
+#include <cstdlib>
+#include <cstdio>
+#include <iostream>
+
+#include <cuda_runtime.h>
+#include <glog/logging.h>
+#include <gtest/gtest.h>
+
+namespace caffeine {
+
+cudaDeviceProp CAFFEINE_TEST_CUDA_PROP;
+
+}  // namespace caffeine
+
+using namespace caffeine;
+using namespace std;
+
+int main(int argc, char** argv) {
+  ::testing::InitGoogleTest(&argc, argv);
+  ::google::InitGoogleLogging(argv[0]);
+  // Before starting testing, let's first print out a few cuda defice info.
+  int device;
+  cudaGetDeviceCount(&device);
+  cout << "Cuda number of devices: " << device << endl;
+  if (argc > 1) {
+    // Use the given device
+    device = atoi(argv[1]);
+    cudaSetDevice(device);
+    cout << "Setting to use device " << device << endl;
+  }
+  cudaGetDevice(&device);
+  cout << "Current device id: " << device << endl;
+  cudaGetDeviceProperties(&CAFFEINE_TEST_CUDA_PROP, device);
+  // invoke the test.
+  return RUN_ALL_TESTS();
+}
+
+#endif  // CAFFEINE_TEST_TEST_CAFFEINE_MAIN_HPP_
index edc6c1f..8f7db2c 100644 (file)
@@ -5,6 +5,8 @@
 #include "caffeine/common.hpp"
 #include "caffeine/syncedmem.hpp"
 
+#include "caffeine/test/test_caffeine_main.hpp"
+
 namespace caffeine {
 
 class CommonTest : public ::testing::Test {};
index 61dfdfe..6a66f8e 100644 (file)
@@ -4,6 +4,8 @@
 #include "gtest/gtest.h"
 #include "caffeine/filler.hpp"
 
+#include "caffeine/test/test_caffeine_main.hpp"
+
 namespace caffeine {
 
 typedef ::testing::Types<float, double> Dtypes;
diff --git a/src/caffeine/test/test_gradient_check_util.cpp b/src/caffeine/test/test_gradient_check_util.cpp
deleted file mode 100644 (file)
index 2bea22b..0000000
+++ /dev/null
@@ -1,124 +0,0 @@
-#include <algorithm>
-#include <cmath>
-#include <glog/logging.h>
-#include <gtest/gtest.h>
-#include "caffeine/test/test_gradient_check_util.hpp"
-
-using std::max;
-
-namespace caffeine {
-
-template <typename Dtype>
-void GradientChecker<Dtype>::CheckGradientSingle(Layer<Dtype>& layer,
-    vector<Blob<Dtype>*>& bottom, vector<Blob<Dtype>*>& top,
-    int check_bottom, int top_id, int top_data_id) {
-  // First, figure out what blobs we need to check against.
-  vector<Blob<Dtype>*> blobs_to_check;
-  for (int i = 0; i < layer.params().size(); ++i) {
-    blobs_to_check.push_back(&layer.params()[i]);
-  }
-  if (check_bottom < 0) {
-    for (int i = 0; i < bottom.size(); ++i) {
-      blobs_to_check.push_back(bottom[i]);
-    }
-  } else {
-    CHECK(check_bottom < bottom.size());
-    blobs_to_check.push_back(bottom[check_bottom]);
-  }
-  // go through the bottom and parameter blobs
-  //LOG(ERROR) << "Checking " << blobs_to_check.size() << " blobs.";
-  for (int blobid = 0; blobid < blobs_to_check.size(); ++blobid) {
-    Blob<Dtype>* current_blob = blobs_to_check[blobid];
-    //LOG(ERROR) << "Blob " << blobid << ": checking " << current_blob->count()
-    //    << " parameters.";
-    // go through the values
-    for (int feat_id = 0; feat_id < current_blob->count(); ++feat_id) {
-      // First, obtain the original data
-      Caffeine::set_random_seed(seed_);
-      layer.Forward(bottom, &top);
-      Dtype computed_objective = GetObjAndGradient(top, top_id, top_data_id);
-      // Get any additional loss from the layer
-      computed_objective += layer.Backward(top, true, &bottom);
-      Dtype computed_gradient = current_blob->cpu_diff()[feat_id];
-      // compute score by adding stepsize
-      current_blob->mutable_cpu_data()[feat_id] += stepsize_;
-      Caffeine::set_random_seed(seed_);
-      layer.Forward(bottom, &top);
-      Dtype positive_objective = GetObjAndGradient(top, top_id, top_data_id);
-      positive_objective += layer.Backward(top, true, &bottom);
-      // compute score by subtracting stepsize
-      current_blob->mutable_cpu_data()[feat_id] -= stepsize_ * 2;
-      Caffeine::set_random_seed(seed_);
-      layer.Forward(bottom, &top);
-      Dtype negative_objective = GetObjAndGradient(top, top_id, top_data_id);
-      negative_objective += layer.Backward(top, true, &bottom);
-      // Recover stepsize
-      current_blob->mutable_cpu_data()[feat_id] += stepsize_;
-      Dtype estimated_gradient = (positive_objective - negative_objective) /
-          stepsize_ / 2.;
-      Dtype feature = current_blob->cpu_data()[feat_id];
-      //LOG(ERROR) << "debug: " << current_blob->cpu_data()[feat_id] << " "
-      //    << current_blob->cpu_diff()[feat_id];
-      if (kink_ - kink_range_ > feature || feature > kink_ + kink_range_) {
-        // We check relative accuracy, but for too small values, we threshold
-        // the scale factor by 1.
-        Dtype scale = max(max(fabs(computed_gradient), fabs(estimated_gradient)),
-            1.);
-        EXPECT_GT(computed_gradient, estimated_gradient - threshold_ * scale);
-        EXPECT_LT(computed_gradient, estimated_gradient + threshold_ * scale);
-      }
-      //LOG(ERROR) << "Feature: " << current_blob->cpu_data()[feat_id];
-      //LOG(ERROR) << "computed gradient: " << computed_gradient
-      //    << " estimated_gradient: " << estimated_gradient;
-    }
-  }
-}
-
-template <typename Dtype>
-void GradientChecker<Dtype>::CheckGradientExhaustive(Layer<Dtype>& layer,
-    vector<Blob<Dtype>*>& bottom, vector<Blob<Dtype>*>& top, int check_bottom) {
-  layer.SetUp(bottom, &top);
-  //LOG(ERROR) << "Exhaustive Mode.";
-  for (int i = 0; i < top.size(); ++i) {
-    //LOG(ERROR) << "Exhaustive: blob " << i << " size " << top[i]->count();
-    for (int j = 0; j < top[i]->count(); ++j) {
-      //LOG(ERROR) << "Exhaustive: blob " << i << " data " << j;
-      CheckGradientSingle(layer, bottom, top, check_bottom, i, j);
-    }
-  }
-}
-
-template <typename Dtype>
-Dtype GradientChecker<Dtype>::GetObjAndGradient(vector<Blob<Dtype>*>& top,
-    int top_id, int top_data_id) {
-  Dtype loss = 0;
-  if (top_id < 0) {
-    // the loss will be half of the sum of squares of all outputs
-    for (int i = 0; i < top.size(); ++i) {
-      Blob<Dtype>* top_blob = top[i];
-      const Dtype* top_blob_data = top_blob->cpu_data();
-      Dtype* top_blob_diff = top_blob->mutable_cpu_diff();
-      int count = top_blob->count();
-      for (int j = 0; j < count; ++j) {
-        loss += top_blob_data[j] * top_blob_data[j];
-      }
-      // set the diff: simply the data.
-      memcpy(top_blob_diff, top_blob_data, sizeof(Dtype) * top_blob->count());
-    }
-    loss /= 2.;
-  } else {
-    // the loss will be the top_data_id-th element in the top_id-th blob.
-    for (int i = 0; i < top.size(); ++i) {
-      Blob<Dtype>* top_blob = top[i];
-      Dtype* top_blob_diff = top_blob->mutable_cpu_diff();
-      memset(top_blob_diff, 0, sizeof(Dtype) * top_blob->count());
-    }
-    loss = top[top_id]->cpu_data()[top_data_id];
-    top[top_id]->mutable_cpu_diff()[top_data_id] = 1.;
-  }
-  return loss;
-}
-
-INSTANTIATE_CLASS(GradientChecker);
-
-}  // namespace caffeine
index cb55766..6b77336 100644 (file)
@@ -1,8 +1,14 @@
 #ifndef CAFFEINE_TEST_GRADIENT_CHECK_UTIL_H_
 #define CAFFEINE_TEST_GRADIENT_CHECK_UTIL_H_
 
+#include <algorithm>
+#include <cmath>
+#include <glog/logging.h>
+#include <gtest/gtest.h>
 #include "caffeine/layer.hpp"
 
+using std::max;
+
 namespace caffeine {
 
 // The gradient checker adds a L2 normalization loss function on top of the
@@ -43,6 +49,121 @@ class GradientChecker {
   Dtype kink_range_;
 };
 
+
+// Detailed implementations are as follows.
+
+
+template <typename Dtype>
+void GradientChecker<Dtype>::CheckGradientSingle(Layer<Dtype>& layer,
+    vector<Blob<Dtype>*>& bottom, vector<Blob<Dtype>*>& top,
+    int check_bottom, int top_id, int top_data_id) {
+  // First, figure out what blobs we need to check against.
+  vector<Blob<Dtype>*> blobs_to_check;
+  for (int i = 0; i < layer.params().size(); ++i) {
+    blobs_to_check.push_back(&layer.params()[i]);
+  }
+  if (check_bottom < 0) {
+    for (int i = 0; i < bottom.size(); ++i) {
+      blobs_to_check.push_back(bottom[i]);
+    }
+  } else {
+    CHECK(check_bottom < bottom.size());
+    blobs_to_check.push_back(bottom[check_bottom]);
+  }
+  // go through the bottom and parameter blobs
+  //LOG(ERROR) << "Checking " << blobs_to_check.size() << " blobs.";
+  for (int blobid = 0; blobid < blobs_to_check.size(); ++blobid) {
+    Blob<Dtype>* current_blob = blobs_to_check[blobid];
+    //LOG(ERROR) << "Blob " << blobid << ": checking " << current_blob->count()
+    //    << " parameters.";
+    // go through the values
+    for (int feat_id = 0; feat_id < current_blob->count(); ++feat_id) {
+      // First, obtain the original data
+      Caffeine::set_random_seed(seed_);
+      layer.Forward(bottom, &top);
+      Dtype computed_objective = GetObjAndGradient(top, top_id, top_data_id);
+      // Get any additional loss from the layer
+      computed_objective += layer.Backward(top, true, &bottom);
+      Dtype computed_gradient = current_blob->cpu_diff()[feat_id];
+      // compute score by adding stepsize
+      current_blob->mutable_cpu_data()[feat_id] += stepsize_;
+      Caffeine::set_random_seed(seed_);
+      layer.Forward(bottom, &top);
+      Dtype positive_objective = GetObjAndGradient(top, top_id, top_data_id);
+      positive_objective += layer.Backward(top, true, &bottom);
+      // compute score by subtracting stepsize
+      current_blob->mutable_cpu_data()[feat_id] -= stepsize_ * 2;
+      Caffeine::set_random_seed(seed_);
+      layer.Forward(bottom, &top);
+      Dtype negative_objective = GetObjAndGradient(top, top_id, top_data_id);
+      negative_objective += layer.Backward(top, true, &bottom);
+      // Recover stepsize
+      current_blob->mutable_cpu_data()[feat_id] += stepsize_;
+      Dtype estimated_gradient = (positive_objective - negative_objective) /
+          stepsize_ / 2.;
+      Dtype feature = current_blob->cpu_data()[feat_id];
+      //LOG(ERROR) << "debug: " << current_blob->cpu_data()[feat_id] << " "
+      //    << current_blob->cpu_diff()[feat_id];
+      if (kink_ - kink_range_ > feature || feature > kink_ + kink_range_) {
+        // We check relative accuracy, but for too small values, we threshold
+        // the scale factor by 1.
+        Dtype scale = max(max(fabs(computed_gradient), fabs(estimated_gradient)),
+            1.);
+        EXPECT_GT(computed_gradient, estimated_gradient - threshold_ * scale);
+        EXPECT_LT(computed_gradient, estimated_gradient + threshold_ * scale);
+      }
+      //LOG(ERROR) << "Feature: " << current_blob->cpu_data()[feat_id];
+      //LOG(ERROR) << "computed gradient: " << computed_gradient
+      //    << " estimated_gradient: " << estimated_gradient;
+    }
+  }
+}
+
+template <typename Dtype>
+void GradientChecker<Dtype>::CheckGradientExhaustive(Layer<Dtype>& layer,
+    vector<Blob<Dtype>*>& bottom, vector<Blob<Dtype>*>& top, int check_bottom) {
+  layer.SetUp(bottom, &top);
+  //LOG(ERROR) << "Exhaustive Mode.";
+  for (int i = 0; i < top.size(); ++i) {
+    //LOG(ERROR) << "Exhaustive: blob " << i << " size " << top[i]->count();
+    for (int j = 0; j < top[i]->count(); ++j) {
+      //LOG(ERROR) << "Exhaustive: blob " << i << " data " << j;
+      CheckGradientSingle(layer, bottom, top, check_bottom, i, j);
+    }
+  }
+}
+
+template <typename Dtype>
+Dtype GradientChecker<Dtype>::GetObjAndGradient(vector<Blob<Dtype>*>& top,
+    int top_id, int top_data_id) {
+  Dtype loss = 0;
+  if (top_id < 0) {
+    // the loss will be half of the sum of squares of all outputs
+    for (int i = 0; i < top.size(); ++i) {
+      Blob<Dtype>* top_blob = top[i];
+      const Dtype* top_blob_data = top_blob->cpu_data();
+      Dtype* top_blob_diff = top_blob->mutable_cpu_diff();
+      int count = top_blob->count();
+      for (int j = 0; j < count; ++j) {
+        loss += top_blob_data[j] * top_blob_data[j];
+      }
+      // set the diff: simply the data.
+      memcpy(top_blob_diff, top_blob_data, sizeof(Dtype) * top_blob->count());
+    }
+    loss /= 2.;
+  } else {
+    // the loss will be the top_data_id-th element in the top_id-th blob.
+    for (int i = 0; i < top.size(); ++i) {
+      Blob<Dtype>* top_blob = top[i];
+      Dtype* top_blob_diff = top_blob->mutable_cpu_diff();
+      memset(top_blob_diff, 0, sizeof(Dtype) * top_blob->count());
+    }
+    loss = top[top_id]->cpu_data()[top_data_id];
+    top[top_id]->mutable_cpu_diff()[top_data_id] = 1.;
+  }
+  return loss;
+}
+
 }  // namespace caffeine
 
 #endif  // CAFFEINE_TEST_GRADIENT_CHECK_UTIL_H_
index d96d011..7456dfb 100644 (file)
@@ -8,6 +8,7 @@
 #include "caffeine/vision_layers.hpp"
 #include "caffeine/test/test_gradient_check_util.hpp"
 
+#include "caffeine/test/test_caffeine_main.hpp"
 
 namespace caffeine {
 
index 9c883db..357e6b3 100644 (file)
@@ -8,6 +8,8 @@
 #include "caffeine/vision_layers.hpp"
 #include "caffeine/test/test_gradient_check_util.hpp"
 
+#include "caffeine/test/test_caffeine_main.hpp"
+
 namespace caffeine {
 
 extern cudaDeviceProp CAFFEINE_TEST_CUDA_PROP;
index b2c4c26..49a8ee4 100644 (file)
@@ -10,6 +10,8 @@
 #include "caffeine/vision_layers.hpp"
 #include "caffeine/test/test_gradient_check_util.hpp"
 
+#include "caffeine/test/test_caffeine_main.hpp"
+
 using std::min;
 using std::max;
 
index b4254fe..f73198b 100644 (file)
@@ -8,6 +8,7 @@
 #include "caffeine/vision_layers.hpp"
 #include "caffeine/test/test_gradient_check_util.hpp"
 
+#include "caffeine/test/test_caffeine_main.hpp"
 
 namespace caffeine {
 
index 03bf61f..896c66e 100644 (file)
@@ -8,6 +8,7 @@
 #include "caffeine/vision_layers.hpp"
 #include "caffeine/test/test_gradient_check_util.hpp"
 
+#include "caffeine/test/test_caffeine_main.hpp"
 
 namespace caffeine {
 
similarity index 71%
rename from src/caffeine/test/test_caffeine_main.cpp
rename to src/caffeine/test/test_platform.cpp
index 2c8042c..ada7e0e 100644 (file)
@@ -5,32 +5,15 @@
 #include <cuda_runtime.h>
 #include <glog/logging.h>
 #include <gtest/gtest.h>
+#include "caffeine/test/test_caffeine_main.hpp"
 
 namespace caffeine {
 
-cudaDeviceProp CAFFEINE_TEST_CUDA_PROP;
+extern cudaDeviceProp CAFFEINE_TEST_CUDA_PROP;
 
-}  // namespace caffeine
-
-using namespace caffeine;
-using namespace std;
+class PlatformTest : public ::testing::Test {};
 
-int main(int argc, char** argv) {
-  ::testing::InitGoogleTest(&argc, argv);
-  ::google::InitGoogleLogging(argv[0]);
-  // Before starting testing, let's first print out a few cuda defice info.
-  int device;
-  cudaGetDeviceCount(&device);
-  cout << "Cuda number of devices: " << device << endl;
-  if (argc > 1) {
-    // Use the given device
-    device = atoi(argv[1]);
-    cudaSetDevice(device);
-    cout << "Setting to use device " << device << endl;
-  }
-  cudaGetDevice(&device);
-  cout << "Current device id: " << device << endl;
-  cudaGetDeviceProperties(&CAFFEINE_TEST_CUDA_PROP, device);
+TEST_F(PlatformTest, TestInitialization) {
   printf("Major revision number:         %d\n",  CAFFEINE_TEST_CUDA_PROP.major);
   printf("Minor revision number:         %d\n",  CAFFEINE_TEST_CUDA_PROP.minor);
   printf("Name:                          %s\n",  CAFFEINE_TEST_CUDA_PROP.name);
@@ -50,7 +33,7 @@ int main(int argc, char** argv) {
   printf("Concurrent copy and execution: %s\n",  (CAFFEINE_TEST_CUDA_PROP.deviceOverlap ? "Yes" : "No"));
   printf("Number of multiprocessors:     %d\n",  CAFFEINE_TEST_CUDA_PROP.multiProcessorCount);
   printf("Kernel execution timeout:      %s\n",  (CAFFEINE_TEST_CUDA_PROP.kernelExecTimeoutEnabled ? "Yes" : "No"));
-  
-  return RUN_ALL_TESTS();
+  EXPECT_TRUE(true);
 }
 
+}  // namespace caffeine
index 76d22a5..a99552d 100644 (file)
@@ -5,6 +5,7 @@
 #include "caffeine/common.hpp"
 #include "caffeine/syncedmem.hpp"
 
+#include "caffeine/test/test_caffeine_main.hpp"
 
 namespace caffeine {
 
index cdfe80f..e9c09bb 100644 (file)
@@ -7,6 +7,8 @@
 #include "caffeine/blob.hpp"
 #include "caffeine/util/math_functions.hpp"
 
+#include "caffeine/test/test_caffeine_main.hpp"
+
 namespace caffeine {
 
 extern cudaDeviceProp CAFFEINE_TEST_CUDA_PROP;