return *singleton_;
}
enum Brew { CPU, GPU };
- enum Phase { TRAIN, TEST };
-
// This random number generator facade hides boost and CUDA rng
// implementation from one another (for cross-platform compatibility).
// Returns the mode: running on CPU or GPU.
inline static Brew mode() { return Get().mode_; }
- // Returns the phase: TRAIN or TEST.
- inline static Phase phase() { return Get().phase_; }
// The setters for the variables
// Sets the mode. It is recommended that you don't change the mode halfway
// into the program since that may cause allocation of pinned memory being
// freed in a non-pinned way, which may cause problems - I haven't verified
// it personally but better to note it here in the header file.
inline static void set_mode(Brew mode) { Get().mode_ = mode; }
- // Sets the phase.
- inline static void set_phase(Phase phase) { Get().phase_ = phase; }
// Sets the random seed of both boost and curand
static void set_random_seed(const unsigned int seed);
// Sets the device. Since we have cublas and curand stuff, set device also
shared_ptr<RNG> random_generator_;
Brew mode_;
- Phase phase_;
static shared_ptr<Caffe> singleton_;
private:
#include "caffe/filler.hpp"
#include "caffe/internal_thread.hpp"
#include "caffe/layer.hpp"
+#include "caffe/net.hpp"
#include "caffe/proto/caffe.pb.h"
#include "caffe/util/db.hpp"
*/
explicit Layer(const LayerParameter& param)
: layer_param_(param) {
- // The only thing we do is to copy blobs if there are any.
+ // Set phase and copy blobs (if there are any).
+ phase_ = param.phase();
if (layer_param_.blobs_size() > 0) {
blobs_.resize(layer_param_.blobs_size());
for (int i = 0; i < layer_param_.blobs_size(); ++i) {
protected:
/** The protobuf that stores the layer parameters */
LayerParameter layer_param_;
+ /** The phase: TRAIN or TEST */
+ Phase phase_;
/** The vector that stores the learnable parameters as a set of blobs. */
vector<shared_ptr<Blob<Dtype> > > blobs_;
/** Vector indicating whether to compute the diff of each param blob. */
/**
* @brief Computes the Contrastive error gradient w.r.t. the inputs.
- *
- * Computes the gradients with respect to the two input vectors (bottom[0] and
+ *
+ * Computes the gradients with respect to the two input vectors (bottom[0] and
* bottom[1]), but not the similarity label (bottom[2]).
*
* @param top output Blob vector (length 1), providing the error gradient with
* the features @f$a@f$; Backward fills their diff with
* gradients if propagate_down[0]
* -# @f$ (N \times C \times 1 \times 1) @f$
- * the features @f$b@f$; Backward fills their diff with gradients if
+ * the features @f$b@f$; Backward fills their diff with gradients if
* propagate_down[1]
*/
virtual void Backward_cpu(const vector<Blob<Dtype>*>& top,
inline const vector<shared_ptr<Layer<Dtype> > >& layers() const {
return layers_;
}
+ /// @brief returns the phase: TRAIN or TEST
+ inline Phase phase() const { return phase_; }
/**
* @brief returns the bottom vecs for each layer -- usually you won't
* need this unless you do per-layer checks such as gradients.
/// @brief Get misc parameters, e.g. the LR multiplier and weight decay.
void GetLearningRateAndWeightDecay();
+ /// @brief The network name
+ string name_;
+ /// @brief The phase: TRAIN or TEST
+ Phase phase_;
/// @brief Individual layers in the net
vector<shared_ptr<Layer<Dtype> > > layers_;
vector<string> layer_names_;
vector<int> net_output_blob_indices_;
vector<Blob<Dtype>*> net_input_blobs_;
vector<Blob<Dtype>*> net_output_blobs_;
- string name_;
/// The parameters in the network.
vector<shared_ptr<Blob<Dtype> > > params_;
/// the learning rate multipliers
#include "caffe/blob.hpp"
#include "caffe/common.hpp"
#include "caffe/layer.hpp"
+#include "caffe/net.hpp"
#include "caffe/proto/caffe.pb.h"
#define HDF5_DATA_DATASET_NAME "data"
#ifdef CPU_ONLY // CPU-only Caffe.
Caffe::Caffe()
- : random_generator_(), mode_(Caffe::CPU), phase_(Caffe::TRAIN) { }
+ : random_generator_(), mode_(Caffe::CPU) { }
Caffe::~Caffe() { }
Caffe::Caffe()
: cublas_handle_(NULL), curand_generator_(NULL), random_generator_(),
- mode_(Caffe::CPU), phase_(Caffe::TRAIN) {
+ mode_(Caffe::CPU) {
// Try to create a cublas handler, and report an error if failed (but we will
// keep the program running as one might just want to run CPU code).
if (cublasCreate(&cublas_handle_) != CUBLAS_STATUS_SUCCESS) {
}
// The subclasses should setup the size of bottom and top
DataLayerSetUp(bottom, top);
- data_transformer_.InitRand();
+ data_transformer_->InitRand();
}
template <typename Dtype>
Dtype* top_data = top[0]->mutable_cpu_data();
unsigned int* mask = rand_vec_.mutable_cpu_data();
const int count = bottom[0]->count();
- if (Caffe::phase() == Caffe::TRAIN) {
+ if (this->phase_ == TRAIN) {
// Create random numbers
caffe_rng_bernoulli(count, 1. - threshold_, mask);
for (int i = 0; i < count; ++i) {
if (propagate_down[0]) {
const Dtype* top_diff = top[0]->cpu_diff();
Dtype* bottom_diff = bottom[0]->mutable_cpu_diff();
- if (Caffe::phase() == Caffe::TRAIN) {
+ if (this->phase_ == TRAIN) {
const unsigned int* mask = rand_vec_.cpu_data();
const int count = bottom[0]->count();
for (int i = 0; i < count; ++i) {
const Dtype* bottom_data = bottom[0]->gpu_data();
Dtype* top_data = top[0]->mutable_gpu_data();
const int count = bottom[0]->count();
- if (Caffe::phase() == Caffe::TRAIN) {
+ if (this->phase_ == TRAIN) {
unsigned int* mask =
static_cast<unsigned int*>(rand_vec_.mutable_gpu_data());
caffe_gpu_rng_uniform(count, mask);
if (propagate_down[0]) {
const Dtype* top_diff = top[0]->gpu_diff();
Dtype* bottom_diff = bottom[0]->mutable_gpu_diff();
- if (Caffe::phase() == Caffe::TRAIN) {
+ if (this->phase_ == TRAIN) {
const unsigned int* mask =
static_cast<const unsigned int*>(rand_vec_.gpu_data());
const int count = bottom[0]->count();
kernel_w_, stride_h_, stride_w_, pad_h_, pad_w_, top_data);
break;
case PoolingParameter_PoolMethod_STOCHASTIC:
- if (Caffe::phase() == Caffe::TRAIN) {
+ if (this->phase_ == TRAIN) {
// We need to create the random index as well.
caffe_gpu_rng_uniform(count, Dtype(0), Dtype(1),
rand_idx_.mutable_gpu_data());
template <typename Dtype>
void Net<Dtype>::Init(const NetParameter& in_param) {
+ // Set phase from the state.
+ phase_ = in_param.state().phase();
// Filter layers based on their include/exclude rules and
// the current NetState.
NetParameter filtered_param;
top_id_vecs_.resize(param.layer_size());
bottom_need_backward_.resize(param.layer_size());
for (int layer_id = 0; layer_id < param.layer_size(); ++layer_id) {
+ // Inherit phase from net if unset.
+ if (!param.layer(layer_id).has_phase()) {
+ param.mutable_layer(layer_id)->set_phase(phase_);
+ }
+ // Setup layer.
const LayerParameter& layer_param = param.layer(layer_id);
layers_.push_back(LayerRegistry<Dtype>::CreateLayer(layer_param));
layer_names_.push_back(layer_param.name());
void Net<Dtype>::FilterNet(const NetParameter& param,
NetParameter* param_filtered) {
NetState net_state(param.state());
- // Let the phase of the net be the current global phase provided in the Caffe
- // singleton, unless explicitly provided by the state.
- if (!net_state.has_phase()) {
- switch (Caffe::phase()) {
- case Caffe::TRAIN:
- net_state.set_phase(TRAIN);
- break;
- case Caffe::TEST:
- net_state.set_phase(TEST);
- break;
- default:
- LOG(FATAL) << "Unknown phase: " << Caffe::phase();
- }
- }
param_filtered->CopyFrom(param);
param_filtered->clear_layer();
for (int i = 0; i < param.layer_size(); ++i) {
repeated string bottom = 3; // the name of each bottom blob
repeated string top = 4; // the name of each top blob
+ // The train / test phase for computation.
+ optional Phase phase = 10;
+
// The amount of weight to assign each top blob in the objective.
// Each layer assigns a default value, usually of either 0 or 1,
// to each top blob.
EXPECT_EQ(Caffe::mode(), Caffe::GPU);
}
-TEST_F(CommonTest, TestPhase) {
- Caffe::set_phase(Caffe::TRAIN);
- EXPECT_EQ(Caffe::phase(), Caffe::TRAIN);
- Caffe::set_phase(Caffe::TEST);
- EXPECT_EQ(Caffe::phase(), Caffe::TEST);
-}
-
TEST_F(CommonTest, TestRandSeedCPU) {
SyncedMemory data_a(10 * sizeof(int));
SyncedMemory data_b(10 * sizeof(int));
void TestRead() {
const Dtype scale = 3;
LayerParameter param;
+ param.set_phase(TRAIN);
DataParameter* data_param = param.mutable_data_param();
data_param->set_batch_size(5);
data_param->set_source(filename_->c_str());
// Load and check data of various shapes.
LayerParameter param;
+ param.set_phase(TEST);
DataParameter* data_param = param.mutable_data_param();
data_param->set_batch_size(1);
data_param->set_source(filename_->c_str());
}
}
- void TestReadCrop() {
+ void TestReadCrop(Phase phase) {
const Dtype scale = 3;
LayerParameter param;
+ param.set_phase(phase);
Caffe::set_random_seed(1701);
DataParameter* data_param = param.mutable_data_param();
num_with_center_value +=
(center_value == blob_top_data_->cpu_data()[i * 2 + j]);
// At TEST time, check that we always get center value.
- if (Caffe::phase() == Caffe::TEST) {
+ if (phase == caffe::TEST) {
EXPECT_EQ(center_value, this->blob_top_data_->cpu_data()[i * 2 + j])
<< "debug: iter " << iter << " i " << i << " j " << j;
}
// At TRAIN time, check that we did not get the center crop all 10 times.
// (This check fails with probability 1-1/12^10 in a correct
// implementation, so we call set_random_seed.)
- if (Caffe::phase() == Caffe::TRAIN) {
+ if (phase == caffe::TRAIN) {
EXPECT_LT(num_with_center_value, 10);
}
}
void TestReadCropTrainSequenceSeeded() {
LayerParameter param;
+ param.set_phase(TRAIN);
DataParameter* data_param = param.mutable_data_param();
data_param->set_batch_size(5);
data_param->set_source(filename_->c_str());
void TestReadCropTrainSequenceUnseeded() {
LayerParameter param;
+ param.set_phase(TRAIN);
DataParameter* data_param = param.mutable_data_param();
data_param->set_batch_size(5);
data_param->set_source(filename_->c_str());
}
TYPED_TEST(DataLayerTest, TestReadCropTrainLevelDB) {
- Caffe::set_phase(Caffe::TRAIN);
const bool unique_pixels = true; // all images the same; pixels different
this->Fill(unique_pixels, DataParameter_DB_LEVELDB);
- this->TestReadCrop();
+ this->TestReadCrop(TRAIN);
}
// Test that the sequence of random crops is consistent when using
// Caffe::set_random_seed.
TYPED_TEST(DataLayerTest, TestReadCropTrainSequenceSeededLevelDB) {
- Caffe::set_phase(Caffe::TRAIN);
const bool unique_pixels = true; // all images the same; pixels different
this->Fill(unique_pixels, DataParameter_DB_LEVELDB);
this->TestReadCropTrainSequenceSeeded();
// Test that the sequence of random crops differs across iterations when
// Caffe::set_random_seed isn't called (and seeds from srand are ignored).
TYPED_TEST(DataLayerTest, TestReadCropTrainSequenceUnseededLevelDB) {
- Caffe::set_phase(Caffe::TRAIN);
const bool unique_pixels = true; // all images the same; pixels different
this->Fill(unique_pixels, DataParameter_DB_LEVELDB);
this->TestReadCropTrainSequenceUnseeded();
}
TYPED_TEST(DataLayerTest, TestReadCropTestLevelDB) {
- Caffe::set_phase(Caffe::TEST);
const bool unique_pixels = true; // all images the same; pixels different
this->Fill(unique_pixels, DataParameter_DB_LEVELDB);
- this->TestReadCrop();
+ this->TestReadCrop(TEST);
}
TYPED_TEST(DataLayerTest, TestReadLMDB) {
}
TYPED_TEST(DataLayerTest, TestReadCropTrainLMDB) {
- Caffe::set_phase(Caffe::TRAIN);
const bool unique_pixels = true; // all images the same; pixels different
this->Fill(unique_pixels, DataParameter_DB_LMDB);
- this->TestReadCrop();
+ this->TestReadCrop(TRAIN);
}
// Test that the sequence of random crops is consistent when using
// Caffe::set_random_seed.
TYPED_TEST(DataLayerTest, TestReadCropTrainSequenceSeededLMDB) {
- Caffe::set_phase(Caffe::TRAIN);
const bool unique_pixels = true; // all images the same; pixels different
this->Fill(unique_pixels, DataParameter_DB_LMDB);
this->TestReadCropTrainSequenceSeeded();
// Test that the sequence of random crops differs across iterations when
// Caffe::set_random_seed isn't called (and seeds from srand are ignored).
TYPED_TEST(DataLayerTest, TestReadCropTrainSequenceUnseededLMDB) {
- Caffe::set_phase(Caffe::TRAIN);
const bool unique_pixels = true; // all images the same; pixels different
this->Fill(unique_pixels, DataParameter_DB_LMDB);
this->TestReadCropTrainSequenceUnseeded();
}
TYPED_TEST(DataLayerTest, TestReadCropTestLMDB) {
- Caffe::set_phase(Caffe::TEST);
const bool unique_pixels = true; // all images the same; pixels different
this->Fill(unique_pixels, DataParameter_DB_LMDB);
- this->TestReadCrop();
+ this->TestReadCrop(TEST);
}
} // namespace caffe
num_iter_(10) {}
int NumSequenceMatches(const TransformationParameter transform_param,
- const Datum& datum) {
+ const Datum& datum, Phase phase) {
// Get crop sequence with Caffe seed 1701.
DataTransformer<Dtype>* transformer =
- new DataTransformer<Dtype>(transform_param);
+ new DataTransformer<Dtype>(transform_param, phase);
const int crop_size = transform_param.crop_size();
Caffe::set_random_seed(seed_);
transformer->InitRand();
FillDatum(label, channels, height, width, unique_pixels, &datum);
Blob<TypeParam>* blob = new Blob<TypeParam>(1, channels, height, width);
DataTransformer<TypeParam>* transformer =
- new DataTransformer<TypeParam>(transform_param);
+ new DataTransformer<TypeParam>(transform_param, TEST);
transformer->InitRand();
transformer->Transform(datum, blob);
EXPECT_EQ(blob->num(), 1);
FillDatum(label, channels, height, width, unique_pixels, &datum);
Blob<TypeParam>* blob = new Blob<TypeParam>(1, 3, 4, 5);
DataTransformer<TypeParam>* transformer =
- new DataTransformer<TypeParam>(transform_param);
+ new DataTransformer<TypeParam>(transform_param, TEST);
transformer->InitRand();
transformer->Transform(datum, blob);
EXPECT_EQ(blob->num(), 1);
Datum datum;
FillDatum(label, channels, height, width, unique_pixels, &datum);
DataTransformer<TypeParam>* transformer =
- new DataTransformer<TypeParam>(transform_param);
+ new DataTransformer<TypeParam>(transform_param, TEST);
transformer->InitRand();
Blob<TypeParam>* blob =
new Blob<TypeParam>(1, channels, crop_size, crop_size);
transform_param.set_crop_size(crop_size);
Datum datum;
FillDatum(label, channels, height, width, unique_pixels, &datum);
- Caffe::set_phase(Caffe::TRAIN);
- int num_matches = this->NumSequenceMatches(transform_param, datum);
+ int num_matches = this->NumSequenceMatches(transform_param, datum, TRAIN);
EXPECT_LT(num_matches, size * this->num_iter_);
}
transform_param.set_crop_size(crop_size);
Datum datum;
FillDatum(label, channels, height, width, unique_pixels, &datum);
- Caffe::set_phase(Caffe::TEST);
- int num_matches = this->NumSequenceMatches(transform_param, datum);
+ int num_matches = this->NumSequenceMatches(transform_param, datum, TEST);
EXPECT_EQ(num_matches, size * this->num_iter_);
}
transform_param.set_mirror(true);
Datum datum;
FillDatum(label, channels, height, width, unique_pixels, &datum);
- Caffe::set_phase(Caffe::TRAIN);
- int num_matches = this->NumSequenceMatches(transform_param, datum);
+ int num_matches = this->NumSequenceMatches(transform_param, datum, TRAIN);
EXPECT_LT(num_matches, size * this->num_iter_);
}
transform_param.set_mirror(true);
Datum datum;
FillDatum(label, channels, height, width, unique_pixels, &datum);
- Caffe::set_phase(Caffe::TEST);
- int num_matches = this->NumSequenceMatches(transform_param, datum);
+ int num_matches = this->NumSequenceMatches(transform_param, datum, TEST);
EXPECT_LT(num_matches, size * this->num_iter_);
}
Datum datum;
FillDatum(label, channels, height, width, unique_pixels, &datum);
transform_param.set_crop_size(crop_size);
- Caffe::set_phase(Caffe::TRAIN);
- int num_matches_crop = this->NumSequenceMatches(transform_param, datum);
+ int num_matches_crop = this->NumSequenceMatches(
+ transform_param, datum, TRAIN);
transform_param.set_mirror(true);
int num_matches_crop_mirror =
- this->NumSequenceMatches(transform_param, datum);
+ this->NumSequenceMatches(transform_param, datum, TRAIN);
// When doing crop and mirror we expect less num_matches than just crop
EXPECT_LE(num_matches_crop_mirror, num_matches_crop);
}
Datum datum;
FillDatum(label, channels, height, width, unique_pixels, &datum);
transform_param.set_crop_size(crop_size);
- Caffe::set_phase(Caffe::TEST);
- int num_matches_crop = this->NumSequenceMatches(transform_param, datum);
+ int num_matches_crop = this->NumSequenceMatches(transform_param, datum, TEST);
transform_param.set_mirror(true);
int num_matches_crop_mirror =
- this->NumSequenceMatches(transform_param, datum);
+ this->NumSequenceMatches(transform_param, datum, TEST);
// When doing crop and mirror we expect less num_matches than just crop
EXPECT_LT(num_matches_crop_mirror, num_matches_crop);
}
FillDatum(label, channels, height, width, unique_pixels, &datum);
Blob<TypeParam>* blob = new Blob<TypeParam>(1, channels, height, width);
DataTransformer<TypeParam>* transformer =
- new DataTransformer<TypeParam>(transform_param);
+ new DataTransformer<TypeParam>(transform_param, TEST);
transformer->InitRand();
transformer->Transform(datum, blob);
for (int j = 0; j < blob->count(); ++j) {
FillDatum(label, channels, height, width, unique_pixels, &datum);
Blob<TypeParam>* blob = new Blob<TypeParam>(1, channels, height, width);
DataTransformer<TypeParam>* transformer =
- new DataTransformer<TypeParam>(transform_param);
+ new DataTransformer<TypeParam>(transform_param, TEST);
transformer->InitRand();
transformer->Transform(datum, blob);
for (int c = 0; c < channels; ++c) {
FillDatum(label, channels, height, width, unique_pixels, &datum);
Blob<TypeParam>* blob = new Blob<TypeParam>(1, channels, height, width);
DataTransformer<TypeParam>* transformer =
- new DataTransformer<TypeParam>(transform_param);
+ new DataTransformer<TypeParam>(transform_param, TEST);
transformer->InitRand();
transformer->Transform(datum, blob);
for (int j = 0; j < blob->count(); ++j) {
TYPED_TEST(MaxPoolingDropoutTest, TestBackward) {
typedef typename TypeParam::Dtype Dtype;
- Caffe::set_phase(Caffe::TRAIN);
LayerParameter layer_param;
+ layer_param.set_phase(TRAIN);
PoolingParameter* pooling_param = layer_param.mutable_pooling_param();
pooling_param->set_kernel_size(3);
pooling_param->set_stride(2);
output_proto_test + " state: { phase: TEST } ";
this->RunFilterNetTest(input_proto_train, output_proto_train_explicit);
this->RunFilterNetTest(input_proto_test, output_proto_test_explicit);
-
- // Also check that nets are filtered according to the Caffe singleton phase,
- // if not explicitly specified in the input proto.
- Caffe::set_phase(Caffe::TRAIN);
- this->RunFilterNetTest(input_proto, output_proto_train);
- Caffe::set_phase(Caffe::TEST);
- this->RunFilterNetTest(input_proto, output_proto_test);
-
- // Finally, check that the current Caffe singleton phase is ignored if the
- // phase is explicitly specified in the input proto.
- Caffe::set_phase(Caffe::TEST);
- this->RunFilterNetTest(input_proto_train, output_proto_train_explicit);
- Caffe::set_phase(Caffe::TRAIN);
- this->RunFilterNetTest(input_proto_test, output_proto_test_explicit);
}
TEST_F(FilterNetTest, TestFilterOutByStage) {
if (dropout_ratio != 0.5) {
layer_param.mutable_dropout_param()->set_dropout_ratio(dropout_ratio);
}
- Caffe::set_phase(Caffe::TRAIN);
DropoutLayer<Dtype> layer(layer_param);
+ layer_param.set_phase(TRAIN);
layer.SetUp(this->blob_bottom_vec_, this->blob_top_vec_);
layer.Forward(this->blob_bottom_vec_, this->blob_top_vec_);
// Now, check values
TYPED_TEST(NeuronLayerTest, TestDropoutTestPhase) {
typedef typename TypeParam::Dtype Dtype;
LayerParameter layer_param;
- Caffe::set_phase(Caffe::TEST);
+ layer_param.set_phase(TEST);
DropoutLayer<Dtype> layer(layer_param);
layer.SetUp(this->blob_bottom_vec_, this->blob_top_vec_);
layer.Forward(this->blob_bottom_vec_, this->blob_top_vec_);
TYPED_TEST(NeuronLayerTest, TestDropoutGradient) {
typedef typename TypeParam::Dtype Dtype;
LayerParameter layer_param;
- Caffe::set_phase(Caffe::TRAIN);
+ layer_param.set_phase(TRAIN);
DropoutLayer<Dtype> layer(layer_param);
GradientChecker<Dtype> checker(1e-2, 1e-3);
checker.CheckGradientEltwise(&layer, this->blob_bottom_vec_,
TYPED_TEST(NeuronLayerTest, TestDropoutGradientTest) {
typedef typename TypeParam::Dtype Dtype;
LayerParameter layer_param;
- Caffe::set_phase(Caffe::TEST);
+ layer_param.set_phase(TEST);
DropoutLayer<Dtype> layer(layer_param);
GradientChecker<Dtype> checker(1e-2, 1e-3);
checker.CheckGradientEltwise(&layer, this->blob_bottom_vec_,
TYPED_TEST(StochasticPoolingLayerTest, TestStochasticGPU) {
Caffe::set_mode(Caffe::GPU);
- Caffe::set_phase(Caffe::TRAIN);
LayerParameter layer_param;
+ layer_param.set_phase(TRAIN);
PoolingParameter* pooling_param = layer_param.mutable_pooling_param();
pooling_param->set_kernel_size(3);
pooling_param->set_stride(2);
TYPED_TEST(StochasticPoolingLayerTest, TestStochasticGPUTestPhase) {
Caffe::set_mode(Caffe::GPU);
- Caffe::set_phase(Caffe::TEST);
LayerParameter layer_param;
+ layer_param.set_phase(TEST);
PoolingParameter* pooling_param = layer_param.mutable_pooling_param();
pooling_param->set_kernel_size(3);
pooling_param->set_stride(2);
TYPED_TEST(StochasticPoolingLayerTest, TestGradientGPU) {
Caffe::set_mode(Caffe::GPU);
- Caffe::set_phase(Caffe::TRAIN);
LayerParameter layer_param;
+ layer_param.set_phase(TRAIN);
PoolingParameter* pooling_param = layer_param.mutable_pooling_param();
pooling_param->set_kernel_size(3);
pooling_param->set_stride(2);