1# Copyright 2015 The TensorFlow Authors. All Rights Reserved. 2# 3# Licensed under the Apache License, Version 2.0 (the "License"); 4# you may not use this file except in compliance with the License. 5# You may obtain a copy of the License at 6# 7# http://www.apache.org/licenses/LICENSE-2.0 8# 9# Unless required by applicable law or agreed to in writing, software 10# distributed under the License is distributed on an "AS IS" BASIS, 11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12# See the License for the specific language governing permissions and 13# limitations under the License. 14# ============================================================================== 15"""Operations that generate constants. 16 17See the [constants guide](https://tensorflow.org/api_guides/python/constant_op). 18""" 19 20# Must be separate from array_ops to avoid a cyclic dependency. 21 22from __future__ import absolute_import 23from __future__ import division 24from __future__ import print_function 25 26from tensorflow.core.framework import attr_value_pb2 27from tensorflow.core.framework import types_pb2 28from tensorflow.python.eager import context 29from tensorflow.python.eager import execute 30from tensorflow.python.framework import dtypes 31from tensorflow.python.framework import op_callbacks 32from tensorflow.python.framework import ops 33from tensorflow.python.framework import tensor_shape 34from tensorflow.python.framework import tensor_util 35from tensorflow.python.profiler import trace 36from tensorflow.python.util.tf_export import tf_export 37 38 39def _eager_reshape(tensor, shape, ctx): 40 """Eager-only version of Reshape op; requires tensor is an eager Tensor.""" 41 attr_t = tensor._datatype_enum() # pylint: disable=protected-access 42 attr_tshape, (shape,) = execute.args_to_matching_eager( 43 [shape], ctx, [dtypes.int32, dtypes.int64], dtypes.int32) 44 inputs_flat = [tensor, shape] 45 attrs = ("T", attr_t, "Tshape", attr_tshape) 46 result, = execute.execute( 47 b"Reshape", 1, inputs=inputs_flat, attrs=attrs, ctx=ctx) 48 return result 49 50 51def _eager_fill(dims, value, ctx): 52 """Eager-only version of Fill op; requires value is an eager Tensor.""" 53 attr_t = value.dtype.as_datatype_enum 54 dims = convert_to_eager_tensor(dims, ctx, dtypes.int32) 55 inputs_flat = [dims, value] 56 attrs = ("T", attr_t, "index_type", types_pb2.DT_INT32) 57 result, = execute.execute( 58 b"Fill", 1, inputs=inputs_flat, attrs=attrs, ctx=ctx) 59 return result 60 61 62def _eager_identity(tensor, ctx): 63 """Eager-only version of Identity op; requires tensor is an eager Tensor.""" 64 attrs = ("T", tensor.dtype.as_datatype_enum) 65 result, = execute.execute( 66 b"Identity", 1, inputs=[tensor], attrs=attrs, ctx=ctx) 67 return result 68 69 70def convert_to_eager_tensor(value, ctx, dtype=None): 71 """Converts the given `value` to an `EagerTensor`. 72 73 Note that this function could return cached copies of created constants for 74 performance reasons. 75 76 Args: 77 value: value to convert to EagerTensor. 78 ctx: value of context.context(). 79 dtype: optional desired dtype of the converted EagerTensor. 80 81 Returns: 82 EagerTensor created from value. 83 84 Raises: 85 TypeError: if `dtype` is not compatible with the type of t. 86 """ 87 if isinstance(value, ops.EagerTensor): 88 if dtype is not None and value.dtype != dtype: 89 raise TypeError("Expected tensor with type %r not %r" % ( 90 dtype, value.dtype)) 91 return value 92 if dtype is not None: 93 try: 94 dtype = dtype.as_datatype_enum 95 except AttributeError: 96 dtype = dtypes.as_dtype(dtype).as_datatype_enum 97 ctx.ensure_initialized() 98 return ops.EagerTensor(value, ctx.device_name, dtype) 99 100 101@tf_export(v1=["constant"]) 102def constant_v1( 103 value, dtype=None, shape=None, name="Const", verify_shape=False): 104 """Creates a constant tensor. 105 106 The resulting tensor is populated with values of type `dtype`, as 107 specified by arguments `value` and (optionally) `shape` (see examples 108 below). 109 110 The argument `value` can be a constant value, or a list of values of type 111 `dtype`. If `value` is a list, then the length of the list must be less 112 than or equal to the number of elements implied by the `shape` argument (if 113 specified). In the case where the list length is less than the number of 114 elements specified by `shape`, the last element in the list will be used 115 to fill the remaining entries. 116 117 The argument `shape` is optional. If present, it specifies the dimensions of 118 the resulting tensor. If not present, the shape of `value` is used. 119 120 If the argument `dtype` is not specified, then the type is inferred from 121 the type of `value`. 122 123 For example: 124 125 ```python 126 # Constant 1-D Tensor populated with value list. 127 tensor = tf.constant([1, 2, 3, 4, 5, 6, 7]) => [1 2 3 4 5 6 7] 128 129 # Constant 2-D tensor populated with scalar value -1. 130 tensor = tf.constant(-1.0, shape=[2, 3]) => [[-1. -1. -1.] 131 [-1. -1. -1.]] 132 ``` 133 134 `tf.constant` differs from `tf.fill` in a few ways: 135 136 * `tf.constant` supports arbitrary constants, not just uniform scalar 137 Tensors like `tf.fill`. 138 * `tf.constant` creates a `Const` node in the computation graph with the 139 exact value at graph construction time. On the other hand, `tf.fill` 140 creates an Op in the graph that is expanded at runtime. 141 * Because `tf.constant` only embeds constant values in the graph, it does 142 not support dynamic shapes based on other runtime Tensors, whereas 143 `tf.fill` does. 144 145 Args: 146 value: A constant value (or list) of output type `dtype`. 147 148 dtype: The type of the elements of the resulting tensor. 149 150 shape: Optional dimensions of resulting tensor. 151 152 name: Optional name for the tensor. 153 154 verify_shape: Boolean that enables verification of a shape of values. 155 156 Returns: 157 A Constant Tensor. 158 159 Raises: 160 TypeError: if shape is incorrectly specified or unsupported. 161 """ 162 return _constant_impl(value, dtype, shape, name, verify_shape=verify_shape, 163 allow_broadcast=False) 164 165 166@tf_export("constant", v1=[]) 167def constant(value, dtype=None, shape=None, name="Const"): 168 """Creates a constant tensor from a tensor-like object. 169 170 Note: All eager `tf.Tensor` values are immutable (in contrast to 171 `tf.Variable`). There is nothing especially _constant_ about the value 172 returned from `tf.constant`. This function is not fundamentally different from 173 `tf.convert_to_tensor`. The name `tf.constant` comes from the `value` being 174 embedded in a `Const` node in the `tf.Graph`. `tf.constant` is useful 175 for asserting that the value can be embedded that way. 176 177 If the argument `dtype` is not specified, then the type is inferred from 178 the type of `value`. 179 180 >>> # Constant 1-D Tensor from a python list. 181 >>> tf.constant([1, 2, 3, 4, 5, 6]) 182 <tf.Tensor: shape=(6,), dtype=int32, 183 numpy=array([1, 2, 3, 4, 5, 6], dtype=int32)> 184 >>> # Or a numpy array 185 >>> a = np.array([[1, 2, 3], [4, 5, 6]]) 186 >>> tf.constant(a) 187 <tf.Tensor: shape=(2, 3), dtype=int64, numpy= 188 array([[1, 2, 3], 189 [4, 5, 6]])> 190 191 If `dtype` is specified, the resulting tensor values are cast to the requested 192 `dtype`. 193 194 >>> tf.constant([1, 2, 3, 4, 5, 6], dtype=tf.float64) 195 <tf.Tensor: shape=(6,), dtype=float64, 196 numpy=array([1., 2., 3., 4., 5., 6.])> 197 198 If `shape` is set, the `value` is reshaped to match. Scalars are expanded to 199 fill the `shape`: 200 201 >>> tf.constant(0, shape=(2, 3)) 202 <tf.Tensor: shape=(2, 3), dtype=int32, numpy= 203 array([[0, 0, 0], 204 [0, 0, 0]], dtype=int32)> 205 >>> tf.constant([1, 2, 3, 4, 5, 6], shape=[2, 3]) 206 <tf.Tensor: shape=(2, 3), dtype=int32, numpy= 207 array([[1, 2, 3], 208 [4, 5, 6]], dtype=int32)> 209 210 `tf.constant` has no effect if an eager Tensor is passed as the `value`, it 211 even transmits gradients: 212 213 >>> v = tf.Variable([0.0]) 214 >>> with tf.GradientTape() as g: 215 ... loss = tf.constant(v + v) 216 >>> g.gradient(loss, v).numpy() 217 array([2.], dtype=float32) 218 219 But, since `tf.constant` embeds the value in the `tf.Graph` this fails for 220 symbolic tensors: 221 222 >>> with tf.compat.v1.Graph().as_default(): 223 ... i = tf.compat.v1.placeholder(shape=[None, None], dtype=tf.float32) 224 ... t = tf.constant(i) 225 Traceback (most recent call last): 226 ... 227 TypeError: ... 228 229 `tf.constant` will _always_ create CPU (host) tensors. In order to create 230 tensors on other devices, use `tf.identity`. (If the `value` is an eager 231 Tensor, however, the tensor will be returned unmodified as mentioned above.) 232 233 Related Ops: 234 235 * `tf.convert_to_tensor` is similar but: 236 * It has no `shape` argument. 237 * Symbolic tensors are allowed to pass through. 238 239 >>> with tf.compat.v1.Graph().as_default(): 240 ... i = tf.compat.v1.placeholder(shape=[None, None], dtype=tf.float32) 241 ... t = tf.convert_to_tensor(i) 242 243 * `tf.fill`: differs in a few ways: 244 * `tf.constant` supports arbitrary constants, not just uniform scalar 245 Tensors like `tf.fill`. 246 * `tf.fill` creates an Op in the graph that is expanded at runtime, so it 247 can efficiently represent large tensors. 248 * Since `tf.fill` does not embed the value, it can produce dynamically 249 sized outputs. 250 251 Args: 252 value: A constant value (or list) of output type `dtype`. 253 dtype: The type of the elements of the resulting tensor. 254 shape: Optional dimensions of resulting tensor. 255 name: Optional name for the tensor. 256 257 Returns: 258 A Constant Tensor. 259 260 Raises: 261 TypeError: if shape is incorrectly specified or unsupported. 262 ValueError: if called on a symbolic tensor. 263 """ 264 return _constant_impl(value, dtype, shape, name, verify_shape=False, 265 allow_broadcast=True) 266 267 268def _constant_impl( 269 value, dtype, shape, name, verify_shape, allow_broadcast): 270 """Implementation of constant.""" 271 ctx = context.context() 272 if ctx.executing_eagerly(): 273 if trace.enabled: 274 with trace.Trace("tf.constant"): 275 return _constant_eager_impl(ctx, value, dtype, shape, verify_shape) 276 return _constant_eager_impl(ctx, value, dtype, shape, verify_shape) 277 278 g = ops.get_default_graph() 279 tensor_value = attr_value_pb2.AttrValue() 280 tensor_value.tensor.CopyFrom( 281 tensor_util.make_tensor_proto( 282 value, dtype=dtype, shape=shape, verify_shape=verify_shape, 283 allow_broadcast=allow_broadcast)) 284 dtype_value = attr_value_pb2.AttrValue(type=tensor_value.tensor.dtype) 285 attrs = {"value": tensor_value, "dtype": dtype_value} 286 const_tensor = g._create_op_internal( # pylint: disable=protected-access 287 "Const", [], [dtype_value.type], attrs=attrs, name=name).outputs[0] 288 289 if op_callbacks.should_invoke_op_callbacks(): 290 # TODO(b/147670703): Once the special-op creation code paths 291 # are unified. Remove this `if` block. 292 callback_outputs = op_callbacks.invoke_op_callbacks( 293 "Const", tuple(), attrs, (const_tensor,), op_name=name, graph=g) 294 if callback_outputs is not None: 295 const_tensor, = callback_outputs 296 return const_tensor 297 298 299def _constant_eager_impl(ctx, value, dtype, shape, verify_shape): 300 """Implementation of eager constant.""" 301 t = convert_to_eager_tensor(value, ctx, dtype) 302 if shape is None: 303 return t 304 shape = tensor_shape.as_shape(shape) 305 if shape == t.shape: 306 return t 307 if verify_shape: 308 raise TypeError("Expected Tensor's shape: %s, got %s." % 309 (tuple(shape), tuple(t.shape))) 310 num_t = t.shape.num_elements() 311 # TODO(josh11b): Implement shape -> eager tensor conversion. 312 if num_t == shape.num_elements(): 313 return _eager_reshape(t, shape.as_list(), ctx) 314 if num_t == 1: 315 if t.dtype == dtypes.bool: 316 # We don't have a Fill kernel for bool dtype on GPU. So we first run 317 # Fill on CPU and then copy to GPU if needed. 318 with ops.device("/device:CPU:0"): 319 x = _eager_fill(shape.as_list(), _eager_identity(t, ctx), ctx) 320 return _eager_identity(x, ctx) 321 else: 322 return _eager_fill(shape.as_list(), t, ctx) 323 raise TypeError("Eager execution of tf.constant with unsupported shape " 324 "(value has %d elements, shape is %s with %d elements)." % 325 (num_t, shape, shape.num_elements())) 326 327 328def is_constant(tensor_or_op): 329 if isinstance(tensor_or_op, ops.Tensor): 330 op = tensor_or_op.op 331 else: 332 op = tensor_or_op 333 return op.type == "Const" 334 335 336def _constant_tensor_conversion_function(v, dtype=None, name=None, 337 as_ref=False): 338 _ = as_ref 339 return constant(v, dtype=dtype, name=name) 340 341 342ops.register_tensor_conversion_function( 343 (list, tuple), _constant_tensor_conversion_function, 100) 344ops.register_tensor_conversion_function( 345 object, _constant_tensor_conversion_function, 200) 346 347 348def _tensor_shape_tensor_conversion_function(s, 349 dtype=None, 350 name=None, 351 as_ref=False): 352 """Function to convert TensorShape to Tensor.""" 353 _ = as_ref 354 if not s.is_fully_defined(): 355 raise ValueError( 356 "Cannot convert a partially known TensorShape to a Tensor: %s" % s) 357 s_list = s.as_list() 358 int64_value = 0 359 for dim in s_list: 360 if dim >= 2**31: 361 int64_value = dim 362 break 363 364 if dtype is not None: 365 if dtype not in (dtypes.int32, dtypes.int64): 366 raise TypeError("Cannot convert a TensorShape to dtype: %s" % dtype) 367 if dtype == dtypes.int32 and int64_value: 368 raise ValueError("Cannot convert a TensorShape to dtype int32; " 369 "a dimension is too large (%s)" % int64_value) 370 else: 371 dtype = dtypes.int64 if int64_value else dtypes.int32 372 if name is None: 373 name = "shape_as_tensor" 374 return constant(s_list, dtype=dtype, name=name) 375 376 377ops.register_tensor_conversion_function( 378 tensor_shape.TensorShape, _tensor_shape_tensor_conversion_function, 100) 379 380 381def _dimension_tensor_conversion_function(d, 382 dtype=None, 383 name=None, 384 as_ref=False): 385 """Function to convert Dimension to Tensor.""" 386 _ = as_ref 387 if d.value is None: 388 raise ValueError("Cannot convert an unknown Dimension to a Tensor: %s" % d) 389 if dtype is not None: 390 if dtype not in (dtypes.int32, dtypes.int64): 391 raise TypeError("Cannot convert a TensorShape to dtype: %s" % dtype) 392 else: 393 dtype = dtypes.int32 394 if name is None: 395 name = "shape_as_tensor" 396 return constant(d.value, dtype=dtype, name=name) 397 398 399ops.register_tensor_conversion_function( 400 tensor_shape.Dimension, _dimension_tensor_conversion_function, 100) 401