om.js 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830
  1. // Experimental
  2. import * as base from './base.js';
  3. import * as protobuf from './protobuf.js';
  4. const om = {};
  5. const svp = {};
  6. om.ModelFactory = class {
  7. async match(context) {
  8. const container = om.Container.open(context);
  9. if (container) {
  10. return context.set('om', container);
  11. }
  12. return null;
  13. }
  14. async open(context) {
  15. const target = context.value;
  16. await target.read();
  17. const metadata = await context.metadata('om-metadata.json');
  18. return new om.Model(metadata, target);
  19. }
  20. };
  21. om.Model = class {
  22. constructor(metadata, target) {
  23. this.format = target.format;
  24. this.version = target.signature === 'PICO' ? target.model.version : '';
  25. const context = {
  26. metadata,
  27. signature: target.signature,
  28. weights: target.weights
  29. };
  30. this.modules = target.model.graph.map((graph) => new om.Graph(context, graph));
  31. }
  32. };
  33. om.Graph = class {
  34. constructor(context, graph) {
  35. switch (context.signature) {
  36. case 'IMOD': this.name = graph.name; break;
  37. case 'PICO': this.name = graph.id.toString(); break;
  38. default: throw new om.Error(`Unsupported DaVinci OM ${context.signature} signature.`);
  39. }
  40. this.nodes = [];
  41. this.inputs = [];
  42. this.outputs = [];
  43. const values = new Map();
  44. values.map = (name, type, tensor) => {
  45. if (!values.has(name)) {
  46. values.set(name, new om.Value(name, type || null, tensor || null));
  47. } else if ((type && !type.equals(values.get(name).type)) ||
  48. (tensor && tensor !== values.get(name).initializer)) {
  49. throw new om.Error(`Duplicate value '${name}'.`);
  50. }
  51. return values.get(name);
  52. };
  53. const tensors = new Map();
  54. const ops = [];
  55. for (const op of graph.op) {
  56. if (op.type === 'Const' && op.attr && op.attr.value) {
  57. const desc = op.attr.value.t.desc;
  58. let data = null;
  59. if (op.attr.value.t.data.length !== 0) {
  60. data = op.attr.value.t.data;
  61. } else if (context.weights === null) {
  62. data = null;
  63. } else if (desc.attr.merged_offset) {
  64. const offset = desc.attr.merged_offset.i.toNumber();
  65. data = context.weights.slice(offset, offset + desc.weight_size.toNumber());
  66. } else {
  67. const offset = desc.data_offset.toNumber();
  68. data = context.weights.slice(offset, offset + desc.weight_size.toNumber());
  69. }
  70. const type = om.Utility.tensorType(desc);
  71. const tensor = new om.Tensor('Constant', type, data);
  72. tensors.set(op.name, tensor);
  73. continue;
  74. }
  75. ops.push(op);
  76. }
  77. for (const op of ops) {
  78. const node = new om.Node(context, op, graph, values, tensors);
  79. this.nodes.push(node);
  80. }
  81. }
  82. };
  83. om.Node = class {
  84. constructor(context, op, graph, values, tensors) {
  85. this.name = op.name || '';
  86. this.type = context.metadata.type(op.type) || { name: op.type };
  87. this.inputs = [];
  88. this.outputs = [];
  89. this.attributes = [];
  90. this.chain = [];
  91. this.controlDependencies = [];
  92. this.device = null;
  93. if (op.input) {
  94. let index = 0;
  95. for (let i = 0; i < op.input.length; i++) {
  96. const input = op.input[i];
  97. if (input === '') {
  98. continue;
  99. }
  100. const name = this.type.inputs && i < this.type.inputs.length ? this.type.inputs[i].name : `input${index === 0 ? '' : index}`;
  101. index++;
  102. const end = this.type.inputs && i < this.type.inputs.length && this.type.inputs[i].type && this.type.inputs[i].type === 'Tensor[]' ? op.input.length : i + 1;
  103. const list = [];
  104. for (let j = i; j < end; j++) {
  105. const input = op.input[j];
  106. if (input === '') {
  107. continue;
  108. }
  109. const index = input.lastIndexOf(':');
  110. const identifier = input.substring(0, index);
  111. const src_index = input.substring(index + 1);
  112. if (src_index === '-1') {
  113. this.controlDependencies.push(values.map(name));
  114. continue;
  115. }
  116. const type = om.Utility.tensorType(op.input_desc[j]);
  117. const tensor = tensors.get(identifier);
  118. const value = values.map(input, type, tensor);
  119. list.push(value);
  120. }
  121. const argument = new om.Argument(name, list);
  122. this.inputs.push(argument);
  123. i = end - 1;
  124. }
  125. }
  126. if (op.output_desc) {
  127. for (let i = 0; i < op.output_desc.length; i++) {
  128. const identifier = `${this.name}:${i}`;
  129. const type = om.Utility.tensorType(op.output_desc[i]);
  130. const name = this.type.outputs && i < this.type.outputs.length ? this.type.outputs[i].name : `output${i === 0 ? '' : i}`;
  131. const value = values.map(identifier, type);
  132. const argument = new om.Argument(name, [value]);
  133. this.outputs.push(argument);
  134. }
  135. }
  136. for (const [name, obj] of Object.entries(op.attr || {})) {
  137. if (name === 'device') {
  138. this.device = obj;
  139. continue;
  140. }
  141. if (name === 'original_op_names') {
  142. continue;
  143. }
  144. if (name === 'relu_flag' && obj.b) {
  145. const node = new om.Node(context, { type: 'ReLU' }, graph, obj);
  146. this.chain.push(node);
  147. continue;
  148. }
  149. let value = obj;
  150. let type = null;
  151. switch (obj.value) {
  152. case 'i': {
  153. value = obj.i;
  154. type = 'int64';
  155. break;
  156. }
  157. case 'f': {
  158. value = obj.f;
  159. type = 'float32';
  160. break;
  161. }
  162. case 'b': {
  163. value = obj.b;
  164. type = 'boolean';
  165. break;
  166. }
  167. case 'bt': {
  168. value = null;
  169. if (obj.bt.length !== 0) {
  170. type = 'tensor';
  171. const shape = new om.TensorShape([obj.bt.length / 4]);
  172. value = new om.Tensor('Constant', new om.TensorType('float32', shape), obj.bt);
  173. }
  174. break;
  175. }
  176. case 'dt': {
  177. type = 'DataType';
  178. value = om.Utility.dtype(Number(obj.dt));
  179. break;
  180. }
  181. case 's': {
  182. if (typeof obj.s === 'string') {
  183. value = obj.s;
  184. } else if (obj.s.every((c) => c >= 32 && c <= 128)) {
  185. value = om.Utility.decodeText(obj.s);
  186. } else {
  187. value = obj.s;
  188. }
  189. type = 'string';
  190. break;
  191. }
  192. case 'g': {
  193. type = 'graph';
  194. value = new om.Graph(context, obj.g);
  195. break;
  196. }
  197. case 'func': {
  198. break;
  199. }
  200. case 'list': {
  201. const list = obj.list;
  202. value = [];
  203. if (list.s && list.s.length > 0) {
  204. value = list.s.map((v) => String.fromCharCode.apply(null, new Uint16Array(v))).join(', ');
  205. type = 'string[]';
  206. } else if (list.b && list.b.length > 0) {
  207. value = list.b;
  208. type = 'boolean[]';
  209. } else if (list.i && list.i.length > 0) {
  210. value = list.i;
  211. type = 'int64[]';
  212. } else if (list.f && list.f.length > 0) {
  213. value = list.f;
  214. type = 'float32[]';
  215. } else if (list.type && list.type.length > 0) {
  216. type = 'type[]';
  217. value = list.type.map((type) => om.Node.enum2Dtype(type) || '?');
  218. } else if (list.shape && list.shape.length > 0) {
  219. type = 'shape[]';
  220. value = list.shape.map((shape) => new om.TensorShape(shape));
  221. }
  222. break;
  223. }
  224. case 'list_list_int': {
  225. value = obj.list_list_int.list_list_i.map((list) => list.list_i);
  226. break;
  227. }
  228. case 't': {
  229. type = 'tensor';
  230. value = new om.Tensor('Constant', om.Utility.tensorType(obj.t.desc), obj.t.bytes);
  231. break;
  232. }
  233. case undefined: {
  234. value = null;
  235. break;
  236. }
  237. default: {
  238. throw new om.Error(`Unsupported attribute type '${JSON.stringify(obj).substring(0, 32)}'.`);
  239. }
  240. }
  241. const attribute = new om.Argument(name, value, type);
  242. this.attributes.push(attribute);
  243. }
  244. }
  245. };
  246. om.Argument = class {
  247. constructor(name, value, type = null) {
  248. this.name = name;
  249. this.value = value;
  250. this.type = type;
  251. }
  252. };
  253. om.Value = class {
  254. constructor(name, type, initializer = null) {
  255. if (typeof name !== 'string') {
  256. throw new om.Error(`Invalid value identifier '${JSON.stringify(name)}'.`);
  257. }
  258. this.name = name;
  259. this.type = initializer ? initializer.type : type;
  260. this.initializer = initializer;
  261. }
  262. };
  263. om.Tensor = class {
  264. constructor(category, type, value) {
  265. this.category = category;
  266. this.type = type;
  267. this.values = value;
  268. }
  269. };
  270. om.TensorType = class {
  271. constructor(dataType, shape, denotation) {
  272. this.dataType = dataType;
  273. this.shape = shape;
  274. this.denotation = denotation;
  275. }
  276. equals(obj) {
  277. return obj && this.dataType === obj.dataType && this.shape && this.shape.equals(obj.shape);
  278. }
  279. toString() {
  280. return this.dataType + this.shape.toString();
  281. }
  282. };
  283. om.TensorShape = class {
  284. constructor(dimensions) {
  285. this.dimensions = dimensions.map((dim) => typeof dim === 'bigint' ? dim.toNumber() : dim);
  286. }
  287. equals(obj) {
  288. if (obj && Array.isArray(obj.dimensions) && Array.isArray(this.dimensions)) {
  289. if (this.dimensions.length === obj.dimensions.length &&
  290. obj.dimensions.every((value, index) => this.dimensions[index] === value)) {
  291. return true;
  292. }
  293. if (obj.dimensions.every((dim) => Number.isInteger(dim)) && this.dimensions.every((dim) => Number.isInteger(dim))) {
  294. const a = obj.dimensions.reduce((a, b) => a * b, 1);
  295. const b = this.dimensions.reduce((a, b) => a * b, 1);
  296. return a === b;
  297. }
  298. }
  299. return false;
  300. }
  301. toString() {
  302. if (this.dimensions && Array.isArray(this.dimensions) && this.dimensions.length > 0) {
  303. return `[${this.dimensions.map((dim) => dim ? dim.toString() : '?').join(',')}]`;
  304. }
  305. return '';
  306. }
  307. };
  308. om.Container = class {
  309. static open(context) {
  310. const stream = context.stream;
  311. if (stream && stream.length >= 256) {
  312. const buffer = stream.peek(4);
  313. const signature = Array.from(buffer).map((c) => String.fromCharCode(c)).join('');
  314. if (signature === 'IMOD' || signature === 'PICO') {
  315. return new om.Container(context, signature);
  316. }
  317. }
  318. return null;
  319. }
  320. constructor(context, signature) {
  321. this.context = context;
  322. this.signature = signature;
  323. this.weights = null;
  324. }
  325. async read() {
  326. if (this.context) {
  327. const stream = this.context.stream;
  328. const reader = base.BinaryReader.open(stream);
  329. reader.skip(4);
  330. switch (this.signature) {
  331. case 'IMOD': {
  332. const decoder = new TextDecoder('utf-8');
  333. this.format = 'DaVinci OM';
  334. const header = {};
  335. header.headsize = reader.uint32();
  336. header.version = reader.uint32();
  337. header.checksum = reader.read(64);
  338. header.length = reader.uint32();
  339. header.is_encrypt = reader.byte();
  340. header.is_checksum = reader.byte();
  341. header.modeltype = reader.byte(); // 0=IR model, 1=standard model, 2=OM Tiny model
  342. header.genmode = reader.byte(); // 0=offline, 1=online
  343. header.name = decoder.decode(reader.read(32));
  344. header.ops = reader.uint32();
  345. header.userdefineinfo = reader.read(32);
  346. header.om_ir_version = reader.uint32();
  347. header.model_num = header.version >= 0x20000000 ? reader.uint32() : 1;
  348. header.platform_version = decoder.decode(reader.read(20));
  349. header.platform_type = reader.byte();
  350. header.padd = [reader.byte(), reader.byte(), reader.byte()];
  351. header.model_length = reader.uint64();
  352. header.need_check_os_cpu_info = reader.byte();
  353. header.is_unknow_model = reader.byte(); // 0:static model 1:dynamic model
  354. header.reserved = reader.read(62);
  355. const partitions = new Map();
  356. let size = -1;
  357. for (let align = 4; align <= 8; align += 4) {
  358. reader.seek(header.headsize);
  359. const count = reader.uint32();
  360. reader.skip(align - 4);
  361. size = 4 + (align - 4) + (count * 3 * align);
  362. for (let i = 0; i < count; i++) {
  363. const type = align === 4 ? reader.uint32() : reader.uint64().toNumber();
  364. const offset = align === 4 ? reader.uint32() : reader.uint64().toNumber();
  365. const size = align === 4 ? reader.uint32() : reader.uint64().toNumber();
  366. if (type >= 32 || partitions.has(type) || (offset + size) >= stream.length) {
  367. partitions.clear();
  368. break;
  369. }
  370. partitions.set(type, { offset, size });
  371. }
  372. if (partitions.size > 0) {
  373. break;
  374. }
  375. }
  376. if (!partitions.has(0)) {
  377. throw new om.Error('File does not contain a model definition.');
  378. }
  379. const offset = header.headsize + size;
  380. for (const [type, partition] of partitions) {
  381. reader.seek(offset + partition.offset);
  382. const buffer = reader.read(partition.size);
  383. switch (type) {
  384. case 0: { // MODEL_DEF
  385. this.model = buffer;
  386. break;
  387. }
  388. case 1: { // WEIGHTS_DATA
  389. this.weights = buffer;
  390. break;
  391. }
  392. case 2: // TASK_INFO
  393. case 3: // TBE_KERNELS
  394. case 4: { // CUST_AICPU_KERNELS
  395. break;
  396. }
  397. case 5: { // DEVICE_CONFIG, SO_BINS
  398. this.devices = new Map();
  399. const decoder = new TextDecoder('ascii');
  400. const reader = base.BinaryReader.open(buffer);
  401. reader.uint32();
  402. for (let position = 4; position < partition.size;) {
  403. const length = reader.uint32();
  404. const buffer = reader.read(length);
  405. const name = decoder.decode(buffer);
  406. const device = reader.uint32();
  407. this.devices.set(name, device);
  408. position += 4 + length + 4;
  409. }
  410. break;
  411. }
  412. case 6: // FLOW_MODEL
  413. case 7: // FLOW_SUBMODEL
  414. case 8: // MODEL_INOUT_INFO
  415. case 9: // STATIC_TASK_DESC
  416. case 10: // DYNAMIC_TASK_DESC
  417. case 11: // TASK_PARAM
  418. case 20: // PRE_MODEL_DESC
  419. case 21: // PRE_MODEL_SQE
  420. case 22: { // PRE_KERNEL_ARGS
  421. break;
  422. }
  423. default: {
  424. throw new om.Error(`Unsupported DaVinci OM partition type '${type}'.`);
  425. }
  426. }
  427. }
  428. om.proto = await this.context.require('./om-proto');
  429. om.proto = om.proto.ge.proto;
  430. try {
  431. const reader = protobuf.BinaryReader.open(this.model);
  432. this.model = om.proto.ModelDef.decode(reader);
  433. } catch (error) {
  434. const message = error && error.message ? error.message : error.toString();
  435. throw new om.Error(`File format is not ge.proto.ModelDef (${message.replace(/\.$/, '')}).`);
  436. }
  437. break;
  438. }
  439. case 'PICO': {
  440. this.format = 'DaVinci OM SVP'; // SVP = Smart Vision Platform
  441. reader.uint32(); // reserved
  442. this.size = reader.uint32();
  443. const param_size = reader.uint32();
  444. const param_offset = reader.uint32();
  445. reader.uint32(); // tmp_bufsize
  446. const tfm_offset = reader.uint32();
  447. reader.uint32(); // tfm_size
  448. reader.seek(param_offset);
  449. this.param = reader.read(param_size);
  450. const buffer = reader.read(tfm_offset - reader.position);
  451. this.model = new svp.ModelDef(buffer);
  452. break;
  453. }
  454. default: {
  455. throw new om.Error(`Unsupported DaVinci OM ${this.signature} signature.`);
  456. }
  457. }
  458. delete this.context;
  459. }
  460. }
  461. };
  462. om.Utility = class {
  463. static dtype(value) {
  464. om.Utility._types = om.Utility._types || [
  465. 'undefined', 'float32', 'float16', 'int8', 'uint8', 'int16', 'uint16', 'int32',
  466. 'int64', 'uint32', 'uint64', 'boolean', 'float64', 'string', 'dual_sub_int8', 'dual_sub_uint8',
  467. 'complex<float32>', 'complex<float64>', 'qint8', 'qint16', 'qint32', 'quint8', 'quint16', 'resource',
  468. 'stringref', 'dual', 'variant', 'bfloat16', 'int4', 'uint1', 'int2', 'uint2'
  469. ];
  470. if (value >= om.Utility._types.length) {
  471. throw new om.Error(`Unsupported dtype '${value}'.`);
  472. }
  473. return om.Utility._types[value];
  474. }
  475. static tensorType(desc) {
  476. if (desc && desc.shape && Array.isArray(desc.shape.dim)) {
  477. const dataType = desc && desc.dtype ? om.Utility.dtype(desc.dtype) : '?';
  478. const shape = new om.TensorShape(desc.shape.dim);
  479. return new om.TensorType(dataType, shape, desc.layout);
  480. }
  481. return null;
  482. }
  483. static decodeText(value) {
  484. om.Utility._textDecoder = om.Utility._textDecoder || new TextDecoder('utf-8');
  485. return om.Utility._textDecoder.decode(value);
  486. }
  487. };
  488. om.Error = class extends Error {
  489. constructor(message) {
  490. super(message);
  491. this.name = 'Error loading DaVinci OM model.';
  492. }
  493. };
  494. svp.ModelDef = class ModelDef {
  495. constructor(buffer) {
  496. const reader = new svp.BinaryReader(buffer);
  497. this.attr = {};
  498. this.graph = [];
  499. this.name = reader.find(0x800D, 'string');
  500. this.batch_num = reader.find(0x600A);
  501. this.version = '';
  502. while (reader.position < reader.length) {
  503. const tag = reader.uint16();
  504. const value = reader.value(tag);
  505. switch (tag & 0x1fff) {
  506. case 0x0040: {
  507. this.graph.push(new svp.GraphDef(value));
  508. break;
  509. }
  510. case 0x0111: {
  511. const op = new svp.OpDef(value);
  512. for (const item of this.graph) {
  513. if (op.attr && op.attr.seg_id && op.attr.seg_id.i === item.id) {
  514. let out_num = 0;
  515. if (typeof op.output_index === 'number') {
  516. out_num = op.output_index + 1;
  517. } else {
  518. const input_num = op.input.map((element) => element.split(":")[1]);
  519. out_num = input_num.length > 0 ? Math.max(...input_num) + 1 : 1;
  520. }
  521. const out_types = [];
  522. if (op.data_flow && op.data_flow !== '') {
  523. const data = op.data_flow;
  524. if (data.indexOf('o[{t') !== -1) {
  525. const outs = data.substring(data.indexOf('o[{t')).split(',');
  526. for (const out of outs) {
  527. const startIndex = out.indexOf("\"");
  528. const endIndex = out.indexOf("\"", startIndex + 1);
  529. out_types.push(out.substring(startIndex + 1, endIndex));
  530. }
  531. }
  532. }
  533. const out_list = [];
  534. while (out_num > 0) {
  535. const output_desc = {};
  536. output_desc.shape = { dim: op.output_shape_vector };
  537. output_desc.layout = 'NCHW';
  538. if (op.data_flow && out_types.length >= out_num) {
  539. output_desc.dtype = out_types[op.output_index + 1 - out_num];
  540. }
  541. out_list.push(output_desc);
  542. out_num--;
  543. }
  544. let curr_op = null;
  545. for (const op_item of item.op) {
  546. if (op_item.id === op.id) {
  547. curr_op = op_item;
  548. break;
  549. }
  550. }
  551. if (curr_op === null) {
  552. op.output_desc = op.output_desc.concat(out_list);
  553. item.op.push(op);
  554. } else {
  555. curr_op.output_desc = curr_op.output_desc.concat(out_list);
  556. }
  557. break;
  558. }
  559. }
  560. break;
  561. }
  562. default: {
  563. break;
  564. }
  565. }
  566. }
  567. if (this.graph.length > 1) {
  568. for (let i = 1; i < this.graph.length; i++) {
  569. this.graph[0].op = this.graph[0].op.concat(this.graph[i].op);
  570. }
  571. }
  572. this.version = this.graph[0].op.length === 0 ? 'release' : 'debug';
  573. }
  574. };
  575. svp.GraphDef = class {
  576. constructor(buffer) {
  577. this.input = [];
  578. this.output = [];
  579. this.op = [];
  580. this.attr = {};
  581. const reader = new svp.BinaryReader(buffer);
  582. const input = (buffer) => {
  583. const input = {};
  584. const reader = new svp.BinaryReader(buffer);
  585. while (reader.position < reader.length) {
  586. const tag = reader.uint16();
  587. switch (tag & 0x1fff) {
  588. case 0x0051: input.id = reader.value(tag); break;
  589. case 0x0058: input.name = reader.value(tag, 'string').trim(); break;
  590. case 0x005a: input.shape_vector = reader.value(tag, 'uint32[]'); break;
  591. default: reader.value(tag); break;
  592. }
  593. }
  594. return input;
  595. };
  596. const output = (buffer) => {
  597. const output = {};
  598. const reader = new svp.BinaryReader(buffer);
  599. while (reader.position < reader.length) {
  600. const tag = reader.uint16();
  601. switch (tag & 0x1fff) {
  602. case 0x0061: output.id = reader.value(tag); break;
  603. case 0x0066: output.name = reader.value(tag, 'string').trim(); break;
  604. case 0x0069: output.shape_vector = reader.value(tag, 'uint32[]'); break;
  605. case 0x0110: output.layer_num = reader.value(tag); break;
  606. default: reader.value(tag); break;
  607. }
  608. }
  609. return output;
  610. };
  611. while (reader.position < reader.length) {
  612. const tag = reader.uint16();
  613. const value = reader.value(tag);
  614. switch (tag & 0x1fff) {
  615. case 0x0041: this.id = value; break;
  616. case 0x0050: this.input.push(input(value)); break;
  617. case 0x0060: this.output.push(output(value)); break;
  618. default: break;
  619. }
  620. }
  621. }
  622. };
  623. svp.OpDef = class {
  624. constructor(buffer) {
  625. this.input = [];
  626. this.attr = {};
  627. this.input_i = [];
  628. this.output_i = [];
  629. this.input_desc = [];
  630. this.output_desc = [];
  631. const reader = new svp.BinaryReader(buffer);
  632. while (reader.position < reader.length) {
  633. const tag = reader.uint16();
  634. switch (tag & 0x1fff) {
  635. case 0x0114: this.name = reader.value(tag, 'string').trim(); break;
  636. case 0x0112: this.id = reader.value(tag); break;
  637. case 0x0119: this.attr.output_m2m_flag = reader.attribute(tag, 'i'); break;
  638. case 0x0121: this.attr.batch_flag = reader.attribute(tag, 'i'); break;
  639. case 0x0124: this.attr.dequant_scale = reader.attribute(tag, 'i'); break;
  640. case 0x0126: this.attr.output_address = reader.attribute(tag, 'i'); break;
  641. case 0x0125: this.attr.dequant_offset = reader.attribute(tag, 'i'); break;
  642. case 0x0127: this.attr.first_inst_addr = reader.attribute(tag, 'i'); break;
  643. case 0x0128: this.attr.last_inst_addr = reader.attribute(tag, 'i'); break;
  644. case 0x013B: this.attr.is_fusion_layer = reader.attribute(tag, 'i'); break;
  645. case 0x013C: this.input = reader.value(tag, 'string').split(','); break;
  646. case 0x014B: this.attr.seg_id = reader.attribute(tag, 'i'); break;
  647. case 0x0150: this.attr.is_not_last_merge_layer = reader.attribute(tag, 'i'); break;
  648. case 0x0151: this.attr.is_dump_avavilable = reader.attribute(tag, 'i'); break;
  649. case 0x0153: this.attr.debug_dump_offset = reader.attribute(tag, 'i'); break;
  650. case 0x0152: this.type = reader.value(tag, 'string'); break;
  651. case 0x0154: this.output_shape_vector = reader.value(tag, 'uint32[]'); break;
  652. case 0x0155: this.input_index = reader.value(tag); break;
  653. case 0x015B: this.output_index = reader.value(tag); break;
  654. case 0x0156: this.attr.trap_inst_pc = reader.attribute(tag, 'i'); break;
  655. case 0x0157: this.attr.profile_layer_id = reader.attribute(tag, 'i'); break;
  656. case 0xA15A:
  657. this.data_flow = reader.value(tag, 'string');
  658. this.attr.data_flow = new svp.AttrDef(this.data_flow.replace('i[{t', 'input[{type').replace(',f[{t', '\tforward[{type').replace(',o[{t', '\toutput[{type').replace(',{[t', ',{type'), 's');
  659. break;
  660. default: reader.value(tag); break;
  661. }
  662. }
  663. for (let i = 0; i < this.input.length; i++) {
  664. this.input_desc.push({ layout: 'NCHW', shape: {} });
  665. }
  666. }
  667. };
  668. svp.AttrDef = class {
  669. constructor(item, type) {
  670. switch (type) {
  671. case 's': this.s = item; break;
  672. case 'i': this.i = item; break;
  673. default: throw new svp.Error(`Unsupported attribute type '${type}'.`);
  674. }
  675. }
  676. get value() {
  677. if (this.s !== undefined) {
  678. return 's';
  679. }
  680. if (this.i !== undefined) {
  681. return 'i';
  682. }
  683. return undefined;
  684. }
  685. };
  686. svp.BinaryReader = class {
  687. constructor(buffer) {
  688. this._reader = base.BinaryReader.open(buffer);
  689. }
  690. get length() {
  691. return this._reader.length;
  692. }
  693. get position() {
  694. return this._reader.position;
  695. }
  696. seek(position) {
  697. this._reader.seek(position);
  698. }
  699. read(length) {
  700. return this._reader.read(length);
  701. }
  702. int8() {
  703. return this._reader.int8();
  704. }
  705. uint16() {
  706. return this._reader.uint16();
  707. }
  708. uint32() {
  709. return this._reader.uint32();
  710. }
  711. value(tag, type) {
  712. let value = 0;
  713. switch (tag >> 13) {
  714. case 1: value = this.int8(); break;
  715. case 2: value = this.uint16(); break;
  716. case 3: value = this.uint32(); break;
  717. case 4: value = this.read(this.int8()); break;
  718. case 5: value = this.read(this.uint16()); break;
  719. case 6: value = this.read(this.uint32()); break;
  720. default: throw new svp.Error(`Unsupported value identifier '${tag}'.`);
  721. }
  722. return type ? this._cast(value, type, tag) : value;
  723. }
  724. find(tag, type) {
  725. let value = null;
  726. let match = false;
  727. while (!match && this.position < this.length) {
  728. const current = this.uint16();
  729. value = this.value(current);
  730. match = current === tag;
  731. }
  732. this.seek(0);
  733. return match && type ? this._cast(value, type, tag) : value;
  734. }
  735. attribute(tag, type) {
  736. const value = this.value(tag);
  737. return new svp.AttrDef(value, type);
  738. }
  739. _cast(value, type, tag) {
  740. switch (type) {
  741. case 'string': {
  742. if (value instanceof Uint8Array) {
  743. svp.BinaryReader._decoder = svp.BinaryReader._decoder || new TextDecoder('utf-8');
  744. return svp.BinaryReader._decoder.decode(value).replace(/\0.*$/g, '');
  745. }
  746. throw new om.Error(`Invalid 'string' tag '${tag.toString(16)}'.`);
  747. }
  748. case 'uint32[]': {
  749. const reader = base.BinaryReader.open(value);
  750. value = [];
  751. while (reader.position < reader.length) {
  752. value.push(reader.uint32());
  753. }
  754. return value;
  755. }
  756. default: {
  757. return value;
  758. }
  759. }
  760. }
  761. };
  762. svp.Error = class extends Error {
  763. constructor(message) {
  764. super(message);
  765. this.name = 'Error loading DaVinci SVP model.';
  766. }
  767. };
  768. export const ModelFactory = om.ModelFactory;