# 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
Last Updated: 8/4/2022, 9:56:44 PM