Skip to content

Commit 097b250

Browse files
committed
[microNPU][4] Add the cascader Proposal generator
The Proposal generator takes optimal Plans and combines them to find optimal 'Proposals' - sets of disjoint Plans that cover every Part in a CascaderGraph. It ultimately produces a Pareto-frontier of 'optimal' Proposals in terms of estimated cycles and memory usage. Change-Id: Id42099819a596496a5769bae22f08eeb75ec69b6
1 parent 59dd0ec commit 097b250

File tree

11 files changed

+1183
-0
lines changed

11 files changed

+1183
-0
lines changed

python/tvm/contrib/ethosu/cascader/pareto.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121

2222
from . import _ffi_api
2323
from .plan import Plan
24+
from .proposal import Proposal
25+
from .tensor_config import MemoryRegion
2426

2527

2628
def get_pareto_frontier(costs: List[List[float]]) -> List[bool]:
@@ -37,3 +39,9 @@ def thin_vector(vec: List[Object], max_size: int) -> List[Object]:
3739

3840
def pareto_cull_plans(plans: List[Plan], max_plans: int) -> List[Plan]:
3941
return list(_ffi_api.ParetoCullPlans(plans, max_plans))
42+
43+
44+
def pareto_cull_proposals(
45+
proposals: List[Proposal], cascade_region: MemoryRegion, max_proposals: int
46+
) -> List[Proposal]:
47+
return list(_ffi_api.ParetoCullProposals(proposals, cascade_region, max_proposals))
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
# Licensed to the Apache Software Foundation (ASF) under one
2+
# or more contributor license agreements. See the NOTICE file
3+
# distributed with this work for additional information
4+
# regarding copyright ownership. The ASF licenses this file
5+
# to you under the Apache License, Version 2.0 (the
6+
# "License"); you may not use this file except in compliance
7+
# with the License. You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing,
12+
# software distributed under the License is distributed on an
13+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
# KIND, either express or implied. See the License for the
15+
# specific language governing permissions and limitations
16+
# under the License.
17+
"""Proposal class to hold graph scheduling information."""
18+
from typing import Dict, FrozenSet, List
19+
import tvm._ffi
20+
from tvm.contrib.ethosu.cascader.plan import Plan
21+
22+
from tvm.runtime import Object
23+
24+
from . import _ffi_api
25+
from .graph import Tensor, Part
26+
from .tensor_config import TensorConfig, MemoryRegion
27+
28+
29+
@tvm._ffi.register_object("contrib.ethosu.cascader.Proposal")
30+
class Proposal(Object):
31+
"""Proposal class"""
32+
33+
def __init__(
34+
self,
35+
part_group: FrozenSet[Part],
36+
plans: List[Plan],
37+
input_tensor_configs: Dict[Tensor, TensorConfig],
38+
memory_usage: Dict[MemoryRegion, int],
39+
cycles: int,
40+
):
41+
self.__init_handle_by_constructor__(
42+
_ffi_api.Proposal,
43+
list(part_group),
44+
plans,
45+
input_tensor_configs,
46+
memory_usage,
47+
cycles,
48+
)
49+
50+
@property
51+
def graph(self):
52+
return self._graph
53+
54+
@property
55+
def part_group(self):
56+
return frozenset(self._part_group)
57+
58+
@property
59+
def plans(self):
60+
return list(self._plans)
61+
62+
@property
63+
def input_tensor_configs(self):
64+
return dict(self._input_tensor_configs)
65+
66+
@property
67+
def memory_usage(self):
68+
return int(self._memory_usage)
69+
70+
@property
71+
def cycles(self):
72+
return int(self._cycles)
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
# Licensed to the Apache Software Foundation (ASF) under one
2+
# or more contributor license agreements. See the NOTICE file
3+
# distributed with this work for additional information
4+
# regarding copyright ownership. The ASF licenses this file
5+
# to you under the Apache License, Version 2.0 (the
6+
# "License"); you may not use this file except in compliance
7+
# with the License. You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing,
12+
# software distributed under the License is distributed on an
13+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
# KIND, either express or implied. See the License for the
15+
# specific language governing permissions and limitations
16+
# under the License.
17+
"""Algorithms to generate Proposals for a Graph."""
18+
from typing import List, Dict, FrozenSet
19+
20+
from . import _ffi_api
21+
from .cascader_options import CascaderOptions
22+
from .plan import Plan
23+
from .proposal import Proposal
24+
from .graph import CascaderGraph, Part
25+
26+
27+
def generate_proposals(
28+
graph: CascaderGraph,
29+
home_map: Dict[FrozenSet[Part], List[Plan]],
30+
options: CascaderOptions,
31+
) -> List[Proposal]:
32+
return list(
33+
_ffi_api.GenerateProposals(
34+
graph,
35+
home_map,
36+
options,
37+
)
38+
)

