caffe.js 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828
  1. /* jshint esversion: 6 */
  2. var caffe = caffe || {};
  3. var protobuf = protobuf || require('./protobuf');
  4. caffe.ModelFactory = class {
  5. match(context) {
  6. const identifier = context.identifier;
  7. const extension = identifier.split('.').pop().toLowerCase();
  8. if (extension == 'caffemodel') {
  9. return true;
  10. }
  11. if (identifier == 'saved_model.pbtxt' || identifier == 'saved_model.prototxt' ||
  12. identifier.endsWith('predict_net.pbtxt') || identifier.endsWith('predict_net.prototxt') ||
  13. identifier.endsWith('init_net.pbtxt') || identifier.endsWith('init_net.prototxt')) {
  14. return false;
  15. }
  16. const tags = context.tags('pbtxt');
  17. if (tags.has('layer') || tags.has('layers') || tags.has('net') || tags.has('train_net') || tags.has('net_param')) {
  18. return true;
  19. }
  20. return false;
  21. }
  22. open(context) {
  23. return context.require('./caffe-proto').then(() => {
  24. caffe.proto = protobuf.get('caffe').caffe;
  25. return caffe.Metadata.open(context).then((metadata) => {
  26. const tags = context.tags('pbtxt');
  27. if (tags.has('net') || tags.has('train_net') || tags.has('net_param')) {
  28. try {
  29. const stream = context.stream;
  30. const reader = protobuf.TextReader.open(stream);
  31. reader.field = function(tag, message) {
  32. if (message instanceof caffe.proto.SolverParameter) {
  33. message[tag] = this.read();
  34. return;
  35. }
  36. throw new Error("Unknown field '" + tag + "'" + this.location());
  37. };
  38. const solver = caffe.proto.SolverParameter.decodeText(reader);
  39. if (solver.net_param) {
  40. return new caffe.Model(metadata, solver.net_param);
  41. }
  42. else if (solver.net || solver.train_net) {
  43. let file = solver.net || solver.train_net;
  44. file = file.split('/').pop();
  45. return context.request(file, null).then((stream) => {
  46. const buffer = stream.peek();
  47. return this._openNetParameterText(metadata, file, buffer);
  48. }).catch((error) => {
  49. if (error) {
  50. const message = error && error.message ? error.message : error.toString();
  51. throw new caffe.Error("Failed to load '" + file + "' (" + message.replace(/\.$/, '') + ').');
  52. }
  53. });
  54. }
  55. }
  56. catch (error) {
  57. // continue regardless of error
  58. }
  59. }
  60. else if (tags.has('layer') || tags.has('layers')) {
  61. return this._openNetParameterText(metadata, context.identifier, context.stream.peek());
  62. }
  63. else {
  64. let netParameter = null;
  65. try {
  66. const stream = context.stream;
  67. const reader = protobuf.BinaryReader.open(stream);
  68. netParameter = caffe.proto.NetParameter.decode(reader);
  69. }
  70. catch (error) {
  71. const message = error && error.message ? error.message : error.toString();
  72. throw new caffe.Error('File format is not caffe.NetParameter (' + message.replace(/\.$/, '') + ').');
  73. }
  74. return new caffe.Model(metadata, netParameter);
  75. }
  76. });
  77. });
  78. }
  79. _openNetParameterText(metadata, identifier, buffer) {
  80. let netParameter = null;
  81. try {
  82. const reader = protobuf.TextReader.open(buffer);
  83. reader.field = function(tag, message) {
  84. const type = message.constructor.name;
  85. if (tag.endsWith('_param') && (type == 'LayerParameter' || type == 'V1LayerParameter' || type == 'V0LayerParameter')) {
  86. message[tag] = caffe.ModelFactory._decodeText(reader);
  87. return;
  88. }
  89. else if (message.constructor.name.endsWith('Parameter') || message.constructor.name === 'ParamSpec') {
  90. if (message[tag]) {
  91. if (!Array.isArray(message[tag])) {
  92. message[tag] = [ message[tag] ];
  93. }
  94. message[tag].push(this.read());
  95. }
  96. else {
  97. message[tag] = this.read();
  98. }
  99. return;
  100. }
  101. throw new Error("Unknown field '" + tag + "'" + this.location());
  102. };
  103. reader.enum = function(type) {
  104. const token = this.token();
  105. this.next();
  106. this.semicolon();
  107. if (!Object.prototype.hasOwnProperty.call(type, token)) {
  108. const value = Number.parseInt(token, 10);
  109. if (!Number.isNaN(token - value)) {
  110. return value;
  111. }
  112. return token;
  113. }
  114. return type[token];
  115. };
  116. if (/MobileNetSSD_train_template.prototxt/.exec(identifier)) {
  117. reader.integer = function() {
  118. const token = this.token();
  119. const value = Number.parseInt(token, 10);
  120. this.next();
  121. this.semicolon();
  122. if (Number.isNaN(token - value)) {
  123. return token;
  124. }
  125. return value;
  126. };
  127. }
  128. netParameter = caffe.proto.NetParameter.decodeText(reader);
  129. }
  130. catch (error) {
  131. const message = error && error.message ? error.message : error.toString();
  132. throw new caffe.Error('File text format is not caffe.NetParameter (' + message.replace(/\.$/, '') + ').');
  133. }
  134. return new caffe.Model(metadata, netParameter);
  135. }
  136. static _decodeText(reader) {
  137. const message = {};
  138. reader.start();
  139. while (!reader.end()) {
  140. const tag = reader.tag();
  141. const value = reader.read();
  142. if (!message[tag]) {
  143. message[tag] = value;
  144. }
  145. else {
  146. if (!Array.isArray(message[tag])) {
  147. message[tag] = [ message[tag] ];
  148. }
  149. message[tag].push(value);
  150. }
  151. }
  152. return message;
  153. }
  154. };
  155. caffe.Model = class {
  156. constructor(metadata, net) {
  157. this._name = net.name;
  158. if (net.layers && net.layers.length > 0) {
  159. if (net.layers.every((layer) => Object.prototype.hasOwnProperty.call(layer, 'layer'))) {
  160. this._version = 0;
  161. net.layer = net.layers;
  162. }
  163. else {
  164. this._version = 1;
  165. net.layer = net.layers;
  166. }
  167. }
  168. else if (net.layer && net.layer.length > 0) {
  169. this._version = 2;
  170. }
  171. this._graphs = [];
  172. const phases = new Set();
  173. for (const layer of net.layer) {
  174. for (const include of layer.include) {
  175. if (include.phase !== undefined) {
  176. phases.add(include.phase);
  177. }
  178. }
  179. }
  180. if (phases.size === 0) {
  181. phases.add(-1);
  182. }
  183. for (const phase of phases) {
  184. this._graphs.push(new caffe.Graph(metadata, phase, net, this._version));
  185. }
  186. }
  187. get format() {
  188. return 'Caffe' + (this._version ? ' v' + this._version.toString() : '');
  189. }
  190. get graphs() {
  191. return this._graphs;
  192. }
  193. };
  194. caffe.Graph = class {
  195. constructor(metadata, phase, net, version) {
  196. switch (phase) {
  197. case 0: this._phase = 'TRAIN'; break;
  198. case 1: this._phase = 'TEST'; break;
  199. case -1: this._phase = ''; break;
  200. default: this._phase = phase.toString(); break;
  201. }
  202. this._nodes = [];
  203. this._inputs = [];
  204. this._outputs = [];
  205. for (const layer of net.layer) {
  206. layer.input = layer.bottom.slice(0);
  207. layer.output = layer.top.slice(0);
  208. layer.chain = [];
  209. }
  210. const layers = [];
  211. for (const layer of net.layer) {
  212. if (phase === -1 || layer.include.every((include) => include.phase === phase)) {
  213. layers.push(layer);
  214. }
  215. }
  216. const scope = {};
  217. let index = 0;
  218. for (const layer of layers) {
  219. layer.input = layer.input.map((input) => scope[input] ? scope[input] : input);
  220. layer.output = layer.output.map((output) => {
  221. scope[output] = scope[output] ? output + '\n' + index.toString() : output; // custom argument id
  222. return scope[output];
  223. });
  224. index++;
  225. }
  226. // Graph Inputs
  227. const usedOutputs = new Set();
  228. for (const layer of layers) {
  229. for (const output of layer.output) {
  230. usedOutputs.add(output);
  231. }
  232. }
  233. const unusedInputs = [];
  234. for (const layer of layers) {
  235. for (const input of layer.input) {
  236. if (!usedOutputs.has(input)) {
  237. unusedInputs.push(input);
  238. }
  239. }
  240. }
  241. const nodes = [];
  242. let lastLayer = null;
  243. let lastTop = null;
  244. while (layers.length > 0) {
  245. let layer = layers.shift();
  246. if (layer.output.length == 1 && layer.input.length == 1 &&
  247. layer.output[0].split('\n').shift() == layer.input[0].split('\n').shift() &&
  248. lastLayer &&
  249. lastTop == layer.output[0].split('\n').shift()) {
  250. lastLayer.chain = lastLayer.chain || [];
  251. lastLayer.chain.push(layer);
  252. }
  253. else {
  254. if (layer.type == 'Input' || layer.type == 'Data') {
  255. if (layer.input.length == 0 && layer.output.length == 1 &&
  256. layer.input_param && layer.input_param.shape &&
  257. layer.input_param.shape.length == 1 && layer.input_param.shape[0].dim) {
  258. const shape = new caffe.TensorShape(layer.input_param.shape[0].dim.map((dim) => dim.toNumber()));
  259. const type = new caffe.TensorType(null, shape);
  260. this._inputs.push(new caffe.Parameter(layer.output[0], [ new caffe.Argument(layer.output[0], type) ]));
  261. layer = null;
  262. }
  263. }
  264. if (layer) {
  265. nodes.push(layer);
  266. lastLayer = null;
  267. lastTop = null;
  268. if (layer.output.length == 1) {
  269. lastLayer = layer;
  270. lastTop = layer.output[0].split('\n').shift();
  271. }
  272. }
  273. }
  274. }
  275. if (net.input) {
  276. for (let i = 0; i < net.input.length; i++) {
  277. const input = net.input[i];
  278. if (this._inputs.some((item) => item.name === input)) {
  279. continue;
  280. }
  281. let inputType = null;
  282. if (net.input_shape && i < net.input_shape.length) {
  283. const blobShape = net.input_shape[i];
  284. if (blobShape && blobShape.dim) {
  285. const shape = new caffe.TensorShape(blobShape.dim.map((dim) => dim.toNumber()));
  286. inputType = new caffe.TensorType(null, shape);
  287. }
  288. }
  289. const dim = i * 4;
  290. if (!inputType && net.input_dim && net.input_dim.length >= dim) {
  291. const shape = new caffe.TensorShape(net.input_dim.slice(dim, dim + 4));
  292. inputType = new caffe.TensorType(null, shape);
  293. }
  294. this._inputs.push(new caffe.Parameter(input, [ new caffe.Argument(input, inputType, null) ]));
  295. }
  296. }
  297. for (const layer of nodes) {
  298. const node = new caffe.Node(metadata, layer, version);
  299. if (layer.chain && layer.chain.length > 0) {
  300. for (const chain of layer.chain) {
  301. node.chain.push(new caffe.Node(metadata, chain, version));
  302. }
  303. }
  304. this._nodes.push(node);
  305. }
  306. if (this._inputs.length === 0 && unusedInputs.length === 1) {
  307. this._inputs.push(new caffe.Parameter(unusedInputs[0], [
  308. new caffe.Argument(unusedInputs[0], null)
  309. ]));
  310. }
  311. }
  312. get name() {
  313. return this._phase;
  314. }
  315. get type() {
  316. return '';
  317. }
  318. get inputs() {
  319. return this._inputs;
  320. }
  321. get outputs() {
  322. return this._outputs;
  323. }
  324. get nodes() {
  325. return this._nodes;
  326. }
  327. };
  328. caffe.Parameter = class {
  329. constructor(name, args) {
  330. this._name = name;
  331. this._arguments = args;
  332. }
  333. get name() {
  334. return this._name;
  335. }
  336. get visible() {
  337. return true;
  338. }
  339. get arguments() {
  340. return this._arguments;
  341. }
  342. };
  343. caffe.Argument = class {
  344. constructor(name, type, initializer) {
  345. if (typeof name !== 'string') {
  346. throw new caffe.Error("Invalid argument identifier '" + JSON.stringify(name) + "'.");
  347. }
  348. this._name = name;
  349. this._type = type || null;
  350. this._initializer = initializer || null;
  351. }
  352. get name() {
  353. return this._name;
  354. }
  355. get type() {
  356. return this._type;
  357. }
  358. get initializer() {
  359. return this._initializer;
  360. }
  361. };
  362. caffe.Node = class {
  363. constructor(metadata, layer, version) {
  364. this._chain = [];
  365. this._attributes = [];
  366. let type;
  367. switch (version) {
  368. case 0: {
  369. this._name = layer.layer.name;
  370. type = layer.layer.type;
  371. break;
  372. }
  373. case 1: {
  374. this._name = layer.name;
  375. type = caffe.Utility.layerType(layer.type);
  376. break;
  377. }
  378. case 2: {
  379. this._name = layer.name;
  380. type = layer.type;
  381. break;
  382. }
  383. }
  384. this._type = metadata.type(type) || { name: type };
  385. let initializers = [];
  386. switch (version) {
  387. case 0: {
  388. for (const name of Object.keys(layer.layer)) {
  389. if (name != 'type' && name != 'name' && name != 'blobs' && name != 'blobs_lr') {
  390. const value = layer.layer[name];
  391. const attribute = new caffe.Attribute(metadata.attribute(type, name), name, value);
  392. this._attributes.push(attribute);
  393. }
  394. }
  395. initializers = layer.layer.blobs.map((blob) => new caffe.Tensor(blob));
  396. break;
  397. }
  398. case 1:
  399. case 2: {
  400. for (const layer_kind of Object.keys(layer)) {
  401. if (layer_kind.endsWith('_param') || layer_kind == 'transform_param') {
  402. const param = layer[layer_kind];
  403. if (type == 'Deconvolution') {
  404. type = 'Convolution';
  405. }
  406. const prototype = Object.getPrototypeOf(param);
  407. for (const name of Object.keys(param)) {
  408. const defaultValue = prototype[name];
  409. const value = param[name];
  410. const attribute = new caffe.Attribute(metadata.attribute(type, name), name, value, defaultValue);
  411. this._attributes.push(attribute);
  412. }
  413. }
  414. }
  415. if (layer.include && layer.include.length > 0) {
  416. const attribute = new caffe.Attribute(metadata.attribute(type, 'include'), 'include', layer.include);
  417. this._attributes.push(attribute);
  418. }
  419. if (layer.exclude && layer.exclude.length > 0) {
  420. const attribute = new caffe.Attribute(metadata.attribute(type, 'exclude'), 'exclude', layer.exclude);
  421. this._attributes.push(attribute);
  422. }
  423. if (this._type == 'Data' && layer.input_param && layer.input_param.shape) {
  424. const attribute = new caffe.Attribute(metadata.attribute(type, 'shape'), 'shape', layer.input_param.shape);
  425. this._attributes.push(attribute);
  426. }
  427. initializers = layer.blobs.map((blob) => new caffe.Tensor(blob));
  428. break;
  429. }
  430. }
  431. this._inputs = [];
  432. const inputs = layer.input.concat(initializers);
  433. let inputIndex = 0;
  434. if (this._type && this._type.inputs) {
  435. for (const inputDef of this._type.inputs) {
  436. if (inputIndex < inputs.length || inputDef.option != 'optional') {
  437. const inputCount = inputDef.option == 'variadic' ? inputs.length - inputIndex : 1;
  438. this._inputs.push(new caffe.Parameter(inputDef.name, inputs.slice(inputIndex, inputIndex + inputCount).filter((input) => input !== '' || inputDef.option != 'optional').map((input) => {
  439. return input instanceof caffe.Tensor ? new caffe.Argument('', input.type, input) : new caffe.Argument(input, null, null);
  440. })));
  441. inputIndex += inputCount;
  442. }
  443. }
  444. }
  445. this._inputs.push(...inputs.slice(inputIndex).map((input) => {
  446. return new caffe.Parameter(inputIndex.toString(), [
  447. input instanceof caffe.Tensor ? new caffe.Argument('', input.type, input) : new caffe.Argument(input, null, null)
  448. ]);
  449. }));
  450. this._outputs = [];
  451. const outputs = layer.output;
  452. let outputIndex = 0;
  453. if (this._type && this._type.outputs) {
  454. for (const outputDef of this._type.outputs) {
  455. if (outputIndex < outputs.length) {
  456. const outputCount = (outputDef.option == 'variadic') ? (outputs.length - outputIndex) : 1;
  457. this._outputs.push(new caffe.Parameter(outputDef.name, outputs.slice(outputIndex, outputIndex + outputCount).map((output) => {
  458. return new caffe.Argument(output, null, null);
  459. })));
  460. outputIndex += outputCount;
  461. }
  462. }
  463. }
  464. this._outputs.push(...outputs.slice(outputIndex).map((output, index) => {
  465. return new caffe.Parameter((outputIndex + index).toString(), [
  466. new caffe.Argument(output, null, null)
  467. ]);
  468. }));
  469. }
  470. get type() {
  471. return this._type;
  472. }
  473. get name() {
  474. return this._name;
  475. }
  476. get inputs() {
  477. return this._inputs;
  478. }
  479. get outputs() {
  480. return this._outputs;
  481. }
  482. get attributes() {
  483. return this._attributes;
  484. }
  485. get chain() {
  486. return this._chain;
  487. }
  488. };
  489. caffe.Attribute = class {
  490. constructor(metadata, name, value, defaultValue) {
  491. this._name = name;
  492. this._value = value;
  493. if (metadata && metadata.type) {
  494. this._type = metadata.type;
  495. }
  496. if (value instanceof caffe.proto.BlobShape) {
  497. this._value = new caffe.TensorShape(value.dim.map((dim) => dim.toNumber()));
  498. this._type = 'shape';
  499. }
  500. if (metadata && Object.prototype.hasOwnProperty.call(metadata, 'visible') && !metadata.visible) {
  501. this._visible = false;
  502. }
  503. if (metadata && Object.prototype.hasOwnProperty.call(metadata, 'default')) {
  504. defaultValue = metadata.default;
  505. }
  506. if (defaultValue !== undefined) {
  507. if (this._value == defaultValue) {
  508. this._visible = false;
  509. }
  510. else if (Array.isArray(this._value) && Array.isArray(defaultValue)) {
  511. if (this._value.length == defaultValue.length &&
  512. this._value.every((item, index) => { return item == defaultValue[index]; })) {
  513. this._visible = false;
  514. }
  515. }
  516. }
  517. if (this._type) {
  518. this._value = caffe.Utility.enum(this._type, this._value);
  519. }
  520. }
  521. get type() {
  522. return this._type;
  523. }
  524. get name() {
  525. return this._name;
  526. }
  527. get value() {
  528. return this._value;
  529. }
  530. get visible() {
  531. return this._visible == false ? false : true;
  532. }
  533. };
  534. caffe.Tensor = class {
  535. constructor(blob) {
  536. this._blob = blob;
  537. let shape = [];
  538. if (Object.prototype.hasOwnProperty.call(blob, 'num') &&
  539. Object.prototype.hasOwnProperty.call(blob, 'channels') &&
  540. Object.prototype.hasOwnProperty.call(blob, 'width') &&
  541. Object.prototype.hasOwnProperty.call(blob, 'height')) {
  542. if (blob.num != 1) {
  543. shape.push(blob.num);
  544. }
  545. if (blob.channels != 1) {
  546. shape.push(blob.channels);
  547. }
  548. if (blob.height != 1) {
  549. shape.push(blob.height);
  550. }
  551. if (blob.width != 1) {
  552. shape.push(blob.width);
  553. }
  554. }
  555. else if (Object.prototype.hasOwnProperty.call(blob, 'shape')) {
  556. shape = blob.shape.dim.map((dim) => dim.toNumber());
  557. }
  558. let dataType = '?';
  559. if (blob.data.length > 0) {
  560. dataType = 'float32';
  561. this._data = blob.data;
  562. }
  563. else if (blob.double_data.length > 0) {
  564. dataType = 'float64';
  565. this._data = blob.double_data;
  566. }
  567. this._type = new caffe.TensorType(dataType, new caffe.TensorShape(shape));
  568. }
  569. get kind() {
  570. return 'Blob';
  571. }
  572. get type() {
  573. return this._type;
  574. }
  575. get state() {
  576. return this._context().state;
  577. }
  578. get value() {
  579. const context = this._context();
  580. if (context.state) {
  581. return null;
  582. }
  583. context.limit = Number.MAX_SAFE_INTEGER;
  584. return this._decode(context, 0);
  585. }
  586. toString() {
  587. const context = this._context();
  588. if (context.state) {
  589. return '';
  590. }
  591. context.limit = 10000;
  592. const value = this._decode(context, 0);
  593. return JSON.stringify(value, null, 4);
  594. }
  595. _context() {
  596. const context = {};
  597. context.state = null;
  598. context.index = 0;
  599. context.count = 0;
  600. context.data = this._data;
  601. context.dimensions = this.type.shape.dimensions;
  602. if (!this._data) {
  603. context.state = 'Tensor data is empty.';
  604. }
  605. return context;
  606. }
  607. _decode(context, dimension) {
  608. const results = [];
  609. const size = context.dimensions[dimension];
  610. if (dimension == context.dimensions.length - 1) {
  611. for (let i = 0; i < size; i++) {
  612. if (context.count > context.limit) {
  613. results.push('...');
  614. return results;
  615. }
  616. results.push(context.data[context.index]);
  617. context.index++;
  618. context.count++;
  619. }
  620. }
  621. else {
  622. for (let j = 0; j < size; j++) {
  623. if (context.count > context.limit) {
  624. results.push('...');
  625. return results;
  626. }
  627. results.push(this._decode(context, dimension + 1));
  628. }
  629. }
  630. return results;
  631. }
  632. };
  633. caffe.TensorType = class {
  634. constructor(dataType, shape) {
  635. this._dataType = dataType;
  636. this._shape = shape;
  637. }
  638. get dataType() {
  639. return this._dataType;
  640. }
  641. get shape() {
  642. return this._shape;
  643. }
  644. toString() {
  645. return (this.dataType || '?') + this._shape.toString();
  646. }
  647. };
  648. caffe.TensorShape = class {
  649. constructor(dimensions) {
  650. this._dimensions = dimensions;
  651. }
  652. get dimensions() {
  653. return this._dimensions;
  654. }
  655. toString() {
  656. return this._dimensions ? ('[' + this._dimensions.map((dimension) => dimension.toString()).join(',') + ']') : '';
  657. }
  658. };
  659. caffe.Utility = class {
  660. static layerType(type) {
  661. type = type || 0;
  662. if (!caffe.Utility._layerTypeMap) {
  663. caffe.Utility._layerTypeMap = new Map();
  664. const known = { 'BNLL': 'BNLL', 'HDF5': 'HDF5', 'LRN': 'LRN', 'RELU': 'ReLU', 'TANH': 'TanH', 'ARGMAX': 'ArgMax', 'MVN': 'MVN', 'ABSVAL': 'AbsVal' };
  665. for (const key of Object.keys(caffe.proto.V1LayerParameter.LayerType)) {
  666. const value = caffe.proto.V1LayerParameter.LayerType[key];
  667. caffe.Utility._layerTypeMap.set(value, key.split('_').map((item) => known[item] || item.substring(0, 1) + item.substring(1).toLowerCase()).join(''));
  668. }
  669. }
  670. return caffe.Utility._layerTypeMap.has(type) ? caffe.Utility._layerTypeMap.get(type) : type.toString();
  671. }
  672. static enum(name, value) {
  673. let type = caffe.proto;
  674. const parts = name.split('.');
  675. while (type && parts.length > 0) {
  676. type = type[parts.shift()];
  677. }
  678. if (type) {
  679. caffe.Utility._enumKeyMap = caffe.Utility._enumKeyMap || new Map();
  680. if (!caffe.Utility._enumKeyMap.has(name)) {
  681. const map = new Map(Object.entries(type).map((pair) => [ pair[1], pair[0] ]));
  682. caffe.Utility._enumKeyMap.set(name, map);
  683. }
  684. const map = caffe.Utility._enumKeyMap.get(name);
  685. if (map.has(value)) {
  686. return map.get(value);
  687. }
  688. }
  689. return value;
  690. }
  691. };
  692. caffe.Metadata = class {
  693. static open(context) {
  694. if (caffe.Metadata._metadata) {
  695. return Promise.resolve(caffe.Metadata._metadata);
  696. }
  697. return context.request('caffe-metadata.json', 'utf-8', null).then((data) => {
  698. caffe.Metadata._metadata = new caffe.Metadata(data);
  699. return caffe.Metadata._metadata;
  700. }).catch(() => {
  701. caffe.Metadata._metadata = new caffe.Metadata(null);
  702. return caffe.Metadata._metadata;
  703. });
  704. }
  705. constructor(data) {
  706. this._map = new Map();
  707. this._attributeCache = new Map();
  708. if (data) {
  709. const metadata = JSON.parse(data);
  710. this._map = new Map(metadata.map((item) => [ item.name, item ]));
  711. }
  712. }
  713. type(name) {
  714. return this._map.get(name);
  715. }
  716. attribute(type, name) {
  717. const key = type + ':' + name;
  718. if (!this._attributeCache.has(key)) {
  719. this._attributeCache.set(key, null);
  720. const metadata = this.type(type);
  721. if (metadata && Array.isArray(metadata.attributes) && metadata.attributes.length > 0) {
  722. for (const attribute of metadata.attributes) {
  723. this._attributeCache.set(type + ':' + attribute.name, attribute);
  724. }
  725. }
  726. }
  727. return this._attributeCache.get(key);
  728. }
  729. };
  730. caffe.Error = class extends Error {
  731. constructor(message) {
  732. super(message);
  733. this.name = 'Error loading Caffe model.';
  734. }
  735. };
  736. if (typeof module !== 'undefined' && typeof module.exports === 'object') {
  737. module.exports.ModelFactory = caffe.ModelFactory;
  738. }