You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

pass_level1.cpp 16 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410
  1. // Tencent is pleased to support the open source community by making ncnn available.
  2. //
  3. // Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved.
  4. //
  5. // Licensed under the BSD 3-Clause License (the "License"); you may not use this file except
  6. // in compliance with the License. You may obtain a copy of the License at
  7. //
  8. // https://opensource.org/licenses/BSD-3-Clause
  9. //
  10. // Unless required by applicable law or agreed to in writing, software distributed
  11. // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
  12. // CONDITIONS OF ANY KIND, either express or implied. See the License for the
  13. // specific language governing permissions and limitations under the License.
  14. #include <torch/csrc/jit/passes/quantization/helper.h>
  15. #include <torch/csrc/api/include/torch/version.h>
  16. #include "pass_level1.h"
  17. namespace pnnx {
  18. FuseModulePass::~FuseModulePass()
  19. {
  20. }
  21. void FuseModulePass::write(Operator* /*op*/, const std::shared_ptr<torch::jit::Graph>& /*graph*/) const
  22. {
  23. }
  24. void FuseModulePass::write(Operator* op, const std::shared_ptr<torch::jit::Graph>& graph, const torch::jit::Module& /*mod*/) const
  25. {
  26. write(op, graph);
  27. }
  28. static std::vector<const FuseModulePass*> g_global_pnnx_fuse_module_passes;
  29. const std::vector<const FuseModulePass*>& get_global_pnnx_fuse_module_passes()
  30. {
  31. return g_global_pnnx_fuse_module_passes;
  32. }
  33. FuseModulePassRegister::FuseModulePassRegister(const FuseModulePass* _pass)
  34. : pass(_pass)
  35. {
  36. g_global_pnnx_fuse_module_passes.push_back(pass);
  37. }
  38. FuseModulePassRegister::~FuseModulePassRegister()
  39. {
  40. delete pass;
  41. }
  42. void pass_level1(const torch::jit::Module& mod, const std::shared_ptr<torch::jit::Graph>& g, const std::vector<std::string>& module_operators, Graph& pg)
  43. {
  44. for (int i = 1; i < (int)g->inputs().size(); i++)
  45. {
  46. const auto& in = g->inputs()[i];
  47. char name[32];
  48. sprintf(name, "pnnx_input_%d", i - 1);
  49. Operator* op = pg.new_operator("pnnx.Input", name);
  50. Operand* r = pg.new_operand(in);
  51. r->producer = op;
  52. op->outputs.push_back(r);
  53. }
  54. std::map<std::string, std::string> class_type_to_names;
  55. int pnnx_unknown_index = 0;
  56. for (const auto& n : g->block()->nodes())
  57. {
  58. if (n->kind() == c10::prim::GetAttr)
  59. {
  60. // pass
  61. std::string name = n->s(torch::jit::attr::name);
  62. // std::string name = n->debugName();
  63. auto class_type = n->output(0)->type()->cast<torch::jit::ClassType>();
  64. if (class_type)
  65. {
  66. std::string class_type_str = class_type->str();
  67. class_type_to_names[class_type_str] = name;
  68. // class_type_to_names[class_type_str] = class_type_str + "." + name;
  69. }
  70. else
  71. {
  72. // Tensor from some class
  73. // Operator* op = pg.new_operator(n->kind().toDisplayString(), name);
  74. Operator* op = pg.new_operator("pnnx.Attribute", name);
  75. for (int i = 0; i < (int)n->outputs().size(); i++)
  76. {
  77. const auto& on = n->output(i);
  78. Operand* r = pg.new_operand(on);
  79. r->producer = op;
  80. op->outputs.push_back(r);
  81. }
  82. std::deque<std::string> module_names; // = split(n->input(0)->node()->s(torch::jit::attr::name), '.');
  83. {
  84. auto np = n->input(0)->node();
  85. while (np->hasAttribute(torch::jit::attr::name))
  86. {
  87. module_names.push_front(np->s(torch::jit::attr::name));
  88. np = np->input(0)->node();
  89. }
  90. }
  91. std::string wrapped_name;
  92. auto sub_mod = mod;
  93. for (auto module_name : module_names)
  94. {
  95. if (wrapped_name.size() > 0)
  96. wrapped_name = wrapped_name + "." + module_name;
  97. else
  98. wrapped_name = module_name;
  99. sub_mod = sub_mod.attr(module_name).toModule();
  100. }
  101. if (wrapped_name.empty())
  102. {
  103. // top-level module
  104. wrapped_name = name;
  105. }
  106. op->name = wrapped_name;
  107. // op->params["this"] = n->input(i)
  108. // sub_mod.dump(true, true, true);
  109. op->attrs[name] = sub_mod.attr(name).toTensor();
  110. }
  111. }
  112. else if (n->kind() == c10::prim::Constant) // || n->kind() == c10::prim::ListConstruct)
  113. {
  114. char name[32];
  115. sprintf(name, "pnnx_%d", pnnx_unknown_index++);
  116. Operator* op = pg.new_operator(n->kind().toDisplayString(), name);
  117. for (int i = 0; i < (int)n->inputs().size(); i++)
  118. {
  119. const auto& in = n->input(i);
  120. Operand* r = pg.get_operand(in->debugName());
  121. r->consumers.push_back(op);
  122. op->inputs.push_back(r);
  123. }
  124. for (int i = 0; i < (int)n->outputs().size(); i++)
  125. {
  126. const auto& on = n->output(i);
  127. Operand* r = pg.new_operand(on);
  128. r->producer = op;
  129. op->outputs.push_back(r);
  130. }
  131. op->params["value"] = n;
  132. if (op->params["value"].type == 8)
  133. {
  134. op->type = "pnnx.Attribute";
  135. op->params.erase("value");
  136. op->attrs[name] = n->t(torch::jit::attr::value);
  137. }
  138. }
  139. else if (n->kind() == c10::prim::CallMethod)
  140. {
  141. auto class_type = n->input(0)->type()->cast<torch::jit::ClassType>();
  142. // const std::string& name = n->s(torch::jit::attr::name);
  143. // fprintf(stderr, "call %s\n", class_type->str().c_str());
  144. std::string name = class_type_to_names[class_type->str()];
  145. std::string class_type_str = torch::jit::removeTorchMangle(class_type->str());
  146. std::string class_type_str_no_torch_prefix = class_type_str.substr(10);
  147. std::string optypename = class_type_str;
  148. for (const auto& ow : get_global_pnnx_fuse_module_passes())
  149. {
  150. if (class_type_str != ow->match_type_str())
  151. continue;
  152. optypename = ow->type_str();
  153. break;
  154. }
  155. if (optypename == class_type_str)
  156. {
  157. optypename = class_type_str_no_torch_prefix;
  158. }
  159. Operator* op = pg.new_operator(optypename, name);
  160. for (int i = 1; i < (int)n->inputs().size(); i++)
  161. {
  162. const auto& in = n->input(i);
  163. Operand* r = pg.get_operand(in->debugName());
  164. r->consumers.push_back(op);
  165. op->inputs.push_back(r);
  166. }
  167. for (int i = 0; i < (int)n->outputs().size(); i++)
  168. {
  169. const auto& on = n->output(i);
  170. Operand* r = pg.new_operand(on);
  171. r->producer = op;
  172. op->outputs.push_back(r);
  173. }
  174. // module operator
  175. if (std::find(module_operators.begin(), module_operators.end(), class_type_str_no_torch_prefix) != module_operators.end())
  176. {
  177. const std::string& function_name = n->s(torch::jit::attr::name);
  178. torch::jit::Function& function = class_type->getMethod(function_name);
  179. if (function.isGraphFunction())
  180. {
  181. int pnnx_moduleop_unknown_index = 0;
  182. #if TORCH_VERSION_MAJOR >= 2 || (TORCH_VERSION_MAJOR >= 1 && TORCH_VERSION_MINOR >= 11)
  183. torch::jit::Block* moduleop_block = toGraphFunction(function).graph()->block();
  184. #else
  185. torch::jit::Block* moduleop_block = function.graph()->block();
  186. #endif
  187. for (const auto& mn : moduleop_block->nodes())
  188. {
  189. if (mn->kind() == c10::prim::GetAttr)
  190. {
  191. std::string name = mn->s(torch::jit::attr::name);
  192. // std::string name = mn->debugName();
  193. auto class_type = mn->output(0)->type()->cast<torch::jit::ClassType>();
  194. if (!class_type)
  195. {
  196. std::deque<std::string> module_names; // = split(mn->input(0)->node()->s(torch::jit::attr::name), '.');
  197. {
  198. auto np = n->input(0)->node();
  199. while (np->hasAttribute(torch::jit::attr::name))
  200. {
  201. module_names.push_front(np->s(torch::jit::attr::name));
  202. np = np->input(0)->node();
  203. }
  204. }
  205. std::deque<std::string> module_names2;
  206. {
  207. auto np = mn->input(0)->node();
  208. while (np->hasAttribute(torch::jit::attr::name))
  209. {
  210. module_names2.push_front(np->s(torch::jit::attr::name));
  211. np = np->input(0)->node();
  212. }
  213. }
  214. for (auto x : module_names2)
  215. {
  216. module_names.push_back(x);
  217. }
  218. auto sub_mod = mod;
  219. for (auto module_name : module_names)
  220. {
  221. sub_mod = sub_mod.attr(module_name).toModule();
  222. }
  223. std::string wrapped_name;
  224. for (auto module_name : module_names2)
  225. {
  226. if (wrapped_name.size() > 0)
  227. wrapped_name = wrapped_name + "." + module_name;
  228. else
  229. wrapped_name = module_name;
  230. }
  231. if (wrapped_name.empty())
  232. {
  233. // top-level module
  234. wrapped_name = name;
  235. }
  236. else
  237. {
  238. wrapped_name = wrapped_name + "." + name;
  239. }
  240. op->attrs[wrapped_name] = sub_mod.attr(name).toTensor();
  241. }
  242. }
  243. else if (mn->kind() == c10::prim::Constant)
  244. {
  245. Parameter p(mn);
  246. if (p.type == 8)
  247. {
  248. char name[32];
  249. sprintf(name, "pnnx_%d", pnnx_moduleop_unknown_index++);
  250. op->attrs[name] = mn->t(torch::jit::attr::value);
  251. }
  252. }
  253. }
  254. }
  255. }
  256. else
  257. {
  258. for (const auto& ow : get_global_pnnx_fuse_module_passes())
  259. {
  260. if (class_type_str != ow->match_type_str())
  261. continue;
  262. auto class_type = n->input(0)->type()->cast<torch::jit::ClassType>();
  263. torch::jit::Function& function = class_type->getMethod(n->s(torch::jit::attr::name));
  264. std::deque<std::string> module_names; // = split(n->input(0)->node()->s(torch::jit::attr::name), '.');
  265. {
  266. auto np = n->input(0)->node();
  267. while (np->hasAttribute(torch::jit::attr::name))
  268. {
  269. module_names.push_front(np->s(torch::jit::attr::name));
  270. np = np->input(0)->node();
  271. }
  272. }
  273. std::string wrapped_name;
  274. auto sub_mod = mod;
  275. for (auto module_name : module_names)
  276. {
  277. if (wrapped_name.size() > 0)
  278. wrapped_name = wrapped_name + "." + module_name;
  279. else
  280. wrapped_name = module_name;
  281. sub_mod = sub_mod.attr(module_name).toModule();
  282. }
  283. op->name = wrapped_name;
  284. #if TORCH_VERSION_MAJOR >= 2 || (TORCH_VERSION_MAJOR >= 1 && TORCH_VERSION_MINOR >= 11)
  285. ow->write(op, toGraphFunction(function).graph(), sub_mod);
  286. #else
  287. ow->write(op, function.graph(), sub_mod);
  288. #endif
  289. break;
  290. }
  291. }
  292. }
  293. // else if (n->kind() == c10::prim::CallFunction)
  294. // {
  295. // fprintf(stderr, "function %s", n->kind().toDisplayString());
  296. //
  297. // AT_ASSERT(cur->input(0)->node()->kind() == c10::prim::Constant);
  298. // auto function_constant = cur->input(0)->node();
  299. // auto fun_type = function_constant->output()->type()->expect<torch::jit::FunctionType>();
  300. // if (!fun_type->function()->isGraphFunction())
  301. // {
  302. // continue;
  303. // }
  304. // cur->removeInput(0);
  305. //
  306. // fprintf(stderr, "inline function %s\n", fun_type->function()->name().c_str());
  307. //
  308. // GRAPH_UPDATE("Inlining function '", fun_type->function()->name(), "' to ", *cur);
  309. // GRAPH_UPDATE("Function body: ", *fun_type->function()->optimized_graph());
  310. // inlineCallTo(cur, fun_type->function(), false);
  311. // break;
  312. // }
  313. else
  314. {
  315. char name[32];
  316. sprintf(name, "pnnx_%d", pnnx_unknown_index++);
  317. Operator* op = pg.new_operator(n->kind().toDisplayString(), name);
  318. for (int i = 0; i < (int)n->inputs().size(); i++)
  319. {
  320. const auto& in = n->input(i);
  321. Operand* r = pg.get_operand(in->debugName());
  322. r->consumers.push_back(op);
  323. op->inputs.push_back(r);
  324. }
  325. for (int i = 0; i < (int)n->outputs().size(); i++)
  326. {
  327. const auto& on = n->output(i);
  328. Operand* r = pg.new_operand(on);
  329. r->producer = op;
  330. op->outputs.push_back(r);
  331. }
  332. }
  333. }
  334. for (int i = 0; i < (int)g->outputs().size(); i++)
  335. {
  336. const auto& in = g->outputs()[i];
  337. char name[32];
  338. sprintf(name, "pnnx_output_%d", i);
  339. Operator* op = pg.new_operator("pnnx.Output", name);
  340. Operand* r = pg.get_operand(in->debugName());
  341. r->consumers.push_back(op);
  342. op->inputs.push_back(r);
  343. }
  344. }
  345. } // namespace pnnx