// META: title=validation tests for WebNN API pooling operation // META: global=window // META: variant=?cpu // META: variant=?gpu // META: variant=?npu // META: script=../resources/utils_validation.js 'use strict'; const kPoolingOperators = ['averagePool2d', 'l2Pool2d', 'maxPool2d']; kPoolingOperators.forEach((operatorName) => { validateInputFromAnotherBuilder( operatorName, {dataType: 'float32', shape: [2, 2, 2, 2]}); }); const label = 'pool_2d_xxx'; const tests = [ { name: 'Test pool2d with default options.', input: {dataType: 'float32', shape: [1, 3, 4, 4]}, output: {dataType: 'float32', shape: [1, 3, 1, 1]} }, { name: 'Test pool2d with windowDimensions', input: {dataType: 'float16', shape: [1, 3, 4, 4]}, options: { windowDimensions: [3, 3], }, output: {dataType: 'float16', shape: [1, 3, 2, 2]} }, { name: 'Test pool2d with padding.', input: {dataType: 'float32', shape: [1, 3, 5, 5]}, options: { windowDimensions: [5, 5], padding: [2, 2, 2, 2], }, output: {dataType: 'float32', shape: [1, 3, 5, 5]} }, { name: 'Test pool2d with strides.', input: {dataType: 'float16', shape: [1, 3, 5, 5]}, options: { windowDimensions: [2, 2], strides: [2, 2], }, output: {dataType: 'float16', shape: [1, 3, 2, 2]} }, { name: 'Test pool2d with strides and padding.', input: {dataType: 'float32', shape: [1, 3, 5, 5]}, options: { windowDimensions: [3, 3], padding: [1, 1, 1, 1], strides: [2, 2], }, output: {dataType: 'float32', shape: [1, 3, 3, 3]} }, { name: 'Test pool2d with strides and asymmetric padding.', input: {dataType: 'float32', shape: [1, 3, 7, 7]}, options: { windowDimensions: [4, 4], padding: [2, 1, 2, 1], strides: [2, 2], }, output: {dataType: 'float32', shape: [1, 3, 4, 4]} }, { name: 'Test pool2d with strides, padding and roundingType="floor".', input: {dataType: 'float32', shape: [1, 3, 7, 7]}, options: { windowDimensions: [4, 4], padding: [1, 1, 1, 1], strides: [2, 2], roundingType: 'floor', }, output: {dataType: 'float32', shape: [1, 3, 3, 3]} }, { name: 'Test pool2d with strides, padding and roundingType="ceil".', input: {dataType: 'float16', shape: [1, 3, 7, 7]}, options: { windowDimensions: [4, 4], padding: [1, 1, 1, 1], strides: [2, 2], roundingType: 'ceil', }, output: {dataType: 'float16', shape: [1, 3, 4, 4]} }, { name: 'Test pool2d with explicit outputSizes ignored roundingType', input: {dataType: 'float32', shape: [1, 3, 7, 7]}, options: { windowDimensions: [4, 4], padding: [1, 1, 1, 1], strides: [2, 2], roundingType: 'ceil', outputSizes: [3, 3], }, output: {dataType: 'float32', shape: [1, 3, 3, 3]} }, { name: 'Test pool2d with strides, padding and outputSizes=[3, 3].', input: {dataType: 'float32', shape: [1, 3, 7, 7]}, options: { windowDimensions: [4, 4], padding: [1, 1, 1, 1], strides: [2, 2], outputSizes: [3, 3], }, output: {dataType: 'float32', shape: [1, 3, 3, 3]} }, { name: 'Test pool2d with strides, padding and outputSizes=[4, 4].', input: {dataType: 'float32', shape: [1, 3, 7, 7]}, options: { windowDimensions: [4, 4], padding: [1, 1, 1, 1], strides: [2, 2], outputSizes: [4, 4], }, output: {dataType: 'float32', shape: [1, 3, 4, 4]} }, { name: 'Test pool2d with layout="nchw".', input: {dataType: 'float32', shape: [1, 2, 5, 5]}, options: { windowDimensions: [3, 3], layout: 'nchw', }, output: {dataType: 'float32', shape: [1, 2, 3, 3]} }, { name: 'Test pool2d with layout="nhwc".', input: {dataType: 'float16', shape: [1, 5, 5, 2]}, options: { windowDimensions: [3, 3], layout: 'nhwc', }, output: {dataType: 'float16', shape: [1, 3, 3, 2]} }, { name: 'Throw if the input is not a 4-D tensor.', input: {dataType: 'float32', shape: [1, 5, 5]}, options: {label}, }, { name: 'Throw if the output sizes is incorrect.', input: {dataType: 'float32', shape: [1, 2, 5, 5]}, options: { windowDimensions: [2, 2], padding: [2, 2, 2, 2], strides: [2, 2], outputSizes: [3, 3], label: label, }, }, { name: 'Throw if the length of output sizes is not 2.', input: {dataType: 'float32', shape: [1, 2, 5, 5]}, options: { windowDimensions: [2, 2], padding: [2, 2, 2, 2], strides: [2, 2], outputSizes: [1, 2, 4, 4], label: label, }, }, { name: 'Throw if outputSizes[0] is not greater than 0.', input: {dataType: 'float32', shape: [1, 2, 5, 5]}, options: { windowDimensions: [2, 2], padding: [2, 2, 2, 2], strides: [2, 2], outputSizes: [0, 4], label: label, }, }, { name: 'Throw if outputSizes[1] is not greater than 0.', input: {dataType: 'float32', shape: [1, 2, 5, 5]}, options: { windowDimensions: [2, 2], padding: [2, 2, 2, 2], strides: [2, 2], outputSizes: [4, 0], label: label, }, }, { name: 'Throw if the length of window dimensions is not 2.', input: {dataType: 'float32', shape: [1, 2, 5, 5]}, options: { windowDimensions: [1, 1, 1, 1], label: label, }, }, { name: 'Throw if any window dimension is lesser than 1.', input: {dataType: 'float32', shape: [1, 2, 5, 5]}, options: { windowDimensions: [0, 2], label: label, }, }, { name: 'Throw if the input height is too small to fill the pool window height.', input: {dataType: 'float32', shape: [1, 2, 5, 5]}, options: { windowDimensions: [8, 2], label: label, }, }, { name: 'Throw if the input width is too small to fill the pool window width.', input: {dataType: 'float32', shape: [1, 2, 5, 5]}, options: { windowDimensions: [2, 8], label: label, }, }, { name: 'Throw if the calculated output height is equal to 0.', input: {dataType: 'float32', shape: [1, 2, 5, 5]}, options: { windowDimensions: [6, 3], label: label, }, }, { name: 'Throw if the calculated output width is equal to 0.', input: {dataType: 'float32', shape: [1, 2, 5, 5]}, options: { windowDimensions: [3, 6], label: label, }, }, { name: 'Throw if the length of padding is not 4.', input: {dataType: 'float32', shape: [1, 2, 5, 5]}, options: { padding: [2, 2], label: label, }, }, { name: 'Throw if the length of strides is not 2.', input: {dataType: 'float32', shape: [1, 2, 5, 5]}, options: { strides: [2], label: label, }, }, { name: 'Throw if one stride value is smaller than 1.', input: {dataType: 'float32', shape: [1, 2, 5, 5]}, options: { strides: [0, 2], label: label, }, }, { name: 'Throw if the length of dilations is not 2.', input: {dataType: 'float32', shape: [1, 2, 5, 5]}, options: { dilations: [1, 1, 2], label: label, }, }, { name: 'Throw if one dilation value is smaller than 1.', input: {dataType: 'float32', shape: [1, 2, 5, 5]}, options: { dilations: [1, 0], label: label, }, }, { name: 'Throw if the padding height value is too large', input: {dataType: 'float32', shape: [1, 3, 5, 5]}, options: { padding: [kMaxUnsignedLong, kMaxUnsignedLong, 0, 0], label: label, }, }, { name: 'Throw if the padding width value is too large', input: {dataType: 'float32', shape: [1, 3, 5, 5]}, options: { padding: [0, 0, kMaxUnsignedLong, kMaxUnsignedLong], label: label, }, }, ]; tests.forEach( test => promise_test(async t => { const builder = new MLGraphBuilder(context); const input = builder.input('input', test.input); kPoolingOperators.forEach((operatorName) => { if (test.output) { const output = builder[operatorName](input, test.options); assert_equals(output.dataType, test.output.dataType); assert_array_equals(output.shape, test.output.shape); } else { const regrexp = new RegExp('\\[' + label + '\\]'); assert_throws_with_label( () => builder[operatorName](input, test.options), regrexp); } }); }, test.name)); ['int32', 'uint32', 'int8', 'uint8'].forEach( dataType => promise_test(async t => { const builder = new MLGraphBuilder(context); const input = builder.input('input', {dataType, shape: [1, 3, 4, 4]}); const output = builder.maxPool2d(input); assert_equals(output.dataType, dataType); assert_array_equals(output.shape, [1, 3, 1, 1]); }, `[maxPool2d] Test maxPool2d with data type ${dataType}`)); promise_test(async t => { const builder = new MLGraphBuilder(context); const input = builder.input('input', {dataType: 'int64', shape: [1, 2, 3, 3]}); assert_throws_js(TypeError, () => builder.averagePool2d(input)); }, '[averagePool2d] Throw if the input data type is not floating point'); promise_test(async t => { const builder = new MLGraphBuilder(context); const input = builder.input('input', {dataType: 'uint8', shape: [1, 2, 4, 4]}); assert_throws_js(TypeError, () => builder.l2Pool2d(input)); }, '[l2Pool2d] Throw if the input data type is not floating point');