Skip to content

Commit

Permalink
Use both MLOperandDescriptor.dimensions and MLOperandDescriptor.shape (
Browse files Browse the repository at this point in the history
…#274)

Fixed #273
  • Loading branch information
Honry authored Sep 19, 2024
1 parent c5e6539 commit 229c4e2
Show file tree
Hide file tree
Showing 37 changed files with 152 additions and 101 deletions.
12 changes: 10 additions & 2 deletions code/samples/matmul.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,16 @@
const context = await navigator.ml.createContext({deviceType: 'gpu'});
const builder = new MLGraphBuilder(context);
// Step 1: Create a computational graph calculating `c = a * b`.
const a = builder.input('a', {dataType: 'float32', dimensions: [3, 4]});
const b = builder.input('b', {dataType: 'float32', dimensions: [4, 3]});
const a = builder.input('a', {
dataType: 'float32',
dimensions: [3, 4],
shape: [3, 4],
});
const b = builder.input('b', {
dataType: 'float32',
dimensions: [4, 3],
shape: [4, 3],
});
const c = builder.matmul(a, b);
// Step 2: Compile it into an executable graph.
const graph = await builder.build({c});
Expand Down
2 changes: 1 addition & 1 deletion code/samples/mul_add.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
const operandType = {dataType: 'float32', dimensions: [2, 2]};
const operandType = {dataType: 'float32', dimensions: [2, 2], shape: [2, 2]};
const context = await navigator.ml.createContext();
const builder = new MLGraphBuilder(context);
// 1. Create a computational graph 'C = 0.2 * A + B'.
Expand Down
2 changes: 1 addition & 1 deletion code/samples/simple_graph.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ const TENSOR_SIZE = 8;
const builder = new MLGraphBuilder(context);

// Create MLOperandDescriptor object.
const desc = {dataType: 'float32', dimensions: TENSOR_DIMS};
const desc = {dataType: 'float32', dimensions: TENSOR_DIMS, shape: TENSOR_DIMS};

// constant1 is a constant MLOperand with the value 0.5.
const constantBuffer1 = new Float32Array(TENSOR_SIZE).fill(0.5);
Expand Down
15 changes: 8 additions & 7 deletions common/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ export async function buildConstantByNpy(builder, url, targetType = 'float32') {
if (!dataTypeMap.has(npArray.dataType)) {
throw new Error(`Data type ${npArray.dataType} is not supported.`);
}
const dimensions = npArray.shape;
const shape = npArray.shape;
let type = dataTypeMap.get(npArray.dataType).type;
const TypedArrayConstructor = dataTypeMap.get(npArray.dataType).array;
const dataView = new Uint8Array(npArray.data.buffer);
Expand All @@ -121,7 +121,8 @@ export async function buildConstantByNpy(builder, url, targetType = 'float32') {
throw new Error(`Conversion from ${npArray.dataType} ` +
`to ${targetType} is not supported.`);
}
return builder.constant({dataType: type, dimensions}, typedArray);
return builder.constant(
{dataType: type, dimensions: shape, shape}, typedArray);
}

// Convert video frame to a canvas element
Expand Down Expand Up @@ -162,7 +163,7 @@ export function stopCameraStream(id, stream) {
* input element.
* inputOptions = {
* inputLayout {String}, // input layout of tensor.
* inputDimensions: {!Array<number>}, // dimensions of input tensor.
* inputShape: {!Array<number>}, // shape of input tensor.
* mean: {Array<number>}, // optional, mean values for processing the input
* element. If not specified, it will be set to [0, 0, 0, 0].
* std: {Array<number>}, // optional, std values for processing the input
Expand Down Expand Up @@ -190,16 +191,16 @@ export function stopCameraStream(id, stream) {
* @return {Object} tensor, an object of input tensor.
*/
export function getInputTensor(inputElement, inputOptions) {
const inputDimensions = inputOptions.inputDimensions;
const inputShape = inputOptions.inputShape;
const tensor = new Float32Array(
inputDimensions.slice(1).reduce((a, b) => a * b));
inputShape.slice(1).reduce((a, b) => a * b));

inputElement.width = inputElement.videoWidth ||
inputElement.naturalWidth;
inputElement.height = inputElement.videoHeight ||
inputElement.naturalHeight;

let [channels, height, width] = inputDimensions.slice(1);
let [channels, height, width] = inputShape.slice(1);
const mean = inputOptions.mean || [0, 0, 0, 0];
const std = inputOptions.std || [1, 1, 1, 1];
const normlizationFlag = inputOptions.norm || false;
Expand All @@ -209,7 +210,7 @@ export function getInputTensor(inputElement, inputOptions) {
const imageChannels = 4; // RGBA
const drawOptions = inputOptions.drawOptions;
if (inputLayout === 'nhwc') {
[height, width, channels] = inputDimensions.slice(1);
[height, width, channels] = inputShape.slice(1);
}
const canvasElement = document.createElement('canvas');
canvasElement.width = width;
Expand Down
5 changes: 3 additions & 2 deletions face_recognition/facenet_nchw.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ export class FaceNetNchw {
std: [127.5, 127.5, 127.5, 127.5],
channelScheme: 'BGR',
inputLayout: 'nchw',
inputDimensions: [1, 3, 160, 160],
inputShape: [1, 3, 160, 160],
};
this.postOptions = {
distanceMetric: 'euclidean',
Expand Down Expand Up @@ -140,7 +140,8 @@ export class FaceNetNchw {
this.builder_ = new MLGraphBuilder(this.context_);
const input = this.builder_.input('input', {
dataType: 'float32',
dimensions: this.inputOptions.inputDimensions,
dimensions: this.inputOptions.inputShape,
shape: this.inputOptions.inputShape,
});

const poolOptions = {windowDimensions: [3, 3], strides};
Expand Down
5 changes: 3 additions & 2 deletions face_recognition/facenet_nhwc.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ export class FaceNetNhwc {
std: [127.5, 127.5, 127.5, 127.5],
channelScheme: 'BGR',
inputLayout: 'nhwc',
inputDimensions: [1, 160, 160, 3],
inputShape: [1, 160, 160, 3],
};
this.postOptions = {
distanceMetric: 'euclidean',
Expand Down Expand Up @@ -141,7 +141,8 @@ export class FaceNetNhwc {
this.builder_ = new MLGraphBuilder(this.context_);
const input = this.builder_.input('input', {
dataType: 'float32',
dimensions: this.inputOptions.inputDimensions,
dimensions: this.inputOptions.inputShape,
shape: this.inputOptions.inputShape,
});

const poolOptions = {windowDimensions: [3, 3], strides, layout: 'nhwc'};
Expand Down
4 changes: 2 additions & 2 deletions face_recognition/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -375,9 +375,9 @@ async function main() {
console.log('- Computing... ');
// Do warm up
const fdResults = await fdInstance.compute(new Float32Array(
utils.sizeOfShape(fdInputOptions.inputDimensions)), fdOutputs);
utils.sizeOfShape(fdInputOptions.inputShape)), fdOutputs);
const frResults = await frInstance.compute(new Float32Array(
utils.sizeOfShape(frInputOptions.inputDimensions)), frOutputs);
utils.sizeOfShape(frInputOptions.inputShape)), frOutputs);
fdOutputs = fdResults.outputs;
frOutputs = frResults.outputs;
for (let i = 0; i < numRuns; i++) {
Expand Down
5 changes: 3 additions & 2 deletions facial_landmark_detection/face_landmark_nchw.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export class FaceLandmarkNchw {
'/test-data/models/face_landmark_nchw/weights';
this.inputOptions = {
inputLayout: 'nchw',
inputDimensions: [1, 3, 128, 128],
inputShape: [1, 3, 128, 128],
};
}

Expand Down Expand Up @@ -71,7 +71,8 @@ export class FaceLandmarkNchw {
this.builder_ = new MLGraphBuilder(this.context_);
const input = this.builder_.input('input', {
dataType: 'float32',
dimensions: this.inputOptions.inputDimensions,
dimensions: this.inputOptions.inputShape,
shape: this.inputOptions.inputShape,
});

const poolOptions =
Expand Down
5 changes: 3 additions & 2 deletions facial_landmark_detection/face_landmark_nhwc.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export class FaceLandmarkNhwc {
'/test-data/models/face_landmark_nhwc/weights';
this.inputOptions = {
inputLayout: 'nhwc',
inputDimensions: [1, 128, 128, 3],
inputShape: [1, 128, 128, 3],
};
}

Expand Down Expand Up @@ -72,7 +72,8 @@ export class FaceLandmarkNhwc {
this.builder_ = new MLGraphBuilder(this.context_);
const input = this.builder_.input('input', {
dataType: 'float32',
dimensions: this.inputOptions.inputDimensions,
dimensions: this.inputOptions.inputShape,
shape: this.inputOptions.inputShape,
});

const poolOptions =
Expand Down
4 changes: 2 additions & 2 deletions facial_landmark_detection/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -312,9 +312,9 @@ async function main() {
console.log('- Computing... ');
// Do warm up
const fdResults = await fdInstance.compute(new Float32Array(
utils.sizeOfShape(fdInputOptions.inputDimensions)), fdOutputs);
utils.sizeOfShape(fdInputOptions.inputShape)), fdOutputs);
const fldResults = await fldInstance.compute(new Float32Array(
utils.sizeOfShape(fldInputOptions.inputDimensions)), fldOutputs);
utils.sizeOfShape(fldInputOptions.inputShape)), fldOutputs);
fdOutputs = fdResults.outputs;
fldOutputs = fldResults.outputs;
for (let i = 0; i < numRuns; i++) {
Expand Down
5 changes: 3 additions & 2 deletions facial_landmark_detection/ssd_mobilenetv2_face_nchw.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ export class SsdMobilenetV2FaceNchw {
boxSize: 4,
numClasses: 2,
numBoxes: [1083, 600, 150, 54, 24, 6],
inputDimensions: [1, 3, 300, 300],
inputShape: [1, 3, 300, 300],
};
this.outputsInfo = {
'biasAdd0': [1, 12, 19, 19],
Expand Down Expand Up @@ -115,7 +115,8 @@ ${nameArray[1]}`;
this.builder_ = new MLGraphBuilder(this.context_);
const input = this.builder_.input('input', {
dataType: 'float32',
dimensions: this.inputOptions.inputDimensions,
dimensions: this.inputOptions.inputShape,
shape: this.inputOptions.inputShape,
});

const bottleneck0 = this.buildLinearBottleneck_(
Expand Down
5 changes: 3 additions & 2 deletions facial_landmark_detection/ssd_mobilenetv2_face_nhwc.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ export class SsdMobilenetV2FaceNhwc {
boxSize: 4,
numClasses: 2,
numBoxes: [1083, 600, 150, 54, 24, 6],
inputDimensions: [1, 300, 300, 3],
inputShape: [1, 300, 300, 3],
};
this.outputsInfo = {
'biasAdd0': [1, 19, 19, 12],
Expand Down Expand Up @@ -127,7 +127,8 @@ ${nameArray[1]}`;
this.builder_ = new MLGraphBuilder(this.context_);
const input = this.builder_.input('input', {
dataType: 'float32',
dimensions: this.inputOptions.inputDimensions,
dimensions: this.inputOptions.inputShape,
shape: this.inputOptions.inputShape,
});

const bottleneck0 = this.buildLinearBottleneck_(
Expand Down
7 changes: 4 additions & 3 deletions image_classification/efficientnet_fp16_nchw.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@ export class EfficientNetFP16Nchw {
norm: true,
inputLayout: 'nchw',
labelUrl: './labels/labels1000.txt',
inputDimensions: [1, 3, 224, 224],
inputShape: [1, 3, 224, 224],
};
this.outputDimensions = [1, 1000];
this.outputShape = [1, 1000];
}

async buildConv_(input, name, blockName, clip = false, options = {}) {
Expand Down Expand Up @@ -77,7 +77,8 @@ export class EfficientNetFP16Nchw {
this.builder_ = new MLGraphBuilder(this.context_);
let data = this.builder_.input('input', {
dataType: 'float32',
dimensions: this.inputOptions.inputDimensions,
dimensions: this.inputOptions.inputShape,
shape: this.inputOptions.inputShape,
});
data = this.builder_.cast(data, 'float16');
// Block 0
Expand Down
2 changes: 1 addition & 1 deletion image_classification/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -335,7 +335,7 @@ async function main() {
inputOptions = netInstance.inputOptions;
labels = await fetchLabels(inputOptions.labelUrl);
outputBuffer =
new Float32Array(utils.sizeOfShape(netInstance.outputDimensions));
new Float32Array(utils.sizeOfShape(netInstance.outputShape));
isFirstTimeLoad = false;
console.log(`- Model name: ${modelName}, Model layout: ${layout} -`);
// UI shows model loading progress
Expand Down
7 changes: 4 additions & 3 deletions image_classification/mobilenet_nchw.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,9 @@ export class MobileNetV2Nchw {
norm: true,
inputLayout: 'nchw',
labelUrl: './labels/labels1000.txt',
inputDimensions: [1, 3, 224, 224],
inputShape: [1, 3, 224, 224],
};
this.outputDimensions = [1, 1000];
this.outputShape = [1, 1000];
}

async buildConv_(input, name, relu6 = true, options = {}) {
Expand Down Expand Up @@ -91,7 +91,8 @@ export class MobileNetV2Nchw {
this.builder_ = new MLGraphBuilder(this.context_);
let data = this.builder_.input('input', {
dataType: 'float32',
dimensions: this.inputOptions.inputDimensions,
dimensions: this.inputOptions.inputShape,
shape: this.inputOptions.inputShape,
});
if (this.dataType_ === 'float16') {
data = this.builder_.cast(data, 'float16');
Expand Down
7 changes: 4 additions & 3 deletions image_classification/mobilenet_nhwc.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@ export class MobileNetV2Nhwc {
std: [127.5, 127.5, 127.5],
inputLayout: 'nhwc',
labelUrl: './labels/labels1001.txt',
inputDimensions: [1, 224, 224, 3],
inputShape: [1, 224, 224, 3],
};
this.outputDimensions = [1, 1001];
this.outputShape = [1, 1001];
}

async buildConv_(input, weightsSubName, biasSubName, relu6, options) {
Expand Down Expand Up @@ -89,7 +89,8 @@ export class MobileNetV2Nhwc {
const filterLayout = 'ohwi';
const input = this.builder_.input('input', {
dataType: 'float32',
dimensions: this.inputOptions.inputDimensions,
dimensions: this.inputOptions.inputShape,
shape: this.inputOptions.inputShape,
});
const conv0 = this.buildConv_(
input, '90', 'Conv_Conv2D', true, {strides, autoPad, filterLayout});
Expand Down
7 changes: 4 additions & 3 deletions image_classification/resnet50v1_fp16_nchw.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@ export class ResNet50V1FP16Nchw {
norm: true,
inputLayout: 'nchw',
labelUrl: './labels/labels1000.txt',
inputDimensions: [1, 3, 224, 224],
inputShape: [1, 3, 224, 224],
};
this.outputDimensions = [1, 1000];
this.outputShape = [1, 1000];
}

async buildConv_(input, name, stageName, relu, options = undefined) {
Expand Down Expand Up @@ -78,7 +78,8 @@ export class ResNet50V1FP16Nchw {
this.builder_ = new MLGraphBuilder(this.context_);
let data = this.builder_.input('input', {
dataType: 'float32',
dimensions: this.inputOptions.inputDimensions,
dimensions: this.inputOptions.inputShape,
shape: this.inputOptions.inputShape,
});
data = this.builder_.cast(data, 'float16');
const conv1 = await this.buildConv_(
Expand Down
7 changes: 4 additions & 3 deletions image_classification/resnet50v2_nchw.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@ export class ResNet50V2Nchw {
norm: true,
inputLayout: 'nchw',
labelUrl: './labels/labels1000.txt',
inputDimensions: [1, 3, 224, 224],
inputShape: [1, 3, 224, 224],
};
this.outputDimensions = [1, 1000];
this.outputShape = [1, 1000];
}

async buildConv_(input, name, stageName, options = undefined) {
Expand Down Expand Up @@ -100,7 +100,8 @@ export class ResNet50V2Nchw {
this.builder_ = new MLGraphBuilder(this.context_);
const data = this.builder_.input('input', {
dataType: 'float32',
dimensions: this.inputOptions.inputDimensions,
dimensions: this.inputOptions.inputShape,
shape: this.inputOptions.inputShape,
});
const bn1 = this.buildBatchNorm_(data, '0', '', false);
const conv0 = this.buildConv_(
Expand Down
7 changes: 4 additions & 3 deletions image_classification/resnet50v2_nhwc.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@ export class ResNet50V2Nhwc {
std: [127.5, 127.5, 127.5],
inputLayout: layout,
labelUrl: './labels/labels1001.txt',
inputDimensions: [1, 224, 224, 3],
inputShape: [1, 224, 224, 3],
};
this.outputDimensions = [1, 1001];
this.outputShape = [1, 1001];
}

async buildConv_(input, nameIndices, options = {}, relu = true) {
Expand Down Expand Up @@ -122,7 +122,8 @@ export class ResNet50V2Nhwc {
this.builder_ = new MLGraphBuilder(this.context_);
const input = this.builder_.input('input', {
dataType: 'float32',
dimensions: this.inputOptions.inputDimensions,
dimensions: this.inputOptions.inputShape,
shape: this.inputOptions.inputShape,
});
const conv1 = await this.buildConv_(
input, ['', '', '1'], {strides, padding: [3, 3, 3, 3]}, false);
Expand Down
7 changes: 4 additions & 3 deletions image_classification/squeezenet_nchw.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@ export class SqueezeNetNchw {
norm: true,
inputLayout: 'nchw',
labelUrl: './labels/labels1000.txt',
inputDimensions: [1, 3, 224, 224],
inputShape: [1, 3, 224, 224],
};
this.outputDimensions = [1, 1000];
this.outputShape = [1, 1000];
}

async buildConv_(input, name, options = {}) {
Expand All @@ -45,7 +45,8 @@ export class SqueezeNetNchw {
this.builder_ = new MLGraphBuilder(this.context_);
const data = this.builder_.input('input', {
dataType: 'float32',
dimensions: this.inputOptions.inputDimensions,
dimensions: this.inputOptions.inputShape,
shape: this.inputOptions.inputShape,
});
const conv0 = this.buildConv_(data, 'conv0', {strides: [2, 2]});
const pool0 = this.builder_.maxPool2d(
Expand Down
Loading

0 comments on commit 229c4e2

Please sign in to comment.