Files
wehub-resource-sync 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
chore: import upstream snapshot with attribution
2026-07-13 12:37:45 +08:00

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;