circle.js 37 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047
  1. var circle = circle || {};
  2. var flatbuffers = flatbuffers || require('./flatbuffers');
  3. var flexbuffers = {};
  4. var zip = zip || require('./zip');
  5. circle.ModelFactory = class {
  6. match(context) {
  7. const tags = context.tags('flatbuffers');
  8. if (tags.get('file_identifier') === 'CIR0') {
  9. return 'circle.flatbuffers';
  10. }
  11. const obj = context.open('json');
  12. if (obj && obj.subgraphs && obj.operator_codes) {
  13. return 'circle.flatbuffers.json';
  14. }
  15. return undefined;
  16. }
  17. open(context, match) {
  18. return context.require('./circle-schema').then(() => {
  19. circle.schema = flatbuffers.get('circle').circle;
  20. let model = null;
  21. const attachments = new Map();
  22. switch (match) {
  23. case 'circle.flatbuffers.json': {
  24. try {
  25. const obj = context.open('json');
  26. const reader = new flatbuffers.TextReader(obj);
  27. model = circle.schema.Model.createText(reader);
  28. }
  29. catch (error) {
  30. const message = error && error.message ? error.message : error.toString();
  31. throw new circle.Error('File text format is not circle.Model (' + message.replace(/\.$/, '') + ').');
  32. }
  33. break;
  34. }
  35. case 'circle.flatbuffers': {
  36. const stream = context.stream;
  37. try {
  38. const reader = flatbuffers.BinaryReader.open(stream);
  39. model = circle.schema.Model.create(reader);
  40. }
  41. catch (error) {
  42. const message = error && error.message ? error.message : error.toString();
  43. throw new circle.Error('File format is not circle.Model (' + message.replace(/\.$/, '') + ').');
  44. }
  45. try {
  46. const archive = zip.Archive.open(stream);
  47. if (archive) {
  48. for (const entry of archive.entries) {
  49. attachments.set(entry[0], entry[1]);
  50. }
  51. }
  52. }
  53. catch (error) {
  54. // continue regardless of error
  55. }
  56. break;
  57. }
  58. default: {
  59. throw new circle.Error("Unknown Circle format '" + match + "'.");
  60. }
  61. }
  62. return circle.Metadata.open(context).then((metadata) => {
  63. return new circle.Model(metadata, model);
  64. });
  65. });
  66. }
  67. };
  68. circle.Model = class {
  69. constructor(metadata, model) {
  70. this._graphs = [];
  71. this._format = 'Circle';
  72. this._format = this._format + ' v' + model.version.toString();
  73. this._description = model.description || '';
  74. const builtinOperators = new Map();
  75. const upperCase = new Set([ '2D', 'LSH', 'SVDF', 'RNN', 'L2', 'LSTM' ]);
  76. for (const key of Object.keys(circle.schema.BuiltinOperator)) {
  77. const value = key === 'BATCH_MATMUL' ? 'BATCH_MAT_MUL' : key;
  78. const name = value.split('_').map((s) => (s.length < 1 || upperCase.has(s)) ? s : s[0] + s.substring(1).toLowerCase()).join('');
  79. const index = circle.schema.BuiltinOperator[key];
  80. builtinOperators.set(index, name);
  81. }
  82. const operators = model.operator_codes.map((operator) => {
  83. const code = operator.builtin_code || 0;
  84. const version = operator.version;
  85. const custom = code === circle.schema.BuiltinOperator.CUSTOM;
  86. const name = custom ? operator.custom_code ? operator.custom_code : 'Custom' : builtinOperators.has(code) ? builtinOperators.get(code) : code.toString();
  87. return custom ? { name: name, version: version, custom: true } : { name: name, version: version };
  88. });
  89. let modelMetadata = null;
  90. for (const metadata of model.metadata) {
  91. const buffer = model.buffers[metadata.buffer];
  92. if (buffer) {
  93. switch (metadata.name) {
  94. case 'min_runtime_version': {
  95. const data = buffer.data || new Uint8Array(0);
  96. this._runtime = data ? new TextDecoder().decode(data) : undefined;
  97. break;
  98. }
  99. case 'TFLITE_METADATA': {
  100. const data = buffer.data || new Uint8Array(0);
  101. const reader = flatbuffers.BinaryReader.open(data);
  102. if (circle.schema.ModelMetadata.identifier(reader)) {
  103. modelMetadata = circle.schema.ModelMetadata.create(reader);
  104. this._name = modelMetadata.name || '';
  105. this._version = modelMetadata.version || '';
  106. this._description = modelMetadata.description ? [ this.description, modelMetadata.description].join(' ') : this._description;
  107. this._author = modelMetadata.author || '';
  108. this._license = modelMetadata.license || '';
  109. }
  110. break;
  111. }
  112. }
  113. }
  114. }
  115. const subgraphs = model.subgraphs;
  116. const subgraphsMetadata = modelMetadata ? modelMetadata.subgraph_metadata : null;
  117. for (let i = 0; i < subgraphs.length; i++) {
  118. const subgraph = subgraphs[i];
  119. const name = subgraphs.length > 1 ? i.toString() : '';
  120. const subgraphMetadata = subgraphsMetadata && i < subgraphsMetadata.length ? subgraphsMetadata[i] : null;
  121. this._graphs.push(new circle.Graph(metadata, subgraph, subgraphMetadata, name, operators, model));
  122. }
  123. }
  124. get format() {
  125. return this._format;
  126. }
  127. get runtime() {
  128. return this._runtime;
  129. }
  130. get name() {
  131. return this._name;
  132. }
  133. get version() {
  134. return this._version;
  135. }
  136. get description() {
  137. return this._description;
  138. }
  139. get author() {
  140. return this._author;
  141. }
  142. get license() {
  143. return this._license;
  144. }
  145. get graphs() {
  146. return this._graphs;
  147. }
  148. };
  149. circle.Graph = class {
  150. constructor(metadata, subgraph, subgraphMetadata, name, operators, model) {
  151. this._nodes = [];
  152. this._inputs = [];
  153. this._outputs = [];
  154. this._name = subgraph.name || name;
  155. const tensors = new Map();
  156. const args = (index) => {
  157. if (index === -1) {
  158. return null;
  159. }
  160. if (!tensors.has(index)) {
  161. if (index < subgraph.tensors.length) {
  162. const tensor = subgraph.tensors[index];
  163. const buffer = model.buffers[tensor.buffer];
  164. const is_variable = tensor.is_variable;
  165. const data = buffer ? buffer.data : null;
  166. const initializer = (data && data.length > 0) || is_variable ? new circle.Tensor(index, tensor, buffer, is_variable) : null;
  167. tensors.set(index, new circle.Argument(index, tensor, initializer));
  168. }
  169. else {
  170. tensors.set(index, new circle.Argument(index, { name: '' }, null));
  171. }
  172. }
  173. return tensors.get(index);
  174. };
  175. for (let i = 0; i < subgraph.operators.length; i++) {
  176. const node = subgraph.operators[i];
  177. const index = node.opcode_index;
  178. const operator = index < operators.length ? operators[index] : { name: '(' + index.toString() + ')' };
  179. this._nodes.push(new circle.Node(metadata, node, operator, i.toString(), args));
  180. }
  181. const applyTensorMetadata = (argument, tensorMetadata) => {
  182. if (tensorMetadata) {
  183. const description = tensorMetadata.description;
  184. if (description) {
  185. argument.description = description;
  186. }
  187. const content = tensorMetadata.content;
  188. if (argument.type && content) {
  189. let denotation = null;
  190. const contentProperties = content.content_properties;
  191. if (contentProperties instanceof circle.schema.FeatureProperties) {
  192. denotation = 'Feature';
  193. }
  194. else if (contentProperties instanceof circle.schema.ImageProperties) {
  195. denotation = 'Image';
  196. switch(contentProperties.color_space) {
  197. case 1: denotation += '(RGB)'; break;
  198. case 2: denotation += '(Grayscale)'; break;
  199. }
  200. }
  201. else if (contentProperties instanceof circle.schema.BoundingBoxProperties) {
  202. denotation = 'BoundingBox';
  203. }
  204. else if (contentProperties instanceof circle.schema.AudioProperties) {
  205. denotation = 'Audio(' + contentProperties.sample_rate.toString() + ',' + contentProperties.channels.toString() + ')';
  206. }
  207. if (denotation) {
  208. argument.type.denotation = denotation;
  209. }
  210. }
  211. }
  212. };
  213. const inputs = subgraph.inputs;
  214. for (let i = 0; i < inputs.length; i++) {
  215. const input = inputs[i];
  216. const argument = args(input);
  217. if (subgraphMetadata && i < subgraphMetadata.input_tensor_metadata.length) {
  218. applyTensorMetadata(argument, subgraphMetadata.input_tensor_metadata[i]);
  219. }
  220. this._inputs.push(new circle.Parameter(argument ? argument.name : '?', true, argument ? [ argument ] : []));
  221. }
  222. const outputs = subgraph.outputs;
  223. for (let i = 0; i < outputs.length; i++) {
  224. const output = outputs[i];
  225. const argument = args(output);
  226. if (subgraphMetadata && i < subgraphMetadata.output_tensor_metadata.length) {
  227. applyTensorMetadata(argument, subgraphMetadata.output_tensor_metadata[i]);
  228. }
  229. this._outputs.push(new circle.Parameter(argument ? argument.name : '?', true, argument ? [ argument ] : []));
  230. }
  231. }
  232. get name() {
  233. return this._name;
  234. }
  235. get inputs() {
  236. return this._inputs;
  237. }
  238. get outputs() {
  239. return this._outputs;
  240. }
  241. get nodes() {
  242. return this._nodes;
  243. }
  244. };
  245. circle.Node = class {
  246. constructor(metadata, node, type, location, args) {
  247. this._location = location;
  248. this._type = type.custom ? { name: type.name, category: 'custom' } : metadata.type(type.name);
  249. this._inputs = [];
  250. this._outputs = [];
  251. this._attributes = [];
  252. if (node) {
  253. let inputs = [];
  254. let outputs = [];
  255. inputs = Array.from(node.inputs || new Int32Array(0));
  256. outputs = Array.from(node.outputs || new Int32Array(0));
  257. let inputIndex = 0;
  258. while (inputIndex < inputs.length) {
  259. let count = 1;
  260. let inputName = null;
  261. let inputVisible = true;
  262. const inputArguments = [];
  263. if (this._type && this._type.inputs && inputIndex < this._type.inputs.length) {
  264. const input = this._type.inputs[inputIndex];
  265. inputName = input.name;
  266. if (input.option == 'variadic') {
  267. count = inputs.length - inputIndex;
  268. }
  269. if (Object.prototype.hasOwnProperty.call(input, 'visible') && !input.visible) {
  270. inputVisible = false;
  271. }
  272. }
  273. const inputArray = inputs.slice(inputIndex, inputIndex + count);
  274. for (const index of inputArray) {
  275. const argument = args(index);
  276. if (argument) {
  277. inputArguments.push(argument);
  278. }
  279. }
  280. inputIndex += count;
  281. inputName = inputName ? inputName : inputIndex.toString();
  282. this._inputs.push(new circle.Parameter(inputName, inputVisible, inputArguments));
  283. }
  284. for (let k = 0; k < outputs.length; k++) {
  285. const index = outputs[k];
  286. const outputArguments = [];
  287. const argument = args(index);
  288. if (argument) {
  289. outputArguments.push(argument);
  290. }
  291. let outputName = k.toString();
  292. if (this._type && this._type.outputs && k < this._type.outputs.length) {
  293. const output = this._type.outputs[k];
  294. if (output && output.name) {
  295. outputName = output.name;
  296. }
  297. }
  298. this._outputs.push(new circle.Parameter(outputName, true, outputArguments));
  299. }
  300. if (type.custom && node.custom_options.length > 0) {
  301. let decoded = false;
  302. if (node.custom_options_format === circle.schema.CustomOptionsFormat.FLEXBUFFERS) {
  303. try {
  304. const reader = flexbuffers.Reader.open(node.custom_options);
  305. const custom_options = reader.read();
  306. if (Array.isArray(custom_options)) {
  307. const attribute = new circle.Attribute(null, 'custom_options', custom_options);
  308. this._attributes.push(attribute);
  309. decoded = true;
  310. }
  311. else if (custom_options) {
  312. for (const pair of Object.entries(custom_options)) {
  313. const key = pair[0];
  314. const value = pair[1];
  315. const schema = metadata.attribute(type.name, key);
  316. const attribute = new circle.Attribute(schema, key, value);
  317. this._attributes.push(attribute);
  318. }
  319. decoded = true;
  320. }
  321. }
  322. catch (err) {
  323. // continue regardless of error
  324. }
  325. }
  326. if (!decoded) {
  327. const schema = metadata.attribute(type.name, 'custom');
  328. this._attributes.push(new circle.Attribute(schema, 'custom', Array.from(node.custom_options)));
  329. }
  330. }
  331. const options = node.builtin_options;
  332. if (options) {
  333. for (const name of Object.keys(options)) {
  334. const value = options[name];
  335. if (name === 'fused_activation_function' && value !== 0) {
  336. const activationFunctionMap = { 1: 'Relu', 2: 'ReluN1To1', 3: 'Relu6', 4: 'Tanh', 5: 'SignBit' };
  337. if (!activationFunctionMap[value]) {
  338. throw new circle.Error("Unknown activation funtion index '" + JSON.stringify(value) + "'.");
  339. }
  340. const type = activationFunctionMap[value];
  341. this._chain = [ new circle.Node(metadata, null, { name: type }, null, []) ];
  342. }
  343. const schema = metadata.attribute(type.name, name);
  344. this._attributes.push(new circle.Attribute(schema, name, value));
  345. }
  346. }
  347. }
  348. }
  349. get type() {
  350. return this._type;
  351. }
  352. get name() {
  353. return '';
  354. }
  355. get location() {
  356. return this._location;
  357. }
  358. get inputs() {
  359. return this._inputs;
  360. }
  361. get outputs() {
  362. return this._outputs;
  363. }
  364. get chain() {
  365. return this._chain;
  366. }
  367. get attributes() {
  368. return this._attributes;
  369. }
  370. };
  371. circle.Attribute = class {
  372. constructor(metadata, name, value) {
  373. this._name = name;
  374. this._value = ArrayBuffer.isView(value) ? Array.from(value) : value;
  375. this._type = metadata && metadata.type ? metadata.type : null;
  376. if (this._name == 'fused_activation_function') {
  377. this._visible = false;
  378. }
  379. if (this._type) {
  380. this._value = circle.Utility.enum(this._type, this._value);
  381. }
  382. if (metadata) {
  383. if (Object.prototype.hasOwnProperty.call(metadata, 'visible') && !metadata.visible) {
  384. this._visible = false;
  385. }
  386. else if (Object.prototype.hasOwnProperty.call(metadata, 'default')) {
  387. value = this._value;
  388. if (typeof value == 'function') {
  389. value = value();
  390. }
  391. if (value == metadata.default) {
  392. this._visible = false;
  393. }
  394. }
  395. }
  396. }
  397. get name() {
  398. return this._name;
  399. }
  400. get type() {
  401. return this._type;
  402. }
  403. get value() {
  404. return this._value;
  405. }
  406. get visible() {
  407. return this._visible == false ? false : true;
  408. }
  409. };
  410. circle.Parameter = class {
  411. constructor(name, visible, args) {
  412. this._name = name;
  413. this._visible = visible;
  414. this._arguments = args;
  415. }
  416. get name() {
  417. return this._name;
  418. }
  419. get visible() {
  420. return this._visible;
  421. }
  422. get arguments() {
  423. return this._arguments;
  424. }
  425. };
  426. circle.Argument = class {
  427. constructor(index, tensor, initializer) {
  428. const name = tensor.name || '';
  429. this._name = name + '\n' + index.toString();
  430. this._location = index.toString();
  431. this._type = tensor.type !== undefined && tensor.shape !== undefined ? new circle.TensorType(tensor) : null;
  432. this._initializer = initializer;
  433. const quantization = tensor.quantization;
  434. if (quantization) {
  435. const length = Math.max(quantization.scale.length, quantization.zero_point.length, quantization.min.length, quantization.max.length);
  436. const list = [];
  437. for (let i = 0; i < length; i++) {
  438. let value = 'q';
  439. const scale = i < quantization.scale.length ? quantization.scale[i] : 0;
  440. const zeroPoint = (i < quantization.zero_point.length ? quantization.zero_point[i] : 0).toString();
  441. if (scale !== 0 || zeroPoint !== '0') {
  442. value = scale.toString() + ' * ' + (zeroPoint === '0' ? 'q' : ('(q' + (!zeroPoint.startsWith('-') ? ' - ' + zeroPoint : ' + ' + zeroPoint.substring(1)) + ')'));
  443. }
  444. if (i < quantization.min.length) {
  445. value = quantization.min[i].toString() + ' \u2264 ' + value;
  446. }
  447. if (i < quantization.max.length) {
  448. value = value + ' \u2264 ' + quantization.max[i].toString();
  449. }
  450. list.push(value);
  451. }
  452. if (list.length > 0 && !list.every((value) => value === 'q')) {
  453. this._quantization = list;
  454. }
  455. }
  456. }
  457. get name() {
  458. return this._name;
  459. }
  460. get location() {
  461. return this._location;
  462. }
  463. get type() {
  464. return this._type;
  465. }
  466. get quantization() {
  467. return this._quantization;
  468. }
  469. set description(value) {
  470. this._description = value;
  471. }
  472. get description() {
  473. return this._description;
  474. }
  475. get initializer() {
  476. return this._initializer;
  477. }
  478. };
  479. circle.Tensor = class {
  480. constructor(index, tensor, buffer, is_variable) {
  481. this._location = index.toString();
  482. this._type = new circle.TensorType(tensor);
  483. this._is_variable = is_variable;
  484. this._name = tensor.name;
  485. this._data = buffer.data.slice(0);
  486. }
  487. get kind() {
  488. return this._is_variable ? 'Variable' : '';
  489. }
  490. get name() {
  491. return this._name;
  492. }
  493. get location() {
  494. return this._location;
  495. }
  496. get type() {
  497. return this._type;
  498. }
  499. get state() {
  500. return this._context().state;
  501. }
  502. get value() {
  503. const context = this._context();
  504. if (context.state) {
  505. return null;
  506. }
  507. context.limit = Number.MAX_SAFE_INTEGER;
  508. return this._decode(context, 0);
  509. }
  510. toString() {
  511. const context = this._context();
  512. if (context.state) {
  513. return '';
  514. }
  515. context.limit = 10000;
  516. const value = this._decode(context, 0);
  517. return JSON.stringify(value, null, 4);
  518. }
  519. _context() {
  520. const context = {};
  521. context.state = null;
  522. context.index = 0;
  523. context.count = 0;
  524. if (this._data == null || this._data.length === 0) {
  525. context.state = 'Tensor data is empty.';
  526. return context;
  527. }
  528. const dataType = this.type.dataType;
  529. const shape = this.type.shape.dimensions;
  530. context.dataType = dataType;
  531. context.shape = shape;
  532. if (dataType === 'string') {
  533. let offset = 0;
  534. const data = new DataView(this._data.buffer, this._data.byteOffset, this._data.byteLength);
  535. const count = data.getInt32(0, true);
  536. offset += 4;
  537. const offsetTable = [];
  538. for (let j = 0; j < count; j++) {
  539. offsetTable.push(data.getInt32(offset, true));
  540. offset += 4;
  541. }
  542. offsetTable.push(this._data.length);
  543. const stringTable = [];
  544. const utf8Decoder = new TextDecoder('utf-8');
  545. for (let k = 0; k < count; k++) {
  546. const textArray = this._data.subarray(offsetTable[k], offsetTable[k + 1]);
  547. stringTable.push(utf8Decoder.decode(textArray));
  548. }
  549. context.data = stringTable;
  550. }
  551. else {
  552. const itemsize = new Map([
  553. [ 'boolean' ],
  554. [ 'uint8', 1 ], [ 'uint32', 4],
  555. [ 'int8', 1 ], [ 'int16', 2 ], [ 'int32', 4 ], [ 'int64', 8 ],
  556. [ 'float16', 2 ], [ 'float32', 4 ], [ 'float64', 8 ]
  557. ]);
  558. if (!itemsize.has(dataType)) {
  559. throw new circle.Error("Tensor data type '" + this.type.dataType + "' is not implemented.");
  560. }
  561. const size = shape.reduce((a, b) => a * b, 1);
  562. if (this._data.length < itemsize.get(dataType) * size) {
  563. context.state = "Invalid tensor data size.";
  564. return context;
  565. }
  566. context.data = new DataView(this._data.buffer, this._data.byteOffset, this._data.byteLength);
  567. }
  568. return context;
  569. }
  570. _decode(context, dimension) {
  571. const shape = (context.shape.length == 0) ? [ 1 ] : context.shape;
  572. const size = shape[dimension];
  573. const results = [];
  574. if (dimension == shape.length - 1) {
  575. for (let i = 0; i < size; i++) {
  576. if (context.count > context.limit) {
  577. results.push('...');
  578. return results;
  579. }
  580. switch (context.dataType) {
  581. case 'boolean':
  582. results.push(context.data.getUint8(context.index) === 0 ? false : true);
  583. context.index += 1;
  584. context.count++;
  585. break;
  586. case 'uint8':
  587. results.push(context.data.getUint8(context.index));
  588. context.index += 1;
  589. context.count++;
  590. break;
  591. case 'uint32':
  592. results.push(context.data.getUint32(context.index));
  593. context.index += 4;
  594. context.count++;
  595. break;
  596. case 'int8':
  597. results.push(context.data.getInt8(context.index));
  598. context.index += 1;
  599. context.count++;
  600. break;
  601. case 'int16':
  602. results.push(context.data.getInt16(context.index, true));
  603. context.index += 2;
  604. context.count++;
  605. break;
  606. case 'int32':
  607. results.push(context.data.getInt32(context.index, true));
  608. context.index += 4;
  609. context.count++;
  610. break;
  611. case 'int64':
  612. results.push(context.data.getInt64(context.index, true));
  613. context.index += 8;
  614. context.count++;
  615. break;
  616. case 'float16':
  617. results.push(context.data.getFloat16(context.index, true));
  618. context.index += 2;
  619. context.count++;
  620. break;
  621. case 'float32':
  622. results.push(context.data.getFloat32(context.index, true));
  623. context.index += 4;
  624. context.count++;
  625. break;
  626. case 'float64':
  627. results.push(context.data.getFloat64(context.index, true));
  628. context.index += 8;
  629. context.count++;
  630. break;
  631. case 'string':
  632. results.push(context.data[context.index++]);
  633. context.count++;
  634. break;
  635. default:
  636. break;
  637. }
  638. }
  639. }
  640. else {
  641. for (let j = 0; j < size; j++) {
  642. if (context.count > context.limit) {
  643. results.push('...');
  644. return results;
  645. }
  646. results.push(this._decode(context, dimension + 1));
  647. }
  648. }
  649. if (context.shape.length == 0) {
  650. return results[0];
  651. }
  652. return results;
  653. }
  654. };
  655. circle.TensorType = class {
  656. constructor(tensor) {
  657. this._dataType = circle.Utility.dataType(tensor.type);
  658. this._shape = new circle.TensorShape(Array.from(tensor.shape || []));
  659. }
  660. get dataType() {
  661. return this._dataType;
  662. }
  663. get shape() {
  664. return this._shape;
  665. }
  666. set denotation(value) {
  667. this._denotation = value;
  668. }
  669. get denotation() {
  670. return this._denotation;
  671. }
  672. toString() {
  673. return this.dataType + this._shape.toString();
  674. }
  675. };
  676. circle.TensorShape = class {
  677. constructor(dimensions) {
  678. this._dimensions = dimensions;
  679. }
  680. get dimensions() {
  681. return this._dimensions;
  682. }
  683. toString() {
  684. if (!this._dimensions || this._dimensions.length == 0) {
  685. return '';
  686. }
  687. return '[' + this._dimensions.map((dimension) => dimension.toString()).join(',') + ']';
  688. }
  689. };
  690. circle.Metadata = class {
  691. static open(context) {
  692. if (circle.Metadata._metadata) {
  693. return Promise.resolve(circle.Metadata._metadata);
  694. }
  695. return context.request('circle-metadata.json', 'utf-8', null).then((data) => {
  696. circle.Metadata._metadata = new circle.Metadata(data);
  697. return circle.Metadata._metadata;
  698. }).catch(() => {
  699. circle.Metadata._metadata = new circle.Metadata(null);
  700. return circle.Metadata._metadata;
  701. });
  702. }
  703. constructor(data) {
  704. this._types = new Map();
  705. this._attributes = new Map();
  706. if (data) {
  707. const metadata = JSON.parse(data);
  708. this._types = new Map(metadata.map((item) => [ item.name, item ]));
  709. }
  710. }
  711. type(name) {
  712. if (!this._types.has(name)) {
  713. this._types.set(name, { name: name });
  714. }
  715. return this._types.get(name);
  716. }
  717. attribute(type, name) {
  718. const key = type + ':' + name;
  719. if (!this._attributes.has(key)) {
  720. this._attributes.set(key, null);
  721. const metadata = this.type(type);
  722. if (metadata && Array.isArray(metadata.attributes)) {
  723. for (const attribute of metadata.attributes) {
  724. this._attributes.set(type + ':' + attribute.name, attribute);
  725. }
  726. }
  727. }
  728. return this._attributes.get(key);
  729. }
  730. };
  731. circle.Utility = class {
  732. static dataType(type) {
  733. if (!circle.Utility._tensorTypeMap) {
  734. circle.Utility._tensorTypeMap = new Map(Object.keys(circle.schema.TensorType).map((key) => [ circle.schema.TensorType[key], key.toLowerCase() ]));
  735. circle.Utility._tensorTypeMap.set(6, 'boolean');
  736. }
  737. return circle.Utility._tensorTypeMap.has(type) ? circle.Utility._tensorTypeMap.get(type) : '?';
  738. }
  739. static enum(name, value) {
  740. const type = name && circle.schema ? circle.schema[name] : undefined;
  741. if (type) {
  742. circle.Utility._enums = circle.Utility._enums || new Map();
  743. if (!circle.Utility._enums.has(name)) {
  744. const map = new Map(Object.keys(type).map((key) => [ type[key], key ]));
  745. circle.Utility._enums.set(name, map);
  746. }
  747. const map = circle.Utility._enums.get(name);
  748. if (map.has(value)) {
  749. return map.get(value);
  750. }
  751. }
  752. return value;
  753. }
  754. };
  755. circle.Error = class extends Error {
  756. constructor(message) {
  757. super(message);
  758. this.name = 'Error loading Circle model.';
  759. }
  760. };
  761. flexbuffers.Reader = class {
  762. static open(buffer) {
  763. return new flexbuffers.Reader(buffer);
  764. }
  765. constructor(buffer) {
  766. this._reader = new flexbuffers.BinaryReader(buffer);
  767. }
  768. read() {
  769. const end = this._reader.length;
  770. if (end < 3) {
  771. throw new flexbuffers.Error('Invalid buffer size.');
  772. }
  773. const byteWidth = this._reader.uint(end - 1, 1);
  774. if (byteWidth > 8) {
  775. throw new flexbuffers.Error('Invalid byte size.');
  776. }
  777. const packedType = this._reader.uint(end - 2, 1);
  778. const reference = new flexbuffers.Reference(this._reader, end - 2 - byteWidth, byteWidth, 1 << (packedType & 3), packedType >> 2);
  779. return reference.read();
  780. }
  781. };
  782. flexbuffers.Reference = class {
  783. constructor(reader, offset, parentWidth, byteWidth, type) {
  784. this._reader = reader;
  785. this._offset = offset;
  786. this._parentWidth = parentWidth;
  787. this._byteWidth = byteWidth;
  788. this._type = type;
  789. }
  790. read() {
  791. switch (this._type) {
  792. case 0x00: // null
  793. return null;
  794. case 0x01: // int
  795. return this._reader.int(this._offset, this._parentWidth);
  796. case 0x02: // uint
  797. return this._reader.uint(this._offset, this._parentWidth);
  798. case 0x03: // float
  799. return this._reader.float(this._offset, this._parentWidth);
  800. case 0x04: { // key
  801. return this._reader.string(this._indirect());
  802. }
  803. case 0x05: { // string
  804. const offset = this._indirect();
  805. const size = this._reader.uint(offset - this._byteWidth, this._byteWidth);
  806. return this._reader.string(offset, size);
  807. }
  808. case 0x06: // indirect int
  809. return this._reader.int(this._indirect(), this._byteWidth);
  810. case 0x07: // indirect uint
  811. return this._reader.uint(this._indirect(), this._byteWidth);
  812. case 0x08: // indirect float
  813. return this._reader.float(this._indirect(), this._byteWidth);
  814. case 0x09: { // map
  815. const offset = this._indirect();
  816. const keysOffset = offset - (this._byteWidth * 3);
  817. const keysVectorOffset = keysOffset - this._reader.uint(keysOffset, this._byteWidth);
  818. const keysByteWidth = this._reader.uint(keysOffset + this._byteWidth, this._byteWidth);
  819. const keys = this._typedVector(keysVectorOffset, keysByteWidth, 0x04);
  820. const values = this._vector(offset, this._byteWidth);
  821. const map = {};
  822. for (let i = 0; i < keys.length; i++) {
  823. map[keys[i]] = values[i];
  824. }
  825. return map;
  826. }
  827. case 0x0a: { // vector
  828. return this._vector(this._indirect(), this._byteWidth);
  829. }
  830. case 0x0b: // vector int
  831. case 0x0c: // vector uint
  832. case 0x0d: // vector float
  833. case 0x0e: // vector key
  834. case 0x0f: // vector string deprecated
  835. case 0x24: { // vector bool
  836. return this._typedVector(this._indirect(), this._byteWidth, this._type - 0x0b + 0x01);
  837. }
  838. case 0x10: // vector int2
  839. case 0x11: // vector uint2
  840. case 0x12: // vector float2
  841. case 0x13: // vector int3
  842. case 0x14: // vector uint3
  843. case 0x15: // vector float3
  844. case 0x16: // vector int4
  845. case 0x17: // vector uint4
  846. case 0x18: { // vector float4
  847. const offset = this._indirect();
  848. const size = (((this._type - 0x10) / 3) >> 0) + 2;
  849. const type = ((this._type - 0x10) % 3) + 0x01;
  850. return this._typedVector(offset, this._byteWidth, type, size);
  851. }
  852. case 0x19: { // blob
  853. const offset = this._indirect();
  854. const size = this._reader.uint(offset - this._byteWidth, this._byteWidth);
  855. return this._reader.bytes(offset, size);
  856. }
  857. case 0x1a: { // bool
  858. return this._reader.uint(this._offset, this._parentWidth) !== 0;
  859. }
  860. }
  861. return undefined;
  862. }
  863. _indirect() {
  864. return this._offset - this._reader.uint(this._offset, this._parentWidth);
  865. }
  866. _vector(offset, byteWidth) {
  867. const size = this._reader.uint(offset - byteWidth, byteWidth);
  868. const packedTypeOffset = offset + (size * byteWidth);
  869. const vector = new Array(size);
  870. for (let i = 0; i < size; i++) {
  871. const packedType = this._reader.uint(packedTypeOffset + i, 1);
  872. const reference = new flexbuffers.Reference(this._reader, offset + (i * byteWidth), byteWidth, 1 << (packedType & 3), packedType >> 2);
  873. vector[i] = reference.read();
  874. }
  875. return vector;
  876. }
  877. _typedVector(offset, byteWidth, type, size) {
  878. size = size === undefined ? this._reader.uint(offset - byteWidth, byteWidth) : size;
  879. const vector = new Array(size);
  880. for (let i = 0; i < size; i++) {
  881. const reference = new flexbuffers.Reference(this._reader, offset + (i * byteWidth), byteWidth, 1, type);
  882. vector[i] = reference.read();
  883. }
  884. return vector;
  885. }
  886. };
  887. flexbuffers.BinaryReader = class {
  888. constructor(buffer) {
  889. this._buffer = buffer;
  890. this._length = buffer.length;
  891. this._view = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength);
  892. this._utf8Decoder = new TextDecoder('utf-8');
  893. }
  894. get length() {
  895. return this._length;
  896. }
  897. int(offset, size) {
  898. switch (size) {
  899. case 1: return this._view.getInt8(offset);
  900. case 2: return this._view.getInt16(offset, true);
  901. case 4: return this._view.getInt32(offset, true);
  902. case 8: return this._view.getInt64(offset, true);
  903. }
  904. throw new flexbuffers.Error("Invalid int size '" + size + "'.");
  905. }
  906. uint(offset, size) {
  907. switch (size) {
  908. case 1: return this._view.getUint8(offset);
  909. case 2: return this._view.getUint16(offset, true);
  910. case 4: return this._view.getUint32(offset, true);
  911. case 8: return this._view.getUint64(offset, true);
  912. }
  913. throw new flexbuffers.Error("Invalid uint size '" + size + "'.");
  914. }
  915. float(offset, size) {
  916. switch (size) {
  917. case 4: return this._view.getFloat32(offset, true);
  918. case 8: return this._view.getFloat64(offset, true);
  919. }
  920. throw new flexbuffers.Error("Invalid float size '" + size + "'.");
  921. }
  922. string(offset, size) {
  923. let end = size === undefined ? this._buffer.indexOf(0, offset) : offset + size;
  924. end = end === -1 ? this._buffer.length : end;
  925. const bytes = this._buffer.subarray(offset, end);
  926. return this._utf8Decoder.decode(bytes);
  927. }
  928. bytes(offset, size) {
  929. return this._buffer.slice(offset, offset + size);
  930. }
  931. };
  932. flexbuffers.Error = class extends Error {
  933. constructor(message) {
  934. super(message);
  935. this.name = 'FlexBuffers Error';
  936. this.message = message;
  937. }
  938. };
  939. if (typeof module !== 'undefined' && typeof module.exports === 'object') {
  940. module.exports.ModelFactory = circle.ModelFactory;
  941. }