diff --git a/webnn/conformance_tests/gpu/resample2d.https.any.js b/webnn/conformance_tests/gpu/resample2d.https.any.js new file mode 100644 index 00000000000000..dd8e441946e1b5 --- /dev/null +++ b/webnn/conformance_tests/gpu/resample2d.https.any.js @@ -0,0 +1,10 @@ +// META: title=test WebNN API resample2d operation +// META: global=window,dedicatedworker +// META: script=../../resources/utils.js +// META: timeout=long + +'use strict'; + +// https://webmachinelearning.github.io/webnn/#api-mlgraphbuilder-resample2d-method + +testWebNNOperation('resample2d', buildOperationWithSingleInput, 'gpu'); \ No newline at end of file diff --git a/webnn/conformance_tests/resample2d.https.any.js b/webnn/conformance_tests/resample2d.https.any.js new file mode 100644 index 00000000000000..0b5b3e00320299 --- /dev/null +++ b/webnn/conformance_tests/resample2d.https.any.js @@ -0,0 +1,10 @@ +// META: title=test WebNN API resample2d operation +// META: global=window,dedicatedworker +// META: script=../resources/utils.js +// META: timeout=long + +'use strict'; + +// https://webmachinelearning.github.io/webnn/#api-mlgraphbuilder-resample2d-method + +testWebNNOperation('resample2d', buildOperationWithSingleInput); \ No newline at end of file diff --git a/webnn/resources/test_data/resample2d.json b/webnn/resources/test_data/resample2d.json new file mode 100644 index 00000000000000..605d1b55c017a5 --- /dev/null +++ b/webnn/resources/test_data/resample2d.json @@ -0,0 +1,527 @@ +{ + "tests": [ + { + "name": "resample2d float32 4D tensor default options", + "inputs": { + "input": { + "shape": [1, 1, 4, 6], // nchw + "data": [ + 3.8600528355143604, + 45.18463077286585, + 87.67153742917091, + 98.78210347338205, + 66.3741434682883, + 3.4115834948988955, + 86.14930500548006, + 95.98133720121507, + 76.87126314100948, + 16.52591355131756, + 65.98782867250333, + 25.470921564461158, + 22.56010547750855, + 92.08479613461083, + 85.80876634651386, + 92.6316602716033, + 29.91620870840146, + 75.40461275485572, + 62.063754512670435, + 1.7712158798243394, + 99.47231285272224, + 11.440550135595085, + 25.39634271166711, + 67.02175102425608 + ], + "type": "float32" + } + }, + "expected": { + "shape": [1, 1, 4, 6], + "data": [ + 3.8600528240203857, + 45.18463134765625, + 87.67153930664062, + 98.7821044921875, + 66.3741455078125, + 3.411583423614502, + 86.14930725097656, + 95.98133850097656, + 76.87126159667969, + 16.52591323852539, + 65.98783111572266, + 25.470922470092773, + 22.56010627746582, + 92.08479309082031, + 85.80876922607422, + 92.63166046142578, + 29.916208267211914, + 75.40460968017578, + 62.06375503540039, + 1.7712159156799316, + 99.4723129272461, + 11.440549850463867, + 25.396343231201172, + 67.0217514038086 + ], + "type": "float32" + } + }, + { + "name": "resample2d(upsample) float32 4D tensor options.scales", + "inputs": { + "input": { + "shape": [1, 1, 2, 3], + "data": [ + 59.92947164849423, + 41.989187594696546, + 66.39534663077877, + 90.70066412516924, + 86.95106056135486, + 79.10004839481242 + ], + "type": "float32" + } + }, + "options": { + "scales": [2.0, 2.0] + }, + "expected": { + "shape": [1, 1, 4, 6], + "data": [ + 59.92947006225586, + 59.92947006225586, + 41.98918914794922, + 41.98918914794922, + 66.39534759521484, + 66.39534759521484, + 59.92947006225586, + 59.92947006225586, + 41.98918914794922, + 41.98918914794922, + 66.39534759521484, + 66.39534759521484, + 90.7006607055664, + 90.7006607055664, + 86.95105743408203, + 86.95105743408203, + 79.10005187988281, + 79.10005187988281, + 90.7006607055664, + 90.7006607055664, + 86.95105743408203, + 86.95105743408203, + 79.10005187988281, + 79.10005187988281 + ], + "type": "float32" + } + }, + { + "name": "resample2d(upsample) float32 4D tensor options.sizes", + "inputs": { + "input": { + "shape": [1, 1, 2, 3], + "data": [ + 59.92947164849423, + 41.989187594696546, + 66.39534663077877, + 90.70066412516924, + 86.95106056135486, + 79.10004839481242 + ], + "type": "float32" + } + }, + "options": { + "sizes": [4, 6] + }, + "expected": { + "shape": [1, 1, 4, 6], + "data": [ + 59.92947006225586, + 59.92947006225586, + 41.98918914794922, + 41.98918914794922, + 66.39534759521484, + 66.39534759521484, + 59.92947006225586, + 59.92947006225586, + 41.98918914794922, + 41.98918914794922, + 66.39534759521484, + 66.39534759521484, + 90.7006607055664, + 90.7006607055664, + 86.95105743408203, + 86.95105743408203, + 79.10005187988281, + 79.10005187988281, + 90.7006607055664, + 90.7006607055664, + 86.95105743408203, + 86.95105743408203, + 79.10005187988281, + 79.10005187988281 + ], + "type": "float32" + } + }, + { + "name": "resample2d(upsample) float32 4D tensor options.sizes ignored options.scales", + "inputs": { + "input": { + "shape": [1, 1, 2, 3], + "data": [ + 59.92947164849423, + 41.989187594696546, + 66.39534663077877, + 90.70066412516924, + 86.95106056135486, + 79.10004839481242 + ], + "type": "float32" + } + }, + "options": { + "scales": [0.5, 0.5], + "sizes": [4, 6] + }, + "expected": { + "shape": [1, 1, 4, 6], + "data": [ + 59.92947006225586, + 59.92947006225586, + 41.98918914794922, + 41.98918914794922, + 66.39534759521484, + 66.39534759521484, + 59.92947006225586, + 59.92947006225586, + 41.98918914794922, + 41.98918914794922, + 66.39534759521484, + 66.39534759521484, + 90.7006607055664, + 90.7006607055664, + 86.95105743408203, + 86.95105743408203, + 79.10005187988281, + 79.10005187988281, + 90.7006607055664, + 90.7006607055664, + 86.95105743408203, + 86.95105743408203, + 79.10005187988281, + 79.10005187988281 + ], + "type": "float32" + } + }, + { + "name": "resample2d(upsample) float32 4D tensor options.axes=[1, 2]", + "inputs": { + "input": { + "shape": [1, 2, 3, 1], // nhwc + "data": [ + 59.92947164849423, + 41.989187594696546, + 66.39534663077877, + 90.70066412516924, + 86.95106056135486, + 79.10004839481242 + ], + "type": "float32" + } + }, + "options": { + "sizes": [4, 6], + "axes": [1, 2] + }, + "expected": { + "shape": [1, 4, 6, 1], + "data": [ + 59.92947006225586, + 59.92947006225586, + 41.98918914794922, + 41.98918914794922, + 66.39534759521484, + 66.39534759521484, + 59.92947006225586, + 59.92947006225586, + 41.98918914794922, + 41.98918914794922, + 66.39534759521484, + 66.39534759521484, + 90.7006607055664, + 90.7006607055664, + 86.95105743408203, + 86.95105743408203, + 79.10005187988281, + 79.10005187988281, + 90.7006607055664, + 90.7006607055664, + 86.95105743408203, + 86.95105743408203, + 79.10005187988281, + 79.10005187988281 + ], + "type": "float32" + } + }, + { + "name": "resample2d(upsample) float32 4D tensor explicit options.axes=[2, 3]", + "inputs": { + "input": { + "shape": [1, 1, 2, 3], // nchw + "data": [ + 59.92947164849423, + 41.989187594696546, + 66.39534663077877, + 90.70066412516924, + 86.95106056135486, + 79.10004839481242 + ], + "type": "float32" + } + }, + "options": { + "sizes": [4, 6], + "axes": [2, 3] + }, + "expected": { + "shape": [1, 1, 4, 6], + "data": [ + 59.92947006225586, + 59.92947006225586, + 41.98918914794922, + 41.98918914794922, + 66.39534759521484, + 66.39534759521484, + 59.92947006225586, + 59.92947006225586, + 41.98918914794922, + 41.98918914794922, + 66.39534759521484, + 66.39534759521484, + 90.7006607055664, + 90.7006607055664, + 86.95105743408203, + 86.95105743408203, + 79.10005187988281, + 79.10005187988281, + 90.7006607055664, + 90.7006607055664, + 86.95105743408203, + 86.95105743408203, + 79.10005187988281, + 79.10005187988281 + ], + "type": "float32" + } + }, + { + "name": "resample2d(upsample) float32 4D tensor explicit options.mode='nearest-neighbor'", + "inputs": { + "input": { + "shape": [1, 1, 2, 3], + "data": [ + 59.92947164849423, + 41.989187594696546, + 66.39534663077877, + 90.70066412516924, + 86.95106056135486, + 79.10004839481242 + ], + "type": "float32" + } + }, + "options": { + "mode": "nearest-neighbor", + "sizes": [4, 6] + }, + "expected": { + "shape": [1, 1, 4, 6], + "data": [ + 59.92947006225586, + 59.92947006225586, + 41.98918914794922, + 41.98918914794922, + 66.39534759521484, + 66.39534759521484, + 59.92947006225586, + 59.92947006225586, + 41.98918914794922, + 41.98918914794922, + 66.39534759521484, + 66.39534759521484, + 90.7006607055664, + 90.7006607055664, + 86.95105743408203, + 86.95105743408203, + 79.10005187988281, + 79.10005187988281, + 90.7006607055664, + 90.7006607055664, + 86.95105743408203, + 86.95105743408203, + 79.10005187988281, + 79.10005187988281 + ], + "type": "float32" + } + }, + { + "name": "resample2d(upsample) float32 4D tensor options.scales options.mode='linear'", + "inputs": { + "input": { + "shape": [1, 1, 2, 3], + "data": [ + 59.92947164849423, + 41.989187594696546, + 66.39534663077877, + 90.70066412516924, + 86.95106056135486, + 79.10004839481242 + ], + "type": "float32" + } + }, + "options": { + "mode": "linear", + "scales": [2.0, 2.0] + }, + "expected": { + "shape": [1, 1, 4, 6], + "data": [ + 59.92947006225586, + 55.444400787353516, + 46.47425842285156, + 48.090728759765625, + 60.29380798339844, + 66.39534759521484, + 67.62226867675781, + 64.02411651611328, + 56.82780838012695, + 57.31512451171875, + 65.48605346679688, + 69.57152557373047, + 83.00786590576172, + 81.18354797363281, + 77.534912109375, + 75.76390838623047, + 75.87055206298828, + 75.92387390136719, + 90.7006607055664, + 89.76325988769531, + 87.88845825195312, + 84.9883041381836, + 81.06280517578125, + 79.10005187988281 + ], + "type": "float32" + } + }, + { + "name": "resample2d(upsample) float32 4D tensor options.sizes options.mode='linear'", + "inputs": { + "input": { + "shape": [1, 1, 2, 3], + "data": [ + 59.92947164849423, + 41.989187594696546, + 66.39534663077877, + 90.70066412516924, + 86.95106056135486, + 79.10004839481242 + ], + "type": "float32" + } + }, + "options": { + "mode": "linear", + "sizes": [4, 6] + }, + "expected": { + "shape": [1, 1, 4, 6], + "data": [ + 59.92947006225586, + 55.444400787353516, + 46.47425842285156, + 48.090728759765625, + 60.29380798339844, + 66.39534759521484, + 67.62226867675781, + 64.02411651611328, + 56.82780838012695, + 57.31512451171875, + 65.48605346679688, + 69.57152557373047, + 83.00786590576172, + 81.18354797363281, + 77.534912109375, + 75.76390838623047, + 75.87055206298828, + 75.92387390136719, + 90.7006607055664, + 89.76325988769531, + 87.88845825195312, + 84.9883041381836, + 81.06280517578125, + 79.10005187988281 + ], + "type": "float32" + } + }, + { + "name": "resample2d(upsample) float32 4D tensor options.axes=[1, 2] options.mode='linear'", + "inputs": { + "input": { + "shape": [1, 2, 3, 1], + "data": [ + 59.92947164849423, + 41.989187594696546, + 66.39534663077877, + 90.70066412516924, + 86.95106056135486, + 79.10004839481242 + ], + "type": "float32" + } + }, + "options": { + "mode": "linear", + "sizes": [4, 6], + "axes": [1, 2] + }, + "expected": { + "shape": [1, 4, 6, 1], + "data": [ + 59.92947006225586, + 55.444400787353516, + 46.47425842285156, + 48.090728759765625, + 60.29380798339844, + 66.39534759521484, + 67.62226867675781, + 64.02411651611328, + 56.82780838012695, + 57.31512451171875, + 65.48605346679688, + 69.57152557373047, + 83.00786590576172, + 81.18354797363281, + 77.534912109375, + 75.76390838623047, + 75.87055206298828, + 75.92387390136719, + 90.7006607055664, + 89.76325988769531, + 87.88845825195312, + 84.9883041381836, + 81.06280517578125, + 79.10005187988281 + ], + "type": "float32" + } + } + ] +} \ No newline at end of file diff --git a/webnn/resources/utils.js b/webnn/resources/utils.js index 0e404dbcd07e4b..375c71174a8d11 100644 --- a/webnn/resources/utils.js +++ b/webnn/resources/utils.js @@ -282,6 +282,32 @@ const getReductionPrecisionTolerance = (resources, operationName) => { return tolerance; }; +/** + * Get ULP tolerance of resample2d operations. + * @param {Object} resources - Resources used for building a graph + * @param {String} operationName - An operation name + * @returns {Number} A tolerance number + */ +const getResample2dPrecisionTolerance = (resources, operationName) => { + const options = {...resources.options}; + let tolerance; + if (options.mode && options.mode === 'linear') { + // interpolation mode is linear + const precisionType = resources.expected.type; + if (precisionType === 'float32') { + tolerance = 84; + } else if (precisionType === 'float16') { + tolerance = 10; + } else { + tolerance = 1; + } + } else { + // interpolation mode is nearest-neighbor + tolerance = 0; + } + return tolerance; +}; + // Refer to precision metrics on https://github.com/webmachinelearning/webnn/issues/265#issuecomment-1256242643 const PrecisionMetrics = { argMax: {ULP: {int64: 0}}, @@ -356,6 +382,7 @@ const PrecisionMetrics = { reduceSumSquare: {ULP: {float32: getReductionPrecisionTolerance, float16: getReductionPrecisionTolerance}}, // End Reduction operations relu: {ULP: {float32: 0, float16: 0}}, + resample2d: {ULP: {float32: getResample2dPrecisionTolerance, float16: getResample2dPrecisionTolerance}}, reshape: {ULP: {float32: 0, float16: 0}}, sigmoid: {ULP: {float32: 32+2, float16: 3}}, // float32 (leaving a few ULP for roundoff) slice: {ULP: {float32: 0, float16: 0}},