netron / mlnet.js
shethjenil's picture
Upload 30 files
d0d9416 verified
// Experimental
import * as base from './base.js';
const mlnet = {};
mlnet.ModelFactory = class {
async match(context) {
const entries = await context.peek('zip');
if (entries instanceof Map && entries.size > 0) {
const root = new Set(['TransformerChain', 'Predictor']);
if (Array.from(entries.keys()).some((name) => root.has(name.split('\\').shift().split('/').shift()))) {
return context.set('mlnet', entries);
}
}
return null;
}
async open(context) {
const metadata = await context.metadata('mlnet-metadata.json');
const reader = new mlnet.ModelReader(context.value);
await reader.resolve(context);
return new mlnet.Model(metadata, reader);
}
};
mlnet.Model = class {
constructor(metadata, reader) {
this.format = "ML.NET";
if (reader.version && reader.version.length > 0) {
this.format += ` v${reader.version}`;
}
this.modules = [new mlnet.Module(metadata, reader)];
}
};
mlnet.Module = class {
constructor(metadata, reader) {
this.inputs = [];
this.outputs = [];
this.nodes = [];
this.groups = false;
const values = new Map();
values.map = (name, type) => {
if (!values.has(name)) {
values.set(name, new mlnet.Value(name, type || null));
} else if (type) {
throw new mlnet.Error(`Duplicate value '${name}'.`);
}
return values.get(name);
};
if (reader.schema && reader.schema.inputs) {
for (const input of reader.schema.inputs) {
const argument = new mlnet.Argument(input.name, [values.map(input.name, new mlnet.TensorType(input.type))]);
this.inputs.push(argument);
}
}
const createNode = (scope, group, transformer) => {
if (transformer.inputs && transformer.outputs) {
for (const input of transformer.inputs) {
input.name = scope[input.name] ? scope[input.name].argument : input.name;
}
for (const output of transformer.outputs) {
if (scope[output.name]) {
scope[output.name].counter++;
const next = `${output.name}\n${scope[output.name].counter}`; // custom argument id
scope[output.name].argument = next;
output.name = next;
} else {
scope[output.name] = {
argument: output.name,
counter: 0
};
}
}
}
const node = new mlnet.Node(metadata, transformer, group, values);
this.nodes.push(node);
};
/* eslint-disable no-use-before-define */
const loadChain = (scope, name, chain) => {
this.groups = true;
const group = name.split('/').splice(1).join('/');
for (const childTransformer of chain) {
loadTransformer(scope, group, childTransformer);
}
};
const loadTransformer = (scope, group, transformer) => {
switch (transformer.__type__) {
case 'TransformerChain':
case 'Text':
loadChain(scope, transformer.__name__, transformer.chain);
break;
default:
createNode(scope, group, transformer);
break;
}
};
const scope = new Map();
if (reader.schema && reader.schema.inputs) {
for (const input of reader.schema.inputs) {
scope[input.name] = { argument: input.name, counter: 0 };
}
}
if (reader.dataLoaderModel) {
loadTransformer(scope, '', reader.dataLoaderModel);
}
if (reader.predictor) {
loadTransformer(scope, '', reader.predictor);
}
if (reader.transformerChain) {
loadTransformer(scope, '', reader.transformerChain);
}
}
};
mlnet.Argument = class {
constructor(name, value, type = null) {
this.name = name;
this.value = value;
this.type = type;
}
};
mlnet.Value = class {
constructor(name, type) {
if (typeof name !== 'string') {
throw new mlnet.Error(`Invalid value identifier '${JSON.stringify(name)}'.`);
}
this.name = name;
this.type = type;
this.initializer = null;
}
};
mlnet.Node = class {
constructor(metadata, obj, group, values) {
const op = obj.__type__;
this.type = metadata.type(op) || { name: op || '?' };
this.name = obj.__name__ || '';
this.group = group || '';
this.inputs = [];
this.outputs = [];
this.attributes = [];
if (values && obj.inputs) {
for (let i = 0; i < obj.inputs.length; i++) {
const value = values.map(obj.inputs[i].name);
this.inputs.push(new mlnet.Argument(i.toString(), [value]));
}
}
if (values && obj.outputs) {
for (let i = 0; i < obj.outputs.length; i++) {
this.outputs.push(new mlnet.Argument(i.toString(), [values.map(obj.outputs[i].name)]));
}
}
for (const [name, raw] of Object.entries(obj).filter(([key]) => !key.startsWith('_') && key !== 'inputs' && key !== 'outputs')) {
const schema = metadata.attribute(op, name);
let value = raw;
let type = null;
if (schema) {
type = schema.type ? schema.type : null;
value = mlnet.Utility.enum(type, value);
}
if (value && typeof value === 'object' && !Array.isArray(value) && Array.isArray(value.nodes)) {
type = 'graph';
} else if (value && typeof value === 'object' && !Array.isArray(value) && value.__type__) {
value = new mlnet.Node(metadata, value);
type = 'object';
} else if (Array.isArray(value) && value.length > 0 && value.every((item) => item && item.__type__)) {
value = value.map((item) => new mlnet.Node(metadata, item));
type = 'object[]';
}
this.attributes.push(new mlnet.Argument(name, value, type));
}
}
};
mlnet.TensorType = class {
constructor(codec) {
mlnet.TensorType._map = mlnet.TensorType._map || new Map([
['Byte', 'uint8'],
['Boolean', 'boolean'],
['Single', 'float32'],
['Double', 'float64'],
['UInt32', 'uint32'],
['Int32', 'int32'],
['Int64', 'int64'],
['TextSpan', 'string']
]);
this.dataType = '?';
this.shape = new mlnet.TensorShape(null);
if (mlnet.TensorType._map.has(codec.name)) {
this.dataType = mlnet.TensorType._map.get(codec.name);
} else if (codec.name === 'VBuffer') {
if (mlnet.TensorType._map.has(codec.itemType.name)) {
this.dataType = mlnet.TensorType._map.get(codec.itemType.name);
} else {
throw new mlnet.Error(`Unsupported data type '${codec.itemType.name}'.`);
}
this.shape = new mlnet.TensorShape(codec.dims);
} else if (codec.name === 'Key2') {
this.dataType = 'key2';
} else {
throw new mlnet.Error(`Unsupported data type '${codec.name}'.`);
}
}
toString() {
return this.dataType + this.shape.toString();
}
};
mlnet.TensorShape = class {
constructor(dimensions) {
this.dimensions = dimensions;
}
toString() {
if (!this.dimensions || this.dimensions.length === 0) {
return '';
}
return `[${this.dimensions.join(',')}]`;
}
};
mlnet.ModelReader = class {
constructor(entries) {
const catalog = new mlnet.ComponentCatalog();
catalog.register('AffineNormExec', mlnet.AffineNormSerializationUtils);
catalog.register('AnomalyPredXfer', mlnet.AnomalyPredictionTransformer);
catalog.register('BinaryPredXfer', mlnet.BinaryPredictionTransformer);
catalog.register('BinaryLoader', mlnet.BinaryLoader);
catalog.register('CaliPredExec', mlnet.CalibratedPredictor);
catalog.register('CdfNormalizeFunction', mlnet.CdfColumnFunction);
catalog.register('CharToken', mlnet.TokenizingByCharactersTransformer);
catalog.register('ChooseColumnsTransform', mlnet.ColumnSelectingTransformer);
catalog.register('ClusteringPredXfer', mlnet.ClusteringPredictionTransformer);
catalog.register('ConcatTransform', mlnet.ColumnConcatenatingTransformer);
catalog.register('CopyTransform', mlnet.ColumnCopyingTransformer);
catalog.register('ConvertTransform', mlnet.TypeConvertingTransformer);
catalog.register('CSharpTransform', mlnet.CSharpTransform);
catalog.register('DropColumnsTransform', mlnet.DropColumnsTransform);
catalog.register('FAFMPredXfer', mlnet.FieldAwareFactorizationMachinePredictionTransformer);
catalog.register('FastForestBinaryExec', mlnet.FastForestClassificationPredictor);
catalog.register('FastTreeBinaryExec', mlnet.FastTreeBinaryModelParameters);
catalog.register('FastTreeTweedieExec', mlnet.FastTreeTweedieModelParameters);
catalog.register('FastTreeRankerExec', mlnet.FastTreeRankingModelParameters);
catalog.register('FastTreeRegressionExec', mlnet.FastTreeRegressionModelParameters);
catalog.register('FeatWCaliPredExec', mlnet.FeatureWeightsCalibratedModelParameters);
catalog.register('FieldAwareFactMacPredict', mlnet.FieldAwareFactorizationMachineModelParameters);
catalog.register('GcnTransform', mlnet.LpNormNormalizingTransformer);
catalog.register('GenericScoreTransform', mlnet.GenericScoreTransform);
catalog.register('IidChangePointDetector', mlnet.IidChangePointDetector);
catalog.register('IidSpikeDetector', mlnet.IidSpikeDetector);
catalog.register('ImageClassificationTrans', mlnet.ImageClassificationTransformer);
catalog.register('ImageClassificationPred', mlnet.ImageClassificationModelParameters);
catalog.register('ImageLoaderTransform', mlnet.ImageLoadingTransformer);
catalog.register('ImageScalerTransform', mlnet.ImageResizingTransformer);
catalog.register('ImagePixelExtractor', mlnet.ImagePixelExtractingTransformer);
catalog.register('KeyToValueTransform', mlnet.KeyToValueMappingTransformer);
catalog.register('KeyToVectorTransform', mlnet.KeyToVectorMappingTransformer);
catalog.register('KMeansPredictor', mlnet.KMeansModelParameters);
catalog.register('LinearRegressionExec', mlnet.LinearRegressionModelParameters);
catalog.register('LightGBMRegressionExec', mlnet.LightGbmRegressionModelParameters);
catalog.register('LightGBMBinaryExec', mlnet.LightGbmBinaryModelParameters);
catalog.register('Linear2CExec', mlnet.LinearBinaryModelParameters);
catalog.register('LinearModelStats', mlnet.LinearModelParameterStatistics);
catalog.register('MaFactPredXf', mlnet.MatrixFactorizationPredictionTransformer);
catalog.register('MFPredictor', mlnet.MatrixFactorizationModelParameters);
catalog.register('MulticlassLinear', mlnet.LinearMulticlassModelParameters);
catalog.register('MultiClassLRExec', mlnet.MaximumEntropyModelParameters);
catalog.register('MultiClassNaiveBayesPred', mlnet.NaiveBayesMulticlassModelParameters);
catalog.register('MultiClassNetPredictor', mlnet.MultiClassNetPredictor);
catalog.register('MulticlassPredXfer', mlnet.MulticlassPredictionTransformer);
catalog.register('NAReplaceTransform', mlnet.MissingValueReplacingTransformer);
catalog.register('NgramTransform', mlnet.NgramExtractingTransformer);
catalog.register('NgramHashTransform', mlnet.NgramHashingTransformer);
catalog.register('NltTokenizeTransform', mlnet.NltTokenizeTransform);
catalog.register('Normalizer', mlnet.NormalizingTransformer);
catalog.register('NormalizeTransform', mlnet.NormalizeTransform);
catalog.register('OnnxTransform', mlnet.OnnxTransformer);
catalog.register('OptColTransform', mlnet.OptionalColumnTransform);
catalog.register('OVAExec', mlnet.OneVersusAllModelParameters);
catalog.register('pcaAnomExec', mlnet.PcaModelParameters);
catalog.register('PcaTransform', mlnet.PrincipalComponentAnalysisTransformer);
catalog.register('PipeDataLoader', mlnet.CompositeDataLoader);
catalog.register('PlattCaliExec', mlnet.PlattCalibrator);
catalog.register('PMixCaliPredExec', mlnet.ParameterMixingCalibratedModelParameters);
catalog.register('PoissonRegressionExec', mlnet.PoissonRegressionModelParameters);
catalog.register('ProtonNNMCPred', mlnet.ProtonNNMCPred);
catalog.register('RegressionPredXfer', mlnet.RegressionPredictionTransformer);
catalog.register('RowToRowMapper', mlnet.RowToRowMapperTransform);
catalog.register('SsaForecasting', mlnet.SsaForecastingTransformer);
catalog.register('SSAModel', mlnet.AdaptiveSingularSpectrumSequenceModelerInternal);
catalog.register('SelectColumnsTransform', mlnet.ColumnSelectingTransformer);
catalog.register('StopWordsTransform', mlnet.StopWordsTransform);
catalog.register('TensorFlowTransform', mlnet.TensorFlowTransformer);
catalog.register('TermLookupTransform', mlnet.ValueMappingTransformer);
catalog.register('TermTransform', mlnet.ValueToKeyMappingTransformer);
catalog.register('TermManager', mlnet.TermManager);
catalog.register('Text', mlnet.TextFeaturizingEstimator);
catalog.register('TextLoader', mlnet.TextLoader);
catalog.register('TextNormalizerTransform', mlnet.TextNormalizingTransformer);
catalog.register('TokenizeTextTransform', mlnet.WordTokenizingTransformer);
catalog.register('TransformerChain', mlnet.TransformerChain);
catalog.register('ValueMappingTransformer', mlnet.ValueMappingTransformer);
catalog.register('XGBoostMulticlass', mlnet.XGBoostMulticlass);
this._resolve = [];
const root = new mlnet.ModelHeader(catalog, entries, '', null, this._resolve);
const version = root.openText('TrainingInfo/Version.txt');
if (version) {
[this.version] = version.split(/[\s+\r]+/);
}
const schemaReader = root.openBinary('Schema');
if (schemaReader) {
this.schema = new mlnet.BinaryLoader(null, schemaReader).schema;
}
const transformerChain = root.open('TransformerChain');
if (transformerChain) {
this.transformerChain = transformerChain;
}
const dataLoaderModel = root.open('DataLoaderModel');
if (dataLoaderModel) {
this.dataLoaderModel = dataLoaderModel;
}
const predictor = root.open('Predictor');
if (predictor) {
this.predictor = predictor;
}
}
async resolve(context) {
const resolve = async (entry) => {
let module = null;
let content = '';
if (entry.format === 'tf') {
const protobuf = await import('./protobuf.js');
module = await context.require('./tf');
content = new mlnet.Context(context, 'model.pb', entry.bytes, protobuf);
} else if (entry.format === 'onnx') {
const protobuf = await import('./protobuf.js');
module = await context.require('./onnx');
content = new mlnet.Context(context, 'model.onnx', entry.bytes, protobuf);
} else {
throw new mlnet.Error(`Unsupported ML.NET model format '${entry.format}'.`);
}
const factory = new module.ModelFactory();
await factory.match(content);
const model = await factory.open(content);
if (model && Array.isArray(model.modules) && model.modules.length > 0) {
return model.modules[0];
}
return null;
};
const results = await Promise.all(this._resolve.map((entry) => resolve(entry).catch(() => null)));
for (let i = 0; i < this._resolve.length; i++) {
if (results[i]) {
this._resolve[i].target.Model = results[i];
}
}
}
};
mlnet.Context = class {
constructor(context, identifier, bytes, protobuf) {
this._context = context;
this._protobuf = protobuf;
this._identifier = identifier;
this._stream = new base.BinaryStream(bytes);
this._tags = new Map();
}
get identifier() {
return this._identifier;
}
get stream() {
return this._stream;
}
set(type, value) {
this.type = type;
this.value = value;
return type;
}
async require(id) {
return this._context.require(id);
}
async metadata(id) {
return this._context.metadata(id);
}
async request(file, encoding) {
return this._context.request(file, encoding);
}
async read(type) {
if (type === 'protobuf.binary') {
return this._protobuf.BinaryReader.open(this.stream);
}
throw new mlnet.Error(`Unsupported read type '${type}'.`);
}
async tags(type) {
if (!this._tags.has(type)) {
let tags = new Map();
try {
const reader = this._protobuf.BinaryReader.open(this.stream);
tags = type === 'pb+' ? reader.decode() : reader.signature();
} catch {
// continue regardless of error
}
this.stream.seek(0);
this._tags.set(type, tags);
}
return this._tags.get(type);
}
async peek() {
return undefined;
}
error(err) {
this._context.error(err, false);
}
};
mlnet.ComponentCatalog = class {
constructor() {
this._registry = new Map();
}
register(signature, type) {
this._registry.set(signature, type);
}
create(signature, context) {
if (!this._registry.has(signature)) {
throw new mlnet.Error(`Unsupported loader signature '${signature}'.`);
}
const type = this._registry.get(signature);
return Reflect.construct(type, [context]);
}
};
mlnet.ModelHeader = class {
constructor(catalog, entries, directory, data, resolve) {
this._entries = entries;
this._catalog = catalog;
this._directory = directory;
this._resolve = resolve;
if (data) {
const reader = new mlnet.BinaryReader(data);
const decoder = new TextDecoder('ascii');
reader.assert('ML\0MODEL');
this.versionWritten = reader.uint32();
this.versionReadable = reader.uint32();
const modelBlockOffset = reader.uint64().toNumber();
/* let modelBlockSize = */ reader.uint64();
const stringTableOffset = reader.uint64().toNumber();
const stringTableSize = reader.uint64().toNumber();
const stringCharsOffset = reader.uint64().toNumber();
/* v stringCharsSize = */ reader.uint64();
this.modelSignature = decoder.decode(reader.read(8));
this.modelVersionWritten = reader.uint32();
this.modelVersionReadable = reader.uint32();
this.loaderSignature = decoder.decode(reader.read(24).filter((c) => c !== 0));
this.loaderSignatureAlt = decoder.decode(reader.read(24).filter((c) => c !== 0));
const tailOffset = reader.uint64().toNumber();
/* let tailLimit = */ reader.uint64();
const assemblyNameOffset = reader.uint64().toNumber();
const assemblyNameSize = reader.uint32();
if (stringTableOffset !== 0 && stringCharsOffset !== 0) {
reader.seek(stringTableOffset);
const stringCount = stringTableSize >> 3;
const stringSizes = [];
let previousStringSize = 0;
for (let i = 0; i < stringCount; i++) {
const stringSize = reader.uint64().toNumber();
stringSizes.push(stringSize - previousStringSize);
previousStringSize = stringSize;
}
reader.seek(stringCharsOffset);
this.strings = [];
for (let i = 0; i < stringCount; i++) {
const cch = stringSizes[i] >> 1;
let sb = '';
for (let ich = 0; ich < cch; ich++) {
sb += String.fromCharCode(reader.uint16());
}
this.strings.push(sb);
}
}
if (assemblyNameOffset !== 0) {
reader.seek(assemblyNameOffset);
this.assemblyName = decoder.decode(reader.read(assemblyNameSize));
}
reader.seek(tailOffset);
reader.assert('LEDOM\0LM');
this._reader = reader;
this._reader.seek(modelBlockOffset);
}
}
get reader() {
return this._reader;
}
string(empty) {
const id = this.reader.int32();
if (empty === null && id < 0) {
return null;
}
return this.strings[id];
}
open(name) {
const dir = this._directory.length > 0 ? `${this._directory}/` : this._directory;
name = dir + name;
const key = `${name}/Model.key`;
const stream = this._entries.get(key) || this._entries.get(key.replace(/\//g, '\\'));
if (stream) {
const buffer = stream.peek();
const context = new mlnet.ModelHeader(this._catalog, this._entries, name, buffer, this._resolve);
const value = this._catalog.create(context.loaderSignature, context);
value.__type__ = value.__type__ || context.loaderSignature;
value.__name__ = name;
return value;
}
return null;
}
openBinary(name) {
const dir = this._directory.length > 0 ? `${this._directory}/` : this._directory;
name = dir + name;
const stream = this._entries.get(name) || this._entries.get(name.replace(/\//g, '\\'));
if (stream) {
return new mlnet.BinaryReader(stream);
}
return null;
}
openText(name) {
const dir = this._directory.length > 0 ? `${this._directory}/` : this._directory;
name = dir + name;
const stream = this._entries.get(name) || this._entries.get(name.replace(/\//g, '\\'));
if (stream) {
const buffer = stream.peek();
const decoder = new TextDecoder('utf-8');
return decoder.decode(buffer);
}
return null;
}
check(signature, verWrittenCur, verWeCanReadBack) {
return signature === this.modelSignature && verWrittenCur >= this.modelVersionReadable && verWeCanReadBack <= this.modelVersionWritten;
}
resolve(target, format, bytes) {
this._resolve.push({ target, format, bytes });
}
};
mlnet.BinaryReader = class {
constructor(data) {
this._reader = base.BinaryReader.open(data);
}
seek(position) {
this._reader.seek(position);
}
skip(offset) {
this._reader.skip(offset);
}
read(length) {
return this._reader.read(length);
}
boolean() {
return this._reader.boolean();
}
booleans(count) {
const values = [];
for (let i = 0; i < count; i++) {
values.push(this.boolean());
}
return values;
}
byte() {
return this._reader.byte();
}
int16() {
return this._reader.int16();
}
int32() {
return this._reader.int32();
}
int32s(count) {
const values = [];
for (let i = 0; i < count; i++) {
values.push(this.int32());
}
return values;
}
int64() {
return this._reader.int64();
}
uint16() {
return this._reader.uint16();
}
uint32() {
return this._reader.uint32();
}
uint32s(count) {
const values = [];
for (let i = 0; i < count; i++) {
values.push(this.uint32());
}
return values;
}
uint64() {
return this._reader.uint64();
}
float32() {
return this._reader.float32();
}
float32s(count) {
const values = [];
for (let i = 0; i < count; i++) {
values.push(this.float32());
}
return values;
}
float64() {
return this._reader.float64();
}
float64s(count) {
const values = [];
for (let i = 0; i < count; i++) {
values.push(this.float64());
}
return values;
}
string() {
const size = this.leb128();
const buffer = this.read(size);
return new TextDecoder('utf-8').decode(buffer);
}
leb128() {
let result = 0;
let shift = 0;
let value = 0;
do {
value = this.byte();
result |= (value & 0x7F) << shift;
shift += 7;
} while ((value & 0x80) !== 0);
return result;
}
match(text) {
const position = this.position;
for (let i = 0; i < text.length; i++) {
if (this.byte() !== text.charCodeAt(i)) {
this.seek(position);
return false;
}
}
return true;
}
assert(text) {
if (!this.match(text)) {
throw new mlnet.Error(`Invalid '${text.split('\0').join('')}' signature.`);
}
}
};
mlnet.BinaryLoader = class { // 'BINLOADR'
constructor(context, reader) {
if (context) {
if (context.modelVersionWritten >= 0x00010002) {
this.Threads = context.reader.int32();
this.GeneratedRowIndexName = context.string(null);
}
this.ShuffleBlocks = context.modelVersionWritten >= 0x00010003 ? context.reader.float64() : 4;
reader = context.openBinary('Schema.idv');
}
// https://github.com/dotnet/machinelearning/blob/master/docs/code/IdvFileFormat.md
reader.assert('CML\0DVB\0');
reader.skip(8); // version
reader.skip(8); // compatibleVersion
const tableOfContentsOffset = reader.uint64().toNumber();
const tailOffset = reader.int64().toNumber();
reader.int64(); // rowCount
const columnCount = reader.int32();
reader.seek(tailOffset);
reader.assert('\0BVD\0LMC');
reader.seek(tableOfContentsOffset);
this.schema = {};
this.schema.inputs = [];
const columns = new Map();
for (let c = 0; c < columnCount; c ++) {
const input = {};
input.name = reader.string();
input.type = new mlnet.Codec(reader);
input.compression = reader.byte(); // None = 0, Deflate = 1
input.rowsPerBlock = reader.leb128();
input.lookupOffset = reader.int64();
input.metadataTocOffset = reader.int64();
columns.set(input.name, input);
}
for (const input of columns.values()) {
this.schema.inputs.push(input);
}
}
};
mlnet.TransformerChain = class {
constructor(context) {
const reader = context.reader;
const length = reader.int32();
this.scopes = [];
this.chain = [];
for (let i = 0; i < length; i++) {
this.scopes.push(reader.int32()); // 0x01 = Training, 0x02 = Testing, 0x04 = Scoring
const dirName = `Transform_${(`00${i}`).slice(-3)}`;
const transformer = context.open(dirName);
this.chain.push(transformer);
}
}
};
mlnet.TransformBase = class {
};
mlnet.RowToRowTransformBase = class extends mlnet.TransformBase {
};
mlnet.RowToRowTransformerBase = class {
};
mlnet.RowToRowMapperTransformBase = class extends mlnet.RowToRowTransformBase {
};
mlnet.OneToOneTransformerBase = class {
constructor(context) {
const reader = context.reader;
const n = reader.int32();
this.inputs = [];
this.outputs = [];
for (let i = 0; i < n; i++) {
const output = context.string();
const input = context.string();
this.outputs.push({ name: output });
this.inputs.push({ name: input });
}
}
};
mlnet.ColumnCopyingTransformer = class {
constructor(context) {
const reader = context.reader;
const length = reader.uint32();
this.inputs = [];
this.outputs = [];
for (let i = 0; i < length; i++) {
this.outputs.push({ name: context.string() });
this.inputs.push({ name: context.string() });
}
}
};
mlnet.ColumnConcatenatingTransformer = class {
constructor(context) {
const reader = context.reader;
if (context.modelVersionReadable >= 0x00010003) {
const count = reader.int32();
for (let i = 0; i < count; i++) {
this.outputs = [];
this.outputs.push({ name: context.string() });
const n = reader.int32();
this.inputs = [];
for (let j = 0; j < n; j++) {
const input = {
name: context.string()
};
const alias = context.string(null);
if (alias) {
input.alias = alias;
}
this.inputs.push(input);
}
}
} else {
this.precision = reader.int32();
const n = reader.int32();
const names = [];
const inputs = [];
for (let i = 0; i < n; i++) {
names.push(context.string());
const numSources = reader.int32();
const input = [];
for (let j = 0; j < numSources; j++) {
input.push(context.string());
}
inputs.push(input);
}
const aliases = [];
if (context.modelVersionReadable >= 0x00010002) {
for (let i = 0; i < n; i++) {
/* let length = inputs[i].length; */
const alias = {};
aliases.push(alias);
if (context.modelVersionReadable >= 0x00010002) {
for (;;) {
const j = reader.int32();
if (j === -1) {
break;
}
alias[j] = context.string();
}
}
}
}
if (n > 1) {
throw new mlnet.Error(`Unsupported ColumnConcatenatingTransformer name count '${n}'.`);
}
this.outputs = [];
for (let i = 0; i < n; i++) {
this.outputs.push({
name: names[i]
});
this.inputs = inputs[i];
}
}
}
};
mlnet.PredictionTransformerBase = class {
constructor(context) {
this.Model = context.open('Model');
const trainSchemaReader = context.openBinary('TrainSchema');
if (trainSchemaReader) {
this.schema = new mlnet.BinaryLoader(null, trainSchemaReader).schema;
}
}
};
mlnet.MatrixFactorizationModelParameters = class {
constructor(context) {
const reader = context.reader;
this.NumberOfRows = reader.int32();
if (context.modelVersionWritten < 0x00010002) {
reader.uint64(); // mMin
}
this.NumberOfColumns = reader.int32();
if (context.modelVersionWritten < 0x00010002) {
reader.uint64(); // nMin
}
this.ApproximationRank = reader.int32();
this._leftFactorMatrix = reader.float32s(this.NumberOfRows * this.ApproximationRank);
this._rightFactorMatrix = reader.float32s(this.NumberOfColumns * this.ApproximationRank);
}
};
mlnet.MatrixFactorizationPredictionTransformer = class extends mlnet.PredictionTransformerBase {
constructor(context) {
super(context);
this.MatrixColumnIndexColumnName = context.string();
this.MatrixRowIndexColumnName = context.string();
}
};
mlnet.FieldAwareFactorizationMachinePredictionTransformer = class extends mlnet.PredictionTransformerBase {
constructor(context) {
super(context);
const reader = context.reader;
this.inputs = [];
for (let i = 0; i < this.FieldCount; i++) {
this.inputs.push({ name: context.string() });
}
this.Threshold = reader.float32();
this.ThresholdColumn = context.string();
this.outputs = [];
this.outputs.push({ name: 'Score' });
this.outputs.push({ name: 'Probability' });
this.outputs.push({ name: 'PredictedLabel' });
}
};
mlnet.SingleFeaturePredictionTransformerBase = class extends mlnet.PredictionTransformerBase {
constructor(context) {
super(context);
const featureColumn = context.string(null);
this.inputs = [];
this.inputs.push({ name: featureColumn });
this.outputs = [];
}
};
mlnet.ClusteringPredictionTransformer = class extends mlnet.SingleFeaturePredictionTransformerBase {
constructor(context) {
super(context);
this.outputs.push({ name: 'Score' });
this.outputs.push({ name: 'PredictedLabel' });
}
};
mlnet.AnomalyPredictionTransformer = class extends mlnet.SingleFeaturePredictionTransformerBase {
constructor(context) {
super(context);
const reader = context.reader;
this.Threshold = reader.float32();
this.ThresholdColumn = context.string();
this.outputs.push({ name: 'Score' });
this.outputs.push({ name: 'PredictedLabel' });
}
};
mlnet.AffineNormSerializationUtils = class {
constructor(context) {
const reader = context.reader;
/* cbFloat = */ reader.int32();
this.NumFeatures = reader.int32();
const morphCount = reader.int32();
if (morphCount === -1) {
this.ScalesSparse = reader.float32s(reader.int32());
this.OffsetsSparse = reader.float32s(reader.int32());
} else {
// debugger;
}
}
};
mlnet.RegressionPredictionTransformer = class extends mlnet.SingleFeaturePredictionTransformerBase {
constructor(context) {
super(context);
this.outputs.push({ name: 'Score' });
}
};
mlnet.BinaryPredictionTransformer = class extends mlnet.SingleFeaturePredictionTransformerBase {
constructor(context) {
super(context);
const reader = context.reader;
this.Threshold = reader.float32();
this.ThresholdColumn = context.string();
this.outputs.push({ name: 'Score' });
this.outputs.push({ name: 'PredictedLabel' });
}
};
mlnet.MulticlassPredictionTransformer = class extends mlnet.SingleFeaturePredictionTransformerBase {
constructor(context) {
super(context);
this.TrainLabelColumn = context.string(null);
this.inputs.push({ name: this.TrainLabelColumn });
if (context.modelVersionWritten >= 0x00010002) {
const scoreColumn = context.string(null);
const predictedLabelColumn = context.string(null);
this.outputs.push({ name: scoreColumn || 'Score' });
this.outputs.push({ name: predictedLabelColumn || 'PredictedLabel' });
} else {
this.outputs.push({ name: 'Score' });
this.outputs.push({ name: 'PredictedLabel' });
}
}
};
mlnet.MissingValueReplacingTransformer = class extends mlnet.OneToOneTransformerBase {
constructor(context) {
super(context);
const reader = context.reader;
for (let i = 0; i < this.inputs.length; i++) {
const codec = new mlnet.Codec(reader);
const count = reader.int32();
this.values = codec.read(reader, count);
}
}
};
mlnet.PredictorBase = class {
constructor(context) {
const reader = context.reader;
if (reader.int32() !== 4) {
throw new mlnet.Error('Invalid float type size.');
}
}
};
mlnet.ModelParametersBase = class {
constructor(context) {
const reader = context.reader;
const cbFloat = reader.int32();
if (cbFloat !== 4) {
throw new mlnet.Error('This file was saved by an incompatible version.');
}
}
};
mlnet.ImageClassificationModelParameters = class extends mlnet.ModelParametersBase {
constructor(context) {
super(context);
const reader = context.reader;
this.classCount = reader.int32();
this.imagePreprocessorTensorInput = reader.string();
this.imagePreprocessorTensorOutput = reader.string();
this.graphInputTensor = reader.string();
this.graphOutputTensor = reader.string();
const modelReader = context.openBinary('TFModel');
if (modelReader) {
const size = modelReader.uint32();
context.resolve(this, 'tf', modelReader.read(size));
}
}
};
mlnet.NaiveBayesMulticlassModelParameters = class extends mlnet.ModelParametersBase {
constructor(context) {
super(context);
const reader = context.reader;
this._labelHistogram = reader.int32s(reader.int32());
this._featureCount = reader.int32();
this._featureHistogram = [];
for (let i = 0; i < this._labelHistogram.length; i++) {
if (this._labelHistogram[i] > 0) {
this._featureHistogram.push(reader.int32s(this._featureCount));
}
}
this._absentFeaturesLogProb = reader.float64s(this._labelHistogram.length);
}
};
mlnet.LinearModelParameters = class extends mlnet.ModelParametersBase {
constructor(context) {
super(context);
const reader = context.reader;
this.Bias = reader.float32();
/* let len = */ reader.int32();
this.Indices = reader.int32s(reader.int32());
this.Weights = reader.float32s(reader.int32());
}
};
mlnet.LinearBinaryModelParameters = class extends mlnet.LinearModelParameters {
constructor(context) {
super(context);
if (context.modelVersionWritten > 0x00020001) {
this.Statistics = context.open('ModelStats');
}
}
};
mlnet.ModelStatisticsBase = class {
constructor(context) {
const reader = context.reader;
this.ParametersCount = reader.int32();
this.TrainingExampleCount = reader.int64().toNumber();
this.Deviance = reader.float32();
this.NullDeviance = reader.float32();
}
};
mlnet.LinearModelParameterStatistics = class extends mlnet.ModelStatisticsBase {
constructor(context) {
super(context);
const reader = context.reader;
if (context.modelVersionWritten < 0x00010002) {
if (!reader.boolean()) {
return;
}
}
const stdErrorValues = reader.float32s(this.ParametersCount);
const length = reader.int32();
if (length === this.ParametersCount) {
this._coeffStdError = stdErrorValues;
} else {
this.stdErrorIndices = reader.int32s(this.ParametersCount);
this._coeffStdError = stdErrorValues;
}
this._bias = reader.float32();
const isWeightsDense = reader.byte();
const weightsLength = reader.int32();
const weightsValues = reader.float32s(weightsLength);
if (isWeightsDense) {
this._weights = weightsValues;
} else {
this.weightsIndices = reader.int32s(weightsLength);
}
}
};
mlnet.LinearMulticlassModelParametersBase = class extends mlnet.ModelParametersBase {
constructor(context) {
super(context);
const reader = context.reader;
const numberOfFeatures = reader.int32();
const numberOfClasses = reader.int32();
this.Biases = reader.float32s(numberOfClasses);
const numStarts = reader.int32();
if (numStarts === 0) {
/* let numIndices = */ reader.int32();
/* let numWeights = */ reader.int32();
this.Weights = [];
for (let i = 0; i < numberOfClasses; i++) {
const w = reader.float32s(numberOfFeatures);
this.Weights.push(w);
}
} else {
const starts = reader.int32s(reader.int32());
/* let numIndices = */ reader.int32();
const indices = [];
for (let i = 0; i < numberOfClasses; i++) {
indices.push(reader.int32s(starts[i + 1] - starts[i]));
}
/* let numValues = */ reader.int32();
this.Weights = [];
for (let i = 0; i < numberOfClasses; i++) {
const values = reader.float32s(starts[i + 1] - starts[i]);
this.Weights.push(values);
}
}
const labelNamesReader = context.openBinary('LabelNames');
if (labelNamesReader) {
this.LabelNames = [];
for (let i = 0; i < numberOfClasses; i++) {
const id = labelNamesReader.int32();
this.LabelNames.push(context.strings[id]);
}
}
const statistics = context.open('ModelStats');
if (statistics) {
this.Statistics = statistics;
}
}
};
mlnet.LinearMulticlassModelParameters = class extends mlnet.LinearMulticlassModelParametersBase {
};
mlnet.RegressionModelParameters = class extends mlnet.LinearModelParameters {
};
mlnet.PoissonRegressionModelParameters = class extends mlnet.RegressionModelParameters {
};
mlnet.LinearRegressionModelParameters = class extends mlnet.RegressionModelParameters {
};
mlnet.MaximumEntropyModelParameters = class extends mlnet.LinearMulticlassModelParametersBase {
};
mlnet.TokenizingByCharactersTransformer = class extends mlnet.OneToOneTransformerBase {
constructor(context) {
super(context);
const reader = context.reader;
this.UseMarkerChars = reader.boolean();
this.IsSeparatorStartEnd = context.modelVersionReadable < 0x00010002 ? true : reader.boolean();
}
};
mlnet.SequencePool = class {
constructor(reader) {
this.idLim = reader.int32();
this.start = reader.int32s(this.idLim + 1);
this.bytes = reader.read(this.start[this.idLim]);
}
};
mlnet.NgramExtractingTransformer = class extends mlnet.OneToOneTransformerBase {
constructor(context) {
super(context);
const reader = context.reader;
if (this.inputs.length === 1) {
this._option(context, reader, this);
} else {
// debugger;
}
}
_option(context, reader, option) {
const readWeighting = context.modelVersionReadable >= 0x00010002;
option.NgramLength = reader.int32();
option.SkipLength = reader.int32();
if (readWeighting) {
option.Weighting = reader.int32();
}
option.NonEmptyLevels = reader.booleans(option.NgramLength);
option.NgramMap = new mlnet.SequencePool(reader);
if (readWeighting) {
option.InvDocFreqs = reader.float64s(reader.int32());
}
}
};
// mlnet.NgramExtractingTransformer.WeightingCriteria
mlnet.NgramHashingTransformer = class extends mlnet.RowToRowTransformerBase {
constructor(context) {
super(context);
const loadLegacy = context.modelVersionWritten < 0x00010003;
const reader = context.reader;
if (loadLegacy) {
reader.int32(); // cbFloat
}
this.inputs = [];
this.outputs = [];
const columnsLength = reader.int32();
if (loadLegacy) {
// for (let i = 0; i < columnsLength; i++) {
// this.Columns.push(new NgramHashingEstimator.ColumnOptions(context));
// }
} else {
for (let i = 0; i < columnsLength; i++) {
this.outputs.push(context.string());
const csrc = reader.int32();
for (let j = 0; j < csrc; j++) {
const src = context.string();
this.inputs.push(src);
// inputs[i][j] = src;
}
}
}
}
};
mlnet.WordTokenizingTransformer = class extends mlnet.OneToOneTransformerBase {
constructor(context) {
super(context);
const reader = context.reader;
if (this.inputs.length === 1) {
this.Separators = [];
const count = reader.int32();
for (let i = 0; i < count; i++) {
this.Separators.push(String.fromCharCode(reader.int16()));
}
} else {
// debugger;
}
}
};
mlnet.TextNormalizingTransformer = class extends mlnet.OneToOneTransformerBase {
constructor(context) {
super(context);
const reader = context.reader;
this.CaseMode = reader.byte();
this.KeepDiacritics = reader.boolean();
this.KeepPunctuations = reader.boolean();
this.KeepNumbers = reader.boolean();
}
};
mlnet.TextNormalizingTransformer.CaseMode = {
Lower: 0,
Upper: 1,
None: 2
};
mlnet.PrincipalComponentAnalysisTransformer = class extends mlnet.OneToOneTransformerBase {
constructor(context) {
super(context);
const reader = context.reader;
if (context.modelVersionReadable === 0x00010001) {
if (reader.int32() !== 4) {
throw new mlnet.Error('This file was saved by an incompatible version.');
}
}
this.TransformInfos = [];
for (let i = 0; i < this.inputs.length; i++) {
const option = {};
option.Dimension = reader.int32();
option.Rank = reader.int32();
option.Eigenvectors = [];
for (let j = 0; j < option.Rank; j++) {
option.Eigenvectors.push(reader.float32s(option.Dimension));
}
option.MeanProjected = reader.float32s(reader.int32());
this.TransformInfos.push(option);
}
}
};
mlnet.LpNormNormalizingTransformer = class extends mlnet.OneToOneTransformerBase {
constructor(context) {
super(context);
const reader = context.reader;
if (context.modelVersionWritten <= 0x00010002) {
/* cbFloat */ reader.int32();
}
// let normKindSerialized = context.modelVersionWritten >= 0x00010002;
if (this.inputs.length === 1) {
this.EnsureZeroMean = reader.boolean();
this.Norm = reader.byte();
this.Scale = reader.float32();
} else {
// debugger;
}
}
};
mlnet.KeyToVectorMappingTransformer = class extends mlnet.OneToOneTransformerBase {
constructor(context) {
super(context);
const reader = context.reader;
if (context.modelVersionWritten === 0x00010001) {
/* cbFloat = */ reader.int32();
}
const columnsLength = this.inputs.length;
this.Bags = reader.booleans(columnsLength);
}
};
mlnet.TypeConvertingTransformer = class extends mlnet.OneToOneTransformerBase {
};
mlnet.ImageLoadingTransformer = class extends mlnet.OneToOneTransformerBase {
constructor(context) {
super(context);
this.ImageFolder = context.string(null);
}
};
mlnet.ImageResizingTransformer = class extends mlnet.OneToOneTransformerBase {
constructor(context) {
super(context);
const reader = context.reader;
if (this.inputs.length === 1) {
this._option(reader, this);
} else {
this.Options = [];
for (let i = 0; i < this.inputs.length; i++) {
const option = {};
this._option(reader, option);
this.Options.push(option);
}
}
}
_option(reader, option) {
option.Width = reader.int32();
option.Height = reader.int32();
option.Resizing = reader.byte();
option.Anchor = reader.byte();
}
};
mlnet.ImageResizingTransformer.ResizingKind = {
IsoPad: 0,
IsoCrop: 1,
Fill: 2
};
mlnet.ImageResizingTransformer.Anchor = {
Right: 0,
Left: 1,
Top: 2,
Bottom: 3,
Center: 4
};
mlnet.ImagePixelExtractingTransformer = class extends mlnet.OneToOneTransformerBase {
constructor(context) {
super(context);
const reader = context.reader;
if (this.inputs.length === 1) {
this._option(context, reader, this);
} else {
this.Options = [];
for (let i = 0; i < this.inputs.length; i++) {
const option = {};
this._option(context, reader, option);
this.Options.push(option);
}
}
}
_option(context, reader, option) {
option.ColorsToExtract = reader.byte();
option.OrderOfExtraction = context.modelVersionWritten <= 0x00010002 ? mlnet.ImagePixelExtractingTransformer.ColorsOrder.ARGB : reader.byte();
let planes = option.ColorsToExtract;
planes = (planes & 0x05) + ((planes >> 1) & 0x05);
planes = (planes & 0x03) + ((planes >> 2) & 0x03);
option.Planes = planes & 0xFF;
option.OutputAsFloatArray = reader.boolean();
option.OffsetImage = reader.float32();
option.ScaleImage = reader.float32();
option.InterleavePixelColors = reader.boolean();
}
};
mlnet.ImagePixelExtractingTransformer.ColorBits = {
Alpha: 0x01,
Red: 0x02,
Green: 0x04,
Blue: 0x08,
Rgb: 0x0E,
All: 0x0F
};
mlnet.ImagePixelExtractingTransformer.ColorsOrder = {
ARGB: 1,
ARBG: 2,
ABRG: 3,
ABGR: 4,
AGRB: 5,
AGBR: 6
};
mlnet.NormalizingTransformer = class extends mlnet.OneToOneTransformerBase {
constructor(context) {
super(context);
const reader = context.reader;
this.Options = [];
for (let i = 0; i < this.inputs.length; i++) {
let isVector = false;
let shape = 0;
let itemKind = '';
if (context.modelVersionWritten < 0x00010002) {
isVector = reader.boolean();
shape = [reader.int32()];
itemKind = reader.byte();
} else {
isVector = reader.boolean();
itemKind = reader.byte();
shape = reader.int32s(reader.int32());
}
let itemType = '';
switch (itemKind) {
case 9: itemType = 'float32'; break;
case 10: itemType = 'float64'; break;
default: throw new mlnet.Error(`Unsupported NormalizingTransformer item kind '${itemKind}'.`);
}
const type = itemType + (isVector ? `[${shape.map((dim) => dim.toString()).join(',')}]` : '');
const name = `Normalizer_${(`00${i}`).slice(-3)}`;
const func = context.open(name);
this.Options.push({ type, func });
}
}
};
mlnet.KeyToValueMappingTransformer = class extends mlnet.OneToOneTransformerBase {
};
mlnet.ValueToKeyMappingTransformer = class extends mlnet.OneToOneTransformerBase {
constructor(context) {
super(context);
const reader = context.reader;
if (context.modelVersionWritten >= 0x00010003) {
this.textMetadata = reader.booleans(this.outputs.length + this.inputs.length);
} else {
this.textMetadata = [];
for (let i = 0; i < this.columnPairs.length; i++) {
this.textMetadata.push(false);
}
}
const vocabulary = context.open('Vocabulary');
if (vocabulary) {
this.termMap = vocabulary.termMap;
}
}
};
mlnet.TermMap = class {
constructor(context) {
const reader = context.reader;
const mtype = reader.byte();
switch (mtype) {
case 0: { // Text
this.values = [];
const cstr = reader.int32();
for (let i = 0; i < cstr; i++) {
this.values.push(context.string());
}
break;
}
case 1: { // Codec
const codec = new mlnet.Codec(reader);
const count = reader.int32();
this.values = codec.read(reader, count);
break;
}
default:
throw new mlnet.Error(`Unsupported term map type '${mtype}'.`);
}
}
};
mlnet.TermManager = class {
constructor(context) {
const reader = context.reader;
const cmap = reader.int32();
this.termMap = [];
if (context.modelVersionWritten >= 0x00010002) {
for (let i = 0; i < cmap; ++i) {
this.termMap.push(new mlnet.TermMap(context));
// debugger;
// termMap[i] = TermMap.Load(c, host, CodecFactory);
}
} else {
throw new mlnet.Error('Unsupported TermManager version.');
// for (let i = 0; i < cmap; ++i) {
// debugger;
// // termMap[i] = TermMap.TextImpl.Create(c, host)
// }
}
}
};
mlnet.ValueMappingTransformer = class extends mlnet.OneToOneTransformerBase {
constructor(context) {
super(context);
this.keyColumnName = 'Key';
if (context.check('TXTLOOKT', 0x00010002, 0x00010002)) {
this.keyColumnName = 'Term';
}
}
};
mlnet.KeyToVectorTransform = class {
};
mlnet.GenericScoreTransform = class {
};
mlnet.CompositeDataLoader = class {
constructor(context) {
/* let loader = */ context.open('Loader');
const reader = context.reader;
// LoadTransforms
reader.int32(); // floatSize
const cxf = reader.int32();
const tagData = [];
for (let i = 0; i < cxf; i++) {
let tag = '';
let args = null;
if (context.modelVersionReadable >= 0x00010002) {
tag = context.string();
args = context.string(null);
}
tagData.push([tag, args]);
}
this.chain = [];
for (let j = 0; j < cxf; j++) {
const name = `Transform_${(`00${j}`).slice(-3)}`;
const transform = context.open(name);
this.chain.push(transform);
}
}
};
mlnet.RowToRowMapperTransform = class extends mlnet.RowToRowTransformBase {
constructor(context) {
super(context);
const mapper = context.open('Mapper');
this.__type__ = mapper.__type__;
for (const key of Object.keys(mapper)) {
this[key] = mapper[key];
}
}
};
mlnet.ImageClassificationTransformer = class extends mlnet.RowToRowTransformerBase {
constructor(context) {
super(context);
const reader = context.reader;
this.addBatchDimensionInput = reader.boolean();
const numInputs = reader.int32();
this.inputs = [];
for (let i = 0; i < numInputs; i++) {
this.inputs.push({ name: context.string() });
}
this.outputs = [];
const numOutputs = reader.int32();
for (let i = 0; i < numOutputs; i++) {
this.outputs.push({ name: context.string() });
}
this.labelColumn = reader.string();
this.checkpointName = reader.string();
this.arch = reader.int32(); // Architecture
this.scoreColumnName = reader.string();
this.predictedColumnName = reader.string();
this.learningRate = reader.float32();
this.classCount = reader.int32();
this.keyValueAnnotations = [];
for (let i = 0; i < this.classCount; i++) {
this.keyValueAnnotations.push(context.string());
}
this.predictionTensorName = reader.string();
this.softMaxTensorName = reader.string();
this.jpegDataTensorName = reader.string();
this.resizeTensorName = reader.string();
}
};
mlnet.OnnxTransformer = class extends mlnet.RowToRowTransformerBase {
constructor(context) {
super(context);
const reader = context.reader;
const modelReader = context.openBinary('OnnxModel');
if (modelReader) {
const size = modelReader.uint32();
context.resolve(this, 'onnx', modelReader.read(size));
}
const numInputs = context.modelVersionWritten > 0x00010001 ? reader.int32() : 1;
this.inputs = [];
for (let i = 0; i < numInputs; i++) {
this.inputs.push({ name: context.string() });
}
const numOutputs = context.modelVersionWritten > 0x00010001 ? reader.int32() : 1;
this.outputs = [];
for (let i = 0; i < numOutputs; i++) {
this.outputs.push({ name: context.string() });
}
if (context.modelVersionWritten > 0x0001000C) {
const customShapeInfosLength = reader.int32();
this.LoadedCustomShapeInfos = [];
for (let i = 0; i < customShapeInfosLength; i++) {
this.LoadedCustomShapeInfos.push({
name: context.string(),
shape: reader.int32s(reader.int32())
});
}
}
}
};
mlnet.OptionalColumnTransform = class extends mlnet.RowToRowMapperTransformBase {
};
mlnet.TensorFlowTransformer = class extends mlnet.RowToRowTransformerBase {
constructor(context) {
super(context);
const reader = context.reader;
this.IsFrozen = context.modelVersionReadable >= 0x00010002 ? reader.boolean() : true;
this.AddBatchDimensionInput = context.modelVersionReadable >= 0x00010003 ? reader.boolean() : true;
const numInputs = reader.int32();
this.inputs = [];
for (let i = 0; i < numInputs; i++) {
this.inputs.push({ name: context.string() });
}
const numOutputs = context.modelVersionReadable >= 0x00010002 ? reader.int32() : 1;
this.outputs = [];
for (let i = 0; i < numOutputs; i++) {
this.outputs.push({ name: context.string() });
}
}
};
mlnet.OneVersusAllModelParameters = class extends mlnet.ModelParametersBase {
constructor(context) {
super(context);
const reader = context.reader;
this.UseDist = reader.boolean();
const len = reader.int32();
this.chain = [];
for (let i = 0; i < len; i++) {
const name = `SubPredictor_${(`00${i}`).slice(-3)}`;
const predictor = context.open(name);
this.chain.push(predictor);
}
}
};
mlnet.TextFeaturizingEstimator = class {
constructor(context) {
if (context.modelVersionReadable === 0x00010001) {
const reader = context.reader;
const n = reader.int32();
this.chain = [];
/* let loader = */ context.open('Loader');
for (let i = 0; i < n; i++) {
const name = `Step_${(`00${i}`).slice(-3)}`;
const transformer = context.open(name);
this.chain.push(transformer);
// debugger;
}
// throw new mlnet.Error('Unsupported TextFeaturizingEstimator format.');
} else {
const chain = context.open('Chain');
this.chain = chain.chain;
}
}
};
mlnet.TextLoader = class {
constructor(context) {
const reader = context.reader;
reader.int32(); // floatSize
this.MaxRows = reader.int64();
this.Flags = reader.uint32();
this.InputSize = reader.int32();
const separatorCount = reader.int32();
this.Separators = [];
for (let i = 0; i < separatorCount; i++) {
this.Separators.push(String.fromCharCode(reader.uint16()));
}
this.Bindinds = new mlnet.TextLoader.Bindinds(context);
}
};
mlnet.TextLoader.Bindinds = class {
constructor(context) {
const reader = context.reader;
const cinfo = reader.int32();
for (let i = 0; i < cinfo; i++) {
// debugger;
}
}
};
mlnet.CalibratedPredictorBase = class {
constructor(predictor, calibrator) {
this.SubPredictor = predictor;
this.Calibrator = calibrator;
}
};
mlnet.ValueMapperCalibratedPredictorBase = class extends mlnet.CalibratedPredictorBase {
};
mlnet.CalibratedModelParametersBase = class {
constructor(context) {
this.Predictor = context.open('Predictor');
this.Calibrator = context.open('Calibrator');
}
};
mlnet.ValueMapperCalibratedModelParametersBase = class extends mlnet.CalibratedModelParametersBase {
};
mlnet.CalibratedPredictor = class extends mlnet.ValueMapperCalibratedPredictorBase {
constructor(context) {
const predictor = context.open('Predictor');
const calibrator = context.open('Calibrator');
super(predictor, calibrator);
}
};
mlnet.ParameterMixingCalibratedModelParameters = class extends mlnet.ValueMapperCalibratedModelParametersBase {
};
mlnet.FieldAwareFactorizationMachineModelParameters = class {
constructor(context) {
const reader = context.reader;
this.Norm = reader.boolean();
this.FieldCount = reader.int32();
this.FeatureCount = reader.int32();
this.LatentDim = reader.int32();
this.LinearWeights = reader.float32s(reader.int32());
this.LatentWeights = reader.float32s(reader.int32());
}
};
mlnet.KMeansModelParameters = class extends mlnet.ModelParametersBase {
constructor(context) {
super(context);
const reader = context.reader;
this.k = reader.int32();
this.Dimensionality = reader.int32();
this.Centroids = [];
for (let i = 0; i < this.k; i++) {
const count = context.modelVersionWritten >= 0x00010002 ? reader.int32() : this.Dimensionality;
const indices = count < this.Dimensionality ? reader.int32s(count) : null;
const values = reader.float32s(count);
this.Centroids.push({ indices, values });
}
// input type = float32[dimensionality]
// output type = float32[k]
}
};
mlnet.PcaModelParameters = class extends mlnet.ModelParametersBase {
constructor(context) {
super(context);
const reader = context.reader;
this.Dimension = reader.int32();
this.Rank = reader.int32();
const center = reader.boolean();
if (center) {
this.Mean = reader.float32s(this.Dimension);
} else {
this.Mean = [];
}
this.EigenVectors = [];
for (let i = 0; i < this.Rank; ++i) {
this.EigenVectors.push(reader.float32s(this.Dimension));
}
// input type -> float32[Dimension]
}
};
mlnet.TreeEnsembleModelParameters = class extends mlnet.ModelParametersBase {
constructor(context) {
super(context);
const reader = context.reader;
const usingDefaultValues = context.modelVersionWritten >= this.VerDefaultValueSerialized;
const categoricalSplits = context.modelVersionWritten >= this.VerCategoricalSplitSerialized;
this.TrainedEnsemble = new mlnet.InternalTreeEnsemble(context, usingDefaultValues, categoricalSplits);
this.InnerOptions = context.string(null);
if (context.modelVersionWritten >= this.VerNumFeaturesSerialized) {
this.NumFeatures = reader.int32();
}
// input type -> float32[NumFeatures]
// output type -> float32
}
};
mlnet.InternalTreeEnsemble = class {
constructor(context, usingDefaultValues, categoricalSplits) {
const reader = context.reader;
this.Trees = [];
const numTrees = reader.int32();
for (let i = 0; i < numTrees; i++) {
switch (reader.byte()) {
case mlnet.InternalTreeEnsemble.TreeType.Regression:
this.Trees.push(new mlnet.InternalRegressionTree(context, usingDefaultValues, categoricalSplits));
break;
case mlnet.InternalTreeEnsemble.TreeType.FastForest:
this.Trees.push(new mlnet.InternalQuantileRegressionTree(context, usingDefaultValues, categoricalSplits));
break;
case mlnet.InternalTreeEnsemble.TreeType.Affine:
// Affine regression trees do not actually work, nor is it clear how they ever
// could have worked within TLC, so the chance of this happening seems remote.
throw new mlnet.Error('Affine regression trees unsupported.');
default:
throw new mlnet.Error('Unsupported ensemble tree type.');
}
}
this.Bias = reader.float64();
this.FirstInputInitializationContent = context.string(null);
}
};
mlnet.InternalRegressionTree = class {
constructor(context, usingDefaultValue, categoricalSplits) {
const reader = context.reader;
this.NumLeaves = reader.int32();
this.MaxOuptut = reader.float64();
this.Weight = reader.float64();
this.LteChild = reader.int32s(reader.int32());
this.GtChild = reader.int32s(reader.int32());
this.SplitFeatures = reader.int32s(reader.int32());
if (categoricalSplits) {
const categoricalNodeIndices = reader.int32s(reader.int32());
if (categoricalNodeIndices.length > 0) {
this.CategoricalSplitFeatures = [];
this.CategoricalSplitFeatureRanges = [];
for (const index of categoricalNodeIndices) {
this.CategoricalSplitFeatures[index] = reader.int32s(reader.int32());
this.CategoricalSplitFeatureRanges[index] = reader.int32s(2);
}
}
}
this.Thresholds = reader.uint32s(reader.int32());
this.RawThresholds = reader.float32s(reader.int32());
this.DefaultValueForMissing = usingDefaultValue ? reader.float32s(reader.int32()) : null;
this.LeafValues = reader.float64s(reader.int32());
this.SplitGain = reader.float64s(reader.int32());
this.GainPValue = reader.float64s(reader.int32());
this.PreviousLeafValue = reader.float64s(reader.int32());
}
};
mlnet.InternalTreeEnsemble.TreeType = {
Regression: 0,
Affine: 1,
FastForest: 2
};
mlnet.TreeEnsembleModelParametersBasedOnRegressionTree = class extends mlnet.TreeEnsembleModelParameters {
};
mlnet.FastTreeTweedieModelParameters = class extends mlnet.TreeEnsembleModelParametersBasedOnRegressionTree {
get VerNumFeaturesSerialized() {
return 0x00010001;
}
get VerDefaultValueSerialized() {
return 0x00010002;
}
get VerCategoricalSplitSerialized() {
return 0x00010003;
}
};
mlnet.FastTreeRankingModelParameters = class extends mlnet.TreeEnsembleModelParametersBasedOnRegressionTree {
get VerNumFeaturesSerialized() {
return 0x00010002;
}
get VerDefaultValueSerialized() {
return 0x00010004;
}
get VerCategoricalSplitSerialized() {
return 0x00010005;
}
};
mlnet.FastTreeBinaryModelParameters = class extends mlnet.TreeEnsembleModelParametersBasedOnRegressionTree {
get VerNumFeaturesSerialized() {
return 0x00010002;
}
get VerDefaultValueSerialized() {
return 0x00010004;
}
get VerCategoricalSplitSerialized() {
return 0x00010005;
}
};
mlnet.FastTreeRegressionModelParameters = class extends mlnet.TreeEnsembleModelParametersBasedOnRegressionTree {
get VerNumFeaturesSerialized() {
return 0x00010002;
}
get VerDefaultValueSerialized() {
return 0x00010004;
}
get VerCategoricalSplitSerialized() {
return 0x00010005;
}
};
mlnet.LightGbmRegressionModelParameters = class extends mlnet.TreeEnsembleModelParametersBasedOnRegressionTree {
get VerNumFeaturesSerialized() {
return 0x00010002;
}
get VerDefaultValueSerialized() {
return 0x00010004;
}
get VerCategoricalSplitSerialized() {
return 0x00010005;
}
};
mlnet.LightGbmBinaryModelParameters = class extends mlnet.TreeEnsembleModelParametersBasedOnRegressionTree {
get VerNumFeaturesSerialized() {
return 0x00010002;
}
get VerDefaultValueSerialized() {
return 0x00010004;
}
get VerCategoricalSplitSerialized() {
return 0x00010005;
}
};
mlnet.FeatureWeightsCalibratedModelParameters = class extends mlnet.ValueMapperCalibratedModelParametersBase {
};
mlnet.FastTreePredictionWrapper = class {
};
mlnet.FastForestClassificationPredictor = class extends mlnet.FastTreePredictionWrapper {
};
mlnet.PlattCalibrator = class {
constructor(context) {
const reader = context.reader;
this.ParamA = reader.float64();
this.ParamB = reader.float64();
}
};
mlnet.Codec = class {
constructor(reader) {
this.name = reader.string();
const size = reader.leb128();
const data = reader.read(size);
reader = new mlnet.BinaryReader(data);
switch (this.name) {
case 'Boolean': break;
case 'Single': break;
case 'Double': break;
case 'Byte': break;
case 'Int32': break;
case 'UInt32': break;
case 'Int64': break;
case 'TextSpan': break;
case 'VBuffer':
this.itemType = new mlnet.Codec(reader);
this.dims = reader.int32s(reader.int32());
break;
case 'Key':
case 'Key2':
this.itemType = new mlnet.Codec(reader);
this.count = reader.uint64().toNumber();
break;
default:
throw new mlnet.Error(`Unsupported codec '${this.name}'.`);
}
}
read(reader, count) {
const values = [];
switch (this.name) {
case 'Single':
for (let i = 0; i < count; i++) {
values.push(reader.float32());
}
break;
case 'Int32':
for (let i = 0; i < count; i++) {
values.push(reader.int32());
}
break;
case 'Int64':
for (let i = 0; i < count; i++) {
values.push(reader.int64());
}
break;
default:
throw new mlnet.Error(`Unsupported codec read operation '${this.name}'.`);
}
return values;
}
};
mlnet.SequentialTransformerBase = class {
constructor(context) {
const reader = context.reader;
this.WindowSize = reader.int32();
this.InitialWindowSize = reader.int32();
this.inputs = [];
this.inputs.push({ name: context.string() });
this.outputs = [];
this.outputs.push({ name: context.string() });
this.ConfidenceLowerBoundColumn = reader.string();
this.ConfidenceUpperBoundColumn = reader.string();
this.Type = new mlnet.Codec(reader);
}
};
mlnet.AnomalyDetectionStateBase = class {
constructor(context) {
const reader = context.reader;
this.LogMartingaleUpdateBuffer = mlnet.AnomalyDetectionStateBase._deserializeFixedSizeQueueDouble(reader);
this.RawScoreBuffer = mlnet.AnomalyDetectionStateBase._deserializeFixedSizeQueueDouble(reader);
this.LogMartingaleValue = reader.float64();
this.SumSquaredDist = reader.float64();
this.MartingaleAlertCounter = reader.int32();
}
static _deserializeFixedSizeQueueDouble(reader) {
/* let capacity = */ reader.int32();
const count = reader.int32();
const queue = [];
for (let i = 0; i < count; i++) {
queue.push(reader.float64());
}
return queue;
}
};
mlnet.SequentialAnomalyDetectionTransformBase = class extends mlnet.SequentialTransformerBase {
constructor(context) {
super(context);
const reader = context.reader;
this.Martingale = reader.byte();
this.ThresholdScore = reader.byte();
this.Side = reader.byte();
this.PowerMartingaleEpsilon = reader.float64();
this.AlertThreshold = reader.float64();
this.State = new mlnet.AnomalyDetectionStateBase(context);
}
};
mlnet.TimeSeriesUtils = class {
static deserializeFixedSizeQueueSingle(reader) {
/* const capacity = */ reader.int32();
const count = reader.int32();
const queue = [];
for (let i = 0; i < count; i++) {
queue.push(reader.float32());
}
return queue;
}
};
mlnet.IidAnomalyDetectionBase = class extends mlnet.SequentialAnomalyDetectionTransformBase {
constructor(context) {
super(context);
const reader = context.reader;
this.WindowedBuffer = mlnet.TimeSeriesUtils.deserializeFixedSizeQueueSingle(reader);
this.InitialWindowedBuffer = mlnet.TimeSeriesUtils.deserializeFixedSizeQueueSingle(reader);
}
};
mlnet.IidAnomalyDetectionBaseWrapper = class {
constructor(context) {
const internalTransform = new mlnet.IidAnomalyDetectionBase(context);
for (const key of Object.keys(internalTransform)) {
this[key] = internalTransform[key];
}
}
};
mlnet.IidChangePointDetector = class extends mlnet.IidAnomalyDetectionBaseWrapper {
};
mlnet.IidSpikeDetector = class extends mlnet.IidAnomalyDetectionBaseWrapper {
};
mlnet.SequenceModelerBase = class {
};
mlnet.RankSelectionMethod = {
Fixed: 0,
Exact: 1,
Fact: 2
};
mlnet.AdaptiveSingularSpectrumSequenceModelerInternal = class extends mlnet.SequenceModelerBase {
constructor(context) {
super(context);
const reader = context.reader;
this._seriesLength = reader.int32();
this._windowSize = reader.int32();
this._trainSize = reader.int32();
this._rank = reader.int32();
this._discountFactor = reader.float32();
this._rankSelectionMethod = reader.byte(); // RankSelectionMethod
const isWeightSet = reader.byte();
this._alpha = reader.float32s(reader.int32());
if (context.modelVersionReadable >= 0x00010002) {
this._state = reader.float32s(reader.int32());
}
this.ShouldComputeForecastIntervals = reader.byte();
this._observationNoiseVariance = reader.float32();
this._autoregressionNoiseVariance = reader.float32();
this._observationNoiseMean = reader.float32();
this._autoregressionNoiseMean = reader.float32();
if (context.modelVersionReadable >= 0x00010002) {
this._nextPrediction = reader.float32();
}
this._maxRank = reader.int32();
this._shouldStablize = reader.byte();
this._shouldMaintainInfo = reader.byte();
this._maxTrendRatio = reader.float64();
if (isWeightSet) {
this._wTrans = reader.float32s(reader.int32());
this._y = reader.float32s(reader.int32());
}
this._buffer = mlnet.TimeSeriesUtils.deserializeFixedSizeQueueSingle(reader);
}
};
mlnet.SequentialForecastingTransformBase = class extends mlnet.SequentialTransformerBase {
constructor(context) {
super(context);
const reader = context.reader;
this._outputLength = reader.int32();
}
};
mlnet.SsaForecastingBaseWrapper = class extends mlnet.SequentialForecastingTransformBase {
constructor(context) {
super(context);
const reader = context.reader;
this.IsAdaptive = reader.boolean();
this.Horizon = reader.int32();
this.ConfidenceLevel = reader.float32();
this.WindowedBuffer = mlnet.TimeSeriesUtils.deserializeFixedSizeQueueSingle(reader);
this.InitialWindowedBuffer = mlnet.TimeSeriesUtils.deserializeFixedSizeQueueSingle(reader);
this.Model = context.open('SSA');
}
};
mlnet.SsaForecastingTransformer = class extends mlnet.SsaForecastingBaseWrapper {
};
mlnet.ColumnSelectingTransformer = class {
constructor(context) {
const reader = context.reader;
if (context.check('DRPCOLST', 0x00010002, 0x00010002)) {
throw new mlnet.Error("'LoadDropColumnsTransform' not supported.");
} else if (context.check('CHSCOLSF', 0x00010001, 0x00010001)) {
reader.int32(); // cbFloat
this.KeepHidden = this._getHiddenOption(reader.byte());
const count = reader.int32();
this.inputs = [];
for (let colIdx = 0; colIdx < count; colIdx++) {
const dst = context.string();
this.inputs.push(dst);
context.string(); // src
this._getHiddenOption(reader.byte()); // colKeepHidden
}
} else {
const keepColumns = reader.boolean();
this.KeepHidden = reader.boolean();
this.IgnoreMissing = reader.boolean();
const length = reader.int32();
this.inputs = [];
for (let i = 0; i < length; i++) {
this.inputs.push({ name: context.string() });
}
if (keepColumns) {
this.ColumnsToKeep = this.inputs;
} else {
this.ColumnsToDrop = this.inputs;
}
}
}
_getHiddenOption(value) {
switch (value) {
case 1: return true;
case 2: return false;
default: throw new mlnet.Error('Unsupported hide option specified');
}
}
};
mlnet.XGBoostMulticlass = class {};
mlnet.NltTokenizeTransform = class {};
mlnet.DropColumnsTransform = class {};
mlnet.StopWordsTransform = class {};
mlnet.CSharpTransform = class {};
mlnet.GenericScoreTransform = class {};
mlnet.NormalizeTransform = class {};
mlnet.CdfColumnFunction = class {
};
mlnet.MultiClassNetPredictor = class {};
mlnet.ProtonNNMCPred = class {};
mlnet.Utility = class {
static enum(type, value) {
if (type) {
mlnet.Utility._enums = mlnet.Utility._enums || new Map();
if (!mlnet.Utility._enums.has(type)) {
let obj = mlnet;
const id = type.split('.');
while (obj && id.length > 0) {
obj = obj[id.shift()];
}
if (obj) {
const entries = new Map(Object.entries(obj).map(([key, value]) => [value, key]));
mlnet.Utility._enums.set(type, entries);
} else {
mlnet.Utility._enums.set(type, new Map());
}
}
const map = mlnet.Utility._enums.get(type);
if (map.has(value)) {
return map.get(value);
}
}
return value;
}
};
mlnet.Error = class extends Error {
constructor(message) {
super(message);
this.name = 'Error loading ML.NET model.';
}
};
export const ModelFactory = mlnet.ModelFactory;