CHECK(google::protobuf::TextFormat::ParseFromString(
"clip_param { min: -1, max: 2 }", &layer_param));
ClipLayer<Dtype> layer(layer_param);
- GradientChecker<Dtype> checker(1e-2, 1e-3);
- checker.CheckGradientEltwise(&layer, this->blob_bottom_vec_,
- this->blob_top_vec_);
+ // Unfortunately, it might happen that an input value lands exactly within
+ // the discontinuity region of the Clip function. In this case the numeric
+ // gradient is likely to differ significantly (i.e. by a value larger than
+ // checker tolerance) from the computed gradient. To handle such cases, we
+ // eliminate such values from the input blob before the gradient check.
+ const Dtype epsilon = 1e-2;
+ const Dtype min_range_start = layer_param.clip_param().min() - epsilon;
+ const Dtype min_range_end = layer_param.clip_param().min() + epsilon;
+ const Dtype max_range_start = layer_param.clip_param().max() - epsilon;
+ const Dtype max_range_end = layer_param.clip_param().max() + epsilon;
+ // The input blob is owned by the NeuronLayerTest object, so we begin with
+ // creating a temporary blob and copying the input data there.
+ Blob<Dtype> temp_bottom;
+ temp_bottom.ReshapeLike(*this->blob_bottom_);
+ const Dtype* bottom_data = this->blob_bottom_->cpu_data();
+ Dtype* temp_data_mutable = temp_bottom.mutable_cpu_data();
+ for (int i = 0; i < this->blob_bottom_->count(); ++i) {
+ if (bottom_data[i] >= min_range_start &&
+ bottom_data[i] <= min_range_end) {
+ temp_data_mutable[i] = bottom_data[i] - epsilon;
+ } else if (bottom_data[i] >= max_range_start &&
+ bottom_data[i] <= max_range_end) {
+ temp_data_mutable[i] = bottom_data[i] + epsilon;
+ } else {
+ temp_data_mutable[i] = bottom_data[i];
+ }
+ }
+ vector<Blob<Dtype>*> temp_bottom_vec;
+ temp_bottom_vec.push_back(&temp_bottom);
+ GradientChecker<Dtype> checker(epsilon, 1e-3);
+ checker.CheckGradientEltwise(&layer, temp_bottom_vec, this->blob_top_vec_);
}
TYPED_TEST(NeuronLayerTest, TestReLU) {