ADD file via upload

This commit is contained in:
zyf1234 2023-08-27 15:01:40 +08:00
parent 1b48792f84
commit a95bf608a0
1 changed files with 234 additions and 0 deletions

234
graph_runner.cc Normal file
View File

@ -0,0 +1,234 @@
/**
* Copyright 2019 Huawei Technologies Co., Ltd
*
* 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 "include/transform/graph_ir/graph_runner.h"
#include <algorithm>
#include <string>
#include <memory>
#ifndef ENABLE_LITE_ACL
#include "pybind11/pybind11.h"
#endif
#include "utils/log_adapter.h"
#include "include/common/utils/config_manager.h"
#include "sys/time.h"
#include "include/common/utils/utils.h"
#include "include/common/utils/callbacks.h"
#ifdef ENABLE_D
#include "include/common/utils/callbacks_ge.h"
#endif
#include "utils/ms_context.h"
#ifndef ENABLE_LITE_ACL
namespace py = pybind11;
#endif
namespace mindspore {
namespace transform {
// 该函数用于创建新的 GEGraphEngine会话。
// 参数 'sess_options' 表示会话的选项。
std::shared_ptr<ge::Session> GraphRunner::NewSession(const SessionOptions &sess_options) {
#ifdef ENABLE_D
std::shared_ptr<ge::Session> ret; // 用于存储创建的 GE 会话的智能指针
auto ms_context = MsContext::GetInstance(); // 获取 MindSpore 上下文实例
MS_EXCEPTION_IF_NULL(ms_context); // 检查上下文实例是否为空
if (ms_context->backend_policy() == "ge") { // 检查当前的后端策略是否为 GE
ret = std::make_shared<ge::Session>(sess_options); // 创建一个新的 GE 会话,并使用传入的选项 'sess_options'
if (ret == nullptr) { // 如果创建 GE 会话失败,抛出异常并记录错误日志
MS_LOG(EXCEPTION) << "Create GE session failed!";
}
MS_LOG(INFO) << "Create new GE session success!"; // 记录成功创建 GE 会话的日志
return ret; // 返回新创建的 GE 会话的智能指针
}
#endif
MS_LOG(WARNING) << "no GE client, return nullptr!"; // 如果没有启用 GE 后端,记录警告日志并返回空指针
return nullptr; // 返回空指针,表示没有创建 GE 会话
}
// 该构造函数用于初始化GraphRunner对象
GraphRunner::GraphRunner(const GraphRunnerOptions &options)
: options_(options), graph_manager_(DfGraphManager::GetInstance()) {
// 检查并记录MindSpore的并行策略是否为ONE_DEVICE
if (ConfigManager::GetInstance().parallel_strategy() == ParallelStrategy::ONE_DEVICE) {
MS_LOG(INFO) << "ME run in ONE_DEVICE strategy mode";
}
if (options.sess_ptr != nullptr) { // 根据options中传入的sess_ptr判断是否已有现有会话
sess_ = options.sess_ptr;
} else { // 若sess_ptr为空则调用NewSession函数创建新的GE会话
sess_ = NewSession(options.options);
if (sess_ == nullptr) {
MS_LOG(WARNING) << "graph runner sess_ is nullptr!";
}
}
#ifdef ENABLE_D
auto ms_context = MsContext::GetInstance();
MS_EXCEPTION_IF_NULL(ms_context);
if (ms_context->backend_policy() == "ge") {
// register the callback function
// 注册回调函数
if (sess_->RegisterCallBackFunc(callbacks::kCheckPoint, callbacks::CheckpointSaveCallback) != ge::GRAPH_SUCCESS) {
MS_LOG(EXCEPTION) << "register callback failed!";
}
if (sess_->RegisterCallBackFunc(callbacks::kSummary, callbacks::SummarySaveCallback) != ge::GRAPH_SUCCESS) {
MS_LOG(EXCEPTION) << "register summary callback failed!";
}
}
#endif
// 从图形管理器获取所有的图形包装器
std::vector<DfGraphWrapperPtr> wrappers = graph_manager_.GetAllGraphs();
if (wrappers.empty()) { // 若图形包装器为空,记录日志并直接返回
MS_LOG(INFO) << "The GraphManager is empty!!";
return;
}
#ifdef ENABLE_D
if (ms_context->backend_policy() != "ge") {
return;
}
for (auto &it : wrappers) { // 遍历所有图形包装器并将未保存的图形添加到GE会话中
std::set<string> saved_graph = graph_manager_.GetSavedGraphs();
auto iter_find = saved_graph.find(std::to_string(it->id_));
if (iter_find != saved_graph.end()) {
continue;
}
MS_LOG(INFO) << "Add the graph " << (*it).name_ << " to GE, it's id is: " << (*it).id_;
graph_manager_.AddSavedGraphs(std::to_string(it->id_));
(void)sess_->AddGraph(static_cast<uint32_t>(it->id_), *(it->graph_ptr_), it->options_);
}
#endif
}
// 该函数用于运行指定名称的图形Graph
Status GraphRunner::RunGraph(const RunOptions &options, const std::vector<GeTensorPtr> &inputs,
std::vector<GeTensorPtr> *outputs) {
std::string name = options.name; // 获取运行选项中的图形名称
if (name.empty()) { // 如果图形名称为空,记录错误日志并返回无效参数状态
MS_LOG(ERROR) << "The graph name is null";
return Status::INVALID_ARGUMENT;
}
// 从图形管理器获取指定名称的图形包装器
DfGraphWrapperPtr wrap_ptr = graph_manager_.GetGraphByName(name);
if (wrap_ptr == nullptr) {
MS_LOG(ERROR) << "Get graph form DfGraphManager failed!"; // 如果获取图形包装器失败,记录未找到状态的错误日志
return Status::NOT_FOUND;
}
if (wrap_ptr->graph_ptr_ == nullptr) { // 如果图形为空,记录警告日志并返回未找到状态
MS_LOG(WARNING) << "The graph is null";
return Status::NOT_FOUND;
}
// call ge::RunGraph() to exec a graph;
// 调用 ge::RunGraph() 来执行图形计算
std::vector<GeTensor> ge_inputs;
std::vector<GeTensor> ge_outputs;
// 将输入参数 'inputs' 转换为 'ge_inputs',用于调用 GE 接口
(void)std::transform(inputs.begin(), inputs.end(), std::back_inserter(ge_inputs),
[](const GeTensorPtr &i) { return *i; });
MS_LOG(INFO) << "Run the graph in GE with " << ge_inputs.size() << " inputs"; // 记录日志,表示正在运行 GE 图形,以及输入的数量
struct timeval start_time, end_time;
(void)gettimeofday(&start_time, nullptr);
#ifdef ENABLE_D
auto ms_context = MsContext::GetInstance();
MS_EXCEPTION_IF_NULL(ms_context);
if (ms_context->backend_policy() == "ge") {
if (sess_ == nullptr) {
MS_LOG(ERROR) << "The GE session is null, can't run the graph!"; // 如果 GE 会话为空,记录错误日志并返回执行失败状态
return Status::FAILED;
}
ge::Status ret = sess_->RunGraph(static_cast<uint32_t>(wrap_ptr->id_), ge_inputs, ge_outputs); // 调用 GE 接口运行图形
if (ret != ge::GRAPH_SUCCESS) {
MS_LOG(ERROR) << "Call GE RunGraph Failed, ret is: " << ret; // 如果运行图形失败,记录错误日志并返回执行失败状态
return Status::FAILED;
}
}
#else
ge_outputs.swap(ge_inputs); // 如果未启用 GE 后端,直接交换输入和输出,用于后续返回输出结果
#endif
(void)gettimeofday(&end_time, nullptr);
const uint64_t kUSecondInSecond = 1000000;
uint64_t cost = kUSecondInSecond * static_cast<uint64_t>(end_time.tv_sec - start_time.tv_sec);
cost += static_cast<uint64_t>(end_time.tv_usec - start_time.tv_usec);
MS_LOG(INFO) << "Call GE RunGraph Success in " << cost << " us, the GE outputs num is: " << ge_outputs.size();
// 记录日志,表示图形计算成功执行,并打印执行时间和输出数量
// 将 GE 输出结果转换为 'outputs',用于返回给调用者
(void)std::transform(ge_outputs.begin(), ge_outputs.end(), std::back_inserter(*outputs),
[](const GeTensor &ge_tensor) { return std::make_shared<GeTensor>(ge_tensor); });
return Status::SUCCESS; // 返回执行成功状态,并带有输出结果
}
// 该函数用于运行指定名称的图形,并将输入和输出都转换为 MeTensorPtr 类型
Status GraphRunner::RunGraph(const RunOptions &options, const std::vector<MeTensorPtr> &inputs,
std::vector<MeTensorPtr> *const outputs) {
std::vector<GeTensorPtr> ge_inputs; // 用于存储转换后的输入 GeTensorPtr
for (auto it : inputs) {
MS_EXCEPTION_IF_NULL(it);
MS_LOG(INFO) << "inputs tensor's data size is: " << (*it).DataSize(); // 打印输入 MeTensor 的数据大小
auto shape = (*it).shape();
std::string shape_str;
for (const auto &elem : shape) {
shape_str += std::to_string(elem);
shape_str += " ";
}
MS_LOG(INFO) << "inputs tensor's shape is: { " << shape_str << "}"; // 打印输入 MeTensor 的形状
// 将输入 MeTensor 转换为 GeTensor转换后的格式为 kOpFormat_NCHW
auto ge_tensor_ptr = TransformUtil::ConvertTensor(it, kOpFormat_NCHW);
if (ge_tensor_ptr != nullptr) {
ge_inputs.emplace_back(ge_tensor_ptr); // 将转换后的 GeTensorPtr 添加到 ge_inputs 中
} else { // 如果转换失败,记录日志并返回执行失败状态
MS_LOG(INFO) << "Convert input Me tensor to Ge tensor failed. Abort this graph";
return Status::FAILED;
}
}
std::vector<GeTensorPtr> ge_outputs; // 用于存储运行图形后的输出 GeTensorPtr
Status ret;
{
// Release GIL before calling into (potentially long-running) C++ code
// 释放 GIL然后调用 C++ 代码(可能是长时间运行的代码)
#ifndef ENABLE_LITE_ACL
py::gil_scoped_release release;
#endif
ret = RunGraph(options, ge_inputs, &ge_outputs); // 调用 RunGraph 函数运行图形计算
}
if (ret != Status::SUCCESS) {
return ret; // 如果运行图形失败,直接返回执行失败状态
} else {
// convert GeTensor to MeTensor
// 将输出 GeTensor 转换为 MeTensor并将转换后的 MeTensorPtr 添加到 outputs 中
for (auto &it : ge_outputs) {
auto tensor = TransformUtil::ConvertGeTensor(it);
if (tensor != nullptr) {
(void)outputs->emplace_back(tensor);
}
}
MS_LOG(INFO) << "Return Me tensor outputs num is: " << outputs->size(); // 打印返回的 MeTensor 数量
return Status::SUCCESS; // 返回执行成功状态,并带有输出结果
}
}
} // namespace transform
} // namespace mindspore