// Experimental const lasagne = {}; lasagne.ModelFactory = class { async match(context) { const obj = await context.peek('pkl'); if (obj && obj.__class__ && obj.__class__.__module__ === 'nolearn.lasagne.base' && obj.__class__.__name__ === 'NeuralNet') { return context.set('lasagne', obj); } return null; } async open(context) { const metadata = await context.metadata('lasagne-metadata.json'); return new lasagne.Model(metadata, context.value); } }; lasagne.Model = class { constructor(metadata, model) { this.format = 'Lasagne'; this.modules = [new lasagne.Graph(metadata, model)]; } }; lasagne.Graph = class { constructor(metadata, model) { this.nodes = []; this.inputs = []; this.outputs = []; const values = new Map(); values.map = (name, type, tensor) => { if (!values.has(name)) { values.set(name, new lasagne.Value(name, type, tensor)); } else if (tensor) { throw new lasagne.Error(`Duplicate value '${name}'.`); } else if (type && !type.equals(values.get(name).type)) { throw new lasagne.Error(`Duplicate value '${name}'.`); } return values.get(name); }; for (const [name] of model.layers) { const layer = model.layers_[name]; if (layer.input_layer && layer.input_layer.name) { const input_layer = layer.input_layer; const dataType = input_layer.input_var && input_layer.input_var.type ? input_layer.input_var.type.dtype : '?'; const shape = layer.input_shape ? new lasagne.TensorShape(layer.input_shape) : null; const type = shape ? new lasagne.TensorType(dataType, shape) : null; values.map(input_layer.name, type); } } for (const [name] of model.layers) { const layer = model.layers_[name]; if (layer && layer.__class__ && layer.__class__.__module__ === 'lasagne.layers.input' && layer.__class__.__name__ === 'InputLayer') { const shape = new lasagne.TensorShape(layer.shape); const type = new lasagne.TensorType(layer.input_var.type.dtype, shape); const argument = new lasagne.Argument(layer.name, [values.map(layer.name, type)]); this.inputs.push(argument); continue; } this.nodes.push(new lasagne.Node(metadata, layer, values)); } if (model._output_layer) { const output_layer = model._output_layer; this.outputs.push(new lasagne.Argument(output_layer.name, [values.map(output_layer.name)])); } } }; lasagne.Argument = class { constructor(name, value, type = null) { this.name = name; this.value = value; this.type = type; } }; lasagne.Value = class { constructor(name, type, initializer) { if (typeof name !== 'string') { throw new lasagne.Error(`Invalid value identifier '${JSON.stringify(name)}'.`); } this.name = name; this.type = !type && initializer ? initializer.type : type; this.initializer = initializer; } }; lasagne.Node = class { constructor(metadata, layer, values) { this.name = layer.name || ''; const type = layer.__class__ ? `${layer.__class__.__module__}.${layer.__class__.__name__}` : ''; this.type = metadata.type(type) || { name: type }; this.inputs = []; this.outputs = []; this.attributes = []; const params = new Map(); for (const [key, value] of Object.entries(layer)) { if (key === 'name' || key === 'params' || key === 'input_layer' || key === 'input_shape') { continue; } if (value && value.__class__ && value.__class__.__module__ === 'theano.tensor.sharedvar' && value.__class__.__name__ === 'TensorSharedVariable') { params.set(value.name, key); continue; } const type = value && value.__class__ ? `${value.__class__.__module__}.${value.__class__.__name__}` : null; const attribute = new lasagne.Argument(key, value, type); this.attributes.push(attribute); } if (layer.input_layer && layer.input_layer.name) { const value = values.map(layer.input_layer.name); const argument = new lasagne.Argument('input', [value]); this.inputs.push(argument); } if (layer.params) { for (const [param] of layer.params) { const param_key = params.get(param.name); if (param_key) { const initializer = new lasagne.Tensor(param.container.storage[0]); const argument = new lasagne.Argument(param_key, [values.map(param.name, null, initializer)]); this.inputs.push(argument); } } } this.outputs.push(new lasagne.Argument('output', [values.map(this.name)])); } }; lasagne.TensorType = class { constructor(dataType, shape) { this.dataType = dataType; this.shape = shape; } equals(obj) { return obj && this.dataType === obj.dataType && this.shape && this.shape.equals(obj.shape); } toString() { return this.dataType + this.shape.toString(); } }; lasagne.TensorShape = class { constructor(dimensions) { this.dimensions = dimensions; } equals(obj) { return obj && Array.isArray(obj.dimensions) && Array.isArray(this.dimensions) && this.dimensions.length === obj.dimensions.length && obj.dimensions.every((value, index) => this.dimensions[index] === value); } toString() { if (this.dimensions && this.dimensions.length > 0) { return `[${this.dimensions.map((dimension) => dimension ? dimension.toString() : '?').join(',')}]`; } return ''; } }; lasagne.Tensor = class { constructor(storage) { this.type = new lasagne.TensorType(storage.dtype.__name__, new lasagne.TensorShape(storage.shape)); this.values = storage.data; } }; lasagne.Error = class extends Error { constructor(message) { super(message); this.name = 'Lasagne Error'; } }; export const ModelFactory = lasagne.ModelFactory;