const tosa = {}; tosa.ModelFactory = class { async match(context) { const reader = await context.peek('flatbuffers.binary'); if (reader && reader.identifier === 'TOSA') { return context.set('tosa.flatbuffers', reader); } const obj = await context.peek('json'); if (obj && obj.regions && obj.version && obj.version._major !== undefined) { return context.set('tosa.flatbuffers.json', obj); } return null; } async open(context) { tosa.schema = await context.require('./tosa-schema'); tosa.schema = tosa.schema.tosa; let major = -1; let minor = -1; let patch = -1; switch (context.type) { case 'tosa.flatbuffers': { const reader = context.value; try { const root = reader.root; const vtable = root - reader.int32(root); const vtableSize = reader.int16(vtable); if (vtableSize > 4) { const versionFieldOffset = reader.int16(vtable + 4); if (versionFieldOffset) { const ref = root + versionFieldOffset; const position = ref + reader.int32(ref); const vvtable = position - reader.int32(position); const vvtableSize = reader.int16(vvtable); const field = (index) => { const offset = 4 + index * 2; if (offset < vvtableSize) { const value = reader.int16(vvtable + offset); if (value) { return reader.int32(position + value); } } return -1; }; major = field(0); minor = field(1); patch = field(2); } } } catch (error) { const message = error && error.message ? error.message : error.toString(); throw new tosa.Error(`File format is not tosa.TosaGraph (${message.replace(/\.$/, '')}).`); } break; } case 'tosa.flatbuffers.json': { const obj = context.value; if (obj.version) { const v = obj.version; major = v._major === undefined ? -1 : v._major; minor = v._minor === undefined ? -1 : v._minor; patch = v._patch === undefined ? -1 : v._patch; } break; } default: { throw new tosa.Error(`Unsupported TOSA format '${context.type}'.`); } } const file_version = `${major}.${minor}.${patch}`; let schema_version = ''; if (major === 0 && minor >= 80) { schema_version = '0.80'; } else if (major === 1) { schema_version = '1.0'; } const schema = { '0.80': tosa.schema.v0, '1.0': tosa.schema.v1 }[schema_version]; if (!schema) { throw new tosa.Error(`Unsupported TOSA version '${file_version}'.`); } let model = null; try { switch (context.type) { case 'tosa.flatbuffers': { model = schema.TosaGraph.create(context.value); break; } case 'tosa.flatbuffers.json': { const reader = await context.read('flatbuffers.text'); model = schema.TosaGraph.createText(reader); break; } default: { break; } } } catch (error) { const message = error && error.message ? error.message : error.toString(); throw new tosa.Error(`File format is not tosa.TosaGraph (${message.replace(/\.$/, '')}).`); } const data = await context.asset('tosa-metadata.json'); const metadata = new tosa.Metadata(data, schema_version); return new tosa.Model(new tosa.Context(schema, metadata), model, file_version); } }; tosa.Model = class { constructor(context, model, version) { this.format = `TOSA v${version}`; this.modules = []; for (const region of model.regions) { for (const block of region.blocks) { this.modules.push(new tosa.Graph(context, block, region.name)); } } } }; tosa.Graph = class { constructor(context, block, region) { this.name = region ? `${region}/${block.name}` : block.name || ''; const tensors = new Map(); for (const tensor of block.tensors) { const type = new tosa.TensorType(context, tensor.type, tensor.shape); const data = tensor.data && tensor.data.length > 0 ? tensor.data : null; const initializer = data ? new tosa.Tensor(tensor.name, type, data) : null; if (initializer && tensor.variable) { initializer.category = 'Variable'; } const value = new tosa.Value(tensor.name, type, initializer); if (tensor.variable) { value.visible = tensor.variable; } tensors.set(tensor.name, value); } const value = (name) => { if (!tensors.has(name)) { tensors.set(name, new tosa.Value(name, null, null)); } return tensors.get(name); }; this.inputs = (block.inputs || []).map((name) => new tosa.Argument(name, [value(name)])); this.outputs = (block.outputs || []).map((name) => new tosa.Argument(name, [value(name)])); this.nodes = (block.operators || []).map((operator, index) => new tosa.Node(context, operator, index, value)).filter((node) => !node.type.name.startsWith('CONST')); } }; tosa.Node = class { constructor(context, operator, index, value) { const enumTypes = { acc_type: 'DType', accum_dtype: 'DType', type: 'DType', mode: 'ResizeMode', nan_mode: 'NanPropagationMode', rounding_mode: 'RoundingMode' }; const op = operator.op; const opName = context.enum('Op', op); this.type = context.type(opName); this.name = ''; this.identifier = index.toString(); this.inputs = []; this.outputs = []; this.attributes = []; const inputs = operator.inputs || []; for (let i = 0; i < inputs.length; i++) { const name = this.type && this.type.inputs && i < this.type.inputs.length ? this.type.inputs[i].name : `input${i}`; const values = [value(inputs[i])]; this.inputs.push(new tosa.Argument(name, values)); } const outputs = operator.outputs || []; for (let i = 0; i < outputs.length; i++) { const name = this.type && this.type.outputs && i < this.type.outputs.length ? this.type.outputs[i].name : `output${i}`; const values = [value(outputs[i])]; this.outputs.push(new tosa.Argument(name, values)); } const options = operator.attribute; if (options) { for (const [name, obj] of Object.entries(options)) { if (name === 'type') { continue; } const schema = context.attribute(opName, name); let value = ArrayBuffer.isView(obj) ? Array.from(obj) : obj; let visible = true; let type = null; if (schema) { if (schema.visible === false) { visible = false; } else if (schema.default !== undefined) { if (value === schema.default) { visible = false; } } } if (typeof value === 'bigint') { value = value.toNumber(); } if (typeof value === 'number' && Number.isInteger(value)) { const enumType = enumTypes[name] || null; if (enumType) { const enumValue = context.enum(enumType, value); if (enumValue !== value.toString()) { type = enumType; value = enumValue; } } } if (opName !== 'CUSTOM' && obj instanceof Uint8Array) { const view = new DataView(obj.buffer); const output = this.outputs[0]; type = output && output.value && output.value[0] && output.value[0].type ? output.value[0].type.dataType : null; switch (type) { case 'boolean': value = view.getUint8(0) !== 0; break; case 'int8': value = view.getInt8(0); break; case 'int16': value = view.getInt16(0, true); break; case 'int32': value = view.getInt32(0, true); break; case 'int64': value = view.getBigInt64(0, true); break; case 'float16': value = view.getFloat16(0, true); break; case 'bfloat16': value = view.getBfloat16(0, true); break; case 'float32': value = view.getFloat32(0, true); break; case 'float8e4m3': value = view.getFloat8e4m3(0); break; case 'float8e5m2': value = view.getFloat8e5m2(0); break; default: throw new tosa.Error(`Unsupported attribute type '${type}.`); } } this.attributes.push(new tosa.Argument(name, value, type, visible)); } } } }; tosa.Argument = class { constructor(name, value, type = null, visible = true) { this.name = name; this.value = value; this.type = type; this.visible = visible; } }; tosa.Value = class { constructor(name, type, initializer) { this.name = name; this.type = type; this.initializer = initializer; } }; tosa.Tensor = class { constructor(name, type, data) { this.name = name; this.type = type; this.encoding = '<'; this._data = data; } get values() { if (this._data instanceof Uint8Array) { return this._data; } if (this._data && this._data.peek) { return this._data.peek(); } return null; } }; tosa.TensorType = class { constructor(context, dataType, shape) { this.dataType = context.dataType(dataType); this.shape = new tosa.TensorShape(shape); } toString() { return this.dataType + this.shape.toString(); } }; tosa.TensorShape = class { constructor(dimensions) { this.dimensions = dimensions ? Array.from(dimensions) : []; } toString() { if (this.dimensions && this.dimensions.length > 0) { return `[${this.dimensions.map((d) => d.toString()).join(',')}]`; } return ''; } }; tosa.Context = class { constructor(schema, metadata) { this._schema = schema; this._metadata = metadata; const mapping = { BOOL: 'boolean', UINT8: 'uint8', UINT16: 'uint16', INT4: 'int4', INT8: 'int8', INT16: 'int16', INT32: 'int32', INT48: 'int48', FP16: 'float16', BF16: 'bfloat16', FP32: 'float32', FP8E4M3: 'float8e4m3', FP8E5M2: 'float8e5m2', SHAPE: 'int64' }; this._dataTypes = new Map(); for (const [key, value] of Object.entries(schema.DType)) { this._dataTypes.set(value, mapping[key] || key.toLowerCase()); } } type(name) { return this._metadata.type(name); } attribute(type, name) { return this._metadata.attribute(type, name); } dataType(type) { return this._dataTypes.get(type) || '?'; } enum(name, value) { const type = name && this._schema ? this._schema[name] : undefined; return type && type[value] ? type[value] : value.toString(); } }; tosa.Metadata = class { constructor(data, version) { this._types = new Map(); this._attributes = new Map(); if (data) { const types = JSON.parse(data); for (const type of types) { if (type.version === version) { this._types.set(type.name, type); } } } } type(name) { if (!this._types.has(name)) { this._types.set(name, { name }); } return this._types.get(name); } attribute(type, name) { const key = `${type}:${name}`; if (!this._attributes.has(key)) { this._attributes.set(key, null); const metadata = this._types.get(type); if (metadata && metadata.attributes) { for (const attribute of metadata.attributes) { this._attributes.set(`${type}:${attribute.name}`, attribute); } } } return this._attributes.get(key); } }; tosa.Error = class extends Error { constructor(message) { super(message); this.name = 'Error loading TOSA model.'; } }; export const ModelFactory = tosa.ModelFactory;