map<string, int> blob_name_to_idx;
set<string> available_blobs;
int num_layers = param.layers_size();
- CHECK_EQ(bottom.size(), param.bottom_size())
+ CHECK_EQ(bottom.size(), param.input_size())
<< "Incorrect bottom blob size.";
// set the input blobs
- for (int i = 0; i < param.bottom_size(); ++i) {
- const string& blob_name = param.bottom(i);
+ for (int i = 0; i < param.input_size(); ++i) {
+ const string& blob_name = param.input(i);
CHECK_GT(bottom[i]->count(), 0);
shared_ptr<Blob<Dtype> > blob_pointer(
new Blob<Dtype>(bottom[i]->num(), bottom[i]->channels(),
top_id_vecs_[i].push_back(blob_names_.size() - 1);
}
}
- LOG(INFO) << "Checking top blobs.";
- // In the end, check if all remaining available blobs are top blobs.
- for (int i = 0; i < param.top_size(); ++i) {
- const string& blob_name = param.top(i);
- if (blob_name_to_idx.find(blob_name) == blob_name_to_idx.end()) {
- LOG(FATAL) << "Unknown blob output " << blob_name;
- }
- net_output_blob_indices_.push_back(blob_name_to_idx[blob_name]);
- available_blobs.erase(blob_name);
- }
- if (!available_blobs.empty()) {
- LOG(WARNING) << "There are some internal blobs not used:";
- for (set<string>::iterator it = available_blobs.begin();
- it != available_blobs.end(); ++it) {
- LOG(WARNING) << " " << *it;
- }
+ // In the end, all remaining blobs are considered output blobs.
+ for (set<string>::iterator it = available_blobs.begin();
+ it != available_blobs.end(); ++it) {
+ LOG(ERROR) << "This network produces output " << *it;
+ net_output_blob_indices_.push_back(blob_name_to_idx[*it]);
+ net_output_blobs_.push_back(blobs_[blob_name_to_idx[*it]].get());
}
- LOG(INFO) << "Setting up the layers.";
+ LOG(ERROR) << "Setting up the layers.";
for (int i = 0; i < layers_.size(); ++i) {
LOG(INFO) << "Setting up " << layer_names_[i];
layers_[i]->SetUp(bottom_vecs_[i], &top_vecs_[i]);
}
}
- LOG(INFO) << "Network initialization done.";
+ LOG(ERROR) << "Network initialization done.";
}
template <typename Dtype>
-void Net<Dtype>::Forward(const vector<Blob<Dtype>*> & bottom,
- vector<Blob<Dtype>*>* top) {
+const vector<Blob<Dtype>*>& Net<Dtype>::Forward(
+ const vector<Blob<Dtype>*> & bottom) {
// Copy bottom to internal bottom
for (int i = 0; i < bottom.size(); ++i) {
blobs_[net_input_blob_indices_[i]]->CopyFrom(*bottom[i]);
for (int i = 0; i < layers_.size(); ++i) {
layers_[i]->Forward(bottom_vecs_[i], &top_vecs_[i]);
}
- // Copy internal top to top
- for (int i = 0; i < (*top).size(); ++i) {
- (*top)[i]->CopyFrom(*blobs_[net_output_blob_indices_[i]]);
- }
+ return net_output_blobs_;
}
template <typename Dtype>
param->set_name(name_);
// Add bottom and top
for (int i = 0; i < net_input_blob_indices_.size(); ++i) {
- param->add_bottom(blob_names_[net_input_blob_indices_[i]]);
- }
- for (int i = 0; i < net_output_blob_indices_.size(); ++i) {
- param->add_top(blob_names_[net_output_blob_indices_[i]]);
+ param->add_input(blob_names_[net_input_blob_indices_[i]]);
}
for (int i = 0; i < layers_.size(); ++i) {
LayerConnection* layer_connection = param->add_layers();
Net(const NetParameter& param,
const vector<Blob<Dtype>* >& bottom);
~Net() {}
- void Forward(const vector<Blob<Dtype>* > & bottom,
- vector<Blob<Dtype>*>* top);
+ const vector<Blob<Dtype>*>& Forward(const vector<Blob<Dtype>* > & bottom);
// The network backward should take no input and output, since it solely
// computes the gradient w.r.t the parameters, and the data has already
// been provided during the forward pass.
Dtype Backward();
- Dtype ForwardBackWard(const vector<Blob<Dtype>* > & bottom,
- vector<Blob<Dtype>*>* top) {
- Forward(bottom, top);
+ Dtype ForwardBackWard(const vector<Blob<Dtype>* > & bottom) {
+ Forward(bottom);
return Backward();
}
// layers.
vector<shared_ptr<Blob<Dtype> > > blobs_;
vector<string> blob_names_;
- // bottom_vecs stores the vectors containing the input for each layer, except
- // for the first layer whose bottom vec is provided by the network's input.
+ // bottom_vecs stores the vectors containing the input for each layer
vector<vector<Blob<Dtype>*> > bottom_vecs_;
vector<vector<int> > bottom_id_vecs_;
- // top_vecs stores the vectors containing the output for each layer, except
- // for the last layer (likewise)
+ // top_vecs stores the vectors containing the output for each layer
vector<vector<Blob<Dtype>*> > top_vecs_;
vector<vector<int> > top_id_vecs_;
// blob indices for the input and the output of the net.
vector<int> net_input_blob_indices_;
vector<int> net_output_blob_indices_;
+ vector<Blob<Dtype>*> net_output_blobs_;
string name_;
// The parameters in the network.
vector<shared_ptr<Blob<Dtype> > > params_;
// For a network that is trained by the solver, no bottom or top vecs
// should be given, and we will just provide dummy vecs.
vector<Blob<Dtype>*> bottom_vec;
- vector<Blob<Dtype>*> top_vec;
while (iter_++ < param_.max_iter()) {
- Dtype loss = net_->ForwardBackWard(bottom_vec, &top_vec);
+ Dtype loss = net_->ForwardBackWard(bottom_vec);
ComputeUpdateValue();
net->Update();
message NetParameter {
optional string name = 1; // consider giving the network a name
repeated LayerConnection layers = 2; // a bunch of layers.
- repeated string bottom = 3; // The input to the network
- repeated string top = 4; // The output of the network.
+ repeated string input = 3; // The input to the network
}
message SolverParameter {
name: "LeNet"
-bottom: "data"
-bottom: "label"
+input: "data"
+input: "label"
layers {
layer {
name: "conv1"
--- /dev/null
+name: "SimpleConv"
+input: "data"
+layers {
+ layer {
+ name: "conv"
+ type: "conv"
+ num_output: 1
+ kernelsize: 5
+ stride: 1
+ weight_filler {
+ type: "constant"
+ value: 0.01333333
+ }
+ biasterm: false
+ }
+ bottom: "data"
+ top: "smooth"
+}
namespace caffe {
const char* kLENET = "name: \"LeNet\"\n"
-"bottom: \"data\"\n"
-"bottom: \"label\"\n"
+"input: \"data\"\n"
+"input: \"label\"\n"
"layers {\n"
" layer {\n"
" name: \"conv1\"\n"
lenet_string, &net_param));
// check if things are right
EXPECT_EQ(net_param.layers_size(), 9);
- EXPECT_EQ(net_param.bottom_size(), 2);
- EXPECT_EQ(net_param.top_size(), 0);
+ EXPECT_EQ(net_param.input_size(), 2);
// Now, initialize a network using the parameter
shared_ptr<Blob<TypeParam> > data(new Blob<TypeParam>(10, 1, 28, 28));
// Run the network without training.
vector<Blob<TypeParam>*> top_vec;
LOG(ERROR) << "Performing Forward";
- caffe_net.Forward(bottom_vec, &top_vec);
+ caffe_net.Forward(bottom_vec);
LOG(ERROR) << "Performing Backward";
LOG(ERROR) << caffe_net.Backward();
}
--- /dev/null
+// Copyright 2013 Yangqing Jia
+
+#include <gtest/gtest.h>
+
+#include <cstring>
+
+#include "caffe/common.hpp"
+#include "caffe/blob.hpp"
+#include "caffe/net.hpp"
+#include "caffe/proto/caffe.pb.h"
+#include "caffe/util/io.hpp"
+
+#include "caffe/test/test_caffe_main.hpp"
+
+namespace caffe {
+
+template <typename Dtype>
+class NetProtoTest : public ::testing::Test {};
+
+typedef ::testing::Types<float> Dtypes;
+TYPED_TEST_CASE(NetProtoTest, Dtypes);
+
+TYPED_TEST(NetProtoTest, TestLoadFromText) {
+ NetParameter net_param;
+ ReadProtoFromTextFile("caffe/test/data/simple_conv.prototxt", &net_param);
+ Blob<TypeParam> lena_image;
+ ReadImageToBlob<TypeParam>(string("caffe/test/data/lena_256.jpg"), &lena_image);
+ vector<Blob<TypeParam>*> bottom_vec;
+ bottom_vec.push_back(&lena_image);
+
+ for (int i = 0; i < lena_image.count(); ++i) {
+ EXPECT_GE(lena_image.cpu_data()[i], 0);
+ EXPECT_LE(lena_image.cpu_data()[i], 1);
+ }
+
+ // Initialize the network, and then does smoothing
+ Net<TypeParam> caffe_net(net_param, bottom_vec);
+ const vector<Blob<TypeParam>*>& output = caffe_net.Forward(bottom_vec);
+ LOG(ERROR) << "Forward Done.";
+ EXPECT_EQ(output[0]->num(), 1);
+ EXPECT_EQ(output[0]->channels(), 1);
+ EXPECT_EQ(output[0]->height(), 252);
+ EXPECT_EQ(output[0]->width(), 252);
+ for (int i = 0; i < output[0]->count(); ++i) {
+ EXPECT_GE(output[0]->cpu_data()[i], 0);
+ EXPECT_LE(output[0]->cpu_data()[i], 1);
+ }
+ WriteBlobToImage<TypeParam>(string("lena_smoothed.png"), *output[0]);
+}
+
+
+} // namespace caffe
CHECK_GT(proto.height(), 0);
CHECK_GT(proto.width(), 0);
Mat cv_img(proto.height(), proto.width(), CV_8UC3);
- for (int c = 0; c < 3; ++c) {
- int source_c = max(c, proto.channels() - 1);
- for (int h = 0; h < cv_img.rows; ++h) {
- for (int w = 0; w < cv_img.cols; ++w) {
- cv_img.at<Vec3b>(h, w)[c] =
- uint8_t(proto.data((source_c * cv_img.rows + h) * cv_img.cols + w)
- * 255.);
+ if (proto.channels() == 1) {
+ for (int c = 0; c < 3; ++c) {
+ for (int h = 0; h < cv_img.rows; ++h) {
+ for (int w = 0; w < cv_img.cols; ++w) {
+ cv_img.at<Vec3b>(h, w)[c] =
+ uint8_t(proto.data(h * cv_img.cols + w) * 255.);
+ }
+ }
+ }
+ } else {
+ for (int c = 0; c < 3; ++c) {
+ for (int h = 0; h < cv_img.rows; ++h) {
+ for (int w = 0; w < cv_img.cols; ++w) {
+ cv_img.at<Vec3b>(h, w)[c] =
+ uint8_t(proto.data((c * cv_img.rows + h) * cv_img.cols + w)
+ * 255.);
+ }
}
}
}
#include <string>
+#include "caffe/blob.hpp"
#include "caffe/proto/caffe.pb.h"
using std::string;
namespace caffe {
void ReadImageToProto(const string& filename, BlobProto* proto);
+
+template <typename Dtype>
+inline void ReadImageToBlob(const string& filename, Blob<Dtype>* blob) {
+ BlobProto proto;
+ ReadImageToProto(filename, &proto);
+ blob->FromProto(proto);
+}
+
void WriteProtoToImage(const string& filename, const BlobProto& proto);
+template <typename Dtype>
+inline void WriteBlobToImage(const string& filename, const Blob<Dtype>& blob) {
+ BlobProto proto;
+ blob.ToProto(&proto);
+ WriteProtoToImage(filename, proto);
+}
+
void ReadProtoFromTextFile(const char* filename,
::google::protobuf::Message* proto);
inline void ReadProtoFromTextFile(const string& filename,