tengine.js 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979
  1. // Experimental
  2. var tengine = tengine || {};
  3. tengine.ModelFactory = class {
  4. match(context) {
  5. const stream = context.stream;
  6. if (stream.length > 4) {
  7. const buffer = stream.peek(2);
  8. if (buffer[0] < 4 && buffer[1] === 0) {
  9. return true;
  10. }
  11. }
  12. return false;
  13. }
  14. open(context) {
  15. return tengine.Metadata.open(context).then((metadata) => {
  16. const buffer = context.stream.peek();
  17. const majorVersion = buffer[0] | buffer[1] << 8;
  18. const minorVersion = buffer[2] | buffer[3] << 8;
  19. if (majorVersion !== 2) {
  20. throw new tengine.Error("Unsupported format version 'v" + majorVersion.toString() + "." + minorVersion.toString() + "'.");
  21. }
  22. return new tengine.Model(metadata, buffer);
  23. });
  24. }
  25. };
  26. tengine.Model = class {
  27. constructor(metadata, buffer) {
  28. const reader = new tengine.ModelFileReader(buffer);
  29. this._version = reader.version;
  30. this._source = reader.source;
  31. this._graphs = reader.graphs.map((graph) => new tengine.Graph(metadata, graph));
  32. }
  33. get format() {
  34. return "Tengine v" + this._version;
  35. }
  36. get source() {
  37. return this._source;
  38. }
  39. get graphs() {
  40. return this._graphs;
  41. }
  42. };
  43. tengine.Graph = class {
  44. constructor(metadata, graph) {
  45. this._name = graph.id.toString();
  46. this._inputs = [];
  47. this._outputs = [];
  48. this._nodes = [];
  49. const tensors = graph.tensors.map((tensor) => new tengine.Argument(tensor));
  50. for (const input of graph.inputs) {
  51. const node = graph.nodes[input];
  52. this._inputs.push(new tengine.Parameter(node.name, true, node.outputs.map((output) => tensors[output])));
  53. }
  54. for (const output of graph.outputs) {
  55. const node = graph.nodes[output];
  56. this._outputs.push(new tengine.Parameter(node.name, true, node.outputs.map((output) => tensors[output])));
  57. }
  58. for (const node of graph.nodes) {
  59. switch (node.type) {
  60. case 'INPUT':
  61. case 'Const':
  62. break;
  63. default:
  64. this._nodes.push(new tengine.Node(metadata, node, tensors));
  65. break;
  66. }
  67. }
  68. }
  69. get name() {
  70. return this._name;
  71. }
  72. get inputs() {
  73. return this._inputs;
  74. }
  75. get outputs() {
  76. return this._outputs;
  77. }
  78. get nodes() {
  79. return this._nodes;
  80. }
  81. };
  82. tengine.Parameter = class {
  83. constructor(name, visible, args) {
  84. this._name = name;
  85. this._visible = visible;
  86. this._arguments = args;
  87. }
  88. get name() {
  89. return this._name;
  90. }
  91. get visible() {
  92. return this._visible;
  93. }
  94. get arguments() {
  95. return this._arguments;
  96. }
  97. };
  98. tengine.Argument = class {
  99. constructor(tensor) {
  100. this._name = tensor.name;
  101. this._type = new tengine.TensorType(tensor.dataType, new tengine.TensorShape(tensor.dims));
  102. this._initializer = (tensor.type === 2) ? new tengine.Tensor(this._type, tensor.buffer) : null;
  103. }
  104. get name() {
  105. return this._name;
  106. }
  107. get type() {
  108. if (this._initializer) {
  109. return this._initializer.type;
  110. }
  111. return this._type;
  112. }
  113. get quantization() {
  114. return null;
  115. }
  116. get initializer() {
  117. return this._initializer;
  118. }
  119. };
  120. tengine.Node = class {
  121. constructor(metadata, node, tensors) {
  122. this._metadata = metadata;
  123. this._name = node.name;
  124. this._type = node.type; + (node.version && node.version !== 1 ? ':' + node.version.toString() : '');
  125. this._version = node.version;
  126. this._inputs = [];
  127. this._outputs = [];
  128. this._attributes = [];
  129. const schema = metadata.type(this._type, this._version);
  130. for (let i = 0; i < node.params.length; i++) {
  131. const attributeSchema = (schema && schema.attributes && i < schema.attributes.length) ? schema.attributes[i] : null;
  132. const attributeName = attributeSchema ? attributeSchema.name : i.toString();
  133. this._attributes.push(new tengine.Attribute(attributeSchema, attributeName, node.params[i]));
  134. }
  135. const inputs = node.inputs;
  136. let inputIndex = 0;
  137. if (schema && schema.inputs) {
  138. for (const inputDef of schema.inputs) {
  139. if (inputIndex < inputs.length || inputDef.option != 'optional') {
  140. const inputCount = (inputDef.option == 'variadic') ? (inputs.length - inputIndex) : 1;
  141. const inputArguments = inputs.slice(inputIndex, inputIndex + inputCount).filter((id) => id != '' || inputDef.option != 'optional').map((id) => tensors[id]);
  142. this._inputs.push(new tengine.Parameter(inputDef.name, true, inputArguments));
  143. inputIndex += inputCount;
  144. }
  145. }
  146. }
  147. else {
  148. this._inputs.push(...inputs.slice(inputIndex).map((id, index) => {
  149. const inputName = ((inputIndex + index) == 0) ? 'input' : (inputIndex + index).toString();
  150. return new tengine.Parameter(inputName, true, [ tensors[id] ]);
  151. }));
  152. }
  153. const outputs = node.outputs;
  154. let outputIndex = 0;
  155. if (schema && schema.outputs) {
  156. for (const outputDef of schema.outputs) {
  157. if (outputIndex < outputs.length || outputDef.option != 'optional') {
  158. const outputCount = (outputDef.option == 'variadic') ? (outputs.length - outputIndex) : 1;
  159. const outputArguments = outputs.slice(outputIndex, outputIndex + outputCount).map((id) => tensors[id]);
  160. this._outputs.push(new tengine.Parameter(outputDef.name, true, outputArguments));
  161. outputIndex += outputCount;
  162. }
  163. }
  164. }
  165. else {
  166. this._outputs.push(...outputs.slice(outputIndex).map((id, index) => {
  167. const outputName = ((outputIndex + index) == 0) ? 'output' : (outputIndex + index).toString();
  168. return new tengine.Parameter(outputName, true, [ tensors[id] ]);
  169. }));
  170. }
  171. }
  172. get type() {
  173. return this._type;
  174. }
  175. get name() {
  176. return this._name;
  177. }
  178. get metadata() {
  179. return this._metadata.type(this._type, this._version);
  180. }
  181. get attributes() {
  182. return this._attributes;
  183. }
  184. get inputs() {
  185. return this._inputs;
  186. }
  187. get outputs() {
  188. return this._outputs;
  189. }
  190. };
  191. tengine.Attribute = class {
  192. constructor(schema, key, value) {
  193. this._type = '';
  194. this._name = key;
  195. this._value = value;
  196. if (schema) {
  197. this._name = schema.name;
  198. if (schema.type) {
  199. this._type = schema.type;
  200. }
  201. if (Object.prototype.hasOwnProperty.call(schema, 'visible') && !schema.visible) {
  202. this._visible = false;
  203. }
  204. else if (Object.prototype.hasOwnProperty.call(schema, 'default')) {
  205. if (this._value == schema.default || (this._value && this._value.toString() == schema.default.toString())) {
  206. this._visible = false;
  207. }
  208. }
  209. }
  210. }
  211. get type() {
  212. return this._type;
  213. }
  214. get name() {
  215. return this._name;
  216. }
  217. get value() {
  218. return this._value;
  219. }
  220. get visible() {
  221. return this._visible == false ? false : true;
  222. }
  223. };
  224. tengine.Tensor = class {
  225. constructor(type, data, kind) {
  226. this._type = type;
  227. this._data = data;
  228. this._kind = kind;
  229. }
  230. get kind() {
  231. return this._kind;
  232. }
  233. get type() {
  234. return this._type;
  235. }
  236. get state() {
  237. return this._context().state || null;
  238. }
  239. get value() {
  240. const context = this._context();
  241. if (context.state) {
  242. return null;
  243. }
  244. context.limit = Number.MAX_SAFE_INTEGER;
  245. return this._decode(context, 0);
  246. }
  247. toString() {
  248. const context = this._context();
  249. if (context.state) {
  250. return '';
  251. }
  252. context.limit = 10000;
  253. const value = this._decode(context, 0);
  254. return JSON.stringify(value, null, 4);
  255. }
  256. _context() {
  257. const context = {};
  258. context.index = 0;
  259. context.count = 0;
  260. context.state = null;
  261. if (this._type.dataType == '?') {
  262. context.state = 'Tensor has unknown data type.';
  263. return context;
  264. }
  265. if (!this._type.shape || (this._type.shape.dimensions && this._type.shape.dimensions.length == 0)) {
  266. context.state = 'Tensor has no dimensions.';
  267. return context;
  268. }
  269. if (!this._data) {
  270. context.state = 'Tensor data is empty.';
  271. return context;
  272. }
  273. switch (this._type.dataType) {
  274. case 'int8':
  275. case 'uint8':
  276. case 'float16':
  277. case 'float32':
  278. case 'int32':
  279. case 'int16':
  280. context.data = new DataView(this._data.buffer, this._data.byteOffset, this._data.byteLength);
  281. break;
  282. default:
  283. context.state = 'Tensor data type is not implemented.';
  284. break;
  285. }
  286. context.dataType = this._type.dataType;
  287. context.shape = this._type.shape.dimensions;
  288. return context;
  289. }
  290. _decode(context, dimension) {
  291. const shape = context.shape.length == 0 ? [ 1 ] : context.shape;
  292. const results = [];
  293. const size = shape[dimension];
  294. if (dimension == shape.length - 1) {
  295. for (let i = 0; i < size; i++) {
  296. if (context.count > context.limit) {
  297. results.push('...');
  298. return results;
  299. }
  300. switch (this._type.dataType) {
  301. case 'float32':
  302. results.push(context.data.getFloat32(context.index, true));
  303. context.index += 4;
  304. context.count++;
  305. break;
  306. case 'float16':
  307. results.push(context.data.getFloat16(context.index, true));
  308. context.index += 2;
  309. context.count++;
  310. break;
  311. case 'int8':
  312. results.push(context.data.getInt8(context.index, true));
  313. context.index += 1;
  314. context.count++;
  315. break;
  316. case 'uint8':
  317. results.push(context.data.getUint8(context.index, true));
  318. context.index += 1;
  319. context.count++;
  320. break;
  321. case 'int32':
  322. results.push(context.data.getInt32(context.index, true));
  323. context.index += 4;
  324. context.count++;
  325. break;
  326. case 'int16':
  327. results.push(context.data.getInt16(context.index, true));
  328. context.index += 2;
  329. context.count++;
  330. break;
  331. }
  332. }
  333. }
  334. else {
  335. for (let j = 0; j < size; j++) {
  336. if (context.count > context.limit) {
  337. results.push('...');
  338. return results;
  339. }
  340. results.push(this._decode(context, dimension + 1));
  341. }
  342. }
  343. if (context.shape.length == 0) {
  344. return results[0];
  345. }
  346. return results;
  347. }
  348. };
  349. tengine.TensorType = class {
  350. constructor(dataType, shape) {
  351. switch (dataType) {
  352. case 0: this._dataType = 'float32'; break;
  353. case 1: this._dataType = 'float16'; break;
  354. case 2: this._dataType = 'int8'; break;
  355. case 3: this._dataType = 'uint8'; break;
  356. case 4: this._dataType = 'int32'; break;
  357. case 5: this._dataType = 'int16'; break;
  358. default: throw new tengine.Error("Unknown data type'" + dataType + "'.");
  359. }
  360. this._shape = shape;
  361. }
  362. get dataType() {
  363. return this._dataType;
  364. }
  365. get shape() {
  366. return this._shape;
  367. }
  368. toString() {
  369. return this._dataType + this._shape.toString();
  370. }
  371. };
  372. tengine.TensorShape = class {
  373. constructor(dimensions) {
  374. this._dimensions = dimensions;
  375. }
  376. get dimensions() {
  377. return this._dimensions;
  378. }
  379. toString() {
  380. return this._dimensions ? ('[' + this._dimensions.map((dimension) => dimension ? dimension.toString() : '?').join(',') + ']') : '';
  381. }
  382. };
  383. tengine.Metadata = class {
  384. static open(context) {
  385. if (tengine.Metadata._metadata) {
  386. return Promise.resolve(tengine.Metadata._metadata);
  387. }
  388. return context.request('tengine-metadata.json', 'utf-8', null).then((data) => {
  389. tengine.Metadata._metadata = new tengine.Metadata(data);
  390. return tengine.Metadata._metadata;
  391. }).catch(() => {
  392. tengine.Metadata._metadata = new tengine.Metadata(null);
  393. return tengine.Metadata._metadata;
  394. });
  395. }
  396. constructor(data) {
  397. this._map = new Map();
  398. if (data) {
  399. const metadata = JSON.parse(data);
  400. for (const item of metadata) {
  401. if (item.name) {
  402. const version = item.version || 0;
  403. const name = item.name + ':' + version.toString();
  404. this._map.set(name, item);
  405. }
  406. }
  407. }
  408. }
  409. type(name, version) {
  410. let current = version;
  411. while (current > 0) {
  412. if (this._map.has(name + ':' + current.toString())) {
  413. break;
  414. }
  415. current--;
  416. }
  417. if (current >= 0) {
  418. const schema = this._map.get(name + ':' + current.toString());
  419. if (current !== version) {
  420. this._map.set(name + ':' + version.toString(), schema);
  421. }
  422. return schema;
  423. }
  424. return null;
  425. }
  426. };
  427. tengine.ModelFileReader = class {
  428. constructor(buffer) {
  429. // https://github.com/OAID/Tengine/blob/tengine-lite/src/serializer/tm/tm2_format.h
  430. // https://github.com/OAID/Tengine/wiki/The-format-of-tmfile
  431. const types = new Map();
  432. const register = (index, version, name, params) => {
  433. types.set(index.toString() + ':' + version.toString(), { name: name, params: params });
  434. };
  435. const operator = (index, version) => {
  436. let current = version;
  437. while (current >= 0) {
  438. if (types.has(index.toString() + ':' + current.toString())) {
  439. break;
  440. }
  441. current--;
  442. }
  443. if (current >= 0) {
  444. const schema = types.get(index.toString() + ':' + current.toString());
  445. if (current !== version) {
  446. types.set(index.toString() + ':' + version.toString(), schema);
  447. }
  448. return schema;
  449. }
  450. return null;
  451. };
  452. register( 0, 0, 'Accuracy', []);
  453. register( 1, 0, 'BatchNormalization', [ 'f', 'f', 'i' ]);
  454. register( 2, 0, 'BilinearResize', [ 'f', 'f', 'i' ]);
  455. register( 3, 0, 'Concat', [ 'i' ]);
  456. register( 4, 0, 'Const', []);
  457. register( 5, 0, 'Convolution', [ 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i' ]);
  458. register( 6, 0, 'Deconvolution', [ 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i' ]);
  459. register( 7, 0, 'DetectionOutput', [ 'i', 'i', 'i', 'f', 'f' ]);
  460. register( 8, 0, 'DropOut', []);
  461. register( 9, 0, 'Eltwise', [ 'i', 'i' ]);
  462. register(10, 0, 'Flatten', [ 'i' ]);
  463. register(11, 0, 'FullyConnected', [ 'i' ]);
  464. register(12, 0, 'INPUT', []);
  465. register(13, 0, 'LRN', [ 'i', 'f', 'f', 'i', 'f' ]);
  466. register(14, 0, 'Normalize', [ 'i', 'i' ]);
  467. register(15, 0, 'Permute', [ 'i', 'i', 'i', 'i', 'i' ]);
  468. register(16, 0, 'Pooling', [ 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i' ]);
  469. register(17, 0, 'Prelu', []);
  470. register(18, 0, 'PriorBox', [ 'f[]', 'f[]', 'f[]', 'f[]', 'i', 'i', 'i', 'i', 'i', 'f', 'f', 'f', 'i', 'i' ]);
  471. register(19, 0, 'Region', [ 'i', 'i', 'i', 'i', 'f', 'f', 'f[]' ]);
  472. register(20, 0, 'ReLU', [ 'f' ]);
  473. register(21, 0, 'ReLU6', []);
  474. register(22, 0, 'Reorg', [ 'i' ]);
  475. register(23, 0, 'Reshape', [ 'i', 'i', 'i', 'i', 'i', 'i' ]);
  476. // register(23, 0, 'Reshape', [ 'i', 'i', 'i[]' ]);
  477. register(24, 0, 'RoiPooling', [ 'i', 'i', 'f' ]);
  478. register(25, 0, 'RPN', [ 'f[]', 'f[]', 'i', 'i', 'i', 'i', 'i', 'f', 'anchors' ]);
  479. register(26, 0, 'Scale', [ 'i', 'i', 'i' ]);
  480. register(27, 0, 'Slice', [ 'i', 'i[]', 'i[]', 'i[]', 'i', 'i', 'i', 'i', 'i' ]);
  481. register(28, 0, 'SoftMax', [ 'i' ]);
  482. register(29, 0, 'Split', [ 'i', 'i', 'boolean', 'boolean', 'i[]' ]);
  483. register(30, 0, 'DetectionPostProcess', [ 'i', 'i', 'f', 'f', 'i', 'f[]' ]);
  484. register(31, 0, 'Gemm', [ 'f', 'f', 'i', 'i' ]);
  485. register(32, 0, 'Generic', [ 'i', 'i', 'string' ]);
  486. register(33, 0, 'Logistic', []);
  487. register(34, 0, 'LSTM', [ 'f', 'f', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i' ]);
  488. register(35, 0, 'RNN', [ 'f', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i' ]);
  489. register(36, 0, 'TanH', []);
  490. register(37, 0, 'Sigmoid', []);
  491. register(38, 0, 'Squeeze', [ 'i', 'i', 'i', 'i' ]);
  492. register(39, 0, 'FusedbnScaleRelu', []);
  493. register(40, 0, 'Pad', [ 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'f' ]);
  494. register(41, 0, 'StridedSlice', [ 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i' ]);
  495. register(42, 0, 'ArgMax', [ 'i' ]);
  496. register(43, 0, 'ArgMin', [ 'i' ]);
  497. register(44, 0, 'TopKV2', [ 'i', 'i' ]);
  498. register(45, 0, 'Reduction', [ 'i', 'i', 'i', 'i', 'i', 'i' ]);
  499. register(46, 0, 'Max', []);
  500. register(47, 0, 'Min', []);
  501. register(48, 0, 'GRU', [ 'f', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i' ]);
  502. register(49, 0, 'Addn', 'i');
  503. register(50, 0, 'SwapAxis', [ 'i', 'i' ]);
  504. register(51, 0, 'Upsample', [ 'f' ]);
  505. register(52, 0, 'SpaceToBatchND', [ 'i', 'i', 'i', 'i', 'i', 'i' ]);
  506. register(53, 0, 'BatchToSpaceND', [ 'i', 'i', 'i', 'i', 'i', 'i' ]);
  507. register(54, 0, 'Resize', [ 'f', 'f', 'i' ]);
  508. register(55, 0, 'ShuffleChannel', [ 'i' ]);
  509. register(56, 0, 'Crop', [ 'i', 'i', 'i', 'i', 'i', 'i', 'boolean', 'i', 'i' ]);
  510. register(57, 0, 'ROIAlign', [ 'i', 'i', 'f' ]);
  511. register(58, 0, 'Psroipooling', [ 'i', 'i', 'f', 'i' ]);
  512. register(59, 0, 'Unary', [ 'i' ]);
  513. register(60, 0, 'Expanddims', [ 'i' ]);
  514. register(61, 0, 'Bias', [ 'i' ]);
  515. register(62, 0, 'Noop', []);
  516. register(63, 0, 'Threshold', [ 'f' ]);
  517. register(64, 0, 'Hardsigmoid', [ 'f', 'f' ]);
  518. register(65, 0, 'Embed', [ 'f', 'f', 'f', 'f' ]);
  519. register(66, 0, 'InstanceNorm', [ 'f' ]);
  520. register(67, 0, 'MVN', [ 'i', 'i', 'f' ]);
  521. register(68, 0, 'Absval', []);
  522. register(69, 0, 'Cast', [ 'i', 'i' ]);
  523. register(70, 0, 'HardSwish', [ 'f', 'f' ]);
  524. register(71, 0, 'Interp', [ 'i', 'i', 'f', 'f', 'i' ]);
  525. register(72, 0, 'SELU', [ 'f', 'f' ]);
  526. register(73, 0, 'ELU', [ 'f' ]);
  527. register(74, 0, 'BroadMul', []);
  528. register(75, 0, 'Logical', [ 'i' ]);
  529. register(76, 0, 'Gather', [ 'i', 'i' ]);
  530. register(77, 0, 'Transpose', [ 'i[]' ]);
  531. register(78, 0, 'Comparison', [ 'i' ]);
  532. register(79, 0, 'SpaceToDepth', [ 'i' ]);
  533. register(80, 0, 'DepthToSpace', [ 'i' ]);
  534. register(81, 0, 'Reverse', []);
  535. register(82, 0, 'SparseToDense', [ 'i','i','i' ]);
  536. register(83, 0, 'Ceil', []);
  537. register(84, 0, 'SquaredDifference', []);
  538. register(85, 0, 'Round', []);
  539. register(86, 0, 'ZerosLike', []);
  540. register(87, 0, 'Clip', [ 'f','f' ]);
  541. register(88, 0, 'Unsqueeze', [ 'i[]' ]);
  542. register(89, 0, 'ReduceL2', [ 'i','i' ]);
  543. register(90, 0, 'Mean', []);
  544. register(91, 0, 'MatMul', []);
  545. register(92, 0, 'Expand', ['i[]']);
  546. register(93, 0, 'Scatter', ['i','boolean']);
  547. register(94, 0, 'Shape', []);
  548. register(95, 0, 'Where', []);
  549. register(96, 0, 'Tile', ['i','i']);
  550. register(97, 0, 'Mish', []);
  551. register(98, 0, 'L2Pool', []);
  552. register(99, 0, 'LogSoftmax', []);
  553. register(100, 0, 'ReLU1', []);
  554. register(101, 0, 'L2Normalization', []);
  555. register(102, 0, 'PackModel', ['i','i']);
  556. register(103, 0, 'Num', []);
  557. const reader = new tengine.BinaryReader(buffer);
  558. this._majorVersion = reader.uint16();
  559. this._minorVersion = reader.uint16();
  560. this._compileVersion = reader.uint16();
  561. reader.skip(2); // struct align
  562. reader.seek(reader.uint32()); // root table
  563. this._originalFormat = reader.int32();
  564. this._subFormat = reader.int32();
  565. this._graphs = [];
  566. const subgraphOffsets = reader.uint32s();
  567. for (const subgraphOffset of subgraphOffsets) {
  568. reader.seek(subgraphOffset);
  569. const subgraph = {};
  570. subgraph.id = reader.int32();
  571. subgraph.graphLayout = reader.int32();
  572. /*
  573. if (graphLayout == 0) {
  574. return "NCHW";
  575. }
  576. if (graphLayout == 1) {
  577. return "NHWC";
  578. }
  579. */
  580. subgraph.originalLayout = reader.int32();
  581. subgraph.inputs = reader.uint32s();
  582. subgraph.outputs = reader.uint32s();
  583. const nodeOffsets = reader.uint32s();
  584. const tensorOffsets = reader.uint32s();
  585. const bufferOffsets = reader.uint32s();
  586. subgraph.name = reader.string();
  587. subgraph.nodes = [];
  588. subgraph.tensors = [];
  589. this._graphs.push(subgraph);
  590. // nodes
  591. for (const nodeOffset of nodeOffsets) {
  592. reader.seek(nodeOffset);
  593. const node = {};
  594. node.id = reader.int32();
  595. node.inputs = reader.uint32s();
  596. node.outputs = reader.uint32s();
  597. const typeOffset = reader.int32();
  598. node.name = reader.string();
  599. const attributeOffsets = reader.uint32s();
  600. node.dynamicShape = reader.boolean() ? true : false;
  601. reader.seek(typeOffset);
  602. node.version = reader.int32();
  603. const index = reader.int32();
  604. const paramsOffset = reader.uint32();
  605. const schema = operator(index, node.version);
  606. node.type = schema ? schema.name : index.toString();
  607. const paramTypes = schema ? schema.params : [];
  608. node.params = [];
  609. if (paramsOffset) {
  610. reader.seek(paramsOffset);
  611. for (const paramType of paramTypes) {
  612. if (paramType !== 'boolean') {
  613. reader.align(4);
  614. }
  615. switch (paramType) {
  616. case 'i':
  617. node.params.push(reader.int32());
  618. break;
  619. case 'f':
  620. node.params.push(reader.float32());
  621. break;
  622. case 'i[]':
  623. node.params.push(reader.int32s());
  624. break;
  625. case 'f[]':
  626. node.params.push(reader.float32s());
  627. break;
  628. case 'boolean':
  629. node.params.push(reader.boolean());
  630. break;
  631. case 'string':
  632. node.params.push(reader.string());
  633. break;
  634. case 'anchors':
  635. node.params.push(reader.anchors(4));
  636. break;
  637. default:
  638. throw new tengine.Error("Unsupported param type '" + paramType + "' in '" + node.type + "'.");
  639. }
  640. }
  641. }
  642. if (node.type === 'Slice') {
  643. node.params[6] = (this._originalFormat == 5) ? node.params[6] : 0;
  644. }
  645. node.attributes = attributeOffsets.map((attributeOffset) => {
  646. reader.seek(attributeOffset);
  647. const name = reader.string();
  648. const value = reader.string();
  649. const type = reader.int32();
  650. return { name: name, value: value, type: type };
  651. });
  652. subgraph.nodes.push(node);
  653. }
  654. // buffers
  655. const buffers = bufferOffsets.map((bufferOffset) => {
  656. reader.seek(bufferOffset);
  657. const size = reader.uint32();
  658. const offset = reader.int32();
  659. if (offset !== 0) {
  660. reader.seek(offset);
  661. return reader.bytes(size);
  662. }
  663. return null;
  664. });
  665. // tensors
  666. subgraph.tensors = tensorOffsets.map((tensorOffset) => {
  667. reader.seek(tensorOffset);
  668. const tensor = {};
  669. tensor.id = reader.int32();
  670. tensor.buffer = buffers[reader.int32()];
  671. tensor.dims = reader.int32s();
  672. tensor.name = reader.string();
  673. const quantparamsOffset = reader.int32();
  674. tensor.layout = reader.int32();
  675. tensor.type = reader.int32(); // ar = 1, const = 2, input = 3, vdep, unknown
  676. tensor.dataType = reader.int32();
  677. if (quantparamsOffset) {
  678. reader.seek(quantparamsOffset);
  679. tensor.quantparams = {
  680. zeroPoint: reader.int32(),
  681. scale: reader.float32(),
  682. width: reader.int32()
  683. };
  684. }
  685. return tensor;
  686. });
  687. for (const node of subgraph.nodes) {
  688. if (node.type === 'Convolution') {
  689. switch (subgraph.graphLayout) {
  690. case 0: // NCHW
  691. node.params[6] = subgraph.tensors[node.inputs[1]].dims[1];
  692. break;
  693. case 1: // NHWC
  694. node.params[6] = subgraph.tensors[node.inputs[1]].dims[3];
  695. break;
  696. }
  697. }
  698. }
  699. }
  700. }
  701. get version() {
  702. return this._majorVersion + '.' + this._minorVersion;
  703. }
  704. get source() {
  705. switch (this._originalFormat) {
  706. case 0: return '';
  707. case 1: return 'Tengine';
  708. case 2: return 'Caffe';
  709. case 3: return 'ONNX';
  710. case 4: return 'MXNet';
  711. case 5: return 'TensorFlow';
  712. case 6: return 'TensorFlow Lite';
  713. case 7: return 'Darknet';
  714. case 8: return 'DLA v' + this._subFormat;
  715. case 9: return 'ncnn';
  716. case 10: return 'MegEngine';
  717. case 11: return 'OneFlow';
  718. case 12: return 'Horizon';
  719. case 13: return 'Bitman';
  720. default: throw new tengine.Error("Unknown source '" + this._originalFormat.toString() + "'.");
  721. }
  722. }
  723. get graphs() {
  724. return this._graphs;
  725. }
  726. };
  727. tengine.BinaryReader = class {
  728. constructor(buffer) {
  729. this._buffer = buffer;
  730. this._dataView = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength);
  731. this._position = 0;
  732. }
  733. seek(position) {
  734. this._position = position;
  735. if (this._position > this._buffer.length) {
  736. throw new tengine.Error('Expected ' + (this._position - this._buffer.length) + ' more bytes. The file might be corrupted. Unexpected end of file.');
  737. }
  738. }
  739. skip(offset) {
  740. this._position += offset;
  741. if (this._position > this._buffer.length) {
  742. throw new tengine.Error('Expected ' + (this._position - this._buffer.length) + ' more bytes. The file might be corrupted. Unexpected end of file.');
  743. }
  744. }
  745. align(mod) {
  746. if (this._position % mod != 0) {
  747. this.skip(mod - (this._position % mod));
  748. }
  749. }
  750. bytes(length) {
  751. const position = this._position;
  752. this.skip(length);
  753. return this._buffer.slice(position, this._position);
  754. }
  755. byte() {
  756. this.skip(1);
  757. return this._dataView.getUint8(this._position);
  758. }
  759. boolean() {
  760. return this.byte() == 0x00 ? true : false;
  761. }
  762. uint16() {
  763. const position = this._position;
  764. this.skip(2);
  765. return this._dataView.getUint16(position, true);
  766. }
  767. uint32() {
  768. const position = this._position;
  769. this.skip(4);
  770. return this._dataView.getUint32(position, true);
  771. }
  772. uint32s() {
  773. const values = [];
  774. const offset = this.uint32();
  775. if (offset) {
  776. const next = this._position;
  777. this.seek(offset);
  778. const count = this.uint32();
  779. for (let i = 0; i < count; i++) {
  780. values.push(this.uint32());
  781. }
  782. this.seek(next);
  783. }
  784. return values;
  785. }
  786. int32() {
  787. const position = this._position;
  788. this.skip(4);
  789. return this._dataView.getInt32(position, true);
  790. }
  791. int32s() {
  792. const values = [];
  793. const offset = this.uint32();
  794. if (offset) {
  795. const next = this._position;
  796. this.seek(offset);
  797. const count = this.uint32();
  798. for (let i = 0; i < count; i++) {
  799. values.push(this.int32());
  800. }
  801. this.seek(next);
  802. }
  803. return values;
  804. }
  805. float32() {
  806. const position = this._position;
  807. this.skip(4);
  808. return this._dataView.getFloat32(position, true);
  809. }
  810. float32s() {
  811. const values = [];
  812. const offset = this.uint32();
  813. if (offset) {
  814. const next = this._position;
  815. this.seek(offset);
  816. const count = this.uint32();
  817. for (let i = 0; i < count; i++) {
  818. values.push(this.float32());
  819. }
  820. this.seek(next);
  821. }
  822. return values;
  823. }
  824. anchors(length) {
  825. const arrays = [];
  826. const offset = this.uint32();
  827. if (offset) {
  828. const next = this._position;
  829. this.seek(offset);
  830. const count = this.uint32();
  831. for (let i = 0; i < count; i++) {
  832. const array = [];
  833. for (let j = 0; j < length; j++) {
  834. array.push(this.float32());
  835. }
  836. arrays.push(array);
  837. }
  838. this.seek(next);
  839. }
  840. return arrays;
  841. }
  842. string() {
  843. const position = this.uint32();
  844. let text = '';
  845. if (position) {
  846. const next = this._position;
  847. this.seek(position);
  848. const size = this.uint32();
  849. this.seek(this.uint32());
  850. for(let i = 0; i < size - 1; i++) {
  851. text += String.fromCharCode(this._buffer[this._position++]);
  852. }
  853. this.seek(next);
  854. }
  855. return text;
  856. }
  857. };
  858. tengine.Error = class extends Error {
  859. constructor(message) {
  860. super(message);
  861. this.name = 'Error loading Tengine model.';
  862. }
  863. };
  864. if (typeof module !== 'undefined' && typeof module.exports === 'object') {
  865. module.exports.ModelFactory = tengine.ModelFactory;
  866. }