pooling.https.any.js (9631B)
1 // META: title=validation tests for WebNN API pooling 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 kPoolingOperators = ['averagePool2d', 'l2Pool2d', 'maxPool2d']; 11 12 kPoolingOperators.forEach((operatorName) => { 13 validateInputFromAnotherBuilder( 14 operatorName, {dataType: 'float32', shape: [2, 2, 2, 2]}); 15 }); 16 17 const label = 'pool_2d_xxx'; 18 const tests = [ 19 { 20 name: 'Test pool2d with default options.', 21 input: {dataType: 'float32', shape: [1, 3, 4, 4]}, 22 output: {dataType: 'float32', shape: [1, 3, 1, 1]} 23 }, 24 { 25 name: 'Test pool2d with windowDimensions', 26 input: {dataType: 'float16', shape: [1, 3, 4, 4]}, 27 options: { 28 windowDimensions: [3, 3], 29 }, 30 output: {dataType: 'float16', shape: [1, 3, 2, 2]} 31 }, 32 { 33 name: 'Test pool2d with padding.', 34 input: {dataType: 'float32', shape: [1, 3, 5, 5]}, 35 options: { 36 windowDimensions: [5, 5], 37 padding: [2, 2, 2, 2], 38 }, 39 output: {dataType: 'float32', shape: [1, 3, 5, 5]} 40 }, 41 { 42 name: 'Test pool2d with strides.', 43 input: {dataType: 'float16', shape: [1, 3, 5, 5]}, 44 options: { 45 windowDimensions: [2, 2], 46 strides: [2, 2], 47 }, 48 output: {dataType: 'float16', shape: [1, 3, 2, 2]} 49 }, 50 { 51 name: 'Test pool2d with strides and padding.', 52 input: {dataType: 'float32', shape: [1, 3, 5, 5]}, 53 options: { 54 windowDimensions: [3, 3], 55 padding: [1, 1, 1, 1], 56 strides: [2, 2], 57 }, 58 output: {dataType: 'float32', shape: [1, 3, 3, 3]} 59 }, 60 { 61 name: 'Test pool2d with strides and asymmetric padding.', 62 input: {dataType: 'float32', shape: [1, 3, 7, 7]}, 63 options: { 64 windowDimensions: [4, 4], 65 padding: [2, 1, 2, 1], 66 strides: [2, 2], 67 }, 68 output: {dataType: 'float32', shape: [1, 3, 4, 4]} 69 }, 70 { 71 name: 'Test pool2d with strides, padding and roundingType="floor".', 72 input: {dataType: 'float32', shape: [1, 3, 7, 7]}, 73 options: { 74 windowDimensions: [4, 4], 75 padding: [1, 1, 1, 1], 76 strides: [2, 2], 77 roundingType: 'floor', 78 }, 79 output: {dataType: 'float32', shape: [1, 3, 3, 3]} 80 }, 81 { 82 name: 'Test pool2d with strides, padding and roundingType="ceil".', 83 input: {dataType: 'float16', shape: [1, 3, 7, 7]}, 84 options: { 85 windowDimensions: [4, 4], 86 padding: [1, 1, 1, 1], 87 strides: [2, 2], 88 roundingType: 'ceil', 89 }, 90 output: {dataType: 'float16', shape: [1, 3, 4, 4]} 91 }, 92 { 93 name: 'Test pool2d with explicit outputSizes ignored roundingType', 94 input: {dataType: 'float32', shape: [1, 3, 7, 7]}, 95 options: { 96 windowDimensions: [4, 4], 97 padding: [1, 1, 1, 1], 98 strides: [2, 2], 99 roundingType: 'ceil', 100 outputSizes: [3, 3], 101 }, 102 output: {dataType: 'float32', shape: [1, 3, 3, 3]} 103 }, 104 { 105 name: 'Test pool2d with strides, padding and outputSizes=[3, 3].', 106 input: {dataType: 'float32', shape: [1, 3, 7, 7]}, 107 options: { 108 windowDimensions: [4, 4], 109 padding: [1, 1, 1, 1], 110 strides: [2, 2], 111 outputSizes: [3, 3], 112 }, 113 output: {dataType: 'float32', shape: [1, 3, 3, 3]} 114 }, 115 { 116 name: 'Test pool2d with strides, padding and outputSizes=[4, 4].', 117 input: {dataType: 'float32', shape: [1, 3, 7, 7]}, 118 options: { 119 windowDimensions: [4, 4], 120 padding: [1, 1, 1, 1], 121 strides: [2, 2], 122 outputSizes: [4, 4], 123 }, 124 output: {dataType: 'float32', shape: [1, 3, 4, 4]} 125 }, 126 { 127 name: 'Test pool2d with layout="nchw".', 128 input: {dataType: 'float32', shape: [1, 2, 5, 5]}, 129 options: { 130 windowDimensions: [3, 3], 131 layout: 'nchw', 132 }, 133 output: {dataType: 'float32', shape: [1, 2, 3, 3]} 134 }, 135 { 136 name: 'Test pool2d with layout="nhwc".', 137 input: {dataType: 'float16', shape: [1, 5, 5, 2]}, 138 options: { 139 windowDimensions: [3, 3], 140 layout: 'nhwc', 141 }, 142 output: {dataType: 'float16', shape: [1, 3, 3, 2]} 143 }, 144 { 145 name: 'Throw if the input is not a 4-D tensor.', 146 input: {dataType: 'float32', shape: [1, 5, 5]}, 147 options: {label}, 148 }, 149 { 150 name: 'Throw if the output sizes is incorrect.', 151 input: {dataType: 'float32', shape: [1, 2, 5, 5]}, 152 options: { 153 windowDimensions: [2, 2], 154 padding: [2, 2, 2, 2], 155 strides: [2, 2], 156 outputSizes: [3, 3], 157 label: label, 158 }, 159 }, 160 { 161 name: 'Throw if the length of output sizes is not 2.', 162 input: {dataType: 'float32', shape: [1, 2, 5, 5]}, 163 options: { 164 windowDimensions: [2, 2], 165 padding: [2, 2, 2, 2], 166 strides: [2, 2], 167 outputSizes: [1, 2, 4, 4], 168 label: label, 169 }, 170 }, 171 { 172 name: 'Throw if outputSizes[0] is not greater than 0.', 173 input: {dataType: 'float32', shape: [1, 2, 5, 5]}, 174 options: { 175 windowDimensions: [2, 2], 176 padding: [2, 2, 2, 2], 177 strides: [2, 2], 178 outputSizes: [0, 4], 179 label: label, 180 }, 181 }, 182 { 183 name: 'Throw if outputSizes[1] is not greater than 0.', 184 input: {dataType: 'float32', shape: [1, 2, 5, 5]}, 185 options: { 186 windowDimensions: [2, 2], 187 padding: [2, 2, 2, 2], 188 strides: [2, 2], 189 outputSizes: [4, 0], 190 label: label, 191 }, 192 }, 193 { 194 name: 'Throw if the length of window dimensions is not 2.', 195 input: {dataType: 'float32', shape: [1, 2, 5, 5]}, 196 options: { 197 windowDimensions: [1, 1, 1, 1], 198 label: label, 199 }, 200 }, 201 { 202 name: 'Throw if any window dimension is lesser than 1.', 203 input: {dataType: 'float32', shape: [1, 2, 5, 5]}, 204 options: { 205 windowDimensions: [0, 2], 206 label: label, 207 }, 208 }, 209 { 210 name: 211 'Throw if the input height is too small to fill the pool window height.', 212 input: {dataType: 'float32', shape: [1, 2, 5, 5]}, 213 options: { 214 windowDimensions: [8, 2], 215 label: label, 216 }, 217 }, 218 { 219 name: 220 'Throw if the input width is too small to fill the pool window width.', 221 input: {dataType: 'float32', shape: [1, 2, 5, 5]}, 222 options: { 223 windowDimensions: [2, 8], 224 label: label, 225 }, 226 }, 227 { 228 name: 'Throw if the calculated output height is equal to 0.', 229 input: {dataType: 'float32', shape: [1, 2, 5, 5]}, 230 options: { 231 windowDimensions: [6, 3], 232 label: label, 233 }, 234 }, 235 { 236 name: 'Throw if the calculated output width is equal to 0.', 237 input: {dataType: 'float32', shape: [1, 2, 5, 5]}, 238 options: { 239 windowDimensions: [3, 6], 240 label: label, 241 }, 242 }, 243 { 244 name: 'Throw if the length of padding is not 4.', 245 input: {dataType: 'float32', shape: [1, 2, 5, 5]}, 246 options: { 247 padding: [2, 2], 248 label: label, 249 }, 250 }, 251 { 252 name: 'Throw if the length of strides is not 2.', 253 input: {dataType: 'float32', shape: [1, 2, 5, 5]}, 254 options: { 255 strides: [2], 256 label: label, 257 }, 258 }, 259 { 260 name: 'Throw if one stride value is smaller than 1.', 261 input: {dataType: 'float32', shape: [1, 2, 5, 5]}, 262 options: { 263 strides: [0, 2], 264 label: label, 265 }, 266 }, 267 { 268 name: 'Throw if the length of dilations is not 2.', 269 input: {dataType: 'float32', shape: [1, 2, 5, 5]}, 270 options: { 271 dilations: [1, 1, 2], 272 label: label, 273 }, 274 }, 275 { 276 name: 'Throw if one dilation value is smaller than 1.', 277 input: {dataType: 'float32', shape: [1, 2, 5, 5]}, 278 options: { 279 dilations: [1, 0], 280 label: label, 281 }, 282 }, 283 { 284 name: 'Throw if the padding height value is too large', 285 input: {dataType: 'float32', shape: [1, 3, 5, 5]}, 286 options: { 287 padding: [kMaxUnsignedLong, kMaxUnsignedLong, 0, 0], 288 label: label, 289 }, 290 }, 291 { 292 name: 'Throw if the padding width value is too large', 293 input: {dataType: 'float32', shape: [1, 3, 5, 5]}, 294 options: { 295 padding: [0, 0, kMaxUnsignedLong, kMaxUnsignedLong], 296 label: label, 297 }, 298 }, 299 ]; 300 301 tests.forEach( 302 test => promise_test(async t => { 303 const builder = new MLGraphBuilder(context); 304 const input = builder.input('input', test.input); 305 kPoolingOperators.forEach((operatorName) => { 306 if (test.output) { 307 const output = builder[operatorName](input, test.options); 308 assert_equals(output.dataType, test.output.dataType); 309 assert_array_equals(output.shape, test.output.shape); 310 } else { 311 const regrexp = new RegExp('\\[' + label + '\\]'); 312 assert_throws_with_label( 313 () => builder[operatorName](input, test.options), regrexp); 314 } 315 }); 316 }, test.name)); 317 318 ['int32', 'uint32', 'int8', 'uint8'].forEach( 319 dataType => promise_test(async t => { 320 const builder = new MLGraphBuilder(context); 321 const input = builder.input('input', {dataType, shape: [1, 3, 4, 4]}); 322 const output = builder.maxPool2d(input); 323 assert_equals(output.dataType, dataType); 324 assert_array_equals(output.shape, [1, 3, 1, 1]); 325 }, `[maxPool2d] Test maxPool2d with data type ${dataType}`)); 326 327 promise_test(async t => { 328 const builder = new MLGraphBuilder(context); 329 const input = 330 builder.input('input', {dataType: 'int64', shape: [1, 2, 3, 3]}); 331 assert_throws_js(TypeError, () => builder.averagePool2d(input)); 332 }, '[averagePool2d] Throw if the input data type is not floating point'); 333 334 promise_test(async t => { 335 const builder = new MLGraphBuilder(context); 336 const input = 337 builder.input('input', {dataType: 'uint8', shape: [1, 2, 4, 4]}); 338 assert_throws_js(TypeError, () => builder.l2Pool2d(input)); 339 }, '[l2Pool2d] Throw if the input data type is not floating point');