summary | shortlog | log | commit | commitdiff | tree
raw | patch | inline | side by side (parent: adbbbfd)
raw | patch | inline | side by side (parent: adbbbfd)
author | Yangqing Jia <jiayq84@gmail.com> | |
Tue, 17 Sep 2013 22:09:50 +0000 (15:09 -0700) | ||
committer | Yangqing Jia <jiayq84@gmail.com> | |
Tue, 17 Sep 2013 22:09:50 +0000 (15:09 -0700) |
src/caffeine/test/test_gradient_check_util.cpp | [new file with mode: 0644] | patch | blob |
src/caffeine/test/test_gradient_check_util.hpp | [new file with mode: 0644] | patch | blob |
diff --git a/src/caffeine/test/test_gradient_check_util.cpp b/src/caffeine/test/test_gradient_check_util.cpp
--- /dev/null
@@ -0,0 +1,76 @@
+#include <cmath>
+#include <gtest/gtest.h>
+#include "caffeine/test/test_gradient_check_util.hpp"
+
+namespace caffeine {
+
+template <typename Dtype>
+void GradientChecker<Dtype>::CheckGradient(Layer<Dtype>& layer,
+ vector<Blob<Dtype>*>& bottom, vector<Blob<Dtype>*>& top,
+ int check_bottom) {
+ layer.SetUp(bottom, &top);
+ // 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 blobs
+ for (int i = 0; i < blobs_to_check.size(); ++i) {
+ Blob<Dtype>* current_blob = blobs_to_check[i];
+ // go through the values
+ for (int j = 0; j < current_blob->count(); ++j) {
+ // First, obtain the original data
+ layer.Forward(bottom, &top);
+ Dtype computed_objective = GetObjAndGradient(top);
+ // Get any additional loss from the layer
+ computed_objective += layer.Backward(top, true, &bottom);
+ Dtype computed_gradient = current_blob->cpu_diff()[i];
+ // compute score by adding stepsize
+ current_blob->mutable_cpu_data()[i] += stepsize_;
+ layer.Forward(bottom, &top);
+ Dtype positive_objective = GetObjAndGradient(top);
+ positive_objective += layer.Backward(top, true, &bottom);
+ // compute score by subtracting stepsize
+ current_blob->mutable_cpu_data()[i] -= stepsize_ * 2;
+ layer.Forward(bottom, &top);
+ Dtype negative_objective = GetObjAndGradient(top);
+ negative_objective += layer.Backward(top, true, &bottom);
+ // Recover stepsize
+ current_blob->mutable_cpu_data()[i] += stepsize_;
+ Dtype estimated_gradient = (positive_objective - negative_objective) /
+ stepsize_ / 2.;
+ EXPECT_GT(computed_gradient, estimated_gradient - threshold_);
+ EXPECT_LT(computed_gradient, estimated_gradient + threshold_);
+ }
+ }
+}
+
+template <typename Dtype>
+Dtype GradientChecker<Dtype>::GetObjAndGradient(vector<Blob<Dtype>*>& top) {
+ Dtype loss = 0;
+ 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) * count);
+ }
+ loss /= 2.;
+ return loss;
+}
+
+INSTANTIATE_CLASS(GradientChecker);
+
+} // namespace caffeine
\ No newline at end of file
diff --git a/src/caffeine/test/test_gradient_check_util.hpp b/src/caffeine/test/test_gradient_check_util.hpp
--- /dev/null
@@ -0,0 +1,31 @@
+#ifndef CAFFEINE_TEST_GRADIENT_CHECK_UTIL_H_
+#define CAFFEINE_TEST_GRADIENT_CHECK_UTIL_H_
+
+#include "caffeine/layer.hpp"
+
+namespace caffeine {
+
+// The gradient checker adds a L2 normalization loss function on top of the
+// top blobs, and checks the gradient.
+template <typename Dtype>
+class GradientChecker {
+ public:
+ GradientChecker(const Dtype stepsize, const Dtype threshold)
+ : stepsize_(stepsize), threshold_(threshold) {};
+ // Checks the gradient of a layer, with provided bottom layers and top
+ // layers. The gradient checker will check the gradient with respect to
+ // the parameters of the layer, as well as the input blobs if check_through
+ // is set True.
+ // Note that after the gradient check, we do not guarantee that the data
+ // stored in the layer parameters and the blobs.
+ void CheckGradient(Layer<Dtype>& layer, vector<Blob<Dtype>*>& bottom,
+ vector<Blob<Dtype>*>& top, int check_bottom = -1);
+ protected:
+ Dtype GetObjAndGradient(vector<Blob<Dtype>*>& top);
+ Dtype stepsize_;
+ Dtype threshold_;
+};
+
+} // namespace caffeine
+
+#endif // CAFFEINE_TEST_GRADIENT_CHECK_UTIL_H_
\ No newline at end of file