PaddlePaddleinference源码分析(一)
2023年7月3日发(作者:)
PaddlePaddleinference源码分析(⼀)本⽂针对代码版本为Paddle/2.2,主要针对预测流程的梳理。⼀、简要使⽤流程paddle inference的使⽤较为简单,其基本代码如下:// 创建predictorstd::shared_ptr InitPredictor() { Config config; if (FLAGS_model_dir != "") { el(FLAGS_model_dir); } el(FLAGS_model_file, FLAGS_params_file); if (FLAGS_use_gpu) { UseGpu(100, 0); } else { MKLDNN(); } // Open the memory optim. MemoryOptim(); return CreatePredictor(config);}// 执⾏预测void run(Predictor *predictor, const std::vector &input, const std::vector &input_shape, std::vector *out_data) { int input_num = std::accumulate(input_(), input_(), 1, std::multiplies()); auto input_names = predictor->GetInputNames(); auto output_names = predictor->GetOutputNames(); auto input_t = predictor->GetInputHandle(input_names[0]); input_t->Reshape(input_shape); input_t->CopyFromCpu(()); for (size_t i = 0; i < FLAGS_warmup; ++i) CHECK(predictor->Run()); auto st = time(); for (size_t i = 0; i < FLAGS_repeats; ++i) { CHECK(predictor->Run()); auto output_t = predictor->GetOutputHandle(output_names[0]); std::vector output_shape = output_t->shape(); int out_num = std::accumulate(output_(), output_(), 1, std::multiplies()); out_data->resize(out_num); output_t->CopyToCpu(out_data->data()); } LOG(INFO) << "run avg time is " << time_diff(st, time()) / FLAGS_repeats << " ms";}⼆、代码⽬录结构⽬录结构如下:--cmake #cmake编译脚本以及编译链接的第三⽅库等--doc--paddle #c++代码 -fluid -distributed #分布式相关代码,主要为训练使⽤,包括模型内all_reduce进⾏跨卡通信、跨机通信等 -extension # -framework #基础组件代码 -imperative #分布式通信相关代码,包括nccl、all_reduce、bkcl等 -inference #预测相关代码以及api定义 -memory -operators #算⼦ -platform #平台相关代码 -pybind #pybind接⼝定义 -string -scripts -testing -utils--patches--python #python部分代码-- #编译脚本,包括⼤部分编译参数、三⽅库依赖等逻辑三、编译产出 产出⽬录如下: build -python #whl安装包 -paddle_install_dir #产出的所有头⽂件及库 -paddle_inference_install_dir #预测c++依赖库 -paddle_inference_c_install_dir #预测c依赖库 四、构件简介1、predictor实例持有所有资源,是预测端的主要端⼝。在第⼀个predictor创建出来后,可以使⽤clone接⼝创建新的实例,使⽤clone接⼝创建出来的predictor实例与⽗实例共有固定参数资源scope。会预先进⾏内存和显存的分配。2、scope⽤于保存参数变量的结构。其内部结构为:scope->variable->LodTensor。scope中保存variable的map表。predictor会持有scope并保存模型权重。同时,每个predictor实例会保存sub_scope(使⽤scope创建的⼦scope)⽤于保存临时参数(计算过程中的可变参数、输⼊输出等)。在第⼀次执⾏创建好内存后,后续的执⾏都是从scope中获取缓存的内存来使⽤。在inference中scope由于只会有单线程写,多线程读的部分为持久参数,因此⽆锁。但是在训练框架中scope有锁。3、place⽤于表征当前操作运⾏环境的变量,如:CPUPlace、GPUPlace等。程序使⽤place选择对应opkernel,或者表征当前内存所在的位置为cpu还是gpu等4、DeviceContext与DeviceContextPoolDeviceContext⽤于存储当前环境中所有计算资源,每种硬件资源都有对应的context,包括cpu、gpu、npu等。predictor从全局单例的DeviceContextPool中根据place获取对应DeviceContext5、Operator与Kernel算⼦,计算单元。模型⽂件中保存了所要运⾏的有向图,图中每个节点就是⼀个Op,predictor执⾏时会顺序执⾏图中的每个OP。这⾥OP有两种,⼀种是功能性OP,直接在OP中写好了操作内容,如打印错误信息、收集性能数据等;另⼀种是计算OP,基于OpWithKernel实现,调⽤该种OP时,会根据place参数以及op本⾝特性选择对应器件的Kernel执⾏计算。⼀般每个OP都会注册包括CPU、GPU、NPU等版本的对应Kernel。6、IR Pass图优化。加载模型⽂件,创建predictor后,如果开启ir_optim会进⾏图优化。这⾥实际是对原始的模型op图顺序执⾏符合要求的各个Pass,每个pass代表⼀种优化规则,⽐如有节点融合、特殊结构优化、⼦图切割进tensorrt等等。
发布者:admin,转转请注明出处:http://www.yc00.com/news/1688384127a129950.html
评论列表(0条)