38
38
from tensorflow .python .distribute import distribution_strategy_context
39
39
from tensorflow .python .distribute import multi_worker_util
40
40
from tensorflow .python .eager import context
41
- from tensorflow .python .framework import composite_tensor_utils
42
41
from tensorflow .python .eager import function as eager_function
43
42
from tensorflow .python .eager import lift_to_graph
44
43
from tensorflow .python .framework import composite_tensor
70
69
from tensorflow .python .ops import tensor_array_grad # pylint: disable=unused-import
71
70
from tensorflow .python .ops import tensor_array_ops
72
71
from tensorflow .python .ops import variables as variables_module
72
+ from tensorflow .python .ops .ragged import ragged_factory_ops
73
73
from tensorflow .python .platform import tf_logging as logging
74
74
from tensorflow .python .util import nest
75
75
from tensorflow .python .util import tf_contextlib
@@ -958,7 +958,12 @@ def is_keras_tensor(x):
958
958
959
959
960
960
@keras_export ('keras.backend.placeholder' )
961
- def placeholder (shape = None , ndim = None , dtype = None , sparse = False , name = None ):
961
+ def placeholder (shape = None ,
962
+ ndim = None ,
963
+ dtype = None ,
964
+ sparse = False ,
965
+ name = None ,
966
+ ragged = False ):
962
967
"""Instantiates a placeholder tensor and returns it.
963
968
964
969
Arguments:
@@ -970,9 +975,14 @@ def placeholder(shape=None, ndim=None, dtype=None, sparse=False, name=None):
970
975
dtype: Placeholder type.
971
976
sparse: Boolean, whether the placeholder should have a sparse type.
972
977
name: Optional name string for the placeholder.
978
+ ragged: Boolean, whether the placeholder should have a ragged type.
979
+ In this case, values of 'None' in the 'shape' argument represent
980
+ ragged dimensions. For more information about RaggedTensors, see this
981
+ [guide](https://www.tensorflow.org/guide/ragged_tensors).
973
982
974
983
Raises:
975
- ValueError: If called with eager execution.
984
+ ValueError: If called with eager execution
985
+ ValueError: If called with sparse = True and ragged = True.
976
986
977
987
Returns:
978
988
Tensor instance (with Keras metadata included).
@@ -985,6 +995,11 @@ def placeholder(shape=None, ndim=None, dtype=None, sparse=False, name=None):
985
995
<tf.Tensor 'Placeholder_4:0' shape=(2, 4, 5) dtype=float32>
986
996
```
987
997
"""
998
+ if sparse and ragged :
999
+ raise ValueError (
1000
+ 'Cannot set both sparse and ragged to True when creating a placeholder.'
1001
+ )
1002
+
988
1003
if dtype is None :
989
1004
dtype = floatx ()
990
1005
if not shape :
@@ -993,6 +1008,20 @@ def placeholder(shape=None, ndim=None, dtype=None, sparse=False, name=None):
993
1008
with get_graph ().as_default ():
994
1009
if sparse :
995
1010
x = array_ops .sparse_placeholder (dtype , shape = shape , name = name )
1011
+ elif ragged :
1012
+ ragged_rank = 0
1013
+ for i in range (1 , len (shape )):
1014
+ if shape [i ] is None :
1015
+ ragged_rank += 1
1016
+ else :
1017
+ break
1018
+ value_shape = shape [(ragged_rank + 1 ):]
1019
+
1020
+ x = ragged_factory_ops .placeholder (
1021
+ dtype = dtype ,
1022
+ ragged_rank = ragged_rank ,
1023
+ value_shape = value_shape ,
1024
+ name = name )
996
1025
else :
997
1026
x = array_ops .placeholder (dtype , shape = shape , name = name )
998
1027
return x
@@ -1008,7 +1037,11 @@ def is_placeholder(x):
1008
1037
Boolean.
1009
1038
"""
1010
1039
try :
1011
- return x .op .type == 'Placeholder'
1040
+ if isinstance (x , composite_tensor .CompositeTensor ):
1041
+ flat_components = nest .flatten (x , expand_composites = True )
1042
+ return py_any (is_placeholder (c ) for c in flat_components )
1043
+ else :
1044
+ return x .op .type == 'Placeholder'
1012
1045
except AttributeError :
1013
1046
return False
1014
1047
@@ -3108,63 +3141,6 @@ def print_tensor(x, message=''):
3108
3141
logging_ops .print_v2 (message , x , output_stream = sys .stdout )
3109
3142
return x
3110
3143
3111
-
3112
- def is_tensor_or_composite_tensor (value ):
3113
- """Test if a passed value object is a tensor-like or composite tensor."""
3114
- return (tensor_util .is_tensor (value ) or isinstance (value , np .ndarray ) or
3115
- composite_tensor_utils .is_composite_or_composite_value (value ))
3116
-
3117
-
3118
- def _try_process_scipy_sparse_input (value ):
3119
- """Converts 'value' to a SparseTensor if it is a scipy sparse matrix.
3120
-
3121
- Arguments:
3122
- value: An object that may have the attributes of a scipy sparse matrix.
3123
-
3124
- Returns:
3125
- Either a SparseTensor based off of 'value' or 'value' itself.
3126
- """
3127
- try :
3128
- sparse_coo = value .tocoo ()
3129
- row , col = sparse_coo .row , sparse_coo .col
3130
- data , shape = sparse_coo .data , sparse_coo .shape
3131
- except AttributeError :
3132
- # If we can't convert this object, it could be either a single data
3133
- # element (ie, a bool/int/float) which is OK to pass on, or something
3134
- # that we don't understand (which may or may not be OK). In either
3135
- # case, don't die here: the data standardization code will catch
3136
- # those issues.
3137
- return value
3138
-
3139
- indices = np .concatenate ((np .expand_dims (row , 1 ), np .expand_dims (col , 1 )), 1 )
3140
- return sparse_tensor .SparseTensor (indices , data , shape )
3141
-
3142
-
3143
- def try_convert_scipy_to_sparse (values ):
3144
- """Converts scipy sparse matrices in 'values' to SparseTensors, if possible.
3145
-
3146
- Arguments:
3147
- values: An input or list of inputs to convert. These may be TensorLikes,
3148
- ndarrays, composite tensors, or scipy sparse values.
3149
-
3150
- Returns:
3151
- An input or list of inputs where scipy sparse tensors have been converted
3152
- to tf.SparseTensors.
3153
-
3154
- Raises:
3155
- ValueError: If input cannot be converted to a SparseTensor.
3156
- """
3157
- # Convert scipy sparse data into sparse tensors.
3158
- value_structure = values
3159
- values = nest .flatten (values )
3160
- for idx , value in enumerate (values ):
3161
- if not is_tensor_or_composite_tensor (value ):
3162
- values [idx ] = _try_process_scipy_sparse_input (value )
3163
- values = nest .pack_sequence_as (value_structure , values )
3164
-
3165
- return values
3166
-
3167
-
3168
3144
# GRAPH MANIPULATION
3169
3145
3170
3146
@@ -3194,6 +3170,7 @@ def __init__(self, inputs, outputs, updates=None, name=None,
3194
3170
if not isinstance (updates , (list , tuple )):
3195
3171
raise TypeError ('`updates` in a Keras backend function '
3196
3172
'should be a list or tuple.' )
3173
+
3197
3174
self ._inputs_structure = inputs
3198
3175
self .inputs = nest .flatten (inputs , expand_composites = True )
3199
3176
self ._outputs_structure = outputs
@@ -3311,10 +3288,6 @@ def _eval_if_composite(self, tensor):
3311
3288
return tensor
3312
3289
3313
3290
def __call__ (self , inputs ):
3314
- inputs = try_convert_scipy_to_sparse (inputs )
3315
-
3316
- # Ensure that input value types match any expected composite tensor types.
3317
- # TODO(momernick): Once TensorSpecs are implemented for CTs, use that here.
3318
3291
inputs = nest .flatten (inputs , expand_composites = True )
3319
3292
3320
3293
session = get_session (inputs )
@@ -3488,10 +3461,8 @@ def __init__(self, inputs, outputs, updates=None, name=None):
3488
3461
x .op .inputs [0 ])
3489
3462
3490
3463
def __call__ (self , inputs ):
3491
- # Convert scipy sparse data into sparse tensors.
3492
- inputs = try_convert_scipy_to_sparse (inputs )
3493
-
3494
3464
input_values = nest .flatten (inputs , expand_composites = True )
3465
+
3495
3466
if self ._freezable_vars_values :
3496
3467
input_values = input_values + self ._freezable_vars_values
3497
3468
converted_inputs = []
0 commit comments