1 #include "caffe2/core/net.h" 4 #include <unordered_map> 5 #include <unordered_set> 7 #include "caffe2/core/operator.h" 8 #include "caffe2/core/static_tracepoint.h" 9 #include "caffe2/core/timer.h" 10 #include "caffe2/proto/caffe2.pb.h" 11 #include "caffe2/utils/proto_utils.h" 15 CAFFE_DEFINE_REGISTRY(NetRegistry, NetBase,
const NetDef&, Workspace*);
17 NetBase::NetBase(
const NetDef& def, Workspace* )
18 : external_input_(def.external_input().begin(), def.external_input().end()),
20 def.external_output().begin(),
21 def.external_output().end()),
24 std::set<string> known_blobs(
25 external_input_.begin(), external_input_.end());
26 std::set<string> remaining_output(
27 external_output_.begin(), external_output_.end());
28 for (
const auto& blob : known_blobs) {
29 remaining_output.erase(blob);
31 for (
const OperatorDef& op : def.op()) {
32 for (
const string& in : op.input()) {
33 if (!known_blobs.count(in)) {
34 if (external_input_.size()) {
38 ": Source for input ",
40 " is unknown for net ",
43 ProtoDebugString(op));
47 VLOG(1) <<
"op " << op.type() <<
": input " << in <<
" is unknown.";
51 for (
const string& out : op.output()) {
52 known_blobs.insert(out);
53 remaining_output.erase(out);
58 remaining_output.size() == 0,
59 "Some of the blobs are declared as output but never produced by the " 62 ", the first one is ",
63 *remaining_output.begin());
69 if (!net_def.has_type()) {
70 return make_unique<SimpleNet>(net_def, ws);
72 return NetRegistry()->Create(net_def.type(), net_def, ws);
75 SimpleNet::SimpleNet(
const NetDef& net_def,
Workspace* ws)
77 VLOG(1) <<
"Constructing SimpleNet " << net_def.name();
78 bool net_def_has_device_option = net_def.has_device_option();
80 for (
const OperatorDef& operator_def : net_def.op()) {
81 VLOG(1) <<
"Creating operator " << operator_def.name()
82 <<
":" << operator_def.type();
83 if (!operator_def.has_device_option() && net_def_has_device_option) {
87 OperatorDef temp_def(operator_def);
88 temp_def.mutable_device_option()->CopyFrom(net_def.device_option());
89 operators_.emplace_back(CreateOperator(temp_def, ws));
91 operators_.emplace_back(CreateOperator(operator_def, ws));
96 bool SimpleNet::Run() {
97 VLOG(1) <<
"Running net " << name_;
98 for (
auto& op : operators_) {
99 VLOG(1) <<
"Running operator " << op->def().name()
100 <<
"(" << op->def().type() <<
").";
102 LOG(ERROR) <<
"Operator failed: " 103 << ProtoDebugString(op->def());
110 bool SimpleNet::RunAsync() {
111 VLOG(1) <<
"Running net " << name_;
112 for (
auto& op : operators_) {
113 VLOG(1) <<
"Running operator " << op->def().name()
114 <<
"(" << op->def().type() <<
").";
115 if (!op->RunAsync()) {
116 LOG(ERROR) <<
"Operator failed: " 117 << ProtoDebugString(op->def());
125 template <
typename A,
typename B>
126 bool PairLargerThan(
const std::pair<A, B>& x,
const std::pair<A, B>& y) {
127 return x.second > y.second;
132 const int warmup_runs,
134 const bool run_individual) {
135 LOG(INFO) <<
"Starting benchmark.";
136 LOG(INFO) <<
"Running warmup runs.";
139 "Number of warm up runs should be non negative, provided ",
142 for (
int i = 0; i < warmup_runs; ++i) {
143 CAFFE_ENFORCE(Run(),
"Warmup run ", i,
" has failed.");
146 LOG(INFO) <<
"Main runs.";
149 "Number of main runs should be non negative, provided ",
153 for (
int i = 0; i < main_runs; ++i) {
154 CAFFE_ENFORCE(Run(),
"Main run ", i,
" has failed.");
157 LOG(INFO) <<
"Main run finished. Milliseconds per iter: " 158 << millis / main_runs
159 <<
". Iters per second: " << 1000.0 * main_runs / millis;
161 vector<float> time_per_op(operators_.size(), 0);
162 CaffeMap<string, float> time_per_op_type;
163 if (run_individual) {
164 for (
int i = 0; i < main_runs; ++i) {
166 for (
auto& op : operators_) {
167 const string& op_type = op->def().type();
177 time_per_op[idx] += spent;
178 time_per_op_type[op_type] += spent;
184 for (
auto& op : operators_) {
185 const string& op_type = op->def().type();
186 const string& print_name =
187 (op->def().name().size()
189 : (op->def().output_size() ? op->def().output(0) :
"NO_OUTPUT"));
190 LOG(INFO) <<
"Operator #" << idx <<
" (" << print_name <<
", " << op_type
191 <<
") " << time_per_op[idx] / main_runs <<
" ms/iter";
194 LOG(INFO) <<
"Time per operator type:";
196 std::vector<std::pair<string, float>> time_per_op_type_vec(
197 time_per_op_type.begin(), time_per_op_type.end());
199 time_per_op_type_vec.begin(),
200 time_per_op_type_vec.end(),
201 PairLargerThan<string, float>);
202 for (
const auto& item : time_per_op_type_vec) {
203 LOG(INFO) << std::setw(15) << std::setfill(
' ') << item.second / main_runs
204 <<
" " << item.first;
208 for (
int i = 0; i < time_per_op.size(); ++i) {
209 time_per_op[i] /= main_runs;
211 time_per_op.insert(time_per_op.begin(), millis / main_runs);
Workspace is a class that holds all the related objects created during runtime: (1) all blobs...
float MilliSeconds()
Returns the elapsed time in milliseconds.
A simple timer object for measuring time.
Simple registry implementation in Caffe2 that uses static variables to register object creators durin...
void Start()
Starts a timer.
unique_ptr< NetBase > CreateNet(const NetDef &net_def, Workspace *ws)
Creates a network, accessing / creating blobs in the given workspace.
vector< float > TEST_Benchmark(const int warmup_runs, const int main_runs, const bool run_individual) override
Benchmarks a network.