Caffe
layer.hpp
1 #ifndef CAFFE_LAYER_H_
2 #define CAFFE_LAYER_H_
3 
4 #include <algorithm>
5 #include <string>
6 #include <vector>
7 
8 #include "caffe/blob.hpp"
9 #include "caffe/common.hpp"
10 #include "caffe/layer_factory.hpp"
11 #include "caffe/proto/caffe.pb.h"
12 #include "caffe/util/math_functions.hpp"
13 
18 namespace boost { class mutex; }
19 
20 namespace caffe {
21 
32 template <typename Dtype>
33 class Layer {
34  public:
40  explicit Layer(const LayerParameter& param)
41  : layer_param_(param), is_shared_(false) {
42  // Set phase and copy blobs (if there are any).
43  phase_ = param.phase();
44  if (layer_param_.blobs_size() > 0) {
45  blobs_.resize(layer_param_.blobs_size());
46  for (int i = 0; i < layer_param_.blobs_size(); ++i) {
47  blobs_[i].reset(new Blob<Dtype>());
48  blobs_[i]->FromProto(layer_param_.blobs(i));
49  }
50  }
51  }
52  virtual ~Layer() {}
53 
67  void SetUp(const vector<Blob<Dtype>*>& bottom,
68  const vector<Blob<Dtype>*>& top) {
69  InitMutex();
70  CheckBlobCounts(bottom, top);
71  LayerSetUp(bottom, top);
72  Reshape(bottom, top);
73  SetLossWeights(top);
74  }
75 
92  virtual void LayerSetUp(const vector<Blob<Dtype>*>& bottom,
93  const vector<Blob<Dtype>*>& top) {}
94 
101  virtual inline bool ShareInParallel() const { return false; }
102 
107  inline bool IsShared() const { return is_shared_; }
108 
113  inline void SetShared(bool is_shared) {
114  CHECK(ShareInParallel() || !is_shared)
115  << type() << "Layer does not support sharing.";
116  is_shared_ = is_shared;
117  }
118 
131  virtual void Reshape(const vector<Blob<Dtype>*>& bottom,
132  const vector<Blob<Dtype>*>& top) = 0;
133 
151  inline Dtype Forward(const vector<Blob<Dtype>*>& bottom,
152  const vector<Blob<Dtype>*>& top);
153 
175  inline void Backward(const vector<Blob<Dtype>*>& top,
176  const vector<bool>& propagate_down,
177  const vector<Blob<Dtype>*>& bottom);
178 
182  vector<shared_ptr<Blob<Dtype> > >& blobs() {
183  return blobs_;
184  }
185 
189  const LayerParameter& layer_param() const { return layer_param_; }
190 
194  virtual void ToProto(LayerParameter* param, bool write_diff = false);
195 
199  inline Dtype loss(const int top_index) const {
200  return (loss_.size() > top_index) ? loss_[top_index] : Dtype(0);
201  }
202 
206  inline void set_loss(const int top_index, const Dtype value) {
207  if (loss_.size() <= top_index) {
208  loss_.resize(top_index + 1, Dtype(0));
209  }
210  loss_[top_index] = value;
211  }
212 
216  virtual inline const char* type() const { return ""; }
217 
225  virtual inline int ExactNumBottomBlobs() const { return -1; }
233  virtual inline int MinBottomBlobs() const { return -1; }
241  virtual inline int MaxBottomBlobs() const { return -1; }
249  virtual inline int ExactNumTopBlobs() const { return -1; }
257  virtual inline int MinTopBlobs() const { return -1; }
265  virtual inline int MaxTopBlobs() const { return -1; }
273  virtual inline bool EqualNumBottomTopBlobs() const { return false; }
274 
283  virtual inline bool AutoTopBlobs() const { return false; }
284 
293  virtual inline bool AllowForceBackward(const int bottom_index) const {
294  return true;
295  }
296 
304  inline bool param_propagate_down(const int param_id) {
305  return (param_propagate_down_.size() > param_id) ?
306  param_propagate_down_[param_id] : false;
307  }
312  inline void set_param_propagate_down(const int param_id, const bool value) {
313  if (param_propagate_down_.size() <= param_id) {
314  param_propagate_down_.resize(param_id + 1, true);
315  }
316  param_propagate_down_[param_id] = value;
317  }
318 
319 
320  protected:
322  LayerParameter layer_param_;
324  Phase phase_;
326  vector<shared_ptr<Blob<Dtype> > > blobs_;
328  vector<bool> param_propagate_down_;
329 
332  vector<Dtype> loss_;
333 
335  virtual void Forward_cpu(const vector<Blob<Dtype>*>& bottom,
336  const vector<Blob<Dtype>*>& top) = 0;
341  virtual void Forward_gpu(const vector<Blob<Dtype>*>& bottom,
342  const vector<Blob<Dtype>*>& top) {
343  // LOG(WARNING) << "Using CPU code as backup.";
344  return Forward_cpu(bottom, top);
345  }
346 
351  virtual void Backward_cpu(const vector<Blob<Dtype>*>& top,
352  const vector<bool>& propagate_down,
353  const vector<Blob<Dtype>*>& bottom) = 0;
359  virtual void Backward_gpu(const vector<Blob<Dtype>*>& top,
360  const vector<bool>& propagate_down,
361  const vector<Blob<Dtype>*>& bottom) {
362  // LOG(WARNING) << "Using CPU code as backup.";
363  Backward_cpu(top, propagate_down, bottom);
364  }
365 
371  virtual void CheckBlobCounts(const vector<Blob<Dtype>*>& bottom,
372  const vector<Blob<Dtype>*>& top) {
373  if (ExactNumBottomBlobs() >= 0) {
374  CHECK_EQ(ExactNumBottomBlobs(), bottom.size())
375  << type() << " Layer takes " << ExactNumBottomBlobs()
376  << " bottom blob(s) as input.";
377  }
378  if (MinBottomBlobs() >= 0) {
379  CHECK_LE(MinBottomBlobs(), bottom.size())
380  << type() << " Layer takes at least " << MinBottomBlobs()
381  << " bottom blob(s) as input.";
382  }
383  if (MaxBottomBlobs() >= 0) {
384  CHECK_GE(MaxBottomBlobs(), bottom.size())
385  << type() << " Layer takes at most " << MaxBottomBlobs()
386  << " bottom blob(s) as input.";
387  }
388  if (ExactNumTopBlobs() >= 0) {
389  CHECK_EQ(ExactNumTopBlobs(), top.size())
390  << type() << " Layer produces " << ExactNumTopBlobs()
391  << " top blob(s) as output.";
392  }
393  if (MinTopBlobs() >= 0) {
394  CHECK_LE(MinTopBlobs(), top.size())
395  << type() << " Layer produces at least " << MinTopBlobs()
396  << " top blob(s) as output.";
397  }
398  if (MaxTopBlobs() >= 0) {
399  CHECK_GE(MaxTopBlobs(), top.size())
400  << type() << " Layer produces at most " << MaxTopBlobs()
401  << " top blob(s) as output.";
402  }
403  if (EqualNumBottomTopBlobs()) {
404  CHECK_EQ(bottom.size(), top.size())
405  << type() << " Layer produces one top blob as output for each "
406  << "bottom blob input.";
407  }
408  }
409 
414  inline void SetLossWeights(const vector<Blob<Dtype>*>& top) {
415  const int num_loss_weights = layer_param_.loss_weight_size();
416  if (num_loss_weights) {
417  CHECK_EQ(top.size(), num_loss_weights) << "loss_weight must be "
418  "unspecified or specified once per top blob.";
419  for (int top_id = 0; top_id < top.size(); ++top_id) {
420  const Dtype loss_weight = layer_param_.loss_weight(top_id);
421  if (loss_weight == Dtype(0)) { continue; }
422  this->set_loss(top_id, loss_weight);
423  const int count = top[top_id]->count();
424  Dtype* loss_multiplier = top[top_id]->mutable_cpu_diff();
425  caffe_set(count, loss_weight, loss_multiplier);
426  }
427  }
428  }
429 
430  private:
432  bool is_shared_;
433 
435  shared_ptr<boost::mutex> forward_mutex_;
436 
438  void InitMutex();
440  void Lock();
442  void Unlock();
443 
444  DISABLE_COPY_AND_ASSIGN(Layer);
445 }; // class Layer
446 
447 // Forward and backward wrappers. You should implement the cpu and
448 // gpu specific implementations instead, and should not change these
449 // functions.
450 template <typename Dtype>
451 inline Dtype Layer<Dtype>::Forward(const vector<Blob<Dtype>*>& bottom,
452  const vector<Blob<Dtype>*>& top) {
453  // Lock during forward to ensure sequential forward
454  Lock();
455  Dtype loss = 0;
456  Reshape(bottom, top);
457  switch (Caffe::mode()) {
458  case Caffe::CPU:
459  Forward_cpu(bottom, top);
460  for (int top_id = 0; top_id < top.size(); ++top_id) {
461  if (!this->loss(top_id)) { continue; }
462  const int count = top[top_id]->count();
463  const Dtype* data = top[top_id]->cpu_data();
464  const Dtype* loss_weights = top[top_id]->cpu_diff();
465  loss += caffe_cpu_dot(count, data, loss_weights);
466  }
467  break;
468  case Caffe::GPU:
469  Forward_gpu(bottom, top);
470 #ifndef CPU_ONLY
471  for (int top_id = 0; top_id < top.size(); ++top_id) {
472  if (!this->loss(top_id)) { continue; }
473  const int count = top[top_id]->count();
474  const Dtype* data = top[top_id]->gpu_data();
475  const Dtype* loss_weights = top[top_id]->gpu_diff();
476  Dtype blob_loss = 0;
477  caffe_gpu_dot(count, data, loss_weights, &blob_loss);
478  loss += blob_loss;
479  }
480 #endif
481  break;
482  default:
483  LOG(FATAL) << "Unknown caffe mode.";
484  }
485  Unlock();
486  return loss;
487 }
488 
489 template <typename Dtype>
490 inline void Layer<Dtype>::Backward(const vector<Blob<Dtype>*>& top,
491  const vector<bool>& propagate_down,
492  const vector<Blob<Dtype>*>& bottom) {
493  switch (Caffe::mode()) {
494  case Caffe::CPU:
495  Backward_cpu(top, propagate_down, bottom);
496  break;
497  case Caffe::GPU:
498  Backward_gpu(top, propagate_down, bottom);
499  break;
500  default:
501  LOG(FATAL) << "Unknown caffe mode.";
502  }
503 }
504 
505 // Serialize LayerParameter to protocol buffer
506 template <typename Dtype>
507 void Layer<Dtype>::ToProto(LayerParameter* param, bool write_diff) {
508  param->Clear();
509  param->CopyFrom(layer_param_);
510  param->clear_blobs();
511  for (int i = 0; i < blobs_.size(); ++i) {
512  blobs_[i]->ToProto(param->add_blobs(), write_diff);
513  }
514 }
515 
516 } // namespace caffe
517 
518 #endif // CAFFE_LAYER_H_
virtual void Backward_gpu(const vector< Blob< Dtype > *> &top, const vector< bool > &propagate_down, const vector< Blob< Dtype > *> &bottom)
Using the GPU device, compute the gradients for any parameters and for the bottom blobs if propagate_...
Definition: layer.hpp:359
vector< Dtype > loss_
Definition: layer.hpp:332
virtual void Forward_gpu(const vector< Blob< Dtype > *> &bottom, const vector< Blob< Dtype > *> &top)
Using the GPU device, compute the layer output. Fall back to Forward_cpu() if unavailable.
Definition: layer.hpp:341
An interface for the units of computation which can be composed into a Net.
Definition: layer.hpp:33
A layer factory that allows one to register layers. During runtime, registered layers can be called b...
Definition: blob.hpp:14
Definition: internal_thread.hpp:10
vector< shared_ptr< Blob< Dtype > > > blobs_
Definition: layer.hpp:326
virtual const char * type() const
Returns the layer type.
Definition: layer.hpp:216
vector< shared_ptr< Blob< Dtype > > > & blobs()
Returns the vector of learnable parameter blobs.
Definition: layer.hpp:182
virtual int MaxTopBlobs() const
Returns the maximum number of top blobs required by the layer, or -1 if no maximum number is required...
Definition: layer.hpp:265
void SetShared(bool is_shared)
Set whether this layer is actually shared by other nets If ShareInParallel() is true and using more t...
Definition: layer.hpp:113
void SetLossWeights(const vector< Blob< Dtype > *> &top)
Definition: layer.hpp:414
vector< bool > param_propagate_down_
Definition: layer.hpp:328
virtual int ExactNumBottomBlobs() const
Returns the exact number of bottom blobs required by the layer, or -1 if no exact number is required...
Definition: layer.hpp:225
virtual int MaxBottomBlobs() const
Returns the maximum number of bottom blobs required by the layer, or -1 if no maximum number is requi...
Definition: layer.hpp:241
void set_param_propagate_down(const int param_id, const bool value)
Sets whether the layer should compute gradients w.r.t. a parameter at a particular index given by par...
Definition: layer.hpp:312
virtual bool ShareInParallel() const
Whether a layer should be shared by multiple nets during data parallelism. By default, all layers except for data layers should not be shared. data layers should be shared to ensure each worker solver access data sequentially during data parallelism.
Definition: layer.hpp:101
const LayerParameter & layer_param() const
Returns the layer parameter.
Definition: layer.hpp:189
virtual int ExactNumTopBlobs() const
Returns the exact number of top blobs required by the layer, or -1 if no exact number is required...
Definition: layer.hpp:249
void SetUp(const vector< Blob< Dtype > *> &bottom, const vector< Blob< Dtype > *> &top)
Implements common layer setup functionality.
Definition: layer.hpp:67
Layer(const LayerParameter &param)
Definition: layer.hpp:40
virtual bool AllowForceBackward(const int bottom_index) const
Return whether to allow force_backward for a given bottom blob index.
Definition: layer.hpp:293
virtual bool AutoTopBlobs() const
Return whether "anonymous" top blobs are created automatically by the layer.
Definition: layer.hpp:283
virtual int MinTopBlobs() const
Returns the minimum number of top blobs required by the layer, or -1 if no minimum number is required...
Definition: layer.hpp:257
virtual void ToProto(LayerParameter *param, bool write_diff=false)
Writes the layer parameter to a protocol buffer.
Definition: layer.hpp:507
Phase phase_
Definition: layer.hpp:324
LayerParameter layer_param_
Definition: layer.hpp:322
virtual void LayerSetUp(const vector< Blob< Dtype > *> &bottom, const vector< Blob< Dtype > *> &top)
Does layer-specific setup: your layer should implement this function as well as Reshape.
Definition: layer.hpp:92
void set_loss(const int top_index, const Dtype value)
Sets the loss associated with a top blob at a given index.
Definition: layer.hpp:206
Dtype loss(const int top_index) const
Returns the scalar loss associated with a top blob at a given index.
Definition: layer.hpp:199
virtual int MinBottomBlobs() const
Returns the minimum number of bottom blobs required by the layer, or -1 if no minimum number is requi...
Definition: layer.hpp:233
bool IsShared() const
Return whether this layer is actually shared by other nets. If ShareInParallel() is true and using mo...
Definition: layer.hpp:107
virtual void CheckBlobCounts(const vector< Blob< Dtype > *> &bottom, const vector< Blob< Dtype > *> &top)
Definition: layer.hpp:371
bool param_propagate_down(const int param_id)
Specifies whether the layer should compute gradients w.r.t. a parameter at a particular index given b...
Definition: layer.hpp:304
virtual bool EqualNumBottomTopBlobs() const
Returns true if the layer requires an equal number of bottom and top blobs.
Definition: layer.hpp:273
A wrapper around SyncedMemory holders serving as the basic computational unit through which Layers...
Definition: blob.hpp:24