Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add memory data layer to pass data directly into the network #196

Closed
wants to merge 6 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 17 additions & 6 deletions examples/lenet/lenet.prototxt
Original file line number Diff line number Diff line change
@@ -1,10 +1,21 @@
name: "LeNet"
input: "data"
input_dim: 64
input_dim: 1
input_dim: 28
input_dim: 28
# N.B. input should be 0/1 = mnist raw data scaled by 0.00390625
# The memory data does not process the input data
# N.B. input should be between [0, 1]
# i.e. raw data pixels scaled by 0.00390625 (1/255)
# max batch size is determined by the num field of bottom blobs
# passed in the MemoryDataLayer::SetUp
layers {
layer {
name: "data"
type: "memory_data"
datum_dims: {
channels: 1
height: 28
width: 28
}
}
top: "data"
}
layers {
layer {
name: "conv1"
Expand Down
21 changes: 20 additions & 1 deletion include/caffe/vision_layers.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -378,7 +378,6 @@ class DataLayer : public Layer<Dtype> {
Blob<Dtype> data_mean_;
};


template <typename Dtype>
class HDF5DataLayer : public Layer<Dtype> {
public:
Expand All @@ -405,6 +404,26 @@ class HDF5DataLayer : public Layer<Dtype> {
hsize_t current_row;
};

template <typename Dtype>
class MemoryDataLayer : public Layer<Dtype> {
public:
explicit MemoryDataLayer(const LayerParameter& param);
virtual ~MemoryDataLayer() {}
virtual void SetUp(const vector<Blob<Dtype>*>& bottom,
vector<Blob<Dtype>*>* top);

protected:
virtual void Forward_cpu(const vector<Blob<Dtype>*>& bottom,
vector<Blob<Dtype>*>* top);
virtual void Forward_gpu(const vector<Blob<Dtype>*>& bottom,
vector<Blob<Dtype>*>* top);
virtual Dtype Backward_cpu(const vector<Blob<Dtype>*>& top,
const bool propagate_down, vector<Blob<Dtype>*>* bottom);
virtual Dtype Backward_gpu(const vector<Blob<Dtype>*>& top,
const bool propagate_down, vector<Blob<Dtype>*>* bottom);
vector<DatumDimensions> datum_dims_;
size_t num_data_blobs_;
};

template <typename Dtype>
class SoftmaxLayer : public Layer<Dtype> {
Expand Down
19 changes: 14 additions & 5 deletions models/imagenet.prototxt
Original file line number Diff line number Diff line change
@@ -1,9 +1,18 @@
name: "CaffeNet"
input: "data"
input_dim: 10
input_dim: 3
input_dim: 227
input_dim: 227
# max batch size is determined by the num field of bottom blobs
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you remove the input part of the prototxt then you would need to change the python and matlab wrappers, otherwise they will not work

# passed in the MemoryDataLayer::SetUp
layers {
layer {
name: "data"
type: "memory_data"
datum_dims: {
channels: 3
height: 227
width: 227
}
}
top: "data"
}
layers {
layer {
name: "conv1"
Expand Down
2 changes: 2 additions & 0 deletions src/caffe/layer_factory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ Layer<Dtype>* GetLayer(const LayerParameter& param) {
return new InnerProductLayer<Dtype>(param);
} else if (type == "lrn") {
return new LRNLayer<Dtype>(param);
} else if (type == "memory_data") {
return new MemoryDataLayer<Dtype>(param);
} else if (type == "pool") {
return new PoolingLayer<Dtype>(param);
} else if (type == "relu") {
Expand Down
69 changes: 69 additions & 0 deletions src/caffe/layers/memory_data_layer.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
// Copyright 2014 kloudkl@github

#include <vector>

#include "caffe/layer.hpp"
#include "caffe/vision_layers.hpp"

using std::string;

namespace caffe {

template <typename Dtype>
MemoryDataLayer<Dtype>::MemoryDataLayer(const LayerParameter& param)
: Layer<Dtype>(param), num_data_blobs_(param.datum_dims_size()) {
for (int i = 0; i < param.datum_dims_size(); ++i) {
datum_dims_.push_back(param.datum_dims(i));
}
}

template <typename Dtype>
void MemoryDataLayer<Dtype>::SetUp(const vector<Blob<Dtype>*>& bottom,
vector<Blob<Dtype>*>* top) {
CHECK_EQ(bottom.size(), num_data_blobs_) <<
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kloudkl The idea behind of Data Layers is that they don't any bottom blobs, they just provide top blobs of data for the next layers.
Your current implementation only copy a bottom blob into the top blob, but which layers defines the bottom blob? which part of the code will be in charge of copying the data in there?

"MemoryDataLayer takes " << num_data_blobs_ << " blobs as input.";
CHECK_EQ(top->size(), num_data_blobs_) <<
"MemoryDataLayer takes " << num_data_blobs_ << " blobs as output.";
for (int i = 0; i < num_data_blobs_; ++i) {
CHECK_EQ(bottom[i]->channels(), datum_dims_[i].channels());
CHECK_EQ(bottom[i]->height(), datum_dims_[i].height());
CHECK_EQ(bottom[i]->width(), datum_dims_[i].width());
(*top)[i]->Reshape(bottom[i]->num(), datum_dims_[i].channels(),
datum_dims_[i].height(), datum_dims_[i].width());
}
}

template <typename Dtype>
void MemoryDataLayer<Dtype>::Forward_cpu(const vector<Blob<Dtype>*>& bottom,
vector<Blob<Dtype>*>* top) {
for (int i = 0; i < num_data_blobs_; ++i) {
memcpy((*top)[i]->mutable_cpu_data(), bottom[i]->cpu_data(),
sizeof(Dtype) * bottom[i]->count());
}
}

template <typename Dtype>
void MemoryDataLayer<Dtype>::Forward_gpu(const vector<Blob<Dtype>*>& bottom,
vector<Blob<Dtype>*>* top) {
for (int i = 0; i < num_data_blobs_; ++i) {
CUDA_CHECK(cudaMemcpy((*top)[i]->mutable_gpu_data(), bottom[i]->gpu_data(),
sizeof(Dtype) * bottom[i]->count(), cudaMemcpyDefault
/**< Default based unified virtual address space */));
}
}

template <typename Dtype>
Dtype MemoryDataLayer<Dtype>::Backward_cpu(const vector<Blob<Dtype>*>& top,
const bool propagate_down, vector<Blob<Dtype>*>* bottom) {
return Dtype(0.);
}

template <typename Dtype>
Dtype MemoryDataLayer<Dtype>::Backward_gpu(const vector<Blob<Dtype>*>& top,
const bool propagate_down, vector<Blob<Dtype>*>* bottom) {
return Dtype(0.);
}

INSTANTIATE_CLASS(MemoryDataLayer);

} // namespace caffe
9 changes: 9 additions & 0 deletions src/caffe/proto/caffe.proto
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@

package caffe;

message DatumDimensions {
optional int32 channels = 1;
optional int32 height = 2;
optional int32 width = 3;
}

message BlobProto {
optional int32 num = 1 [default = 0];
optional int32 channels = 2 [default = 0];
Expand Down Expand Up @@ -96,6 +102,9 @@ message LayerParameter {
// the other dimensions must be the same for all the bottom blobs
// By default it will concatenate blobs along channels dimension
optional uint32 concat_dim = 65 [ default = 1 ];

// Memory data layer specify the expected dimensions of input datum blobs
repeated DatumDimensions datum_dims = 10000;
}

message LayerConnection {
Expand Down
55 changes: 34 additions & 21 deletions src/caffe/test/test_data_layer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -83,31 +83,44 @@ TYPED_TEST(DataLayerTest, TestRead) {
EXPECT_EQ(this->blob_top_label_->height(), 1);
EXPECT_EQ(this->blob_top_label_->width(), 1);

// Go through the data 100 times
for (int iter = 0; iter < 100; ++iter) {
layer.Forward(this->blob_bottom_vec_, &this->blob_top_vec_);
for (int i = 0; i < 5; ++i) {
EXPECT_EQ(i, this->blob_top_label_->cpu_data()[i]);
}
for (int i = 0; i < 5; ++i) {
for (int j = 0; j < 24; ++j) {
EXPECT_EQ(i, this->blob_top_data_->cpu_data()[i * 24 + j])
<< "debug: i " << i << " j " << j;
Caffe::Brew modes[] = {Caffe::CPU, Caffe::GPU};
for (int n_mode = 0; n_mode < 2; ++n_mode) {
Caffe::set_mode(modes[n_mode]);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do you modify test_data_layer in this PR, that should be in a different PR

for (int iter = 0; iter < 100; ++iter) {
layer.Forward(this->blob_bottom_vec_, &this->blob_top_vec_);
for (int i = 0; i < 5; ++i) {
EXPECT_EQ(i, this->blob_top_label_->cpu_data()[i]);
}
for (int i = 0; i < 5; ++i) {
for (int j = 0; j < 24; ++j) {
EXPECT_EQ(i, this->blob_top_data_->cpu_data()[i * 24 + j])
<< "debug: i " << i << " j " << j;
}
}
}
}
}

// Same test, in GPU mode.
Caffe::set_mode(Caffe::GPU);
for (int iter = 0; iter < 100; ++iter) {
layer.Forward(this->blob_bottom_vec_, &this->blob_top_vec_);
for (int i = 0; i < 5; ++i) {
EXPECT_EQ(i, this->blob_top_label_->cpu_data()[i]);
}
for (int i = 0; i < 5; ++i) {
for (int j = 0; j < 24; ++j) {
EXPECT_EQ(i, this->blob_top_data_->cpu_data()[i * 24 + j])
<< "debug: i " << i << " j " << j;
TYPED_TEST(DataLayerTest, TestSetDataAndLabel) {
LayerParameter param;
param.set_batchsize(5);
param.set_source(this->filename);
DataLayer<TypeParam> layer(param);
layer.SetUp(this->blob_bottom_vec_, &this->blob_top_vec_);

Caffe::Brew modes[] = {Caffe::CPU, Caffe::GPU};
for (int n_mode = 0; n_mode < 2; ++n_mode) {
Caffe::set_mode(modes[n_mode]);
for (int iter = 0; iter < 100; ++iter) {
layer.Forward(this->blob_bottom_vec_, &this->blob_top_vec_);
for (int i = 0; i < 5; ++i) {
EXPECT_EQ(i, this->blob_top_label_->cpu_data()[i]);
}
for (int i = 0; i < 5; ++i) {
for (int j = 0; j < 24; ++j) {
EXPECT_EQ(i, this->blob_top_data_->cpu_data()[i * 24 + j])
<< "debug: i " << i << " j " << j;
}
}
}
}
Expand Down
Loading