long-standing issue with how this is handled in loss layers (esp.
EuclideanLossLayer)
virtual Dtype Forward_gpu(const vector<Blob<Dtype>*>& bottom,
vector<Blob<Dtype>*>* top);
virtual void Backward_cpu(const vector<Blob<Dtype>*>& top,
- const bool propagate_down, vector<Blob<Dtype>*>* bottom);
+ const vector<bool>& propagate_down, vector<Blob<Dtype>*>* bottom);
virtual void Backward_gpu(const vector<Blob<Dtype>*>& top,
- const bool propagate_down, vector<Blob<Dtype>*>* bottom);
+ const vector<bool>& propagate_down, vector<Blob<Dtype>*>* bottom);
virtual void SaveBlobs();
std::string file_name_;
virtual Dtype Forward_gpu(const vector<Blob<Dtype>*>& bottom,
vector<Blob<Dtype>*>* top);
virtual void Backward_cpu(const vector<Blob<Dtype>*>& top,
- const bool propagate_down, vector<Blob<Dtype>*>* bottom);
+ const vector<bool>& propagate_down, vector<Blob<Dtype>*>* bottom) {}
virtual void Backward_gpu(const vector<Blob<Dtype>*>& top,
- const bool propagate_down, vector<Blob<Dtype>*>* bottom);
+ const vector<bool>& propagate_down, vector<Blob<Dtype>*>* bottom) {}
virtual void LoadHDF5FileData(const char* filename);
std::vector<std::string> hdf_filenames_;
virtual Dtype Forward_gpu(const vector<Blob<Dtype>*>& bottom,
vector<Blob<Dtype>*>* top);
virtual void Backward_cpu(const vector<Blob<Dtype>*>& top,
- const bool propagate_down, vector<Blob<Dtype>*>* bottom) { return; }
+ const vector<bool>& propagate_down, vector<Blob<Dtype>*>* bottom) {}
virtual void Backward_gpu(const vector<Blob<Dtype>*>& top,
- const bool propagate_down, vector<Blob<Dtype>*>* bottom) { return; }
+ const vector<bool>& propagate_down, vector<Blob<Dtype>*>* bottom) {}
virtual void CreatePrefetchThread();
virtual void JoinPrefetchThread();
virtual Dtype Forward_cpu(const vector<Blob<Dtype>*>& bottom,
vector<Blob<Dtype>*>* top);
virtual void Backward_cpu(const vector<Blob<Dtype>*>& top,
- const bool propagate_down, vector<Blob<Dtype>*>* bottom) { return; }
+ const vector<bool>& propagate_down, vector<Blob<Dtype>*>* bottom) {}
virtual void Backward_gpu(const vector<Blob<Dtype>*>& top,
- const bool propagate_down, vector<Blob<Dtype>*>* bottom) { return; }
+ const vector<bool>& propagate_down, vector<Blob<Dtype>*>* bottom) {}
vector<shared_ptr<Filler<Dtype> > > fillers_;
vector<bool> refill_;
virtual Dtype Forward_gpu(const vector<Blob<Dtype>*>& bottom,
vector<Blob<Dtype>*>* top);
virtual void Backward_cpu(const vector<Blob<Dtype>*>& top,
- const bool propagate_down, vector<Blob<Dtype>*>* bottom) { return; }
+ const vector<bool>& propagate_down, vector<Blob<Dtype>*>* bottom) {}
virtual void Backward_gpu(const vector<Blob<Dtype>*>& top,
- const bool propagate_down, vector<Blob<Dtype>*>* bottom) { return; }
+ const vector<bool>& propagate_down, vector<Blob<Dtype>*>* bottom) {}
virtual void ShuffleImages();
virtual Dtype Forward_cpu(const vector<Blob<Dtype>*>& bottom,
vector<Blob<Dtype>*>* top);
virtual void Backward_cpu(const vector<Blob<Dtype>*>& top,
- const bool propagate_down, vector<Blob<Dtype>*>* bottom) { return; }
+ const vector<bool>& propagate_down, vector<Blob<Dtype>*>* bottom) {}
virtual void Backward_gpu(const vector<Blob<Dtype>*>& top,
- const bool propagate_down, vector<Blob<Dtype>*>* bottom) { return; }
+ const vector<bool>& propagate_down, vector<Blob<Dtype>*>* bottom) {}
Dtype* data_;
Dtype* labels_;
virtual Dtype Forward_gpu(const vector<Blob<Dtype>*>& bottom,
vector<Blob<Dtype>*>* top);
virtual void Backward_cpu(const vector<Blob<Dtype>*>& top,
- const bool propagate_down, vector<Blob<Dtype>*>* bottom) { return; }
+ const vector<bool>& propagate_down, vector<Blob<Dtype>*>* bottom) {}
virtual void Backward_gpu(const vector<Blob<Dtype>*>& top,
- const bool propagate_down, vector<Blob<Dtype>*>* bottom) { return; }
+ const vector<bool>& propagate_down, vector<Blob<Dtype>*>* bottom) {}
virtual void CreatePrefetchThread();
virtual void JoinPrefetchThread();
inline Dtype Forward(const vector<Blob<Dtype>*>& bottom,
vector<Blob<Dtype>*>* top);
inline void Backward(const vector<Blob<Dtype>*>& top,
- const bool propagate_down,
+ const vector<bool>& propagate_down,
vector<Blob<Dtype>*>* bottom);
// Returns the vector of blobs.
// Backward functions: compute the gradients for any parameters and
// for the bottom blobs if propagate_down is true.
virtual void Backward_cpu(const vector<Blob<Dtype>*>& top,
- const bool propagate_down,
+ const vector<bool>& propagate_down,
vector<Blob<Dtype>*>* bottom) = 0;
virtual void Backward_gpu(const vector<Blob<Dtype>*>& top,
- const bool propagate_down,
+ const vector<bool>& propagate_down,
vector<Blob<Dtype>*>* bottom) {
// LOG(WARNING) << "Using CPU code as backup.";
Backward_cpu(top, propagate_down, bottom);
template <typename Dtype>
inline void Layer<Dtype>::Backward(const vector<Blob<Dtype>*>& top,
- const bool propagate_down,
+ const vector<bool>& propagate_down,
vector<Blob<Dtype>*>* bottom) {
switch (Caffe::mode()) {
case Caffe::CPU:
virtual inline LayerParameter_LayerType type() const {
return LayerParameter_LayerType_SOFTMAX_LOSS;
}
- virtual inline int ExactNumBottomBlobs() const { return 2; }
virtual inline int MaxTopBlobs() const { return 2; }
protected:
virtual Dtype Forward_gpu(const vector<Blob<Dtype>*>& bottom,
vector<Blob<Dtype>*>* top);
virtual void Backward_cpu(const vector<Blob<Dtype>*>& top,
- const bool propagate_down, vector<Blob<Dtype>*>* bottom);
+ const vector<bool>& propagate_down, vector<Blob<Dtype>*>* bottom);
virtual void Backward_gpu(const vector<Blob<Dtype>*>& top,
- const bool propagate_down, vector<Blob<Dtype>*>* bottom);
+ const vector<bool>& propagate_down, vector<Blob<Dtype>*>* bottom);
shared_ptr<SoftmaxLayer<Dtype> > softmax_layer_;
// prob stores the output probability of the layer.
virtual Dtype Forward_gpu(const vector<Blob<Dtype>*>& bottom,
vector<Blob<Dtype>*>* top);
virtual void Backward_cpu(const vector<Blob<Dtype>*>& top,
- const bool propagate_down, vector<Blob<Dtype>*>* bottom);
+ const vector<bool>& propagate_down, vector<Blob<Dtype>*>* bottom);
virtual void Backward_gpu(const vector<Blob<Dtype>*>& top,
- const bool propagate_down, vector<Blob<Dtype>*>* bottom);
+ const vector<bool>& propagate_down, vector<Blob<Dtype>*>* bottom);
shared_ptr<SigmoidLayer<Dtype> > sigmoid_layer_;
// sigmoid_output stores the output of the sigmoid layer.
protected:
virtual Dtype Forward_cpu(const vector<Blob<Dtype>*>& bottom,
vector<Blob<Dtype>*>* top);
+ virtual Dtype Forward_gpu(const vector<Blob<Dtype>*>& bottom,
+ vector<Blob<Dtype>*>* top);
virtual void Backward_cpu(const vector<Blob<Dtype>*>& top,
- const bool propagate_down, vector<Blob<Dtype>*>* bottom);
+ const vector<bool>& propagate_down, vector<Blob<Dtype>*>* bottom);
+ virtual void Backward_gpu(const vector<Blob<Dtype>*>& top,
+ const vector<bool>& propagate_down, vector<Blob<Dtype>*>* bottom);
Blob<Dtype> diff_;
};
virtual Dtype Forward_cpu(const vector<Blob<Dtype>*>& bottom,
vector<Blob<Dtype>*>* top);
virtual void Backward_cpu(const vector<Blob<Dtype>*>& top,
- const bool propagate_down, vector<Blob<Dtype>*>* bottom);
+ const vector<bool>& propagate_down, vector<Blob<Dtype>*>* bottom);
Blob<Dtype> infogain_;
};
virtual Dtype Forward_cpu(const vector<Blob<Dtype>*>& bottom,
vector<Blob<Dtype>*>* top);
virtual void Backward_cpu(const vector<Blob<Dtype>*>& top,
- const bool propagate_down, vector<Blob<Dtype>*>* bottom);
+ const vector<bool>& propagate_down, vector<Blob<Dtype>*>* bottom);
};
/* MultinomialLogisticLossLayer
virtual Dtype Forward_cpu(const vector<Blob<Dtype>*>& bottom,
vector<Blob<Dtype>*>* top);
virtual void Backward_cpu(const vector<Blob<Dtype>*>& top,
- const bool propagate_down, vector<Blob<Dtype>*>* bottom);
+ const vector<bool>& propagate_down, vector<Blob<Dtype>*>* bottom);
};
/* AccuracyLayer
virtual Dtype Forward_cpu(const vector<Blob<Dtype>*>& bottom,
vector<Blob<Dtype>*>* top);
virtual void Backward_cpu(const vector<Blob<Dtype>*>& top,
- const bool propagate_down, vector<Blob<Dtype>*>* bottom) {
+ const vector<bool>& propagate_down, vector<Blob<Dtype>*>* bottom) {
NOT_IMPLEMENTED;
}
};
-/* Also see
-- SoftmaxWithLossLayer in vision_layers.hpp
-*/
-
} // namespace caffe
#endif // CAFFE_LOSS_LAYERS_HPP_
// this unless you do per-layer checks such as gradients.
inline vector<vector<Blob<Dtype>*> >& bottom_vecs() { return bottom_vecs_; }
inline vector<vector<Blob<Dtype>*> >& top_vecs() { return top_vecs_; }
+ inline vector<vector<bool> >& bottom_need_backward() {
+ return bottom_need_backward_;
+ }
// returns the parameters
inline vector<shared_ptr<Blob<Dtype> > >& params() { return params_; }
// returns the parameter learning rate multipliers
// pointers.
vector<vector<Blob<Dtype>*> > bottom_vecs_;
vector<vector<int> > bottom_id_vecs_;
+ vector<vector<bool> > bottom_need_backward_;
// top_vecs stores the vectors containing the output for each layer
vector<vector<Blob<Dtype>*> > top_vecs_;
vector<vector<int> > top_id_vecs_;
virtual Dtype Forward_gpu(const vector<Blob<Dtype>*>& bottom,
vector<Blob<Dtype>*>* top);
virtual void Backward_cpu(const vector<Blob<Dtype>*>& top,
- const bool propagate_down, vector<Blob<Dtype>*>* bottom);
+ const vector<bool>& propagate_down, vector<Blob<Dtype>*>* bottom);
virtual void Backward_gpu(const vector<Blob<Dtype>*>& top,
- const bool propagate_down, vector<Blob<Dtype>*>* bottom);
+ const vector<bool>& propagate_down, vector<Blob<Dtype>*>* bottom);
};
/* DropoutLayer
virtual Dtype Forward_gpu(const vector<Blob<Dtype>*>& bottom,
vector<Blob<Dtype>*>* top);
virtual void Backward_cpu(const vector<Blob<Dtype>*>& top,
- const bool propagate_down, vector<Blob<Dtype>*>* bottom);
+ const vector<bool>& propagate_down, vector<Blob<Dtype>*>* bottom);
virtual void Backward_gpu(const vector<Blob<Dtype>*>& top,
- const bool propagate_down, vector<Blob<Dtype>*>* bottom);
+ const vector<bool>& propagate_down, vector<Blob<Dtype>*>* bottom);
shared_ptr<Blob<unsigned int> > rand_vec_;
Dtype threshold_;
virtual Dtype Forward_gpu(const vector<Blob<Dtype>*>& bottom,
vector<Blob<Dtype>*>* top);
virtual void Backward_cpu(const vector<Blob<Dtype>*>& top,
- const bool propagate_down, vector<Blob<Dtype>*>* bottom);
+ const vector<bool>& propagate_down, vector<Blob<Dtype>*>* bottom);
virtual void Backward_gpu(const vector<Blob<Dtype>*>& top,
- const bool propagate_down, vector<Blob<Dtype>*>* bottom);
+ const vector<bool>& propagate_down, vector<Blob<Dtype>*>* bottom);
Dtype power_;
Dtype scale_;
vector<Blob<Dtype>*>* top);
virtual void Backward_cpu(const vector<Blob<Dtype>*>& top,
- const bool propagate_down, vector<Blob<Dtype>*>* bottom);
+ const vector<bool>& propagate_down, vector<Blob<Dtype>*>* bottom);
virtual void Backward_gpu(const vector<Blob<Dtype>*>& top,
- const bool propagate_down, vector<Blob<Dtype>*>* bottom);
+ const vector<bool>& propagate_down, vector<Blob<Dtype>*>* bottom);
};
/* SigmoidLayer
virtual Dtype Forward_gpu(const vector<Blob<Dtype>*>& bottom,
vector<Blob<Dtype>*>* top);
virtual void Backward_cpu(const vector<Blob<Dtype>*>& top,
- const bool propagate_down, vector<Blob<Dtype>*>* bottom);
+ const vector<bool>& propagate_down, vector<Blob<Dtype>*>* bottom);
virtual void Backward_gpu(const vector<Blob<Dtype>*>& top,
- const bool propagate_down, vector<Blob<Dtype>*>* bottom);
+ const vector<bool>& propagate_down, vector<Blob<Dtype>*>* bottom);
};
/* TanHLayer
virtual Dtype Forward_gpu(const vector<Blob<Dtype>*>& bottom,
vector<Blob<Dtype>*>* top);
virtual void Backward_cpu(const vector<Blob<Dtype>*>& top,
- const bool propagate_down, vector<Blob<Dtype>*>* bottom);
+ const vector<bool>& propagate_down, vector<Blob<Dtype>*>* bottom);
virtual void Backward_gpu(const vector<Blob<Dtype>*>& top,
- const bool propagate_down, vector<Blob<Dtype>*>* bottom);
+ const vector<bool>& propagate_down, vector<Blob<Dtype>*>* bottom);
};
/* ThresholdLayer
virtual Dtype Forward_gpu(const vector<Blob<Dtype>*>& bottom,
vector<Blob<Dtype>*>* top);
virtual void Backward_cpu(const vector<Blob<Dtype>*>& top,
- const bool propagate_down, vector<Blob<Dtype>*>* bottom) {
+ const vector<bool>& propagate_down, vector<Blob<Dtype>*>* bottom) {
NOT_IMPLEMENTED;
}
virtual Dtype Forward_cpu(const vector<Blob<Dtype>*>& bottom,
vector<Blob<Dtype>*>* top);
virtual void Backward_cpu(const vector<Blob<Dtype>*>& top,
- const bool propagate_down, vector<Blob<Dtype>*>* bottom) {
+ const vector<bool>& propagate_down, vector<Blob<Dtype>*>* bottom) {
NOT_IMPLEMENTED;
}
bool out_max_val_;
virtual Dtype Forward_gpu(const vector<Blob<Dtype>*>& bottom,
vector<Blob<Dtype>*>* top);
virtual void Backward_cpu(const vector<Blob<Dtype>*>& top,
- const bool propagate_down, vector<Blob<Dtype>*>* bottom);
+ const vector<bool>& propagate_down, vector<Blob<Dtype>*>* bottom);
virtual void Backward_gpu(const vector<Blob<Dtype>*>& top,
- const bool propagate_down, vector<Blob<Dtype>*>* bottom);
+ const vector<bool>& propagate_down, vector<Blob<Dtype>*>* bottom);
Blob<Dtype> col_bob_;
int count_;
virtual Dtype Forward_gpu(const vector<Blob<Dtype>*>& bottom,
vector<Blob<Dtype>*>* top);
virtual void Backward_cpu(const vector<Blob<Dtype>*>& top,
- const bool propagate_down, vector<Blob<Dtype>*>* bottom);
+ const vector<bool>& propagate_down, vector<Blob<Dtype>*>* bottom);
virtual void Backward_gpu(const vector<Blob<Dtype>*>& top,
- const bool propagate_down, vector<Blob<Dtype>*>* bottom);
+ const vector<bool>& propagate_down, vector<Blob<Dtype>*>* bottom);
int kernel_size_;
int stride_;
virtual Dtype Forward_gpu(const vector<Blob<Dtype>*>& bottom,
vector<Blob<Dtype>*>* top);
virtual void Backward_cpu(const vector<Blob<Dtype>*>& top,
- const bool propagate_down, vector<Blob<Dtype>*>* bottom);
+ const vector<bool>& propagate_down, vector<Blob<Dtype>*>* bottom);
virtual void Backward_gpu(const vector<Blob<Dtype>*>& top,
- const bool propagate_down, vector<Blob<Dtype>*>* bottom);
+ const vector<bool>& propagate_down, vector<Blob<Dtype>*>* bottom);
EltwiseParameter_EltwiseOp op_;
vector<Dtype> coeffs_;
virtual Dtype Forward_gpu(const vector<Blob<Dtype>*>& bottom,
vector<Blob<Dtype>*>* top);
virtual void Backward_cpu(const vector<Blob<Dtype>*>& top,
- const bool propagate_down, vector<Blob<Dtype>*>* bottom);
+ const vector<bool>& propagate_down, vector<Blob<Dtype>*>* bottom);
virtual void Backward_gpu(const vector<Blob<Dtype>*>& top,
- const bool propagate_down, vector<Blob<Dtype>*>* bottom);
+ const vector<bool>& propagate_down, vector<Blob<Dtype>*>* bottom);
int count_;
};
virtual Dtype Forward_gpu(const vector<Blob<Dtype>*>& bottom,
vector<Blob<Dtype>*>* top);
virtual void Backward_cpu(const vector<Blob<Dtype>*>& top,
- const bool propagate_down, vector<Blob<Dtype>*>* bottom);
+ const vector<bool>& propagate_down, vector<Blob<Dtype>*>* bottom);
virtual void Backward_gpu(const vector<Blob<Dtype>*>& top,
- const bool propagate_down, vector<Blob<Dtype>*>* bottom);
+ const vector<bool>& propagate_down, vector<Blob<Dtype>*>* bottom);
int kernel_size_;
int stride_;
virtual Dtype Forward_gpu(const vector<Blob<Dtype>*>& bottom,
vector<Blob<Dtype>*>* top);
virtual void Backward_cpu(const vector<Blob<Dtype>*>& top,
- const bool propagate_down, vector<Blob<Dtype>*>* bottom);
+ const vector<bool>& propagate_down, vector<Blob<Dtype>*>* bottom);
virtual void Backward_gpu(const vector<Blob<Dtype>*>& top,
- const bool propagate_down, vector<Blob<Dtype>*>* bottom);
+ const vector<bool>& propagate_down, vector<Blob<Dtype>*>* bottom);
int M_;
int K_;
virtual Dtype Forward_gpu(const vector<Blob<Dtype>*>& bottom,
vector<Blob<Dtype>*>* top);
virtual void Backward_cpu(const vector<Blob<Dtype>*>& top,
- const bool propagate_down, vector<Blob<Dtype>*>* bottom);
+ const vector<bool>& propagate_down, vector<Blob<Dtype>*>* bottom);
virtual void Backward_gpu(const vector<Blob<Dtype>*>& top,
- const bool propagate_down, vector<Blob<Dtype>*>* bottom);
+ const vector<bool>& propagate_down, vector<Blob<Dtype>*>* bottom);
virtual Dtype CrossChannelForward_cpu(const vector<Blob<Dtype>*>& bottom,
vector<Blob<Dtype>*>* top);
virtual Dtype WithinChannelForward(const vector<Blob<Dtype>*>& bottom,
vector<Blob<Dtype>*>* top);
virtual void CrossChannelBackward_cpu(const vector<Blob<Dtype>*>& top,
- const bool propagate_down, vector<Blob<Dtype>*>* bottom);
+ const vector<bool>& propagate_down, vector<Blob<Dtype>*>* bottom);
virtual void CrossChannelBackward_gpu(const vector<Blob<Dtype>*>& top,
- const bool propagate_down, vector<Blob<Dtype>*>* bottom);
+ const vector<bool>& propagate_down, vector<Blob<Dtype>*>* bottom);
virtual void WithinChannelBackward(const vector<Blob<Dtype>*>& top,
- const bool propagate_down, vector<Blob<Dtype>*>* bottom);
+ const vector<bool>& propagate_down, vector<Blob<Dtype>*>* bottom);
int size_;
int pre_pad_;
virtual Dtype Forward_gpu(const vector<Blob<Dtype>*>& bottom,
vector<Blob<Dtype>*>* top);
virtual void Backward_cpu(const vector<Blob<Dtype>*>& top,
- const bool propagate_down, vector<Blob<Dtype>*>* bottom);
+ const vector<bool>& propagate_down, vector<Blob<Dtype>*>* bottom);
virtual void Backward_gpu(const vector<Blob<Dtype>*>& top,
- const bool propagate_down, vector<Blob<Dtype>*>* bottom);
+ const vector<bool>& propagate_down, vector<Blob<Dtype>*>* bottom);
int max_top_blobs_;
int kernel_size_;
virtual Dtype Forward_gpu(const vector<Blob<Dtype>*>& bottom,
vector<Blob<Dtype>*>* top);
virtual void Backward_cpu(const vector<Blob<Dtype>*>& top,
- const bool propagate_down, vector<Blob<Dtype>*>* bottom);
+ const vector<bool>& propagate_down, vector<Blob<Dtype>*>* bottom);
virtual void Backward_gpu(const vector<Blob<Dtype>*>& top,
- const bool propagate_down, vector<Blob<Dtype>*>* bottom);
+ const vector<bool>& propagate_down, vector<Blob<Dtype>*>* bottom);
// sum_multiplier is just used to carry out sum using blas
Blob<Dtype> sum_multiplier_;
virtual Dtype Forward_gpu(const vector<Blob<Dtype>*>& bottom,
vector<Blob<Dtype>*>* top);
virtual void Backward_cpu(const vector<Blob<Dtype>*>& top,
- const bool propagate_down, vector<Blob<Dtype>*>* bottom);
+ const vector<bool>& propagate_down, vector<Blob<Dtype>*>* bottom);
virtual void Backward_gpu(const vector<Blob<Dtype>*>& top,
- const bool propagate_down, vector<Blob<Dtype>*>* bottom);
+ const vector<bool>& propagate_down, vector<Blob<Dtype>*>* bottom);
int count_;
};
template <typename Dtype>
void BNLLLayer<Dtype>::Backward_cpu(const vector<Blob<Dtype>*>& top,
- const bool propagate_down,
+ const vector<bool>& propagate_down,
vector<Blob<Dtype>*>* bottom) {
- if (propagate_down) {
+ if (propagate_down[0]) {
const Dtype* bottom_data = (*bottom)[0]->cpu_data();
const Dtype* top_diff = top[0]->cpu_diff();
Dtype* bottom_diff = (*bottom)[0]->mutable_cpu_diff();
template <typename Dtype>
void BNLLLayer<Dtype>::Backward_gpu(const vector<Blob<Dtype>*>& top,
- const bool propagate_down,
+ const vector<bool>& propagate_down,
vector<Blob<Dtype>*>* bottom) {
- if (propagate_down) {
+ if (propagate_down[0]) {
const Dtype* bottom_data = (*bottom)[0]->gpu_data();
const Dtype* top_diff = top[0]->gpu_diff();
Dtype* bottom_diff = (*bottom)[0]->mutable_gpu_diff();
template <typename Dtype>
void ConcatLayer<Dtype>::Backward_cpu(const vector<Blob<Dtype>*>& top,
- const bool propagate_down, vector<Blob<Dtype>*>* bottom) {
+ const vector<bool>& propagate_down, vector<Blob<Dtype>*>* bottom) {
const Dtype* top_diff = top[0]->cpu_diff();
if (concat_dim_ == 0) {
int offset_num = 0;
for (int i = 0; i < bottom->size(); ++i) {
Blob<Dtype>* blob = (*bottom)[i];
- Dtype* bottom_diff = blob->mutable_cpu_diff();
- caffe_copy(blob->count(),
- top_diff+top[0]->offset(offset_num), bottom_diff);
+ if (propagate_down[i]) {
+ Dtype* bottom_diff = blob->mutable_cpu_diff();
+ caffe_copy(blob->count(), top_diff + top[0]->offset(offset_num),
+ bottom_diff);
+ }
offset_num += blob->num();
}
} else if (concat_dim_ == 1) {
int offset_channel = 0;
for (int i = 0; i < bottom->size(); ++i) {
Blob<Dtype>* blob = (*bottom)[i];
- Dtype* bottom_diff = blob->mutable_cpu_diff();
- int num_elem = blob->channels()*blob->height()*blob->width();
- for (int n = 0; n < num_; ++n) {
- caffe_copy(num_elem, top_diff+top[0]->offset(n, offset_channel),
- bottom_diff+blob->offset(n));
+ if (propagate_down[i]) {
+ Dtype* bottom_diff = blob->mutable_cpu_diff();
+ int num_elem = blob->channels()*blob->height()*blob->width();
+ for (int n = 0; n < num_; ++n) {
+ caffe_copy(num_elem, top_diff + top[0]->offset(n, offset_channel),
+ bottom_diff + blob->offset(n));
+ }
}
offset_channel += blob->channels();
}
template <typename Dtype>
void ConcatLayer<Dtype>::Backward_gpu(const vector<Blob<Dtype>*>& top,
- const bool propagate_down, vector<Blob<Dtype>*>* bottom) {
+ const vector<bool>& propagate_down, vector<Blob<Dtype>*>* bottom) {
const Dtype* top_diff = top[0]->gpu_diff();
if (concat_dim_ == 0) {
int offset_num = 0;
for (int i = 0; i < bottom->size(); ++i) {
Blob<Dtype>* blob = (*bottom)[i];
- Dtype* bottom_diff = blob->mutable_gpu_diff();
- caffe_gpu_copy(blob->count(),
- top_diff + top[0]->offset(offset_num), bottom_diff);
+ if (propagate_down[i]) {
+ Dtype* bottom_diff = blob->mutable_gpu_diff();
+ caffe_gpu_copy(blob->count(), top_diff + top[0]->offset(offset_num),
+ bottom_diff);
+ }
offset_num += blob->num();
}
} else if (concat_dim_ == 1) {
int offset_channel = 0;
for (int i = 0; i < bottom->size(); ++i) {
Blob<Dtype>* blob = (*bottom)[i];
- Dtype* bottom_diff = blob->mutable_gpu_diff();
- int num_elem = blob->channels()*blob->height()*blob->width();
- for (int n = 0; n < num_; ++n) {
- caffe_gpu_copy(num_elem, top_diff + top[0]->offset(n, offset_channel),
- bottom_diff + blob->offset(n));
+ if (propagate_down[i]) {
+ Dtype* bottom_diff = blob->mutable_gpu_diff();
+ int num_elem = blob->channels()*blob->height()*blob->width();
+ for (int n = 0; n < num_; ++n) {
+ caffe_gpu_copy(num_elem, top_diff + top[0]->offset(n, offset_channel),
+ bottom_diff + blob->offset(n));
+ }
}
offset_channel += blob->channels();
}
template <typename Dtype>
void ConvolutionLayer<Dtype>::Backward_cpu(const vector<Blob<Dtype>*>& top,
- const bool propagate_down, vector<Blob<Dtype>*>* bottom) {
+ const vector<bool>& propagate_down, vector<Blob<Dtype>*>* bottom) {
const Dtype* top_diff = top[0]->cpu_diff();
const Dtype* weight = this->blobs_[0]->cpu_data();
Dtype* weight_diff = this->blobs_[0]->mutable_cpu_diff();
weight_diff + weight_offset * g);
}
// gradient w.r.t. bottom data, if necessary
- if (propagate_down) {
+ if (propagate_down[0]) {
for (int g = 0; g < group_; ++g) {
caffe_cpu_gemm<Dtype>(CblasTrans, CblasNoTrans, K_, N_, M_,
(Dtype)1., weight + weight_offset * g,
template <typename Dtype>
void ConvolutionLayer<Dtype>::Backward_gpu(const vector<Blob<Dtype>*>& top,
- const bool propagate_down, vector<Blob<Dtype>*>* bottom) {
+ const vector<bool>& propagate_down, vector<Blob<Dtype>*>* bottom) {
const Dtype* top_diff = top[0]->gpu_diff();
const Dtype* weight = this->blobs_[0]->gpu_data();
Dtype* weight_diff = this->blobs_[0]->mutable_gpu_diff();
weight_diff + weight_offset * g);
}
// gradient w.r.t. bottom data, if necessary
- if (propagate_down) {
+ if (propagate_down[0]) {
for (int g = 0; g < group_; ++g) {
caffe_gpu_gemm<Dtype>(CblasTrans, CblasNoTrans, K_, N_, M_,
(Dtype)1., weight + weight_offset * g,
template <typename Dtype>
void DropoutLayer<Dtype>::Backward_cpu(const vector<Blob<Dtype>*>& top,
- const bool propagate_down,
+ const vector<bool>& propagate_down,
vector<Blob<Dtype>*>* bottom) {
CHECK(Caffe::phase() == Caffe::TRAIN);
- if (propagate_down) {
+ if (propagate_down[0]) {
const Dtype* top_diff = top[0]->cpu_diff();
Dtype* bottom_diff = (*bottom)[0]->mutable_cpu_diff();
const unsigned int* mask = rand_vec_->cpu_data();
template <typename Dtype>
void DropoutLayer<Dtype>::Backward_gpu(const vector<Blob<Dtype>*>& top,
- const bool propagate_down,
+ const vector<bool>& propagate_down,
vector<Blob<Dtype>*>* bottom) {
CHECK(Caffe::phase() == Caffe::TRAIN);
- if (propagate_down) {
+ if (propagate_down[0]) {
const Dtype* top_diff = top[0]->gpu_diff();
Dtype* bottom_diff = (*bottom)[0]->mutable_gpu_diff();
const unsigned int* mask =
template <typename Dtype>
void EltwiseLayer<Dtype>::Backward_cpu(const vector<Blob<Dtype>*>& top,
- const bool propagate_down, vector<Blob<Dtype>*>* bottom) {
- if (propagate_down) {
- const int count = top[0]->count();
- const Dtype* top_data = top[0]->cpu_data();
- const Dtype* top_diff = top[0]->cpu_diff();
- for (int i = 0; i < bottom->size(); ++i) {
+ const vector<bool>& propagate_down, vector<Blob<Dtype>*>* bottom) {
+ const int count = top[0]->count();
+ const Dtype* top_data = top[0]->cpu_data();
+ const Dtype* top_diff = top[0]->cpu_diff();
+ for (int i = 0; i < bottom->size(); ++i) {
+ if (propagate_down[i]) {
const Dtype* bottom_data = (*bottom)[i]->cpu_data();
Dtype* bottom_diff = (*bottom)[i]->mutable_cpu_diff();
switch (op_) {
template <typename Dtype>
void EltwiseLayer<Dtype>::Backward_gpu(const vector<Blob<Dtype>*>& top,
- const bool propagate_down, vector<Blob<Dtype>*>* bottom) {
- if (propagate_down) {
- const int count = top[0]->count();
- const Dtype* top_data = top[0]->gpu_data();
- const Dtype* top_diff = top[0]->gpu_diff();
- for (int i = 0; i < bottom->size(); ++i) {
+ const vector<bool>& propagate_down, vector<Blob<Dtype>*>* bottom) {
+ const int count = top[0]->count();
+ const Dtype* top_data = top[0]->gpu_data();
+ const Dtype* top_diff = top[0]->gpu_diff();
+ for (int i = 0; i < bottom->size(); ++i) {
+ if (propagate_down[i]) {
const Dtype* bottom_data = (*bottom)[i]->gpu_data();
Dtype* bottom_diff = (*bottom)[i]->mutable_gpu_diff();
switch (op_) {
// Copyright 2014 BVLC and contributors.
-#include <algorithm>
-#include <cmath>
-#include <cfloat>
#include <vector>
#include "caffe/layer.hpp"
#include "caffe/util/math_functions.hpp"
#include "caffe/util/io.hpp"
-using std::max;
-
namespace caffe {
template <typename Dtype>
template <typename Dtype>
void EuclideanLossLayer<Dtype>::Backward_cpu(const vector<Blob<Dtype>*>& top,
- const bool propagate_down, vector<Blob<Dtype>*>* bottom) {
- caffe_cpu_axpby(
- (*bottom)[0]->count(), // count
- Dtype(1) / (*bottom)[0]->num(), // alpha
- diff_.cpu_data(), // a
- Dtype(0), // beta
- (*bottom)[0]->mutable_cpu_diff()); // b
+ const vector<bool>& propagate_down, vector<Blob<Dtype>*>* bottom) {
+ for (int i = 0; i < 2; ++i) {
+ if (propagate_down[i]) {
+ const Dtype sign = (i == 0) ? 1 : -1;
+ caffe_cpu_axpby(
+ (*bottom)[i]->count(), // count
+ sign / (*bottom)[i]->num(), // alpha
+ diff_.cpu_data(), // a
+ Dtype(0), // beta
+ (*bottom)[i]->mutable_cpu_diff()); // b
+ }
+ }
}
INSTANTIATE_CLASS(EuclideanLossLayer);
--- /dev/null
+// Copyright 2014 BVLC and contributors.
+
+#include <vector>
+
+#include "caffe/layer.hpp"
+#include "caffe/vision_layers.hpp"
+#include "caffe/util/math_functions.hpp"
+#include "caffe/util/io.hpp"
+
+namespace caffe {
+
+template <typename Dtype>
+Dtype EuclideanLossLayer<Dtype>::Forward_gpu(const vector<Blob<Dtype>*>& bottom,
+ vector<Blob<Dtype>*>* top) {
+ int count = bottom[0]->count();
+ caffe_gpu_sub(
+ count,
+ bottom[0]->gpu_data(),
+ bottom[1]->gpu_data(),
+ diff_.mutable_gpu_data());
+ Dtype dot;
+ caffe_gpu_dot(count, diff_.gpu_data(), diff_.gpu_data(), &dot);
+ Dtype loss = dot / bottom[0]->num() / Dtype(2);
+ return loss;
+}
+
+template <typename Dtype>
+void EuclideanLossLayer<Dtype>::Backward_gpu(const vector<Blob<Dtype>*>& top,
+ const vector<bool>& propagate_down, vector<Blob<Dtype>*>* bottom) {
+ for (int i = 0; i < 2; ++i) {
+ if (propagate_down[i]) {
+ const Dtype sign = (i == 0) ? 1 : -1;
+ caffe_gpu_axpby(
+ (*bottom)[i]->count(), // count
+ sign / (*bottom)[i]->num(), // alpha
+ diff_.gpu_data(), // a
+ Dtype(0), // beta
+ (*bottom)[i]->mutable_gpu_diff()); // b
+ }
+ }
+}
+
+INSTANTIATE_CLASS(EuclideanLossLayer);
+
+} // namespace caffe
template <typename Dtype>
void FlattenLayer<Dtype>::Backward_cpu(const vector<Blob<Dtype>*>& top,
- const bool propagate_down, vector<Blob<Dtype>*>* bottom) {
+ const vector<bool>& propagate_down, vector<Blob<Dtype>*>* bottom) {
(*bottom)[0]->ShareDiff(*top[0]);
}
template <typename Dtype>
void FlattenLayer<Dtype>::Backward_gpu(const vector<Blob<Dtype>*>& top,
- const bool propagate_down, vector<Blob<Dtype>*>* bottom) {
+ const vector<bool>& propagate_down, vector<Blob<Dtype>*>* bottom) {
(*bottom)[0]->ShareDiff(*top[0]);
}
return Dtype(0.);
}
-// The backward operations are dummy - they do not carry any computation.
-template <typename Dtype>
-void HDF5DataLayer<Dtype>::Backward_cpu(const vector<Blob<Dtype>*>& top,
- const bool propagate_down, vector<Blob<Dtype>*>* bottom) { }
-
INSTANTIATE_CLASS(HDF5DataLayer);
} // namespace caffe
return Dtype(0.);
}
-template <typename Dtype>
-void HDF5DataLayer<Dtype>::Backward_gpu(const vector<Blob<Dtype>*>& top,
- const bool propagate_down, vector<Blob<Dtype>*>* bottom) {
-}
-
INSTANTIATE_CLASS(HDF5DataLayer);
} // namespace caffe
template <typename Dtype>
void HDF5OutputLayer<Dtype>::Backward_cpu(const vector<Blob<Dtype>*>& top,
- const bool propagate_down, vector<Blob<Dtype>*>* bottom) {
+ const vector<bool>& propagate_down, vector<Blob<Dtype>*>* bottom) {
return;
}
template <typename Dtype>
void HDF5OutputLayer<Dtype>::Backward_gpu(const vector<Blob<Dtype>*>& top,
- const bool propagate_down, vector<Blob<Dtype>*>* bottom) {
+ const vector<bool>& propagate_down, vector<Blob<Dtype>*>* bottom) {
return;
}
template <typename Dtype>
void HingeLossLayer<Dtype>::Backward_cpu(const vector<Blob<Dtype>*>& top,
- const bool propagate_down, vector<Blob<Dtype>*>* bottom) {
- Dtype* bottom_diff = (*bottom)[0]->mutable_cpu_diff();
- const Dtype* label = (*bottom)[1]->cpu_data();
- int num = (*bottom)[0]->num();
- int count = (*bottom)[0]->count();
- int dim = count / num;
-
- for (int i = 0; i < num; ++i) {
- bottom_diff[i * dim + static_cast<int>(label[i])] *= -1;
+ const vector<bool>& propagate_down, vector<Blob<Dtype>*>* bottom) {
+ if (propagate_down[1]) {
+ LOG(FATAL) << this->type_name()
+ << " Layer cannot backpropagate to label inputs.";
}
+ if (propagate_down[0]) {
+ Dtype* bottom_diff = (*bottom)[0]->mutable_cpu_diff();
+ const Dtype* label = (*bottom)[1]->cpu_data();
+ int num = (*bottom)[0]->num();
+ int count = (*bottom)[0]->count();
+ int dim = count / num;
- switch (this->layer_param_.hinge_loss_param().norm()) {
- case HingeLossParameter_Norm_L1:
- caffe_cpu_sign(count, bottom_diff, bottom_diff);
- caffe_scal(count, Dtype(1. / num), bottom_diff);
- break;
- case HingeLossParameter_Norm_L2:
- caffe_scal(count, Dtype(2. / num), bottom_diff);
- break;
- default:
- LOG(FATAL) << "Unknown Norm";
+ for (int i = 0; i < num; ++i) {
+ bottom_diff[i * dim + static_cast<int>(label[i])] *= -1;
+ }
+
+ switch (this->layer_param_.hinge_loss_param().norm()) {
+ case HingeLossParameter_Norm_L1:
+ caffe_cpu_sign(count, bottom_diff, bottom_diff);
+ caffe_scal(count, Dtype(1. / num), bottom_diff);
+ break;
+ case HingeLossParameter_Norm_L2:
+ caffe_scal(count, Dtype(2. / num), bottom_diff);
+ break;
+ default:
+ LOG(FATAL) << "Unknown Norm";
+ }
}
}
template <typename Dtype>
void Im2colLayer<Dtype>::Backward_cpu(const vector<Blob<Dtype>*>& top,
- const bool propagate_down, vector<Blob<Dtype>*>* bottom) {
+ const vector<bool>& propagate_down, vector<Blob<Dtype>*>* bottom) {
const Dtype* top_diff = top[0]->cpu_diff();
Dtype* bottom_diff = (*bottom)[0]->mutable_cpu_diff();
for (int n = 0; n < top[0]->num(); ++n) {
template <typename Dtype>
void Im2colLayer<Dtype>::Backward_gpu(const vector<Blob<Dtype>*>& top,
- const bool propagate_down, vector<Blob<Dtype>*>* bottom) {
+ const vector<bool>& propagate_down, vector<Blob<Dtype>*>* bottom) {
const Dtype* top_diff = top[0]->gpu_diff();
Dtype* bottom_diff = (*bottom)[0]->mutable_gpu_diff();
for (int n = 0; n < top[0]->num(); ++n) {
template <typename Dtype>
void InfogainLossLayer<Dtype>::Backward_cpu(const vector<Blob<Dtype>*>& top,
- const bool propagate_down,
+ const vector<bool>& propagate_down,
vector<Blob<Dtype>*>* bottom) {
- const Dtype* bottom_data = (*bottom)[0]->cpu_data();
- const Dtype* bottom_label = (*bottom)[1]->cpu_data();
- const Dtype* infogain_mat = infogain_.cpu_data();
- Dtype* bottom_diff = (*bottom)[0]->mutable_cpu_diff();
- int num = (*bottom)[0]->num();
- int dim = (*bottom)[0]->count() / (*bottom)[0]->num();
- CHECK_EQ(infogain_.height(), dim);
- for (int i = 0; i < num; ++i) {
- int label = static_cast<int>(bottom_label[i]);
- for (int j = 0; j < dim; ++j) {
- Dtype prob = max(bottom_data[i * dim + j], Dtype(kLOG_THRESHOLD));
- bottom_diff[i * dim + j] = - infogain_mat[label * dim + j] / prob / num;
+ if (propagate_down[1]) {
+ LOG(FATAL) << this->type_name()
+ << " Layer cannot backpropagate to label inputs.";
+ }
+ if (propagate_down[0]) {
+ const Dtype* bottom_data = (*bottom)[0]->cpu_data();
+ const Dtype* bottom_label = (*bottom)[1]->cpu_data();
+ const Dtype* infogain_mat = infogain_.cpu_data();
+ Dtype* bottom_diff = (*bottom)[0]->mutable_cpu_diff();
+ int num = (*bottom)[0]->num();
+ int dim = (*bottom)[0]->count() / (*bottom)[0]->num();
+ CHECK_EQ(infogain_.height(), dim);
+ for (int i = 0; i < num; ++i) {
+ int label = static_cast<int>(bottom_label[i]);
+ for (int j = 0; j < dim; ++j) {
+ Dtype prob = max(bottom_data[i * dim + j], Dtype(kLOG_THRESHOLD));
+ bottom_diff[i * dim + j] = - infogain_mat[label * dim + j] / prob / num;
+ }
}
}
}
template <typename Dtype>
void InnerProductLayer<Dtype>::Backward_cpu(const vector<Blob<Dtype>*>& top,
- const bool propagate_down,
+ const vector<bool>& propagate_down,
vector<Blob<Dtype>*>* bottom) {
const Dtype* top_diff = top[0]->cpu_diff();
const Dtype* bottom_data = (*bottom)[0]->cpu_data();
reinterpret_cast<const Dtype*>(bias_multiplier_->cpu_data()), (Dtype)0.,
this->blobs_[1]->mutable_cpu_diff());
}
- if (propagate_down) {
+ if (propagate_down[0]) {
// Gradient with respect to bottom data
caffe_cpu_gemm<Dtype>(CblasNoTrans, CblasNoTrans, M_, K_, N_, (Dtype)1.,
top_diff, this->blobs_[0]->cpu_data(), (Dtype)0.,
template <typename Dtype>
void InnerProductLayer<Dtype>::Backward_gpu(const vector<Blob<Dtype>*>& top,
- const bool propagate_down,
+ const vector<bool>& propagate_down,
vector<Blob<Dtype>*>* bottom) {
const Dtype* top_diff = top[0]->gpu_diff();
const Dtype* bottom_data = (*bottom)[0]->gpu_data();
reinterpret_cast<const Dtype*>(bias_multiplier_->gpu_data()),
(Dtype)0., this->blobs_[1]->mutable_gpu_diff());
}
- if (propagate_down) {
+ if (propagate_down[0]) {
// Gradient with respect to bottom data
caffe_gpu_gemm<Dtype>(CblasNoTrans, CblasNoTrans, M_, K_, N_, (Dtype)1.,
top_diff, this->blobs_[0]->gpu_data(), (Dtype)0.,
template <typename Dtype>
void LRNLayer<Dtype>::Backward_cpu(const vector<Blob<Dtype>*>& top,
- const bool propagate_down, vector<Blob<Dtype>*>* bottom) {
+ const vector<bool>& propagate_down, vector<Blob<Dtype>*>* bottom) {
switch (this->layer_param_.lrn_param().norm_region()) {
case LRNParameter_NormRegion_ACROSS_CHANNELS:
CrossChannelBackward_cpu(top, propagate_down, bottom);
template <typename Dtype>
void LRNLayer<Dtype>::CrossChannelBackward_cpu(
- const vector<Blob<Dtype>*>& top, const bool propagate_down,
+ const vector<Blob<Dtype>*>& top, const vector<bool>& propagate_down,
vector<Blob<Dtype>*>* bottom) {
const Dtype* top_diff = top[0]->cpu_diff();
const Dtype* top_data = top[0]->cpu_data();
template <typename Dtype>
void LRNLayer<Dtype>::WithinChannelBackward(
- const vector<Blob<Dtype>*>& top, const bool propagate_down,
+ const vector<Blob<Dtype>*>& top, const vector<bool>& propagate_down,
vector<Blob<Dtype>*>* bottom) {
- if (propagate_down) {
- product_layer_->Backward(top, true, &product_bottom_vec_);
- power_layer_->Backward(power_top_vec_, true, &pool_top_vec_);
- pool_layer_->Backward(pool_top_vec_, true, &square_top_vec_);
- square_layer_->Backward(square_top_vec_, true, &square_bottom_vec_);
- split_layer_->Backward(split_top_vec_, true, bottom);
+ if (propagate_down[0]) {
+ vector<bool> product_propagate_down(2, true);
+ product_layer_->Backward(top, product_propagate_down, &product_bottom_vec_);
+ power_layer_->Backward(power_top_vec_, propagate_down, &pool_top_vec_);
+ pool_layer_->Backward(pool_top_vec_, propagate_down, &square_top_vec_);
+ square_layer_->Backward(square_top_vec_, propagate_down,
+ &square_bottom_vec_);
+ split_layer_->Backward(split_top_vec_, propagate_down, bottom);
}
}
template <typename Dtype>
void LRNLayer<Dtype>::Backward_gpu(const vector<Blob<Dtype>*>& top,
- const bool propagate_down, vector<Blob<Dtype>*>* bottom) {
+ const vector<bool>& propagate_down, vector<Blob<Dtype>*>* bottom) {
switch (this->layer_param_.lrn_param().norm_region()) {
case LRNParameter_NormRegion_ACROSS_CHANNELS:
CrossChannelBackward_gpu(top, propagate_down, bottom);
template <typename Dtype>
void LRNLayer<Dtype>::CrossChannelBackward_gpu(
- const vector<Blob<Dtype>*>& top, const bool propagate_down,
+ const vector<Blob<Dtype>*>& top, const vector<bool>& propagate_down,
vector<Blob<Dtype>*>* bottom) {
int n_threads = num_ * height_ * width_;
// NOLINT_NEXT_LINE(whitespace/operators)
template <typename Dtype>
void MultinomialLogisticLossLayer<Dtype>::Backward_cpu(
- const vector<Blob<Dtype>*>& top, const bool propagate_down,
+ const vector<Blob<Dtype>*>& top, const vector<bool>& propagate_down,
vector<Blob<Dtype>*>* bottom) {
- const Dtype* bottom_data = (*bottom)[0]->cpu_data();
- const Dtype* bottom_label = (*bottom)[1]->cpu_data();
- Dtype* bottom_diff = (*bottom)[0]->mutable_cpu_diff();
- int num = (*bottom)[0]->num();
- int dim = (*bottom)[0]->count() / (*bottom)[0]->num();
- memset(bottom_diff, 0, sizeof(Dtype) * (*bottom)[0]->count());
- for (int i = 0; i < num; ++i) {
- int label = static_cast<int>(bottom_label[i]);
- Dtype prob = max(bottom_data[i * dim + label], Dtype(kLOG_THRESHOLD));
- bottom_diff[i * dim + label] = -1. / prob / num;
+ if (propagate_down[1]) {
+ LOG(FATAL) << this->type_name()
+ << " Layer cannot backpropagate to label inputs.";
+ }
+ if (propagate_down[0]) {
+ const Dtype* bottom_data = (*bottom)[0]->cpu_data();
+ const Dtype* bottom_label = (*bottom)[1]->cpu_data();
+ Dtype* bottom_diff = (*bottom)[0]->mutable_cpu_diff();
+ int num = (*bottom)[0]->num();
+ int dim = (*bottom)[0]->count() / (*bottom)[0]->num();
+ memset(bottom_diff, 0, sizeof(Dtype) * (*bottom)[0]->count());
+ for (int i = 0; i < num; ++i) {
+ int label = static_cast<int>(bottom_label[i]);
+ Dtype prob = max(bottom_data[i * dim + label], Dtype(kLOG_THRESHOLD));
+ bottom_diff[i * dim + label] = -1. / prob / num;
+ }
}
}
template <typename Dtype>
void PoolingLayer<Dtype>::Backward_cpu(const vector<Blob<Dtype>*>& top,
- const bool propagate_down, vector<Blob<Dtype>*>* bottom) {
- if (!propagate_down) {
+ const vector<bool>& propagate_down, vector<Blob<Dtype>*>* bottom) {
+ if (!propagate_down[0]) {
return;
}
const Dtype* top_diff = top[0]->cpu_diff();
template <typename Dtype>
void PoolingLayer<Dtype>::Backward_gpu(const vector<Blob<Dtype>*>& top,
- const bool propagate_down, vector<Blob<Dtype>*>* bottom) {
- if (!propagate_down) {
+ const vector<bool>& propagate_down, vector<Blob<Dtype>*>* bottom) {
+ if (!propagate_down[0]) {
return;
}
const Dtype* top_diff = top[0]->gpu_diff();
template <typename Dtype>
void PowerLayer<Dtype>::Backward_cpu(const vector<Blob<Dtype>*>& top,
- const bool propagate_down,
+ const vector<bool>& propagate_down,
vector<Blob<Dtype>*>* bottom) {
- if (propagate_down) {
+ if (propagate_down[0]) {
Dtype* bottom_diff = (*bottom)[0]->mutable_cpu_diff();
const int count = (*bottom)[0]->count();
const Dtype* top_diff = top[0]->cpu_diff();
template <typename Dtype>
void PowerLayer<Dtype>::Backward_gpu(const vector<Blob<Dtype>*>& top,
- const bool propagate_down,
+ const vector<bool>& propagate_down,
vector<Blob<Dtype>*>* bottom) {
- if (propagate_down) {
+ if (propagate_down[0]) {
Dtype* bottom_diff = (*bottom)[0]->mutable_gpu_diff();
const int count = (*bottom)[0]->count();
const Dtype* top_diff = top[0]->gpu_diff();
template <typename Dtype>
void ReLULayer<Dtype>::Backward_cpu(const vector<Blob<Dtype>*>& top,
- const bool propagate_down,
+ const vector<bool>& propagate_down,
vector<Blob<Dtype>*>* bottom) {
- if (propagate_down) {
+ if (propagate_down[0]) {
const Dtype* bottom_data = (*bottom)[0]->cpu_data();
const Dtype* top_diff = top[0]->cpu_diff();
Dtype* bottom_diff = (*bottom)[0]->mutable_cpu_diff();
template <typename Dtype>
void ReLULayer<Dtype>::Backward_gpu(const vector<Blob<Dtype>*>& top,
- const bool propagate_down,
+ const vector<bool>& propagate_down,
vector<Blob<Dtype>*>* bottom) {
- if (propagate_down) {
+ if (propagate_down[0]) {
const Dtype* bottom_data = (*bottom)[0]->gpu_data();
const Dtype* top_diff = top[0]->gpu_diff();
Dtype* bottom_diff = (*bottom)[0]->mutable_gpu_diff();
void SigmoidCrossEntropyLossLayer<Dtype>::FurtherSetUp(
const vector<Blob<Dtype>*>& bottom, vector<Blob<Dtype>*>* top) {
CHECK_EQ(bottom[0]->count(), bottom[1]->count()) <<
- "SigmoidCrossEntropyLoss Layer inputs must have same count.";
+ "SIGMOID_CROSS_ENTROPY_LOSS layer inputs must have the same count.";
sigmoid_bottom_vec_.clear();
sigmoid_bottom_vec_.push_back(bottom[0]);
sigmoid_top_vec_.clear();
template <typename Dtype>
void SigmoidCrossEntropyLossLayer<Dtype>::Backward_cpu(
- const vector<Blob<Dtype>*>& top, const bool propagate_down,
+ const vector<Blob<Dtype>*>& top, const vector<bool>& propagate_down,
vector<Blob<Dtype>*>* bottom) {
- // First, compute the diff
- const int count = (*bottom)[0]->count();
- const int num = (*bottom)[0]->num();
- const Dtype* sigmoid_output_data = sigmoid_output_->cpu_data();
- const Dtype* target = (*bottom)[1]->cpu_data();
- Dtype* bottom_diff = (*bottom)[0]->mutable_cpu_diff();
- caffe_sub(count, sigmoid_output_data, target, bottom_diff);
- // Scale down gradient
- caffe_scal(count, Dtype(1) / num, bottom_diff);
+ if (propagate_down[1]) {
+ LOG(FATAL) << this->type_name()
+ << " Layer cannot backpropagate to label inputs.";
+ }
+ if (propagate_down[0]) {
+ // First, compute the diff
+ const int count = (*bottom)[0]->count();
+ const int num = (*bottom)[0]->num();
+ const Dtype* sigmoid_output_data = sigmoid_output_->cpu_data();
+ const Dtype* target = (*bottom)[1]->cpu_data();
+ Dtype* bottom_diff = (*bottom)[0]->mutable_cpu_diff();
+ caffe_sub(count, sigmoid_output_data, target, bottom_diff);
+ // Scale down gradient
+ caffe_scal(count, Dtype(1) / num, bottom_diff);
+ }
}
INSTANTIATE_CLASS(SigmoidCrossEntropyLossLayer);
template <typename Dtype>
void SigmoidCrossEntropyLossLayer<Dtype>::Backward_gpu(
- const vector<Blob<Dtype>*>& top, const bool propagate_down,
+ const vector<Blob<Dtype>*>& top, const vector<bool>& propagate_down,
vector<Blob<Dtype>*>* bottom) {
- // First, compute the diff
- const int count = (*bottom)[0]->count();
- const int num = (*bottom)[0]->num();
- const Dtype* sigmoid_output_data = sigmoid_output_->gpu_data();
- const Dtype* target = (*bottom)[1]->gpu_data();
- Dtype* bottom_diff = (*bottom)[0]->mutable_gpu_diff();
- caffe_gpu_copy(count, sigmoid_output_data, bottom_diff);
- caffe_gpu_axpy(count, Dtype(-1), target, bottom_diff);
- // Scale down gradient
- caffe_gpu_scal(count, Dtype(1) / num, bottom_diff);
+ if (propagate_down[1]) {
+ LOG(FATAL) << this->type_name()
+ << " Layer cannot backpropagate to label inputs.";
+ }
+ if (propagate_down[0]) {
+ // First, compute the diff
+ const int count = (*bottom)[0]->count();
+ const int num = (*bottom)[0]->num();
+ const Dtype* sigmoid_output_data = sigmoid_output_->gpu_data();
+ const Dtype* target = (*bottom)[1]->gpu_data();
+ Dtype* bottom_diff = (*bottom)[0]->mutable_gpu_diff();
+ caffe_gpu_copy(count, sigmoid_output_data, bottom_diff);
+ caffe_gpu_axpy(count, Dtype(-1), target, bottom_diff);
+ // Scale down gradient
+ caffe_gpu_scal(count, Dtype(1) / num, bottom_diff);
+ }
}
INSTANTIATE_CLASS(SigmoidCrossEntropyLossLayer);
template <typename Dtype>
void SigmoidLayer<Dtype>::Backward_cpu(const vector<Blob<Dtype>*>& top,
- const bool propagate_down,
+ const vector<bool>& propagate_down,
vector<Blob<Dtype>*>* bottom) {
- if (propagate_down) {
+ if (propagate_down[0]) {
const Dtype* top_data = top[0]->cpu_data();
const Dtype* top_diff = top[0]->cpu_diff();
Dtype* bottom_diff = (*bottom)[0]->mutable_cpu_diff();
template <typename Dtype>
void SigmoidLayer<Dtype>::Backward_gpu(const vector<Blob<Dtype>*>& top,
- const bool propagate_down,
+ const vector<bool>& propagate_down,
vector<Blob<Dtype>*>* bottom) {
- if (propagate_down) {
+ if (propagate_down[0]) {
const Dtype* top_data = top[0]->gpu_data();
const Dtype* top_diff = top[0]->gpu_diff();
Dtype* bottom_diff = (*bottom)[0]->mutable_gpu_diff();
template <typename Dtype>
void SoftmaxLayer<Dtype>::Backward_cpu(const vector<Blob<Dtype>*>& top,
- const bool propagate_down,
+ const vector<bool>& propagate_down,
vector<Blob<Dtype>*>* bottom) {
const Dtype* top_diff = top[0]->cpu_diff();
const Dtype* top_data = top[0]->cpu_data();
// TODO(Yangqing): implement the GPU version of softmax.
template <typename Dtype>
void SoftmaxLayer<Dtype>::Backward_gpu(const vector<Blob<Dtype>*>& top,
- const bool propagate_down, vector<Blob<Dtype>*>* bottom) {
+ const vector<bool>& propagate_down, vector<Blob<Dtype>*>* bottom) {
const Dtype* top_diff = top[0]->gpu_diff();
const Dtype* top_data = top[0]->gpu_data();
Dtype* bottom_diff = (*bottom)[0]->mutable_gpu_diff();
template <typename Dtype>
void SoftmaxWithLossLayer<Dtype>::Backward_cpu(const vector<Blob<Dtype>*>& top,
- const bool propagate_down,
+ const vector<bool>& propagate_down,
vector<Blob<Dtype>*>* bottom) {
- // Compute the diff
- Dtype* bottom_diff = (*bottom)[0]->mutable_cpu_diff();
- const Dtype* prob_data = prob_.cpu_data();
- memcpy(bottom_diff, prob_data, sizeof(Dtype) * prob_.count());
- const Dtype* label = (*bottom)[1]->cpu_data();
- int num = prob_.num();
- int dim = prob_.count() / num;
- for (int i = 0; i < num; ++i) {
- bottom_diff[i * dim + static_cast<int>(label[i])] -= 1;
+ if (propagate_down[1]) {
+ LOG(FATAL) << this->type_name()
+ << " Layer cannot backpropagate to label inputs.";
+ }
+ if (propagate_down[0]) {
+ Dtype* bottom_diff = (*bottom)[0]->mutable_cpu_diff();
+ const Dtype* prob_data = prob_.cpu_data();
+ memcpy(bottom_diff, prob_data, sizeof(Dtype) * prob_.count());
+ const Dtype* label = (*bottom)[1]->cpu_data();
+ int num = prob_.num();
+ int dim = prob_.count() / num;
+ for (int i = 0; i < num; ++i) {
+ bottom_diff[i * dim + static_cast<int>(label[i])] -= 1;
+ }
+ // Scale down gradient
+ caffe_scal(prob_.count(), Dtype(1) / num, bottom_diff);
}
- // Scale down gradient
- caffe_scal(prob_.count(), Dtype(1) / num, bottom_diff);
}
template <typename Dtype>
void SoftmaxWithLossLayer<Dtype>::Backward_gpu(const vector<Blob<Dtype>*>& top,
- const bool propagate_down, vector<Blob<Dtype>*>* bottom) {
+ const vector<bool>& propagate_down, vector<Blob<Dtype>*>* bottom) {
// TODO(Yangqing): implement the GPU version of softmax.
Backward_cpu(top, propagate_down, bottom);
}
template <typename Dtype>
void SplitLayer<Dtype>::Backward_cpu(const vector<Blob<Dtype>*>& top,
- const bool propagate_down, vector<Blob<Dtype>*>* bottom) {
- if (propagate_down) {
+ const vector<bool>& propagate_down, vector<Blob<Dtype>*>* bottom) {
+ if (propagate_down[0]) {
(*bottom)[0]->ShareDiff(*top[0]);
// Add remaining top blob diffs.
Dtype* bottom_diff = (*bottom)[0]->mutable_cpu_diff();
template <typename Dtype>
void SplitLayer<Dtype>::Backward_gpu(const vector<Blob<Dtype>*>& top,
- const bool propagate_down, vector<Blob<Dtype>*>* bottom) {
- if (propagate_down) {
+ const vector<bool>& propagate_down, vector<Blob<Dtype>*>* bottom) {
+ if (propagate_down[0]) {
(*bottom)[0]->ShareDiff(*top[0]);
// Add remaining top blob diffs.
Dtype* bottom_diff = (*bottom)[0]->mutable_gpu_diff();
template <typename Dtype>
void TanHLayer<Dtype>::Backward_cpu(const vector<Blob<Dtype>*>& top,
- const bool propagate_down,
+ const vector<bool>& propagate_down,
vector<Blob<Dtype>*>* bottom) {
- if (propagate_down) {
+ if (propagate_down[0]) {
const Dtype* top_data = top[0]->cpu_data();
const Dtype* top_diff = top[0]->cpu_diff();
Dtype* bottom_diff = (*bottom)[0]->mutable_cpu_diff();
template <typename Dtype>
void TanHLayer<Dtype>::Backward_gpu(const vector<Blob<Dtype>*>& top,
- const bool propagate_down,
+ const vector<bool>& propagate_down,
vector<Blob<Dtype>*>* bottom) {
- if (propagate_down) {
+ if (propagate_down[0]) {
const Dtype* top_data = top[0]->gpu_data();
const Dtype* top_diff = top[0]->gpu_diff();
Dtype* bottom_diff = (*bottom)[0]->mutable_gpu_diff();
top_vecs_.resize(param.layers_size());
bottom_id_vecs_.resize(param.layers_size());
top_id_vecs_.resize(param.layers_size());
+ bottom_need_backward_.resize(param.layers_size());
for (int layer_id = 0; layer_id < param.layers_size(); ++layer_id) {
const LayerParameter& layer_param = param.layers(layer_id);
layers_.push_back(shared_ptr<Layer<Dtype> >(GetLayer<Dtype>(layer_param)));
bottom_vecs_[layer_id].push_back(blobs_[blob_id].get());
bottom_id_vecs_[layer_id].push_back(blob_id);
available_blobs->erase(blob_name);
+ const bool need_backward = param.force_backward() || blob_need_backward_[blob_id];
+ bottom_need_backward_[layer_id].push_back(need_backward);
return blob_id;
}
void Net<Dtype>::Backward() {
for (int i = layers_.size() - 1; i >= 0; --i) {
if (layer_need_backward_[i]) {
- layers_[i]->Backward(top_vecs_[i], true, &bottom_vecs_[i]);
+ layers_[i]->Backward(
+ top_vecs_[i], bottom_need_backward_[i], &bottom_vecs_[i]);
}
}
}
TYPED_TEST_CASE(EuclideanLossLayerTest, Dtypes);
TYPED_TEST(EuclideanLossLayerTest, TestGradientCPU) {
- LayerParameter layer_param;
Caffe::set_mode(Caffe::CPU);
+ LayerParameter layer_param;
+ EuclideanLossLayer<TypeParam> layer(layer_param);
+ layer.SetUp(this->blob_bottom_vec_, &this->blob_top_vec_);
+ GradientChecker<TypeParam> checker(1e-2, 1e-2, 1701);
+ checker.CheckGradientSingle(&layer, &(this->blob_bottom_vec_),
+ &(this->blob_top_vec_), -1, -1, -1);
+}
+
+TYPED_TEST(EuclideanLossLayerTest, TestGradientGPU) {
+ Caffe::set_mode(Caffe::GPU);
+ LayerParameter layer_param;
EuclideanLossLayer<TypeParam> layer(layer_param);
layer.SetUp(this->blob_bottom_vec_, &this->blob_top_vec_);
GradientChecker<TypeParam> checker(1e-2, 1e-2, 1701);
checker.CheckGradientSingle(&layer, &(this->blob_bottom_vec_),
- &(this->blob_top_vec_), 0, -1, -1);
+ &(this->blob_top_vec_), -1, -1, -1);
}
} // namespace caffe
}
// First, figure out what blobs we need to check against.
vector<Blob<Dtype>*> blobs_to_check;
+ vector<bool> propagate_down(bottom->size(), check_bottom < 0);
for (int i = 0; i < layer->blobs().size(); ++i) {
blobs_to_check.push_back(layer->blobs()[i].get());
}
blobs_to_check.push_back((*bottom)[i]);
}
} else {
- CHECK(check_bottom < bottom->size());
+ CHECK_LT(check_bottom, bottom->size());
blobs_to_check.push_back((*bottom)[check_bottom]);
+ propagate_down[check_bottom] = true;
}
// Compute the gradient analytically using Backward
Caffe::set_random_seed(seed_);
Dtype computed_objective = layer->Forward(*bottom, top);
// Get additional loss from the objective
computed_objective += GetObjAndGradient(top, top_id, top_data_id);
- layer->Backward(*top, true, bottom);
+ layer->Backward(*top, propagate_down, bottom);
// Store computed gradients for all checked blobs
vector<shared_ptr<Blob<Dtype> > >
computed_gradient_blobs(blobs_to_check.size());
for (int i = 0; i < this->blob_top_->count(); ++i) {
this->blob_top_->mutable_cpu_diff()[i] = 1.;
}
- layer.Backward(this->blob_top_vec_, true, &(this->blob_bottom_vec_));
+ vector<bool> propagate_down(this->blob_bottom_vec_.size(), true);
+ layer.Backward(this->blob_top_vec_, propagate_down,
+ &(this->blob_bottom_vec_));
// for (int i = 0; i < this->blob_bottom_->count(); ++i) {
// std::cout << "CPU diff " << this->blob_bottom_->cpu_diff()[i]
// << std::endl;
for (int i = 0; i < this->blob_top_->count(); ++i) {
this->blob_top_->mutable_cpu_diff()[i] = 1.;
}
- layer.Backward(this->blob_top_vec_, true, &(this->blob_bottom_vec_));
+ vector<bool> propagate_down(this->blob_bottom_vec_.size(), true);
+ layer.Backward(this->blob_top_vec_, propagate_down,
+ &(this->blob_bottom_vec_));
// for (int i = 0; i < this->blob_bottom_->count(); ++i) {
// std::cout << "GPU diff " << this->blob_bottom_->cpu_diff()[i]
// << std::endl;
for (int i = 0; i < this->blob_top_->count(); ++i) {
this->blob_top_->mutable_cpu_diff()[i] = 1.;
}
- layer.Backward(this->blob_top_vec_, true, &(this->blob_bottom_vec_));
checker.CheckGradientExhaustive(&layer, &(this->blob_bottom_vec_),
&(this->blob_top_vec_));
}
for (int i = 0; i < this->blob_top_->count(); ++i) {
this->blob_top_->mutable_cpu_diff()[i] = 1.;
}
- layer.Backward(this->blob_top_vec_, true, &(this->blob_bottom_vec_));
checker.CheckGradientExhaustive(&layer, &(this->blob_bottom_vec_),
&(this->blob_top_vec_));
}
for (int i = 0; i < this->blob_top_->count(); ++i) {
this->blob_top_->mutable_cpu_diff()[i] = 1.;
}
- layer.Backward(this->blob_top_vec_, true, &(this->blob_bottom_vec_));
+ vector<bool> propagate_down(this->blob_bottom_vec_.size(), true);
+ layer.Backward(this->blob_top_vec_, propagate_down,
+ &(this->blob_bottom_vec_));
const TypeParam* bottom_diff = this->blob_bottom_->cpu_diff();
TypeParam sum = 0.;
for (int i = 0; i < this->blob_bottom_->count(); ++i) {
DropoutLayer<TypeParam> dropout_layer(layer_param);
dropout_layer.SetUp(this->blob_top_vec_, &(this->blob_top_vec_));
dropout_layer.Forward(this->blob_top_vec_, &(this->blob_top_vec_));
- dropout_layer.Backward(this->blob_top_vec_, true, &(this->blob_top_vec_));
- layer.Backward(this->blob_top_vec_, true, &(this->blob_bottom_vec_));
+ dropout_layer.Backward(this->blob_top_vec_, propagate_down,
+ &(this->blob_top_vec_));
+ layer.Backward(this->blob_top_vec_, propagate_down,
+ &(this->blob_bottom_vec_));
TypeParam sum_with_dropout = 0.;
bottom_diff = this->blob_bottom_->cpu_diff();
for (int i = 0; i < this->blob_bottom_->count(); ++i) {
for (int i = 0; i < this->blob_top_->count(); ++i) {
this->blob_top_->mutable_cpu_diff()[i] = 1.;
}
- layer.Backward(this->blob_top_vec_, true, &(this->blob_bottom_vec_));
+ vector<bool> propagate_down(this->blob_bottom_vec_.size(), true);
+ layer.Backward(this->blob_top_vec_, propagate_down,
+ &(this->blob_bottom_vec_));
const TypeParam* bottom_diff = this->blob_bottom_->cpu_diff();
TypeParam sum = 0.;
for (int i = 0; i < this->blob_bottom_->count(); ++i) {
DropoutLayer<TypeParam> dropout_layer(layer_param);
dropout_layer.SetUp(this->blob_top_vec_, &(this->blob_top_vec_));
dropout_layer.Forward(this->blob_top_vec_, &(this->blob_top_vec_));
- dropout_layer.Backward(this->blob_top_vec_, true, &(this->blob_top_vec_));
- layer.Backward(this->blob_top_vec_, true, &(this->blob_bottom_vec_));
+ dropout_layer.Backward(this->blob_top_vec_, propagate_down,
+ &(this->blob_top_vec_));
+ layer.Backward(this->blob_top_vec_, propagate_down,
+ &(this->blob_bottom_vec_));
TypeParam sum_with_dropout = 0.;
bottom_diff = this->blob_bottom_->cpu_diff();
for (int i = 0; i < this->blob_bottom_->count(); ++i) {
// Copyright 2014 BVLC and contributors.
-#include <google/protobuf/text_format.h>
#include <string>
+#include <vector>
+
+#include "google/protobuf/text_format.h"
#include "gtest/gtest.h"
#include "caffe/common.hpp"
template <typename Dtype>
class NetTest : public ::testing::Test {
protected:
- virtual void SetUp() {
- const string& proto =
- "name: 'TestNetwork' "
+ virtual void InitNetFromProtoString(const string& proto) {
+ NetParameter param;
+ CHECK(google::protobuf::TextFormat::ParseFromString(proto, ¶m));
+ net_.reset(new Net<Dtype>(param));
+ }
+
+ virtual void InitTinyNet(const bool force_backward = false) {
+ string proto =
+ "name: 'TinyTestNetwork' "
"layers: { "
" name: 'data' "
" type: DUMMY_DATA "
" bottom: 'label' "
" top: 'top_loss' "
"} ";
- NetParameter param;
- CHECK(google::protobuf::TextFormat::ParseFromString(proto, ¶m));
- net_.reset(new Net<Dtype>(param));
+ if (force_backward) {
+ proto += "force_backward: true ";
+ }
+ InitNetFromProtoString(proto);
+ }
+
+ virtual void InitTrickyNet() {
+ const string& proto =
+ "name: 'TrickyTestNetwork' "
+ "layers: { "
+ " name: 'data' "
+ " type: DUMMY_DATA "
+ " dummy_data_param { "
+ " num: 5 "
+ " channels: 2 "
+ " height: 3 "
+ " width: 4 "
+ " num: 5 "
+ " channels: 1 "
+ " height: 1 "
+ " width: 1 "
+ " data_filler { "
+ " type: 'gaussian' "
+ " std: 0.01 "
+ " } "
+ " } "
+ " top: 'data' "
+ " top: 'label' "
+ "} "
+ "layers: { "
+ " name: 'innerproduct' "
+ " type: INNER_PRODUCT "
+ " inner_product_param { "
+ " num_output: 1000 "
+ " weight_filler { "
+ " type: 'gaussian' "
+ " std: 0.01 "
+ " } "
+ " bias_filler { "
+ " type: 'constant' "
+ " value: 0 "
+ " } "
+ " } "
+ " blobs_lr: 1. "
+ " blobs_lr: 2. "
+ " weight_decay: 1. "
+ " weight_decay: 0. "
+ " bottom: 'data' "
+ " top: 'transformed_data' "
+ "} "
+ "layers: { "
+ " name: 'innerproduct' "
+ " type: INNER_PRODUCT "
+ " inner_product_param { "
+ " num_output: 1 "
+ " weight_filler { "
+ " type: 'gaussian' "
+ " std: 0.01 "
+ " } "
+ " bias_filler { "
+ " type: 'constant' "
+ " value: 0 "
+ " } "
+ " } "
+ " blobs_lr: 1. "
+ " blobs_lr: 2. "
+ " weight_decay: 1. "
+ " weight_decay: 0. "
+ " bottom: 'label' "
+ " top: 'transformed_label' "
+ "} "
+ "layers: { "
+ " name: 'loss' "
+ " type: SOFTMAX_LOSS "
+ " bottom: 'transformed_data' "
+ " bottom: 'transformed_label' "
+ "} ";
+ InitNetFromProtoString(proto);
}
shared_ptr<Net<Dtype> > net_;
TYPED_TEST_CASE(NetTest, Dtypes);
TYPED_TEST(NetTest, TestHasBlob) {
+ this->InitTinyNet();
EXPECT_TRUE(this->net_->has_blob("data"));
EXPECT_TRUE(this->net_->has_blob("label"));
EXPECT_TRUE(this->net_->has_blob("innerproduct"));
}
TYPED_TEST(NetTest, TestGetBlob) {
+ this->InitTinyNet();
EXPECT_EQ(this->net_->blob_by_name("data"), this->net_->blobs()[0]);
EXPECT_EQ(this->net_->blob_by_name("label"), this->net_->blobs()[1]);
EXPECT_EQ(this->net_->blob_by_name("innerproduct"), this->net_->blobs()[2]);
}
TYPED_TEST(NetTest, TestHasLayer) {
+ this->InitTinyNet();
EXPECT_TRUE(this->net_->has_layer("data"));
EXPECT_TRUE(this->net_->has_layer("innerproduct"));
EXPECT_TRUE(this->net_->has_layer("loss"));
}
TYPED_TEST(NetTest, TestGetLayerByName) {
+ this->InitTinyNet();
EXPECT_EQ(this->net_->layer_by_name("data"), this->net_->layers()[0]);
EXPECT_EQ(this->net_->layer_by_name("innerproduct"), this->net_->layers()[1]);
EXPECT_EQ(this->net_->layer_by_name("loss"), this->net_->layers()[2]);
EXPECT_FALSE(this->net_->layer_by_name("label"));
}
+TYPED_TEST(NetTest, TestBottomNeedBackward) {
+ this->InitTinyNet();
+ const vector<vector<bool> >& bottom_need_backward =
+ this->net_->bottom_need_backward();
+ EXPECT_EQ(3, bottom_need_backward.size());
+ EXPECT_EQ(0, bottom_need_backward[0].size());
+ EXPECT_EQ(1, bottom_need_backward[1].size());
+ EXPECT_EQ(false, bottom_need_backward[1][0]);
+ EXPECT_EQ(2, bottom_need_backward[2].size());
+ EXPECT_EQ(true, bottom_need_backward[2][0]);
+ EXPECT_EQ(false, bottom_need_backward[2][1]);
+}
+
+TYPED_TEST(NetTest, TestBottomNeedBackwardForce) {
+ const bool force_backward = true;
+ this->InitTinyNet(force_backward);
+ const vector<vector<bool> >& bottom_need_backward =
+ this->net_->bottom_need_backward();
+ EXPECT_EQ(3, bottom_need_backward.size());
+ EXPECT_EQ(0, bottom_need_backward[0].size());
+ EXPECT_EQ(1, bottom_need_backward[1].size());
+ EXPECT_EQ(true, bottom_need_backward[1][0]);
+ EXPECT_EQ(2, bottom_need_backward[2].size());
+ EXPECT_EQ(true, bottom_need_backward[2][0]);
+ EXPECT_EQ(true, bottom_need_backward[2][1]);
+}
+
+TYPED_TEST(NetTest, TestBottomNeedBackwardTricky) {
+ this->InitTrickyNet();
+ const vector<vector<bool> >& bottom_need_backward =
+ this->net_->bottom_need_backward();
+ EXPECT_EQ(4, bottom_need_backward.size());
+ EXPECT_EQ(0, bottom_need_backward[0].size());
+ EXPECT_EQ(1, bottom_need_backward[1].size());
+ EXPECT_EQ(false, bottom_need_backward[1][0]);
+ EXPECT_EQ(1, bottom_need_backward[2].size());
+ EXPECT_EQ(false, bottom_need_backward[2][0]);
+ EXPECT_EQ(2, bottom_need_backward[3].size());
+ EXPECT_EQ(true, bottom_need_backward[3][0]);
+ EXPECT_EQ(true, bottom_need_backward[3][1]);
+}
+
} // namespace caffe
const vector<shared_ptr<Layer<float> > >& layers = caffe_net.layers();
vector<vector<Blob<float>*> >& bottom_vecs = caffe_net.bottom_vecs();
vector<vector<Blob<float>*> >& top_vecs = caffe_net.top_vecs();
+ const vector<vector<bool> >& bottom_need_backward =
+ caffe_net.bottom_need_backward();
LOG(ERROR) << "*** Benchmark begins ***";
Timer total_timer;
total_timer.Start();
const string& layername = layers[i]->layer_param().name();
timer.Start();
for (int j = 0; j < total_iter; ++j) {
- layers[i]->Backward(top_vecs[i], true, &bottom_vecs[i]);
+ layers[i]->Backward(top_vecs[i], bottom_need_backward[i],
+ &bottom_vecs[i]);
}
LOG(ERROR) << layername << "\tbackward: "
<< timer.MilliSeconds() << " milli seconds.";