diff --git a/include/caffe/data_layers.hpp b/include/caffe/data_layers.hpp new file mode 100644 index 00000000000..d9865ce485b --- /dev/null +++ b/include/caffe/data_layers.hpp @@ -0,0 +1,218 @@ +// Copyright 2014 BVLC and contributors. + +#ifndef CAFFE_DATA_LAYERS_HPP_ +#define CAFFE_DATA_LAYERS_HPP_ + +#include +#include +#include + +#include "leveldb/db.h" +#include "pthread.h" +#include "hdf5.h" +#include "boost/scoped_ptr.hpp" + +#include "caffe/blob.hpp" +#include "caffe/common.hpp" +#include "caffe/layer.hpp" +#include "caffe/proto/caffe.pb.h" + +namespace caffe { + +#define HDF5_DATA_DATASET_NAME "data" +#define HDF5_DATA_LABEL_NAME "label" + +template +class HDF5OutputLayer : public Layer { + public: + explicit HDF5OutputLayer(const LayerParameter& param); + virtual ~HDF5OutputLayer(); + virtual void SetUp(const vector*>& bottom, + vector*>* top); + inline std::string file_name() const { return file_name_; } + + protected: + virtual Dtype Forward_cpu(const vector*>& bottom, + vector*>* top); + virtual Dtype Forward_gpu(const vector*>& bottom, + vector*>* top); + virtual void Backward_cpu(const vector*>& top, + const bool propagate_down, vector*>* bottom); + virtual void Backward_gpu(const vector*>& top, + const bool propagate_down, vector*>* bottom); + virtual void SaveBlobs(); + + std::string file_name_; + hid_t file_id_; + Blob data_blob_; + Blob label_blob_; +}; + + +template +class HDF5DataLayer : public Layer { + public: + explicit HDF5DataLayer(const LayerParameter& param) + : Layer(param) {} + virtual ~HDF5DataLayer(); + virtual void SetUp(const vector*>& bottom, + vector*>* top); + + protected: + virtual Dtype Forward_cpu(const vector*>& bottom, + vector*>* top); + virtual Dtype Forward_gpu(const vector*>& bottom, + vector*>* top); + virtual void Backward_cpu(const vector*>& top, + const bool propagate_down, vector*>* bottom); + virtual void Backward_gpu(const vector*>& top, + const bool propagate_down, vector*>* bottom); + virtual void LoadHDF5FileData(const char* filename); + + std::vector hdf_filenames_; + unsigned int num_files_; + unsigned int current_file_; + hsize_t current_row_; + Blob data_blob_; + Blob label_blob_; +}; + +// TODO: DataLayer, ImageDataLayer, and WindowDataLayer all have the +// same basic structure and a lot of duplicated code. + +// This function is used to create a pthread that prefetches the data. +template +void* DataLayerPrefetch(void* layer_pointer); + +template +class DataLayer : public Layer { + // The function used to perform prefetching. + friend void* DataLayerPrefetch(void* layer_pointer); + + public: + explicit DataLayer(const LayerParameter& param) + : Layer(param) {} + virtual ~DataLayer(); + virtual void SetUp(const vector*>& bottom, + vector*>* top); + + protected: + virtual Dtype Forward_cpu(const vector*>& bottom, + vector*>* top); + virtual Dtype Forward_gpu(const vector*>& bottom, + vector*>* top); + virtual void Backward_cpu(const vector*>& top, + const bool propagate_down, vector*>* bottom) { return; } + virtual void Backward_gpu(const vector*>& top, + const bool propagate_down, vector*>* bottom) { return; } + + virtual void CreatePrefetchThread(); + virtual void JoinPrefetchThread(); + virtual unsigned int PrefetchRand(); + + shared_ptr prefetch_rng_; + shared_ptr db_; + shared_ptr iter_; + int datum_channels_; + int datum_height_; + int datum_width_; + int datum_size_; + pthread_t thread_; + shared_ptr > prefetch_data_; + shared_ptr > prefetch_label_; + Blob data_mean_; + bool output_labels_; + Caffe::Phase phase_; +}; + +// This function is used to create a pthread that prefetches the data. +template +void* ImageDataLayerPrefetch(void* layer_pointer); + +template +class ImageDataLayer : public Layer { + // The function used to perform prefetching. + friend void* ImageDataLayerPrefetch(void* layer_pointer); + + public: + explicit ImageDataLayer(const LayerParameter& param) + : Layer(param) {} + virtual ~ImageDataLayer(); + virtual void SetUp(const vector*>& bottom, + vector*>* top); + + protected: + virtual Dtype Forward_cpu(const vector*>& bottom, + vector*>* top); + virtual Dtype Forward_gpu(const vector*>& bottom, + vector*>* top); + virtual void Backward_cpu(const vector*>& top, + const bool propagate_down, vector*>* bottom) { return; } + virtual void Backward_gpu(const vector*>& top, + const bool propagate_down, vector*>* bottom) { return; } + + virtual void ShuffleImages(); + + virtual void CreatePrefetchThread(); + virtual void JoinPrefetchThread(); + virtual unsigned int PrefetchRand(); + + shared_ptr prefetch_rng_; + vector > lines_; + int lines_id_; + int datum_channels_; + int datum_height_; + int datum_width_; + int datum_size_; + pthread_t thread_; + shared_ptr > prefetch_data_; + shared_ptr > prefetch_label_; + Blob data_mean_; + Caffe::Phase phase_; +}; + + +// This function is used to create a pthread that prefetches the window data. +template +void* WindowDataLayerPrefetch(void* layer_pointer); + +template +class WindowDataLayer : public Layer { + // The function used to perform prefetching. + friend void* WindowDataLayerPrefetch(void* layer_pointer); + + public: + explicit WindowDataLayer(const LayerParameter& param) + : Layer(param) {} + virtual ~WindowDataLayer(); + virtual void SetUp(const vector*>& bottom, + vector*>* top); + + protected: + virtual Dtype Forward_cpu(const vector*>& bottom, + vector*>* top); + virtual Dtype Forward_gpu(const vector*>& bottom, + vector*>* top); + virtual void Backward_cpu(const vector*>& top, + const bool propagate_down, vector*>* bottom) { return; } + virtual void Backward_gpu(const vector*>& top, + const bool propagate_down, vector*>* bottom) { return; } + + virtual void CreatePrefetchThread(); + virtual void JoinPrefetchThread(); + virtual unsigned int PrefetchRand(); + + shared_ptr prefetch_rng_; + pthread_t thread_; + shared_ptr > prefetch_data_; + shared_ptr > prefetch_label_; + Blob data_mean_; + vector > > image_database_; + enum WindowField { IMAGE_INDEX, LABEL, OVERLAP, X1, Y1, X2, Y2, NUM }; + vector > fg_windows_; + vector > bg_windows_; +}; + +} // namespace caffe + +#endif // CAFFE_DATA_LAYERS_HPP_ diff --git a/include/caffe/loss_layers.hpp b/include/caffe/loss_layers.hpp new file mode 100644 index 00000000000..cc798c499d3 --- /dev/null +++ b/include/caffe/loss_layers.hpp @@ -0,0 +1,171 @@ +// Copyright 2014 BVLC and contributors. + +#ifndef CAFFE_LOSS_LAYERS_HPP_ +#define CAFFE_LOSS_LAYERS_HPP_ + +#include +#include +#include + +#include "leveldb/db.h" +#include "pthread.h" +#include "boost/scoped_ptr.hpp" +#include "hdf5.h" + +#include "caffe/blob.hpp" +#include "caffe/common.hpp" +#include "caffe/layer.hpp" +#include "caffe/neuron_layers.hpp" +#include "caffe/proto/caffe.pb.h" + +namespace caffe { + +const float kLOG_THRESHOLD = 1e-20; + +/* LossLayer + Takes two inputs of same num (a and b), and has no output. + The gradient is propagated to a. +*/ +template +class LossLayer : public Layer { + public: + explicit LossLayer(const LayerParameter& param) + : Layer(param) {} + virtual void SetUp( + const vector*>& bottom, vector*>* top); + virtual void FurtherSetUp( + const vector*>& bottom, vector*>* top) {} +}; + +/* SigmoidCrossEntropyLossLayer +*/ +template +class SigmoidCrossEntropyLossLayer : public LossLayer { + public: + explicit SigmoidCrossEntropyLossLayer(const LayerParameter& param) + : LossLayer(param), + sigmoid_layer_(new SigmoidLayer(param)), + sigmoid_output_(new Blob()) {} + virtual void FurtherSetUp(const vector*>& bottom, + vector*>* top); + + protected: + virtual Dtype Forward_cpu(const vector*>& bottom, + vector*>* top); + virtual Dtype Forward_gpu(const vector*>& bottom, + vector*>* top); + virtual void Backward_cpu(const vector*>& top, + const bool propagate_down, vector*>* bottom); + virtual void Backward_gpu(const vector*>& top, + const bool propagate_down, vector*>* bottom); + + shared_ptr > sigmoid_layer_; + // sigmoid_output stores the output of the sigmoid layer. + shared_ptr > sigmoid_output_; + // Vector holders to call the underlying sigmoid layer forward and backward. + vector*> sigmoid_bottom_vec_; + vector*> sigmoid_top_vec_; +}; + +/* EuclideanLossLayer + Compute the L_2 distance between the two inputs. + + loss = (1/2 \sum_i (a_i - b_i)^2) + a' = 1/I (a - b) +*/ +template +class EuclideanLossLayer : public LossLayer { + public: + explicit EuclideanLossLayer(const LayerParameter& param) + : LossLayer(param), diff_() {} + virtual void FurtherSetUp(const vector*>& bottom, + vector*>* top); + + protected: + virtual Dtype Forward_cpu(const vector*>& bottom, + vector*>* top); + virtual void Backward_cpu(const vector*>& top, + const bool propagate_down, vector*>* bottom); + + Blob diff_; +}; + +/* InfogainLossLayer +*/ +template +class InfogainLossLayer : public LossLayer { + public: + explicit InfogainLossLayer(const LayerParameter& param) + : LossLayer(param), infogain_() {} + virtual void FurtherSetUp(const vector*>& bottom, + vector*>* top); + + protected: + virtual Dtype Forward_cpu(const vector*>& bottom, + vector*>* top); + virtual void Backward_cpu(const vector*>& top, + const bool propagate_down, vector*>* bottom); + + Blob infogain_; +}; + +/* HingeLossLayer +*/ +template +class HingeLossLayer : public LossLayer { + public: + explicit HingeLossLayer(const LayerParameter& param) + : LossLayer(param) {} + + protected: + virtual Dtype Forward_cpu(const vector*>& bottom, + vector*>* top); + virtual void Backward_cpu(const vector*>& top, + const bool propagate_down, vector*>* bottom); +}; + +/* MultinomialLogisticLossLayer +*/ +template +class MultinomialLogisticLossLayer : public LossLayer { + public: + explicit MultinomialLogisticLossLayer(const LayerParameter& param) + : LossLayer(param) {} + virtual void FurtherSetUp(const vector*>& bottom, + vector*>* top); + + protected: + virtual Dtype Forward_cpu(const vector*>& bottom, + vector*>* top); + virtual void Backward_cpu(const vector*>& top, + const bool propagate_down, vector*>* bottom); +}; + +/* AccuracyLayer + Note: not an actual loss layer! Does not implement backwards step. + Computes the accuracy and logprob of a with respect to b. +*/ +template +class AccuracyLayer : public Layer { + public: + explicit AccuracyLayer(const LayerParameter& param) + : Layer(param) {} + virtual void SetUp(const vector*>& bottom, + vector*>* top); + + protected: + virtual Dtype Forward_cpu(const vector*>& bottom, + vector*>* top); + virtual void Backward_cpu(const vector*>& top, + const bool propagate_down, vector*>* bottom) { + NOT_IMPLEMENTED; + } +}; + +/* Also see +- SoftmaxWithLossLayer in vision_layers.hpp +*/ + +} // namespace caffe + +#endif // CAFFE_LOSS_LAYERS_HPP_ diff --git a/include/caffe/neuron_layers.hpp b/include/caffe/neuron_layers.hpp new file mode 100644 index 00000000000..fb2347da436 --- /dev/null +++ b/include/caffe/neuron_layers.hpp @@ -0,0 +1,207 @@ +// Copyright 2014 BVLC and contributors. + +#ifndef CAFFE_NEURON_LAYERS_HPP_ +#define CAFFE_NEURON_LAYERS_HPP_ + +#include +#include +#include + +#include "leveldb/db.h" +#include "pthread.h" +#include "boost/scoped_ptr.hpp" +#include "hdf5.h" + +#include "caffe/blob.hpp" +#include "caffe/common.hpp" +#include "caffe/layer.hpp" +#include "caffe/proto/caffe.pb.h" + +#define HDF5_DATA_DATASET_NAME "data" +#define HDF5_DATA_LABEL_NAME "label" + +namespace caffe { + +/* NeuronLayer + An interface for layers that take one blob as input (x), + and produce one blob as output (y). +*/ +template +class NeuronLayer : public Layer { + public: + explicit NeuronLayer(const LayerParameter& param) + : Layer(param) {} + virtual void SetUp(const vector*>& bottom, + vector*>* top); +}; + +/* BNLLLayer + + y = x + log(1 + exp(-x)) if x > 0 + y = log(1 + exp(x)) if x <= 0 + + y' = exp(x) / (exp(x) + 1) +*/ +template +class BNLLLayer : public NeuronLayer { + public: + explicit BNLLLayer(const LayerParameter& param) + : NeuronLayer(param) {} + + protected: + virtual Dtype Forward_cpu(const vector*>& bottom, + vector*>* top); + virtual Dtype Forward_gpu(const vector*>& bottom, + vector*>* top); + virtual void Backward_cpu(const vector*>& top, + const bool propagate_down, vector*>* bottom); + virtual void Backward_gpu(const vector*>& top, + const bool propagate_down, vector*>* bottom); +}; + +/* DropoutLayer + During training only, sets some portion of x to 0, adjusting the + vector magnitude accordingly. + + mask = bernoulli(1 - threshold) + scale = 1 / (1 - threshold) + y = x * mask * scale + + y' = mask * scale +*/ +template +class DropoutLayer : public NeuronLayer { + public: + explicit DropoutLayer(const LayerParameter& param) + : NeuronLayer(param) {} + virtual void SetUp(const vector*>& bottom, + vector*>* top); + + protected: + virtual Dtype Forward_cpu(const vector*>& bottom, + vector*>* top); + virtual Dtype Forward_gpu(const vector*>& bottom, + vector*>* top); + virtual void Backward_cpu(const vector*>& top, + const bool propagate_down, vector*>* bottom); + virtual void Backward_gpu(const vector*>& top, + const bool propagate_down, vector*>* bottom); + + shared_ptr rand_vec_; + Dtype threshold_; + Dtype scale_; + unsigned int uint_thres_; +}; + +/* PowerLayer + y = (shift + scale * x) ^ power + + y' = scale * power * (shift + scale * x) ^ (power - 1) + = scale * power * y / (shift + scale * x) +*/ +template +class PowerLayer : public NeuronLayer { + public: + explicit PowerLayer(const LayerParameter& param) + : NeuronLayer(param) {} + virtual void SetUp(const vector*>& bottom, + vector*>* top); + + protected: + virtual Dtype Forward_cpu(const vector*>& bottom, + vector*>* top); + virtual Dtype Forward_gpu(const vector*>& bottom, + vector*>* top); + virtual void Backward_cpu(const vector*>& top, + const bool propagate_down, vector*>* bottom); + virtual void Backward_gpu(const vector*>& top, + const bool propagate_down, vector*>* bottom); + + Dtype power_; + Dtype scale_; + Dtype shift_; + Dtype diff_scale_; +}; + +/* ReLULayer + Rectified Linear Unit non-linearity. + The simple max is fast to compute, and the function does not saturate. + + y = max(0, x). + + y' = 0 if x < 0 + y' = 1 if x > 0 +*/ +template +class ReLULayer : public NeuronLayer { + public: + explicit ReLULayer(const LayerParameter& param) + : NeuronLayer(param) {} + + protected: + virtual Dtype Forward_cpu(const vector*>& bottom, + vector*>* top); + virtual Dtype Forward_gpu(const vector*>& bottom, + vector*>* top); + + virtual void Backward_cpu(const vector*>& top, + const bool propagate_down, vector*>* bottom); + virtual void Backward_gpu(const vector*>& top, + const bool propagate_down, vector*>* bottom); +}; + +/* SigmoidLayer + Sigmoid function non-linearity, a classic choice in neural networks. + Note that the gradient vanishes as the values move away from 0. + The ReLULayer is often a better choice for this reason. + + y = 1. / (1 + exp(-x)) + + y ' = exp(x) / (1 + exp(x))^2 + or + y' = y * (1 - y) +*/ +template +class SigmoidLayer : public NeuronLayer { + public: + explicit SigmoidLayer(const LayerParameter& param) + : NeuronLayer(param) {} + + protected: + virtual Dtype Forward_cpu(const vector*>& bottom, + vector*>* top); + virtual Dtype Forward_gpu(const vector*>& bottom, + vector*>* top); + virtual void Backward_cpu(const vector*>& top, + const bool propagate_down, vector*>* bottom); + virtual void Backward_gpu(const vector*>& top, + const bool propagate_down, vector*>* bottom); +}; + +/* TanHLayer + Hyperbolic tangent non-linearity, popular in auto-encoders. + + y = 1. * (exp(2x) - 1) / (exp(2x) + 1) + + y' = 1 - ( (exp(2x) - 1) / (exp(2x) + 1) ) ^ 2 +*/ +template +class TanHLayer : public NeuronLayer { + public: + explicit TanHLayer(const LayerParameter& param) + : NeuronLayer(param) {} + + protected: + virtual Dtype Forward_cpu(const vector*>& bottom, + vector*>* top); + virtual Dtype Forward_gpu(const vector*>& bottom, + vector*>* top); + virtual void Backward_cpu(const vector*>& top, + const bool propagate_down, vector*>* bottom); + virtual void Backward_gpu(const vector*>& top, + const bool propagate_down, vector*>* bottom); +}; + +} // namespace caffe + +#endif // CAFFE_NEURON_LAYERS_HPP_ diff --git a/include/caffe/vision_layers.hpp b/include/caffe/vision_layers.hpp index 4765398aa7b..de99bc3033f 100644 --- a/include/caffe/vision_layers.hpp +++ b/include/caffe/vision_layers.hpp @@ -7,197 +7,21 @@ #include #include -#include "leveldb/db.h" -#include "pthread.h" -#include "boost/scoped_ptr.hpp" -#include "hdf5.h" - #include "caffe/blob.hpp" #include "caffe/common.hpp" #include "caffe/layer.hpp" +#include "caffe/neuron_layers.hpp" +#include "caffe/loss_layers.hpp" +#include "caffe/data_layers.hpp" #include "caffe/proto/caffe.pb.h" -#define HDF5_DATA_DATASET_NAME "data" -#define HDF5_DATA_LABEL_NAME "label" - namespace caffe { - -// The neuron layer is a specific type of layers that just works on single -// celements. -template -class NeuronLayer : public Layer { - public: - explicit NeuronLayer(const LayerParameter& param) - : Layer(param) {} - virtual void SetUp(const vector*>& bottom, - vector*>* top); -}; - -template -class BNLLLayer : public NeuronLayer { - public: - explicit BNLLLayer(const LayerParameter& param) - : NeuronLayer(param) {} - - protected: - virtual Dtype Forward_cpu(const vector*>& bottom, - vector*>* top); - virtual Dtype Forward_gpu(const vector*>& bottom, - vector*>* top); - virtual void Backward_cpu(const vector*>& top, - const bool propagate_down, vector*>* bottom); - virtual void Backward_gpu(const vector*>& top, - const bool propagate_down, vector*>* bottom); -}; - -template -class DropoutLayer : public NeuronLayer { - public: - explicit DropoutLayer(const LayerParameter& param) - : NeuronLayer(param) {} - virtual void SetUp(const vector*>& bottom, - vector*>* top); - - protected: - virtual Dtype Forward_cpu(const vector*>& bottom, - vector*>* top); - virtual Dtype Forward_gpu(const vector*>& bottom, - vector*>* top); - virtual void Backward_cpu(const vector*>& top, - const bool propagate_down, vector*>* bottom); - virtual void Backward_gpu(const vector*>& top, - const bool propagate_down, vector*>* bottom); - - shared_ptr rand_vec_; - Dtype threshold_; - Dtype scale_; - unsigned int uint_thres_; -}; - -template -class PowerLayer : public NeuronLayer { - public: - explicit PowerLayer(const LayerParameter& param) - : NeuronLayer(param) {} - virtual void SetUp(const vector*>& bottom, - vector*>* top); - - protected: - virtual Dtype Forward_cpu(const vector*>& bottom, - vector*>* top); - virtual Dtype Forward_gpu(const vector*>& bottom, - vector*>* top); - virtual void Backward_cpu(const vector*>& top, - const bool propagate_down, vector*>* bottom); - virtual void Backward_gpu(const vector*>& top, - const bool propagate_down, vector*>* bottom); - - Dtype power_; - Dtype scale_; - Dtype shift_; - Dtype diff_scale_; -}; - -template -class ReLULayer : public NeuronLayer { - public: - explicit ReLULayer(const LayerParameter& param) - : NeuronLayer(param) {} - - protected: - virtual Dtype Forward_cpu(const vector*>& bottom, - vector*>* top); - virtual Dtype Forward_gpu(const vector*>& bottom, - vector*>* top); - - virtual void Backward_cpu(const vector*>& top, - const bool propagate_down, vector*>* bottom); - virtual void Backward_gpu(const vector*>& top, - const bool propagate_down, vector*>* bottom); -}; - -template -class SigmoidLayer : public NeuronLayer { - public: - explicit SigmoidLayer(const LayerParameter& param) - : NeuronLayer(param) {} - - protected: - virtual Dtype Forward_cpu(const vector*>& bottom, - vector*>* top); - virtual Dtype Forward_gpu(const vector*>& bottom, - vector*>* top); - virtual void Backward_cpu(const vector*>& top, - const bool propagate_down, vector*>* bottom); - virtual void Backward_gpu(const vector*>& top, - const bool propagate_down, vector*>* bottom); -}; - -template -class SigmoidCrossEntropyLossLayer : public Layer { - public: - explicit SigmoidCrossEntropyLossLayer(const LayerParameter& param) - : Layer(param), - sigmoid_layer_(new SigmoidLayer(param)), - sigmoid_output_(new Blob()) {} - virtual void SetUp(const vector*>& bottom, - vector*>* top); - - protected: - virtual Dtype Forward_cpu(const vector*>& bottom, - vector*>* top); - virtual Dtype Forward_gpu(const vector*>& bottom, - vector*>* top); - virtual void Backward_cpu(const vector*>& top, - const bool propagate_down, vector*>* bottom); - virtual void Backward_gpu(const vector*>& top, - const bool propagate_down, vector*>* bottom); - - shared_ptr > sigmoid_layer_; - // sigmoid_output stores the output of the sigmoid layer. - shared_ptr > sigmoid_output_; - // Vector holders to call the underlying sigmoid layer forward and backward. - vector*> sigmoid_bottom_vec_; - vector*> sigmoid_top_vec_; -}; - -template -class TanHLayer : public NeuronLayer { - public: - explicit TanHLayer(const LayerParameter& param) - : NeuronLayer(param) {} - - protected: - virtual Dtype Forward_cpu(const vector*>& bottom, - vector*>* top); - virtual Dtype Forward_gpu(const vector*>& bottom, - vector*>* top); - virtual void Backward_cpu(const vector*>& top, - const bool propagate_down, vector*>* bottom); - virtual void Backward_gpu(const vector*>& top, - const bool propagate_down, vector*>* bottom); -}; - - -template -class AccuracyLayer : public Layer { - public: - explicit AccuracyLayer(const LayerParameter& param) - : Layer(param) {} - virtual void SetUp(const vector*>& bottom, - vector*>* top); - - protected: - virtual Dtype Forward_cpu(const vector*>& bottom, - vector*>* top); - // The accuracy layer should not be used to compute backward operations. - virtual void Backward_cpu(const vector*>& top, - const bool propagate_down, vector*>* bottom) { - NOT_IMPLEMENTED; - } -}; - +/* +ConcatLayer + Takes at least two blobs and concatenates them along either num or + channel dim, outputting the result. +*/ template class ConcatLayer : public Layer { public: @@ -225,6 +49,8 @@ class ConcatLayer : public Layer { int concat_dim_; }; +/* ConvolutionLayer +*/ template class ConvolutionLayer : public Layer { public: @@ -260,51 +86,8 @@ class ConvolutionLayer : public Layer { int N_; }; -// This function is used to create a pthread that prefetches the data. -template -void* DataLayerPrefetch(void* layer_pointer); - -template -class DataLayer : public Layer { - // The function used to perform prefetching. - friend void* DataLayerPrefetch(void* layer_pointer); - - public: - explicit DataLayer(const LayerParameter& param) - : Layer(param) {} - virtual ~DataLayer(); - virtual void SetUp(const vector*>& bottom, - vector*>* top); - - protected: - virtual Dtype Forward_cpu(const vector*>& bottom, - vector*>* top); - virtual Dtype Forward_gpu(const vector*>& bottom, - vector*>* top); - virtual void Backward_cpu(const vector*>& top, - const bool propagate_down, vector*>* bottom) { return; } - virtual void Backward_gpu(const vector*>& top, - const bool propagate_down, vector*>* bottom) { return; } - - virtual void CreatePrefetchThread(); - virtual void JoinPrefetchThread(); - virtual unsigned int PrefetchRand(); - - shared_ptr prefetch_rng_; - shared_ptr db_; - shared_ptr iter_; - int datum_channels_; - int datum_height_; - int datum_width_; - int datum_size_; - pthread_t thread_; - shared_ptr > prefetch_data_; - shared_ptr > prefetch_label_; - Blob data_mean_; - bool output_labels_; - Caffe::Phase phase_; -}; - +/* EltwiseProductLayer +*/ template class EltwiseProductLayer : public Layer { public: @@ -324,27 +107,6 @@ class EltwiseProductLayer : public Layer { const bool propagate_down, vector*>* bottom); }; -template -class EuclideanLossLayer : public Layer { - public: - explicit EuclideanLossLayer(const LayerParameter& param) - : Layer(param), difference_() {} - virtual void SetUp(const vector*>& bottom, - vector*>* top); - - protected: - virtual Dtype Forward_cpu(const vector*>& bottom, - vector*>* top); - // virtual Dtype Forward_gpu(const vector*>& bottom, - // vector*>* top); - virtual void Backward_cpu(const vector*>& top, - const bool propagate_down, vector*>* bottom); - // virtual void Backward_gpu(const vector*>& top, - // const bool propagate_down, vector*>* bottom); - - Blob difference_; -}; - template class FlattenLayer : public Layer { public: @@ -366,79 +128,8 @@ class FlattenLayer : public Layer { int count_; }; -template -class HDF5OutputLayer : public Layer { - public: - explicit HDF5OutputLayer(const LayerParameter& param); - virtual ~HDF5OutputLayer(); - virtual void SetUp(const vector*>& bottom, - vector*>* top); - inline std::string file_name() const { return file_name_; } - - protected: - virtual Dtype Forward_cpu(const vector*>& bottom, - vector*>* top); - virtual Dtype Forward_gpu(const vector*>& bottom, - vector*>* top); - virtual void Backward_cpu(const vector*>& top, - const bool propagate_down, vector*>* bottom); - virtual void Backward_gpu(const vector*>& top, - const bool propagate_down, vector*>* bottom); - virtual void SaveBlobs(); - - std::string file_name_; - hid_t file_id_; - Blob data_blob_; - Blob label_blob_; -}; - -template -class HDF5DataLayer : public Layer { - public: - explicit HDF5DataLayer(const LayerParameter& param) - : Layer(param) {} - virtual ~HDF5DataLayer(); - virtual void SetUp(const vector*>& bottom, - vector*>* top); - - protected: - virtual Dtype Forward_cpu(const vector*>& bottom, - vector*>* top); - virtual Dtype Forward_gpu(const vector*>& bottom, - vector*>* top); - virtual void Backward_cpu(const vector*>& top, - const bool propagate_down, vector*>* bottom); - virtual void Backward_gpu(const vector*>& top, - const bool propagate_down, vector*>* bottom); - virtual void LoadHDF5FileData(const char* filename); - - std::vector hdf_filenames_; - unsigned int num_files_; - unsigned int current_file_; - hsize_t current_row_; - Blob data_blob_; - Blob label_blob_; -}; - -template -class HingeLossLayer : public Layer { - public: - explicit HingeLossLayer(const LayerParameter& param) - : Layer(param) {} - virtual void SetUp(const vector*>& bottom, - vector*>* top); - - protected: - virtual Dtype Forward_cpu(const vector*>& bottom, - vector*>* top); - // virtual Dtype Forward_gpu(const vector*>& bottom, - // vector*>* top); - virtual void Backward_cpu(const vector*>& top, - const bool propagate_down, vector*>* bottom); - // virtual void Backward_gpu(const vector*>& top, - // const bool propagate_down, vector*>* bottom); -}; - +/* Im2colLayer +*/ template class Im2colLayer : public Layer { public: @@ -465,73 +156,8 @@ class Im2colLayer : public Layer { int pad_; }; -// This function is used to create a pthread that prefetches the data. -template -void* ImageDataLayerPrefetch(void* layer_pointer); - -template -class ImageDataLayer : public Layer { - // The function used to perform prefetching. - friend void* ImageDataLayerPrefetch(void* layer_pointer); - - public: - explicit ImageDataLayer(const LayerParameter& param) - : Layer(param) {} - virtual ~ImageDataLayer(); - virtual void SetUp(const vector*>& bottom, - vector*>* top); - - protected: - virtual Dtype Forward_cpu(const vector*>& bottom, - vector*>* top); - virtual Dtype Forward_gpu(const vector*>& bottom, - vector*>* top); - virtual void Backward_cpu(const vector*>& top, - const bool propagate_down, vector*>* bottom) { return; } - virtual void Backward_gpu(const vector*>& top, - const bool propagate_down, vector*>* bottom) { return; } - - virtual void ShuffleImages(); - - virtual void CreatePrefetchThread(); - virtual void JoinPrefetchThread(); - virtual unsigned int PrefetchRand(); - - shared_ptr prefetch_rng_; - vector > lines_; - int lines_id_; - int datum_channels_; - int datum_height_; - int datum_width_; - int datum_size_; - pthread_t thread_; - shared_ptr > prefetch_data_; - shared_ptr > prefetch_label_; - Blob data_mean_; - Caffe::Phase phase_; -}; - -template -class InfogainLossLayer : public Layer { - public: - explicit InfogainLossLayer(const LayerParameter& param) - : Layer(param), infogain_() {} - virtual void SetUp(const vector*>& bottom, - vector*>* top); - - protected: - virtual Dtype Forward_cpu(const vector*>& bottom, - vector*>* top); - // virtual Dtype Forward_gpu(const vector*>& bottom, - // vector*>* top); - virtual void Backward_cpu(const vector*>& top, - const bool propagate_down, vector*>* bottom); - // virtual void Backward_gpu(const vector*>& top, - // const bool propagate_down, vector*>* bottom); - - Blob infogain_; -}; - +/* InnerProductLayer +*/ template class InnerProductLayer : public Layer { public: @@ -561,6 +187,9 @@ class InnerProductLayer : public Layer { template class PoolingLayer; template class SplitLayer; +/* LRNLayer + Local Response Normalization +*/ template class LRNLayer : public Layer { public: @@ -624,6 +253,8 @@ class LRNLayer : public Layer { vector*> product_bottom_vec_; }; +/* PoolingLayer +*/ template class MemoryDataLayer : public Layer { public: @@ -658,25 +289,6 @@ class MemoryDataLayer : public Layer { int pos_; }; -template -class MultinomialLogisticLossLayer : public Layer { - public: - explicit MultinomialLogisticLossLayer(const LayerParameter& param) - : Layer(param) {} - virtual void SetUp(const vector*>& bottom, - vector*>* top); - - protected: - virtual Dtype Forward_cpu(const vector*>& bottom, - vector*>* top); - // virtual Dtype Forward_gpu(const vector*>& bottom, - // vector*>* top); - virtual void Backward_cpu(const vector*>& top, - const bool propagate_down, vector*>* bottom); - // virtual void Backward_gpu(const vector*>& top, - // const bool propagate_down, vector*>* bottom); -}; - template class PoolingLayer : public Layer { public: @@ -706,6 +318,8 @@ class PoolingLayer : public Layer { Blob rand_idx_; }; +/* SoftmaxLayer +*/ template class SoftmaxLayer : public Layer { public: @@ -730,11 +344,14 @@ class SoftmaxLayer : public Layer { Blob scale_; }; -// SoftmaxWithLossLayer is a layer that implements softmax and then computes -// the loss - it is preferred over softmax + multinomiallogisticloss in the -// sense that during training, this will produce more numerically stable -// gradients. During testing this layer could be replaced by a softmax layer -// to generate probability outputs. +/* SoftmaxWithLossLayer + Implements softmax and computes the loss. + + It is preferred over separate softmax + multinomiallogisticloss + layers due to more numerically stable gradients. + + In test, this layer could be replaced by simple softmax layer. +*/ template class SoftmaxWithLossLayer : public Layer { public: @@ -761,6 +378,8 @@ class SoftmaxWithLossLayer : public Layer { vector*> softmax_top_vec_; }; +/* SplitLayer +*/ template class SplitLayer : public Layer { public: @@ -782,48 +401,6 @@ class SplitLayer : public Layer { int count_; }; -// This function is used to create a pthread that prefetches the window data. -template -void* WindowDataLayerPrefetch(void* layer_pointer); - -template -class WindowDataLayer : public Layer { - // The function used to perform prefetching. - friend void* WindowDataLayerPrefetch(void* layer_pointer); - - public: - explicit WindowDataLayer(const LayerParameter& param) - : Layer(param) {} - virtual ~WindowDataLayer(); - virtual void SetUp(const vector*>& bottom, - vector*>* top); - - protected: - virtual Dtype Forward_cpu(const vector*>& bottom, - vector*>* top); - virtual Dtype Forward_gpu(const vector*>& bottom, - vector*>* top); - virtual void Backward_cpu(const vector*>& top, - const bool propagate_down, vector*>* bottom) { return; } - virtual void Backward_gpu(const vector*>& top, - const bool propagate_down, vector*>* bottom) { return; } - - virtual void CreatePrefetchThread(); - virtual void JoinPrefetchThread(); - virtual unsigned int PrefetchRand(); - - shared_ptr prefetch_rng_; - pthread_t thread_; - shared_ptr > prefetch_data_; - shared_ptr > prefetch_label_; - Blob data_mean_; - vector > > image_database_; - enum WindowField { IMAGE_INDEX, LABEL, OVERLAP, X1, Y1, X2, Y2, NUM }; - vector > fg_windows_; - vector > bg_windows_; -}; - - } // namespace caffe #endif // CAFFE_VISION_LAYERS_HPP_ diff --git a/src/caffe/layers/accuracy_layer.cpp b/src/caffe/layers/accuracy_layer.cpp new file mode 100644 index 00000000000..3e671704465 --- /dev/null +++ b/src/caffe/layers/accuracy_layer.cpp @@ -0,0 +1,65 @@ +// Copyright 2014 BVLC and contributors. + +#include +#include +#include +#include + +#include "caffe/layer.hpp" +#include "caffe/vision_layers.hpp" +#include "caffe/util/math_functions.hpp" +#include "caffe/util/io.hpp" + +using std::max; + +namespace caffe { + +template +void AccuracyLayer::SetUp( + const vector*>& bottom, vector*>* top) { + CHECK_EQ(bottom.size(), 2) << "Accuracy Layer takes two blobs as input."; + CHECK_EQ(top->size(), 1) << "Accuracy Layer takes 1 output."; + CHECK_EQ(bottom[0]->num(), bottom[1]->num()) + << "The data and label should have the same number."; + CHECK_EQ(bottom[1]->channels(), 1); + CHECK_EQ(bottom[1]->height(), 1); + CHECK_EQ(bottom[1]->width(), 1); + (*top)[0]->Reshape(1, 2, 1, 1); +} + +template +Dtype AccuracyLayer::Forward_cpu(const vector*>& bottom, + vector*>* top) { + Dtype accuracy = 0; + Dtype logprob = 0; + const Dtype* bottom_data = bottom[0]->cpu_data(); + const Dtype* bottom_label = bottom[1]->cpu_data(); + int num = bottom[0]->num(); + int dim = bottom[0]->count() / bottom[0]->num(); + for (int i = 0; i < num; ++i) { + // Accuracy + Dtype maxval = -FLT_MAX; + int max_id = 0; + for (int j = 0; j < dim; ++j) { + if (bottom_data[i * dim + j] > maxval) { + maxval = bottom_data[i * dim + j]; + max_id = j; + } + } + if (max_id == static_cast(bottom_label[i])) { + ++accuracy; + } + Dtype prob = max(bottom_data[i * dim + static_cast(bottom_label[i])], + Dtype(kLOG_THRESHOLD)); + logprob -= log(prob); + } + // LOG(INFO) << "Accuracy: " << accuracy; + (*top)[0]->mutable_cpu_data()[0] = accuracy / num; + (*top)[0]->mutable_cpu_data()[1] = logprob / num; + // Accuracy layer should not be used as a loss function. + return Dtype(0); +} + +INSTANTIATE_CLASS(AccuracyLayer); + +} // namespace caffe diff --git a/src/caffe/layers/concat_layer.cpp b/src/caffe/layers/concat_layer.cpp index 4bbce133c51..8036bdab675 100644 --- a/src/caffe/layers/concat_layer.cpp +++ b/src/caffe/layers/concat_layer.cpp @@ -12,14 +12,17 @@ template void ConcatLayer::SetUp(const vector*>& bottom, vector*>* top) { CHECK_GT(bottom.size(), 1) << - "Concat Layer takes at least two blobs as input."; + "ConcatLayer takes at least two blobs as input."; CHECK_EQ(top->size(), 1) << - "Concat Layer takes a single blob as output."; + "ConcatLayer takes a single blob as output."; + concat_dim_ = this->layer_param_.concat_param().concat_dim(); - CHECK_GE(concat_dim_, 0) << "concat_dim should be >= 0"; + CHECK_GE(concat_dim_, 0) << + "concat_dim should be >= 0"; CHECK_LE(concat_dim_, 1) << "For now concat_dim <=1, it can only concat num and channels"; - // Intialize with the first blob + + // Initialize with the first blob. count_ = bottom[0]->count(); num_ = bottom[0]->num(); channels_ = bottom[0]->channels(); @@ -64,10 +67,7 @@ Dtype ConcatLayer::Forward_cpu(const vector*>& bottom, top_data+(*top)[0]->offset(n, offset_channel)); } offset_channel += bottom[i]->channels(); - } - } else { - LOG(FATAL) << "concat_dim along dim" << concat_dim_ << - " not implemented yet"; + } // concat_dim_ is guaranteed to be 0 or 1 by SetUp. } return Dtype(0.); } @@ -97,10 +97,7 @@ void ConcatLayer::Backward_cpu(const vector*>& top, } offset_channel += blob->channels(); } - } else { - LOG(FATAL) << "concat_dim along dim" << concat_dim_ << - " not implemented yet"; - } + } // concat_dim_ is guaranteed to be 0 or 1 by SetUp. } INSTANTIATE_CLASS(ConcatLayer); diff --git a/src/caffe/layers/dropout_layer.cpp b/src/caffe/layers/dropout_layer.cpp index e28cab33fef..e1b69f363b4 100644 --- a/src/caffe/layers/dropout_layer.cpp +++ b/src/caffe/layers/dropout_layer.cpp @@ -1,5 +1,7 @@ // Copyright 2014 BVLC and contributors. +// TODO (sergeyk): effect should not be dependent on phase. wasted memcpy. + #include #include "caffe/common.hpp" diff --git a/src/caffe/layers/euclidean_loss_layer.cpp b/src/caffe/layers/euclidean_loss_layer.cpp new file mode 100644 index 00000000000..a894d470c64 --- /dev/null +++ b/src/caffe/layers/euclidean_loss_layer.cpp @@ -0,0 +1,54 @@ +// Copyright 2014 BVLC and contributors. + +#include +#include +#include +#include + +#include "caffe/layer.hpp" +#include "caffe/vision_layers.hpp" +#include "caffe/util/math_functions.hpp" +#include "caffe/util/io.hpp" + +using std::max; + +namespace caffe { + +template +void EuclideanLossLayer::FurtherSetUp( + const vector*>& bottom, vector*>* top) { + CHECK_EQ(bottom[0]->channels(), bottom[1]->channels()); + CHECK_EQ(bottom[0]->height(), bottom[1]->height()); + CHECK_EQ(bottom[0]->width(), bottom[1]->width()); + diff_.Reshape(bottom[0]->num(), bottom[0]->channels(), + bottom[0]->height(), bottom[0]->width()); +} + +template +Dtype EuclideanLossLayer::Forward_cpu(const vector*>& bottom, + vector*>* top) { + int count = bottom[0]->count(); + caffe_sub( + count, + bottom[0]->cpu_data(), + bottom[1]->cpu_data(), + diff_.mutable_cpu_data()); + Dtype dot = caffe_cpu_dot(count, diff_.cpu_data(), diff_.cpu_data()); + Dtype loss = dot / bottom[0]->num() / Dtype(2); + return loss; +} + +template +void EuclideanLossLayer::Backward_cpu(const vector*>& top, + const bool propagate_down, vector*>* 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 +} + +INSTANTIATE_CLASS(EuclideanLossLayer); + +} // namespace caffe diff --git a/src/caffe/layers/hinge_loss_layer.cpp b/src/caffe/layers/hinge_loss_layer.cpp new file mode 100644 index 00000000000..24329fba028 --- /dev/null +++ b/src/caffe/layers/hinge_loss_layer.cpp @@ -0,0 +1,57 @@ +// Copyright 2014 BVLC and contributors. + +#include +#include +#include +#include + +#include "caffe/layer.hpp" +#include "caffe/vision_layers.hpp" +#include "caffe/util/math_functions.hpp" +#include "caffe/util/io.hpp" + +using std::max; + +namespace caffe { + +template +Dtype HingeLossLayer::Forward_cpu(const vector*>& bottom, + vector*>* top) { + const Dtype* bottom_data = bottom[0]->cpu_data(); + 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; + + caffe_copy(count, bottom_data, bottom_diff); + for (int i = 0; i < num; ++i) { + bottom_diff[i * dim + static_cast(label[i])] *= -1; + } + for (int i = 0; i < num; ++i) { + for (int j = 0; j < dim; ++j) { + bottom_diff[i * dim + j] = max(Dtype(0), 1 + bottom_diff[i * dim + j]); + } + } + return caffe_cpu_asum(count, bottom_diff) / num; +} + +template +void HingeLossLayer::Backward_cpu(const vector*>& top, + const bool propagate_down, vector*>* 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; + + caffe_cpu_sign(count, bottom_diff, bottom_diff); + for (int i = 0; i < num; ++i) { + bottom_diff[i * dim + static_cast(label[i])] *= -1; + } + caffe_scal(count, Dtype(1. / num), bottom_diff); +} + +INSTANTIATE_CLASS(HingeLossLayer); + +} // namespace caffe diff --git a/src/caffe/layers/infogain_loss_layer.cpp b/src/caffe/layers/infogain_loss_layer.cpp new file mode 100644 index 00000000000..ab6e67d73b1 --- /dev/null +++ b/src/caffe/layers/infogain_loss_layer.cpp @@ -0,0 +1,76 @@ +// Copyright 2014 BVLC and contributors. + +#include +#include +#include +#include + +#include "caffe/layer.hpp" +#include "caffe/vision_layers.hpp" +#include "caffe/util/math_functions.hpp" +#include "caffe/util/io.hpp" + +using std::max; + +namespace caffe { + +template +void InfogainLossLayer::FurtherSetUp( + const vector*>& bottom, vector*>* top) { + CHECK_EQ(bottom[1]->channels(), 1); + CHECK_EQ(bottom[1]->height(), 1); + CHECK_EQ(bottom[1]->width(), 1); + + BlobProto blob_proto; + ReadProtoFromBinaryFile( + this->layer_param_.infogain_loss_param().source(), &blob_proto); + infogain_.FromProto(blob_proto); + CHECK_EQ(infogain_.num(), 1); + CHECK_EQ(infogain_.channels(), 1); + CHECK_EQ(infogain_.height(), infogain_.width()); +} + + +template +Dtype InfogainLossLayer::Forward_cpu(const vector*>& bottom, + vector*>* top) { + const Dtype* bottom_data = bottom[0]->cpu_data(); + const Dtype* bottom_label = bottom[1]->cpu_data(); + const Dtype* infogain_mat = infogain_.cpu_data(); + int num = bottom[0]->num(); + int dim = bottom[0]->count() / bottom[0]->num(); + CHECK_EQ(infogain_.height(), dim); + Dtype loss = 0; + for (int i = 0; i < num; ++i) { + int label = static_cast(bottom_label[i]); + for (int j = 0; j < dim; ++j) { + Dtype prob = max(bottom_data[i * dim + j], Dtype(kLOG_THRESHOLD)); + loss -= infogain_mat[label * dim + j] * log(prob); + } + } + return loss / num; +} + +template +void InfogainLossLayer::Backward_cpu(const vector*>& top, + const bool propagate_down, + vector*>* 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(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; + } + } +} + +INSTANTIATE_CLASS(InfogainLossLayer); + +} // namespace caffe diff --git a/src/caffe/layers/loss_layer.cpp b/src/caffe/layers/loss_layer.cpp index b7f812a9288..1efb6235f98 100644 --- a/src/caffe/layers/loss_layer.cpp +++ b/src/caffe/layers/loss_layer.cpp @@ -14,246 +14,16 @@ using std::max; namespace caffe { -const float kLOG_THRESHOLD = 1e-20; - -template -void MultinomialLogisticLossLayer::SetUp( - const vector*>& bottom, vector*>* top) { - CHECK_EQ(bottom.size(), 2) << "Loss Layer takes two blobs as input."; - CHECK_EQ(top->size(), 0) << "Loss Layer takes no output."; - CHECK_EQ(bottom[0]->num(), bottom[1]->num()) - << "The data and label should have the same number."; - CHECK_EQ(bottom[1]->channels(), 1); - CHECK_EQ(bottom[1]->height(), 1); - CHECK_EQ(bottom[1]->width(), 1); -} - -template -Dtype MultinomialLogisticLossLayer::Forward_cpu( - const vector*>& bottom, vector*>* top) { - const Dtype* bottom_data = bottom[0]->cpu_data(); - const Dtype* bottom_label = bottom[1]->cpu_data(); - int num = bottom[0]->num(); - int dim = bottom[0]->count() / bottom[0]->num(); - Dtype loss = 0; - for (int i = 0; i < num; ++i) { - int label = static_cast(bottom_label[i]); - Dtype prob = max(bottom_data[i * dim + label], Dtype(kLOG_THRESHOLD)); - loss -= log(prob); - } - return loss / num; -} - -template -void MultinomialLogisticLossLayer::Backward_cpu( - const vector*>& top, const bool propagate_down, - vector*>* 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(bottom_label[i]); - Dtype prob = max(bottom_data[i * dim + label], Dtype(kLOG_THRESHOLD)); - bottom_diff[i * dim + label] = -1. / prob / num; - } -} - - template -void InfogainLossLayer::SetUp( +void LossLayer::SetUp( const vector*>& bottom, vector*>* top) { CHECK_EQ(bottom.size(), 2) << "Loss Layer takes two blobs as input."; CHECK_EQ(top->size(), 0) << "Loss Layer takes no output."; CHECK_EQ(bottom[0]->num(), bottom[1]->num()) << "The data and label should have the same number."; - CHECK_EQ(bottom[1]->channels(), 1); - CHECK_EQ(bottom[1]->height(), 1); - CHECK_EQ(bottom[1]->width(), 1); - BlobProto blob_proto; - ReadProtoFromBinaryFile(this->layer_param_.infogain_loss_param().source(), - &blob_proto); - infogain_.FromProto(blob_proto); - CHECK_EQ(infogain_.num(), 1); - CHECK_EQ(infogain_.channels(), 1); - CHECK_EQ(infogain_.height(), infogain_.width()); -} - - -template -Dtype InfogainLossLayer::Forward_cpu(const vector*>& bottom, - vector*>* top) { - const Dtype* bottom_data = bottom[0]->cpu_data(); - const Dtype* bottom_label = bottom[1]->cpu_data(); - const Dtype* infogain_mat = infogain_.cpu_data(); - int num = bottom[0]->num(); - int dim = bottom[0]->count() / bottom[0]->num(); - CHECK_EQ(infogain_.height(), dim); - Dtype loss = 0; - for (int i = 0; i < num; ++i) { - int label = static_cast(bottom_label[i]); - for (int j = 0; j < dim; ++j) { - Dtype prob = max(bottom_data[i * dim + j], Dtype(kLOG_THRESHOLD)); - loss -= infogain_mat[label * dim + j] * log(prob); - } - } - return loss / num; -} - -template -void InfogainLossLayer::Backward_cpu(const vector*>& top, - const bool propagate_down, - vector*>* 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(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 -void EuclideanLossLayer::SetUp( - const vector*>& bottom, vector*>* top) { - CHECK_EQ(bottom.size(), 2) << "Loss Layer takes two blobs as input."; - CHECK_EQ(top->size(), 0) << "Loss Layer takes no as output."; - CHECK_EQ(bottom[0]->num(), bottom[1]->num()) - << "The data and label should have the same number."; - CHECK_EQ(bottom[0]->channels(), bottom[1]->channels()); - CHECK_EQ(bottom[0]->height(), bottom[1]->height()); - CHECK_EQ(bottom[0]->width(), bottom[1]->width()); - difference_.Reshape(bottom[0]->num(), bottom[0]->channels(), - bottom[0]->height(), bottom[0]->width()); -} - -template -Dtype EuclideanLossLayer::Forward_cpu(const vector*>& bottom, - vector*>* top) { - int count = bottom[0]->count(); - int num = bottom[0]->num(); - caffe_sub(count, bottom[0]->cpu_data(), bottom[1]->cpu_data(), - difference_.mutable_cpu_data()); - Dtype loss = caffe_cpu_dot( - count, difference_.cpu_data(), difference_.cpu_data()) / num / Dtype(2); - return loss; -} - -template -void EuclideanLossLayer::Backward_cpu(const vector*>& top, - const bool propagate_down, vector*>* bottom) { - int count = (*bottom)[0]->count(); - int num = (*bottom)[0]->num(); - // Compute the gradient - caffe_cpu_axpby(count, Dtype(1) / num, difference_.cpu_data(), Dtype(0), - (*bottom)[0]->mutable_cpu_diff()); -} - -template -void AccuracyLayer::SetUp( - const vector*>& bottom, vector*>* top) { - CHECK_EQ(bottom.size(), 2) << "Accuracy Layer takes two blobs as input."; - CHECK_EQ(top->size(), 1) << "Accuracy Layer takes 1 output."; - CHECK_EQ(bottom[0]->num(), bottom[1]->num()) - << "The data and label should have the same number."; - CHECK_EQ(bottom[1]->channels(), 1); - CHECK_EQ(bottom[1]->height(), 1); - CHECK_EQ(bottom[1]->width(), 1); - (*top)[0]->Reshape(1, 2, 1, 1); -} - -template -Dtype AccuracyLayer::Forward_cpu(const vector*>& bottom, - vector*>* top) { - Dtype accuracy = 0; - Dtype logprob = 0; - const Dtype* bottom_data = bottom[0]->cpu_data(); - const Dtype* bottom_label = bottom[1]->cpu_data(); - int num = bottom[0]->num(); - int dim = bottom[0]->count() / bottom[0]->num(); - for (int i = 0; i < num; ++i) { - // Accuracy - Dtype maxval = -FLT_MAX; - int max_id = 0; - for (int j = 0; j < dim; ++j) { - if (bottom_data[i * dim + j] > maxval) { - maxval = bottom_data[i * dim + j]; - max_id = j; - } - } - if (max_id == static_cast(bottom_label[i])) { - ++accuracy; - } - Dtype prob = max(bottom_data[i * dim + static_cast(bottom_label[i])], - Dtype(kLOG_THRESHOLD)); - logprob -= log(prob); - } - // LOG(INFO) << "Accuracy: " << accuracy; - (*top)[0]->mutable_cpu_data()[0] = accuracy / num; - (*top)[0]->mutable_cpu_data()[1] = logprob / num; - // Accuracy layer should not be used as a loss function. - return Dtype(0); -} - -template -void HingeLossLayer::SetUp(const vector*>& bottom, - vector*>* top) { - CHECK_EQ(bottom.size(), 2) << "Hinge Loss Layer takes two blobs as input."; - CHECK_EQ(top->size(), 0) << "Hinge Loss Layer takes no output."; -} - -template -Dtype HingeLossLayer::Forward_cpu(const vector*>& bottom, - vector*>* top) { - const Dtype* bottom_data = bottom[0]->cpu_data(); - 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; - - caffe_copy(count, bottom_data, bottom_diff); - for (int i = 0; i < num; ++i) { - bottom_diff[i * dim + static_cast(label[i])] *= -1; - } - for (int i = 0; i < num; ++i) { - for (int j = 0; j < dim; ++j) { - bottom_diff[i * dim + j] = max(Dtype(0), 1 + bottom_diff[i * dim + j]); - } - } - return caffe_cpu_asum(count, bottom_diff) / num; -} - -template -void HingeLossLayer::Backward_cpu(const vector*>& top, - const bool propagate_down, vector*>* 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; - - caffe_cpu_sign(count, bottom_diff, bottom_diff); - for (int i = 0; i < num; ++i) { - bottom_diff[i * dim + static_cast(label[i])] *= -1; - } - caffe_scal(count, Dtype(1. / num), bottom_diff); + FurtherSetUp(bottom, top); } -INSTANTIATE_CLASS(MultinomialLogisticLossLayer); -INSTANTIATE_CLASS(InfogainLossLayer); -INSTANTIATE_CLASS(EuclideanLossLayer); -INSTANTIATE_CLASS(AccuracyLayer); -INSTANTIATE_CLASS(HingeLossLayer); +INSTANTIATE_CLASS(LossLayer); } // namespace caffe diff --git a/src/caffe/layers/multinomial_logistic_loss_layer.cpp b/src/caffe/layers/multinomial_logistic_loss_layer.cpp new file mode 100644 index 00000000000..6486621d8aa --- /dev/null +++ b/src/caffe/layers/multinomial_logistic_loss_layer.cpp @@ -0,0 +1,60 @@ +// Copyright 2014 BVLC and contributors. + +#include +#include +#include +#include + +#include "caffe/layer.hpp" +#include "caffe/vision_layers.hpp" +#include "caffe/util/math_functions.hpp" +#include "caffe/util/io.hpp" + +using std::max; + +namespace caffe { + +template +void MultinomialLogisticLossLayer::FurtherSetUp( + const vector*>& bottom, vector*>* top) { + CHECK_EQ(bottom[1]->channels(), 1); + CHECK_EQ(bottom[1]->height(), 1); + CHECK_EQ(bottom[1]->width(), 1); +} + +template +Dtype MultinomialLogisticLossLayer::Forward_cpu( + const vector*>& bottom, vector*>* top) { + const Dtype* bottom_data = bottom[0]->cpu_data(); + const Dtype* bottom_label = bottom[1]->cpu_data(); + int num = bottom[0]->num(); + int dim = bottom[0]->count() / bottom[0]->num(); + Dtype loss = 0; + for (int i = 0; i < num; ++i) { + int label = static_cast(bottom_label[i]); + Dtype prob = max(bottom_data[i * dim + label], Dtype(kLOG_THRESHOLD)); + loss -= log(prob); + } + return loss / num; +} + +template +void MultinomialLogisticLossLayer::Backward_cpu( + const vector*>& top, const bool propagate_down, + vector*>* 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(bottom_label[i]); + Dtype prob = max(bottom_data[i * dim + label], Dtype(kLOG_THRESHOLD)); + bottom_diff[i * dim + label] = -1. / prob / num; + } +} + +INSTANTIATE_CLASS(MultinomialLogisticLossLayer); + +} // namespace caffe diff --git a/src/caffe/layers/sigmoid_cross_entropy_loss_layer.cpp b/src/caffe/layers/sigmoid_cross_entropy_loss_layer.cpp index 767601c5271..a638684f3b6 100644 --- a/src/caffe/layers/sigmoid_cross_entropy_loss_layer.cpp +++ b/src/caffe/layers/sigmoid_cross_entropy_loss_layer.cpp @@ -13,16 +13,10 @@ using std::max; namespace caffe { template -void SigmoidCrossEntropyLossLayer::SetUp( +void SigmoidCrossEntropyLossLayer::FurtherSetUp( const vector*>& bottom, vector*>* top) { - CHECK_EQ(bottom.size(), 2) << - "SigmoidCrossEntropyLoss Layer takes two blobs as input."; - CHECK_EQ(top->size(), 0) << - "SigmoidCrossEntropyLoss Layer takes no blob as output."; CHECK_EQ(bottom[0]->count(), bottom[1]->count()) << "SigmoidCrossEntropyLoss Layer inputs must have same count."; - CHECK_EQ(bottom[0]->num(), bottom[1]->num()) << - "SigmoidCrossEntropyLoss Layer inputs must have same num."; sigmoid_bottom_vec_.clear(); sigmoid_bottom_vec_.push_back(bottom[0]); sigmoid_top_vec_.clear();