Skip to content
This repository has been archived by the owner on Apr 18, 2023. It is now read-only.

Commit

Permalink
Merge pull request #524 from pinzhenx/iter
Browse files Browse the repository at this point in the history
[Example] API for iterating layer outputs
  • Loading branch information
huningxin authored Feb 26, 2019
2 parents 4d58f4f + 2af788b commit 269753a
Show file tree
Hide file tree
Showing 4 changed files with 203 additions and 6 deletions.
46 changes: 46 additions & 0 deletions examples/image_classification/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -218,4 +218,50 @@ class Utils {
this.model._compilation._preparedModel._deleteAll();
}
}


// for debugging
async iterateLayers(configs, layerList) {
if (!this.initialized) return;

let iterators = [];
for (let config of configs) {
let importer = this.modelFile.split('.').pop() === 'tflite' ? TFliteModelImporter : OnnxModelImporter;
let model = await new importer({
rawModel: this.rawModel,
backend: config.backend,
prefer: config.prefer || null,
});
iterators.push(model.layerIterator([this.inputTensor], layerList));
}

while (true) {

let layerOutputs = [];
for (let it of iterators) {
layerOutputs.push(await it.next());
}

let refOutput = layerOutputs[0];
if (refOutput.done) {
break;
}

console.debug(`\n\n\nLayer(${refOutput.value.layerId}) ${refOutput.value.outputName}`);

for (let i = 0; i < configs.length; ++i) {
console.debug(`\n${configs[i].backend}:`);
console.debug(`\n${layerOutputs[i].value.tensor}`);

if (i > 0) {
let sum = 0;
for (let j = 0; j < refOutput.value.tensor.length; j++) {
sum += Math.pow(layerOutputs[i].value.tensor[j] - refOutput.value.tensor[j], 2);
}
let variance = sum / refOutput.value.tensor.length;
console.debug(`var with ${configs[0].backend}: ${variance}`);
}
}
}
}
}
44 changes: 44 additions & 0 deletions examples/semantic_segmentation/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -161,4 +161,48 @@ class Utils {
this.outputTensor = new Float32Array(newModel.outputSize.reduce((x,y) => x*y));
this.tfModel = null;
}

// for debugging
async iterateLayers(configs, layerList) {
if (!this.initialized) return;

let iterators = [];
for (let config of configs) {
let model = await new TFliteModelImporter({
rawModel: this.tfModel,
backend: config.backend,
prefer: config.prefer || null,
});
iterators.push(model.layerIterator([this.inputTensor], layerList));
}

while (true) {

let layerOutputs = [];
for (let it of iterators) {
layerOutputs.push(await it.next());
}

let refOutput = layerOutputs[0];
if (refOutput.done) {
break;
}

console.debug(`\n\n\nLayer(${refOutput.value.layerId}) ${refOutput.value.outputName}`);

for (let i = 0; i < configs.length; ++i) {
console.debug(`\n${configs[i].backend}:`);
console.debug(`\n${layerOutputs[i].value.tensor}`);

if (i > 0) {
let sum = 0;
for (let j = 0; j < refOutput.value.tensor.length; j++) {
sum += Math.pow(layerOutputs[i].value.tensor[j] - refOutput.value.tensor[j], 2);
}
let variance = sum / refOutput.value.tensor.length;
console.debug(`var with ${configs[0].backend}: ${variance}`);
}
}
}
}
}
61 changes: 57 additions & 4 deletions examples/util/onnx/OnnxModelImporter.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,56 @@ class OnnxModelImporter {
return 'success';
}

async * layerIterator(inputTensors, layerList) {
const graph = this._rawModel.graph;
const getLayerOutput = async (lastNode) => {
this._tensorIds = [];
this._tensorTypes = [];
this._operations = [];
this._operands = [];
this._operandIndex = 0;
if (this._backend !== 'WebML' && this._compilation) {
this._compilation._preparedModel._deleteAll();
}

this._model = await this._nn.createModel({backend: this._backend});
this._addTensorOperands();
lastNode = this._addOpsAndParams(lastNode);

const outputName = graph.node[lastNode].output[0];
const inputs = [this._getTensorIdByName(graph.node[0].input[0])];
const outputs = [this._getTensorIdByName(outputName)];
this._model.identifyInputsAndOutputs(inputs, outputs);

await this._model.finish();
this._compilation = await this._model.createCompilation();
this._compilation.setPreference(getPreferCode(this._backend, this._prefer));
await this._compilation.finish();
this._execution = await this._compilation.createExecution();

const outputSize = this._getTensorTypeByName(outputName).dimensions.reduce((a, b) => a * b);
const outputTensor = new Float32Array(outputSize);
await this.compute(inputTensors, [outputTensor]);
return {layerId: lastNode, outputName: outputName, tensor: outputTensor};
}

const operatorsLength = graph.node.length;
if (typeof layerList === 'undefined') {
for (let lastNode = 0; lastNode < operatorsLength;) {
const layerOutput = await getLayerOutput(lastNode);
yield layerOutput;
lastNode = layerOutput.layerId + 1;
}
} else {
for (let layerId of layerList) {
if (layerId >= operatorsLength || layerId < 0) {
throw new Error(`Illegal layer ${layerId}`);
}
yield await getLayerOutput(layerId);
}
}
}

