Skip to content

Commit c1f7fe1

Browse files
committed
Add automatic upgrade for solver type
1 parent 0eea815 commit c1f7fe1

9 files changed

Lines changed: 206 additions & 5 deletions

File tree

include/caffe/caffe.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include "caffe/solver_factory.hpp"
1717
#include "caffe/util/benchmark.hpp"
1818
#include "caffe/util/io.hpp"
19+
#include "caffe/util/upgrade_proto.hpp"
1920
#include "caffe/vision_layers.hpp"
2021

2122
#endif // CAFFE_CAFFE_HPP_

include/caffe/util/upgrade_proto.hpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,18 @@ bool UpgradeV1LayerParameter(const V1LayerParameter& v1_layer_param,
5959

6060
const char* UpgradeV1LayerType(const V1LayerParameter_LayerType type);
6161

62+
// Return true iff the solver contains any old solver_type specified as enums
63+
bool SolverNeedsTypeUpgrade(const SolverParameter& solver_param);
64+
65+
bool UpgradeSolverType(SolverParameter* solver_param);
66+
67+
// Check for deprecations and upgrade the SolverParameter as needed.
68+
bool UpgradeSolverAsNeeded(const string& param_file, SolverParameter* param);
69+
70+
// Read parameters from a file into a SolverParameter proto message.
71+
void ReadSolverParamsFromTextFileOrDie(const string& param_file,
72+
SolverParameter* param);
73+
6274
} // namespace caffe
6375

6476
#endif // CAFFE_UTIL_UPGRADE_PROTO_H_

matlab/+caffe/private/caffe_.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,10 @@ static void get_solver(MEX_ARGS) {
188188
"Usage: caffe_('get_solver', solver_file)");
189189
char* solver_file = mxArrayToString(prhs[0]);
190190
mxCHECK_FILE_EXIST(solver_file);
191-
shared_ptr<Solver<float> > solver(new caffe::SGDSolver<float>(solver_file));
191+
SolverParameter solver_param;
192+
ReadSolverParamsFromTextFileOrDie(solver_file, &solver_param);
193+
shared_ptr<Solver<float> > solver(
194+
SolverRegistry<float>::CreateSolver(solver_param));
192195
solvers_.push_back(solver);
193196
plhs[0] = ptr_to_handle<Solver<float> >(solver.get());
194197
mxFree(solver_file);

