| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268 |
- // Experimental
- import * as python from './python.js';
- const numpy = {};
- numpy.ModelFactory = class {
- async match(context) {
- const stream = context.stream;
- const signature = [0x93, 0x4E, 0x55, 0x4D, 0x50, 0x59];
- if (stream && signature.length <= stream.length && stream.peek(signature.length).every((value, index) => value === signature[index])) {
- return context.set('npy');
- }
- const entries = await context.peek('npz');
- if (entries && entries.size > 0) {
- return context.set('npz', entries);
- }
- return null;
- }
- async open(context) {
- let format = '';
- const modules = [];
- switch (context.type) {
- case 'npy': {
- format = 'NumPy Array';
- const unresolved = new Set();
- const execution = new python.Execution();
- execution.on('resolve', (sender, name) => unresolved.add(name));
- const stream = context.stream;
- const io = execution.__import__('io');
- const np = execution.__import__('numpy');
- const bytes = new io.BytesIO(stream);
- const array = np.load(bytes);
- if (unresolved.size > 0) {
- const name = unresolved.values().next().value;
- throw new numpy.Error(`Unknown type name '${name}'.`);
- }
- const layer = { type: 'numpy.ndarray', parameters: [{ name: 'value', tensor: { name: '', array } }] };
- modules.push({ layers: [layer] });
- break;
- }
- case 'npz': {
- format = 'NumPy Archive';
- const layers = new Map();
- const entries = Array.from(context.value);
- const separator = entries.every(([name]) => name.endsWith('.weight.npy')) ? '.' : '/';
- for (const [key, array] of entries) {
- const name = key.replace(/\.npy$/, '');
- const path = name.split(separator);
- const parameterName = path.pop();
- const groupName = path.join(separator);
- if (!layers.has(groupName)) {
- layers.set(groupName, { name: groupName, parameters: [] });
- }
- const layer = layers.get(groupName);
- layer.parameters.push({
- name: parameterName,
- tensor: { name, array }
- });
- }
- modules.push({ layers: Array.from(layers.values()) });
- break;
- }
- default: {
- throw new numpy.Error(`Unsupported NumPy format '${context.type}'.`);
- }
- }
- return new numpy.Model(format, modules);
- }
- };
- numpy.Model = class {
- constructor(format, modules) {
- this.format = format;
- this.modules = modules.map((module) => new numpy.Module(module));
- }
- };
- numpy.Module = class {
- constructor(graph) {
- this.name = graph.name || '';
- this.nodes = graph.layers.map((layer) => new numpy.Node(layer));
- this.inputs = [];
- this.outputs = [];
- }
- };
- numpy.Argument = class {
- constructor(name, value) {
- this.name = name;
- this.value = value;
- }
- };
- numpy.Value = class {
- constructor(name, initializer = null) {
- if (typeof name !== 'string') {
- throw new numpy.Error(`Invalid value identifier '${JSON.stringify(name)}'.`);
- }
- this.name = name;
- this.type = initializer.type;
- this.initializer = initializer;
- }
- };
- numpy.Node = class {
- constructor(layer) {
- this.name = layer.name || '';
- this.type = { name: layer.type || 'Object' };
- this.inputs = [];
- this.outputs = [];
- this.attributes = [];
- for (const parameter of layer.parameters) {
- const initializer = new numpy.Tensor(parameter.tensor.array);
- const value = new numpy.Value(parameter.tensor.name || '', initializer);
- const argument = new numpy.Argument(parameter.name, [value]);
- this.inputs.push(argument);
- }
- }
- };
- numpy.Tensor = class {
- constructor(array) {
- this.type = new numpy.TensorType(array.dtype.__name__, new numpy.TensorShape(array.shape));
- this.stride = array.strides.map((stride) => stride / array.itemsize);
- const list = this.type.dataType === 'string' || this.type.dataType === 'object' || this.type.dataType === 'void';
- this.values = list ? array.flatten().tolist() : array.tobytes();
- this.encoding = list ? '|' : array.dtype.byteorder;
- }
- };
- numpy.TensorType = class {
- constructor(dataType, shape) {
- this.dataType = dataType || '?';
- this.shape = shape;
- }
- toString() {
- return this.dataType + this.shape.toString();
- }
- };
- numpy.TensorShape = class {
- constructor(dimensions) {
- this.dimensions = dimensions;
- }
- toString() {
- return this.dimensions && this.dimensions.length > 0 ? `[${this.dimensions.join(',')}]` : '';
- }
- };
- numpy.Utility = class {
- static isTensor(obj) {
- return obj && obj.__class__ &&
- ((obj.__class__.__module__ === 'numpy' && obj.__class__.__name__ === 'ndarray') ||
- (obj.__class__.__module__ === 'numpy.core.memmap' && obj.__class__.__name__ === 'memmap'));
- }
- static weights(obj) {
- const dict = (obj, key) => {
- const dict = key === '' ? obj : obj[key];
- if (dict) {
- const weights = new Map();
- if (dict instanceof Map) {
- for (const [key, obj] of dict) {
- if (numpy.Utility.isTensor(obj)) {
- weights.set(key, obj);
- continue;
- } else if (obj instanceof Map && Array.from(obj).every(([, value]) => numpy.Utility.isTensor(value))) {
- for (const [name, value] of obj) {
- weights.set(`${key}.${name}`, value);
- }
- continue;
- } else if (key === '_metadata') {
- continue;
- }
- return null;
- }
- return weights;
- } else if (!Array.isArray(dict)) {
- const set = new Set(['weight_order', 'lr', 'model_iter', '__class__']);
- for (const [name, value] of Object.entries(dict)) {
- if (numpy.Utility.isTensor(value)) {
- weights.set(name, value);
- continue;
- }
- if (set.has(name)) {
- continue;
- }
- if (value && !Array.isArray(value) && Object.entries(value).every(([, value]) => numpy.Utility.isTensor(value))) {
- if (value && value.__class__ && value.__class__.__module__ && value.__class__.__name__) {
- weights.set(`${name}.__class__`, `${value.__class__.__module__}.${value.__class__.__name__}`);
- }
- for (const [key, obj] of Object.entries(value)) {
- weights.set(`${name}.${key}`, obj);
- }
- continue;
- }
- return null;
- }
- return weights;
- }
- }
- return null;
- };
- const list = (obj, key) => {
- let list = key === '' ? obj : obj[key];
- if (list && Array.isArray(list) && list.every((obj) => Object.values(obj).every((value) => numpy.Utility.isTensor(value)))) {
- list = list.map((obj) => obj instanceof Map ? obj : new Map(Object.entries(obj)));
- }
- if (list && Array.isArray(list)) {
- const weights = new Map();
- for (let i = 0; i < list.length; i++) {
- const obj = list[i];
- if (numpy.Utility.isTensor(obj)) {
- weights.set(i.toString(), obj);
- continue;
- } else if (obj instanceof Map && Array.from(obj).every(([, value]) => numpy.Utility.isTensor(value))) {
- for (const [name, value] of obj) {
- weights.set(`${i}.${name}`, value);
- }
- continue;
- }
- return null;
- }
- return weights;
- }
- return null;
- };
- const keys = ['', 'blobs', 'model', 'experiment_state'];
- for (const key of keys) {
- const weights = dict(obj, key);
- if (weights && weights.size > 0) {
- return weights;
- }
- }
- for (const key of keys) {
- const weights = list(obj, key);
- if (weights) {
- return weights;
- }
- }
- return null;
- }
- };
- numpy.Error = class extends Error {
- constructor(message) {
- super(message);
- this.name = 'Error loading NumPy model.';
- }
- };
- export const ModelFactory = numpy.ModelFactory;
|