convTranspose2d.https.any.js (18328B)
1 // META: title=validation tests for WebNN API convTranspose2d 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 // Example input in NCHW layout. 11 const kExampleInputDescriptor = { 12 dataType: 'float32', 13 shape: [1, 1, 5, 5] 14 }; 15 // Example filter in OIHW layout. 16 const kExampleFilterDescriptor = { 17 dataType: 'float32', 18 shape: [1, 1, 3, 3] 19 }; 20 const kExampleBiasDescriptor = { 21 dataType: 'float32', 22 shape: [/* output channels */ 1] 23 }; 24 25 multi_builder_test(async (t, builder, otherBuilder) => { 26 const inputFromOtherBuilder = 27 otherBuilder.input('input', kExampleInputDescriptor); 28 29 const filter = builder.input('filter', kExampleFilterDescriptor); 30 assert_throws_js( 31 TypeError, () => builder.convTranspose2d(inputFromOtherBuilder, filter)); 32 }, '[convTranspose2d] throw if input is from another builder'); 33 34 multi_builder_test(async (t, builder, otherBuilder) => { 35 const filterFromOtherBuilder = 36 otherBuilder.input('filter', kExampleFilterDescriptor); 37 38 const input = builder.input('input', kExampleInputDescriptor); 39 assert_throws_js( 40 TypeError, () => builder.convTranspose2d(input, filterFromOtherBuilder)); 41 }, '[convTranspose2d] throw if filter is from another builder'); 42 43 multi_builder_test(async (t, builder, otherBuilder) => { 44 const biasFromOtherBuilder = 45 otherBuilder.input('bias', kExampleBiasDescriptor); 46 const options = {inputLayout: 'nchw', bias: biasFromOtherBuilder}; 47 48 const input = builder.input('input', kExampleInputDescriptor); 49 const filter = builder.input('filter', kExampleFilterDescriptor); 50 assert_throws_js( 51 TypeError, () => builder.convTranspose2d(input, filter, options)); 52 }, '[convTranspose2d] throw if bias option is from another builder'); 53 54 const label = 'conv_transpose_2d'; 55 const tests = [ 56 { 57 name: '[convTranspose2d] Test with default options.', 58 input: {dataType: 'float32', shape: [1, 1, 3, 3]}, 59 filter: {dataType: 'float32', shape: [1, 1, 3, 3]}, 60 output: {dataType: 'float32', shape: [1, 1, 5, 5]} 61 }, 62 { 63 name: 64 '[convTranspose2d] Test with inputLayout="nchw" and filterLayout="hwoi".', 65 input: {dataType: 'float32', shape: [1, 1, 3, 3]}, 66 filter: {dataType: 'float32', shape: [3, 3, 2, 1]}, 67 options: { 68 filterLayout: 'hwoi', 69 inputLayout: 'nchw', 70 }, 71 output: {dataType: 'float32', shape: [1, 2, 5, 5]} 72 }, 73 { 74 name: 75 '[convTranspose2d] Test with inputLayout="nchw" and filterLayout="ohwi".', 76 input: {dataType: 'float32', shape: [1, 1, 3, 3]}, 77 filter: {dataType: 'float32', shape: [2, 3, 3, 1]}, 78 options: { 79 filterLayout: 'ohwi', 80 inputLayout: 'nchw', 81 }, 82 output: {dataType: 'float32', shape: [1, 2, 5, 5]} 83 }, 84 { 85 name: 86 '[convTranspose2d] Test with inputLayout="nhwc" and filterLayout="iohw".', 87 input: {dataType: 'float32', shape: [1, 3, 3, 1]}, 88 filter: {dataType: 'float32', shape: [1, 2, 3, 3]}, 89 options: { 90 filterLayout: 'iohw', 91 inputLayout: 'nhwc', 92 }, 93 output: {dataType: 'float32', shape: [1, 5, 5, 2]} 94 }, 95 { 96 name: 97 '[convTranspose2d] Test with inputLayout="nhwc" and filterLayout="hwoi".', 98 input: {dataType: 'float32', shape: [1, 3, 3, 1]}, 99 filter: {dataType: 'float32', shape: [3, 3, 2, 1]}, 100 options: { 101 filterLayout: 'hwoi', 102 inputLayout: 'nhwc', 103 }, 104 output: {dataType: 'float32', shape: [1, 5, 5, 2]} 105 }, 106 { 107 name: 108 '[convTranspose2d] Test with inputLayout="nhwc" and filterLayout="ohwi".', 109 input: {dataType: 'float32', shape: [1, 3, 3, 1]}, 110 filter: {dataType: 'float32', shape: [2, 3, 3, 1]}, 111 options: { 112 filterLayout: 'ohwi', 113 inputLayout: 'nhwc', 114 }, 115 output: {dataType: 'float32', shape: [1, 5, 5, 2]} 116 }, 117 { 118 name: '[convTranspose2d] Test with strides=[3, 2], outputSizes=[10, 8].', 119 input: {dataType: 'float32', shape: [1, 1, 3, 3]}, 120 filter: {dataType: 'float32', shape: [1, 2, 3, 3]}, 121 options: { 122 strides: [3, 2], 123 outputSizes: [10, 8], 124 }, 125 output: {dataType: 'float32', shape: [1, 2, 10, 8]} 126 }, 127 { 128 name: '[convTranspose2d] Test with strides=[3, 2], outputPadding=[1, 1].', 129 input: {dataType: 'float32', shape: [1, 1, 3, 3]}, 130 filter: {dataType: 'float32', shape: [1, 2, 3, 3]}, 131 options: { 132 strides: [3, 2], 133 outputPadding: [1, 1], 134 }, 135 output: {dataType: 'float32', shape: [1, 2, 10, 8]} 136 }, 137 { 138 name: '[convTranspose2d] Test with padding=1.', 139 input: {dataType: 'float32', shape: [1, 1, 5, 5]}, 140 filter: {dataType: 'float32', shape: [1, 1, 3, 3]}, 141 options: { 142 padding: [1, 1, 1, 1], 143 }, 144 output: {dataType: 'float32', shape: [1, 1, 5, 5]} 145 }, 146 { 147 name: '[convTranspose2d] Test with padding=1, groups=3.', 148 input: {dataType: 'float32', shape: [1, 1, 5, 5]}, 149 filter: {dataType: 'float32', shape: [1, 1, 3, 3]}, 150 options: { 151 padding: [1, 1, 1, 1], 152 groups: 3, 153 }, 154 output: {dataType: 'float32', shape: [1, 3, 5, 5]} 155 }, 156 { 157 name: '[convTranspose2d] Test with strides=2.', 158 input: {dataType: 'float32', shape: [1, 1, 3, 3]}, 159 filter: {dataType: 'float32', shape: [1, 2, 3, 3]}, 160 options: { 161 strides: [2, 2], 162 }, 163 output: {dataType: 'float32', shape: [1, 2, 7, 7]} 164 }, 165 { 166 name: '[convTranspose2d] Test with strides=2 and padding=1.', 167 input: {dataType: 'float32', shape: [1, 1, 3, 3]}, 168 filter: {dataType: 'float32', shape: [1, 1, 3, 3]}, 169 options: { 170 padding: [1, 1, 1, 1], 171 strides: [2, 2], 172 }, 173 output: {dataType: 'float32', shape: [1, 1, 5, 5]} 174 }, 175 { 176 name: 177 '[convTranspose2d] Test when the output sizes are explicitly specified, the output padding values are ignored though padding value is not smaller than stride along the same axis.', 178 input: {dataType: 'float32', shape: [1, 1, 3, 3]}, 179 filter: {dataType: 'float32', shape: [1, 2, 3, 3]}, 180 options: { 181 outputPadding: [3, 3], 182 strides: [3, 2], 183 outputSizes: [10, 8], 184 }, 185 output: {dataType: 'float32', shape: [1, 2, 10, 8]} 186 }, 187 { 188 name: '[convTranspose2d] Throw if the input is not a 4-D tensor.', 189 input: {dataType: 'float32', shape: [1, 5, 5]}, 190 filter: {dataType: 'float32', shape: [1, 1, 2, 2]}, 191 options: {label}, 192 }, 193 { 194 name: 195 '[convTranspose2d] Throw if the input data type is not floating point.', 196 input: {dataType: 'int32', shape: [1, 1, 5, 5]}, 197 filter: {dataType: 'int32', shape: [1, 1, 2, 2]}, 198 options: {label}, 199 }, 200 { 201 name: '[convTranspose2d] Throw if the filter is not a 4-D tensor.', 202 input: {dataType: 'float32', shape: [1, 1, 5, 5]}, 203 filter: {dataType: 'float32', shape: [2, 2]}, 204 options: {label}, 205 }, 206 { 207 name: 208 '[convTranspose2d] Throw if the filter data type doesn\'t match the input data type.', 209 input: {dataType: 'float32', shape: [1, 1, 5, 5]}, 210 filter: {dataType: 'int32', shape: [1, 1, 2, 2]}, 211 options: { 212 label: label, 213 }, 214 }, 215 { 216 name: '[convTranspose2d] Throw if the length of padding is not 4.', 217 input: {dataType: 'float32', shape: [1, 1, 5, 5]}, 218 filter: {dataType: 'float32', shape: [1, 1, 2, 2]}, 219 options: { 220 padding: [2, 2], 221 label: label, 222 }, 223 }, 224 { 225 name: '[convTranspose2d] Throw if the length of strides is not 2.', 226 input: {dataType: 'float32', shape: [1, 1, 5, 5]}, 227 filter: {dataType: 'float32', shape: [1, 1, 2, 2]}, 228 options: { 229 strides: [2], 230 label: label, 231 }, 232 }, 233 { 234 name: '[convTranspose2d] Throw if one stride value is smaller than 1.', 235 input: {dataType: 'float32', shape: [1, 1, 5, 5]}, 236 filter: {dataType: 'float32', shape: [1, 1, 2, 2]}, 237 options: { 238 strides: [1, 0], 239 label: label, 240 }, 241 }, 242 { 243 name: '[convTranspose2d] Throw if the length of dilations is not 2.', 244 input: {dataType: 'float32', shape: [1, 1, 5, 5]}, 245 filter: {dataType: 'float32', shape: [1, 1, 2, 2]}, 246 options: { 247 dilations: [1], 248 label: label, 249 }, 250 }, 251 { 252 name: 253 '[convTranspose2d] Throw if the one dilation value is smaller than 1.', 254 input: {dataType: 'float32', shape: [1, 1, 5, 5]}, 255 filter: {dataType: 'float32', shape: [1, 1, 2, 2]}, 256 options: { 257 dilations: [1, 0], 258 label: label, 259 }, 260 }, 261 { 262 name: 263 '[convTranspose2d] Throw if the input channels is not equal to the filter input channels with inputLayout="nchw" and filterLayout="iohw".', 264 input: {dataType: 'float32', shape: [1, 3, 3, 3]}, 265 filter: {dataType: 'float32', shape: [1, 1, 3, 3]}, 266 options: { 267 filterLayout: 'iohw', 268 inputLayout: 'nchw', 269 groups: 1, 270 label: label, 271 }, 272 }, 273 { 274 name: 275 '[convTranspose2d] Throw if the input channels is not equal to the filter input channels with inputLayout="nchw" and filterLayout="hwoi".', 276 input: {dataType: 'float32', shape: [1, 3, 3, 3]}, 277 filter: {dataType: 'float32', shape: [3, 1, 2, 1]}, 278 options: { 279 filterLayout: 'hwoi', 280 inputLayout: 'nchw', 281 label: label, 282 }, 283 }, 284 { 285 name: 286 '[convTranspose2d] Throw if the input channels is not equal to the filter input channels with inputLayout="nchw" and filterLayout="ohwi".', 287 input: {dataType: 'float32', shape: [1, 2, 3, 3]}, 288 filter: {dataType: 'float32', shape: [2, 3, 3, 1]}, 289 options: { 290 filterLayout: 'ohwi', 291 inputLayout: 'nchw', 292 label: label, 293 }, 294 }, 295 { 296 name: 297 '[convTranspose2d] Throw if the input channels is not equal to the filter input channels with inputLayout="nhwc" and filterLayout="iohw".', 298 input: {dataType: 'float32', shape: [1, 3, 3, 2]}, 299 filter: {dataType: 'float32', shape: [1, 2, 3, 3]}, 300 options: { 301 filterLayout: 'iohw', 302 inputLayout: 'nhwc', 303 label: label, 304 }, 305 }, 306 { 307 name: 308 '[convTranspose2d] Throw if the input channels is not equal to the filter input channels inputLayout="nhwc" and filterLayout="hwoi".', 309 input: {dataType: 'float32', shape: [1, 3, 3, 2]}, 310 filter: {dataType: 'float32', shape: [3, 3, 2, 1]}, 311 options: { 312 filterLayout: 'hwoi', 313 inputLayout: 'nhwc', 314 label: label, 315 }, 316 }, 317 { 318 name: 319 '[convTranspose2d] Throw if the input channels is not equal to the filter input channels with inputLayout="nhwc" and filterLayout="ohwi".', 320 input: {dataType: 'float32', shape: [1, 3, 3, 2]}, 321 filter: {dataType: 'float32', shape: [2, 3, 3, 1]}, 322 options: { 323 filterLayout: 'ohwi', 324 inputLayout: 'nhwc', 325 label: label, 326 }, 327 }, 328 { 329 name: '[convTranspose2d] Throw if output channels is too large.', 330 input: {dataType: 'float32', shape: [1, 4, 5, 5]}, 331 filter: {dataType: 'float32', shape: [4, 2, 2, 2]}, 332 options: { 333 groups: kMaxUnsignedLong, 334 label: label, 335 }, 336 }, 337 { 338 name: '[convTranspose2d] Throw if the groups is smaller than 1.', 339 input: {dataType: 'float32', shape: [1, 4, 5, 5]}, 340 filter: {dataType: 'float32', shape: [1, 1, 2, 2]}, 341 options: { 342 groups: 0, 343 label: label, 344 }, 345 }, 346 { 347 name: 348 '[convTranspose2d] Throw due to overflow when calculating the effective filter height.', 349 input: {dataType: 'float32', shape: [1, 1, 5, 5]}, 350 filter: {dataType: 'float32', shape: [1, 1, 434983, 2]}, 351 options: { 352 dilations: [328443, 1], 353 label: label, 354 }, 355 }, 356 { 357 name: 358 '[convTranspose2d] Throw due to overflow when calculating the effective filter width.', 359 input: {dataType: 'float32', shape: [1, 1, 5, 5]}, 360 filter: {dataType: 'float32', shape: [1, 1, 2, 234545]}, 361 options: { 362 dilations: [2, 843452], 363 label: label, 364 }, 365 }, 366 { 367 name: 368 '[convTranspose2d] Throw due to overflow when dilation height is too large.', 369 input: {dataType: 'float32', shape: [1, 1, 5, 5]}, 370 filter: {dataType: 'float32', shape: [1, 1, 3, 2]}, 371 options: { 372 dilations: [kMaxUnsignedLong, 1], 373 label: label, 374 }, 375 }, 376 { 377 name: 378 '[convTranspose2d] Throw due to overflow when dilation width is too large.', 379 input: {dataType: 'float32', shape: [1, 1, 5, 5]}, 380 filter: {dataType: 'float32', shape: [1, 1, 3, 2]}, 381 options: { 382 dilations: [1, kMaxUnsignedLong], 383 label: label, 384 }, 385 }, 386 { 387 name: '[convTranspose2d] Throw if the bias is not a 1-D tensor.', 388 input: {dataType: 'float32', shape: [1, 1, 5, 5]}, 389 filter: {dataType: 'float32', shape: [1, 1, 2, 2]}, 390 options: { 391 bias: {dataType: 'float32', shape: [1, 2]}, 392 label: label, 393 }, 394 }, 395 { 396 name: 397 '[convTranspose2d] Throw if the bias shape is not equal to [output_channels] with filterLayout="iohw".', 398 input: {dataType: 'float32', shape: [1, 1, 5, 5]}, 399 filter: {dataType: 'float32', shape: [1, 1, 2, 2]}, 400 options: { 401 filterLayout: 'iohw', 402 bias: {dataType: 'float32', shape: [2]}, 403 label: label, 404 }, 405 }, 406 { 407 name: 408 '[convTranspose2d] Throw if the bias shape is not equal to [output_channels] with filterLayout="hwoi".', 409 input: {dataType: 'float32', shape: [1, 1, 5, 5]}, 410 filter: {dataType: 'float32', shape: [2, 2, 1, 1]}, 411 options: { 412 filterLayout: 'hwoi', 413 bias: {dataType: 'float32', shape: [2]}, 414 label: label, 415 }, 416 }, 417 { 418 name: 419 '[convTranspose2d] Throw if the bias shape is not equal to [output_channels] with filterLayout="ohwi".', 420 input: {dataType: 'float32', shape: [1, 1, 5, 5]}, 421 filter: {dataType: 'float32', shape: [1, 2, 2, 1]}, 422 options: { 423 filterLayout: 'ohwi', 424 bias: {dataType: 'float32', shape: [2]}, 425 label: label, 426 }, 427 }, 428 { 429 name: 430 '[convTranspose2d] Throw if the bias data type doesn\'t match input data type.', 431 input: {dataType: 'float32', shape: [1, 1, 5, 5]}, 432 filter: {dataType: 'float32', shape: [1, 1, 2, 2]}, 433 options: { 434 bias: {dataType: 'int32', shape: [1]}, 435 label: label, 436 }, 437 }, 438 { 439 name: 440 '[convTranspose2d] Throw if the outputPadding is not a sequence of length 2.', 441 input: {dataType: 'float32', shape: [1, 1, 3, 3]}, 442 filter: {dataType: 'float32', shape: [1, 2, 3, 3]}, 443 options: { 444 strides: [3, 2], 445 outputPadding: [1, 1, 1, 1], 446 label: label, 447 }, 448 }, 449 { 450 name: 451 '[convTranspose2d] Throw if the outputPadding is not smaller than stride along the width dimension.', 452 input: {dataType: 'float32', shape: [1, 1, 2, 2]}, 453 filter: {dataType: 'float32', shape: [1, 1, 3, 3]}, 454 options: { 455 padding: [0, 0, 3, 3], 456 strides: [2, 2], 457 outputPadding: [0, 2], 458 label: label, 459 }, 460 }, 461 { 462 name: 463 '[convTranspose2d] Throw if the outputPadding is not smaller than stride along the height dimension.', 464 input: {dataType: 'float32', shape: [1, 1, 2, 2]}, 465 filter: {dataType: 'float32', shape: [1, 1, 3, 3]}, 466 options: { 467 padding: [0, 0, 3, 3], 468 strides: [2, 2], 469 outputPadding: [2, 0], 470 label: label, 471 }, 472 }, 473 { 474 name: 475 '[convTranspose2d] Throw if the outputSizes is not a sequence of length 2.', 476 input: {dataType: 'float32', shape: [1, 1, 3, 3]}, 477 filter: {dataType: 'float32', shape: [1, 2, 3, 3]}, 478 options: { 479 strides: [3, 2], 480 outputSizes: [1, 2, 10, 8], 481 label: label, 482 }, 483 }, 484 { 485 name: '[convTranspose2d] Throw if outputSizes[0] is not greater than 0.', 486 input: {dataType: 'float32', shape: [1, 1, 3, 3]}, 487 filter: {dataType: 'float32', shape: [1, 2, 3, 3]}, 488 options: { 489 strides: [3, 2], 490 outputSizes: [0, 7], 491 label: label, 492 }, 493 }, 494 { 495 name: '[convTranspose2d] Throw if outputSizes[1] is not greater than 0.', 496 input: {dataType: 'float32', shape: [1, 1, 3, 3]}, 497 filter: {dataType: 'float32', shape: [1, 2, 3, 3]}, 498 options: { 499 strides: [3, 2], 500 outputSizes: [9, 0], 501 label: label, 502 }, 503 }, 504 { 505 name: '[convTranspose2d] Throw if the padding height is too large.', 506 input: {dataType: 'float32', shape: [1, 1, 2, 2]}, 507 filter: {dataType: 'float32', shape: [1, 1, 3, 3]}, 508 options: { 509 padding: [4, 4, 0, 0], 510 strides: [2, 2], 511 outputPadding: [1, 0], 512 label: label, 513 }, 514 }, 515 { 516 name: '[convTranspose2d] Throw if the padding width is too large.', 517 input: {dataType: 'float32', shape: [1, 1, 2, 2]}, 518 filter: {dataType: 'float32', shape: [1, 1, 3, 3]}, 519 options: { 520 padding: [0, 0, 4, 4], 521 strides: [2, 2], 522 outputPadding: [0, 1], 523 label: label, 524 }, 525 }, 526 { 527 name: 528 '[convTranspose2d] Throw due to outputSizes values are smaller than the output sizes calculated by not using outputPadding.', 529 input: {dataType: 'float32', shape: [1, 1, 3, 3]}, 530 filter: {dataType: 'float32', shape: [1, 1, 3, 3]}, 531 options: { 532 padding: [1, 1, 1, 1], 533 strides: [2, 2], 534 outputSizes: [4, 4], 535 outputPadding: [1, 1], 536 label: label, 537 }, 538 }, 539 { 540 name: 541 '[convTranspose2d] Throw due to outputSizes values are greater than the output sizes calculated by not using outputPadding.', 542 input: {dataType: 'float32', shape: [1, 1, 3, 3]}, 543 filter: {dataType: 'float32', shape: [1, 1, 3, 3]}, 544 options: { 545 padding: [1, 1, 1, 1], 546 strides: [2, 2], 547 outputSizes: [6, 8], 548 outputPadding: [1, 1], 549 label: label, 550 }, 551 }, 552 ]; 553 554 tests.forEach( 555 test => promise_test(async t => { 556 const builder = new MLGraphBuilder(context); 557 const input = builder.input('input', test.input); 558 const filter = builder.input('filter', test.filter); 559 560 if (test.options && test.options.bias) { 561 test.options.bias = builder.input('bias', test.options.bias); 562 } 563 564 if (test.output && 565 context.opSupportLimits().convTranspose2d.input.dataTypes.includes( 566 test.input.dataType)) { 567 const output = builder.convTranspose2d(input, filter, test.options); 568 assert_equals(output.dataType, test.output.dataType); 569 assert_array_equals(output.shape, test.output.shape); 570 } else { 571 const regrexp = new RegExp('\\[' + label + '\\]'); 572 assert_throws_with_label( 573 () => builder.convTranspose2d(input, filter, test.options), 574 regrexp); 575 } 576 }, test.name));