python/caffe/_caffe.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -134,8 +134,8 @@ void Net_SetInputArrays(Net<Dtype>* net, bp::object data_obj,
134134

135135
Solver<Dtype>* GetSolverFromFile(const string& filename) {
136136
SolverParameter param;
137-
ReadProtoFromTextFileOrDie(filename, &param);
138-
return GetSolver<Dtype>(param);
137+
ReadSolverParamsFromTextFileOrDie(filename, &param);
138+
return SolverRegistry<Dtype>::CreateSolver(param);
139139
}
140140

141141
struct NdarrayConverterGenerator {

src/caffe/solver.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ Solver<Dtype>::Solver(const string& param_file, const Solver* root_solver)
3636
: net_(), callbacks_(), root_solver_(root_solver),
3737
requested_early_exit_(false) {
3838
SolverParameter param;
39-
ReadProtoFromTextFileOrDie(param_file, &param);
39+
ReadSolverParamsFromTextFileOrDie(param_file, &param);
4040
Init(param);
4141
}
4242

src/caffe/test/test_upgrade_proto.cpp

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2928,4 +2928,65 @@ TEST_F(NetUpgradeTest, TestUpgradeV1LayerType) {
29282928
}
29292929
}
29302930
#endif // USE_OPENCV
2931+
2932+
class SolverTypeUpgradeTest : public ::testing::Test {
2933+
protected:
2934+
void RunSolverTypeUpgradeTest(
2935+
const string& input_param_string, const string& output_param_string) {
2936+
// Test upgrading old solver_type field (enum) to new type field (string)
2937+
SolverParameter input_param;
2938+
CHECK(google::protobuf::TextFormat::ParseFromString(
2939+
input_param_string, &input_param));
2940+
SolverParameter expected_output_param;
2941+
CHECK(google::protobuf::TextFormat::ParseFromString(
2942+
output_param_string, &expected_output_param));
2943+
SolverParameter actual_output_param = input_param;
2944+
UpgradeSolverType(&actual_output_param);
2945+
EXPECT_EQ(expected_output_param.DebugString(),
2946+
actual_output_param.DebugString());
2947+
}
2948+
};
2949+
2950+
TEST_F(SolverTypeUpgradeTest, TestSimple) {
2951+
const char* old_type_vec[6] = { "SGD", "ADAGRAD", "NESTEROV", "RMSPROP",
2952+
"ADADELTA", "ADAM" };
2953+
const char* new_type_vec[6] = { "SGD", "AdaGrad", "Nesterov", "RMSProp",
2954+
"AdaDelta", "Adam" };
2955+
for (int i = 0; i < 6; ++i) {
2956+
const string& input_proto =
2957+
"net: 'examples/mnist/lenet_train_test.prototxt' "
2958+
"test_iter: 100 "
2959+
"test_interval: 500 "
2960+
"base_lr: 0.01 "
2961+
"momentum: 0.0 "
2962+
"weight_decay: 0.0005 "
2963+
"lr_policy: 'inv' "
2964+
"gamma: 0.0001 "
2965+
"power: 0.75 "
2966+
"display: 100 "
2967+
"max_iter: 10000 "
2968+
"snapshot: 5000 "
2969+
"snapshot_prefix: 'examples/mnist/lenet_rmsprop' "
2970+
"solver_mode: GPU "
2971+
"solver_type: " + std::string(old_type_vec[i]) + " ";
2972+
const string& expected_output_proto =
2973+
"net: 'examples/mnist/lenet_train_test.prototxt' "
2974+
"test_iter: 100 "
2975+
"test_interval: 500 "
2976+
"base_lr: 0.01 "
2977+
"momentum: 0.0 "
2978+
"weight_decay: 0.0005 "
2979+
"lr_policy: 'inv' "
2980+
"gamma: 0.0001 "
2981+
"power: 0.75 "
2982+
"display: 100 "
2983+
"max_iter: 10000 "
2984+
"snapshot: 5000 "
2985+
"snapshot_prefix: 'examples/mnist/lenet_rmsprop' "
2986+
"solver_mode: GPU "
2987+
"type: '" + std::string(new_type_vec[i]) + "' ";
2988+
this->RunSolverTypeUpgradeTest(input_proto, expected_output_proto);
2989+
}
2990+
}
2991+
29312992
} // NOLINT(readability/fn_size) // namespace caffe

src/caffe/util/upgrade_proto.cpp

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -937,4 +937,78 @@ const char* UpgradeV1LayerType(const V1LayerParameter_LayerType type) {
937937
}
938938
}
939939

