3838from tensorflow .python .distribute import distribution_strategy_context
3939from tensorflow .python .distribute import multi_worker_util
4040from tensorflow .python .eager import context
41- from tensorflow .python .framework import composite_tensor_utils
4241from tensorflow .python .eager import function as eager_function
4342from tensorflow .python .eager import lift_to_graph
4443from tensorflow .python .framework import composite_tensor
7069from tensorflow .python .ops import tensor_array_grad # pylint: disable=unused-import
7170from tensorflow .python .ops import tensor_array_ops
7271from tensorflow .python .ops import variables as variables_module
72+ from tensorflow .python .ops .ragged import ragged_factory_ops
7373from tensorflow .python .platform import tf_logging as logging
7474from tensorflow .python .util import nest
7575from tensorflow .python .util import tf_contextlib
@@ -958,7 +958,12 @@ def is_keras_tensor(x):
958958
959959
960960@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 ):
962967 """Instantiates a placeholder tensor and returns it.
963968
964969 Arguments:
@@ -970,9 +975,14 @@ def placeholder(shape=None, ndim=None, dtype=None, sparse=False, name=None):
970975 dtype: Placeholder type.
971976 sparse: Boolean, whether the placeholder should have a sparse type.
972977 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).
973982
974983 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.
976986
977987 Returns:
978988 Tensor instance (with Keras metadata included).
@@ -985,6 +995,11 @@ def placeholder(shape=None, ndim=None, dtype=None, sparse=False, name=None):
985995 <tf.Tensor 'Placeholder_4:0' shape=(2, 4, 5) dtype=float32>
986996 ```
987997 """
998+ if sparse and ragged :
999+ raise ValueError (
1000+ 'Cannot set both sparse and ragged to True when creating a placeholder.'
1001+ )
1002+
9881003 if dtype is None :
9891004 dtype = floatx ()
9901005 if not shape :
@@ -993,6 +1008,20 @@ def placeholder(shape=None, ndim=None, dtype=None, sparse=False, name=None):
9931008 with get_graph ().as_default ():
9941009 if sparse :
9951010 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 )
9961025 else :
9971026 x = array_ops .placeholder (dtype , shape = shape , name = name )
9981027 return x
@@ -1008,7 +1037,11 @@ def is_placeholder(x):
10081037 Boolean.
10091038 """
10101039 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'
10121045 except AttributeError :
10131046 return False
10141047
@@ -3108,63 +3141,6 @@ def print_tensor(x, message=''):
31083141 logging_ops .print_v2 (message , x , output_stream = sys .stdout )
31093142 return x
31103143
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-
31683144# GRAPH MANIPULATION
31693145
31703146
@@ -3194,6 +3170,7 @@ def __init__(self, inputs, outputs, updates=None, name=None,
31943170 if not isinstance (updates , (list , tuple )):
31953171 raise TypeError ('`updates` in a Keras backend function '
31963172 'should be a list or tuple.' )
3173+
31973174 self ._inputs_structure = inputs
31983175 self .inputs = nest .flatten (inputs , expand_composites = True )
31993176 self ._outputs_structure = outputs
@@ -3311,10 +3288,6 @@ def _eval_if_composite(self, tensor):
33113288 return tensor
33123289
33133290 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.
33183291 inputs = nest .flatten (inputs , expand_composites = True )
33193292
33203293 session = get_session (inputs )
@@ -3488,10 +3461,8 @@ def __init__(self, inputs, outputs, updates=None, name=None):
34883461 x .op .inputs [0 ])
34893462
34903463 def __call__ (self , inputs ):
3491- # Convert scipy sparse data into sparse tensors.
3492- inputs = try_convert_scipy_to_sparse (inputs )
3493-
34943464 input_values = nest .flatten (inputs , expand_composites = True )
3465+
34953466 if self ._freezable_vars_values :
34963467 input_values = input_values + self ._freezable_vars_values
34973468 converted_inputs = []
0 commit comments