未验证 提交 13a9b9cb 编写于 作者: Y Yanzhan Yang 提交者: GitHub

enhance auto debug tool (#1698)

上级 63ac2860
...@@ -133,6 +133,7 @@ enum PowerMode { ...@@ -133,6 +133,7 @@ enum PowerMode {
struct PaddleMobileConfigInternal { struct PaddleMobileConfigInternal {
bool load_when_predict = false; bool load_when_predict = false;
bool enable_memory_optimization = true;
}; };
extern const char *G_OP_TYPE_CONV; extern const char *G_OP_TYPE_CONV;
......
...@@ -65,7 +65,9 @@ Executor<Device, T>::Executor(const Program<Device> &program, ...@@ -65,7 +65,9 @@ Executor<Device, T>::Executor(const Program<Device> &program,
"program_desc_ should not be nullptr"); "program_desc_ should not be nullptr");
#if !defined(PADDLE_MOBILE_FPGA) && !defined(PADDLE_MOBILE_FPGA_KD) && \ #if !defined(PADDLE_MOBILE_FPGA) && !defined(PADDLE_MOBILE_FPGA_KD) && \
!defined(PADDLE_MOBILE_CL) !defined(PADDLE_MOBILE_CL)
pass::MemoryOptPass()(program_desc_.get(), program_.scope.get()); if (config_.enable_memory_optimization) {
pass::MemoryOptPass()(program_desc_.get(), program_.scope.get());
}
#endif #endif
// resize feed and fetch list // resize feed and fetch list
// should init feed and fetch variables before infer shape // should init feed and fetch variables before infer shape
......
...@@ -17,39 +17,51 @@ limitations under the License. */ ...@@ -17,39 +17,51 @@ limitations under the License. */
#include "../test_helper.h" #include "../test_helper.h"
#include "../test_include.h" #include "../test_include.h"
void test(int argc, char *argv[], bool fuse); void test(int argc, char *argv[]);
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
test(argc, argv, false); test(argc, argv);
test(argc, argv, true);
return 0; return 0;
} }
void test(int argc, char *argv[], bool fuse) {
paddle_mobile::PaddleMobile<paddle_mobile::CPU> paddle_mobile; void test(int argc, char *argv[]) {
int arg_index = 1;
bool fuse = std::stoi(argv[arg_index]) == 1;
arg_index++;
bool enable_memory_optimization = std::stoi(argv[arg_index]) == 1;
arg_index++;
paddle_mobile::PaddleMobileConfigInternal config;
config.enable_memory_optimization = enable_memory_optimization;
paddle_mobile::PaddleMobile<paddle_mobile::CPU> paddle_mobile(config);
paddle_mobile.SetThreadNum(1); paddle_mobile.SetThreadNum(1);
std::string tag = fuse ? "-fuse" : "";
int dim_count = std::stoi(argv[1]); int dim_count = std::stoi(argv[arg_index]);
arg_index++;
int size = 1; int size = 1;
std::vector<int64_t> dims; std::vector<int64_t> dims;
for (int i = 0; i < dim_count; i++) { for (int i = 0; i < dim_count; i++) {
int64_t dim = std::stoi(argv[2 + i]); int64_t dim = std::stoi(argv[arg_index + i]);
size *= dim; size *= dim;
dims.push_back(dim); dims.push_back(dim);
} }
arg_index += dim_count;
int var_count = std::stoi(argv[1 + dim_count]); int var_count = std::stoi(argv[arg_index]);
arg_index++;
int sample_step = std::stoi(argv[arg_index]);
arg_index++;
std::vector<std::string> var_names; std::vector<std::string> var_names;
for (int i = 0; i < var_count; i++) { for (int i = 0; i < var_count; i++) {
std::string var_name = argv[1 + dim_count + 1 + 1 + i]; std::string var_name = argv[arg_index + i];
var_names.push_back(var_name); var_names.push_back(var_name);
} }
arg_index += var_count;
auto time1 = time(); auto time1 = time();
if (paddle_mobile.Load("./checked_model/model", "./checked_model/params", if (paddle_mobile.Load("./checked_model/model", "./checked_model/params",
fuse, false, 1, true)) { fuse, false, 1, true)) {
auto time2 = time(); auto time2 = time();
std::cout << "auto-test" << tag std::cout << "auto-test"
<< " load-time-cost :" << time_diff(time1, time1) << "ms" << " load-time-cost :" << time_diff(time1, time1) << "ms"
<< std::endl; << std::endl;
...@@ -73,8 +85,9 @@ void test(int argc, char *argv[], bool fuse) { ...@@ -73,8 +85,9 @@ void test(int argc, char *argv[], bool fuse) {
auto out = paddle_mobile.Predict(input_data, dims); auto out = paddle_mobile.Predict(input_data, dims);
} }
auto time4 = time(); auto time4 = time();
std::cout << "auto-test" << tag << " predict-time-cost " std::cout << "auto-test"
<< time_diff(time3, time4) / 50 << "ms" << std::endl; << " predict-time-cost " << time_diff(time3, time4) / 50 << "ms"
<< std::endl;
// 测试正确性 // 测试正确性
auto out = paddle_mobile.Predict(input_data, dims); auto out = paddle_mobile.Predict(input_data, dims);
...@@ -88,13 +101,12 @@ void test(int argc, char *argv[], bool fuse) { ...@@ -88,13 +101,12 @@ void test(int argc, char *argv[], bool fuse) {
continue; continue;
} }
auto data = out->data<float>(); auto data = out->data<float>();
int step = len / 20;
std::string sample = ""; std::string sample = "";
for (int i = 0; i < len; i += step) { for (int i = 0; i < len; i += sample_step) {
sample += " " + std::to_string(data[i]); sample += " " + std::to_string(data[i]);
} }
std::cout << "auto-test" << tag << " var " << var_name << sample std::cout << "auto-test"
<< std::endl; << " var " << var_name << sample << std::endl;
} }
std::cout << std::endl; std::cout << std::endl;
} }
......
import caffe
import numpy as np
prototxt_path = ""
caffemodel_path = ""
input_path = "input.txt"
input_name = ""
output_name = ""
shape = (1, 3, 64, 64)
data = np.loadtxt(input_path).astype("float32").reshape(shape)
net = caffe.Net(prototxt_path, caffemodel_path, caffe.TEST)
# view inputs blob names
print(net.inputs)
# view outputs blob names
print(net.outputs)
# set input data
net.blobs[input_name].reshape(*shape)
net.blobs[input_name].data[...] = data
# predict
net.forward()
# view output data
print(net.blobs[output_name].data)
# -*- coding: utf-8 -*
import os import os
import sys import sys
import math import math
...@@ -9,6 +10,9 @@ model_path = "model" ...@@ -9,6 +10,9 @@ model_path = "model"
checked_model_path = "checked_model" checked_model_path = "checked_model"
feed_path = "feeds" feed_path = "feeds"
output_path = "outputs" output_path = "outputs"
diff_threshold = 0.01
np.set_printoptions(linewidth=150)
mobile_exec_root = "/data/local/tmp/bin" mobile_exec_root = "/data/local/tmp/bin"
mobile_src_root = os.path.abspath("../../../") mobile_src_root = os.path.abspath("../../../")
...@@ -16,11 +20,11 @@ if mobile_src_root.endswith("/"): ...@@ -16,11 +20,11 @@ if mobile_src_root.endswith("/"):
mobile_src_root = mobile_src_root[:-1] mobile_src_root = mobile_src_root[:-1]
dot = "•" dot = "•"
black = lambda x: "\033[30m" + str(x) black = lambda x: "\033[30m" + str(x) + "\033[0m"
red = lambda x: "\033[31m" + str(x) red = lambda x: "\033[31m" + str(x) + "\033[0m"
green = lambda x: "\033[32m" + str(x) green = lambda x: "\033[32m" + str(x) + "\033[0m"
yellow = lambda x: "\033[33m" + str(x) + "\033[0m"
reset = lambda x: "\033[0m" + str(x) reset = lambda x: "\033[0m" + str(x)
yellow = lambda x: "\033[33m" + str(x)
def pp_tab(x, level=0): def pp_tab(x, level=0):
header = "" header = ""
...@@ -61,6 +65,7 @@ def resave_model(): ...@@ -61,6 +65,7 @@ def resave_model():
# 强制所有var为可持久化 # 强制所有var为可持久化
p_names = [] p_names = []
for name in vars: for name in vars:
name = str(name)
v = fluid.framework._get_var(name, prog) v = fluid.framework._get_var(name, prog)
if not v.persistable: if not v.persistable:
v.persistable = True v.persistable = True
...@@ -69,6 +74,7 @@ def resave_model(): ...@@ -69,6 +74,7 @@ def resave_model():
has_found_wrong_shape = False has_found_wrong_shape = False
# 修正每个var的形状 # 修正每个var的形状
for name in vars: for name in vars:
name = str(name)
v = vars[name] v = vars[name]
if v.persistable: if v.persistable:
v1 = fluid.global_scope().find_var(name) v1 = fluid.global_scope().find_var(name)
...@@ -117,6 +123,8 @@ last_feed_var_name = None ...@@ -117,6 +123,8 @@ last_feed_var_name = None
last_feed_file_name = None last_feed_file_name = None
# 加载feed的key-value对 # 加载feed的key-value对
def load_feed_kv(): def load_feed_kv():
if not os.path.exists(feed_path):
return None
global last_feed_var_name global last_feed_var_name
global last_feed_file_name global last_feed_file_name
feed_kv = {} feed_kv = {}
...@@ -128,7 +136,16 @@ def load_feed_kv(): ...@@ -128,7 +136,16 @@ def load_feed_kv():
file_name = feed_name.replace("/", "_") file_name = feed_name.replace("/", "_")
last_feed_var_name = feed_name last_feed_var_name = feed_name
last_feed_file_name = file_name last_feed_file_name = file_name
data = np.loadtxt(feed_path + "/" + file_name).reshape(feed_shape).astype("float32") feed_file_path = feed_path + "/" + file_name
if not os.path.exists(feed_file_path):
return None
data = np.loadtxt(feed_file_path)
expected_len = 1
for dim in feed_shape:
expected_len *= dim
if len(data) != expected_len:
return None
data = data.reshape(feed_shape).astype("float32")
feed_kv[feed_name] = data feed_kv[feed_name] = data
return feed_kv return feed_kv
...@@ -166,10 +183,11 @@ def get_var_data(var_name, feed_kv=None): ...@@ -166,10 +183,11 @@ def get_var_data(var_name, feed_kv=None):
return output return output
output_var_cache = {} output_var_cache = {}
sample_step = 1
def tensor_sample(tensor): def tensor_sample(tensor):
step = math.floor(len(tensor) / 20) # step = math.floor(len(tensor) / 20)
sample = [] sample = []
for i in range(0, len(tensor), step): for i in range(0, len(tensor), sample_step):
sample.append(tensor[i]) sample.append(tensor[i])
return sample return sample
op_cache = {} op_cache = {}
...@@ -209,19 +227,21 @@ for op in ops: ...@@ -209,19 +227,21 @@ for op in ops:
op_types.add(op.type) op_types.add(op.type)
pp_tab("op types : {}".format(op_types), 1) pp_tab("op types : {}".format(op_types), 1)
def check_mobile_results(lines, fuse): def check_mobile_results(args, fuse, mem_opt):
pp_yellow(dot + dot + " checking {} paddle mobile results".format("fusion" if fuse else "non fusion")) args = "{} {} {}".format("1" if fuse else "0", "1" if mem_opt else "0", args)
res = sh("adb shell \"cd {} && export LD_LIBRARY_PATH=. && ./test-net {}\"".format(mobile_exec_root, args))
lines = res.split("\n")
for line in lines:
if line.startswith("auto-test-debug"):
print(line)
pp_yellow(dot + dot + " checking paddle mobile results for {} -- {} ".format(green("【fusion】" if fuse else "【non fusion】"), green("【memory-optimization】" if mem_opt else "【non-memory-optimization】")))
mobile_var_cache = {} mobile_var_cache = {}
for line in lines: for line in lines:
parts = line.split(" ") parts = line.split(" ")
if len(parts) <= 0: if len(parts) < 2:
continue
if "auto-test" != parts[0]:
continue continue
if fuse:
if "auto-test-fuse" != parts[0]:
continue
else:
if "auto-test" != parts[0]:
continue
if parts[1] == "load-time-cost": if parts[1] == "load-time-cost":
pp_green("load time cost : {}".format(parts[2]), 1) pp_green("load time cost : {}".format(parts[2]), 1)
elif parts[1] == "predict-time-cost": elif parts[1] == "predict-time-cost":
...@@ -235,6 +255,14 @@ def check_mobile_results(lines, fuse): ...@@ -235,6 +255,14 @@ def check_mobile_results(lines, fuse):
error_values2 = None error_values2 = None
for index in op_cache: for index in op_cache:
op_output_var_name, op = op_cache[index] op_output_var_name, op = op_cache[index]
if mem_opt:
found_in_fetch = False
for fetch in fetches:
if op_output_var_name == fetch.name:
found_in_fetch = True
break
if not found_in_fetch:
continue
if not op_output_var_name in output_var_cache: if not op_output_var_name in output_var_cache:
continue continue
if not op_output_var_name in mobile_var_cache: if not op_output_var_name in mobile_var_cache:
...@@ -247,7 +275,7 @@ def check_mobile_results(lines, fuse): ...@@ -247,7 +275,7 @@ def check_mobile_results(lines, fuse):
for i in range(len(values1)): for i in range(len(values1)):
v1 = values1[i] v1 = values1[i]
v2 = values2[i] v2 = values2[i]
if abs(v1 - v2) > 0.01: if abs(v1 - v2) > diff_threshold:
error_index = index error_index = index
break break
if error_index != None: if error_index != None:
...@@ -257,19 +285,23 @@ def check_mobile_results(lines, fuse): ...@@ -257,19 +285,23 @@ def check_mobile_results(lines, fuse):
if error_index == None: if error_index == None:
pp_green("outputs are all correct", 1) pp_green("outputs are all correct", 1)
else: else:
error_values1 = np.array(error_values1)
error_values2 = np.array(error_values2)
pp_red("{} op's output is not correct, op's type is {}".format(error_index, op_cache[error_index][1].type), 1) pp_red("{} op's output is not correct, op's type is {}".format(error_index, op_cache[error_index][1].type), 1)
pp_red("fluid results are : {}".format(error_values1), 1) pp_red("fluid results are : ", 1)
pp_red("paddle mobile results are : {}".format(error_values2), 1) pp_red(str(error_values1).replace("\n", "\n" + "\t" * 1), 1)
pp_red("paddle mobile results are : ", 1)
pp_red(str(error_values2).replace("\n", "\n" + "\t" * 1), 1)
# print(output_var_cache) # print(output_var_cache)
# print(mobile_var_cache) # print(mobile_var_cache)
def main(): def main():
# 如果feed_path不存在,则需要生成并保存feed的键值对
if not os.path.exists(feed_path):
feed_kv = gen_feed_kv()
save_feed_kv(feed_kv)
# 加载kv # 加载kv
feed_kv = load_feed_kv() feed_kv = load_feed_kv()
if feed_kv == None:
feed_kv = gen_feed_kv()
save_feed_kv(feed_kv)
feed_kv = load_feed_kv()
pp_yellow(dot + dot + " checking fetch info") pp_yellow(dot + dot + " checking fetch info")
for fetch in fetches: for fetch in fetches:
pp_tab("fetch var name : {}".format(fetch.name), 1) pp_tab("fetch var name : {}".format(fetch.name), 1)
...@@ -297,12 +329,13 @@ def main(): ...@@ -297,12 +329,13 @@ def main():
for dim in last_feed_var_shape: for dim in last_feed_var_shape:
args += " " + str(dim) args += " " + str(dim)
args += " " + str(len(output_var_cache)) args += " " + str(len(output_var_cache))
args += " " + str(sample_step)
for var_name in output_var_cache.keys(): for var_name in output_var_cache.keys():
args += " " + var_name args += " " + var_name
res = sh("adb shell \"cd {} && export LD_LIBRARY_PATH=. && ./test-net {}\"".format(mobile_exec_root, args)) check_mobile_results(args, False, False)
lines = res.split("\n") check_mobile_results(args, False, True)
check_mobile_results(lines, False) check_mobile_results(args, True, False)
check_mobile_results(lines, True) check_mobile_results(args, True, True)
if __name__ == "__main__": if __name__ == "__main__":
main() main()
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册