940+
// Return true iff the solver contains any old solver_type specified as enums
941+
bool SolverNeedsTypeUpgrade(const SolverParameter& solver_param) {
942+
if (solver_param.has_solver_type()) {
943+
return true;
944+
}
945+
return false;
946+
}
947+
948+
bool UpgradeSolverType(SolverParameter* solver_param) {
949+
CHECK(!solver_param->has_solver_type() || !solver_param->has_type())
950+
<< "Failed to upgrade solver: old solver_type field (enum) and new type "
951+
<< "field (string) cannot be both specified in solver proto text.";
952+
if (solver_param->has_solver_type()) {
953+
string type;
954+
switch (solver_param->solver_type()) {
955+
case SolverParameter_SolverType_SGD:
956+
type = "SGD";
957+
break;
958+
case SolverParameter_SolverType_NESTEROV:
959+
type = "Nesterov";
960+
break;
961+
case SolverParameter_SolverType_ADAGRAD:
962+
type = "AdaGrad";
963+
break;
964+
case SolverParameter_SolverType_RMSPROP:
965+
type = "RMSProp";
966+
break;
967+
case SolverParameter_SolverType_ADADELTA:
968+
type = "AdaDelta";
969+
break;
970+
case SolverParameter_SolverType_ADAM:
971+
type = "Adam";
972+
break;
973+
default:
974+
LOG(FATAL) << "Unknown SolverParameter solver_type: " << type;
975+
}
976+
solver_param->set_type(type);
977+
solver_param->clear_solver_type();
978+
} else {
979+
LOG(ERROR) << "Warning: solver type already up to date. ";
980+
return false;
981+
}
982+
return true;
983+
}
984+
985+
// Check for deprecations and upgrade the SolverParameter as needed.
986+
bool UpgradeSolverAsNeeded(const string& param_file, SolverParameter* param) {
987+
bool success = true;
988+
// Try to upgrade old style solver_type enum fields into new string type
989+
if (SolverNeedsTypeUpgrade(*param)) {
990+
LOG(INFO) << "Attempting to upgrade input file specified using deprecated "
991+
<< "'solver_type' field (enum)': " << param_file;
992+
if (!UpgradeSolverType(param)) {
993+
success = false;
994+
LOG(ERROR) << "Warning: had one or more problems upgrading "
995+
<< "SolverType (see above).";
996+
} else {
997+
LOG(INFO) << "Successfully upgraded file specified using deprecated "
998+
<< "'solver_type' field (enum) to 'type' field (string).";
999+
LOG(WARNING) << "Note that future Caffe releases will only support "
1000+
<< "'type' field (string) for a solver's type.";
1001+
}
1002+
}
1003+
return success;
1004+
}
1005+
1006+
// Read parameters from a file into a SolverParameter proto message.
1007+
void ReadSolverParamsFromTextFileOrDie(const string& param_file,
1008+
SolverParameter* param) {
1009+
CHECK(ReadProtoFromTextFile(param_file, param))
1010+
<< "Failed to parse SolverParameter file: " << param_file;
1011+
UpgradeSolverAsNeeded(param_file, param);
1012+
}
1013+
9401014
} // namespace caffe

tools/caffe.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ int train() {
157157
"but not both.";
158158

159159
caffe::SolverParameter solver_param;
160-
caffe::ReadProtoFromTextFileOrDie(FLAGS_solver, &solver_param);
160+
caffe::ReadSolverParamsFromTextFileOrDie(FLAGS_solver, &solver_param);
161161

162162
// If the gpus flag is not provided, allow the mode and device to be set
163163
// in the solver prototxt.
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
// This is a script to upgrade old solver prototxts to the new format.
2+
// Usage:
3+
// upgrade_solver_proto_text old_solver_proto_file_in solver_proto_file_out
4+
5+
#include <cstring>
6+
#include <fstream> // NOLINT(readability/streams)
7+
#include <iostream> // NOLINT(readability/streams)
8+
#include <string>
9+
10+
#include "caffe/caffe.hpp"
11+
#include "caffe/util/io.hpp"
12+
#include "caffe/util/upgrade_proto.hpp"
13+
14+
using std::ofstream;
15+
16+
using namespace caffe; // NOLINT(build/namespaces)
17+
18+
int main(int argc, char** argv) {
19+
::google::InitGoogleLogging(argv[0]);
20+
if (argc != 3) {
21+
LOG(ERROR) << "Usage: upgrade_solver_proto_text "
22+
<< "old_solver_proto_file_in solver_proto_file_out";
23+
return 1;
24+
}
25+
26+
SolverParameter solver_param;
27+
string input_filename(argv[1]);
28+
if (!ReadProtoFromTextFile(input_filename, &solver_param)) {
29+
LOG(ERROR) << "Failed to parse input text file as SolverParameter: "
30+
<< input_filename;
31+
return 2;
32+
}
33+
bool need_upgrade = SolverNeedsTypeUpgrade(solver_param);
34+
bool success = true;
35+
if (need_upgrade) {
36+
success = UpgradeSolverAsNeeded(input_filename, &solver_param);
37+
if (!success) {
38+
LOG(ERROR) << "Encountered error(s) while upgrading prototxt; "
39+
<< "see details above.";
40+
}
41+
} else {
42+
LOG(ERROR) << "File already in latest proto format: " << input_filename;
43+
}
44+
45+
// Save new format prototxt.
46+
WriteProtoToTextFile(solver_param, argv[2]);
47+
48+
LOG(ERROR) << "Wrote upgraded SolverParameter text proto to " << argv[2];
49+
return !success;
50+
}

0 commit comments

Comments
 (0)