2
0

numpy.js 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583
  1. // Experimental
  2. var numpy = numpy || {};
  3. var python = python || require('./python');
  4. numpy.ModelFactory = class {
  5. match(context) {
  6. const stream = context.stream;
  7. const signature = [ 0x93, 0x4E, 0x55, 0x4D, 0x50, 0x59 ];
  8. if (stream && signature.length <= stream.length && stream.peek(signature.length).every((value, index) => value === signature[index])) {
  9. return { name: 'npy' };
  10. }
  11. const entries = context.entries('zip');
  12. if (entries.size > 0 && Array.from(entries.keys()).every((name) => name.endsWith('.npy'))) {
  13. return { name: 'npz', value: entries };
  14. }
  15. const obj = context.open('pkl');
  16. if (obj) {
  17. if (numpy.Utility.isTensor(obj)) {
  18. return { name: 'numpy.ndarray', value: obj };
  19. }
  20. if (Array.isArray(obj) && obj.every((obj) => obj && obj.__class__ && obj.__class__.__name__ === 'Network' && (obj.__class__.__module__ === 'dnnlib.tflib.network' || obj.__class__.__module__ === 'tfutil'))) {
  21. return { name: 'dnnlib.tflib.network', value: obj };
  22. }
  23. const weights = numpy.Utility.weights(obj);
  24. if (weights) {
  25. return { name: 'pickle', value: weights };
  26. }
  27. }
  28. return undefined;
  29. }
  30. open(context, match) {
  31. let format = '';
  32. const graphs = [];
  33. switch (match.name) {
  34. case 'npy': {
  35. format = 'NumPy Array';
  36. const execution = new python.Execution(null);
  37. const stream = context.stream;
  38. const buffer = stream.peek();
  39. const bytes = execution.invoke('io.BytesIO', [ buffer ]);
  40. const array = execution.invoke('numpy.load', [ bytes ]);
  41. const layer = { type: 'numpy.ndarray', parameters: [ { name: 'value', tensor: { name: '', array: array } } ] };
  42. graphs.push({ layers: [ layer ] });
  43. break;
  44. }
  45. case 'npz': {
  46. format = 'NumPy Zip';
  47. const layers = new Map();
  48. const execution = new python.Execution(null);
  49. for (const entry of match.value) {
  50. if (!entry[0].endsWith('.npy')) {
  51. throw new numpy.Error("Invalid file name '" + entry.name + "'.");
  52. }
  53. const name = entry[0].replace(/\.npy$/, '');
  54. const parts = name.split('/');
  55. const parameterName = parts.pop();
  56. const groupName = parts.join('/');
  57. if (!layers.has(groupName)) {
  58. layers.set(groupName, { name: groupName, parameters: [] });
  59. }
  60. const layer = layers.get(groupName);
  61. const stream = entry[1];
  62. const buffer = stream.peek();
  63. const bytes = execution.invoke('io.BytesIO', [ buffer ]);
  64. let array = execution.invoke('numpy.load', [ bytes ]);
  65. if (array.dtype.byteorder === '|' && array.dtype.itemsize !== 1) {
  66. if (array.dtype.kind !== 'O') {
  67. throw new numpy.Error("Invalid data type '" + array.dataType + "'.");
  68. }
  69. const unpickler = python.Unpickler.open(array.data, execution);
  70. array = unpickler.load();
  71. }
  72. layer.parameters.push({
  73. name: parameterName,
  74. tensor: { name: name, array: array }
  75. });
  76. }
  77. graphs.push({ layers: Array.from(layers.values()) });
  78. break;
  79. }
  80. case 'pickle': {
  81. format = 'NumPy Weights';
  82. const layers = new Map();
  83. const weights = match.value;
  84. let separator = '.';
  85. if (Array.from(weights.keys()).filter((key) => key.indexOf('_') !== -1) &&
  86. Array.from(weights.keys()).every((key) => key.indexOf('_') > key.indexOf('.'))) {
  87. separator = '_';
  88. }
  89. for (const pair of weights) {
  90. const name = pair[0];
  91. const array = pair[1];
  92. const parts = name.split(separator);
  93. const parameterName = parts.length > 1 ? parts.pop() : '?';
  94. const layerName = parts.join(separator);
  95. if (!layers.has(layerName)) {
  96. layers.set(layerName, { name: layerName, parameters: [] });
  97. }
  98. const layer = layers.get(layerName);
  99. layer.parameters.push({
  100. name: parameterName,
  101. tensor: { name: name, array: array }
  102. });
  103. }
  104. graphs.push({ layers: Array.from(layers.values()) });
  105. break;
  106. }
  107. case 'numpy.ndarray': {
  108. format = 'NumPy NDArray';
  109. const layer = {
  110. type: 'numpy.ndarray',
  111. parameters: [ { name: 'value', tensor: { name: '', array: match.value } } ]
  112. };
  113. graphs.push({ layers: [ layer ] });
  114. break;
  115. }
  116. case 'dnnlib.tflib.network': {
  117. format = 'dnnlib';
  118. for (const obj of match.value) {
  119. const layers = new Map();
  120. for (const entry of obj.variables) {
  121. const name = entry[0];
  122. const value = entry[1];
  123. if (numpy.Utility.isTensor(value)) {
  124. const parts = name.split('/');
  125. const parameterName = parts.length > 1 ? parts.pop() : '?';
  126. const layerName = parts.join('/');
  127. if (!layers.has(layerName)) {
  128. layers.set(layerName, { name: layerName, parameters: [] });
  129. }
  130. const layer = layers.get(layerName);
  131. layer.parameters.push({
  132. name: parameterName,
  133. tensor: { name: name, array: value }
  134. });
  135. }
  136. }
  137. graphs.push({ name: obj.name, layers: Array.from(layers.values()) });
  138. }
  139. break;
  140. }
  141. default: {
  142. throw new numpy.Error("Unsupported NumPy format '" + match.name + "'.");
  143. }
  144. }
  145. const model = new numpy.Model(format, graphs);
  146. return Promise.resolve(model);
  147. }
  148. };
  149. numpy.Model = class {
  150. constructor(format, graphs) {
  151. this._format = format;
  152. this._graphs = graphs.map((graph) => new numpy.Graph(graph));
  153. }
  154. get format() {
  155. return this._format;
  156. }
  157. get graphs() {
  158. return this._graphs;
  159. }
  160. };
  161. numpy.Graph = class {
  162. constructor(graph) {
  163. this._name = graph.name || '';
  164. this._nodes = graph.layers.map((layer) => new numpy.Node(layer));
  165. }
  166. get name() {
  167. return this._name;
  168. }
  169. get inputs() {
  170. return [];
  171. }
  172. get outputs() {
  173. return [];
  174. }
  175. get nodes() {
  176. return this._nodes;
  177. }
  178. };
  179. numpy.Parameter = class {
  180. constructor(name, args) {
  181. this._name = name;
  182. this._arguments = args;
  183. }
  184. get name() {
  185. return this._name;
  186. }
  187. get visible() {
  188. return true;
  189. }
  190. get arguments() {
  191. return this._arguments;
  192. }
  193. };
  194. numpy.Argument = class {
  195. constructor(name, initializer) {
  196. if (typeof name !== 'string') {
  197. throw new numpy.Error("Invalid argument identifier '" + JSON.stringify(name) + "'.");
  198. }
  199. this._name = name;
  200. this._initializer = initializer || null;
  201. }
  202. get name() {
  203. return this._name;
  204. }
  205. get type() {
  206. return this._initializer.type;
  207. }
  208. get initializer() {
  209. return this._initializer;
  210. }
  211. };
  212. numpy.Node = class {
  213. constructor(layer) {
  214. this._name = layer.name || '';
  215. this._type = { name: layer.type || '{}' };
  216. this._inputs = [];
  217. for (const parameter of layer.parameters) {
  218. const initializer = new numpy.Tensor(parameter.tensor.array);
  219. this._inputs.push(new numpy.Parameter(parameter.name, [
  220. new numpy.Argument(parameter.tensor.name || '', initializer)
  221. ]));
  222. }
  223. }
  224. get type() {
  225. return this._type;
  226. }
  227. get name() {
  228. return this._name;
  229. }
  230. get inputs() {
  231. return this._inputs;
  232. }
  233. get outputs() {
  234. return [];
  235. }
  236. get attributes() {
  237. return [];
  238. }
  239. };
  240. numpy.Tensor = class {
  241. constructor(array) {
  242. this._type = new numpy.TensorType(array.dtype.__name__, new numpy.TensorShape(array.shape));
  243. this._data = array.tobytes();
  244. this._byteorder = array.dtype.byteorder;
  245. this._itemsize = array.dtype.itemsize;
  246. }
  247. get type(){
  248. return this._type;
  249. }
  250. get state() {
  251. return this._context().state;
  252. }
  253. get value() {
  254. const context = this._context();
  255. if (context.state) {
  256. return null;
  257. }
  258. context.limit = Number.MAX_SAFE_INTEGER;
  259. return this._decode(context, 0);
  260. }
  261. toString() {
  262. const context = this._context();
  263. if (context.state) {
  264. return '';
  265. }
  266. context.limit = 10000;
  267. const value = this._decode(context, 0);
  268. return numpy.Tensor._stringify(value, '', ' ');
  269. }
  270. _context() {
  271. const context = {};
  272. context.index = 0;
  273. context.count = 0;
  274. context.state = null;
  275. if (this._byteorder !== '<' && this._byteorder !== '>' && this._type.dataType !== 'uint8' && this._type.dataType !== 'int8') {
  276. context.state = 'Tensor byte order is not supported.';
  277. return context;
  278. }
  279. if (!this._data || this._data.length == 0) {
  280. context.state = 'Tensor data is empty.';
  281. return context;
  282. }
  283. context.itemSize = this._itemsize;
  284. context.dimensions = this._type.shape.dimensions;
  285. context.dataType = this._type.dataType;
  286. context.littleEndian = this._byteorder == '<';
  287. context.data = this._data;
  288. context.rawData = new DataView(this._data.buffer, this._data.byteOffset, this._data.byteLength);
  289. return context;
  290. }
  291. _decode(context, dimension) {
  292. const littleEndian = context.littleEndian;
  293. const shape = context.dimensions.length == 0 ? [ 1 ] : context.dimensions;
  294. const results = [];
  295. const size = shape[dimension];
  296. if (dimension == shape.length - 1) {
  297. for (let i = 0; i < size; i++) {
  298. if (context.count > context.limit) {
  299. results.push('...');
  300. return results;
  301. }
  302. if (context.rawData) {
  303. switch (context.dataType) {
  304. case 'float16':
  305. results.push(context.rawData.getFloat16(context.index, littleEndian));
  306. break;
  307. case 'float32':
  308. results.push(context.rawData.getFloat32(context.index, littleEndian));
  309. break;
  310. case 'float64':
  311. results.push(context.rawData.getFloat64(context.index, littleEndian));
  312. break;
  313. case 'int8':
  314. results.push(context.rawData.getInt8(context.index, littleEndian));
  315. break;
  316. case 'int16':
  317. results.push(context.rawData.getInt16(context.index, littleEndian));
  318. break;
  319. case 'int32':
  320. results.push(context.rawData.getInt32(context.index, littleEndian));
  321. break;
  322. case 'int64':
  323. results.push(context.rawData.getInt64(context.index, littleEndian));
  324. break;
  325. case 'uint8':
  326. results.push(context.rawData.getUint8(context.index, littleEndian));
  327. break;
  328. case 'uint16':
  329. results.push(context.rawData.getUint16(context.index, littleEndian));
  330. break;
  331. case 'uint32':
  332. results.push(context.rawData.getUint32(context.index, littleEndian));
  333. break;
  334. default:
  335. throw new numpy.Error("Unsupported tensor data type '" + context.dataType + "'.");
  336. }
  337. context.index += context.itemSize;
  338. context.count++;
  339. }
  340. }
  341. }
  342. else {
  343. for (let j = 0; j < size; j++) {
  344. if (context.count > context.limit) {
  345. results.push('...');
  346. return results;
  347. }
  348. results.push(this._decode(context, dimension + 1));
  349. }
  350. }
  351. if (context.dimensions.length == 0) {
  352. return results[0];
  353. }
  354. return results;
  355. }
  356. static _stringify(value, indentation, indent) {
  357. if (Array.isArray(value)) {
  358. const result = [];
  359. result.push(indentation + '[');
  360. const items = value.map((item) => numpy.Tensor._stringify(item, indentation + indent, indent));
  361. if (items.length > 0) {
  362. result.push(items.join(',\n'));
  363. }
  364. result.push(indentation + ']');
  365. return result.join('\n');
  366. }
  367. if (typeof value == 'string') {
  368. return indentation + value;
  369. }
  370. if (value == Infinity) {
  371. return indentation + 'Infinity';
  372. }
  373. if (value == -Infinity) {
  374. return indentation + '-Infinity';
  375. }
  376. if (isNaN(value)) {
  377. return indentation + 'NaN';
  378. }
  379. return indentation + value.toString();
  380. }
  381. };
  382. numpy.TensorType = class {
  383. constructor(dataType, shape) {
  384. this._dataType = dataType;
  385. this._shape = shape;
  386. }
  387. get dataType() {
  388. return this._dataType || '?';
  389. }
  390. get shape() {
  391. return this._shape;
  392. }
  393. toString() {
  394. return this.dataType + this._shape.toString();
  395. }
  396. };
  397. numpy.TensorShape = class {
  398. constructor(dimensions) {
  399. this._dimensions = dimensions;
  400. }
  401. get dimensions() {
  402. return this._dimensions;
  403. }
  404. toString() {
  405. if (!this._dimensions || this._dimensions.length == 0) {
  406. return '';
  407. }
  408. return '[' + this._dimensions.join(',') + ']';
  409. }
  410. };
  411. numpy.Utility = class {
  412. static isTensor(obj) {
  413. return obj && obj.__class__ &&
  414. ((obj.__class__.__module__ === 'numpy' && obj.__class__.__name__ === 'ndarray') ||
  415. (obj.__class__.__module__ === 'numpy.core.memmap' && obj.__class__.__name__ === 'memmap'));
  416. }
  417. static weights(obj) {
  418. const dict = (obj, key) => {
  419. const dict = key === '' ? obj : obj[key];
  420. if (dict) {
  421. const weights = new Map();
  422. if (dict instanceof Map) {
  423. for (const pair of dict) {
  424. const key = pair[0];
  425. const obj = pair[1];
  426. if (numpy.Utility.isTensor(obj)) {
  427. weights.set(key, obj);
  428. continue;
  429. }
  430. else if (obj instanceof Map && Array.from(obj).every((pair) => numpy.Utility.isTensor(pair[1]))) {
  431. for (const pair of obj) {
  432. weights.set(key + '.' + pair[0], pair[1]);
  433. }
  434. continue;
  435. }
  436. else if (key === '_metadata') {
  437. continue;
  438. }
  439. return null;
  440. }
  441. return weights;
  442. }
  443. else if (!Array.isArray(dict)) {
  444. const set = new Set([ 'weight_order', 'lr', 'model_iter', '__class__' ]);
  445. for (const entry of Object.entries(dict)) {
  446. const key = entry[0];
  447. const value = entry[1];
  448. if (key) {
  449. if (numpy.Utility.isTensor(value)) {
  450. weights.set(key, value);
  451. continue;
  452. }
  453. if (set.has(key)) {
  454. continue;
  455. }
  456. if (value && !Array.isArray(value) && Object.entries(value).every((entry) => numpy.Utility.isTensor(entry[1]))) {
  457. const name = key;
  458. for (const entry of Object.entries(value)) {
  459. weights.set(name + '.' + entry[0], entry[1]);
  460. }
  461. continue;
  462. }
  463. }
  464. return null;
  465. }
  466. return weights;
  467. }
  468. }
  469. return null;
  470. };
  471. const list = (obj, key) => {
  472. const list = key === '' ? obj : obj[key];
  473. if (list && Array.isArray(list) && list.every((obj) => Object.entries(obj).every((entry) => numpy.Utility.isTensor(entry[1])))) {
  474. const weights = new Map();
  475. for (let i = 0; i < list.length; i++) {
  476. const obj = list[i];
  477. for (const entry of Object.entries(obj)) {
  478. weights.set(i.toString() + '.' + entry[0], entry[1]);
  479. }
  480. }
  481. return weights;
  482. }
  483. if (list && Array.isArray(list)) {
  484. const weights = new Map();
  485. for (let i = 0; i < list.length; i++) {
  486. const obj = list[i];
  487. if (numpy.Utility.isTensor(obj)) {
  488. weights.set(i.toString(), obj);
  489. continue;
  490. }
  491. else if (obj instanceof Map && Array.from(obj).every((pair) => numpy.Utility.isTensor(pair[1]))) {
  492. for (const pair of obj) {
  493. weights.set(i.toString() + '.' + pair[0], pair[1]);
  494. }
  495. continue;
  496. }
  497. return null;
  498. }
  499. return weights;
  500. }
  501. return null;
  502. };
  503. const keys = [ '', 'blobs', 'model' ];
  504. for (const key of keys) {
  505. const weights = dict(obj, key);
  506. if (weights && weights.size > 0) {
  507. return weights;
  508. }
  509. }
  510. for (const key of keys) {
  511. const weights = list(obj, key);
  512. if (weights) {
  513. return weights;
  514. }
  515. }
  516. return null;
  517. }
  518. };
  519. numpy.Error = class extends Error {
  520. constructor(message) {
  521. super(message);
  522. this.name = 'Error loading Chainer model.';
  523. }
  524. };
  525. if (typeof module !== 'undefined' && typeof module.exports === 'object') {
  526. module.exports.ModelFactory = numpy.ModelFactory;
  527. }