From 2779ce9e0e121a7bec6de90ca304a316cc150cf2 Mon Sep 17 00:00:00 2001 From: Sergey Karayev Date: Mon, 28 Apr 2014 19:06:07 -0700 Subject: [PATCH 1/7] layer definition reorganization and documentation - split out neuron, loss, and data layers into own header files - added LossLayer class with common SetUp checks - in-progress concise documentation of each layer's purpose --- include/caffe/data_layers.hpp | 215 +++++++++ include/caffe/loss_layers.hpp | 150 ++++++ include/caffe/neuron_layers.hpp | 160 +++++++ include/caffe/vision_layers.hpp | 453 +----------------- src/caffe/layers/loss_layer.cpp | 116 +++-- .../sigmoid_cross_entropy_loss_layer.cpp | 8 +- 6 files changed, 586 insertions(+), 516 deletions(-) create mode 100644 include/caffe/data_layers.hpp create mode 100644 include/caffe/loss_layers.hpp create mode 100644 include/caffe/neuron_layers.hpp diff --git a/include/caffe/data_layers.hpp b/include/caffe/data_layers.hpp new file mode 100644 index 00000000000..a1742febce5 --- /dev/null +++ b/include/caffe/data_layers.hpp @@ -0,0 +1,215 @@ +// 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" + +// 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_; +}; + +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_; +}; + +// 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..6ddfcc49514 --- /dev/null +++ b/include/caffe/loss_layers.hpp @@ -0,0 +1,150 @@ +// 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 { + +// LossLayer takes two inputs of same num, and has no output. +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 y = 1/2 \sum_i (x_i - x'_i)^2 +template +class EuclideanLossLayer : public LossLayer { + public: + explicit EuclideanLossLayer(const LayerParameter& param) + : LossLayer(param), difference_() {} + 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 difference_; +}; + + +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_; +}; + +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); +}; + +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: not an actual loss layer; +// computes the accuracy and logprob of x with respect to y'. +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; + } +}; + +} // 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..68ebc2bcac3 --- /dev/null +++ b/include/caffe/neuron_layers.hpp @@ -0,0 +1,160 @@ +// 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 is an interface for layers that work on single elements. +template +class NeuronLayer : public Layer { + public: + explicit NeuronLayer(const LayerParameter& param) + : Layer(param) {} + virtual void SetUp(const vector*>& bottom, + vector*>* top); +}; + +// BNLLLayer +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 sets random portion of its input to 0. +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 computes y = (shift + scale * x)^power +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 computes y = max(0, x). +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 computes y = 1. / (1 + exp(-x)) +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: computes y = 1. * (exp(2 * x) - 1) / (exp(2 * x) + 1) +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..7334adae102 100644 --- a/include/caffe/vision_layers.hpp +++ b/include/caffe/vision_layers.hpp @@ -7,197 +7,16 @@ #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; - } -}; - template class ConcatLayer : public Layer { public: @@ -260,50 +79,6 @@ 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_; -}; template class EltwiseProductLayer : public Layer { @@ -324,27 +99,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 +120,6 @@ 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); -}; - template class Im2colLayer : public Layer { public: @@ -465,73 +146,6 @@ 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_; -}; - template class InnerProductLayer : public Layer { public: @@ -658,25 +272,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: @@ -782,48 +377,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/loss_layer.cpp b/src/caffe/layers/loss_layer.cpp index b7f812a9288..3fc34a6d323 100644 --- a/src/caffe/layers/loss_layer.cpp +++ b/src/caffe/layers/loss_layer.cpp @@ -17,12 +17,24 @@ namespace caffe { const float kLOG_THRESHOLD = 1e-20; template -void MultinomialLogisticLossLayer::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."; + FurtherSetUp(bottom, top); +} + +template +void LossLayer::FurtherSetUp( + const vector*>& bottom, vector*>* top) { + // Nothing to do +} + +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); @@ -63,18 +75,15 @@ void MultinomialLogisticLossLayer::Backward_cpu( template -void InfogainLossLayer::SetUp( +void InfogainLossLayer::FurtherSetUp( 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); + ReadProtoFromBinaryFile( + this->layer_param_.infogain_loss_param().source(), &blob_proto); infogain_.FromProto(blob_proto); CHECK_EQ(infogain_.num(), 1); CHECK_EQ(infogain_.channels(), 1); @@ -124,12 +133,8 @@ void InfogainLossLayer::Backward_cpu(const vector*>& top, template -void EuclideanLossLayer::SetUp( +void EuclideanLossLayer::FurtherSetUp( 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()); @@ -159,6 +164,44 @@ void EuclideanLossLayer::Backward_cpu(const vector*>& top, (*bottom)[0]->mutable_cpu_diff()); } +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); +} + template void AccuracyLayer::SetUp( const vector*>& bottom, vector*>* top) { @@ -205,55 +248,10 @@ Dtype AccuracyLayer::Forward_cpu(const vector*>& bottom, 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); -} - INSTANTIATE_CLASS(MultinomialLogisticLossLayer); INSTANTIATE_CLASS(InfogainLossLayer); INSTANTIATE_CLASS(EuclideanLossLayer); -INSTANTIATE_CLASS(AccuracyLayer); INSTANTIATE_CLASS(HingeLossLayer); +INSTANTIATE_CLASS(AccuracyLayer); } // 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(); From 48a8a64c9b1596f60d6eabff4c0df887a3ea53bf Mon Sep 17 00:00:00 2001 From: Sergey Karayev Date: Mon, 28 Apr 2014 19:39:36 -0700 Subject: [PATCH 2/7] Split all loss layers into own .cpp files --- include/caffe/loss_layers.hpp | 4 +- src/caffe/layers/accuracy_layer.cpp | 65 +++++ src/caffe/layers/euclidean_loss_layer.cpp | 51 ++++ src/caffe/layers/hinge_loss_layer.cpp | 57 +++++ src/caffe/layers/infogain_loss_layer.cpp | 76 ++++++ src/caffe/layers/loss_layer.cpp | 230 +----------------- .../multinomial_logistic_loss_layer.cpp | 60 +++++ 7 files changed, 313 insertions(+), 230 deletions(-) create mode 100644 src/caffe/layers/accuracy_layer.cpp create mode 100644 src/caffe/layers/euclidean_loss_layer.cpp create mode 100644 src/caffe/layers/hinge_loss_layer.cpp create mode 100644 src/caffe/layers/infogain_loss_layer.cpp create mode 100644 src/caffe/layers/multinomial_logistic_loss_layer.cpp diff --git a/include/caffe/loss_layers.hpp b/include/caffe/loss_layers.hpp index 6ddfcc49514..a13e88966d6 100644 --- a/include/caffe/loss_layers.hpp +++ b/include/caffe/loss_layers.hpp @@ -20,6 +20,8 @@ namespace caffe { +const float kLOG_THRESHOLD = 1e-20; + // LossLayer takes two inputs of same num, and has no output. template class LossLayer : public Layer { @@ -29,7 +31,7 @@ class LossLayer : public Layer { virtual void SetUp( const vector*>& bottom, vector*>* top); virtual void FurtherSetUp( - const vector*>& bottom, vector*>* top); + const vector*>& bottom, vector*>* top) {} }; // SigmoidCrossEntropyLossLayer 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/euclidean_loss_layer.cpp b/src/caffe/layers/euclidean_loss_layer.cpp new file mode 100644 index 00000000000..9bf7f983fb3 --- /dev/null +++ b/src/caffe/layers/euclidean_loss_layer.cpp @@ -0,0 +1,51 @@ +// 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()); + 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()); +} + +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 3fc34a6d323..1efb6235f98 100644 --- a/src/caffe/layers/loss_layer.cpp +++ b/src/caffe/layers/loss_layer.cpp @@ -14,8 +14,6 @@ using std::max; namespace caffe { -const float kLOG_THRESHOLD = 1e-20; - template void LossLayer::SetUp( const vector*>& bottom, vector*>* top) { @@ -26,232 +24,6 @@ void LossLayer::SetUp( FurtherSetUp(bottom, top); } -template -void LossLayer::FurtherSetUp( - const vector*>& bottom, vector*>* top) { - // Nothing to do -} - -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; - } -} - - -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; - } - } -} - - -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()); - 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 -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); -} - -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(MultinomialLogisticLossLayer); -INSTANTIATE_CLASS(InfogainLossLayer); -INSTANTIATE_CLASS(EuclideanLossLayer); -INSTANTIATE_CLASS(HingeLossLayer); -INSTANTIATE_CLASS(AccuracyLayer); +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 From 4051cef49e5eecf4ce9de54ef1adf79e35cb3cf0 Mon Sep 17 00:00:00 2001 From: Sergey Karayev Date: Mon, 28 Apr 2014 19:40:43 -0700 Subject: [PATCH 3/7] Cosmetic change in prep for data layer work --- include/caffe/data_layers.hpp | 93 ++++++++++++++++++----------------- 1 file changed, 48 insertions(+), 45 deletions(-) diff --git a/include/caffe/data_layers.hpp b/include/caffe/data_layers.hpp index a1742febce5..d9865ce485b 100644 --- a/include/caffe/data_layers.hpp +++ b/include/caffe/data_layers.hpp @@ -22,51 +22,6 @@ namespace caffe { #define HDF5_DATA_DATASET_NAME "data" #define HDF5_DATA_LABEL_NAME "label" -// 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_; -}; - template class HDF5OutputLayer : public Layer { public: @@ -122,6 +77,54 @@ class HDF5DataLayer : public Layer { 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); From d01c6ed712ba8285ed2b9b4c922e03ffc9fb2929 Mon Sep 17 00:00:00 2001 From: Sergey Karayev Date: Tue, 29 Apr 2014 00:21:15 -0700 Subject: [PATCH 4/7] fwd/back math docs for neuron layers --- include/caffe/neuron_layers.hpp | 55 ++++++++++++++++++++++++++---- src/caffe/layers/dropout_layer.cpp | 2 ++ 2 files changed, 50 insertions(+), 7 deletions(-) diff --git a/include/caffe/neuron_layers.hpp b/include/caffe/neuron_layers.hpp index 68ebc2bcac3..e5108416866 100644 --- a/include/caffe/neuron_layers.hpp +++ b/include/caffe/neuron_layers.hpp @@ -22,7 +22,10 @@ namespace caffe { -// NeuronLayer is an interface for layers that work on single elements. +/* 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: @@ -32,7 +35,13 @@ class NeuronLayer : public Layer { vector*>* top); }; -// BNLLLayer +/* 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: @@ -50,7 +59,16 @@ class BNLLLayer : public NeuronLayer { const bool propagate_down, vector*>* bottom); }; -// DropoutLayer sets random portion of its input to 0. +/* 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: @@ -75,7 +93,12 @@ class DropoutLayer : public NeuronLayer { unsigned int uint_thres_; }; -// PowerLayer computes y = (shift + scale * x)^power +/* 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: @@ -100,7 +123,13 @@ class PowerLayer : public NeuronLayer { Dtype diff_scale_; }; -// ReLULayer computes y = max(0, x). +/* ReLULayer + Rectified Linear Unit non-linearity: fast and stable. + + y = max(0, x). + + y' = x > 0 +*/ template class ReLULayer : public NeuronLayer { public: @@ -119,7 +148,13 @@ class ReLULayer : public NeuronLayer { const bool propagate_down, vector*>* bottom); }; -// SigmoidLayer computes y = 1. / (1 + exp(-x)) +/* SigmoidLayer + Sigmoid function non-linearity: a classic. + + y = 1. / (1 + exp(-x)) + + y' = y * (1 - y) +*/ template class SigmoidLayer : public NeuronLayer { public: @@ -137,7 +172,13 @@ class SigmoidLayer : public NeuronLayer { const bool propagate_down, vector*>* bottom); }; -// TanHLayer: computes y = 1. * (exp(2 * x) - 1) / (exp(2 * x) + 1) +/* TanHLayer + Hyperbolic tangent non-linearity. + + y = 1. * (exp(2x) - 1) / (exp(2x) + 1) + + y' = 1 - [(exp(2x) - 1) / (exp(2x) + 1)] ^ 2 +*/ template class TanHLayer : public NeuronLayer { public: 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" From efeaf17ba55a55d12c2a40b2d80c0bb49cfac340 Mon Sep 17 00:00:00 2001 From: Sergey Karayev Date: Mon, 19 May 2014 10:43:21 -0700 Subject: [PATCH 5/7] =?UTF-8?q?Lil=E2=80=99=20more=20docstring,=20and=20co?= =?UTF-8?q?smetic=20change=20in=20EuclideanLossLayer?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- include/caffe/loss_layers.hpp | 37 +++++++++++++++++------ include/caffe/vision_layers.hpp | 36 ++++++++++++++++++---- src/caffe/layers/euclidean_loss_layer.cpp | 25 ++++++++------- 3 files changed, 72 insertions(+), 26 deletions(-) diff --git a/include/caffe/loss_layers.hpp b/include/caffe/loss_layers.hpp index a13e88966d6..cc798c499d3 100644 --- a/include/caffe/loss_layers.hpp +++ b/include/caffe/loss_layers.hpp @@ -22,7 +22,10 @@ namespace caffe { const float kLOG_THRESHOLD = 1e-20; -// LossLayer takes two inputs of same num, and has no output. +/* 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: @@ -34,7 +37,8 @@ class LossLayer : public Layer { const vector*>& bottom, vector*>* top) {} }; -// SigmoidCrossEntropyLossLayer +/* SigmoidCrossEntropyLossLayer +*/ template class SigmoidCrossEntropyLossLayer : public LossLayer { public: @@ -63,12 +67,17 @@ class SigmoidCrossEntropyLossLayer : public LossLayer { vector*> sigmoid_top_vec_; }; -// EuclideanLossLayer: compute y = 1/2 \sum_i (x_i - x'_i)^2 +/* 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), difference_() {} + : LossLayer(param), diff_() {} virtual void FurtherSetUp(const vector*>& bottom, vector*>* top); @@ -78,10 +87,11 @@ class EuclideanLossLayer : public LossLayer { virtual void Backward_cpu(const vector*>& top, const bool propagate_down, vector*>* bottom); - Blob difference_; + Blob diff_; }; - +/* InfogainLossLayer +*/ template class InfogainLossLayer : public LossLayer { public: @@ -99,6 +109,8 @@ class InfogainLossLayer : public LossLayer { Blob infogain_; }; +/* HingeLossLayer +*/ template class HingeLossLayer : public LossLayer { public: @@ -112,6 +124,8 @@ class HingeLossLayer : public LossLayer { const bool propagate_down, vector*>* bottom); }; +/* MultinomialLogisticLossLayer +*/ template class MultinomialLogisticLossLayer : public LossLayer { public: @@ -127,8 +141,10 @@ class MultinomialLogisticLossLayer : public LossLayer { const bool propagate_down, vector*>* bottom); }; -// AccuracyLayer: not an actual loss layer; -// computes the accuracy and logprob of x with respect to y'. +/* 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: @@ -140,13 +156,16 @@ class AccuracyLayer : public Layer { 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; } }; +/* Also see +- SoftmaxWithLossLayer in vision_layers.hpp +*/ + } // namespace caffe #endif // CAFFE_LOSS_LAYERS_HPP_ diff --git a/include/caffe/vision_layers.hpp b/include/caffe/vision_layers.hpp index 7334adae102..de99bc3033f 100644 --- a/include/caffe/vision_layers.hpp +++ b/include/caffe/vision_layers.hpp @@ -17,6 +17,11 @@ namespace caffe { +/* +ConcatLayer + Takes at least two blobs and concatenates them along either num or + channel dim, outputting the result. +*/ template class ConcatLayer : public Layer { public: @@ -44,6 +49,8 @@ class ConcatLayer : public Layer { int concat_dim_; }; +/* ConvolutionLayer +*/ template class ConvolutionLayer : public Layer { public: @@ -79,7 +86,8 @@ class ConvolutionLayer : public Layer { int N_; }; - +/* EltwiseProductLayer +*/ template class EltwiseProductLayer : public Layer { public: @@ -120,6 +128,8 @@ class FlattenLayer : public Layer { int count_; }; +/* Im2colLayer +*/ template class Im2colLayer : public Layer { public: @@ -146,6 +156,8 @@ class Im2colLayer : public Layer { int pad_; }; +/* InnerProductLayer +*/ template class InnerProductLayer : public Layer { public: @@ -175,6 +187,9 @@ class InnerProductLayer : public Layer { template class PoolingLayer; template class SplitLayer; +/* LRNLayer + Local Response Normalization +*/ template class LRNLayer : public Layer { public: @@ -238,6 +253,8 @@ class LRNLayer : public Layer { vector*> product_bottom_vec_; }; +/* PoolingLayer +*/ template class MemoryDataLayer : public Layer { public: @@ -301,6 +318,8 @@ class PoolingLayer : public Layer { Blob rand_idx_; }; +/* SoftmaxLayer +*/ template class SoftmaxLayer : public Layer { public: @@ -325,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: @@ -356,6 +378,8 @@ class SoftmaxWithLossLayer : public Layer { vector*> softmax_top_vec_; }; +/* SplitLayer +*/ template class SplitLayer : public Layer { public: diff --git a/src/caffe/layers/euclidean_loss_layer.cpp b/src/caffe/layers/euclidean_loss_layer.cpp index 9bf7f983fb3..a894d470c64 100644 --- a/src/caffe/layers/euclidean_loss_layer.cpp +++ b/src/caffe/layers/euclidean_loss_layer.cpp @@ -20,7 +20,7 @@ void EuclideanLossLayer::FurtherSetUp( 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(), + diff_.Reshape(bottom[0]->num(), bottom[0]->channels(), bottom[0]->height(), bottom[0]->width()); } @@ -28,22 +28,25 @@ 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); + 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) { - 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()); + 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); From 1b735b5482b1de6664fffffce42b46105084ea5f Mon Sep 17 00:00:00 2001 From: Sergey Karayev Date: Mon, 19 May 2014 10:44:21 -0700 Subject: [PATCH 6/7] Cosmetic change in ConcatLayer --- src/caffe/layers/concat_layer.cpp | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) 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); From c5db25b2033fbe44712d5a709e5af7fbabc4308d Mon Sep 17 00:00:00 2001 From: Sergey Karayev Date: Mon, 19 May 2014 11:11:37 -0700 Subject: [PATCH 7/7] =?UTF-8?q?Incorporated=20Evan=E2=80=99s=20comments=20?= =?UTF-8?q?for=20neuron=20layers?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- include/caffe/neuron_layers.hpp | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/include/caffe/neuron_layers.hpp b/include/caffe/neuron_layers.hpp index e5108416866..fb2347da436 100644 --- a/include/caffe/neuron_layers.hpp +++ b/include/caffe/neuron_layers.hpp @@ -124,11 +124,13 @@ class PowerLayer : public NeuronLayer { }; /* ReLULayer - Rectified Linear Unit non-linearity: fast and stable. + Rectified Linear Unit non-linearity. + The simple max is fast to compute, and the function does not saturate. y = max(0, x). - y' = x > 0 + y' = 0 if x < 0 + y' = 1 if x > 0 */ template class ReLULayer : public NeuronLayer { @@ -149,10 +151,14 @@ class ReLULayer : public NeuronLayer { }; /* SigmoidLayer - Sigmoid function non-linearity: a classic. + 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 @@ -173,11 +179,11 @@ class SigmoidLayer : public NeuronLayer { }; /* TanHLayer - Hyperbolic tangent non-linearity. + 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 + y' = 1 - ( (exp(2x) - 1) / (exp(2x) + 1) ) ^ 2 */ template class TanHLayer : public NeuronLayer {