forked from jiuyuan/InfiniTensor
feat: 图变换相关类分到单独文件中,并模板化。
划分子图时提供一个模板化的子图类型。 Signed-off-by: YdrMaster <ydrml@hotmail.com>
This commit is contained in:
parent
59a46f3ff9
commit
34f7d7e9ed
|
@ -9,7 +9,7 @@
|
|||
|
||||
## 代码解析
|
||||
|
||||
重要的文件是 [tensor.h](src/tensor.h) 和 [graph.h](src/graph.h)。
|
||||
重要的文件是 [tensor.h](src/tensor.h)、[graph.h](src/graph.h) 和 [mutation.h](src/mutation.h)。
|
||||
|
||||
tensor.h 提供了这个图表示中张量的定义。张量的结构由形状、数据类型和数据组成,并储存了在每个图上和算子的连接关系。张量的所有权由所有连接到张量的算子共享,因此其存在的唯一形式就是 `std::shared_ptr`,脱离共享所有权智能指针是没有意义的。通过向工厂函数直接传递形状、数据类型和数据,直接构造智能指针的张量,一旦所有连接到张量的算子释放,算子也被释放。
|
||||
|
||||
|
@ -19,6 +19,6 @@ tensor.h 提供了这个图表示中张量的定义。张量的结构由形状
|
|||
|
||||
同时,`Unigraph` 具有只增性。只能向其中增加算子,必须以拓扑序,不能移除,也不能修改算子的顺序。因此,算子在图中的序号是唯一的,每个图则持有一个唯一的 ID。因此,可以用 ID 来指示图,用序号指示算子(`OpRef`);用序号指示算子,再用序号指示张量(`TensorPos`)。图必须整体销毁,销毁时,其中所有算子控制的所有张量连接也会同时销毁。因此,不必维持不可独立存在的所有权关系。
|
||||
|
||||
`Partition`、`Mutation` 和 `Rating` 三个类用于支持图的规则优化。这三个类本质是一样的,这种定义是为了对优化的不同阶段实现编译时的约束——一轮优化必须按划分→突变→评价的顺序依次执行每个操作一次。
|
||||
mutation.h 的 `Partition`、`Mutation` 和 `Rating` 三个类用于支持图的规则优化。这三个类本质是一样的,这种定义是为了对优化的不同阶段实现编译时的约束——一轮优化必须按划分→突变→评价的顺序依次执行每个操作一次。
|
||||
|
||||
这些类中保存的是一个 `Mutant` 的二维数组。每个 `Mutant` 是子图的一种突变体,存储了子图结构和评分。内层数组表示每个子图的多个变体,外层数组表示每张图的多个子图。显然,`Partition` 输入完整的图,并构建外层数组的结构,`Mutation` 将填充内层数组。`Rating` 填充每个突变体的得分,然后从高到低排序。接下来可以用序号向量指导图的重建。
|
||||
|
|
|
@ -13,6 +13,7 @@ struct Data {
|
|||
// #ifdef USE_CUDA
|
||||
// void *gpu_data;
|
||||
// #endif
|
||||
|
||||
// #ifdef USE_BANG
|
||||
// void *mlu_data;
|
||||
// #endif
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
#include "graph.h"
|
||||
#include <unordered_set>
|
||||
|
||||
static size_t GRAPH_ID = 1;
|
||||
|
||||
|
@ -65,84 +64,3 @@ OpRef Unigraph::push_operator( // fmt: new line
|
|||
});
|
||||
return ans;
|
||||
}
|
||||
|
||||
bool Mutant::operator<(Mutant const &others) const {
|
||||
return this->score < others.score;
|
||||
}
|
||||
|
||||
bool Mutant::operator>(Mutant const &others) const {
|
||||
return this->score > others.score;
|
||||
}
|
||||
|
||||
Mutant::Mutant(Unigraph &&g) : graph(std::move(g)) {}
|
||||
Mutant::Mutant(Mutant &&others) : graph(std::move(others.graph)) {}
|
||||
Mutant &Mutant::operator=(Mutant &&others) {
|
||||
if (this != &others)
|
||||
this->graph = std::move(others.graph);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <class t> Vec<size_t> list_size(Vec<Vec<t>> const &list) {
|
||||
Vec<size_t> ans(list.size());
|
||||
std::transform(list.begin(), list.end(), ans.begin(),
|
||||
[](const auto &e) { return e.size(); });
|
||||
return ans;
|
||||
}
|
||||
|
||||
Partition::Partition(Unigraph &&g, Func const &f) {
|
||||
auto mutant = f(std::move(g));
|
||||
for (auto &sub : mutant)
|
||||
this->mutant.emplace_back().emplace_back(std::move(sub));
|
||||
}
|
||||
|
||||
Vec<size_t> Partition::size() const { return list_size(mutant); }
|
||||
|
||||
Mutation::Mutation(Partition &&p, Func const &f) : mutant(std::move(p.mutant)) {
|
||||
for (auto &sub : mutant)
|
||||
for (auto &m : f(sub.front().graph))
|
||||
sub.emplace_back(std::move(m));
|
||||
}
|
||||
|
||||
Vec<size_t> Mutation::size() const { return list_size(mutant); }
|
||||
|
||||
Rating::Rating(Mutation &&m, Func const &f) : mutant(std::move(m.mutant)) {
|
||||
for (auto &sub : mutant) {
|
||||
auto sum = 0.0f;
|
||||
for (auto &c : sub)
|
||||
sum += (c.score = f(c.graph));
|
||||
sum = std::abs(sum);
|
||||
for (auto &c : sub)
|
||||
c.score /= sum;
|
||||
std::sort(sub.begin(), sub.end(), std::greater<Mutant>());
|
||||
}
|
||||
}
|
||||
|
||||
Vec<size_t> Rating::size() const { return list_size(mutant); }
|
||||
|
||||
Unigraph Rating::build(Vec<size_t> const &indices) const {
|
||||
const auto size = indices.size();
|
||||
if (size != mutant.size())
|
||||
throw "indices size wrong";
|
||||
Unigraph ans;
|
||||
for (size_t i = 0; i < size; ++i)
|
||||
for (const auto &op : mutant.at(i).at(indices[i]).graph.operators)
|
||||
ans.push_operator(op.op_type, op.inputs, op.outputs);
|
||||
return ans;
|
||||
}
|
||||
|
||||
Vec<Unigraph> split_each(Unigraph &&g) {
|
||||
Vec<Unigraph> ans;
|
||||
for (auto &op : g.operators)
|
||||
ans.emplace_back().push_operator(op.op_type, op.inputs, op.outputs);
|
||||
return ans;
|
||||
}
|
||||
|
||||
float memory_usage(Unigraph const &g) {
|
||||
std::unordered_set<size_t> mark;
|
||||
uintptr_t memory;
|
||||
for (const auto &op : g.operators)
|
||||
for (const auto &t : op.outputs)
|
||||
if (mark.insert(reinterpret_cast<uintptr_t>(t.get())).second)
|
||||
memory += t->size();
|
||||
return 1e6f / static_cast<float>(memory);
|
||||
}
|
||||
|
|
109
try/src/graph.h
109
try/src/graph.h
|
@ -1,9 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include "data.h"
|
||||
#include "op_type.h"
|
||||
#include "tensor.h"
|
||||
#include <functional>
|
||||
|
||||
/// @brief a struct to represent an operator in the computation graph.
|
||||
/// The ownership of an `Operator` belongs to one `Unigraph`.
|
||||
|
@ -51,110 +49,3 @@ struct Unigraph {
|
|||
Vec<Arc<Tensor>> outputs //
|
||||
);
|
||||
};
|
||||
|
||||
/// @brief A candidate subgraph mutant.
|
||||
struct Mutant {
|
||||
/// @brief The mutated subgraph.
|
||||
Unigraph graph;
|
||||
|
||||
/// @brief A score representing the quality of the mutant.
|
||||
float score;
|
||||
|
||||
Mutant(Unigraph &&);
|
||||
Mutant(Mutant const &) = delete;
|
||||
Mutant(Mutant &&);
|
||||
|
||||
Mutant &operator=(Mutant const &) = delete;
|
||||
Mutant &operator=(Mutant &&);
|
||||
|
||||
bool operator<(Mutant const &others) const;
|
||||
bool operator>(Mutant const &others) const;
|
||||
};
|
||||
|
||||
class Mutation;
|
||||
class Rating;
|
||||
|
||||
/// @brief Partitioned subgraphs.
|
||||
struct Partition {
|
||||
/// @brief 2D vector of `Mutant` instances for each partitioned subgraph.
|
||||
Vec<Vec<Mutant>> mutant;
|
||||
|
||||
friend Mutation;
|
||||
|
||||
public:
|
||||
/// @brief A functional object that takes an unpartitioned graph as input
|
||||
/// and returns a vector of partitioned subgraphs.
|
||||
using Func = std::function<Vec<Unigraph>(Unigraph &&)>;
|
||||
|
||||
/// @brief Constructs a partitioned graph from an unpartitioned graph
|
||||
/// using a partitioning function.
|
||||
/// @param arg0 An unpartitioned graph.
|
||||
/// @param arg1 A function that takes an unpartitioned graph as input
|
||||
/// and returns a vector of partitioned subgraphs.
|
||||
Partition(Unigraph &&, Func const &);
|
||||
|
||||
/// @brief Returns mutant vector size.
|
||||
/// @return 2D vector size.
|
||||
Vec<size_t> size() const;
|
||||
};
|
||||
|
||||
/// @brief Generates mutants for every subgraph.
|
||||
class Mutation {
|
||||
/// @brief 2D vector of `Mutant` instances for each partitioned subgraph.
|
||||
Vec<Vec<Mutant>> mutant;
|
||||
|
||||
friend Rating;
|
||||
|
||||
public:
|
||||
/// @brief A functional object that takes a subgraph as input
|
||||
/// and returns a vector of mutated graphs.
|
||||
using Func = std::function<Vec<Unigraph>(Unigraph const &)>;
|
||||
|
||||
/// @brief Mutates every subgraph in a partitioned graph.
|
||||
/// @param arg0 The partitioned graph to be mutated.
|
||||
/// @param arg1 A function that takes a subgraph as input
|
||||
/// and returns a vector of mutated graphs.
|
||||
Mutation(Partition &&, Func const &);
|
||||
|
||||
/// @brief Returns mutant vector size.
|
||||
/// @return 2D vector size.
|
||||
Vec<size_t> size() const;
|
||||
};
|
||||
|
||||
/// @brief Rates each subgraph mutant.
|
||||
class Rating {
|
||||
/// @brief 2D vector of `Mutant` instances for each partitioned subgraph.
|
||||
Vec<Vec<Mutant>> mutant;
|
||||
|
||||
public:
|
||||
/// @brief A functional object that takes a mutated subgraph as input
|
||||
/// and returns its score.
|
||||
using Func = std::function<float(Unigraph const &)>;
|
||||
|
||||
/// @brief Rates every mutated subgraph with a `Rating::Func`.
|
||||
/// @param arg0 The mutated subgraphs to be rated.
|
||||
/// @param arg1 A function that takes a mutated subgraph as input
|
||||
/// and returns its score.
|
||||
Rating(Mutation &&, Func const &);
|
||||
|
||||
/// @brief Returns mutant vector size.
|
||||
/// @return 2D vector size.
|
||||
Vec<size_t> size() const;
|
||||
|
||||
/// @brief Builds `Unigraph` from the subgraphs
|
||||
/// with specified indices.
|
||||
/// @param arg0 Subgraph indices.
|
||||
/// @return Merged `Unigraph`.
|
||||
Unigraph build(Vec<size_t> const &) const;
|
||||
};
|
||||
|
||||
/// @brief Splits a graph into subgraphs, where each subgraph contains
|
||||
/// only one operator.
|
||||
/// @param arg0 An unpartitioned graph.
|
||||
/// @return A vector of individual subgraphs.
|
||||
Vec<Unigraph> split_each(Unigraph &&);
|
||||
|
||||
/// @brief Calculates the memory usage of a graph.
|
||||
/// @param arg0 The graph.
|
||||
/// @return The reciprocal of the total memory usage of the graph in bytes.
|
||||
float memory_usage(Unigraph const &);
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
#include "mutation.h"
|
||||
#include <unordered_set>
|
||||
|
||||
Vec<std::pair<Unigraph, SingleOperator>> split_each(Unigraph &&g) {
|
||||
Vec<std::pair<Unigraph, SingleOperator>> ans;
|
||||
for (auto &op : g.operators) {
|
||||
auto &[g, t] = ans.emplace_back();
|
||||
g.push_operator(op.op_type, op.inputs, op.outputs);
|
||||
}
|
||||
return ans;
|
||||
}
|
||||
|
||||
float memory_usage(Unigraph const &g) {
|
||||
std::unordered_set<size_t> mark;
|
||||
uintptr_t memory;
|
||||
for (const auto &op : g.operators)
|
||||
for (const auto &t : op.outputs)
|
||||
if (mark.insert(reinterpret_cast<uintptr_t>(t.get())).second)
|
||||
memory += t->size();
|
||||
return 1e6f / static_cast<float>(memory);
|
||||
}
|
|
@ -0,0 +1,167 @@
|
|||
#pragma once
|
||||
|
||||
#include "graph.h"
|
||||
#include <functional>
|
||||
|
||||
/// @brief A candidate subgraph mutant.
|
||||
struct Mutant {
|
||||
/// @brief The mutated subgraph.
|
||||
Unigraph graph;
|
||||
|
||||
/// @brief A score representing the quality of the mutant.
|
||||
float score;
|
||||
|
||||
Mutant(Unigraph &&g) : graph(std::move(g)) {}
|
||||
Mutant(Mutant const &) = delete;
|
||||
Mutant(Mutant &&others) : graph(std::move(others.graph)) {}
|
||||
|
||||
Mutant &operator=(Mutant const &) = delete;
|
||||
Mutant &operator=(Mutant &&others) {
|
||||
if (this != &others)
|
||||
this->graph = std::move(others.graph);
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
/// @brief A subgraph partition with `PartitionType`, will be mutated into
|
||||
/// multiple `Mutant`s.
|
||||
/// @tparam PartitionType To partition this subgraph.
|
||||
template <class PartitionType> struct SubGraph {
|
||||
Vec<Mutant> mutants;
|
||||
PartitionType type;
|
||||
};
|
||||
|
||||
template <class t> Vec<size_t> list_size(Vec<Vec<t>> const &);
|
||||
template <class PartitionType> class Mutation;
|
||||
template <class PartitionType> class Rating;
|
||||
|
||||
/// @brief Partitioned subgraphs.
|
||||
template <class PartitionType> struct Partition {
|
||||
/// @brief 2D vector of `Mutant` instances for each partitioned subgraph.
|
||||
Vec<SubGraph<PartitionType>> parts;
|
||||
|
||||
friend Mutation<PartitionType>;
|
||||
|
||||
public:
|
||||
/// @brief A functional object that takes an unpartitioned graph as input
|
||||
/// and returns a vector of partitioned subgraphs.
|
||||
using Func =
|
||||
std::function<Vec<std::pair<Unigraph, PartitionType>>(Unigraph &&)>;
|
||||
|
||||
/// @brief Constructs a partitioned graph from an unpartitioned graph
|
||||
/// using a partitioning function.
|
||||
/// @param g An unpartitioned graph.
|
||||
/// @param f A function that takes an unpartitioned graph as input
|
||||
/// and returns a vector of partitioned subgraphs.
|
||||
Partition(Unigraph &&g, Func const &f) {
|
||||
for (auto &[g_, t] : f(std::move(g))) {
|
||||
auto &sub = this->parts.emplace_back();
|
||||
sub.mutants.emplace_back(std::move(g_));
|
||||
sub.type = std::move(t);
|
||||
}
|
||||
}
|
||||
|
||||
/// @brief Returns mutant vector size.
|
||||
/// @return 2D vector size.
|
||||
Vec<size_t> size() const { return list_size(parts); }
|
||||
};
|
||||
|
||||
/// @brief Generates mutants for every subgraph.
|
||||
template <class PartitionType> class Mutation {
|
||||
/// @brief 2D vector of `Mutant` instances for each partitioned subgraph.
|
||||
Vec<SubGraph<PartitionType>> parts;
|
||||
|
||||
friend Rating<PartitionType>;
|
||||
|
||||
public:
|
||||
/// @brief A functional object that takes a subgraph as input
|
||||
/// and returns a vector of mutated graphs.
|
||||
using Func =
|
||||
std::function<Vec<Unigraph>(Unigraph const &, PartitionType const &)>;
|
||||
|
||||
/// @brief Mutates every subgraph in a partitioned graph.
|
||||
/// @param p The partitioned graph to be mutated.
|
||||
/// @param f A function that takes a subgraph as input
|
||||
/// and returns a vector of mutated graphs.
|
||||
Mutation(Partition<PartitionType> &&p, Func const &f)
|
||||
: parts(std::move(p.parts)) {
|
||||
for (auto &sub : parts)
|
||||
for (auto &m : f(sub.mutants.front().graph, sub.type))
|
||||
sub.mutants.emplace_back(std::move(m));
|
||||
}
|
||||
|
||||
/// @brief Returns mutant vector size.
|
||||
/// @return 2D vector size.
|
||||
Vec<size_t> size() const { return list_size(parts); }
|
||||
};
|
||||
|
||||
/// @brief Rates each subgraph mutant.
|
||||
template <class PartitionType> class Rating {
|
||||
/// @brief 2D vector of `Mutant` instances for each partitioned subgraph.
|
||||
Vec<SubGraph<PartitionType>> parts;
|
||||
|
||||
public:
|
||||
/// @brief A functional object that takes a mutated subgraph as input
|
||||
/// and returns its score.
|
||||
using Func = std::function<float(Unigraph const &)>;
|
||||
|
||||
/// @brief Rates every mutated subgraph with a `Rating::Func`.
|
||||
/// @param m The mutated subgraphs to be rated.
|
||||
/// @param f A function that takes a mutated subgraph as input
|
||||
/// and returns its score.
|
||||
Rating(Mutation<PartitionType> &&m, Func const &f)
|
||||
: parts(std::move(m.parts)) {
|
||||
for (auto &sub : parts) {
|
||||
auto sum = 0.0f;
|
||||
for (auto &c : sub.mutants)
|
||||
sum += (c.score = f(c.graph));
|
||||
sum = std::abs(sum);
|
||||
for (auto &c : sub.mutants)
|
||||
c.score /= sum;
|
||||
std::sort(
|
||||
sub.mutants.begin(), sub.mutants.end(),
|
||||
[](auto const &a, auto const &b) { return a.score > b.score; });
|
||||
}
|
||||
}
|
||||
|
||||
/// @brief Returns mutant vector size.
|
||||
/// @return 2D vector size.
|
||||
Vec<size_t> size() const { return list_size(parts); }
|
||||
|
||||
/// @brief Builds `Unigraph` from the subgraphs
|
||||
/// with specified indices.
|
||||
/// @param indices Subgraph indices.
|
||||
/// @return Merged `Unigraph`.
|
||||
Unigraph build(Vec<size_t> const &indices) const {
|
||||
const auto size = indices.size();
|
||||
if (size != parts.size())
|
||||
throw "indices size wrong";
|
||||
Unigraph ans;
|
||||
for (size_t i = 0; i < size; ++i)
|
||||
for (const auto &op :
|
||||
parts.at(i).mutants.at(indices[i]).graph.operators)
|
||||
ans.push_operator(op.op_type, op.inputs, op.outputs);
|
||||
return ans;
|
||||
}
|
||||
};
|
||||
|
||||
/// @brief Partition every operator as a `Unigraph`.
|
||||
struct SingleOperator {};
|
||||
|
||||
/// @brief Splits a graph into subgraphs, where each subgraph contains
|
||||
/// only one operator.
|
||||
/// @param arg0 An unpartitioned graph.
|
||||
/// @return A vector of individual subgraphs.
|
||||
Vec<std::pair<Unigraph, SingleOperator>> split_each(Unigraph &&);
|
||||
|
||||
/// @brief Calculates the memory usage of a graph.
|
||||
/// @param arg0 The graph.
|
||||
/// @return The reciprocal of the total memory usage of the graph in bytes.
|
||||
float memory_usage(Unigraph const &);
|
||||
|
||||
template <class t> Vec<size_t> list_size(Vec<SubGraph<t>> const &list) {
|
||||
Vec<size_t> ans(list.size());
|
||||
std::transform(list.begin(), list.end(), ans.begin(),
|
||||
[](const auto &e) { return e.mutants.size(); });
|
||||
return ans;
|
||||
}
|
|
@ -1,5 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
enum class OpType : uint16_t {
|
||||
Abs,
|
||||
Acos,
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#include "../src/graph.h"
|
||||
#include "../src/mutation.h"
|
||||
#include <iostream>
|
||||
#include <unordered_set>
|
||||
|
||||
|
@ -26,10 +26,11 @@ int main() {
|
|||
{c} // outputs
|
||||
);
|
||||
|
||||
auto p = Partition(std::move(g), split_each);
|
||||
auto m = Mutation(std::move(p),
|
||||
[](const auto &g) { return Vec<Unigraph>{}; });
|
||||
auto r = Rating(std::move(m), memory_usage);
|
||||
auto p = Partition<SingleOperator>(std::move(g), split_each);
|
||||
auto m = Mutation<SingleOperator>(
|
||||
std::move(p),
|
||||
[](const auto &g, const auto &t) { return Vec<Unigraph>{}; });
|
||||
auto r = Rating<SingleOperator>(std::move(m), memory_usage);
|
||||
auto ans = r.build(Vec<size_t>(r.size().size(), 0));
|
||||
|
||||
return 0;
|
||||
|
|
Loading…
Reference in New Issue