From a916ef49fad7b7a3c5faee7df46af3d327aecee9 Mon Sep 17 00:00:00 2001 From: Yangqing Jia Date: Fri, 25 Jul 2014 09:02:37 -0700 Subject: [PATCH] Adding new caffe binary that does everything in one binary; deprecating device_query, finetune_net, net_speed_benchmark, train_net --- tools/caffe.cpp | 176 ++++++++++++++++++++++++++++++++++++++++++ tools/device_query.cpp | 17 +--- tools/finetune_net.cpp | 26 +------ tools/net_speed_benchmark.cpp | 100 +----------------------- tools/train_net.cpp | 30 +------ 5 files changed, 184 insertions(+), 165 deletions(-) create mode 100644 tools/caffe.cpp diff --git a/tools/caffe.cpp b/tools/caffe.cpp new file mode 100644 index 0000000..4835248 --- /dev/null +++ b/tools/caffe.cpp @@ -0,0 +1,176 @@ +#include +#include + +#include +#include + +#include "caffe/caffe.hpp" + +using caffe::Blob; +using caffe::Caffe; +using caffe::Net; +using caffe::Layer; +using caffe::shared_ptr; +using caffe::Timer; +using caffe::string; +using std::vector; + + +// Used in device query +DEFINE_int32(device_id, 0, + "[devicequery,speedtest] The device id to use."); +// Used in training +DEFINE_string(solver_proto_file, "", + "[train] The protobuf containing the solver definition."); +DEFINE_string(net_proto_file, "", + "[speedtest] The net proto file to use."); +DEFINE_string(resume_point_file, "", + "[train] (optional) The snapshot from which to resume training."); +DEFINE_string(pretrained_net_file, "", + "[train] (optional) A pretrained network to run finetune from. " + "Cannot be set simultaneously with resume_point_file."); +DEFINE_int32(run_iterations, 50, + "[speedtest] The number of iterations to run."); +DEFINE_bool(speedtest_with_gpu, false, + "[speedtest] Test the model with GPU."); + +// A simple registry for caffe commands. +typedef int (*BrewFunction)(); +typedef std::map BrewMap; +BrewMap g_brew_map; + +#define RegisterBrewFunction(func) \ + namespace { \ + class __Registerer_##func { \ + public: \ + __Registerer_##func() { \ + g_brew_map[#func] = &func; \ + } \ + }; \ + __Registerer_##func g_registerer_##func; \ + } + +static BrewFunction GetBrewFunction(const std::string& name) { + if (g_brew_map.count(name)) { + return g_brew_map[name]; + } else { + LOG(ERROR) << "Available caffe actions:"; + for (BrewMap::iterator it = g_brew_map.begin(); + it != g_brew_map.end(); ++it) { + LOG(ERROR) << "\t" << it->first; + } + LOG(FATAL) << "Unknown action: " << name; + return NULL; // not reachable, just to suppress old compiler warnings. + } +} + +// caffe actions that could be called in the form +// caffe.bin action +// To do so, define actions as "int action()" functions, and register it with +// RegisterBrewFunction(action); + +int devicequery() { + LOG(INFO) << "Querying device_id = " << FLAGS_device_id; + caffe::Caffe::SetDevice(FLAGS_device_id); + caffe::Caffe::DeviceQuery(); + return 0; +} +RegisterBrewFunction(devicequery); + +int train() { + CHECK_GT(FLAGS_solver_proto_file.size(), 0); + + caffe::SolverParameter solver_param; + caffe::ReadProtoFromTextFileOrDie(FLAGS_solver_proto_file, &solver_param); + + LOG(INFO) << "Starting Optimization"; + caffe::SGDSolver solver(solver_param); + if (FLAGS_resume_point_file.size()) { + LOG(INFO) << "Resuming from " << FLAGS_resume_point_file; + solver.Solve(FLAGS_resume_point_file); + } else if (FLAGS_pretrained_net_file.size()) { + LOG(INFO) << "Finetuning from " << FLAGS_pretrained_net_file; + solver.net()->CopyTrainedLayersFrom(FLAGS_pretrained_net_file); + solver.Solve(); + } else { + solver.Solve(); + } + LOG(INFO) << "Optimization Done."; + return 0; +} +RegisterBrewFunction(train); + +int speedtest() { + // Set device id and mode + if (FLAGS_speedtest_with_gpu) { + LOG(INFO) << "Use GPU with device id " << FLAGS_device_id; + Caffe::SetDevice(FLAGS_device_id); + Caffe::set_mode(Caffe::GPU); + } else { + LOG(INFO) << "Use CPU."; + Caffe::set_mode(Caffe::CPU); + } + // Instantiate the caffe net. + Caffe::set_phase(Caffe::TRAIN); + Net caffe_net(FLAGS_net_proto_file); + + // Do a clean forward and backward pass, so that memory allocation are done + // and future iterations will be more stable. + LOG(INFO) << "Performing Forward"; + // Note that for the speed benchmark, we will assume that the network does + // not take any input blobs. + float initial_loss; + caffe_net.Forward(vector*>(), &initial_loss); + LOG(INFO) << "Initial loss: " << initial_loss; + LOG(INFO) << "Performing Backward"; + caffe_net.Backward(); + + const vector > >& layers = caffe_net.layers(); + vector*> >& bottom_vecs = caffe_net.bottom_vecs(); + vector*> >& top_vecs = caffe_net.top_vecs(); + const vector >& bottom_need_backward = + caffe_net.bottom_need_backward(); + LOG(INFO) << "*** Benchmark begins ***"; + LOG(INFO) << "Testing for " << FLAGS_run_iterations << " iterations."; + Timer total_timer; + total_timer.Start(); + Timer forward_timer; + forward_timer.Start(); + Timer timer; + for (int i = 0; i < layers.size(); ++i) { + const string& layername = layers[i]->layer_param().name(); + timer.Start(); + for (int j = 0; j < FLAGS_run_iterations; ++j) { + layers[i]->Forward(bottom_vecs[i], &top_vecs[i]); + } + LOG(INFO) << layername << "\tforward: " << timer.MilliSeconds() << + " milli seconds."; + } + LOG(INFO) << "Forward pass: " << forward_timer.MilliSeconds() << + " milli seconds."; + Timer backward_timer; + backward_timer.Start(); + for (int i = layers.size() - 1; i >= 0; --i) { + const string& layername = layers[i]->layer_param().name(); + timer.Start(); + for (int j = 0; j < FLAGS_run_iterations; ++j) { + layers[i]->Backward(top_vecs[i], bottom_need_backward[i], + &bottom_vecs[i]); + } + LOG(INFO) << layername << "\tbackward: " + << timer.MilliSeconds() << " milli seconds."; + } + LOG(INFO) << "Backward pass: " << backward_timer.MilliSeconds() << + " milli seconds."; + LOG(INFO) << "Total Time: " << total_timer.MilliSeconds() << + " milli seconds."; + LOG(INFO) << "*** Benchmark ends ***"; + return 0; +} +RegisterBrewFunction(speedtest); + +int main(int argc, char** argv) { + caffe::GlobalInit(&argc, &argv); + CHECK_EQ(argc, 2); + return GetBrewFunction(std::string(argv[1]))(); +} diff --git a/tools/device_query.cpp b/tools/device_query.cpp index 5040b8e..224a314 100644 --- a/tools/device_query.cpp +++ b/tools/device_query.cpp @@ -1,23 +1,8 @@ // Copyright 2014 BVLC and contributors. - #include "caffe/common.hpp" -#include "caffe/net.hpp" - - -using namespace caffe; // NOLINT(build/namespaces) int main(int argc, char** argv) { - if (argc > 2) { - LOG(ERROR) << "device_query [device_id=0]"; - return 1; - } - if (argc == 2) { - LOG(INFO) << "Querying device_id=" << argv[1]; - Caffe::SetDevice(atoi(argv[1])); - Caffe::DeviceQuery(); - } else { - Caffe::DeviceQuery(); - } + LOG(ERROR) << "Deprecated. Use caffe.bin devicequery [--device_id=0] instead."; return 0; } diff --git a/tools/finetune_net.cpp b/tools/finetune_net.cpp index 4d80be9..dff9721 100644 --- a/tools/finetune_net.cpp +++ b/tools/finetune_net.cpp @@ -1,31 +1,9 @@ // Copyright 2014 BVLC and contributors. -// -// This is a simple script that allows one to quickly finetune a network. -// Usage: -// finetune_net solver_proto_file pretrained_net - -#include #include "caffe/caffe.hpp" -using namespace caffe; // NOLINT(build/namespaces) - int main(int argc, char** argv) { - ::google::InitGoogleLogging(argv[0]); - if (argc != 3) { - LOG(ERROR) << "Usage: finetune_net solver_proto_file pretrained_net"; - return 1; - } - - SolverParameter solver_param; - ReadProtoFromTextFileOrDie(argv[1], &solver_param); - - LOG(INFO) << "Starting Optimization"; - SGDSolver solver(solver_param); - LOG(INFO) << "Loading from " << argv[2]; - solver.net()->CopyTrainedLayersFrom(string(argv[2])); - solver.Solve(); - LOG(INFO) << "Optimization Done."; - + LOG(ERROR) << "Deprecated. Use caffe.bin train --solver_proto_file=... " + "[pretrained_net_file=...] instead."; return 0; } diff --git a/tools/net_speed_benchmark.cpp b/tools/net_speed_benchmark.cpp index bdec391..9e6bb4c 100644 --- a/tools/net_speed_benchmark.cpp +++ b/tools/net_speed_benchmark.cpp @@ -1,103 +1,9 @@ // Copyright 2014 BVLC and contributors. -#include -#include - -#include -#include -#include -#include - -#include "caffe/blob.hpp" -#include "caffe/common.hpp" -#include "caffe/net.hpp" -#include "caffe/filler.hpp" -#include "caffe/proto/caffe.pb.h" -#include "caffe/util/benchmark.hpp" -#include "caffe/util/io.hpp" -#include "caffe/solver.hpp" - -using namespace caffe; // NOLINT(build/namespaces) +#include "caffe/caffe.hpp" int main(int argc, char** argv) { - int total_iter = 50; - if (argc < 2 || argc > 5) { - LOG(ERROR) << "net_speed_benchmark net_proto [iterations=50]" - " [CPU/GPU] [Device_id=0]"; - return 1; - } - - if (argc >=3) { - total_iter = atoi(argv[2]); - } - - LOG(ERROR) << "Testing for " << total_iter << "Iterations."; - - if (argc >= 4 && strcmp(argv[3], "GPU") == 0) { - LOG(ERROR) << "Using GPU"; - uint device_id = 0; - if (argc >= 5 && strcmp(argv[3], "GPU") == 0) { - device_id = atoi(argv[4]); - } - LOG(ERROR) << "Using Device_id=" << device_id; - Caffe::SetDevice(device_id); - Caffe::set_mode(Caffe::GPU); - } else { - LOG(ERROR) << "Using CPU"; - Caffe::set_mode(Caffe::CPU); - } - - Caffe::set_phase(Caffe::TRAIN); - Net caffe_net(argv[1]); - - // Run the network without training. - LOG(ERROR) << "Performing Forward"; - // Note that for the speed benchmark, we will assume that the network does - // not take any input blobs. - float initial_loss; - caffe_net.Forward(vector*>(), &initial_loss); - LOG(ERROR) << "Initial loss: " << initial_loss; - LOG(ERROR) << "Performing Backward"; - caffe_net.Backward(); - - const vector > >& layers = caffe_net.layers(); - vector*> >& bottom_vecs = caffe_net.bottom_vecs(); - vector*> >& top_vecs = caffe_net.top_vecs(); - const vector >& bottom_need_backward = - caffe_net.bottom_need_backward(); - LOG(ERROR) << "*** Benchmark begins ***"; - Timer total_timer; - total_timer.Start(); - Timer forward_timer; - forward_timer.Start(); - Timer timer; - for (int i = 0; i < layers.size(); ++i) { - const string& layername = layers[i]->layer_param().name(); - timer.Start(); - for (int j = 0; j < total_iter; ++j) { - layers[i]->Forward(bottom_vecs[i], &top_vecs[i]); - } - LOG(ERROR) << layername << "\tforward: " << timer.MilliSeconds() << - " milli seconds."; - } - LOG(ERROR) << "Forward pass: " << forward_timer.MilliSeconds() << - " milli seconds."; - Timer backward_timer; - backward_timer.Start(); - for (int i = layers.size() - 1; i >= 0; --i) { - const string& layername = layers[i]->layer_param().name(); - timer.Start(); - for (int j = 0; j < total_iter; ++j) { - layers[i]->Backward(top_vecs[i], bottom_need_backward[i], - &bottom_vecs[i]); - } - LOG(ERROR) << layername << "\tbackward: " - << timer.MilliSeconds() << " milli seconds."; - } - LOG(ERROR) << "Backward pass: " << backward_timer.MilliSeconds() << - " milli seconds."; - LOG(ERROR) << "Total Time: " << total_timer.MilliSeconds() << - " milli seconds."; - LOG(ERROR) << "*** Benchmark ends ***"; + LOG(ERROR) << "Deprecated. Use caffe.bin speedtest --net_proto_file=... " + "[--run_iterations=50] [--speedtest_with_gpu] [--device_id=0]"; return 0; } diff --git a/tools/train_net.cpp b/tools/train_net.cpp index 41a3324..568260c 100644 --- a/tools/train_net.cpp +++ b/tools/train_net.cpp @@ -1,35 +1,9 @@ // Copyright 2014 BVLC and contributors. -// -// This is a simple script that allows one to quickly train a network whose -// parameters are specified by text format protocol buffers. -// Usage: -// train_net net_proto_file solver_proto_file [resume_point_file] - -#include #include "caffe/caffe.hpp" -using namespace caffe; // NOLINT(build/namespaces) - int main(int argc, char** argv) { - ::google::InitGoogleLogging(argv[0]); - if (argc < 2 || argc > 3) { - LOG(ERROR) << "Usage: train_net solver_proto_file [resume_point_file]"; - return 1; - } - - SolverParameter solver_param; - ReadProtoFromTextFileOrDie(argv[1], &solver_param); - - LOG(INFO) << "Starting Optimization"; - SGDSolver solver(solver_param); - if (argc == 3) { - LOG(INFO) << "Resuming from " << argv[2]; - solver.Solve(argv[2]); - } else { - solver.Solve(); - } - LOG(INFO) << "Optimization Done."; - + LOG(ERROR) << "Deprecated. Use caffe.bin train --solver_proto_file=... " + "[resume_point_file=...] instead."; return 0; } -- 2.7.4