ppljs-ppl-core
Version:
ppljs network inference framework core module
552 lines (532 loc) • 20.9 kB
JavaScript
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
class Buffer {
constructor(size, offset) { this.size_ = size; this.offset_ = offset; }
setSize(s) { this.size_ = s; }
setOffset(o) { this.offset_ = o; }
getSize() { return this.size_; }
getOffset() { return this.offset_; }
}
/******************************************************************************
Copyright (c) Microsoft Corporation.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
***************************************************************************** */
function __awaiter(thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
}
let GLOBAL_BACKEND = {
backend: '',
backendInstance: null
};
function registerBackend(backend, backendInstance) {
if (backend) {
GLOBAL_BACKEND.backend = backend;
}
if (backendInstance) {
GLOBAL_BACKEND.backendInstance = backendInstance;
}
}
function get_row() {
var _a;
var stack = (_a = new Error().stack) === null || _a === void 0 ? void 0 : _a.split(':')[7];
return parseInt(stack);
}
function numToString(data) {
var res_ = "";
for (var i = 0; i < data.length; i = i + 1) {
res_ = res_ + "_" + (data[i]).toString();
}
return res_;
}
function ppl_res_check(res, info) {
if (res != 0) {
console.error(info, " with ret:", res);
}
}
function ppl_debug(ifDebug, ...optionalParams) {
if (ifDebug) {
console.log(optionalParams);
}
}
function check_if_undefined(obj, info) {
if (obj == undefined) {
console.error(info);
return -1;
}
return 0;
}
function ppl_diff(src, dst, shape) {
let batch = shape[0];
let channel = shape[1];
let height = shape[2];
let width = shape[3];
if (src.byteLength != dst.byteLength) {
console.error("input0 and input1 have different length", src.byteLength, " vs ", dst.byteLength);
return false;
}
let totalNum = batch * channel * height * width;
if (src.byteLength != totalNum * 4) {
console.error("input and shape isn't match");
return false;
}
let src_ = new Float32Array(src);
let dst_ = new Float32Array(dst);
var equal_value = 0;
var re = 0;
var averageRelativeError = 0;
var averageAbsoluteError = 0;
var not_equal_value = 0;
var not_equal_abs5_value = 0;
var not_equal_abs4_value = 0;
var not_equal_abs3_value = 0;
var not_equal_abs2_value = 0;
var not_equal_abs1_value = 0;
for (var n = 0; n < batch; n++) {
for (var c = 0; c < channel; c++) {
for (var h = 0; h < height; h++) {
for (var w = 0; w < width; w++) {
let idx = w + h * width + c * height * width + n * channel * height * width;
var absoluteError = Math.abs(dst_[idx] - src_[idx]);
var relativeError = absoluteError / Math.abs(dst_[idx]);
if (dst_[idx] == 0 && absoluteError != 0)
relativeError = 1;
if (dst_[idx] == 0 && absoluteError == 0)
relativeError = 0;
averageAbsoluteError += absoluteError;
averageRelativeError += relativeError;
if (absoluteError <= 1e-6) {
equal_value++;
}
else if (absoluteError <= 1e-5) {
not_equal_abs5_value++;
}
else if (absoluteError <= 1e-4) {
not_equal_abs4_value++;
}
else if (absoluteError <= 1e-3) {
not_equal_abs3_value++;
}
else if (absoluteError <= 1e-2) {
not_equal_abs2_value++;
}
else if (absoluteError <= 1e-1) {
not_equal_abs1_value++;
re++;
}
else {
if (re == 0)
console.error("(", n, c, h, w, ") value is not equal:", src_[idx], " vs ", dst_[idx]);
not_equal_value++;
re++;
}
}
}
}
}
console.log("total value is: ", totalNum);
console.log("averageRelativeError value is: ", averageAbsoluteError / totalNum);
console.log("averageAbsoluteError value is: ", averageRelativeError / totalNum);
console.log("equal value is: ", equal_value, " ratio: ", equal_value / totalNum * 100, "%");
console.log("not_equal 10-5 value is: ", not_equal_abs5_value, " ratio: ", not_equal_abs5_value / totalNum * 100, "%");
console.log("not_equal 10-4 value is: ", not_equal_abs4_value, " ratio: ", not_equal_abs4_value / totalNum * 100, "%");
console.log("not_equal 10-3 value is: ", not_equal_abs3_value, " ratio: ", not_equal_abs3_value / totalNum * 100, "%");
console.log("not_equal 10-2 value is: ", not_equal_abs2_value, " ratio: ", not_equal_abs2_value / totalNum * 100, "%");
console.log("not_equal 10-1 value is: ", not_equal_abs1_value, " ratio: ", not_equal_abs1_value / totalNum * 100, "%");
console.log("not equal value is: ", not_equal_value, " ratio: ", not_equal_value / totalNum * 100, "%");
if (not_equal_value == 0)
return true;
else
return false;
}
var log = /*#__PURE__*/Object.freeze({
__proto__: null,
get_row: get_row,
numToString: numToString,
ppl_res_check: ppl_res_check,
ppl_debug: ppl_debug,
check_if_undefined: check_if_undefined,
ppl_diff: ppl_diff
});
class Executer {
constructor(config) {
this.modeConfig_ = {};
this.ret = 0;
this.modeConfig_ = config;
if (!GLOBAL_BACKEND.backendInstance) {
console.error('no backend instance has been registered!');
this.ret = -1;
}
ppl_debug(this.modeConfig_.debug, "backend engin is ", GLOBAL_BACKEND.backend);
GLOBAL_BACKEND.backendInstance.createGraph(this.modeConfig_);
}
prepare() {
return __awaiter(this, void 0, void 0, function* () {
if (this.ret != 0)
return this.ret;
return yield GLOBAL_BACKEND.backendInstance.prepare();
});
}
forward(ifGetOutput = false) {
return GLOBAL_BACKEND.backendInstance.forward(ifGetOutput);
}
release() { GLOBAL_BACKEND.backendInstance.release(); }
setInputByArrayBuffer(data) {
return GLOBAL_BACKEND.backendInstance.setInputByArrayBuffer(data);
}
setInputByArray(data) {
var tmpData = new Array(0);
for (let i of data) {
let tmpBuffer = new Float32Array(i).buffer;
tmpData.push(tmpBuffer);
}
var res = this.setInputByArrayBuffer(tmpData);
return res;
}
setInputByPath(firstName, ...restName) {
const dataArray = [];
return this.setInputByArray(dataArray);
}
getArrayBufferOutput() {
return GLOBAL_BACKEND.backendInstance.getArrayBufferOutput();
}
getInputShapeByIndex(idx) {
return GLOBAL_BACKEND.backendInstance.getInputShapeByIndex(idx);
}
getOutputShapeByIndex(idx) {
return GLOBAL_BACKEND.backendInstance.getOutputShapeByIndex(idx);
}
getInputCount() {
return GLOBAL_BACKEND.backendInstance.getInputCount();
}
getOutputCount() {
return GLOBAL_BACKEND.backendInstance.getOutputCount();
}
finishWork() {
return GLOBAL_BACKEND.backendInstance.finishWork();
}
}
class Graph {
constructor(model) {
this.tmpBufferTensor_ = null;
this.inputData = [];
this.ifDebug = false;
this.inputChanged_ = false;
this.totalOpNode_ = model.ops;
this.totalKernel_ = [];
this.inputTensor_ = [];
this.outputTensor_ = [];
}
;
setIfDebug(ifDebug) { this.ifDebug = ifDebug; }
getIfDebug() { return this.ifDebug; }
;
assignTensorToKernel() {
var currentTensor = {};
this.totalOpNode_.forEach((oneOpNode, idx) => {
oneOpNode.inputs.forEach((opEdge_) => {
var tensorName_ = opEdge_.name;
var find_res = currentTensor[tensorName_];
this.totalKernel_[idx].addInShape(opEdge_.tensorInfo.shape);
if (find_res == undefined) {
var tensor_;
var edgeName_ = opEdge_.name;
if (edgeName_.includes('ppljs_input')) {
tensor_ = this.createTensor(opEdge_.tensorInfo, true, false);
this.inputTensor_.push(tensor_);
}
else
tensor_ = this.createTensor(opEdge_.tensorInfo, false, false);
this.totalKernel_[idx].addInTensor(tensor_);
currentTensor[tensorName_] = tensor_;
}
else {
this.totalKernel_[idx].addInTensor(find_res);
}
});
oneOpNode.outputs.forEach((opEdge_) => {
var edgeName_ = opEdge_.name;
var find_res = currentTensor[edgeName_];
this.totalKernel_[idx].addOutShape(opEdge_.tensorInfo.shape);
if (find_res == undefined) {
var tensor_;
if (edgeName_.includes('ppljs_output')) {
tensor_ = this.createTensor(opEdge_.tensorInfo, false, true);
this.outputTensor_.push(tensor_);
}
else
tensor_ = this.createTensor(opEdge_.tensorInfo, false, false);
this.totalKernel_[idx].addOutTensor(tensor_);
currentTensor[edgeName_] = tensor_;
}
else {
this.totalKernel_[idx].addOutTensor(find_res);
}
});
});
return 0;
}
assignMemoryToTensor() {
this.inputTensor_.forEach((inTensor) => {
if (inTensor.buffer == undefined) {
inTensor.mallocTensorBuffer();
}
});
this.outputTensor_.forEach((outTensor) => {
if (outTensor.buffer == undefined) {
outTensor.mallocTensorBuffer();
}
});
var maxTempSize = 0;
this.totalKernel_.forEach((tTotal) => {
for (var n = 0; n < tTotal.getOutTensorCount(); n++) {
if (tTotal.getOutTensor(n).buffer == undefined) {
tTotal.getOutTensor(n).mallocTensorBuffer();
}
}
maxTempSize = (tTotal.tempBufferSize() > maxTempSize ? tTotal.tempBufferSize() : maxTempSize);
});
if (maxTempSize != 0) {
this.tmpBufferTensor_ = this.createTensor({ name: "tempBuffer", shape: [1, 1, 1, maxTempSize], precision: 1 }, false, false);
this.tmpBufferTensor_.mallocTensorBuffer();
for (let t in this.totalKernel_) {
if ((this.totalKernel_[t]).tempBufferSize() != 0) {
(this.totalKernel_[t]).setTmpTensor(this.tmpBufferTensor_);
}
}
}
return 0;
}
setInputFromArrayBuffer(inData) {
this.inputData = inData;
this.inputChanged_ = true;
return 0;
}
getInputTensorCount() { return this.inputTensor_.length; }
getInputTensor(i) { return this.inputTensor_[i]; }
getOutputTensorCount() { return this.outputTensor_.length; }
getOutputTensor(i) { return this.outputTensor_[i]; }
getKernelCount() { return this.totalKernel_.length; }
getKernel(i) { return this.totalKernel_[i]; }
getInputTensorShape(idx) {
if (idx >= this.getInputTensorCount()) {
console.error("idx exceed inputTensor size");
return null;
}
return this.inputTensor_[idx].shape();
}
getOutputTensorShape(idx) {
if (idx >= this.getOutputTensorCount()) {
console.error("idx exceed outputTensor size");
return null;
}
return this.outputTensor_[idx].shape();
}
releaseResources() {
for (let iT of this.inputTensor_) {
iT.releaseTensorBuffer();
}
for (let oT of this.outputTensor_) {
oT.releaseTensorBuffer();
}
for (let k of this.totalKernel_) {
for (var iT = 0; iT < k.getInTensorCount(); iT = iT + 1) {
k.getInTensor(iT).releaseTensorBuffer();
}
for (var oT = 0; oT < k.getOutTensorCount(); oT = oT + 1) {
k.getOutTensor(oT).releaseTensorBuffer();
}
}
for (let t in this.totalKernel_) {
(this.totalKernel_[t]).releaseKernelResource();
}
if (this.tmpBufferTensor_ != null)
this.tmpBufferTensor_.releaseTensorBuffer();
return 0;
}
}
class Kernel {
constructor(opNode) {
this.name_ = '';
this.type_ = '';
this.data_ = {};
this.param_ = {};
this.inTensors_ = [];
this.outTensors_ = [];
this.tmpTensor_ = null;
this.inShape_ = [];
this.outShape_ = [];
this.name_ = opNode.props.name;
this.type_ = opNode.props.type;
this.param_ = opNode.attrs;
this.data_ = opNode.data;
}
;
setTmpTensor(data) { this.tmpTensor_ = data; return 0; }
set name(name) { this.name_ = name; }
set kernelType(kernelType) { this.type_ = kernelType; }
get name() { return this.name_; }
get kernelType() { return this.type_; }
addInTensor(t) { this.inTensors_.push(t); return 0; }
addInShape(t) { this.inShape_.push(t); return 0; }
addOutTensor(t) { this.outTensors_.push(t); return 0; }
addOutShape(t) { this.outShape_.push(t); return 0; }
getInTensorCount() { return this.inTensors_.length; }
getOutTensorCount() { return this.outTensors_.length; }
getInTensor(index) { return this.inTensors_[index]; }
getInShape(index) { return this.inShape_[index]; }
getOutTensor(index) { return this.outTensors_[index]; }
getOutShape(index) { return this.outShape_[index]; }
}
class Runtime {
constructor() {
this.graph_ = null;
}
;
setInputByArrayBuffer(data) {
return (this.graph_).setInputFromArrayBuffer(data);
}
getArrayBufferOutput() {
return (this.graph_).getArrayBufferOutput();
}
getInputShapeByIndex(idx) {
return (this.graph_).getInputTensorShape(idx);
}
getOutputShapeByIndex(idx) {
return (this.graph_).getOutputTensorShape(idx);
}
getInputCount() {
return (this.graph_).getInputTensorCount();
}
getOutputCount() {
return (this.graph_).getOutputTensorCount();
}
finishWork() {
return (this.graph_).finish();
}
}
class Tensor {
constructor(t) {
this.tensorInfo_ = t;
this.producerCount_ = 0;
this.consumerCount_ = 0;
}
dimCount() { return this.tensorInfo_.shape.length; }
dim(index) { return this.tensorInfo_.shape[index]; }
shape() { return this.tensorInfo_.shape; }
byteLength() {
var shapeNum_ = this.shape();
return shapeNum_[0] * shapeNum_[1] * shapeNum_[2] * shapeNum_[3] * (this.precision() + 1) * 2;
}
precision() { return this.tensorInfo_.precision; }
get name() { return this.tensorInfo_.name; }
set name(name_) { this.tensorInfo_.name = name_; }
get buffer() { return this.tensorInfo_.deviceData; }
set buffer(buffer_) { this.tensorInfo_.deviceData = buffer_; }
getname() { return this.tensorInfo_.name; }
setname(name_) { this.tensorInfo_.name = name_; }
getbuffer() { return this.tensorInfo_.deviceData; }
setbuffer(buffer_) { this.tensorInfo_.deviceData = buffer_; }
producerCount() { return this.producerCount_; }
consumerCount() { return this.consumerCount_; }
incProducerCount() { this.producerCount_++; }
incConsumerCount() { this.consumerCount_++; }
}
class ModelLoader {
constructor(modelConfig) {
this.modelConfig_ = modelConfig;
if (modelConfig.modelName == undefined)
this.modelConfig_.modelName = "model.json";
if (modelConfig.binaryDataName == undefined)
this.modelConfig_.binaryDataName = "model.dat";
if (modelConfig.modelPath.charAt(modelConfig.modelPath.length - 1) != '/') {
this.modelConfig_.modelPath = `${modelConfig.modelPath}/`;
}
this.isLocalPath = modelConfig.modelPath.indexOf('http') != 0;
}
LoadModel() {
return __awaiter(this, void 0, void 0, function* () {
var p1 = this.ParseJsonModel();
var p2 = this.ReadModelData();
return new Promise((resolve) => {
Promise.all([p1, p2]).then(res => {
this.AssignData(res[0], res[1]);
resolve(res[0]);
});
});
});
}
readData(modelPath) {
return new Promise((resolve, reject) => {
fetch(modelPath, {
method: 'get',
}).then(response => { resolve(response.arrayBuffer()); })
.then(err => reject(err));
});
}
ParseJsonModel() {
const modelPath = this.modelConfig_.modelPath + this.modelConfig_.modelName;
return new Promise((resolve, reject) => {
fetch(modelPath, {
method: 'get',
}).then(response => { resolve(response.json()); })
.then(err => reject(err));
});
}
ReadModelData() {
const binaryPath = this.modelConfig_.modelPath + this.modelConfig_.binaryDataName;
return new Promise((resolve, reject) => {
this.readData(binaryPath).then(response => {
var array = new Float32Array(response);
resolve(array);
}).catch(err => reject(err));
});
}
AssignData(opModel_, dataArray) {
opModel_.ops.forEach((op) => {
if (op.data != undefined) {
var offset = op.hostDataOffset;
for (var item in op.data) {
var size_ = op.data[item].size;
op.data[item].hostData = dataArray.slice(offset, offset + size_);
offset += (size_);
}
}
});
}
}
var backend;
(function (backend) {
backend[backend["Backend_WebGPU"] = 0] = "Backend_WebGPU";
})(backend || (backend = {}));
var _interface = /*#__PURE__*/Object.freeze({
__proto__: null,
get backend () { return backend; }
});
var opParam = /*#__PURE__*/Object.freeze({
__proto__: null
});
exports.Buffer = Buffer;
exports.Executer = Executer;
exports.Graph = Graph;
exports.Kernel = Kernel;
exports.ModelLoader = ModelLoader;
exports.Runtime = Runtime;
exports.Tensor = Tensor;
exports.interfaces = _interface;
exports.log = log;
exports.opParams = opParam;
exports.registerBackend = registerBackend;