tflite.js 38 KB

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