_getOperandValue(id) {
return this._operands[id];
}
Expand Down Expand Up @@ -204,9 +254,13 @@ class OnnxModelImporter {
return info.type;
}

_addOpsAndParams() {
_addOpsAndParams(lastNode) {
const graph = this._rawModel.graph;
for (let i = 0; i < graph.node.length; ++i) {
let i;
if (typeof lastNode === 'undefined') {
lastNode = graph.node.length - 1;
}
for (i = 0; i <= lastNode; ++i) {
let node = graph.node[i];
console.log(`opType: ${node.opType}`);
let opCode;
Expand Down Expand Up @@ -761,8 +815,6 @@ class OnnxModelImporter {
// Set beta to 1.0
inputs.push(this._addScalarFloat32(1.0));
const output = node.output[0];
outputs.push(this._getTensorIdByName(output));

const inputType = this._getTensorTypeByName(input);
const outputType = {type: this._nn.TENSOR_FLOAT32, dimensions: inputType.dimensions};
const outputId = this._addNewTensorOperand(output, outputType);
Expand Down Expand Up @@ -820,5 +872,6 @@ class OnnxModelImporter {
for (const [opCode, inputs, outputs] of this._operations) {
this._model.addOperation(opCode, inputs, outputs);
}
return i - 1;
}
}
58 changes: 56 additions & 2 deletions examples/util/tflite/TFliteModelImporter.js
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,56 @@ class TFliteModelImporter {
}, new Float32Array(tensor));
}

_addOpsAndParams() {
async * layerIterator(inputTensors, layerList) {
const graph = this._rawModel.subgraphs(0);
const getLayerOutput = async (lastNode) => {
this._tensorIds = [];
this._operands = [];
this._operandIndex = 0;
if (this._backend !== 'WebML' && this._compilation) {
this._compilation._preparedModel._deleteAll();
}

this._model = await this._nn.createModel({backend: this._backend});
this._addTensorOperands();
lastNode = this._addOpsAndParams(lastNode);

const operator = graph.operators(lastNode);
const inputs = Array.from(graph.inputsArray());
const outputs = Array.from(operator.outputsArray());
const outputName = graph.tensors(outputs[0]).name();
this._model.identifyInputsAndOutputs(inputs, outputs);

await this._model.finish();
this._compilation = await this._model.createCompilation();
this._compilation.setPreference(getPreferCode(this._backend, this._prefer));
await this._compilation.finish();
this._execution = await this._compilation.createExecution();

const outputSize = graph.tensors(outputs[0]).shapeArray().reduce((a,b)=>a*b);
const outputTensor = new Float32Array(outputSize);
await this.compute(inputTensors, [outputTensor]);
return {layerId: lastNode, outputName: outputName, tensor: outputTensor};
}

const operatorsLength = graph.operatorsLength();
if (typeof layerList === 'undefined') {
for (let lastNode = 0; lastNode < operatorsLength;) {
const layerOutput = await getLayerOutput(lastNode);
yield layerOutput;
lastNode = layerOutput.layerId + 1;
}
} else {
for (let layerId of layerList) {
if (layerId >= operatorsLength || layerId < 0) {
throw new Error(`Illegal layer ${layerId}`);
}
yield await getLayerOutput(layerId);
}
}
}

_addOpsAndParams(lastNode) {
const PaddingCodeMap = new Map([
[tflite.Padding.SAME, this._nn.PADDING_SAME],
[tflite.Padding.VALID, this._nn.PADDING_VALID]
Expand All @@ -148,7 +197,11 @@ class TFliteModelImporter {

let graph = this._rawModel.subgraphs(0);
let operatorsLength = graph.operatorsLength();
for (let i = 0; i < operatorsLength; ++i) {
let i;
if (typeof lastNode === 'undefined') {
lastNode = operatorsLength - 1;
}
for (i = 0; i <= lastNode; ++i) {
let operator = graph.operators(i);
let opCode = this._rawModel.operatorCodes(operator.opcodeIndex()).builtinCode();
let opType;
Expand Down Expand Up @@ -318,5 +371,6 @@ class TFliteModelImporter {

this._model.addOperation(opType, inputs, outputs);
}
return i - 1;
}
}

0 comments on commit 269753a

Please sign in to comment.