layers declare their names and number of input/output blobs, and don't
authorJeff Donahue <jeff.donahue@gmail.com>
Fri, 6 Jun 2014 22:40:26 +0000 (15:40 -0700)
committerJeff Donahue <jeff.donahue@gmail.com>
Mon, 9 Jun 2014 02:03:17 +0000 (19:03 -0700)
check top/bottom blob counts explicitly in SetUp; instead call base
Layer::SetUp.

26 files changed:
include/caffe/data_layers.hpp
include/caffe/layer.hpp
include/caffe/loss_layers.hpp
include/caffe/neuron_layers.hpp
include/caffe/vision_layers.hpp
src/caffe/layers/accuracy_layer.cpp
src/caffe/layers/argmax_layer.cpp
src/caffe/layers/concat_layer.cpp
src/caffe/layers/conv_layer.cpp
src/caffe/layers/data_layer.cpp
src/caffe/layers/eltwise_layer.cpp
src/caffe/layers/flatten_layer.cpp
src/caffe/layers/hdf5_data_layer.cpp
src/caffe/layers/hdf5_output_layer.cpp
src/caffe/layers/im2col_layer.cpp
src/caffe/layers/image_data_layer.cpp
src/caffe/layers/inner_product_layer.cpp
src/caffe/layers/loss_layer.cpp
src/caffe/layers/lrn_layer.cpp
src/caffe/layers/memory_data_layer.cpp
src/caffe/layers/neuron_layer.cpp
src/caffe/layers/pooling_layer.cpp
src/caffe/layers/softmax_layer.cpp
src/caffe/layers/softmax_loss_layer.cpp
src/caffe/layers/split_layer.cpp
src/caffe/layers/window_data_layer.cpp

index d9865ce..4678b32 100644 (file)
@@ -28,7 +28,15 @@ class HDF5OutputLayer : public Layer<Dtype> {
   explicit HDF5OutputLayer(const LayerParameter& param);
   virtual ~HDF5OutputLayer();
   virtual void SetUp(const vector<Blob<Dtype>*>& bottom,
-      vector<Blob<Dtype>*>* top);
+      vector<Blob<Dtype>*>* top) {}
+
+  virtual inline LayerParameter_LayerType type() const {
+    return LayerParameter_LayerType_HDF5_OUTPUT;
+  }
+  // TODO: no limit on the number of blobs
+  virtual inline int ExactNumBottomBlobs() const { return 2; }
+  virtual inline int ExactNumTopBlobs() const { return 0; }
+
   inline std::string file_name() const { return file_name_; }
 
  protected:
@@ -58,6 +66,12 @@ class HDF5DataLayer : public Layer<Dtype> {
   virtual void SetUp(const vector<Blob<Dtype>*>& bottom,
       vector<Blob<Dtype>*>* top);
 
+  virtual inline LayerParameter_LayerType type() const {
+    return LayerParameter_LayerType_HDF5_DATA;
+  }
+  virtual inline int ExactNumBottomBlobs() const { return 0; }
+  virtual inline int ExactNumTopBlobs() const { return 2; }
+
  protected:
   virtual Dtype Forward_cpu(const vector<Blob<Dtype>*>& bottom,
       vector<Blob<Dtype>*>* top);
@@ -96,6 +110,13 @@ class DataLayer : public Layer<Dtype> {
   virtual void SetUp(const vector<Blob<Dtype>*>& bottom,
       vector<Blob<Dtype>*>* top);
 
+  virtual inline LayerParameter_LayerType type() const {
+    return LayerParameter_LayerType_DATA;
+  }
+  virtual inline int ExactNumBottomBlobs() const { return 0; }
+  virtual inline int MinTopBlobs() const { return 1; }
+  virtual inline int MaxTopBlobs() const { return 2; }
+
  protected:
   virtual Dtype Forward_cpu(const vector<Blob<Dtype>*>& bottom,
       vector<Blob<Dtype>*>* top);
@@ -141,6 +162,12 @@ class ImageDataLayer : public Layer<Dtype> {
   virtual void SetUp(const vector<Blob<Dtype>*>& bottom,
       vector<Blob<Dtype>*>* top);
 
+  virtual inline LayerParameter_LayerType type() const {
+    return LayerParameter_LayerType_IMAGE_DATA;
+  }
+  virtual inline int ExactNumBottomBlobs() const { return 0; }
+  virtual inline int ExactNumTopBlobs() const { return 2; }
+
  protected:
   virtual Dtype Forward_cpu(const vector<Blob<Dtype>*>& bottom,
       vector<Blob<Dtype>*>* top);
@@ -188,6 +215,12 @@ class WindowDataLayer : public Layer<Dtype> {
   virtual void SetUp(const vector<Blob<Dtype>*>& bottom,
       vector<Blob<Dtype>*>* top);
 
+  virtual inline LayerParameter_LayerType type() const {
+    return LayerParameter_LayerType_WINDOW_DATA;
+  }
+  virtual inline int ExactNumBottomBlobs() const { return 0; }
+  virtual inline int ExactNumTopBlobs() const { return 2; }
+
  protected:
   virtual Dtype Forward_cpu(const vector<Blob<Dtype>*>& bottom,
       vector<Blob<Dtype>*>* top);
index 14bba63..af3d544 100644 (file)
@@ -3,11 +3,14 @@
 #ifndef CAFFE_LAYER_H_
 #define CAFFE_LAYER_H_
 
+#include <string>
 #include <vector>
+
 #include "caffe/blob.hpp"
 #include "caffe/common.hpp"
 #include "caffe/proto/caffe.pb.h"
 
+using std::string;
 using std::vector;
 
 namespace caffe {
@@ -30,9 +33,12 @@ class Layer {
       }
     }
   virtual ~Layer() {}
-  // SetUp: your function should implement this.
+  // SetUp: your function should implement this, and call Layer::SetUp for
+  // common SetUp functionality.
   virtual void SetUp(const vector<Blob<Dtype>*>& bottom,
-      vector<Blob<Dtype>*>* top) = 0;
+      vector<Blob<Dtype>*>* top) {
+    CheckBlobCounts(bottom, *top);
+  }
 
   // Forward and backward wrappers. You should implement the cpu and
   // gpu specific implementations instead, and should not change these
@@ -53,6 +59,31 @@ class Layer {
   // Writes the layer parameter to a protocol buffer
   virtual void ToProto(LayerParameter* param, bool write_diff = false);
 
+  // Returns the layer type as an enum value.
+  virtual inline LayerParameter_LayerType type() const {
+    return LayerParameter_LayerType_NONE;
+  }
+
+  // Returns the layer type name.
+  virtual inline const string& type_name() const {
+    return LayerParameter_LayerType_Name(type());
+  }
+
+  // These methods can be overwritten to declare that this layer type expects
+  // a certain number of blobs as input and output.
+  //
+  // ExactNum{Bottom,Top}Blobs return a non-negative number to require an exact
+  // number of bottom/top blobs; the Min/Max versions return a non-negative
+  // number to require a minimum and/or maximum number of blobs.
+  // If Exact is specified, neither Min nor Max should be specified, and vice
+  // versa.  These methods may not rely on SetUp having been called.
+  virtual inline int ExactNumBottomBlobs() const { return -1; }
+  virtual inline int MinBottomBlobs() const { return -1; }
+  virtual inline int MaxBottomBlobs() const { return -1; }
+  virtual inline int ExactNumTopBlobs() const { return -1; }
+  virtual inline int MinTopBlobs() const { return -1; }
+  virtual inline int MaxTopBlobs() const { return -1; }
+
  protected:
   // The protobuf that stores the layer parameters
   LayerParameter layer_param_;
@@ -82,6 +113,43 @@ class Layer {
     Backward_cpu(top, propagate_down, bottom);
   }
 
+  // CheckBlobCounts: called by the parent Layer's SetUp to check that the
+  // number of bottom and top Blobs provided as input match the expected
+  // numbers specified by the {ExactNum,Min,Max}{Bottom,Top}Blobs() functions.
+  virtual void CheckBlobCounts(const vector<Blob<Dtype>*>& bottom,
+                               const vector<Blob<Dtype>*>& top) {
+    if (ExactNumBottomBlobs() >= 0) {
+      CHECK_EQ(ExactNumBottomBlobs(), bottom.size())
+          << type_name() << " Layer takes " << ExactNumBottomBlobs()
+          << " bottom blob(s) as input.";
+    }
+    if (MinBottomBlobs() >= 0) {
+      CHECK_LE(MinBottomBlobs(), bottom.size())
+          << type_name() << " Layer takes at least " << MinBottomBlobs()
+          << " bottom blob(s) as input.";
+    }
+    if (MaxBottomBlobs() >= 0) {
+      CHECK_GE(MaxBottomBlobs(), bottom.size())
+          << type_name() << " Layer takes at most " << MaxBottomBlobs()
+          << " bottom blob(s) as input.";
+    }
+    if (ExactNumTopBlobs() >= 0) {
+      CHECK_EQ(ExactNumTopBlobs(), top.size())
+          << type_name() << " Layer produces " << ExactNumTopBlobs()
+          << " top blob(s) as output.";
+    }
+    if (MinTopBlobs() >= 0) {
+      CHECK_LE(MinTopBlobs(), top.size())
+          << type_name() << " Layer produces at least " << MinTopBlobs()
+          << " top blob(s) as output.";
+    }
+    if (MaxTopBlobs() >= 0) {
+      CHECK_GE(MaxTopBlobs(), top.size())
+          << type_name() << " Layer produces at most " << MaxTopBlobs()
+          << " top blob(s) as output.";
+    }
+  }
+
   DISABLE_COPY_AND_ASSIGN(Layer);
 };  // class Layer
 
index cc798c4..381bf0f 100644 (file)
@@ -35,6 +35,9 @@ class LossLayer : public Layer<Dtype> {
       const vector<Blob<Dtype>*>& bottom, vector<Blob<Dtype>*>* top);
   virtual void FurtherSetUp(
       const vector<Blob<Dtype>*>& bottom, vector<Blob<Dtype>*>* top) {}
+
+  virtual inline int ExactNumBottomBlobs() const { return 2; }
+  virtual inline int ExactNumTopBlobs() const { return 0; }
 };
 
 /* SigmoidCrossEntropyLossLayer
@@ -49,6 +52,10 @@ class SigmoidCrossEntropyLossLayer : public LossLayer<Dtype> {
   virtual void FurtherSetUp(const vector<Blob<Dtype>*>& bottom,
       vector<Blob<Dtype>*>* top);
 
+  virtual inline LayerParameter_LayerType type() const {
+    return LayerParameter_LayerType_SIGMOID_CROSS_ENTROPY_LOSS;
+  }
+
  protected:
   virtual Dtype Forward_cpu(const vector<Blob<Dtype>*>& bottom,
       vector<Blob<Dtype>*>* top);
@@ -81,6 +88,10 @@ class EuclideanLossLayer : public LossLayer<Dtype> {
   virtual void FurtherSetUp(const vector<Blob<Dtype>*>& bottom,
       vector<Blob<Dtype>*>* top);
 
+  virtual inline LayerParameter_LayerType type() const {
+    return LayerParameter_LayerType_EUCLIDEAN_LOSS;
+  }
+
  protected:
   virtual Dtype Forward_cpu(const vector<Blob<Dtype>*>& bottom,
       vector<Blob<Dtype>*>* top);
@@ -100,6 +111,10 @@ class InfogainLossLayer : public LossLayer<Dtype> {
   virtual void FurtherSetUp(const vector<Blob<Dtype>*>& bottom,
       vector<Blob<Dtype>*>* top);
 
+  virtual inline LayerParameter_LayerType type() const {
+    return LayerParameter_LayerType_INFOGAIN_LOSS;
+  }
+
  protected:
   virtual Dtype Forward_cpu(const vector<Blob<Dtype>*>& bottom,
       vector<Blob<Dtype>*>* top);
@@ -117,6 +132,10 @@ class HingeLossLayer : public LossLayer<Dtype> {
   explicit HingeLossLayer(const LayerParameter& param)
       : LossLayer<Dtype>(param) {}
 
+  virtual inline LayerParameter_LayerType type() const {
+    return LayerParameter_LayerType_HINGE_LOSS;
+  }
+
  protected:
   virtual Dtype Forward_cpu(const vector<Blob<Dtype>*>& bottom,
       vector<Blob<Dtype>*>* top);
@@ -134,6 +153,10 @@ class MultinomialLogisticLossLayer : public LossLayer<Dtype> {
   virtual void FurtherSetUp(const vector<Blob<Dtype>*>& bottom,
       vector<Blob<Dtype>*>* top);
 
+  virtual inline LayerParameter_LayerType type() const {
+    return LayerParameter_LayerType_MULTINOMIAL_LOGISTIC_LOSS;
+  }
+
  protected:
   virtual Dtype Forward_cpu(const vector<Blob<Dtype>*>& bottom,
       vector<Blob<Dtype>*>* top);
@@ -153,6 +176,10 @@ class AccuracyLayer : public Layer<Dtype> {
   virtual void SetUp(const vector<Blob<Dtype>*>& bottom,
       vector<Blob<Dtype>*>* top);
 
+  virtual inline LayerParameter_LayerType type() const {
+    return LayerParameter_LayerType_ACCURACY;
+  }
+
  protected:
   virtual Dtype Forward_cpu(const vector<Blob<Dtype>*>& bottom,
       vector<Blob<Dtype>*>* top);
index 5118e8a..ed664df 100644 (file)
@@ -33,6 +33,12 @@ class NeuronLayer : public Layer<Dtype> {
      : Layer<Dtype>(param) {}
   virtual void SetUp(const vector<Blob<Dtype>*>& bottom,
       vector<Blob<Dtype>*>* top);
+
+  virtual inline LayerParameter_LayerType type() const {
+    return LayerParameter_LayerType_NONE;
+  }
+  virtual inline int ExactNumBottomBlobs() const { return 1; }
+  virtual inline int ExactNumTopBlobs() const { return 1; }
 };
 
 /* BNLLLayer
@@ -48,6 +54,10 @@ class BNLLLayer : public NeuronLayer<Dtype> {
   explicit BNLLLayer(const LayerParameter& param)
       : NeuronLayer<Dtype>(param) {}
 
+  virtual inline LayerParameter_LayerType type() const {
+    return LayerParameter_LayerType_BNLL;
+  }
+
  protected:
   virtual Dtype Forward_cpu(const vector<Blob<Dtype>*>& bottom,
       vector<Blob<Dtype>*>* top);
@@ -77,6 +87,10 @@ class DropoutLayer : public NeuronLayer<Dtype> {
   virtual void SetUp(const vector<Blob<Dtype>*>& bottom,
       vector<Blob<Dtype>*>* top);
 
+  virtual inline LayerParameter_LayerType type() const {
+    return LayerParameter_LayerType_DROPOUT;
+  }
+
  protected:
   virtual Dtype Forward_cpu(const vector<Blob<Dtype>*>& bottom,
       vector<Blob<Dtype>*>* top);
@@ -107,6 +121,10 @@ class PowerLayer : public NeuronLayer<Dtype> {
   virtual void SetUp(const vector<Blob<Dtype>*>& bottom,
       vector<Blob<Dtype>*>* top);
 
+  virtual inline LayerParameter_LayerType type() const {
+    return LayerParameter_LayerType_POWER;
+  }
+
  protected:
   virtual Dtype Forward_cpu(const vector<Blob<Dtype>*>& bottom,
       vector<Blob<Dtype>*>* top);
@@ -138,6 +156,10 @@ class ReLULayer : public NeuronLayer<Dtype> {
   explicit ReLULayer(const LayerParameter& param)
       : NeuronLayer<Dtype>(param) {}
 
+  virtual inline LayerParameter_LayerType type() const {
+    return LayerParameter_LayerType_RELU;
+  }
+
  protected:
   virtual Dtype Forward_cpu(const vector<Blob<Dtype>*>& bottom,
       vector<Blob<Dtype>*>* top);
@@ -167,6 +189,10 @@ class SigmoidLayer : public NeuronLayer<Dtype> {
   explicit SigmoidLayer(const LayerParameter& param)
       : NeuronLayer<Dtype>(param) {}
 
+  virtual inline LayerParameter_LayerType type() const {
+    return LayerParameter_LayerType_SIGMOID;
+  }
+
  protected:
   virtual Dtype Forward_cpu(const vector<Blob<Dtype>*>& bottom,
       vector<Blob<Dtype>*>* top);
@@ -191,6 +217,10 @@ class TanHLayer : public NeuronLayer<Dtype> {
   explicit TanHLayer(const LayerParameter& param)
       : NeuronLayer<Dtype>(param) {}
 
+  virtual inline LayerParameter_LayerType type() const {
+    return LayerParameter_LayerType_TANH;
+  }
+
  protected:
   virtual Dtype Forward_cpu(const vector<Blob<Dtype>*>& bottom,
       vector<Blob<Dtype>*>* top);
@@ -220,6 +250,10 @@ class ThresholdLayer : public NeuronLayer<Dtype> {
   virtual void SetUp(const vector<Blob<Dtype>*>& bottom,
       vector<Blob<Dtype>*>* top);
 
+  virtual inline LayerParameter_LayerType type() const {
+    return LayerParameter_LayerType_THRESHOLD;
+  }
+
  protected:
   virtual Dtype Forward_cpu(const vector<Blob<Dtype>*>& bottom,
       vector<Blob<Dtype>*>* top);
index a43f7f9..3977980 100644 (file)
@@ -34,6 +34,12 @@ class ArgMaxLayer : public Layer<Dtype> {
   virtual void SetUp(const vector<Blob<Dtype>*>& bottom,
       vector<Blob<Dtype>*>* top);
 
+  virtual inline LayerParameter_LayerType type() const {
+    return LayerParameter_LayerType_ARGMAX;
+  }
+  virtual inline int MinBottomBlobs() const { return 1; }
+  virtual inline int ExactNumTopBlobs() const { return 1; }
+
  protected:
   virtual Dtype Forward_cpu(const vector<Blob<Dtype>*>& bottom,
       vector<Blob<Dtype>*>* top);
@@ -56,6 +62,12 @@ class ConcatLayer : public Layer<Dtype> {
   virtual void SetUp(const vector<Blob<Dtype>*>& bottom,
       vector<Blob<Dtype>*>* top);
 
+  virtual inline LayerParameter_LayerType type() const {
+    return LayerParameter_LayerType_CONCAT;
+  }
+  virtual inline int MinBottomBlobs() const { return 2; }
+  virtual inline int ExactNumTopBlobs() const { return 1; }
+
  protected:
   virtual Dtype Forward_cpu(const vector<Blob<Dtype>*>& bottom,
       vector<Blob<Dtype>*>* top);
@@ -85,6 +97,12 @@ class ConvolutionLayer : public Layer<Dtype> {
   virtual void SetUp(const vector<Blob<Dtype>*>& bottom,
       vector<Blob<Dtype>*>* top);
 
+  virtual inline LayerParameter_LayerType type() const {
+    return LayerParameter_LayerType_CONVOLUTION;
+  }
+  virtual inline int ExactNumBottomBlobs() const { return 1; }
+  virtual inline int ExactNumTopBlobs() const { return 1; }
+
  protected:
   virtual Dtype Forward_cpu(const vector<Blob<Dtype>*>& bottom,
       vector<Blob<Dtype>*>* top);
@@ -123,6 +141,12 @@ class EltwiseLayer : public Layer<Dtype> {
   virtual void SetUp(const vector<Blob<Dtype>*>& bottom,
       vector<Blob<Dtype>*>* top);
 
+  virtual inline LayerParameter_LayerType type() const {
+    return LayerParameter_LayerType_ELTWISE;
+  }
+  virtual inline int MinBottomBlobs() const { return 2; }
+  virtual inline int ExactNumTopBlobs() const { return 1; }
+
  protected:
   virtual Dtype Forward_cpu(const vector<Blob<Dtype>*>& bottom,
       vector<Blob<Dtype>*>* top);
@@ -147,6 +171,12 @@ class FlattenLayer : public Layer<Dtype> {
   virtual void SetUp(const vector<Blob<Dtype>*>& bottom,
       vector<Blob<Dtype>*>* top);
 
+  virtual inline LayerParameter_LayerType type() const {
+    return LayerParameter_LayerType_FLATTEN;
+  }
+  virtual inline int ExactNumBottomBlobs() const { return 1; }
+  virtual inline int ExactNumTopBlobs() const { return 1; }
+
  protected:
   virtual Dtype Forward_cpu(const vector<Blob<Dtype>*>& bottom,
       vector<Blob<Dtype>*>* top);
@@ -170,6 +200,12 @@ class Im2colLayer : public Layer<Dtype> {
   virtual void SetUp(const vector<Blob<Dtype>*>& bottom,
       vector<Blob<Dtype>*>* top);
 
+  virtual inline LayerParameter_LayerType type() const {
+    return LayerParameter_LayerType_IM2COL;
+  }
+  virtual inline int ExactNumBottomBlobs() const { return 1; }
+  virtual inline int ExactNumTopBlobs() const { return 1; }
+
  protected:
   virtual Dtype Forward_cpu(const vector<Blob<Dtype>*>& bottom,
       vector<Blob<Dtype>*>* top);
@@ -198,6 +234,12 @@ class InnerProductLayer : public Layer<Dtype> {
   virtual void SetUp(const vector<Blob<Dtype>*>& bottom,
       vector<Blob<Dtype>*>* top);
 
+  virtual inline LayerParameter_LayerType type() const {
+    return LayerParameter_LayerType_INNER_PRODUCT;
+  }
+  virtual inline int ExactNumBottomBlobs() const { return 1; }
+  virtual inline int ExactNumTopBlobs() const { return 1; }
+
  protected:
   virtual Dtype Forward_cpu(const vector<Blob<Dtype>*>& bottom,
       vector<Blob<Dtype>*>* top);
@@ -230,6 +272,12 @@ class LRNLayer : public Layer<Dtype> {
   virtual void SetUp(const vector<Blob<Dtype>*>& bottom,
       vector<Blob<Dtype>*>* top);
 
+  virtual inline LayerParameter_LayerType type() const {
+    return LayerParameter_LayerType_LRN;
+  }
+  virtual inline int ExactNumBottomBlobs() const { return 1; }
+  virtual inline int ExactNumTopBlobs() const { return 1; }
+
  protected:
   virtual Dtype Forward_cpu(const vector<Blob<Dtype>*>& bottom,
       vector<Blob<Dtype>*>* top);
@@ -285,7 +333,7 @@ class LRNLayer : public Layer<Dtype> {
   vector<Blob<Dtype>*> product_bottom_vec_;
 };
 
-/* PoolingLayer
+/* MemoryDataLayer
 */
 template <typename Dtype>
 class MemoryDataLayer : public Layer<Dtype> {
@@ -294,6 +342,13 @@ class MemoryDataLayer : public Layer<Dtype> {
       : Layer<Dtype>(param) {}
   virtual void SetUp(const vector<Blob<Dtype>*>& bottom,
       vector<Blob<Dtype>*>* top);
+
+  virtual inline LayerParameter_LayerType type() const {
+    return LayerParameter_LayerType_MEMORY_DATA;
+  }
+  virtual inline int ExactNumBottomBlobs() { return 0; }
+  virtual inline int ExactNumTopBlobs() { return 2; }
+
   // Reset should accept const pointers, but can't, because the memory
   //  will be given to Blob, which is mutable
   void Reset(Dtype* data, Dtype* label, int n);
@@ -331,6 +386,13 @@ class PoolingLayer : public Layer<Dtype> {
   virtual void SetUp(const vector<Blob<Dtype>*>& bottom,
       vector<Blob<Dtype>*>* top);
 
+  virtual inline LayerParameter_LayerType type() const {
+    return LayerParameter_LayerType_POOLING;
+  }
+  virtual inline int ExactNumBottomBlobs() const { return 1; }
+  virtual inline int MinTopBlobs() const { return 1; }
+  virtual inline int MaxTopBlobs() const { return max_top_blobs_; }
+
  protected:
   virtual Dtype Forward_cpu(const vector<Blob<Dtype>*>& bottom,
       vector<Blob<Dtype>*>* top);
@@ -341,6 +403,7 @@ class PoolingLayer : public Layer<Dtype> {
   virtual void Backward_gpu(const vector<Blob<Dtype>*>& top,
       const bool propagate_down, vector<Blob<Dtype>*>* bottom);
 
+  int max_top_blobs_;
   int kernel_size_;
   int stride_;
   int pad_;
@@ -363,6 +426,12 @@ class SoftmaxLayer : public Layer<Dtype> {
   virtual void SetUp(const vector<Blob<Dtype>*>& bottom,
       vector<Blob<Dtype>*>* top);
 
+  virtual inline LayerParameter_LayerType type() const {
+    return LayerParameter_LayerType_SOFTMAX;
+  }
+  virtual inline int ExactNumBottomBlobs() const { return 1; }
+  virtual inline int ExactNumTopBlobs() const { return 1; }
+
  protected:
   virtual Dtype Forward_cpu(const vector<Blob<Dtype>*>& bottom,
       vector<Blob<Dtype>*>* top);
@@ -395,6 +464,12 @@ class SoftmaxWithLossLayer : public Layer<Dtype> {
   virtual void SetUp(const vector<Blob<Dtype>*>& bottom,
       vector<Blob<Dtype>*>* top);
 
+  virtual inline LayerParameter_LayerType type() const {
+    return LayerParameter_LayerType_SOFTMAX_LOSS;
+  }
+  virtual inline int ExactNumBottomBlobs() const { return 2; }
+  virtual inline int ExactNumTopBlobs() const { return 0; }
+
  protected:
   virtual Dtype Forward_cpu(const vector<Blob<Dtype>*>& bottom,
       vector<Blob<Dtype>*>* top);
@@ -423,6 +498,12 @@ class SplitLayer : public Layer<Dtype> {
   virtual void SetUp(const vector<Blob<Dtype>*>& bottom,
       vector<Blob<Dtype>*>* top);
 
+  virtual inline LayerParameter_LayerType type() const {
+    return LayerParameter_LayerType_SPLIT;
+  }
+  virtual inline int ExactNumBottomBlobs() const { return 1; }
+  virtual inline int MinTopBlobs() const { return 1; }
+
  protected:
   virtual Dtype Forward_cpu(const vector<Blob<Dtype>*>& bottom,
       vector<Blob<Dtype>*>* top);
index 3e67170..fbc943e 100644 (file)
@@ -17,8 +17,7 @@ namespace caffe {
 template <typename Dtype>
 void AccuracyLayer<Dtype>::SetUp(
   const vector<Blob<Dtype>*>& bottom, vector<Blob<Dtype>*>* top) {
-  CHECK_EQ(bottom.size(), 2) << "Accuracy Layer takes two blobs as input.";
-  CHECK_EQ(top->size(), 1) << "Accuracy Layer takes 1 output.";
+  Layer<Dtype>::SetUp(bottom, top);
   CHECK_EQ(bottom[0]->num(), bottom[1]->num())
       << "The data and label should have the same number.";
   CHECK_EQ(bottom[1]->channels(), 1);
index e04588d..70ccfff 100644 (file)
@@ -12,8 +12,7 @@ namespace caffe {
 template <typename Dtype>
 void ArgMaxLayer<Dtype>::SetUp(const vector<Blob<Dtype>*>& bottom,
       vector<Blob<Dtype>*>* top) {
-  CHECK_EQ(bottom.size(), 1) << "ArgMaxLayer Layer takes 1 input.";
-  CHECK_EQ(top->size(), 1) << "ArgMaxLayer Layer takes 1 output.";
+  Layer<Dtype>::SetUp(bottom, top);
   out_max_val_ = this->layer_param_.argmax_param().out_max_val();
   if (out_max_val_) {
     // Produces max_ind and max_val
index 8036bda..4541ee7 100644 (file)
@@ -11,11 +11,7 @@ namespace caffe {
 template <typename Dtype>
 void ConcatLayer<Dtype>::SetUp(const vector<Blob<Dtype>*>& bottom,
       vector<Blob<Dtype>*>* top) {
-  CHECK_GT(bottom.size(), 1) <<
-    "ConcatLayer takes at least two blobs as input.";
-  CHECK_EQ(top->size(), 1) <<
-    "ConcatLayer takes a single blob as output.";
-
+  Layer<Dtype>::SetUp(bottom, top);
   concat_dim_ = this->layer_param_.concat_param().concat_dim();
   CHECK_GE(concat_dim_, 0) <<
     "concat_dim should be >= 0";
index 55966b5..880b83a 100644 (file)
@@ -13,8 +13,7 @@ namespace caffe {
 template <typename Dtype>
 void ConvolutionLayer<Dtype>::SetUp(const vector<Blob<Dtype>*>& bottom,
       vector<Blob<Dtype>*>* top) {
-  CHECK_EQ(bottom.size(), 1) << "Conv Layer takes a single blob as input.";
-  CHECK_EQ(top->size(), 1) << "Conv Layer takes a single blob as output.";
+  Layer<Dtype>::SetUp(bottom, top);
   kernel_size_ = this->layer_param_.convolution_param().kernel_size();
   stride_ = this->layer_param_.convolution_param().stride();
   group_ = this->layer_param_.convolution_param().group();
index 6d7392a..348753e 100644 (file)
@@ -129,9 +129,7 @@ DataLayer<Dtype>::~DataLayer<Dtype>() {
 template <typename Dtype>
 void DataLayer<Dtype>::SetUp(const vector<Blob<Dtype>*>& bottom,
       vector<Blob<Dtype>*>* top) {
-  CHECK_EQ(bottom.size(), 0) << "Data Layer takes no input blobs.";
-  CHECK_GE(top->size(), 1) << "Data Layer takes at least one blob as output.";
-  CHECK_LE(top->size(), 2) << "Data Layer takes at most two blobs as output.";
+  Layer<Dtype>::SetUp(bottom, top);
   if (top->size() == 1) {
     output_labels_ = false;
   } else {
index 5d05124..5e5d760 100644 (file)
@@ -11,10 +11,7 @@ namespace caffe {
 template <typename Dtype>
 void EltwiseLayer<Dtype>::SetUp(const vector<Blob<Dtype>*>& bottom,
       vector<Blob<Dtype>*>* top) {
-  CHECK_GE(bottom.size(), 2) <<
-      "Eltwise Layer takes at least 2 blobs as input.";
-  CHECK_EQ(top->size(), 1) <<
-      "Eltwise Layer takes a single blob as output.";
+  Layer<Dtype>::SetUp(bottom, top);
   CHECK(this->layer_param().eltwise_param().coeff_size() == 0
       || this->layer_param().eltwise_param().coeff_size() == bottom.size()) <<
       "Eltwise Layer takes one coefficient per bottom blob.";
index e954030..95f4859 100644 (file)
@@ -11,8 +11,7 @@ namespace caffe {
 template <typename Dtype>
 void FlattenLayer<Dtype>::SetUp(const vector<Blob<Dtype>*>& bottom,
       vector<Blob<Dtype>*>* top) {
-  CHECK_EQ(bottom.size(), 1) << "Flatten Layer takes a single blob as input.";
-  CHECK_EQ(top->size(), 1) << "Flatten Layer takes a single blob as output.";
+  Layer<Dtype>::SetUp(bottom, top);
   int channels_out = bottom[0]->channels() * bottom[0]->height()
       * bottom[0]->width();
   (*top)[0]->Reshape(bottom[0]->num(), channels_out, 1, 1);
index cff4f7c..d5c64f0 100644 (file)
@@ -52,9 +52,7 @@ void HDF5DataLayer<Dtype>::LoadHDF5FileData(const char* filename) {
 template <typename Dtype>
 void HDF5DataLayer<Dtype>::SetUp(const vector<Blob<Dtype>*>& bottom,
       vector<Blob<Dtype>*>* top) {
-  CHECK_EQ(bottom.size(), 0) << "HDF5DataLayer takes no input blobs.";
-  CHECK_EQ(top->size(), 2) << "HDF5DataLayer takes two blobs as output.";
-
+  Layer<Dtype>::SetUp(bottom, top);
   // Read the source to parse the filenames.
   const string& source = this->layer_param_.hdf5_data_param().source();
   LOG(INFO) << "Loading filename from " << source;
index e491697..0961b9b 100644 (file)
@@ -42,14 +42,6 @@ void HDF5OutputLayer<Dtype>::SaveBlobs() {
 }
 
 template <typename Dtype>
-void HDF5OutputLayer<Dtype>::SetUp(const vector<Blob<Dtype>*>& bottom,
-      vector<Blob<Dtype>*>* top) {
-  // TODO: no limit on the number of blobs
-  CHECK_EQ(bottom.size(), 2) << "HDF5OutputLayer takes two blobs as input.";
-  CHECK_EQ(top->size(), 0) << "HDF5OutputLayer takes no output blobs.";
-}
-
-template <typename Dtype>
 Dtype HDF5OutputLayer<Dtype>::Forward_cpu(const vector<Blob<Dtype>*>& bottom,
       vector<Blob<Dtype>*>* top) {
   CHECK_GE(bottom.size(), 2);
index 749ea3c..f0c26c9 100644 (file)
@@ -12,8 +12,7 @@ namespace caffe {
 template <typename Dtype>
 void Im2colLayer<Dtype>::SetUp(const vector<Blob<Dtype>*>& bottom,
       vector<Blob<Dtype>*>* top) {
-  CHECK_EQ(bottom.size(), 1) << "Im2col Layer takes a single blob as input.";
-  CHECK_EQ(top->size(), 1) << "Im2col Layer takes a single blob as output.";
+  Layer<Dtype>::SetUp(bottom, top);
   kernel_size_ = this->layer_param_.convolution_param().kernel_size();
   stride_ = this->layer_param_.convolution_param().stride();
   pad_ = this->layer_param_.convolution_param().pad();
index ed064d0..9a79e72 100644 (file)
@@ -140,8 +140,7 @@ ImageDataLayer<Dtype>::~ImageDataLayer<Dtype>() {
 template <typename Dtype>
 void ImageDataLayer<Dtype>::SetUp(const vector<Blob<Dtype>*>& bottom,
       vector<Blob<Dtype>*>* top) {
-  CHECK_EQ(bottom.size(), 0) << "Input Layer takes no input blobs.";
-  CHECK_EQ(top->size(), 2) << "Input Layer takes two blobs as output.";
+  Layer<Dtype>::SetUp(bottom, top);
   const int new_height  = this->layer_param_.image_data_param().new_height();
   const int new_width  = this->layer_param_.image_data_param().new_height();
   CHECK((new_height == 0 && new_width == 0) ||
index c60261e..971254c 100644 (file)
@@ -14,8 +14,7 @@ namespace caffe {
 template <typename Dtype>
 void InnerProductLayer<Dtype>::SetUp(const vector<Blob<Dtype>*>& bottom,
       vector<Blob<Dtype>*>* top) {
-  CHECK_EQ(bottom.size(), 1) << "IP Layer takes a single blob as input.";
-  CHECK_EQ(top->size(), 1) << "IP Layer takes a single blob as output.";
+  Layer<Dtype>::SetUp(bottom, top);
   const int num_output = this->layer_param_.inner_product_param().num_output();
   bias_term_ = this->layer_param_.inner_product_param().bias_term();
   // Figure out the dimensions
index 1efb623..14ea975 100644 (file)
@@ -17,8 +17,7 @@ namespace caffe {
 template <typename Dtype>
 void LossLayer<Dtype>::SetUp(
     const vector<Blob<Dtype>*>& bottom, vector<Blob<Dtype>*>* top) {
-  CHECK_EQ(bottom.size(), 2) << "Loss Layer takes two blobs as input.";
-  CHECK_EQ(top->size(), 0) << "Loss Layer takes no output.";
+  Layer<Dtype>::SetUp(bottom, top);
   CHECK_EQ(bottom[0]->num(), bottom[1]->num())
       << "The data and label should have the same number.";
   FurtherSetUp(bottom, top);
index 6f7af75..071e719 100644 (file)
@@ -11,10 +11,7 @@ namespace caffe {
 template <typename Dtype>
 void LRNLayer<Dtype>::SetUp(const vector<Blob<Dtype>*>& bottom,
       vector<Blob<Dtype>*>* top) {
-  CHECK_EQ(bottom.size(), 1) <<
-      "Local Response Normalization Layer takes a single blob as input.";
-  CHECK_EQ(top->size(), 1) <<
-      "Local Response Normalization Layer takes a single blob as output.";
+  Layer<Dtype>::SetUp(bottom, top);
   num_ = bottom[0]->num();
   channels_ = bottom[0]->channels();
   height_ = bottom[0]->height();
index 60bce27..15eedb3 100644 (file)
@@ -10,8 +10,7 @@ namespace caffe {
 template <typename Dtype>
 void MemoryDataLayer<Dtype>::SetUp(const vector<Blob<Dtype>*>& bottom,
      vector<Blob<Dtype>*>* top) {
-  CHECK_EQ(bottom.size(), 0) << "Memory Data Layer takes no blobs as input.";
-  CHECK_EQ(top->size(), 2) << "Memory Data Layer takes two blobs as output.";
+  Layer<Dtype>::SetUp(bottom, top);
   batch_size_ = this->layer_param_.memory_data_param().batch_size();
   datum_channels_ = this->layer_param_.memory_data_param().channels();
   datum_height_ = this->layer_param_.memory_data_param().height();
index e9dbd0e..1b8fcec 100644 (file)
@@ -10,8 +10,7 @@ namespace caffe {
 template <typename Dtype>
 void NeuronLayer<Dtype>::SetUp(const vector<Blob<Dtype>*>& bottom,
       vector<Blob<Dtype>*>* top) {
-  CHECK_EQ(bottom.size(), 1) << "Neuron Layer takes a single blob as input.";
-  CHECK_EQ(top->size(), 1) << "Neuron Layer takes a single blob as output.";
+  Layer<Dtype>::SetUp(bottom, top);
   // NeuronLayer allows in-place computations. If the computation is not
   // in-place, we will need to initialize the top blob.
   if ((*top)[0] != bottom[0]) {
index 929d7df..8f5f82d 100644 (file)
@@ -18,16 +18,16 @@ namespace caffe {
 template <typename Dtype>
 void PoolingLayer<Dtype>::SetUp(const vector<Blob<Dtype>*>& bottom,
       vector<Blob<Dtype>*>* top) {
-  CHECK_EQ(bottom.size(), 1) << "PoolingLayer takes a single blob as input.";
+  // Set the max number of top blobs before calling base Layer::SetUp.
+  // If doing MAX pooling, we can optionally output an extra top Blob
+  // for the mask.  Otherwise, we only have one top Blob.
   if (this->layer_param_.pooling_param().pool() ==
       PoolingParameter_PoolMethod_MAX) {
-    CHECK_GE(top->size(), 1)
-        << "MaxPoolingLayer takes at least one blob as output.";
-    CHECK_LE(top->size(), 2)
-        << "MaxPoolingLayer takes at most two blobs as output.";
+    max_top_blobs_ = 2;
   } else {
-    CHECK_EQ(top->size(), 1) << "PoolingLayer takes a single blob as output.";
+    max_top_blobs_ = 1;
   }
+  Layer<Dtype>::SetUp(bottom, top);
   kernel_size_ = this->layer_param_.pooling_param().kernel_size();
   stride_ = this->layer_param_.pooling_param().stride();
   pad_ = this->layer_param_.pooling_param().pad();
index e998360..dbe16da 100644 (file)
@@ -14,8 +14,7 @@ namespace caffe {
 template <typename Dtype>
 void SoftmaxLayer<Dtype>::SetUp(const vector<Blob<Dtype>*>& bottom,
       vector<Blob<Dtype>*>* top) {
-  CHECK_EQ(bottom.size(), 1) << "Softmax Layer takes a single blob as input.";
-  CHECK_EQ(top->size(), 1) << "Softmax Layer takes a single blob as output.";
+  Layer<Dtype>::SetUp(bottom, top);
   (*top)[0]->Reshape(bottom[0]->num(), bottom[0]->channels(),
       bottom[0]->height(), bottom[0]->width());
   sum_multiplier_.Reshape(1, bottom[0]->channels(),
index fecd7a5..ef6eeba 100644 (file)
@@ -15,8 +15,7 @@ namespace caffe {
 template <typename Dtype>
 void SoftmaxWithLossLayer<Dtype>::SetUp(const vector<Blob<Dtype>*>& bottom,
       vector<Blob<Dtype>*>* top) {
-  CHECK_EQ(bottom.size(), 2) << "SoftmaxLoss Layer takes two blobs as input.";
-  CHECK_EQ(top->size(), 0) << "SoftmaxLoss Layer takes no blob as output.";
+  Layer<Dtype>::SetUp(bottom, top);
   softmax_bottom_vec_.clear();
   softmax_bottom_vec_.push_back(bottom[0]);
   softmax_top_vec_.push_back(&prob_);
index aa2b6f6..2f99ca1 100644 (file)
@@ -11,8 +11,7 @@ namespace caffe {
 template <typename Dtype>
 void SplitLayer<Dtype>::SetUp(const vector<Blob<Dtype>*>& bottom,
       vector<Blob<Dtype>*>* top) {
-  CHECK_EQ(bottom.size(), 1) << "Split Layer takes a single blob as input.";
-  CHECK_GE(top->size(), 1) << "Split Layer takes at least one blob as output.";
+  Layer<Dtype>::SetUp(bottom, top);
   count_ = bottom[0]->count();
   for (int i = 0; i < top->size(); ++i) {
     // Allow the 0th top blob to be 'in-place', but no others.
index 862c034..e08bed7 100644 (file)
@@ -258,14 +258,12 @@ WindowDataLayer<Dtype>::~WindowDataLayer<Dtype>() {
 template <typename Dtype>
 void WindowDataLayer<Dtype>::SetUp(const vector<Blob<Dtype>*>& bottom,
       vector<Blob<Dtype>*>* top) {
+  Layer<Dtype>::SetUp(bottom, top);
   // SetUp runs through the window_file and creates two structures
   // that hold windows: one for foreground (object) windows and one
   // for background (non-object) windows. We use an overlap threshold
   // to decide which is which.
 
-  CHECK_EQ(bottom.size(), 0) << "Window data Layer takes no input blobs.";
-  CHECK_EQ(top->size(), 2) << "Window data Layer prodcues two blobs as output.";
-
   // window_file format
   // repeated:
   //    # image_index