resample2d.https.any.js (8309B)
1 // META: title=validation tests for WebNN API resample2d operation 2 // META: global=window 3 // META: variant=?cpu 4 // META: variant=?gpu 5 // META: variant=?npu 6 // META: script=../resources/utils_validation.js 7 8 'use strict'; 9 10 const label = 'resample-2d'; 11 const regrexp = new RegExp('\\[' + label + '\\]'); 12 // Tests for resample2d(input, options) 13 const tests = [ 14 { 15 name: '[resample2d] Test building resample2d with default options', 16 input: {dataType: 'float32', shape: [1, 1, 2, 4]}, 17 output: {dataType: 'float32', shape: [1, 1, 2, 4]}, 18 }, 19 { 20 name: '[resample2d] Test building resample2d with scales=[2.0, 2.0]', 21 input: {dataType: 'float32', shape: [1, 1, 2, 4]}, 22 options: {scales: [2.0, 2.0]}, 23 output: {dataType: 'float32', shape: [1, 1, 4, 8]}, 24 }, 25 { 26 name: '[resample2d] Test building resample2d with scales=[0.5, 0.5]', 27 input: {dataType: 'float32', shape: [1, 1, 5, 5]}, 28 options: {scales: [0.5, 0.5]}, 29 output: {dataType: 'float32', shape: [1, 1, 2, 2]}, 30 }, 31 { 32 name: 33 '[resample2d] Test building resample2d with scales=[0.5, 0.5] and explicit axes=[2, 3]', 34 input: {dataType: 'float32', shape: [1, 1, 5, 5]}, 35 options: {scales: [0.5, 0.5], axes: [2, 3]}, 36 output: {dataType: 'float32', shape: [1, 1, 2, 2]}, 37 }, 38 { 39 name: 40 '[resample2d] Test building resample2d with scales=[1.0, 2.0] and axes=[0, 1]', 41 input: {dataType: 'float32', shape: [1, 1, 2, 4]}, 42 options: {scales: [1.0, 2.0], axes: [0, 1]}, 43 output: {dataType: 'float32', shape: [1, 2, 2, 4]}, 44 }, 45 { 46 name: 47 '[resample2d] Test building resample2d with scales=[2.0, 2.0] and axes=[1, 2]', 48 input: {dataType: 'float32', shape: [1, 1, 2, 4]}, 49 options: {scales: [2.0, 2.0], axes: [1, 2]}, 50 output: {dataType: 'float32', shape: [1, 2, 4, 4]}, 51 }, 52 { 53 name: 54 '[resample2d] Test building resample2d with sizes=[3, 6] ignored scales', 55 input: {dataType: 'float32', shape: [1, 1, 2, 4]}, 56 options: {scales: [2.0, 2.0], sizes: [3, 6]}, 57 output: {dataType: 'float32', shape: [1, 1, 3, 6]}, 58 }, 59 { 60 name: 61 '[resample2d] Test building resample2d with non consecutive axes=[0,2]', 62 input: {dataType: 'float32', shape: [1, 1, 2, 4]}, 63 options: { 64 axes: [0, 2], 65 label: label, 66 }, 67 output: {dataType: 'float32', shape: [1, 1, 2, 4]}, 68 }, 69 { 70 name: 71 '[resample2d] Throw if the dataType of input is not float32 or float16', 72 input: {dataType: 'int32', shape: [2, 4]}, 73 options: {label}, 74 }, 75 { 76 name: '[resample2d] Throw if the rank of input is not 4', 77 input: {dataType: 'float32', shape: [2, 4]}, 78 options: {label}, 79 }, 80 { 81 name: '[resample2d] Throw if the length of scales is not 2', 82 input: {dataType: 'float32', shape: [1, 1, 2, 4]}, 83 options: { 84 scales: [1.0, 1.0, 2.0, 2.0], 85 label: label, 86 }, 87 }, 88 { 89 name: '[resample2d] Throw if any scale value is negative', 90 input: {dataType: 'float32', shape: [1, 1, 2, 4]}, 91 options: { 92 scales: [1.0, -2.0], 93 label: label, 94 }, 95 }, 96 { 97 name: '[resample2d] Throw if any scale value is 0', 98 input: {dataType: 'float32', shape: [1, 1, 2, 4]}, 99 options: { 100 scales: [0, 2.0], 101 label: label, 102 }, 103 }, 104 { 105 name: '[resample2d] Throw if the length of sizes is not 2', 106 input: {dataType: 'float32', shape: [1, 1, 2, 4]}, 107 options: { 108 sizes: [1, 1, 4, 6], 109 label: label, 110 }, 111 }, 112 { 113 name: '[resample2d] Throw if sizes[0] is not a valid dimension', 114 input: {dataType: 'float32', shape: [1, 1, 2, 4]}, 115 options: { 116 sizes: [0, 1], 117 label: label, 118 }, 119 }, 120 { 121 name: '[resample2d] Throw if sizes[1] is not a valid dimension', 122 input: {dataType: 'float32', shape: [1, 1, 2, 4]}, 123 options: { 124 sizes: [1, 0], 125 label: label, 126 }, 127 }, 128 { 129 name: 130 '[resample2d] Throw if any size value is out of \'unsigned long\' value range', 131 input: {dataType: 'float32', shape: [1, 1, 2, 4]}, 132 options: {sizes: [kMaxUnsignedLong + 1, kMaxUnsignedLong + 1]}, 133 }, 134 { 135 name: 136 '[resample2d] Throw if outputHeight being floor(scaleHeight*inputHeight) is too large', 137 input: {dataType: 'float32', shape: [1, 1, 2, 4]}, 138 // The maximum dimension size is kMaxUnsignedLong (2 ** 32 - 1). 139 // Here scaleHeight=kMaxUnsignedLong and inputHeight=2, 140 // so outputHeight being kMaxUnsignedLong*2 > kMaxUnsignedLong . 141 options: {scales: /*[scaleHeight, scaleWidth]*/[kMaxUnsignedLong, 1]}, 142 }, 143 { 144 name: '[resample2d] Throw if scaleHeight is too small', 145 input: {dataType: 'float32', shape: [1, 1, 2, 4]}, 146 // Here scaleHeight=0.02 and inputHeight=2, 147 // so outputHeight would be 0. 148 // Link to https://github.com/webmachinelearning/webnn/issues/391. 149 options: { 150 scales: /*[scaleHeight, scaleWidth]*/[0.02, 0.8], 151 label: label, 152 }, 153 }, 154 { 155 name: 156 '[resample2d] Throw if outputWidth being floor(scaleWidth*inputWidth) is too large', 157 input: {dataType: 'float32', shape: [1, 1, 4, 2]}, 158 // The maximum dimension size is kMaxUnsignedLong (2 ** 32 - 1). 159 // Here scaleWidth=kMaxUnsignedLong and inputWidth=2, 160 // so outputWidth being kMaxUnsignedLong*2 > kMaxUnsignedLong . 161 options: {scales: /*[scaleHeight, scaleWidth]*/[1, kMaxUnsignedLong]}, 162 }, 163 { 164 name: '[resample2d] Throw if scaleWidth is too small', 165 input: {dataType: 'float32', shape: [1, 1, 2, 4]}, 166 // Here scaleWidth=0.1 and inputWidth=4, 167 // so outputWidth would be 0. 168 // Link to https://github.com/webmachinelearning/webnn/issues/391. 169 options: { 170 scales: /*[scaleHeight, scaleWidth]*/[0.7, 0.1], 171 label: label, 172 }, 173 }, 174 { 175 name: '[resample2d] Throw if the length of axes is not 2', 176 input: {dataType: 'float32', shape: [1, 1, 2, 4]}, 177 options: { 178 axes: [0, 1, 2], 179 label: label, 180 }, 181 }, 182 { 183 name: 184 '[resample2d] Throw if any axis value is greater than or equal to the input rank', 185 input: {dataType: 'float32', shape: [1, 1, 2, 4]}, 186 options: { 187 axes: [3, 4], 188 label: label, 189 }, 190 }, 191 { 192 name: '[resample2d] Throw if the values of axes are same', 193 input: {dataType: 'float32', shape: [1, 1, 2, 4]}, 194 options: { 195 axes: [0, 0], 196 label: label, 197 }, 198 }, 199 ]; 200 201 tests.forEach( 202 test => promise_test(async t => { 203 const builder = new MLGraphBuilder(context); 204 const input = builder.input('input', test.input); 205 const options = test.options ?? {}; 206 if (test.output) { 207 const output = builder.resample2d(input, options); 208 assert_equals(output.dataType, test.output.dataType); 209 assert_array_equals(output.shape, test.output.shape); 210 } else { 211 const options = {...test.options}; 212 if (options.label) { 213 assert_throws_with_label( 214 () => builder.resample2d(input, options), regrexp); 215 } else { 216 assert_throws_js(TypeError, () => builder.resample2d(input, options)); 217 } 218 } 219 }, test.name)); 220 221 validateInputFromAnotherBuilder( 222 'resample2d', {dataType: 'float32', shape: [2, 2, 2, 2]}); 223 224 promise_test(async t => { 225 for (let dataType of allWebNNOperandDataTypes) { 226 if (!context.opSupportLimits().input.dataTypes.includes(dataType)) { 227 continue; 228 } 229 const builder = new MLGraphBuilder(context); 230 const shape = [1, 1, 2, 4]; 231 const input = builder.input(`input`, {dataType, shape}); 232 if (context.opSupportLimits().resample2d.input.dataTypes.includes( 233 dataType)) { 234 const output = builder.resample2d(input); 235 assert_equals(output.dataType, dataType); 236 assert_array_equals(output.shape, shape); 237 } else { 238 assert_throws_js(TypeError, () => builder.resample2d(input)); 239 } 240 } 241 }, `[resample2d] Test resample2d with all of the data types.`); 242 243 promise_test(async t => { 244 const builder = new MLGraphBuilder(context); 245 246 const input = builder.input('input', { 247 dataType: 'float32', 248 shape: [1, 1, context.opSupportLimits().maxTensorByteLength / 4, 1]}); 249 250 const options = {}; 251 options.scales = [2.0, 2.0]; 252 options.label = label; 253 assert_throws_with_label( 254 () => builder.resample2d(input, options), regrexp); 255 }, '[resample2d] throw if the output tensor byte length exceeds limit');