Skip to content

Commit 8db74b5

Browse files
committed
第十节课的代码
1 parent 236a8d5 commit 8db74b5

File tree

3 files changed

+246
-1
lines changed

3 files changed

+246
-1
lines changed

include/runtime/runtime_ir.hpp

+28-1
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,30 @@
2626

2727
// 5. 再把这个runtime_operator存放好
2828
// 这个runtime_operator中既有输入的参数,又有输出的数、参数,又有层的参数,又有层的权重!
29-
// 转换成功!
29+
// 转换成功!
3030

3131

3232
namespace kuiper_infer {
33+
34+
class RuntimeGraphShape {
35+
public:
36+
/**
37+
* 如果图是第一次运行,则根据节点输入operand的形状准备好后续Layer计算中所需要的Tensor
38+
* 如果图是第二次以上运行,则检查输入operand的形状和operand中张量的形状是否匹配
39+
* @param operators 计算图中的计算节点
40+
*/
41+
static void InitOperatorInputTensor(const std::vector<std::shared_ptr<RuntimeOperator>> &operators);
42+
43+
/**
44+
* 如果图是第一次运行,则根据节点输出operand的形状准备好后续Layer计算中所需要的Tensor
45+
* 如果图是第二次以上运行,则检查输出operand的形状和operand中张量的形状是否匹配
46+
* @param pnnx_operators pnnx图节点
47+
* @param operators KuiperInfer计算图中的计算节点
48+
*/
49+
static void InitOperatorOutputTensor(const std::vector<pnnx::Operator *> &pnnx_operators,
50+
const std::vector<std::shared_ptr<RuntimeOperator>> &operators);
51+
};
52+
3353
/// 计算图结构,由多个计算节点和节点之间的数据流图组成
3454
class RuntimeGraph {
3555
public:
@@ -39,6 +59,13 @@ class RuntimeGraph {
3959
*/
4060
bool Init();
4161

62+
/**
63+
* 构建计算图
64+
* @param input_name 计算图输入节点的名称
65+
* @param output_name 计算图输出节点的名称
66+
*/
67+
void Build(const std::string &input_name, const std::string &output_name);
68+
4269
/**
4370
* 初始化计算图
4471
* @param param_path 计算图的结构文件

source/runtime/runtime_ir.cpp

+190
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,166 @@
99
#include "factory/layer_factory.hpp"
1010

1111
namespace kuiper_infer {
12+
13+
void RuntimeGraphShape::InitOperatorInputTensor(
14+
const std::vector<std::shared_ptr<RuntimeOperator>> &operators) {
15+
if (operators.empty()) {
16+
LOG(ERROR) << "Operators for init input shapes is empty!";
17+
return;
18+
}
19+
for (const auto &op : operators) {
20+
if (op->input_operands.empty()) {
21+
continue;
22+
} else {
23+
const std::map<std::string, std::shared_ptr<RuntimeOperand>> &
24+
input_operands_map = op->input_operands;
25+
for (const auto &input_operand_iter : input_operands_map) {
26+
const auto &input_operand = input_operand_iter.second;
27+
const auto &type = input_operand->type;
28+
CHECK(type == RuntimeDataType::kTypeFloat32)
29+
<< "The graph only support float32 yet!";
30+
const auto &input_operand_shape = input_operand->shapes;
31+
auto &input_datas = input_operand->datas;
32+
33+
CHECK(!input_operand_shape.empty());
34+
const int32_t batch = input_operand_shape.at(0);
35+
CHECK(batch >= 0) << "Dynamic batch size is not supported!";
36+
CHECK(input_operand_shape.size() == 2 ||
37+
input_operand_shape.size() == 4 ||
38+
input_operand_shape.size() == 3)
39+
<< "Unsupported tensor shape sizes: " << input_operand_shape.size();
40+
41+
if (!input_datas.empty()) {
42+
CHECK(input_datas.size() == batch) << "Batch size is wrong!";
43+
for (int32_t i = 0; i < batch; ++i) {
44+
const std::vector<uint32_t> &input_data_shape =
45+
input_datas.at(i)->shapes();
46+
CHECK(input_data_shape.size() == 3)
47+
<< "THe origin shape size of operator input data do not equals "
48+
"to three";
49+
if (input_operand_shape.size() == 4) {
50+
CHECK(input_data_shape.at(0) == input_operand_shape.at(1) &&
51+
input_data_shape.at(1) == input_operand_shape.at(2) &&
52+
input_data_shape.at(2) == input_operand_shape.at(3));
53+
} else if (input_operand_shape.size() == 2) {
54+
CHECK(input_data_shape.at(1) == input_operand_shape.at(1) &&
55+
input_data_shape.at(0) == 1 && input_data_shape.at(2) == 1);
56+
} else {
57+
// current shape size = 3
58+
CHECK(input_data_shape.at(1) == input_operand_shape.at(1) &&
59+
input_data_shape.at(0) == 1 &&
60+
input_data_shape.at(2) == input_operand_shape.at(2));
61+
}
62+
}
63+
} else {
64+
input_datas.resize(batch);
65+
for (int32_t i = 0; i < batch; ++i) {
66+
if (input_operand_shape.size() == 4) {
67+
input_datas.at(i) = std::make_shared<Tensor<float>>(
68+
input_operand_shape.at(1), input_operand_shape.at(2),
69+
input_operand_shape.at(3));
70+
} else if (input_operand_shape.size() == 2) {
71+
input_datas.at(i) = std::make_shared<Tensor<float>>(
72+
1, input_operand_shape.at(1), 1);
73+
} else {
74+
// current shape is 3
75+
input_datas.at(i) = std::make_shared<Tensor<float>>(
76+
1, input_operand_shape.at(1), input_operand_shape.at(2));
77+
}
78+
}
79+
}
80+
}
81+
}
82+
}
83+
}
84+
85+
void RuntimeGraphShape::InitOperatorOutputTensor(
86+
const std::vector<pnnx::Operator *> &pnnx_operators,
87+
const std::vector<std::shared_ptr<RuntimeOperator>> &operators) {
88+
CHECK(!pnnx_operators.empty() && !operators.empty());
89+
CHECK(pnnx_operators.size() == operators.size());
90+
for (uint32_t i = 0; i < pnnx_operators.size(); ++i) {
91+
const std::vector<pnnx::Operand *> operands = pnnx_operators.at(i)->outputs;
92+
CHECK(operands.size() <= 1) << "Only support one node one output yet!";
93+
if (operands.empty()) {
94+
continue;
95+
}
96+
CHECK(operands.size() == 1) << "Only support one output in the KuiperInfer";
97+
pnnx::Operand *operand = operands.front();
98+
const auto &runtime_op = operators.at(i);
99+
CHECK(operand != nullptr) << "Operand output is null";
100+
const std::vector<int32_t> &operand_shapes = operand->shape;
101+
const auto &output_tensors = runtime_op->output_operands;
102+
103+
const int32_t batch = operand_shapes.at(0);
104+
CHECK(batch >= 0) << "Dynamic batch size is not supported!";
105+
CHECK(operand_shapes.size() == 2 || operand_shapes.size() == 4 ||
106+
operand_shapes.size() == 3)
107+
<< "Unsupported shape sizes: " << operand_shapes.size();
108+
109+
if (!output_tensors) {
110+
std::shared_ptr<RuntimeOperand> output_operand =
111+
std::make_shared<RuntimeOperand>();
112+
output_operand->shapes = operand_shapes;
113+
output_operand->type = RuntimeDataType::kTypeFloat32;
114+
output_operand->name = operand->name + "_output";
115+
for (int j = 0; j < batch; ++j) {
116+
if (operand_shapes.size() == 4) {
117+
output_operand->datas.push_back(std::make_shared<Tensor<float>>(
118+
operand_shapes.at(1), operand_shapes.at(2),
119+
operand_shapes.at(3)));
120+
} else if (operand_shapes.size() == 2) {
121+
output_operand->datas.push_back(
122+
std::make_shared<Tensor<float>>(1, operand_shapes.at(1), 1));
123+
} else {
124+
// current shape is 3
125+
output_operand->datas.push_back(std::make_shared<Tensor<float>>(
126+
1, operand_shapes.at(1), operand_shapes.at(2)));
127+
}
128+
}
129+
runtime_op->output_operands = std::move(output_operand);
130+
} else {
131+
CHECK(batch == output_tensors->datas.size());
132+
// output_tensors empty
133+
CHECK(output_tensors->type == RuntimeDataType::kTypeFloat32);
134+
CHECK(output_tensors->shapes == operand_shapes);
135+
for (uint32_t b = 0; b < batch; ++b) {
136+
const std::vector<uint32_t> &tensor_shapes =
137+
output_tensors->datas.at(b)->shapes();
138+
if (operand_shapes.size() == 4) {
139+
if (tensor_shapes.at(0) != operand_shapes.at(1) ||
140+
tensor_shapes.at(1) != operand_shapes.at(2) ||
141+
tensor_shapes.at(2) != operand_shapes.at(3)) {
142+
DLOG(WARNING) << "The shape of tensor do not adapting with output operand";
143+
const auto &target_shapes = std::vector<uint32_t>{(uint32_t) operand_shapes.at(1),
144+
(uint32_t) operand_shapes.at(2),
145+
(uint32_t) operand_shapes.at(3)};
146+
output_tensors->datas.at(b)->ReRawshape(target_shapes);
147+
}
148+
} else if (operand_shapes.size() == 2) {
149+
if (tensor_shapes.at(0) != 1 ||
150+
tensor_shapes.at(1) != operand_shapes.at(1) ||
151+
tensor_shapes.at(2) != 1) {
152+
DLOG(WARNING) << "The shape of tensor do not adapting with output operand";
153+
const auto &target_shapes = std::vector<uint32_t>{1, (uint32_t) operand_shapes.at(1), 1};
154+
output_tensors->datas.at(b)->ReRawshape(target_shapes);
155+
}
156+
} else {
157+
// current shape is 3
158+
if (tensor_shapes.at(0) != 1 ||
159+
tensor_shapes.at(1) != operand_shapes.at(1) ||
160+
tensor_shapes.at(2) != operand_shapes.at(2)) {
161+
DLOG(WARNING) << "The shape of tensor do not adapting with output operand";
162+
const auto &target_shapes =
163+
std::vector<uint32_t>{1, (uint32_t) operand_shapes.at(1), (uint32_t) operand_shapes.at(2)};
164+
output_tensors->datas.at(b)->ReRawshape(target_shapes);
165+
}
166+
}
167+
}
168+
}
169+
}
170+
}
171+
12172
RuntimeGraph::RuntimeGraph(std::string param_path, std::string bin_path)
13173
: param_path_(std::move(param_path)), bin_path_(std::move(bin_path)) {
14174

@@ -242,4 +402,34 @@ void RuntimeGraph::InitGraphAttrs(const std::map<std::string, pnnx::Attribute> &
242402
const std::vector<std::shared_ptr<RuntimeOperator>> RuntimeGraph::operators() const {
243403
return this->operators_;
244404
}
405+
406+
void RuntimeGraph::Build(const std::string &input_name, const std::string &output_name) {
407+
if (graph_state_ == GraphState::NeedInit) {
408+
bool init_graph = Init();
409+
LOG_IF(FATAL, !init_graph) << "Init graph failed!";
410+
}
411+
412+
CHECK(graph_state_ >= GraphState::NeedBuild)
413+
<< "Graph status error, current state is " << int(graph_state_);
414+
LOG_IF(FATAL, this->operators_.empty())
415+
<< "Graph operators is empty, may be no init";
416+
417+
this->input_operators_maps_.clear();
418+
this->output_operators_maps_.clear();
419+
420+
for (const auto &kOperator : this->operators_) {
421+
if (kOperator->type == "pnnx.Input") {
422+
this->input_operators_maps_.insert({kOperator->name, kOperator});
423+
} else if (kOperator->type == "pnnx.Output") {
424+
this->output_operators_maps_.insert({kOperator->name, kOperator});
425+
} else {
426+
// 以后的课中加layer的
427+
}
428+
}
429+
RuntimeGraphShape::InitOperatorInputTensor(operators_);
430+
RuntimeGraphShape::InitOperatorOutputTensor(graph_->ops, operators_);
431+
graph_state_ = GraphState::Complete;
432+
input_name_ = input_name;
433+
output_name_ = output_name;
434+
}
245435
}

test/test_init_inoutput.cpp

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
//
2+
// Created by yizhu on 2023/2/13.
3+
//
4+
#include <glog/logging.h>
5+
#include <gtest/gtest.h>
6+
#include "runtime/runtime_ir.hpp"
7+
8+
TEST(test_initinoutput, init_init_input) {
9+
using namespace kuiper_infer;
10+
const std::string &param_path = "./tmp/test.pnnx.param";
11+
const std::string &bin_path = "./tmp/test.pnnx.bin";
12+
RuntimeGraph graph(param_path, bin_path);
13+
graph.Init();
14+
const auto operators = graph.operators();
15+
for (const auto &operator_ : operators) {
16+
LOG(INFO) << "type: " << operator_->type << " name: " << operator_->name;
17+
const std::map<std::string, std::shared_ptr<RuntimeOperand>> &
18+
input_operands_map = operator_->input_operands;
19+
for (const auto &input_operand : input_operands_map) {
20+
LOG(INFO) << "operand name: " << input_operand.first << " operand shape: ";
21+
for (const auto &dim : input_operand.second->shapes) {
22+
LOG(INFO) << dim << " ";
23+
}
24+
}
25+
}
26+
27+
LOG(INFO) << "---------------------------------------";
28+
}

0 commit comments

Comments
 (0)