# Ops
# tf.constant
tf.convert_to_tensor
is similar but:
- It has no shape argument.
- Symbolic tensors are allowed to pass through.
# shape difference
t = tf.constant([1, 2, 3, 4, 5, 6], shape=[2, 3])
# symbolic tensors difference
with tf.compat.v1.Graph().as_default():
i = tf.compat.v1.placeholder(shape=[None, None], dtype=tf.float32)
t = tf.convert_to_tensor(i) # pass
t = tf.constant(i) # error
# tf.tile
a = tf.constant([[1,2,3],[4,5,6]], tf.int32)
b = tf.constant([1,2], tf.int32) # one for each dimension
# [[1,2,3,1,2,3],[4,5,6,4,5,6]]
tf.tile(a, b)
# tf.gather
api
tf.gather(
params, indices, validate_indices=None, axis=None, batch_dims=0, name=None
)
Remark: if r=tf.gather(input, ids, axis=0)
, tape.gradient(input) produces IndexedSlices which removed redundant 0s to save memory.
Gathering happens at tensors whose axes after batch_dims
, and thus axis >= batch_dims
; indices
defines slices into the axis
dimension of tensors.
# 1d indices without batch_dims
ps = np.random.uniform(-1, 1, (5, 2))
ids = [1,0]
# select rows
# (2,) + (2,) => (2, 2)
tf.gather(ps, ids, axis=0) # r[0] = ps[ids[0]]; r[1] = ps[ids[1]]
# select columns
# (5,) + (2,) => (5, 2)
tf.gather(ps, ids, axis=1) # r[:, 0] = ps[:, ids[0]]; r[:, 1] = ps[:, ids[1]]
# 2d indices without batch_dims
ps = np.random.uniform(-1, 1, (5, 2))
ids = np.random.randint(0, 2, (5, 3))
# select rows
# (5, 3) + (,2) => (5, 3, 2)
# for i in range(5):
# for j in range(3):
# r[i, j, :] = ps[ids[i, j], :]
tf.gather(ps, ids, axis=0)
# select cols
# (5, ) + (5, 3) => (5, 5, 3)
# for i in range(5):
# for j in range(3):
# r[:, i, j] = ps[:, ids[i, j]]
tf.gather(ps, ids, axis=1)
# 2d indices with batch_dims
ps = np.random.uniform(-1, 1, (5, 2))
ids = np.random.randint(0, 2, (5, 3))
# batch_dims = 0 takes no effect
tf.gather(ps, ids, axis=1, batch_dims=0)
# if axis = 1
# def manually_batched_gather(ps, ids, axis):
# batch_dims=1
# assert batch_dims <= axis
# assert ids.shape[0] == ps.shape[0]
# result = []
# for p,i in zip(ps, ids):
# r = tf.gather(p, i, axis=axis-batch_dims)
# result.append(r)
# return tf.stack(result)
tf.gather(ps, ids, axis=1, batch_dims=1) # (5, 3)
# 3d indices with batch_dims
ps = np.random.uniform(-1, 1, (3, 5, 2))
ids = np.random.randint(0, 2, (3, 5, 3))
tf.gather(ps, ids, axis=2, batch_dims=1) # (3, 5, 5, 3)
# if axis = batch_dims,
# for p0, i0 in zip(ps, ids):
# sub_result = []
# for p1, i1 in zip(p0, i0):
# r = tf.gather(p1, i1, axis=0)
# sub_result.append(r)
# result.append(tf.stack(sub_result))
# tf.stack(result)
tf.gather(ps, ids, axis=2, batch_dims=2) # (3, 5, 3)
# tf.gather_nd
api
tf.gather_nd(
params, indices, batch_dims=0, name=None
)
indices defines slices into the first indices.shape[-1]
dimensions of tensors and thus indices.shape[-1] <= params.rank
; The output tensor has shape: indices.shape[:-1] + params.shape[indices.shape[-1]:]
; if batch_dims
exists: apply tf.gather_nd
on tensors whose axes after batch_dims
"""
same rank
"""
indices = [[0, 0], [1, 1]]
params = [['a', 'b'], ['c', 'd']]
# ['a', 'd']
tf.gather_nd(params, indices)
indices = [[1], [0]]
params = [['a', 'b'], ['c', 'd']]
# [['c', 'd'], ['a', 'b']]
tf.gather(params, indices)
"""
indices have leading batch axes
"""
indices = [[[0, 0]], [[0, 1]]] # (2, 1, 2)
params = [['a', 'b'], ['c', 'd']] # (2, 2)
# [['a'], ['b']]
tf.gather_nd(params, indices)
indices = [[[1]], [[0]]] # (2, 1, 1)
params = [['a', 'b'], ['c', 'd']] # (2, 2)
# [[['c', 'd']], [['a', 'b']]]
tf.gather_nd(params, indices)
"""
batched indices and params
"""
indices = [[1], [0]] # (2, 1)
params = [
[['a0', 'b0'], ['c0', 'd0']],
[['a1', 'b1'], ['c1', 'd1']]
] # (2, 2, 2)
# [['c0', 'd0'], ['a1', 'b1']]
tf.gather_nd(params, indices, batch_dims = 1)
# tf.transpose
api
tf.transpose( a, perm=None, conjugate=False, name='transpose' )
a = tf.constant(
[
[1, 1, 1, 4],
[4, 0, 1, 1],
[3, 2, 4, 1]
]
)
b = tf.constant(
[
[3, 1, 3, 4],
[2, 4, 0, 4],
[3, 2, 4, 1]
]
)
"""
[
[[1, 3],
[4, 2],
[3, 3]],
[[1, 1],
[0, 4],
[2, 2]],
[[1, 3],
[1, 0],
[4, 4]],
[[4, 4],
[1, 4],
[1, 1]]
]
"""
tf.tanspose([a, b])
# tf.print
effective in graph execution
tf.print(tensor) # tensor value can be printed
tf.print(f'{tensor}') # empty tensor value