src/contrib/ethosu/cascader/pareto.cc

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@
2929

3030
#include "common.h"
3131
#include "plan.h"
32+
#include "proposal.h"
33+
#include "tensor_config.h"
3234

3335
namespace tvm {
3436
namespace contrib {
@@ -106,6 +108,31 @@ std::vector<Plan> ParetoCullPlans(std::vector<Plan> plans, size_t max_plans) {
106108
return ThinVector(optimal_plans, max_plans);
107109
}
108110

111+
std::vector<Proposal> ParetoCullProposals(std::vector<Proposal> proposals, size_t max_proposals) {
112+
std::sort(proposals.begin(), proposals.end(), [](const Proposal& a, const Proposal& b) -> bool {
113+
return a->GetMemoryUsage() < b->GetMemoryUsage();
114+
});
115+
std::vector<std::array<float, 2>> costs;
116+
for (const auto& proposal : proposals) {
117+
std::array<float, 2> cost = {static_cast<float>(proposal->GetMemoryUsage()),
118+
static_cast<float>(proposal->GetCycles())};
119+
costs.emplace_back(cost);
120+
}
121+
std::vector<bool> is_optimal = GetParetoFrontier<2>(costs);
122+
std::vector<Proposal> optimal_proposals;
123+
size_t i = 0;
124+
for (bool optimal : is_optimal) {
125+
if (optimal) {
126+
optimal_proposals.push_back(proposals[i]);
127+
}
128+
i++;
129+
}
130+
if (optimal_proposals.size() <= max_proposals) {
131+
return optimal_proposals;
132+
}
133+
return ThinVector(optimal_proposals, max_proposals);
134+
}
135+
109136
TVM_REGISTER_GLOBAL("contrib.ethosu.cascader.GetParetoFrontier")
110137
.set_body_typed([](Array<Array<FloatImm>> tcosts) {
111138
std::vector<std::array<float, 2>> costs;
@@ -134,6 +161,12 @@ TVM_REGISTER_GLOBAL("contrib.ethosu.cascader.ParetoCullPlans")
134161
return Array<Plan>(ParetoCullPlans(vplans, max_size));
135162
});
136163

164+
TVM_REGISTER_GLOBAL("contrib.ethosu.cascader.ParetoCullProposals")
165+
.set_body_typed([](Array<Proposal> proposals, int max_size) {
166+
std::vector<Proposal> vproposals(proposals.begin(), proposals.end());
167+
return Array<Proposal>(ParetoCullProposals(vproposals, max_size));
168+
});
169+
137170
} // namespace cascader
138171
} // namespace ethosu
139172
} // namespace contrib

