7254f7b4d1
Build / Build (macos-latest) (push) Has been cancelled
Build / Build (ubuntu-latest) (push) Has been cancelled
Build / Build (windows-latest) (push) Has been cancelled
Build / Analyze (javascript) (push) Has been cancelled
Build / Analyze (python) (push) Has been cancelled
941 lines
30 KiB
JavaScript
941 lines
30 KiB
JavaScript
|
|
import * as base from './base.js';
|
|
|
|
const torch = {};
|
|
|
|
torch.ModelFactory = class {
|
|
|
|
async match(context) {
|
|
const reader = torch.T7Reader.open(context);
|
|
if (reader) {
|
|
return context.set('torch', reader);
|
|
}
|
|
return null;
|
|
}
|
|
|
|
async open(context) {
|
|
const metadata = await context.metadata('torch-metadata.json');
|
|
const reader = context.value;
|
|
reader.callback = (name) => {
|
|
if (name && name !== 'nn.JointTrainModule' && !name.startsWith('nn.MSDNet_') && !name.startsWith('onmt.')) {
|
|
context.error(new torch.Error(`Unsupported type '${name}'.`));
|
|
}
|
|
return null;
|
|
};
|
|
const obj = reader.read();
|
|
let graphs = [];
|
|
if (obj && Array.isArray(obj) && obj.length >= 2 &&
|
|
obj.slice(0, obj.length - 1).every((item) => item.__class__) &&
|
|
!obj[obj.length - 1].__class__) {
|
|
graphs = obj.slice(0, obj.length - 1);
|
|
} else {
|
|
graphs = [obj];
|
|
}
|
|
return new torch.Model(metadata, graphs);
|
|
}
|
|
};
|
|
|
|
torch.Model = class {
|
|
|
|
constructor(metadata, graphs) {
|
|
this.format = 'Torch v7';
|
|
this.modules = graphs.map((graph, index) => new torch.Graph(metadata, index.toString(), graph));
|
|
}
|
|
};
|
|
|
|
torch.Graph = class {
|
|
|
|
constructor(metadata, name, module) {
|
|
this.name = name;
|
|
this.inputs = [];
|
|
this.outputs = [];
|
|
this.nodes = [];
|
|
this.groups = 'false';
|
|
const values = new Map();
|
|
values.map = (name, type, tensor) => {
|
|
if (name.length === 0 && tensor) {
|
|
return new torch.Value(name, type || null, tensor || null);
|
|
}
|
|
if (!values.has(name)) {
|
|
values.set(name, new torch.Value(name, type || null, tensor || null));
|
|
} else if (type || tensor) {
|
|
throw new torch.Error(`Duplicate value '${name}'.`);
|
|
}
|
|
return values.get(name);
|
|
};
|
|
const node = new torch.Node(metadata, module, '', values);
|
|
this.nodes.push(node);
|
|
}
|
|
};
|
|
|
|
torch.Argument = class {
|
|
|
|
constructor(name, value, type = null, visible = true) {
|
|
this.name = name;
|
|
this.value = value;
|
|
this.type = type;
|
|
this.visible = visible;
|
|
}
|
|
};
|
|
|
|
torch.Value = class {
|
|
|
|
constructor(name, type, initializer) {
|
|
if (typeof name !== 'string') {
|
|
throw new torch.Error(`Invalid value identifier '${JSON.stringify(name)}'.`);
|
|
}
|
|
this.name = name;
|
|
this.type = initializer ? initializer.type : type;
|
|
this.initializer = initializer;
|
|
}
|
|
};
|
|
|
|
torch.Node = class {
|
|
|
|
constructor(metadata, module, name, values) {
|
|
this.name = name;
|
|
this.inputs = [];
|
|
this.outputs = [];
|
|
const type = module.__class__ ? `${module.__class__.__module__}.${module.__class__.__name__}` : 'nn.Module';
|
|
this.type = metadata.type(type);
|
|
for (const [key, obj] of Object.entries(module)) {
|
|
if (obj && obj.__class__ && obj.__class__.__module__ === 'torch' && obj.__class__.__name__.endsWith('Storage')) {
|
|
module[key] = obj.data();
|
|
}
|
|
}
|
|
delete module.iSize;
|
|
delete module.finput;
|
|
delete module.fgradInput;
|
|
delete module.output;
|
|
delete module.gradInput;
|
|
delete module.gradWeight;
|
|
delete module.gradBias;
|
|
delete module.grad_tmp;
|
|
delete module.scaleT;
|
|
delete module._input;
|
|
delete module._output;
|
|
delete module._gradInput;
|
|
delete module._gradOutput;
|
|
delete module.buffer;
|
|
delete module.buffer2;
|
|
delete module.tmp_in;
|
|
delete module.tmp_out;
|
|
delete module.accUpdateGradParameters;
|
|
this.attributes = [];
|
|
for (const [name, obj] of Object.entries(module)) {
|
|
if (name === '_type') {
|
|
continue;
|
|
}
|
|
if (obj.__class__ && obj.__class__.__module__ === 'torch' && obj.__class__.__name__.endsWith('Tensor')) {
|
|
const argument = new torch.Argument(name, [values.map('', null, new torch.Tensor(obj))]);
|
|
this.inputs.push(argument);
|
|
} else if (Array.isArray(obj) && obj.every((item) => item && item.__class__)) {
|
|
const nodes = obj.map((module) => new torch.Node(metadata, module, '', values));
|
|
const argument = new torch.Argument(name, nodes, 'object[]');
|
|
this.inputs.push(argument);
|
|
} else if ((Array.isArray(obj) && obj.every((obj) => typeof obj === 'number' || typeof obj === 'string' || typeof obj === 'boolean')) ||
|
|
typeof obj === 'number' || typeof obj === 'string' || typeof obj === 'boolean') {
|
|
let visible = name === 'train' ? false : true;
|
|
const schema = metadata.attribute(type, name);
|
|
if (schema) {
|
|
if (schema.visible === false) {
|
|
visible = false;
|
|
} else if (schema.default !== undefined && Object.prototype.hasOwnProperty.call(schema, 'default')) {
|
|
visible = false;
|
|
}
|
|
}
|
|
const attribute = new torch.Argument(name, obj, 'attribute', visible);
|
|
this.inputs.push(attribute);
|
|
} else if (obj) {
|
|
const node = new torch.Node(metadata, obj, '', values);
|
|
const argument = new torch.Argument(name, node, 'object');
|
|
this.inputs.push(argument);
|
|
} else {
|
|
throw new torch.Error(`Invalid input value '${name}'.`);
|
|
}
|
|
}
|
|
}
|
|
|
|
_updateSize(module, name) {
|
|
if (Object.prototype.hasOwnProperty.call(module, `${name}W`) &&
|
|
Object.prototype.hasOwnProperty.call(module, `${name}H`)) {
|
|
module[name] = [module[`${name}W`], module[`${name}H`]];
|
|
delete module[`${name}W`];
|
|
delete module[`${name}H`];
|
|
}
|
|
}
|
|
|
|
_updateBox(module, name) {
|
|
if (Object.prototype.hasOwnProperty.call(module, `${name}_t`) &&
|
|
Object.prototype.hasOwnProperty.call(module, `${name}_r`) &&
|
|
Object.prototype.hasOwnProperty.call(module, `${name}_b`) &&
|
|
Object.prototype.hasOwnProperty.call(module, `${name}_l`)) {
|
|
module[name] = [module[`${name}_t`], module[`${name}_r`], module[`${name}_b`], module[`${name}_l`]];
|
|
delete module[`${name}_t`];
|
|
delete module[`${name}_r`];
|
|
delete module[`${name}_b`];
|
|
delete module[`${name}_l`];
|
|
}
|
|
}
|
|
};
|
|
|
|
torch.Tensor = class {
|
|
|
|
constructor(tensor) {
|
|
this.type = new torch.TensorType(tensor);
|
|
this.encoding = '|';
|
|
this._storage = tensor.storage;
|
|
this._offset = tensor.storage_offset;
|
|
}
|
|
|
|
get values() {
|
|
if (this.type.shape.dimensions.length === 0) {
|
|
return [];
|
|
}
|
|
if (this._storage) {
|
|
const data = this._storage.data();
|
|
if (data) {
|
|
const size = this.type.shape.dimensions.reduce((a, b) => a * Number(b), 1);
|
|
return data.slice(this._offset, this._offset + size);
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
};
|
|
|
|
torch.TensorType = class {
|
|
|
|
constructor(tensor) {
|
|
this.dataType = tensor.dataType;
|
|
this.shape = new torch.TensorShape(tensor.size);
|
|
}
|
|
|
|
toString() {
|
|
return (this.dataType || '?') + this.shape.toString();
|
|
}
|
|
};
|
|
|
|
torch.TensorShape = class {
|
|
|
|
constructor(dimensions) {
|
|
this.dimensions = dimensions;
|
|
}
|
|
|
|
toString() {
|
|
if (this.dimensions) {
|
|
if (this.dimensions.length === 0) {
|
|
return '';
|
|
}
|
|
return `[${this.dimensions.map((dimension) => dimension.toString()).join(',')}]`;
|
|
}
|
|
return '';
|
|
}
|
|
};
|
|
|
|
torch.T7Reader = class {
|
|
|
|
static open(context) {
|
|
const stream = context.stream;
|
|
if (stream && stream.length >= 4 && stream.peek(4).every((value, index) => value === 0x00 || (index === 0 && value <= 0x08))) {
|
|
const reader = new torch.BinaryReader(stream);
|
|
return new torch.T7Reader(reader);
|
|
}
|
|
if (stream && stream.length >= 2) {
|
|
const buffer = stream.peek(2);
|
|
const value = String.fromCharCode(stream.peek(1)[0]);
|
|
if (buffer[1] === 0x0a && (value >= '0' && value <= '8')) {
|
|
const reader = new torch.TextReader(stream);
|
|
return new torch.T7Reader(reader);
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
constructor(reader) {
|
|
// https://github.com/torch/torch7
|
|
// https://github.com/torch/nngraph
|
|
this._reader = reader;
|
|
this._memo = new Map();
|
|
this._types = new Map();
|
|
const Storage = class {
|
|
constructor(dataType, itemSize) {
|
|
this.dataType = dataType;
|
|
this.itemSize = itemSize;
|
|
}
|
|
read(reader) {
|
|
this.size = reader.int64();
|
|
this.reader = reader.storage(this.size, this.itemSize, this.dataType);
|
|
}
|
|
data() {
|
|
if (this.reader) {
|
|
const reader = this.reader;
|
|
reader.seek(0);
|
|
const dataType = this.dataType;
|
|
const size = this.size;
|
|
const array = new Array(size);
|
|
for (let i = 0; i < size; i++) {
|
|
switch (dataType) {
|
|
case 'uint8':
|
|
array[i] = reader.byte();
|
|
break;
|
|
case 'int8':
|
|
array[i] = reader.int8();
|
|
break;
|
|
case 'int16':
|
|
array[i] = reader.int16();
|
|
break;
|
|
case 'int32':
|
|
array[i] = reader.int32();
|
|
break;
|
|
case 'int64':
|
|
array[i] = reader.int64();
|
|
break;
|
|
case 'float32':
|
|
array[i] = reader.float32();
|
|
break;
|
|
case 'float64':
|
|
array[i] = reader.float64();
|
|
break;
|
|
default:
|
|
throw new torch.Error(`Unsupported data type '${dataType}'.`);
|
|
}
|
|
}
|
|
this._data = array;
|
|
delete this.reader;
|
|
}
|
|
return this._data;
|
|
}
|
|
};
|
|
const Tensor = class {
|
|
constructor(dataType) {
|
|
this.dataType = dataType;
|
|
}
|
|
read(reader) {
|
|
const dim = reader.int32();
|
|
this.size = reader.int64s(dim);
|
|
this.stride = reader.int64s(dim);
|
|
this.storage_offset = reader.int64() - 1;
|
|
this.storage = reader.read();
|
|
}
|
|
};
|
|
this.register('bnn.Binary');
|
|
this.register('bnn.SpatialConvolution');
|
|
this.register('cudnn.BatchNormalization');
|
|
this.register('cudnn.BatchBRNNReLU');
|
|
this.register('cudnn.BLSTM');
|
|
this.register('cudnn.ReLU');
|
|
this.register('cudnn.RNN');
|
|
this.register('cudnn.Sigmoid');
|
|
this.register('cudnn.SoftMax');
|
|
this.register('cudnn.LogSoftMax');
|
|
this.register('cudnn.normal3DConv');
|
|
this.register('cudnn.normal3DdeConv');
|
|
this.register('cudnn.SpatialAveragePooling');
|
|
this.register('cudnn.SpatialBatchNormalization');
|
|
this.register('cudnn.SpatialConvolution');
|
|
this.register('cudnn.SpatialFullConvolution');
|
|
this.register('cudnn.SpatialMaxPooling');
|
|
this.register('cudnn.SpatialSoftMax');
|
|
this.register('cudnn.Tanh');
|
|
this.register('cudnn.VolumetricAveragePooling');
|
|
this.register('cudnn.VolumetricBatchNormalization');
|
|
this.register('cudnn.VolumetricConvolution');
|
|
this.register('cudnn.VolumetricMaxPooling');
|
|
this.register('Dict');
|
|
this.register('inn.ConstAffine');
|
|
this.register('inn.SpatialMaxPooling');
|
|
this.register('nn.Abs');
|
|
this.register('nn.AddConstant');
|
|
this.register('nn.BatchNormalization');
|
|
this.register('nn.BilinearSamplerBHWD');
|
|
this.register('nn.BinActiveZ'); // allenai/XNOR-Net
|
|
this.register('nn.BCECriterion');
|
|
this.register('nn.Bottle');
|
|
this.register('nn.Clamp');
|
|
this.register('nn.CMul');
|
|
this.register('nn.CAddTable');
|
|
this.register('nn.CDivTable');
|
|
this.register('nn.CMulTable');
|
|
this.register('nn.CSubTable');
|
|
this.register('nn.Concat');
|
|
this.register('nn.Copy');
|
|
this.register('nn.ConcatTable');
|
|
this.register('nn.Contiguous');
|
|
this.register('nn.Constant');
|
|
this.register('nn.CostVolMulti');
|
|
this.register('nn.DataParallelTable');
|
|
this.register('nn.DepthConcat');
|
|
this.register('nn.Dropout');
|
|
this.register('nn.Exp');
|
|
this.register('nn.ExpOut');
|
|
this.register('nn.FlattenTable');
|
|
this.register('nn.GenNoise');
|
|
this.register('nn.Identity');
|
|
this.register('nn.Index');
|
|
this.register('nn.Inception');
|
|
this.register('nn.InstanceNormalization');
|
|
this.register('nn.JoinTable');
|
|
this.register('nn.JointTrain');
|
|
this.register('nn.KeypointCoordinate');
|
|
this.register('nn.LeakyReLU');
|
|
this.register('nn.Linear');
|
|
this.register('nn.LinearNoBias');
|
|
this.register('nn.LogSoftMax');
|
|
this.register('nn.LookupTable');
|
|
this.register('nn.LSTM');
|
|
this.register('nn.MaskZero');
|
|
this.register('nn.MapTable');
|
|
this.register('nn.Max');
|
|
this.register('nn.Mean');
|
|
this.register('nn.Min');
|
|
this.register('nn.MulConstant');
|
|
this.register('nn.MM');
|
|
this.register('nn.MSECriterion');
|
|
this.register('nn.Narrow');
|
|
this.register('nn.NarrowTable');
|
|
this.register('nn.Normalize');
|
|
this.register('nn.Normalize2');
|
|
this.register('nn.NoiseFill');
|
|
this.register('nn.Padding');
|
|
this.register('nn.Parallel');
|
|
this.register('nn.ParallelCriterion');
|
|
this.register('nn.ParallelTable');
|
|
this.register('nn.PixelShuffle');
|
|
this.register('nn.Power');
|
|
this.register('nn.PReLU');
|
|
this.register('nn.Recursor');
|
|
this.register('nn.ReLU');
|
|
this.register('nn.Replicate');
|
|
this.register('nn.Reshape');
|
|
this.register('nn.ShaveImage');
|
|
this.register('nn.Select');
|
|
this.register('nn.SelectTable');
|
|
this.register('nn.Sequencer');
|
|
this.register('nn.Sequential');
|
|
this.register('nn.Sigmoid');
|
|
this.register('nn.Sum');
|
|
this.register('nn.SoftMax');
|
|
this.register('nn.SpatialAveragePooling');
|
|
this.register('nn.SpatialBatchNormalization');
|
|
this.register('nn.SpatialConvolution');
|
|
this.register('nn.SpatialConvolution1_fw');
|
|
this.register('nn.SpatialConvolutionMM');
|
|
this.register('nn.SpatialCrossMapLRN');
|
|
this.register('nn.SpatialDilatedConvolution');
|
|
this.register('nn.SpatialDropout');
|
|
this.register('nn.SpatialFractionalMaxPooling');
|
|
this.register('nn.SpatialFullConvolution');
|
|
this.register('nn.SpatialLPPooling');
|
|
this.register('nn.SpatialMaxPooling');
|
|
this.register('nn.SpatialMaxUnpooling');
|
|
this.register('nn.SpatialReflectionPadding');
|
|
this.register('nn.SpatialReplicationPadding');
|
|
this.register('nn.SpatialSoftMax');
|
|
this.register('nn.SpatialSubtractiveNormalization');
|
|
this.register('nn.SpatialUpSamplingBilinear');
|
|
this.register('nn.SpatialUpSamplingNearest');
|
|
this.register('nn.SpatialZeroPadding');
|
|
this.register('nn.SplitTable');
|
|
this.register('nn.Squeeze');
|
|
this.register('nn.Square');
|
|
this.register('nn.Sqrt');
|
|
this.register('nn.StereoJoin');
|
|
this.register('nn.Tanh');
|
|
this.register('nn.Transpose');
|
|
this.register('nn.TotalVariation');
|
|
this.register('nn.Unpool');
|
|
this.register('nn.View');
|
|
this.register('nn.gModule');
|
|
this.register('nngraph.Node');
|
|
this.register('graph.Edge');
|
|
this.register('graph.Graph');
|
|
this.register('torch.ByteTensor', class extends Tensor {
|
|
constructor() {
|
|
super('uint8');
|
|
}
|
|
});
|
|
this.register('torch.CharTensor', class extends Tensor {
|
|
constructor() {
|
|
super('int8');
|
|
}
|
|
});
|
|
this.register('torch.ShortTensor', class extends Tensor {
|
|
constructor() {
|
|
super('int16');
|
|
}
|
|
});
|
|
this.register('torch.IntTensor', class extends Tensor {
|
|
constructor() {
|
|
super('int32');
|
|
}
|
|
});
|
|
this.register('torch.LongTensor', class extends Tensor {
|
|
constructor() {
|
|
super('int64');
|
|
}
|
|
});
|
|
this.register('torch.FloatTensor', class extends Tensor {
|
|
constructor() {
|
|
super('float32');
|
|
}
|
|
});
|
|
this.register('torch.DoubleTensor', class extends Tensor {
|
|
constructor() {
|
|
super('float64');
|
|
}
|
|
});
|
|
this.register('torch.CudaByteTensor', class extends Tensor {
|
|
constructor() {
|
|
super('uint8');
|
|
}
|
|
});
|
|
this.register('torch.CudaCharTensor', class extends Tensor {
|
|
constructor() {
|
|
super('int8');
|
|
}
|
|
});
|
|
this.register('torch.CudaShortTensor', class extends Tensor {
|
|
constructor() {
|
|
super('int16');
|
|
}
|
|
});
|
|
this.register('torch.CudaIntTensor', class extends Tensor {
|
|
constructor() {
|
|
super('int32');
|
|
}
|
|
});
|
|
this.register('torch.CudaLongTensor', class extends Tensor {
|
|
constructor() {
|
|
super('int64');
|
|
}
|
|
});
|
|
this.register('torch.CudaTensor', class extends Tensor {
|
|
constructor() {
|
|
super('float32');
|
|
}
|
|
});
|
|
this.register('torch.CudaDoubleTensor', class extends Tensor {
|
|
constructor() {
|
|
super('float64');
|
|
}
|
|
});
|
|
this.register('torch.ByteStorage', class extends Storage {
|
|
constructor() {
|
|
super('uint8', 1);
|
|
}
|
|
});
|
|
this.register('torch.CharStorage', class extends Storage {
|
|
constructor() {
|
|
super('int8', 1);
|
|
}
|
|
});
|
|
this.register('torch.ShortStorage', class extends Storage {
|
|
constructor() {
|
|
super('int16', 2);
|
|
}
|
|
});
|
|
this.register('torch.IntStorage', class extends Storage {
|
|
constructor() {
|
|
super('int32', 4);
|
|
}
|
|
});
|
|
this.register('torch.LongStorage', class extends Storage {
|
|
constructor() {
|
|
super('int64', 8);
|
|
}
|
|
});
|
|
this.register('torch.FloatStorage', class extends Storage {
|
|
constructor() {
|
|
super('float32', 4);
|
|
}
|
|
});
|
|
this.register('torch.DoubleStorage', class extends Storage {
|
|
constructor() {
|
|
super('float64', 8);
|
|
}
|
|
});
|
|
this.register('torch.CudaByteStorage', class extends Storage {
|
|
constructor() {
|
|
super('uint8', 1);
|
|
}
|
|
});
|
|
this.register('torch.CudaCharStorage', class extends Storage {
|
|
constructor() {
|
|
super('int8', 1);
|
|
}
|
|
});
|
|
this.register('torch.CudaShortStorage', class extends Storage {
|
|
constructor() {
|
|
super('int16', 2);
|
|
}
|
|
});
|
|
this.register('torch.CudaIntStorage', class extends Storage {
|
|
constructor() {
|
|
super('int32', 4);
|
|
}
|
|
});
|
|
this.register('torch.CudaLongStorage', class extends Storage {
|
|
constructor() {
|
|
super('int64', 8);
|
|
}
|
|
});
|
|
this.register('torch.CudaIntStorage', class extends Storage {
|
|
constructor() {
|
|
super('int32', 4);
|
|
}
|
|
});
|
|
this.register('torch.CudaStorage', class extends Storage {
|
|
constructor() {
|
|
super('float32', 4);
|
|
}
|
|
});
|
|
this.register('torch.CudaFloatStorage', class extends Storage {
|
|
constructor() {
|
|
super('float64', 8);
|
|
}
|
|
});
|
|
this.register('w2nn.AuxiliaryLossTable');
|
|
this.register('w2nn.InplaceClip01');
|
|
this.register('w2nn.ScaleTable');
|
|
this.register('LuaFunction', class {
|
|
constructor(size, dumped, upvalues) {
|
|
this.size = size;
|
|
this.dumped = dumped;
|
|
this.upvalues = upvalues;
|
|
}
|
|
});
|
|
}
|
|
|
|
register(name, type) {
|
|
type = type || class {};
|
|
const parts = name.split('.');
|
|
type.__name__ = parts.pop();
|
|
type.__module__ = parts.join('.');
|
|
type.prototype.__class__ = type;
|
|
this._types.set(name, type);
|
|
}
|
|
|
|
read() {
|
|
const type = this.int32();
|
|
switch (type) {
|
|
case 0: return null;
|
|
case 1: return this.float64();
|
|
case 2: return this.string();
|
|
case 3: return this.table();
|
|
case 4: return this.object();
|
|
case 5: return this.boolean();
|
|
case 6: return this.function();
|
|
case 7: return this.function();
|
|
case 8: return this.function();
|
|
default: throw new torch.Error(`File format has invalid type '${type}'.`);
|
|
}
|
|
}
|
|
|
|
boolean() {
|
|
return this._reader.boolean();
|
|
}
|
|
|
|
int32() {
|
|
return this._reader.int32();
|
|
}
|
|
|
|
int64() {
|
|
return this._reader.int64();
|
|
}
|
|
|
|
int64s(size) {
|
|
return this._reader.int64s(size);
|
|
}
|
|
|
|
float64() {
|
|
return this._reader.float64();
|
|
}
|
|
|
|
string() {
|
|
return this._reader.string();
|
|
}
|
|
|
|
object() {
|
|
const index = this.int32();
|
|
if (this._memo.has(index)) {
|
|
return this._memo.get(index);
|
|
}
|
|
let version = this.string();
|
|
let name = null;
|
|
if (version.startsWith('V ')) {
|
|
name = this.string();
|
|
version = parseInt(version.split(' ')[1], 10);
|
|
} else {
|
|
name = version;
|
|
version = 0;
|
|
}
|
|
if (!this._types.has(name)) {
|
|
this.callback(name);
|
|
this.register(name);
|
|
}
|
|
const type = this._types.get(name);
|
|
const obj = Reflect.construct(type, []);
|
|
this._memo.set(index, obj);
|
|
if (obj.read) {
|
|
obj.read(this, version);
|
|
} else {
|
|
const attributes = this.read();
|
|
if (attributes !== null) {
|
|
for (const [key, value] of Array.from(attributes)) {
|
|
obj[key] = value;
|
|
}
|
|
}
|
|
}
|
|
return obj;
|
|
}
|
|
|
|
table() {
|
|
const index = this.int32();
|
|
if (this._memo.has(index)) {
|
|
return this._memo.get(index);
|
|
}
|
|
const table = new Map();
|
|
this._memo.set(index, table);
|
|
const size = this.int32();
|
|
let convert = true;
|
|
let sum = 0;
|
|
for (let i = 0; i < size; i++) {
|
|
const key = this.read();
|
|
const value = this.read();
|
|
table.set(key, value);
|
|
if (Number.isInteger(key) && key >= 0) {
|
|
sum += key;
|
|
} else {
|
|
convert = false;
|
|
}
|
|
}
|
|
const n = table.size;
|
|
if (convert && (n * (n + 1)) === (2 * sum)) {
|
|
const list = [];
|
|
for (let i = 0; i < n; i++) {
|
|
let item = table.get(i + 1);
|
|
if (item === table) {
|
|
item = list;
|
|
}
|
|
list.push(item);
|
|
}
|
|
this._memo.set(index, list);
|
|
return list;
|
|
}
|
|
return table;
|
|
}
|
|
|
|
function() {
|
|
const index = this.int32();
|
|
if (this._memo.has(index)) {
|
|
return this._memo.get(index);
|
|
}
|
|
const size = this.int32();
|
|
const dumped = this._reader.read(size);
|
|
const upvalues = this.read();
|
|
const type = this._types.get('LuaFunction');
|
|
const obj = Reflect.construct(type, [size, dumped, upvalues]);
|
|
this._memo.set(index, obj);
|
|
return obj;
|
|
}
|
|
|
|
storage(size, itemSize, dataType) {
|
|
return this._reader.storage(size, itemSize, dataType);
|
|
}
|
|
};
|
|
|
|
torch.BinaryReader = class {
|
|
|
|
constructor(data) {
|
|
this._reader = base.BinaryReader.open(data);
|
|
this._textDecoder = new TextDecoder('ascii');
|
|
}
|
|
|
|
seek(position) {
|
|
this._reader.seek(position);
|
|
}
|
|
|
|
skip(offset) {
|
|
this._reader.skip(offset);
|
|
}
|
|
|
|
read(length) {
|
|
return this._reader.read(length);
|
|
}
|
|
|
|
boolean() {
|
|
return this.int32() === 1;
|
|
}
|
|
|
|
int32() {
|
|
return this._reader.int32();
|
|
}
|
|
|
|
int64() {
|
|
return this._reader.int64().toNumber();
|
|
}
|
|
|
|
int64s(size) {
|
|
const array = [];
|
|
for (let i = 0; i < size; i++) {
|
|
array.push(this.int64());
|
|
}
|
|
return array;
|
|
}
|
|
|
|
float32() {
|
|
return this._reader.float32();
|
|
}
|
|
|
|
float64() {
|
|
return this._reader.float64();
|
|
}
|
|
|
|
string() {
|
|
const size = this.int32();
|
|
const buffer = this.read(size);
|
|
return this._textDecoder.decode(buffer);
|
|
}
|
|
|
|
storage(size, itemSize) {
|
|
const buffer = this.read(size * itemSize);
|
|
return new torch.BinaryReader(buffer);
|
|
}
|
|
};
|
|
|
|
torch.TextReader = class {
|
|
|
|
constructor(data, separator) {
|
|
this._buffer = data instanceof Uint8Array ? data : data.peek();
|
|
this._position = 0;
|
|
this._dataView = new DataView(this._buffer.buffer, this._buffer.byteOffset, this._buffer.byteLength);
|
|
this._textDecoder = new TextDecoder('ascii');
|
|
this._separator = separator || 0x0a;
|
|
}
|
|
|
|
seek(position) {
|
|
this._position = position;
|
|
}
|
|
|
|
line(size) {
|
|
const start = this._position;
|
|
while (this._position < this._buffer.length && size > -1) {
|
|
const c = this._buffer[this._position++];
|
|
if (c === this._separator) {
|
|
return this._buffer.slice(start, this._position - 1);
|
|
} else if (this._position === this._buffer.length) {
|
|
return this._buffer.slice(start, this._position);
|
|
}
|
|
size--;
|
|
}
|
|
throw new torch.Error('Line exceeded maximum length.');
|
|
}
|
|
|
|
boolean() {
|
|
return this.int32() === 1;
|
|
}
|
|
|
|
read(size) {
|
|
return this.line(size);
|
|
}
|
|
|
|
int8() {
|
|
return this.int64();
|
|
}
|
|
|
|
int16() {
|
|
return this.int64();
|
|
}
|
|
|
|
int32() {
|
|
return this.int64();
|
|
}
|
|
|
|
int64() {
|
|
const token = this._textDecoder.decode(this.line(20));
|
|
const number = Number.parseInt(token, 10);
|
|
if (Number.isNaN(token - number)) {
|
|
throw new torch.Error(`Couldn't parse int64 '${token}'.`);
|
|
}
|
|
return number;
|
|
}
|
|
|
|
int64s(size) {
|
|
const array = [];
|
|
if (size > 0) {
|
|
const content = this._textDecoder.decode(this.line(Number.MAX_SAFE_INTEGER));
|
|
for (const token of content.split(' ')) {
|
|
const number = Number.parseInt(token, 10);
|
|
if (Number.isNaN(token - number)) {
|
|
throw new torch.Error(`Couldn't parse int64 '${token}'.`);
|
|
}
|
|
array.push(number);
|
|
}
|
|
}
|
|
return array;
|
|
}
|
|
|
|
float32() {
|
|
return this.float64();
|
|
}
|
|
|
|
float64() {
|
|
const token = this._textDecoder.decode(this.line(24));
|
|
if (token.startsWith('-nan')) {
|
|
return -NaN;
|
|
}
|
|
if (token.startsWith('nan')) {
|
|
return NaN;
|
|
}
|
|
if (token.startsWith('inf')) {
|
|
return Infinity;
|
|
}
|
|
if (token.startsWith('-inf')) {
|
|
return -Infinity;
|
|
}
|
|
const number = Number.parseFloat(token);
|
|
if (Number.isNaN(token - number)) {
|
|
throw new torch.Error(`Couldn't parse float '${token}'.`);
|
|
}
|
|
return number;
|
|
}
|
|
|
|
string() {
|
|
const size = this.int32();
|
|
if (size === 0) {
|
|
return '';
|
|
}
|
|
const data = this.line(size);
|
|
const content = this._textDecoder.decode(data);
|
|
if (size !== content.length) {
|
|
throw new torch.Error('Invalid string length.');
|
|
}
|
|
return content;
|
|
}
|
|
|
|
storage(size, itemSize, dataType) {
|
|
if (size <= 0) {
|
|
throw new torch.Error(`Unsupported storage size '${size}'.`);
|
|
}
|
|
if (dataType === 'uint8') {
|
|
const start = this._position;
|
|
this._position += size;
|
|
const bytes = this._buffer.slice(start, this._position);
|
|
this.line(0);
|
|
return new torch.BinaryReader(bytes);
|
|
}
|
|
const data = this.line(Number.MAX_SAFE_INTEGER);
|
|
return new torch.TextReader(data, 0x20);
|
|
}
|
|
};
|
|
|
|
torch.Error = class extends Error {
|
|
|
|
constructor(message) {
|
|
super(message);
|
|
this.name = 'Error loading Torch model.';
|
|
}
|
|
};
|
|
|
|
export const ModelFactory = torch.ModelFactory;
|