tengine.js 32 KB

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