Skip to content
4 changes: 4 additions & 0 deletions paddle/fluid/operators/detail/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,7 @@ if(WITH_DISTRIBUTE)
cares zlib protobuf sendrecvop_grpc)
cc_test(grpc_server_test SRCS grpc_server_test.cc DEPS sendrecvop_grpc grpc++_unsecure grpc_unsecure gpr cares zlib protobuf executor proto_desc lookup_table_op)
endif()

cc_binary(desc_executor SRCS desc_executor.cc DEPS sendrecvop_grpc grpc++_unsecure grpc_unsecure gpr
cares zlib protobuf lookup_table_op proto_desc memory executor prune init
profiler parallel_executor ${GLOB_OP_LIB})
126 changes: 126 additions & 0 deletions paddle/fluid/operators/detail/desc_executor.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
// Copyright (c) 2018 PaddlePaddle Authors. All Rights Reserved.
Copy link
Contributor

Choose a reason for hiding this comment

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

should this file by call execute_program_desc?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done.

//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <stdio.h>
#include <stdlib.h>

#include <algorithm>
#include <iostream>
#include <string>

#include "gflags/gflags.h"
#include "paddle/fluid/framework/details/op_registry.h"
#include "paddle/fluid/framework/executor.h"
#include "paddle/fluid/framework/init.h"
#include "paddle/fluid/framework/op_registry.h"
#include "paddle/fluid/framework/program_desc.h"
#include "paddle/fluid/framework/scope.h"
#include "paddle/fluid/pybind/pybind.h"

bool read_from_file(const std::string& file, char** buf, int64_t* buf_len) {
FILE* f = fopen(file.c_str(), "rb");
if (NULL == f) {
printf("open %s error\n", file.c_str());
Copy link
Contributor

Choose a reason for hiding this comment

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

fprintf(stderr? or LOG(ERROR)?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

change to fprintf(stderr.
Thanks.

return false;
}

fseek(f, 0, SEEK_END);
int64_t fsize = ftell(f);
fseek(f, 0, SEEK_SET); // same as rewind(f);

*buf = static_cast<char*>(malloc(fsize + 1));
if (fread(*buf, fsize, 1, f) != 1) {
fclose(f);
return false;
}

*buf_len = fsize;

(*buf)[fsize] = 0;
fclose(f);
return true;
}

using namespace paddle; // NOLINT

framework::ProgramDesc* load_desc(const std::string& file) {
Copy link
Contributor

Choose a reason for hiding this comment

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

return unique_ptr?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done.

char* buf = NULL;
std::unique_ptr<char[]> tmp(buf);
int64_t buf_len = 0;

if (!read_from_file(file, &buf, &buf_len)) {
return NULL;
}

framework::proto::ProgramDesc proto;
if (!proto.ParseFromArray(buf, buf_len)) {
printf("parse from %s error!\n", file.c_str());
return NULL;
}

return (new framework::ProgramDesc(proto));
}

DEFINE_string(start_up_proto, "", "start up proto file");
Copy link
Contributor

Choose a reason for hiding this comment

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

put at the file top?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks.Done.

DEFINE_string(loop_proto, "", "loop proto file");
DEFINE_string(executor_device, "CPU", "executor's place:GPU or CPU");
DEFINE_int32(executor_device_id, 0, "GPU device id");

int main(int argc, char** argv) {
// init.
google::ParseCommandLineFlags(&argc, &argv, true);
framework::InitGLOG(argv[0]);
framework::InitDevices(true);

// check arguments.
if (FLAGS_start_up_proto.empty()) {
printf("please set start_up_proto path\n");
return -1;
}

if (FLAGS_loop_proto.empty()) {
printf("please set loop_proto path\n");
return -1;
}

framework::ProgramDesc program;
framework::Scope scope;

framework::ProgramDesc* start_up = load_desc(FLAGS_start_up_proto);
framework::ProgramDesc* loop = load_desc(FLAGS_loop_proto);

std::string place_str = FLAGS_executor_device;
std::transform(place_str.begin(), place_str.end(), place_str.begin(),
[](unsigned char ch) { return toupper(ch); });

framework::Executor* exe = nullptr;
Copy link
Contributor

Choose a reason for hiding this comment

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

unique_ptr>

if (place_str == "CPU") {
platform::CPUPlace place;
exe = new framework::Executor(place);
} else if (place_str == "GPU") {
platform::CUDAPlace place(FLAGS_executor_device_id);
exe = new framework::Executor(place);
} else {
printf("unkown device:%s", FLAGS_executor_device.c_str());
return -1;
}

exe->Run(*start_up, &scope, 0, false, true);
exe->Run(*loop, &scope, 0, false, true);

delete start_up;
delete loop;
delete exe;
return 0;
}
10 changes: 9 additions & 1 deletion python/paddle/fluid/executor.py
Original file line number Diff line number Diff line change
Expand Up @@ -277,7 +277,8 @@ def run(self,
fetch_var_name='fetch',
scope=None,
return_numpy=True,
use_program_cache=False):
use_program_cache=False,
save_program_to_file=""):
Copy link
Contributor

Choose a reason for hiding this comment

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

I still don't want to put "save_program_to_file" as a argument to Executor. Saving program should be in a separate API, such as "save_inference_model".

""" Run program by this Executor. Feed data by feed map, fetch result by fetch_list.

Python executor takes a program, add feed operators and fetch operators to this program according
Expand All @@ -294,6 +295,7 @@ def run(self,
:param scope: the scope used to run this program, you can switch it to different scope. default is global_scope
:param return_numpy: if convert the fetched tensor to numpy
:param use_program_cache: set use_program_cache to true if program not changed compare to the last step.
:param save_program_to_file: save program desc to the file before running.
:return: result according to fetch_list.
"""
if feed is None:
Expand Down Expand Up @@ -333,6 +335,12 @@ def run(self,
fetch_var_name=fetch_var_name)

self._feed_data(program, feed, feed_var_name, scope)

# TODO(gongwb): does a program should be saved in run function?
if len(save_program_to_file) > 0:
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm not sure we should do the save here...

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The programdesc is modified in run function.And sometimes a user can't get chance to save it.

Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe run() shouldn't modify the programdesc? Or we should save after run is called?

with open(save_program_to_file, 'w') as f:
f.write(program.desc.serialize_to_string())

self.executor.run(program.desc, scope, 0, True, True)
outs = self._fetch_data(fetch_list, fetch_var_name, scope)
if return_numpy:
Expand Down