45
45
Layer = keras .layers .Layer
46
46
LeakyReLU = keras .layers .LeakyReLU
47
47
LSTM = keras .layers .LSTM
48
+ LSTMCell = keras .layers .LSTMCell
48
49
Maximum = keras .layers .Maximum
49
50
MaxPool1D = keras .layers .MaxPool1D
50
51
MaxPool3D = keras .layers .MaxPool3D
51
52
MaxPooling2D = keras .layers .MaxPooling2D
52
53
Model = keras .models .Model
53
54
Multiply = keras .layers .Multiply
54
55
Reshape = keras .layers .Reshape
56
+ RNN = keras .layers .RNN
55
57
SeparableConv1D = keras .layers .SeparableConv1D
56
58
SeparableConv2D = keras .layers .SeparableConv2D
57
59
Sequential = keras .models .Sequential
66
68
if not is_keras_older_than ("2.2.4" ):
67
69
ReLU = keras .layers .ReLU
68
70
71
+ GRU_CLASSES = [(GRU , "v1" )]
72
+ LSTM_CLASSES = [(LSTM , LSTMCell , "v1" )]
69
73
RNN_CLASSES = [SimpleRNN , GRU , LSTM ]
70
74
71
75
if is_tf_keras and is_tensorflow_later_than ("1.14.0" ):
72
76
# Add the TF v2 compatability layers (available after TF 1.14)
73
77
from tensorflow .python .keras .layers import recurrent_v2
78
+ GRU_CLASSES .append ((recurrent_v2 .GRU , "v2" ))
79
+ LSTM_CLASSES .append ((recurrent_v2 .LSTM , recurrent_v2 .LSTMCell , "v2" ))
74
80
RNN_CLASSES .extend ([recurrent_v2 .GRU , recurrent_v2 .LSTM ])
75
81
76
82
@@ -1829,134 +1835,175 @@ def test_simpleRNN(runner):
1829
1835
assert runner (onnx_model .graph .name , onnx_model , [x , s ], expected )
1830
1836
1831
1837
1832
- def test_GRU (runner ):
1838
+ @pytest .mark .parametrize ("gru_class, rnn_version" , GRU_CLASSES )
1839
+ @pytest .mark .parametrize ("return_sequences" , [True , False ])
1840
+ def test_GRU (runner , gru_class , rnn_version , return_sequences ):
1833
1841
inputs1 = keras .Input (shape = (3 , 1 ))
1834
1842
1835
- cls = GRU (2 , return_state = False , return_sequences = False )
1843
+ # GRU with no initial state
1844
+ cls = gru_class (2 , return_state = False , return_sequences = False )
1836
1845
oname = cls (inputs1 )
1837
1846
model = keras .Model (inputs = inputs1 , outputs = [oname ])
1838
1847
onnx_model = convert_keras (model , model .name )
1839
-
1848
+ if rnn_version == "v2" :
1849
+ assert no_loops_in_tf2 (onnx_model )
1840
1850
data = np .array ([0.1 , 0.2 , 0.3 ]).astype (np .float32 ).reshape ((1 , 3 , 1 ))
1841
1851
expected = model .predict (data )
1842
1852
assert runner (onnx_model .graph .name , onnx_model , data , expected )
1843
1853
1844
1854
# GRU with initial state
1845
- for return_sequences in [ True , False ]:
1846
- cls = GRU ( 2 , return_state = False , return_sequences = return_sequences )
1847
- initial_state_input = keras . Input ( shape = ( 2 ,) )
1848
- oname = cls ( inputs1 , initial_state = initial_state_input )
1849
- model = keras . Model ( inputs = [ inputs1 , initial_state_input ], outputs = [ oname ] )
1850
- onnx_model = convert_keras ( model , model . name )
1851
-
1852
- data = np .array ([0.1 , 0.2 , 0.3 ]).astype (np .float32 ).reshape ((1 , 3 , 1 ))
1853
- init_state = np .array ([0.4 , 0.5 ]).astype (np .float32 ).reshape ((1 , 2 ))
1854
- init_state_onnx = np .array ([0.4 , 0.5 ]).astype (np .float32 ).reshape ((1 , 2 ))
1855
- expected = model .predict ([data , init_state ])
1856
- assert runner (onnx_model .graph .name , onnx_model , [data , init_state_onnx ], expected )
1855
+ cls = gru_class ( 2 , return_state = False , return_sequences = return_sequences )
1856
+ initial_state_input = keras . Input ( shape = ( 2 ,) )
1857
+ oname = cls ( inputs1 , initial_state = initial_state_input )
1858
+ model = keras . Model ( inputs = [ inputs1 , initial_state_input ], outputs = [ oname ] )
1859
+ onnx_model = convert_keras ( model , model . name )
1860
+ if rnn_version == "v2" :
1861
+ assert no_loops_in_tf2 ( onnx_model )
1862
+ data = np .array ([0.1 , 0.2 , 0.3 ]).astype (np .float32 ).reshape ((1 , 3 , 1 ))
1863
+ init_state = np .array ([0.4 , 0.5 ]).astype (np .float32 ).reshape ((1 , 2 ))
1864
+ init_state_onnx = np .array ([0.4 , 0.5 ]).astype (np .float32 ).reshape ((1 , 2 ))
1865
+ expected = model .predict ([data , init_state ])
1866
+ assert runner (onnx_model .graph .name , onnx_model , [data , init_state_onnx ], expected )
1857
1867
1858
1868
1859
1869
@pytest .mark .skipif (not is_tf_keras and is_tf2 and is_tensorflow_older_than ('2.2' ),
1860
1870
reason = "Fails due to some reason involving bad graph captures. Works in new versions and tf_keras" )
1861
- def test_GRU_2 (runner ):
1871
+ @pytest .mark .parametrize ("gru_class, rnn_version" , GRU_CLASSES )
1872
+ def test_GRU_2 (runner , gru_class , rnn_version ):
1862
1873
model = keras .Sequential (name = 'TestGRU' )
1863
- model .add (keras . layers . GRU (400 , reset_after = True , input_shape = (1 , 257 )))
1864
- model .add (keras . layers . Dense (257 , activation = 'sigmoid' ))
1874
+ model .add (gru_class (400 , reset_after = True , input_shape = (1 , 257 )))
1875
+ model .add (Dense (257 , activation = 'sigmoid' ))
1865
1876
onnx_model = convert_keras (model , name = model .name )
1877
+ if rnn_version == "v2" :
1878
+ assert no_loops_in_tf2 (onnx_model )
1866
1879
data = np .random .rand (3 , 257 ).astype (np .float32 ).reshape ((3 , 1 , 257 ))
1867
1880
expected = model .predict (data )
1868
1881
assert runner (onnx_model .graph .name , onnx_model , data , expected )
1869
1882
1870
1883
1884
+ @pytest .mark .parametrize ("lstm_class, lstmcell_class, rnn_version" , LSTM_CLASSES )
1871
1885
@pytest .mark .parametrize ('return_sequences' , [False , True ])
1872
- def test_LSTM (runner , return_sequences ):
1886
+ @pytest .mark .parametrize ('use_bias' , [False , True ])
1887
+ def test_LSTM (runner , lstm_class , lstmcell_class , rnn_version , return_sequences , use_bias ):
1873
1888
inputs1 = keras .Input (shape = (3 , 5 ))
1874
1889
data = np .random .rand (3 , 5 ).astype (np .float32 ).reshape ((1 , 3 , 5 ))
1875
- for use_bias in [True , False ]:
1876
- for return_sequences in [True , False ]:
1877
- cls = LSTM (units = 2 , return_state = True , return_sequences = return_sequences , use_bias = use_bias )
1878
- lstm1 , state_h , state_c = cls (inputs1 )
1879
- model = keras .Model (inputs = inputs1 , outputs = [lstm1 , state_h , state_c ])
1880
- onnx_model = convert_keras (model , model .name )
1881
- expected = model .predict (data )
1882
- assert runner (onnx_model .graph .name , onnx_model , data , expected )
1890
+ cls1 = lstm_class (units = 2 , return_state = True , return_sequences = return_sequences , use_bias = use_bias )
1891
+ cls2 = RNN (lstmcell_class (units = 2 , use_bias = use_bias ), return_state = True , return_sequences = return_sequences )
1892
+ lstm1 , state_h , state_c = cls1 (inputs1 )
1893
+ lstm2 , state_h_2 , state_c_2 = cls2 (inputs1 )
1894
+ model = keras .Model (inputs = inputs1 , outputs = [lstm1 , state_h , state_c , lstm2 , state_h_2 , state_c_2 ])
1895
+ onnx_model = convert_keras (model , model .name )
1896
+ if rnn_version == "v2" :
1897
+ assert no_loops_in_tf2 (onnx_model )
1898
+ expected = model .predict (data )
1899
+ assert runner (onnx_model .graph .name , onnx_model , data , expected )
1900
+
1883
1901
1884
1902
@pytest .mark .skipif ((is_tensorflow_older_than ('1.14.0' ) or (not is_tf_keras )), reason = 'old tf version' )
1885
- def test_LSTM_rev (runner ):
1903
+ @pytest .mark .parametrize ("lstm_class, lstmcell_class, rnn_version" , LSTM_CLASSES )
1904
+ @pytest .mark .parametrize ('return_sequences' , [False , True ])
1905
+ @pytest .mark .parametrize ('use_bias' , [False , True ])
1906
+ def test_LSTM_rev (runner , lstm_class , lstmcell_class , rnn_version , return_sequences , use_bias ):
1886
1907
inputs1 = keras .Input (shape = (3 , 5 ))
1887
1908
data = np .random .rand (3 , 5 ).astype (np .float32 ).reshape ((1 , 3 , 5 ))
1888
- for use_bias in [ True , False ]:
1889
- for return_sequences in [ True , False ]:
1890
- cls = LSTM ( units = 2 , return_state = True , go_backwards = True , return_sequences = return_sequences , use_bias = use_bias )
1891
- lstm1 , state_h , state_c = cls ( inputs1 )
1892
- model = keras . Model ( inputs = inputs1 , outputs = [ lstm1 , state_h , state_c ])
1893
- onnx_model = convert_keras ( model , model . name )
1894
- expected = model .predict (data )
1895
- assert runner (onnx_model .graph .name , onnx_model , data , expected )
1909
+ cls = lstm_class ( units = 2 , return_state = True , go_backwards = True , return_sequences = return_sequences , use_bias = use_bias )
1910
+ lstm1 , state_h , state_c = cls ( inputs1 )
1911
+ model = keras . Model ( inputs = inputs1 , outputs = [ lstm1 , state_h , state_c ] )
1912
+ onnx_model = convert_keras ( model , model . name )
1913
+ if rnn_version == "v2" :
1914
+ assert no_loops_in_tf2 ( onnx_model )
1915
+ expected = model .predict (data )
1916
+ assert runner (onnx_model .graph .name , onnx_model , data , expected )
1896
1917
1897
1918
1898
1919
@pytest .mark .skipif ((is_tensorflow_older_than ('1.14.0' ) or (not is_tf_keras )),
1899
1920
reason = "keras LSTM does not have time_major attribute" )
1900
- def test_LSTM_time_major_return_seq_true (runner ):
1921
+ @pytest .mark .parametrize ("lstm_class, lstmcell_class, rnn_version" , LSTM_CLASSES )
1922
+ def test_LSTM_time_major_return_seq_true (runner , lstm_class , lstmcell_class , rnn_version ):
1901
1923
inputs1 = keras .Input (shape = (3 , 5 ))
1902
1924
data = np .random .rand (1 , 3 , 5 ).astype (np .float32 )
1903
1925
# Transpose input to be time major
1904
1926
input_transposed = tf .transpose (inputs1 , perm = [1 , 0 , 2 ])
1905
- lstm1 , state_h , state_c = LSTM (units = 2 , time_major = True , return_state = True ,
1927
+ lstm1 , state_h , state_c = lstm_class (units = 2 , time_major = True , return_state = True ,
1906
1928
return_sequences = True )(input_transposed )
1929
+ lstm2 , state_h_2 , state_c_2 = RNN (lstmcell_class (units = 2 ), time_major = True , return_state = True ,
1930
+ return_sequences = True )(input_transposed )
1907
1931
lstm1_trans = tf .transpose (lstm1 , perm = [1 , 0 , 2 ])
1908
- model = keras .Model (inputs = inputs1 , outputs = [lstm1_trans , state_h , state_c ])
1932
+ lstm2_trans = tf .transpose (lstm2 , perm = [1 ,0 ,2 ])
1933
+ model = keras .Model (inputs = inputs1 , outputs = [lstm1_trans , state_h , state_c ,
1934
+ lstm2_trans , state_h_2 , state_c_2 ])
1909
1935
onnx_model = convert_keras (model , model .name )
1936
+ if rnn_version == "v2" :
1937
+ assert no_loops_in_tf2 (onnx_model )
1910
1938
expected = model .predict (data )
1911
1939
assert runner (onnx_model .graph .name , onnx_model , data , expected )
1912
1940
1913
1941
1914
1942
@pytest .mark .skipif ((is_tensorflow_older_than ('1.14.0' ) or (not is_tf_keras )),
1915
1943
reason = "keras LSTM does not have time_major attribute" )
1916
- def test_LSTM_time_major_return_seq_false (runner ):
1944
+ @pytest .mark .parametrize ("lstm_class, lstmcell_class, rnn_version" , LSTM_CLASSES )
1945
+ def test_LSTM_time_major_return_seq_false (runner , lstm_class , lstmcell_class , rnn_version ):
1917
1946
inputs1 = keras .Input (shape = (3 , 5 ))
1918
1947
data = np .random .rand (1 , 3 , 5 ).astype (np .float32 )
1919
1948
# Transpose input to be time major
1920
1949
input_transposed = tf .transpose (inputs1 , perm = [1 , 0 , 2 ])
1921
- lstm1 , state_h , state_c = LSTM (units = 2 , time_major = True , return_state = True ,
1950
+ lstm1 , state_h , state_c = lstm_class (units = 2 , time_major = True , return_state = True ,
1922
1951
return_sequences = False )(input_transposed )
1923
- model = keras .Model (inputs = inputs1 , outputs = [lstm1 , state_h , state_c ])
1952
+ lstm2 , state_h_2 , state_c_2 = RNN (lstmcell_class (units = 2 ), time_major = True , return_state = True ,
1953
+ return_sequences = False )(input_transposed )
1954
+ model = keras .Model (inputs = inputs1 , outputs = [lstm1 , state_h , state_c ,
1955
+ lstm2 , state_h_2 , state_c_2 ])
1924
1956
onnx_model = convert_keras (model , model .name )
1957
+ if rnn_version == "v2" :
1958
+ assert no_loops_in_tf2 (onnx_model )
1925
1959
expected = model .predict (data )
1926
1960
assert runner (onnx_model .graph .name , onnx_model , data , expected )
1927
1961
1928
1962
1929
- def test_LSTM_with_bias (runner ):
1963
+ @pytest .mark .parametrize ("lstm_class, lstmcell_class, rnn_version" , LSTM_CLASSES )
1964
+ def test_LSTM_with_bias (runner , lstm_class , lstmcell_class , rnn_version ):
1930
1965
inputs1 = keras .Input (shape = (1 , 1 ))
1931
- cls = LSTM (units = 1 , return_state = True , return_sequences = True )
1966
+ cls = lstm_class (units = 1 , return_state = True , return_sequences = True )
1932
1967
lstm1 , state_h , state_c = cls (inputs1 )
1933
- model = keras .Model (inputs = inputs1 , outputs = [lstm1 , state_h , state_c ])
1968
+ lstm2 , state_h_2 , state_c_2 = RNN (lstmcell_class (units = 1 ), return_state = True ,
1969
+ return_sequences = True )(inputs1 )
1970
+ model = keras .Model (inputs = inputs1 , outputs = [lstm1 , state_h , state_c ,
1971
+ lstm2 , state_h_2 , state_c_2 ])
1934
1972
# Set weights: kernel, recurrent_kernel and bias
1935
- model .set_weights ((np .array ([[1 , 2 , 3 , 4 ]]), np .array ([[5 , 6 , 7 , 8 ]]), np .array ([1 , 2 , 3 , 4 ])))
1973
+ model .set_weights ((np .array ([[1 , 2 , 3 , 4 ]]), np .array ([[5 , 6 , 7 , 8 ]]), np .array ([1 , 2 , 3 , 4 ]),
1974
+ np .array ([[1 , 2 , 3 , 4 ]]), np .array ([[5 , 6 , 7 , 8 ]]), np .array ([1 , 2 , 3 , 4 ])))
1936
1975
data = np .random .rand (1 , 1 ).astype (np .float32 ).reshape ((1 , 1 , 1 ))
1937
1976
onnx_model = convert_keras (model , model .name )
1938
-
1977
+ if rnn_version == "v2" :
1978
+ assert no_loops_in_tf2 (onnx_model )
1939
1979
expected = model .predict (data )
1940
1980
assert runner (onnx_model .graph .name , onnx_model , data , expected )
1941
1981
1942
1982
1943
- def test_LSTM_reshape (runner ):
1983
+ @pytest .mark .parametrize ("lstm_class, lstmcell_class, rnn_version" , LSTM_CLASSES )
1984
+ def test_LSTM_reshape (runner , lstm_class , lstmcell_class , rnn_version ):
1944
1985
input_dim = 7
1945
1986
sequence_len = 3
1946
1987
inputs1 = keras .Input (shape = (sequence_len , input_dim ))
1947
- cls = LSTM (units = 5 , return_state = False , return_sequences = True )
1988
+ cls = lstm_class (units = 5 , return_state = False , return_sequences = True )
1948
1989
lstm1 = cls (inputs1 )
1990
+ lstm2 = RNN (lstmcell_class (units = 5 ), return_state = False , return_sequences = True )(inputs1 )
1991
+
1949
1992
output = Reshape ((sequence_len , 5 ))(lstm1 )
1950
- model = keras .Model (inputs = inputs1 , outputs = output )
1993
+ output_2 = Reshape ((sequence_len , 5 ))(lstm2 )
1994
+ model = keras .Model (inputs = inputs1 , outputs = [output , output_2 ])
1951
1995
model .compile (optimizer = 'sgd' , loss = 'mse' )
1952
1996
1953
1997
onnx_model = convert_keras (model , 'test' )
1998
+ if rnn_version == "v2" :
1999
+ assert no_loops_in_tf2 (onnx_model )
1954
2000
data = np .random .rand (input_dim , sequence_len ).astype (np .float32 ).reshape ((1 , sequence_len , input_dim ))
1955
2001
expected = model .predict (data )
1956
2002
assert runner ('tf_lstm' , onnx_model , data , expected )
1957
2003
1958
2004
1959
- def test_LSTM_with_initializer (runner ):
2005
+ @pytest .mark .parametrize ("lstm_class, lstmcell_class, rnn_version" , LSTM_CLASSES )
2006
+ def test_LSTM_with_initializer (runner , lstm_class , lstmcell_class , rnn_version ):
1960
2007
# batch_size = N
1961
2008
# seq_length = H
1962
2009
# input_size = W
@@ -1971,34 +2018,44 @@ def test_LSTM_with_initializer(runner):
1971
2018
state_c = keras .Input (shape = (C ,), name = 'state_c' )
1972
2019
1973
2020
# create keras model
1974
- lstm_layer = LSTM (units = C , activation = 'relu' , return_sequences = True )(inputs ,
2021
+ lstm_layer = lstm_class (units = C , activation = 'relu' , return_sequences = True )(inputs ,
1975
2022
initial_state = [state_h ,
1976
2023
state_c ])
2024
+ lstm_layer_2 = RNN (lstmcell_class (units = C , activation = 'relu' ),
2025
+ return_sequences = True )(inputs , initial_state = [state_h , state_c ])
1977
2026
outputs = Dense (W , activation = 'sigmoid' )(lstm_layer )
1978
- keras_model = keras .Model (inputs = [inputs , state_h , state_c ], outputs = outputs )
2027
+ outputs_2 = Dense (W , activation = 'sigmoid' )(lstm_layer_2 )
2028
+ keras_model = keras .Model (inputs = [inputs , state_h , state_c ],
2029
+ outputs = [outputs , outputs_2 ])
1979
2030
1980
2031
x = np .random .rand (1 , H , W ).astype (np .float32 )
1981
2032
sh = np .random .rand (1 , C ).astype (np .float32 )
1982
2033
sc = np .random .rand (1 , C ).astype (np .float32 )
1983
- expected = keras_model .predict ([x , sh , sc ])
1984
2034
onnx_model = convert_keras (keras_model , keras_model .name )
2035
+ if rnn_version == "v2" :
2036
+ assert no_loops_in_tf2 (onnx_model )
2037
+ expected = keras_model .predict ([x , sh , sc ])
1985
2038
assert runner (onnx_model .graph .name , onnx_model , {"inputs" : x , 'state_h' : sh , 'state_c' : sc }, expected )
1986
2039
1987
2040
1988
2041
@pytest .mark .skipif (get_maximum_opset_supported () < 5 ,
1989
2042
reason = "None seq_length LSTM is not supported before opset 5." )
1990
2043
@pytest .mark .skipif (is_tensorflow_older_than ('2.2' ), reason = 'require 2.2 to fix freezing' )
1991
- def test_LSTM_seqlen_none (runner ):
2044
+ @pytest .mark .parametrize ("lstm_class, lstmcell_class, rnn_version" , LSTM_CLASSES )
2045
+ @pytest .mark .parametrize ('return_sequences' , [False , True ])
2046
+ def test_LSTM_seqlen_none (runner , lstm_class , lstmcell_class , rnn_version , return_sequences ):
1992
2047
lstm_dim = 2
1993
2048
data = np .random .rand (1 , 5 , 1 ).astype (np .float32 )
1994
- for return_sequences in [True , False ]:
1995
- inp = Input (batch_shape = (1 , None , 1 ))
1996
- out = LSTM (lstm_dim , return_sequences = return_sequences , stateful = True )(inp )
1997
- keras_model = keras .Model (inputs = inp , outputs = out )
1998
-
1999
- onnx_model = convert_keras (keras_model )
2000
- expected = keras_model .predict (data )
2001
- assert runner (onnx_model .graph .name , onnx_model , data , expected )
2049
+ inp = Input (batch_shape = (1 , None , 1 ))
2050
+ out = lstm_class (lstm_dim , return_sequences = return_sequences , stateful = True )(inp )
2051
+ out_2 = RNN (lstmcell_class (lstm_dim ), return_sequences = return_sequences , stateful = True )(inp )
2052
+ keras_model = keras .Model (inputs = inp , outputs = [out , out_2 ])
2053
+
2054
+ onnx_model = convert_keras (keras_model )
2055
+ if rnn_version == "v2" :
2056
+ assert no_loops_in_tf2 (onnx_model )
2057
+ expected = keras_model .predict (data )
2058
+ assert runner (onnx_model .graph .name , onnx_model , data , expected )
2002
2059
2003
2060
2004
2061
@pytest .mark .parametrize ("return_sequences" , [True , False ])
0 commit comments