src/contrib/ethosu/cascader/pareto.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ namespace ethosu {
3737
namespace cascader {
3838

3939
class Plan;
40+
class MemoryRegion;
41+
class Proposal;
4042

4143
/*!
4244
* \brief Determine the Pareto optimal points.
@@ -65,6 +67,8 @@ std::vector<T> ThinVector(const std::vector<T>& vec, size_t max_size);
6567
*/
6668
std::vector<Plan> ParetoCullPlans(std::vector<Plan> plans, size_t max_plans);
6769

70+
std::vector<Proposal> ParetoCullProposals(std::vector<Proposal> proposals, size_t max_proposals);
71+
6872
} // namespace cascader
6973
} // namespace ethosu
7074
} // namespace contrib
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
#include "proposal.h"
20+
21+
#include <tvm/runtime/container/array.h>
22+
#include <tvm/runtime/container/map.h>
23+
#include <tvm/runtime/object.h>
24+
#include <tvm/runtime/registry.h>
25+
26+
#include <utility>
27+
#include <vector>
28+
29+
#include "plan.h"
30+
31+
namespace tvm {
32+
namespace contrib {
33+
namespace ethosu {
34+
namespace cascader {
35+
36+
void ProposalNode::VisitAttrs(AttrVisitor* v) {
37+
v->Visit("_graph", &graph_);
38+
Array<Part> tmp_parts(part_group_.begin(), part_group_.end());
39+
v->Visit("_part_group", &tmp_parts);
40+
Array<Plan> tmp_plans(plans_.begin(), plans_.end());
41+
v->Visit("_plans", &tmp_plans);
42+
Map<Tensor, TensorConfig> tmp_tmap(input_tensor_configs_.begin(), input_tensor_configs_.end());
43+
v->Visit("_input_tensor_configs", &tmp_tmap);
44+
v->Visit("_cascade_region", &cascade_region_);
45+
v->Visit("_memory_usage", &memory_usage_);
46+
v->Visit("_cycles", &cycles_);
47+
}
48+
49+
Proposal::Proposal(const CascaderGraph& graph, const std::vector<Part>& part_group,
50+
const std::vector<Plan>& plans, const TensorConfigMap& input_tensor_configs,
51+
const MemoryRegion& cascade_region, int memory_usage, int cycles) {
52+
auto n = make_object<ProposalNode>();
53+
n->graph_ = std::move(graph);
54+
n->part_group_ = std::move(part_group);
55+
std::sort(n->part_group_.begin(), n->part_group_.end());
56+
n->plans_ = std::move(plans);
57+
n->input_tensor_configs_ = std::move(input_tensor_configs);
58+
n->cascade_region_ = std::move(cascade_region);
59+
n->memory_usage_ = std::move(memory_usage);
60+
n->cycles_ = cycles;
61+
data_ = std::move(n);
62+
}
63+
64+
TVM_REGISTER_GLOBAL("contrib.ethosu.cascader.Proposal")
65+
.set_body_typed([](CascaderGraph graph, Array<Part> part_group, Array<Plan> plans,
66+
Map<Tensor, TensorConfig> input_tensor_configs, MemoryRegion cascade_region,
67+
int memory_usage, int cycles) {
68+
std::vector<Part> spart_group(part_group.begin(), part_group.end());
69+
std::vector<Plan> vplans(plans.begin(), plans.end());
70+
TensorConfigMap minput_tensor_configs(input_tensor_configs.begin(),
71+
input_tensor_configs.end());
72+
return Proposal(graph, spart_group, vplans, minput_tensor_configs, cascade_region,
73+
memory_usage, cycles);
74+
});
75+
76+
TVM_REGISTER_NODE_TYPE(ProposalNode);
77+
78+
} // namespace cascader
79+
} // namespace ethosu
80+
} // namespace contrib
81+
} // namespace tvm
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
20+
/*!
21+
* \file src/contrib/ethosu/cascader/proposal.h
22+
* \brief Proposal object for the NPU cascader
23+
*/
24+
#ifndef TVM_CONTRIB_ETHOSU_CASCADER_PROPOSAL_H_
25+
#define TVM_CONTRIB_ETHOSU_CASCADER_PROPOSAL_H_
26+
27+
#include <tvm/node/reflection.h>
28+
#include <tvm/runtime/object.h>
29+
30+
#include <unordered_map>
31+
#include <unordered_set>
32+
#include <vector>
33+
34+
#include "graph.h"
35+
#include "plan.h"
36+
#include "tensor_config.h"
37+
38+
namespace tvm {
39+
namespace contrib {
40+
namespace ethosu {
41+
namespace cascader {
42+
43+
using MemoryUsageMap = std::unordered_map<MemoryRegion, int, ObjectPtrHash, ObjectPtrEqual>;
44+
using TensorConfigMap = std::unordered_map<Tensor, TensorConfig, ObjectPtrHash, ObjectPtrEqual>;
45+
46+
/*! \brief Node to represent a Proposal */
47+
class ProposalNode : public Object {
48+
public:
49+
void VisitAttrs(AttrVisitor* v);
50+
51+
/*! \return The CascaderGraph to which the Proposal applies */
52+
const CascaderGraph GetGraph() const { return graph_; }
53+
/*! \return The Parts which are covered by the Proposal */
54+
const std::vector<Part> GetPartGroup() const { return part_group_; }
55+
/*! \return The Plans used in the Proposal */
56+
const std::vector<Plan> GetPlans() const { return plans_; }
57+
/*! \return The TensorConfigs indexed by Tensor in the Proposal which aren't produced by a Plan */
58+
const TensorConfigMap GetInputTensorConfigs() const { return input_tensor_configs_; }
59+
/*! \return The MemoryRegion where cascading buffers should be homed */
60+
const MemoryRegion GetCascadeRegion() const { return cascade_region_; }
61+
/*! \return The memory required to execute the Proposal in the cascading MemoryRegion */
62+
const int GetMemoryUsage() const { return memory_usage_; }
63+
/*! \return The estimated cycles taken to execute the Proposal */
64+
int GetCycles() const { return cycles_; }
65+
66+
static constexpr const char* _type_key = "contrib.ethosu.cascader.Proposal";
67+
TVM_DECLARE_FINAL_OBJECT_INFO(ProposalNode, Object);
68+
69+
protected:
70+
friend class Proposal;
71+
72+
/*! \brief The CascaderGraph to which the Proposal applies */
73+
CascaderGraph graph_;
74+
/*! \brief The Parts which are covered by the Proposal */
75+
std::vector<Part> part_group_;
76+
/*! \brief The Plans used in the Proposal */
77+
std::vector<Plan> plans_;
78+
/*! \brief The TensorConfigs indexed by Tensor in the Proposal which aren't produced by a Plan */
79+
TensorConfigMap input_tensor_configs_;
80+
/*! \brief The MemoryRegion where cascading buffers should be homed */
81+
MemoryRegion cascade_region_;
82+
/*! \brief The memory required to execute the Proposal in the cascading MemoryRegion */
83+
int memory_usage_;
84+
/*! \brief The estimated cycles taken to execute the Proposal */
85+
int cycles_;
86+
};
87+
88+
/*!
89+
* \brief A class which describes how to schedule a CascaderGraph as a series of disjoint Plans.
90+
*/
91+
class Proposal : public ObjectRef {
92+
public:
93+
Proposal(const CascaderGraph& graph, const std::vector<Part>& part_group,
94+
const std::vector<Plan>& plans, const TensorConfigMap& input_tensor_configs,
95+
const MemoryRegion& cascade_region, int memory_usage, int cycles);
96+
97+
TVM_DEFINE_OBJECT_REF_METHODS(Proposal, ObjectRef, ProposalNode);
98+
};
99+
100+
} // namespace cascader
101+
} // namespace ethosu
102+
} // namespace contrib
103+
} // namespace tvm
104+
105+
#endif // TVM_CONTRIB_ETHOSU_CASCADER_PROPOSAL_H_

0 commit comments

Comments
 (0)