@@ -793,5 +793,212 @@ def func(x):
793793 return tf .identity (y [0 ], name = "output" )
794794 self .run_test_case (func , {"input:0" : x_val }, [], ["output:0" ], rtol = 1e-05 , atol = 1e-06 )
795795
796+ @check_tf_min_version ("2.0" )
797+ @skip_tf_versions ("2.1" , "Bug in TF 2.1" )
798+ def test_keras_masked_lstm_embedding_unidirectional (self ):
799+ for go_backwards in [True , False ]:
800+ for return_sequences in [True , False ]:
801+ timesteps = 4
802+ # Note: masked LSTM only support post-padded input after conversion
803+ # test case sequence_lens = [4, 2, 0]
804+ x_val = np .array ([
805+ [1 , 2 , 3 , 4 ],
806+ [5 , 6 , 0 , 0 ],
807+ [0 , 0 , 0 , 0 ]
808+ ], dtype = np .int32 )
809+
810+ model_in = tf .keras .layers .Input ((timesteps ,), dtype = "int32" )
811+ x_embedding = tf .keras .layers .Embedding (
812+ input_dim = 10 ,
813+ output_dim = 5 ,
814+ mask_zero = True ,
815+ embeddings_initializer = tf .random_uniform_initializer (0.0 , 1.0 , seed = 41 ),
816+ )(model_in )
817+
818+ # RNN layer inherits the mask propagated from above embedding layer
819+ model_out = tf .keras .layers .LSTM (
820+ units = 5 ,
821+ go_backwards = go_backwards ,
822+ return_sequences = return_sequences ,
823+ return_state = True ,
824+ kernel_initializer = tf .random_uniform_initializer (0.0 , 1.0 , seed = 42 ),
825+ bias_initializer = tf .random_uniform_initializer (0.0 , 1.0 , seed = 43 ),
826+ recurrent_initializer = tf .random_uniform_initializer (0.0 , 1.0 , seed = 44 ),
827+ )(x_embedding )
828+ model = tf .keras .models .Model (inputs = model_in , outputs = model_out )
829+
830+ def func (x ):
831+ y = model (x )
832+ if return_sequences :
833+ return (
834+ # skipping output Y when return_sequences=True due to inconsistent
835+ # ORT and TF behaviors: https://sim.amazon.com/issues/NEMORT-1712
836+ tf .identity (y [1 ], name = "output_yh" ),
837+ tf .identity (y [2 ], name = "output_yc" ))
838+ return (
839+ tf .identity (y [0 ], name = "output_y" ),
840+ tf .identity (y [1 ], name = "output_yh" ),
841+ tf .identity (y [2 ], name = "output_yc" ))
842+
843+ output_list = ["output_yh:0" , "output_yc:0" ] if return_sequences \
844+ else ["output_y:0" , "output_yh:0" , "output_yc:0" ]
845+ self .run_test_case (func , {"input:0" : x_val }, [], output_list , rtol = 1e-05 , atol = 1e-06 )
846+
847+ @check_tf_min_version ("2.0" )
848+ @skip_tf_versions ("2.1" , "Bug in TF 2.1" )
849+ def test_keras_masked_lstm_embedding_bidirectional (self ):
850+ for return_sequences in [False , True ]:
851+ timesteps = 4
852+ # Note: masked LSTM only support post-padded input after conversion
853+ # test case sequence_lens = [4, 2, 0]
854+ x_val = np .array ([
855+ [1 , 2 , 3 , 4 ],
856+ [5 , 6 , 0 , 0 ],
857+ [0 , 0 , 0 , 0 ]
858+ ], dtype = np .int32 )
859+
860+ model_in = tf .keras .layers .Input ((timesteps ,), dtype = "int32" )
861+ x_embedding = tf .keras .layers .Embedding (
862+ input_dim = 10 ,
863+ output_dim = 5 ,
864+ mask_zero = True ,
865+ embeddings_initializer = tf .random_uniform_initializer (0.0 , 1.0 , seed = 41 ),
866+ )(model_in )
867+
868+ # RNN layer inherits the mask propagated from above embedding layer
869+ lstm_layer = tf .keras .layers .LSTM (
870+ units = 5 ,
871+ go_backwards = False ,
872+ return_sequences = return_sequences ,
873+ return_state = True ,
874+ kernel_initializer = tf .random_uniform_initializer (0.0 , 1.0 , seed = 42 ),
875+ bias_initializer = tf .random_uniform_initializer (0.0 , 1.0 , seed = 43 ),
876+ recurrent_initializer = tf .random_uniform_initializer (0.0 , 1.0 , seed = 44 ),
877+ )
878+ model_out = tf .keras .layers .Bidirectional (lstm_layer )(x_embedding )
879+ model = tf .keras .models .Model (inputs = model_in , outputs = model_out )
880+
881+ def func (x ):
882+ y = model (x )
883+ if return_sequences :
884+ return (
885+ # skipping output Y when return_sequences=True due to inconsistent
886+ # ORT and TF behaviors: https://sim.amazon.com/issues/NEMORT-1712
887+ tf .identity (y [1 ], name = "output_yh_f" ),
888+ tf .identity (y [2 ], name = "output_yc_f" ),
889+ tf .identity (y [3 ], name = "output_yh_r" ),
890+ tf .identity (y [4 ], name = "output_yc_r" ))
891+ return (
892+ tf .identity (y [0 ], name = "output_y_concat" ),
893+ tf .identity (y [1 ], name = "output_yh_f" ),
894+ tf .identity (y [2 ], name = "output_yc_f" ),
895+ tf .identity (y [3 ], name = "output_yh_r" ),
896+ tf .identity (y [4 ], name = "output_yc_r" ))
897+
898+ output_list = ["output_yh_f:0" , "output_yc_f:0" , "output_yh_r:0" , "output_yc_r:0" ] if return_sequences \
899+ else ["output_y_concat:0" , "output_yh_f:0" , "output_yc_f:0" , "output_yh_r:0" , "output_yc_r:0" ]
900+
901+ # translate single BiLSTM to two forward LSTMs
902+ self .run_test_case (func , {"input:0" : x_val }, [], output_list , rtol = 1e-05 , atol = 1e-06 ,
903+ require_lstm_count = 2 )
904+
905+ @check_tf_min_version ("2.0" )
906+ @skip_tf_versions ("2.1" , "Bug in TF 2.1" )
907+ def test_keras_masked_lstm_unidirectional (self ):
908+ for go_backwards in [True , False ]:
909+ for return_sequences in [True , False ]:
910+ batch_size , timesteps , feat = 3 , 4 , 5
911+ in_shape = (timesteps , feat )
912+ x_val = np .random .uniform (size = [batch_size , timesteps , feat ]).astype (np .float32 )
913+ # Note: masked LSTM only support post-padded input after conversion
914+ # test case sequence_lens = [4, 2, 0]
915+ x_val [1 , 2 :, :] = 0.
916+ x_val [2 , :, :] = 0.
917+
918+ model_in = tf .keras .layers .Input (shape = in_shape , dtype = "float32" )
919+ x_masked = tf .keras .layers .Masking (mask_value = 0. )(model_in )
920+
921+ # RNN layer inherits the mask propagated from above mask layer
922+ model_out = tf .keras .layers .LSTM (
923+ units = 5 ,
924+ go_backwards = go_backwards ,
925+ return_sequences = return_sequences ,
926+ return_state = True ,
927+ kernel_initializer = tf .random_uniform_initializer (0.0 , 1.0 , seed = 42 ),
928+ bias_initializer = tf .random_uniform_initializer (0.0 , 1.0 , seed = 43 ),
929+ recurrent_initializer = tf .random_uniform_initializer (0.0 , 1.0 , seed = 44 ),
930+ )(x_masked )
931+ model = tf .keras .models .Model (inputs = model_in , outputs = model_out )
932+
933+ def func (x ):
934+ y = model (x )
935+ if return_sequences :
936+ return (
937+ # skipping output Y when return_sequences=True due to inconsistent
938+ # ORT and TF behaviors: https://sim.amazon.com/issues/NEMORT-1712
939+ tf .identity (y [1 ], name = "output_yh" ),
940+ tf .identity (y [2 ], name = "output_yc" ))
941+ return (
942+ tf .identity (y [0 ], name = "output_y" ),
943+ tf .identity (y [1 ], name = "output_yh" ),
944+ tf .identity (y [2 ], name = "output_yc" ))
945+
946+ output_list = ["output_yh:0" , "output_yc:0" ] if return_sequences \
947+ else ["output_y:0" , "output_yh:0" , "output_yc:0" ]
948+ self .run_test_case (func , {"input:0" : x_val }, [], output_list , rtol = 1e-05 , atol = 1e-06 )
949+
950+ @check_tf_min_version ("2.0" )
951+ @skip_tf_versions ("2.1" , "Bug in TF 2.1" )
952+ def test_keras_masked_lstm_bidirectional (self ):
953+ for return_sequences in [False , True ]:
954+ batch_size , timesteps , feat = 3 , 4 , 5
955+ in_shape = (timesteps , feat )
956+ x_val = np .random .uniform (size = [batch_size , timesteps , feat ]).astype (np .float32 )
957+ # Note: masked LSTM only support post-padded input after conversion
958+ # test case sequence_lens = [4, 2, 0]
959+ x_val [1 , 2 :, :] = 0.
960+ x_val [2 , :, :] = 0.
961+
962+ model_in = tf .keras .layers .Input (shape = in_shape , dtype = "float32" )
963+ x_masked = tf .keras .layers .Masking (mask_value = 0. )(model_in )
964+
965+ # RNN layer inherits the mask propagated from above mask layer
966+ lstm_layer = tf .keras .layers .LSTM (
967+ units = 5 ,
968+ go_backwards = False ,
969+ return_sequences = return_sequences ,
970+ return_state = True ,
971+ kernel_initializer = tf .random_uniform_initializer (0.0 , 1.0 , seed = 42 ),
972+ bias_initializer = tf .random_uniform_initializer (0.0 , 1.0 , seed = 43 ),
973+ recurrent_initializer = tf .random_uniform_initializer (0.0 , 1.0 , seed = 44 ),
974+ )
975+ model_out = tf .keras .layers .Bidirectional (lstm_layer )(x_masked )
976+ model = tf .keras .models .Model (inputs = model_in , outputs = model_out )
977+
978+ def func (x ):
979+ y = model (x )
980+ if return_sequences :
981+ return (
982+ # skipping output Y when return_sequences=True due to inconsistent
983+ # ORT and TF behaviors: https://sim.amazon.com/issues/NEMORT-1712
984+ tf .identity (y [1 ], name = "output_yh_f" ),
985+ tf .identity (y [2 ], name = "output_yc_f" ),
986+ tf .identity (y [3 ], name = "output_yh_r" ),
987+ tf .identity (y [4 ], name = "output_yc_r" ))
988+ return (
989+ tf .identity (y [0 ], name = "output_y_concat" ),
990+ tf .identity (y [1 ], name = "output_yh_f" ),
991+ tf .identity (y [2 ], name = "output_yc_f" ),
992+ tf .identity (y [3 ], name = "output_yh_r" ),
993+ tf .identity (y [4 ], name = "output_yc_r" ))
994+
995+ output_list = ["output_yh_f:0" , "output_yc_f:0" , "output_yh_r:0" , "output_yc_r:0" ] if return_sequences \
996+ else ["output_y_concat:0" , "output_yh_f:0" , "output_yc_f:0" , "output_yh_r:0" , "output_yc_r:0" ]
997+
998+ # translate single BiLSTM to two forward LSTMs
999+ self .run_test_case (func , {"input:0" : x_val }, [], output_list , rtol = 1e-05 , atol = 1e-06 ,
1000+ require_lstm_count = 2 )
1001+
1002+
7961003if __name__ == '__main__' :
7971004 unittest_main ()
0 commit comments