From 980d3c23c9673637004d92e6b5b55506b83c520f Mon Sep 17 00:00:00 2001 From: jwu773 Date: Wed, 4 Feb 2026 17:12:26 +0800 Subject: [PATCH 1/3] AI compiler assigmnets my first commit --- .idea/.gitignore | 10 ++ .idea/TinyInfiniTensor.iml | 9 + .idea/misc.xml | 6 + .idea/modules.xml | 8 + .idea/vcs.xml | 8 + include/core/allocator.h | 2 +- include/core/graph.h | 1 + src/core/allocator.cc | 50 +++++- src/core/graph.cc | 165 ++++++++++++++++++ src/operators/concat.cc | 5 +- src/operators/matmul.cc | 22 ++- src/operators/transpose.cc | 7 +- src/operators/unary.cc | 14 +- src/utils/operator_utils.cc | 28 ++- .../nativecpu/test_nativecpu_concat.cc | 3 +- 15 files changed, 327 insertions(+), 11 deletions(-) create mode 100644 .idea/.gitignore create mode 100644 .idea/TinyInfiniTensor.iml create mode 100644 .idea/misc.xml create mode 100644 .idea/modules.xml create mode 100644 .idea/vcs.xml diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 00000000..ab1f4164 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,10 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Ignored default folder with query files +/queries/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml +# Editor-based HTTP Client requests +/httpRequests/ diff --git a/.idea/TinyInfiniTensor.iml b/.idea/TinyInfiniTensor.iml new file mode 100644 index 00000000..d6ebd480 --- /dev/null +++ b/.idea/TinyInfiniTensor.iml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 00000000..07115cdf --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 00000000..62de32f5 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 00000000..67a1dcf4 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/include/core/allocator.h b/include/core/allocator.h index 002601d2..f3ff75a0 100644 --- a/include/core/allocator.h +++ b/include/core/allocator.h @@ -27,7 +27,7 @@ namespace infini { // TODO:可能需要设计一个数据结构来存储free block,以便于管理和合并 // HINT: 可以使用一个 map 来存储 free block,key 为 block 的起始/结尾地址,value 为 block 的大小 // =================================== 作业 =================================== - + std::map freeByStart; public: Allocator(Runtime runtime); diff --git a/include/core/graph.h b/include/core/graph.h index c45580c2..4c534c8c 100644 --- a/include/core/graph.h +++ b/include/core/graph.h @@ -50,6 +50,7 @@ namespace infini * so the topological sorting fails. */ bool topo_sort(); + void reconstruct(Operator &op1, Operator &op2, Operator &op3); void optimize(); diff --git a/src/core/allocator.cc b/src/core/allocator.cc index ff593aef..47dd942d 100644 --- a/src/core/allocator.cc +++ b/src/core/allocator.cc @@ -32,8 +32,32 @@ namespace infini // =================================== 作业 =================================== // TODO: 设计一个算法来分配内存,返回起始地址偏移量 // =================================== 作业 =================================== + //std::cout<<" ******************* map size "<second >= size){ + freeBlkOk = true; + if(it->second > size) + freeByStart.insert({it->first + size, it->second - size}); + break; + } + } + + if(!freeBlkOk){ + it--; + size_t moreMem = size - it->second; + peak += moreMem; + } + freeByStart.erase(it); + return it->first; - return 0; } void Allocator::free(size_t addr, size_t size) @@ -44,6 +68,30 @@ namespace infini // =================================== 作业 =================================== // TODO: 设计一个算法来回收内存 // =================================== 作业 =================================== + auto it = freeByStart.begin(); + int flag = 0; + for(; it != freeByStart.end(); it++){ + if(it->first + it->second == addr){ + flag = -1; + break; + } + else if(it->first == addr + size){ + flag = 1; + break; + } + } + if(flag == -1){ + freeByStart.insert({it->first, it->second + size}); + freeByStart.erase(it); + } + else if(flag == 0){ + freeByStart.insert({addr, size}); + } + else if(flag == 1){ + freeByStart.insert({addr, size + it->second}); + freeByStart.erase(it); + } + used -= size; } void *Allocator::getPtr() diff --git a/src/core/graph.cc b/src/core/graph.cc index 3a906370..a873de47 100644 --- a/src/core/graph.cc +++ b/src/core/graph.cc @@ -2,6 +2,10 @@ #include #include #include +#include "operators/transpose.h" +#include "operators/matmul.h" +#include +#include namespace infini { @@ -98,6 +102,49 @@ namespace infini return this->sorted = true; } + bool transposeOpsCancel(vector a, vector b){ + if(a.size() != b.size()) + return false; + for(int i = 0; i < (int)a.size(); i++){ + if(b[a[i]] != i) + return false; + } + return true; + } + + bool transOpCanIntegrateToMatmul(vector perm){ + int size = perm.size(); + for(int i = 0; i < size - 2; i++){ + if(perm[i] != i) + return false; + } + if(perm[size - 2] != size - 1 || perm[size - 1] != size - 2) + return false; + else + return true; + } + + void GraphObj::reconstruct(Operator &op1, Operator &op2, Operator &op3){ + Tensor input = op1->getInputs(0); + if(input) {input->addTarget(op3);} + if(op2 == nullptr){ + op3->replaceInput(op1->getOutput(), input); + op1->removeSuccessors(op3); + op3->removePredecessors(op1); + op1->getOutput()->removeTarget(op3); + } + else{ + op3->replaceInput(op2->getOutput(), input); + op3->removePredecessors(op2); + op1->removeSuccessors(op2); + op1->getOutput()->removeTarget(op2); + } + for(auto &pred: op1->getPredecessors()){ + op3->addPredecessors(pred); + pred->addSuccessors(op3); + } + } + void GraphObj::optimize() { // =================================== 作业 =================================== @@ -106,6 +153,93 @@ namespace infini // 1. 去除冗余的算子(例如,两个相邻的算子都是 transpose 算子,且做的是相反的操作,可以将其全部删除) // 2. 合并算子(例如,矩阵乘算子中含有属性transA、transB,如果其输入存在transpose,且对最后两个维度做交换,就可以将transpose融入到矩阵乘算子的属性中去) // =================================== 作业 =================================== + std::unordered_set toDelete; + std::shared_ptr emptyPtr; + + for(auto &op: ops){ + if(toDelete.find(op.get()) != toDelete.end()){ + continue; + } + OpType opType = op->getOpType(); + //std::cout<<"..................... .....................OP................ ...................\n"; + //op->print(); + //std::cout<<"...................... ....................Op................. ....................\n"; + if(opType == OpType::Concat){ //case1:Concat + if(op->numInputs() == 1){ + toDelete.insert(op.get()); + for(auto &succ: op->getSuccessors()){ + reconstruct(op, emptyPtr, succ); + } + } + } + else if(opType == OpType::Transpose){ //case2:Transpose + TransposeObj* transOp = dynamic_cast(op.get()); + //std::cout<<"......2....OP is Transpose........"<getInputs(0); + for(auto &succ: op->getSuccessors()){ + if(succ->getOpType() == OpType::Transpose){ //case2.1:Transpose-->Transpose + TransposeObj* transSucc = dynamic_cast(succ.get()); + //std::cout<<".......2.1...successor is Transpose op.......\n"; + //transSucc->print(); + bool cancelOut = false; + if(transOp && transSucc){ + cancelOut = transposeOpsCancel(transOp->getPermute(), transSucc->getPermute()); + } + //std::cout<<"......2.1...successor is Transpose :they cancel? "<getOutput()); + for(auto &succ_succ: succ->getSuccessors()){ + reconstruct(op, succ, succ_succ); + } + if(op->getSuccessors().size() == 0){ + toDelete.insert(op.get()); + removeTensor(op->getOutput()); + if(input) {input->removeTarget(op);} + for(auto &pred: op->getPredecessors()) + pred->removeSuccessors(op); + } + } + } + else if(succ->getOpType() == OpType::MatMul){ //case2.2:Transpose-->MatMul + bool ok = transOpCanIntegrateToMatmul(transOp->getPermute()); + //std::cout<<"------2.2---successor is Matmul op, can integrate? "<(succ.get()); + if (matmulSucc){ + if(succ->getInputs(0)->getGuid() == op->getOutput()->getGuid()) + matmulSucc->setTransA(!(matmulSucc->getTransA())); + else + matmulSucc->setTransB(!(matmulSucc->getTransB())); + } + reconstruct(op, emptyPtr, succ); + if(op->getSuccessors().size() == 0){ + toDelete.insert(op.get()); + removeTensor(op->getOutput()); + if(input) {input->removeTarget(op);} + for(auto &pred: op->getPredecessors()) + pred->removeSuccessors(op); + } + } + } + } + } + } + //delete redundant operators + //std::cout<<" --------ooo--------- before optimize "<print(); + }**/ } Tensor GraphObj::getTensor(int fuid) const @@ -152,7 +286,38 @@ namespace infini // TODO:利用 allocator 给计算图分配内存 // HINT: 获取分配好的内存指针后,可以调用 tensor 的 setDataBlob 函数给 tensor 绑定内存 // =================================== 作业 =================================== + std::unordered_map tensorOffset; + for(auto &tensor: tensors){ + if(!tensor->getSource()) + tensorOffset.insert({tensor->getFuid(), allocator.alloc(tensor->getBytes())}); + } + std::unordered_set graphOutputsFuid; + for(auto &output: this->getOutputs()){ + graphOutputsFuid.insert(output->getFuid()); + } + for(auto &op: ops){ + for(auto &output: op->getOutputs()){ + tensorOffset.insert({output->getFuid(), allocator.alloc(output->getBytes())}); + } + for(auto input: op->getInputs()){ + if(input->getTargets().size() == 0){ + int fuid = input->getFuid(); + if(graphOutputsFuid.find(fuid) == graphOutputsFuid.end()){ + allocator.free(tensorOffset[fuid], input->getBytes()); + } + } + } + } + void *pointer = allocator.getPtr(); + for(auto &tensor: tensors){ + int fuid = tensor->getFuid(); + if(tensorOffset.count(fuid)){ + size_t offset = tensorOffset[fuid]; + auto blob = make_ref(runtime, pointer + offset); + tensor->setDataBlob(blob); + } + } allocator.info(); } diff --git a/src/operators/concat.cc b/src/operators/concat.cc index d1963308..7408414f 100644 --- a/src/operators/concat.cc +++ b/src/operators/concat.cc @@ -17,7 +17,10 @@ optional> ConcatObj::inferShape(const TensorVec &inputs) { // TODO:修改 dims,返回正确的 concat 后的 shape // REF: https://onnx.ai/onnx/operators/onnx__Concat.html#concat-13 // =================================== 作业 =================================== - + int n = inputs.size(); + for(int i = 1; i < n; i++){ + dims[dim] += inputs[i]->getDims()[dim]; + } return {{dims}}; } diff --git a/src/operators/matmul.cc b/src/operators/matmul.cc index 7a16ca27..b57063a8 100644 --- a/src/operators/matmul.cc +++ b/src/operators/matmul.cc @@ -27,7 +27,27 @@ namespace infini // TODO:返回经过 matmul 操作后的 shape // REF: https://github.com/onnx/onnx/blob/main/docs/Operators.md#gemm // =================================== 作业 =================================== - return std::nullopt; + const auto A = inputs[0]; + auto a_dim = A->getDims(); + const auto B = inputs[1]; + auto b_dim = B->getDims(); + int size = a_dim.size(); + Shape res = a_dim; + //multi-dimensional broadcasting except for the last two dimensions + for(int i = 0; i < size - 2; i++){ + if(a_dim[i] < b_dim[i]) + res[i] = b_dim[i]; + } + + if(transA) + res[size - 2] = a_dim[size - 1]; + if(transB) + res[size - 1] = b_dim[size - 2]; + else + res[size - 1] = b_dim[size - 1]; + + std::vector vec {res}; + return vec; } } // namespace infini \ No newline at end of file diff --git a/src/operators/transpose.cc b/src/operators/transpose.cc index faab2b69..8379a9c5 100644 --- a/src/operators/transpose.cc +++ b/src/operators/transpose.cc @@ -33,8 +33,13 @@ namespace infini // TODO:修改 output_dim,返回正确的 transpose 后的 shape // REF: https://onnx.ai/onnx/operators/onnx__Transpose.html#transpose-21 // =================================== 作业 =================================== + for (int i = 0; i < rank; i++){ + output_dim[i] = input_dim[transposePermute[i]]; + } + std::vector res {output_dim}; + return res; - return std::nullopt; + //return std::nullopt; } std::string TransposeObj::toString() const diff --git a/src/operators/unary.cc b/src/operators/unary.cc index 3daad361..ceb50bcb 100644 --- a/src/operators/unary.cc +++ b/src/operators/unary.cc @@ -39,7 +39,9 @@ namespace infini // TODO:返回经过 clip 操作后的 shape // REF: https://onnx.ai/onnx/operators/onnx__Clip.html#clip-13 // =================================== 作业 =================================== - return std::nullopt; + const auto A = inputs[0]; + return {{A->getDims()}}; + //return std::nullopt; } std::string ClipObj::toString() const @@ -66,7 +68,11 @@ namespace infini // REF_FILE: src/core/operator.cc // REF: https://onnx.ai/onnx/operators/onnx__Cast.html#cast-21 // =================================== 作业 =================================== - return {}; + DataType outputType = getOutputDataType(); + int num = inputs.size(); + std::vector res(num, outputType); + return res; + //return {}; } optional> CastObj::inferShape(const TensorVec &inputs) @@ -75,7 +81,9 @@ namespace infini // TODO:返回经过 cast 操作后的 shape // REF: https://onnx.ai/onnx/operators/onnx__Cast.html#cast-21 // =================================== 作业 =================================== - return std::nullopt; + const auto A = inputs[0]; + return {{A->getDims()}}; + //return std::nullopt; } std::string CastObj::toString() const diff --git a/src/utils/operator_utils.cc b/src/utils/operator_utils.cc index edbd2c82..37eab0d8 100644 --- a/src/utils/operator_utils.cc +++ b/src/utils/operator_utils.cc @@ -9,8 +9,32 @@ Shape infer_broadcast(const Shape &A, const Shape &B) { // TODO:对 A 和 B 进行双向广播,返回广播后的形状。 // REF: https://github.com/onnx/onnx/blob/main/docs/Broadcasting.md // =================================== 作业 =================================== - - return {}; + Shape res; + long unsigned int i = 0; + if(A.size() > B.size()){ + long unsigned int diff = A.size() - B.size(); + for(; i < diff; i++) + res.push_back(A[i]); + for(; i < A.size(); i++){ + if(A[i] == 1) + res.push_back(B[i-diff]); + else + res.push_back(A[i]); + } + } + else{ + long unsigned int diff = B.size() - A.size(); + for(; i < diff; i++) + res.push_back(B[i]); + for(; i < B.size(); i++){ + if(B[i] == 1) + res.push_back(A[i-diff]); + else + res.push_back(B[i]); + } + } + + return res; } int get_real_axis(const int &axis, const int &rank) { diff --git a/test/kernels/nativecpu/test_nativecpu_concat.cc b/test/kernels/nativecpu/test_nativecpu_concat.cc index fc87fb19..8e23bc96 100644 --- a/test/kernels/nativecpu/test_nativecpu_concat.cc +++ b/test/kernels/nativecpu/test_nativecpu_concat.cc @@ -18,8 +18,9 @@ TEST(Concat, NativeCpu) { t1->setData(IncrementalGenerator()); t2->setData(OneGenerator()); t3->setData(OneGenerator()); - runtime->run(g); + //std::cout<<" --------------###--------------- concat output\n"; + op->getOutput()->printData(); EXPECT_TRUE(op->getOutput()->equalData( vector{0, 1, 2, 1, 1, 1, 3, 4, 5, 1, 1, 1, 6, 7, 8, 1, 1, 1, 9, 10, 11, 1, 1, 1})); From bf78e135993e3a5d5331670a7e996707bdfbd14f Mon Sep 17 00:00:00 2001 From: jwu773 Date: Wed, 4 Feb 2026 17:22:52 +0800 Subject: [PATCH 2/3] compilerAssignments --- src/core/graph.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/core/graph.cc b/src/core/graph.cc index a873de47..dca2eef6 100644 --- a/src/core/graph.cc +++ b/src/core/graph.cc @@ -161,9 +161,9 @@ namespace infini continue; } OpType opType = op->getOpType(); - //std::cout<<"..................... .....................OP................ ...................\n"; + //std::cout<<"..................... .....................OP start................ ...................\n"; //op->print(); - //std::cout<<"...................... ....................Op................. ....................\n"; + //std::cout<<"...................... ....................Op end................. ....................\n"; if(opType == OpType::Concat){ //case1:Concat if(op->numInputs() == 1){ toDelete.insert(op.get()); From db61947d48556527f431cc444395494b4d4db8e8 Mon Sep 17 00:00:00 2001 From: jwu773 Date: Wed, 12 Aug 2026 18:12:19 +0800 Subject: [PATCH 3/3] ai compiler assignment 1 Christina --- include/core/allocator.h | 2 +- src/core/allocator.cc | 71 ++++---- src/core/graph.cc | 165 +++++++++--------- src/operators/transpose.cc | 2 - src/operators/unary.cc | 3 - .../nativecpu/test_nativecpu_concat.cc | 2 - 6 files changed, 114 insertions(+), 131 deletions(-) diff --git a/include/core/allocator.h b/include/core/allocator.h index f3ff75a0..5867c79e 100644 --- a/include/core/allocator.h +++ b/include/core/allocator.h @@ -27,7 +27,7 @@ namespace infini { // TODO:可能需要设计一个数据结构来存储free block,以便于管理和合并 // HINT: 可以使用一个 map 来存储 free block,key 为 block 的起始/结尾地址,value 为 block 的大小 // =================================== 作业 =================================== - std::map freeByStart; + std::map freeBlocksMap; public: Allocator(Runtime runtime); diff --git a/src/core/allocator.cc b/src/core/allocator.cc index 47dd942d..80ff93c0 100644 --- a/src/core/allocator.cc +++ b/src/core/allocator.cc @@ -32,32 +32,31 @@ namespace infini // =================================== 作业 =================================== // TODO: 设计一个算法来分配内存,返回起始地址偏移量 // =================================== 作业 =================================== - //std::cout<<" ******************* map size "< peak) + peak = used; + + if(freeBlocksMap.empty()){ return peak - size; } - bool freeBlkOk = false; //is there a free block large enough to alloc? - auto it = freeByStart.begin(); - for(; it != freeByStart.end(); it++){ + bool freeBlkOk = false; //是否存在足够大(>= size)的空闲内存块 + auto it = freeBlocksMap.begin(); + for(; it != freeBlocksMap.end(); it++){ if(it->second >= size){ freeBlkOk = true; if(it->second > size) - freeByStart.insert({it->first + size, it->second - size}); + freeBlocksMap.insert({it->first + size, it->second - size}); break; } } - if(!freeBlkOk){ it--; - size_t moreMem = size - it->second; - peak += moreMem; + size_t moreMemory = size - it->second; + peak += moreMemory; } - freeByStart.erase(it); + freeBlocksMap.erase(it); return it->first; - } void Allocator::free(size_t addr, size_t size) @@ -68,30 +67,30 @@ namespace infini // =================================== 作业 =================================== // TODO: 设计一个算法来回收内存 // =================================== 作业 =================================== - auto it = freeByStart.begin(); - int flag = 0; - for(; it != freeByStart.end(); it++){ - if(it->first + it->second == addr){ - flag = -1; - break; - } - else if(it->first == addr + size){ - flag = 1; - break; - } - } - if(flag == -1){ - freeByStart.insert({it->first, it->second + size}); - freeByStart.erase(it); - } - else if(flag == 0){ - freeByStart.insert({addr, size}); - } - else if(flag == 1){ - freeByStart.insert({addr, size + it->second}); - freeByStart.erase(it); - } - used -= size; + auto it = freeBlocksMap.begin(); + int flag = 0; + for(; it != freeBlocksMap.end(); it++){ //遍历空闲内存块,检查是否能与待回收内存合并成一个大内存块 + if(it->first + it->second == addr){ //可以与待回收内存合并,该空闲块在前,待回收内存在后 + flag = -1; + break; + } + else if(it->first == addr + size){ //可以与待回收内存合并,待回收内存在前,该空闲块在后, + flag = 1; + break; + } + } + if(flag == -1){ + freeBlocksMap.insert({it->first, it->second + size}); //因为可以合并,插入合并后的大内存块,删去原来内存块 + freeBlocksMap.erase(it); + } + else if(flag == 0){ //标记为0,说明以上遍历时没有找到能合并的空闲块 + freeBlocksMap.insert({addr, size}); + } + else if(flag == 1){ + freeBlocksMap.insert({addr, size + it->second}); + freeBlocksMap.erase(it); + } + used -= size; } void *Allocator::getPtr() diff --git a/src/core/graph.cc b/src/core/graph.cc index dca2eef6..92e0992d 100644 --- a/src/core/graph.cc +++ b/src/core/graph.cc @@ -9,7 +9,6 @@ namespace infini { - void GraphObj::addOperatorAndConnect(const Operator &op) { sorted = false; @@ -145,102 +144,85 @@ namespace infini } } - void GraphObj::optimize() - { +void GraphObj::optimize() +{ // =================================== 作业 =================================== // TODO: 设计一个算法来实现指定的图优化规则 // 图优化规则如下: // 1. 去除冗余的算子(例如,两个相邻的算子都是 transpose 算子,且做的是相反的操作,可以将其全部删除) // 2. 合并算子(例如,矩阵乘算子中含有属性transA、transB,如果其输入存在transpose,且对最后两个维度做交换,就可以将transpose融入到矩阵乘算子的属性中去) // =================================== 作业 =================================== - std::unordered_set toDelete; - std::shared_ptr emptyPtr; - + std::unordered_set toDelete; //待删除的算子 + std::shared_ptr emptyPtr; //有的情况下重构计算图时需要 + bool modified = true; + while(modified){ + modified = false; for(auto &op: ops){ - if(toDelete.find(op.get()) != toDelete.end()){ + if(toDelete.find(op.get()) != toDelete.end()){ //如果遍历到之前发现的待删除算子,略过 continue; } - OpType opType = op->getOpType(); - //std::cout<<"..................... .....................OP start................ ...................\n"; - //op->print(); - //std::cout<<"...................... ....................Op end................. ....................\n"; - if(opType == OpType::Concat){ //case1:Concat - if(op->numInputs() == 1){ - toDelete.insert(op.get()); - for(auto &succ: op->getSuccessors()){ - reconstruct(op, emptyPtr, succ); - } - } - } - else if(opType == OpType::Transpose){ //case2:Transpose - TransposeObj* transOp = dynamic_cast(op.get()); - //std::cout<<"......2....OP is Transpose........"<getInputs(0); - for(auto &succ: op->getSuccessors()){ - if(succ->getOpType() == OpType::Transpose){ //case2.1:Transpose-->Transpose - TransposeObj* transSucc = dynamic_cast(succ.get()); - //std::cout<<".......2.1...successor is Transpose op.......\n"; - //transSucc->print(); - bool cancelOut = false; - if(transOp && transSucc){ - cancelOut = transposeOpsCancel(transOp->getPermute(), transSucc->getPermute()); - } - //std::cout<<"......2.1...successor is Transpose :they cancel? "<getOpType(); + if(opType == OpType::Transpose){ + TransposeObj* transOp = dynamic_cast(op.get()); + Tensor input = op->getInputs(0); + for(auto &succ: op->getSuccessors()){ + if(succ->getOpType() == OpType::Transpose){ //优化情况1 去除冗余transpose算子:当两个相邻算子都是transpose且相反操作 + TransposeObj* transSucc = dynamic_cast(succ.get()); + bool cancelOut = false; //判断两个相邻transpose算子是否相反的操作,在transposeOpsCancel函数中进行 + if(transOp && transSucc){ + cancelOut = transposeOpsCancel(transOp->getPermute(), transSucc->getPermute()); + } + if(cancelOut){ toDelete.insert(succ.get()); removeTensor(succ->getOutput()); - for(auto &succ_succ: succ->getSuccessors()){ - reconstruct(op, succ, succ_succ); - } - if(op->getSuccessors().size() == 0){ + for(auto &succ_succ: succ->getSuccessors()){ + reconstruct(op, succ, succ_succ); + } + if(op->getSuccessors().size() == 0){ //如果第1个transpose只有一个后继算子(即第2个transpose),那么可以删除第1个transpose toDelete.insert(op.get()); + //删除第1个transpose时需要进行以下重构 removeTensor(op->getOutput()); if(input) {input->removeTarget(op);} for(auto &pred: op->getPredecessors()) pred->removeSuccessors(op); } - } - } - else if(succ->getOpType() == OpType::MatMul){ //case2.2:Transpose-->MatMul - bool ok = transOpCanIntegrateToMatmul(transOp->getPermute()); - //std::cout<<"------2.2---successor is Matmul op, can integrate? "<(succ.get()); + modified = true; + } + } + else if(succ->getOpType() == OpType::MatMul){ //优化情况2 合并transpose与MatMul:当MatMul算子中含有属性transA、transB,且transpose对最后两个维度做交换 + bool ok = transOpCanIntegrateToMatmul(transOp->getPermute()); //判断能否合并 + if(ok){ //即使能够合并,也不一定就能删除transpose,除非transpose只有matMul唯一一个后继结点 + MatmulObj* matmulSucc = dynamic_cast(succ.get()); if (matmulSucc){ if(succ->getInputs(0)->getGuid() == op->getOutput()->getGuid()) matmulSucc->setTransA(!(matmulSucc->getTransA())); else matmulSucc->setTransB(!(matmulSucc->getTransB())); } - reconstruct(op, emptyPtr, succ); - if(op->getSuccessors().size() == 0){ - toDelete.insert(op.get()); + reconstruct(op, emptyPtr, succ); //合并transpose与matMul时需要进行重构:将transpose的输入作为matMul的输入 + if(op->getSuccessors().size() == 0){ //如果transpose只有一个后继算子(即matMul)那么可以删除transpose。 size()==0是因为前面一步重构时已删去了两算子间的边 + toDelete.insert(op.get()); removeTensor(op->getOutput()); if(input) {input->removeTarget(op);} for(auto &pred: op->getPredecessors()) pred->removeSuccessors(op); } - } - } - } - } - } - //delete redundant operators - //std::cout<<" --------ooo--------- before optimize "<print(); - }**/ } + //删除之前遍历计算图时发现的冗余算子 + for(int i = 0; i < (int)ops.size();){ + if(toDelete.find(ops[i].get()) != toDelete.end()) + ops.erase(ops.begin() + i); + else + i++; + } + this->sorted = false; +} Tensor GraphObj::getTensor(int fuid) const { @@ -286,41 +268,50 @@ namespace infini // TODO:利用 allocator 给计算图分配内存 // HINT: 获取分配好的内存指针后,可以调用 tensor 的 setDataBlob 函数给 tensor 绑定内存 // =================================== 作业 =================================== - std::unordered_map tensorOffset; + std::unordered_map tensorOffset; //tensor在内存中的偏移量。 tensor id作为key,偏移量作为value + std::unordered_map tensorRefNum; //tensor被引用次数,即被多少个算子使用。tensor id作为key,被引用次数作为value + //记录每个张量的被引用次数 for(auto &tensor: tensors){ - if(!tensor->getSource()) - tensorOffset.insert({tensor->getFuid(), allocator.alloc(tensor->getBytes())}); + tensorRefNum[tensor->getFuid()] = static_cast(tensor->getTargets().size()); } - - std::unordered_set graphOutputsFuid; - for(auto &output: this->getOutputs()){ - graphOutputsFuid.insert(output->getFuid()); + //为input分配内存 + for(auto &g_input : getInputs()){ + tensorOffset[g_input->getFuid()] = allocator.alloc(g_input->getBytes()); //if(!tensor->getSource()) } + //遍历算子 for(auto &op: ops){ for(auto &output: op->getOutputs()){ - tensorOffset.insert({output->getFuid(), allocator.alloc(output->getBytes())}); + int id = output->getFuid(); + if(tensorOffset.find(id) == tensorOffset.end()) //确保不会重复分配 + tensorOffset[id] = allocator.alloc(output->getBytes()); } - for(auto input: op->getInputs()){ - if(input->getTargets().size() == 0){ - int fuid = input->getFuid(); - if(graphOutputsFuid.find(fuid) == graphOutputsFuid.end()){ - allocator.free(tensorOffset[fuid], input->getBytes()); + for(auto &input: op->getInputs()){ + int id = input->getFuid(); + if(tensorRefNum.find(id) != tensorRefNum.end()){ + tensorRefNum[id]--; + if(tensorRefNum[id] == 0){ //如果一个张量不再被使用((被引用次数是0),可以释放其内存 + auto it = tensorOffset.find(id); //释放前找到它在内存中的地址(偏移量) + if(it != tensorOffset.end()){ + allocator.free(tensorOffset[id], input->getBytes()); + //tensorOffset.erase(it); + } + tensorRefNum.erase(id); } } } } - void *pointer = allocator.getPtr(); + void *memPtr = allocator.getPtr(); for(auto &tensor: tensors){ - int fuid = tensor->getFuid(); - if(tensorOffset.count(fuid)){ - size_t offset = tensorOffset[fuid]; - auto blob = make_ref(runtime, pointer + offset); - tensor->setDataBlob(blob); - } + auto it = tensorOffset.find(tensor->getFuid()); + IT_ASSERT(it != tensorOffset.end()); + void *tensorPtr = static_cast(static_cast(memPtr) + it->second); + tensor->setDataBlob(make_ref(runtime, tensorPtr)); } + allocator.info(); } + Tensor GraphObj::addTensor(Shape dim, DataType dtype) { return tensors.emplace_back(make_ref(dim, dtype, runtime)); diff --git a/src/operators/transpose.cc b/src/operators/transpose.cc index 8379a9c5..31a009f1 100644 --- a/src/operators/transpose.cc +++ b/src/operators/transpose.cc @@ -38,8 +38,6 @@ namespace infini } std::vector res {output_dim}; return res; - - //return std::nullopt; } std::string TransposeObj::toString() const diff --git a/src/operators/unary.cc b/src/operators/unary.cc index ceb50bcb..c7a8c928 100644 --- a/src/operators/unary.cc +++ b/src/operators/unary.cc @@ -41,7 +41,6 @@ namespace infini // =================================== 作业 =================================== const auto A = inputs[0]; return {{A->getDims()}}; - //return std::nullopt; } std::string ClipObj::toString() const @@ -72,7 +71,6 @@ namespace infini int num = inputs.size(); std::vector res(num, outputType); return res; - //return {}; } optional> CastObj::inferShape(const TensorVec &inputs) @@ -83,7 +81,6 @@ namespace infini // =================================== 作业 =================================== const auto A = inputs[0]; return {{A->getDims()}}; - //return std::nullopt; } std::string CastObj::toString() const diff --git a/test/kernels/nativecpu/test_nativecpu_concat.cc b/test/kernels/nativecpu/test_nativecpu_concat.cc index 8e23bc96..c1b0fa81 100644 --- a/test/kernels/nativecpu/test_nativecpu_concat.cc +++ b/test/kernels/nativecpu/test_nativecpu_concat.cc @@ -19,8 +19,6 @@ TEST(Concat, NativeCpu) { t2->setData(OneGenerator()); t3->setData(OneGenerator()); runtime->run(g); - //std::cout<<" --------------###--------------- concat output\n"; - op->getOutput()->printData(); EXPECT_TRUE(op->getOutput()->equalData( vector{0, 1, 2, 1, 1, 1, 3, 4, 5, 1, 1, 1, 6, 7, 8, 1, 1, 1, 9, 10, 11, 1, 1, 1}));