@@ -392,6 +392,208 @@ def test_div_precision(self):
392
392
self .assertEqual (len (output_dims ), 1 )
393
393
self .assertEqual (output_dims [0 ].dim_value , 512 )
394
394
395
+ def test_quantize_linear (self ):
396
+ """
397
+ Test ONNX QuantizeLinear op.
398
+ Check that the output shape is propagated from the first input and that the output data
399
+ type comes from the zero-point input.
400
+ """
401
+ initializers = [
402
+ helper .make_tensor (
403
+ "scale" ,
404
+ TensorProto .FLOAT ,
405
+ [],
406
+ [1.0 ],
407
+ ),
408
+ helper .make_tensor (
409
+ "zero_point" ,
410
+ TensorProto .INT8 ,
411
+ [],
412
+ [16 ],
413
+ ),
414
+ ]
415
+
416
+ nodes = [
417
+ helper .make_node (
418
+ "QuantizeLinear" ,
419
+ inputs = [
420
+ "input_f32" ,
421
+ "scale" ,
422
+ "zero_point" ,
423
+ ],
424
+ outputs = ["output_s8" ],
425
+ ),
426
+ ]
427
+
428
+ inputs = [
429
+ helper .make_tensor_value_info ("input_f32" , TensorProto .FLOAT , ["b" , 2 , 3 , 4 ]),
430
+ ]
431
+
432
+ outputs = [
433
+ helper .make_tensor_value_info ("output_s8" , TensorProto .UNDEFINED , None ),
434
+ ]
435
+
436
+ graph = helper .make_graph (nodes , "QuantizeLinear_Test" , inputs , outputs , initializers )
437
+ model = helper .make_model (graph )
438
+
439
+ inferred = SymbolicShapeInference .infer_shapes (model , auto_merge = True )
440
+
441
+ expected_shapes = [
442
+ helper .make_tensor_value_info ("output_s8" , TensorProto .INT8 , ["b" , 2 , 3 , 4 ]),
443
+ ]
444
+ self ._check_shapes (graph , inferred .graph , expected_shapes )
445
+
446
+ def test_quantize_linear_ms_domain (self ):
447
+ """
448
+ Test QuantizeLinear op ('com.microsoft' domain).
449
+ Check that the output shape is propagated from the first input and that the output data
450
+ type comes from the zero-point input.
451
+ """
452
+ initializers = [
453
+ helper .make_tensor (
454
+ "scale" ,
455
+ TensorProto .FLOAT ,
456
+ [],
457
+ [1.0 ],
458
+ ),
459
+ helper .make_tensor (
460
+ "zero_point" ,
461
+ TensorProto .UINT16 ,
462
+ [],
463
+ [16 ],
464
+ ),
465
+ ]
466
+
467
+ nodes = [
468
+ helper .make_node (
469
+ "QuantizeLinear" ,
470
+ inputs = [
471
+ "input_f32" ,
472
+ "scale" ,
473
+ "zero_point" ,
474
+ ],
475
+ outputs = ["output_u16" ],
476
+ domain = "com.microsoft" ,
477
+ ),
478
+ ]
479
+
480
+ inputs = [
481
+ helper .make_tensor_value_info ("input_f32" , TensorProto .FLOAT , ["b" , 2 , 3 , 4 ]),
482
+ ]
483
+
484
+ outputs = [
485
+ helper .make_tensor_value_info ("output_u16" , TensorProto .UNDEFINED , None ),
486
+ ]
487
+
488
+ graph = helper .make_graph (nodes , "QuantizeLinear_MSDomain_Test" , inputs , outputs , initializers )
489
+ model = helper .make_model (graph )
490
+
491
+ inferred = SymbolicShapeInference .infer_shapes (model , auto_merge = True )
492
+
493
+ expected_shapes = [
494
+ helper .make_tensor_value_info ("output_u16" , TensorProto .UINT16 , ["b" , 2 , 3 , 4 ]),
495
+ ]
496
+ self ._check_shapes (graph , inferred .graph , expected_shapes )
497
+
498
+ def test_quantize_linear_no_zp_input (self ):
499
+ """
500
+ Test QuantizeLinear op ('com.microsoft' domain).
501
+ Check that the output shape is propagated from the first input.
502
+ The zero-point input is missing, so the output data type should default to uint8.
503
+ """
504
+ initializers = [
505
+ helper .make_tensor (
506
+ "scale" ,
507
+ TensorProto .FLOAT ,
508
+ [],
509
+ [1.0 ],
510
+ ),
511
+ ]
512
+
513
+ nodes = [
514
+ helper .make_node (
515
+ "QuantizeLinear" ,
516
+ inputs = [
517
+ "input_f32" ,
518
+ "scale" ,
519
+ ],
520
+ outputs = ["output_u8" ],
521
+ domain = "com.microsoft" ,
522
+ ),
523
+ ]
524
+
525
+ inputs = [
526
+ helper .make_tensor_value_info ("input_f32" , TensorProto .FLOAT , ["b" , 2 , 3 , 4 ]),
527
+ ]
528
+
529
+ outputs = [
530
+ helper .make_tensor_value_info ("output_u8" , TensorProto .UNDEFINED , None ),
531
+ ]
532
+
533
+ graph = helper .make_graph (nodes , "QuantizeLinear_NoZP_Test" , inputs , outputs , initializers )
534
+ model = helper .make_model (graph )
535
+
536
+ inferred = SymbolicShapeInference .infer_shapes (model , auto_merge = True )
537
+
538
+ # Check that the output shape is propagated from the first input and that the
539
+ # output data type comes from the zero-point input.
540
+ expected_shapes = [
541
+ helper .make_tensor_value_info ("output_u8" , TensorProto .UINT8 , ["b" , 2 , 3 , 4 ]),
542
+ ]
543
+ self ._check_shapes (graph , inferred .graph , expected_shapes )
544
+
545
+ def test_dequantize_linear_ms_domain (self ):
546
+ """
547
+ Test DequantizeLinear operator ('com.microsoft' domain).
548
+ Check that the output shape is propagated from the first input and that the output data
549
+ type comes from the scale input.
550
+ """
551
+ initializers = [
552
+ helper .make_tensor (
553
+ "scale" ,
554
+ TensorProto .FLOAT ,
555
+ [],
556
+ [1.0 ],
557
+ ),
558
+ helper .make_tensor (
559
+ "zero_point" ,
560
+ TensorProto .UINT16 ,
561
+ [],
562
+ [16 ],
563
+ ),
564
+ ]
565
+
566
+ nodes = [
567
+ helper .make_node (
568
+ "DequantizeLinear" ,
569
+ inputs = [
570
+ "input_u16" ,
571
+ "scale" ,
572
+ "zero_point" ,
573
+ ],
574
+ outputs = ["output_f32" ],
575
+ domain = "com.microsoft" ,
576
+ ),
577
+ ]
578
+
579
+ inputs = [
580
+ helper .make_tensor_value_info ("input_u16" , TensorProto .UINT16 , ["b" , 2 , 3 , 4 ]),
581
+ ]
582
+
583
+ outputs = [
584
+ helper .make_tensor_value_info ("output_f32" , TensorProto .UNDEFINED , None ),
585
+ ]
586
+
587
+ graph = helper .make_graph (nodes , "DequantizeLinear_MSDomain_Test" , inputs , outputs , initializers )
588
+ model = helper .make_model (graph )
589
+
590
+ inferred = SymbolicShapeInference .infer_shapes (model , auto_merge = True )
591
+
592
+ expected_shapes = [
593
+ helper .make_tensor_value_info ("output_f32" , TensorProto .FLOAT , ["b" , 2 , 3 , 4 ]),
594
+ ]
595
+ self ._check_shapes (graph , inferred .graph , expected_shapes )
596
+
395
597
396
598
class TestSymbolicShapeInferenceForSlice (unittest .TestCase ):
397
599
def check_slice_of_concat (self , input_dims , start , end , step , expected_output_dim ):
0 commit comments