多个tensor的合并主要包括2个函数:tf.concat和tf.stack,他们的输出参数都是list of tensor。区别是:
import tensorflow as tf
a = tf.constant([[1,2,3],[4,5,6]])
b = tf.constant([[7,8,9],[10,11,12]])
ab1 = tf.concat([a,b],axis=0)
ab2 = tf.stack([a,b], axis=0)
sess = tf.Session()
print(sess.run(ab1))
print(sess.run(ab2))
print ab1
print ab2
结果:
[[ 1 2 3]
[ 4 5 6]
[ 7 8 9]
[10 11 12]]#ab1的值
[[[ 1 2 3]
[ 4 5 6]]
[[ 7 8 9]
[10 11 12]]]#ab2的值
Tensor("concat:0", shape=(4, 3), dtype=int32)#ab1的属性
Tensor("stack:0", shape=(2, 2, 3), dtype=int32)#ab2的属性
将1个tensor拆分成多个tensor,主要包括2个函数:tf.split和tf.unstack。区别是:
a = tf.constant([[1,2,3,4,5],[6,7,8,9,10]])
b = tf.split(a, 2, axis=0)
c = tf.split(a, [1,2,2], axis=1)
d = tf.unstack(a, axis=0)
e = tf.unstack(a, axis=1)
sess=tf.Session()
print(sess.run(b))
print(sess.run(c))
print(sess.run(d))
print(sess.run(e))
结果
[array([[1, 2, 3, 4, 5]], dtype=int32), array([[ 6, 7, 8, 9, 10]], dtype=int32)] #b
[array([[1],[6]], dtype=int32), array([[2, 3], [7, 8]], dtype=int32), array([[ 4, 5],[ 9, 10]], dtype=int32)] #c
[array([1, 2, 3, 4, 5], dtype=int32), array([ 6, 7, 8, 9, 10], dtype=int32)] #d
[array([1, 6], dtype=int32), array([2, 7], dtype=int32), array([3, 8], dtype=int32), array([4, 9], dtype=int32), array([ 5, 10], dtype=int32)] #e
常用多个tensor累加函数主要是tf.math.add, tf.math.add_n和+运算符。区别:
a = tf.constant([[3, 5], [4, 8]])
b = tf.constant([[1, 6], [2, 9]])
c = tf.constant([1])
d = tf.math.add_n([a, b, a])
e = tf.math.add(a, c)
f = a + c
sess=tf.Session()
print(sess.run(d))
print(sess.run(e))
print(sess.run(f))
结果:
[[ 7 16]
[10 25]] #d
[[4 6]
[5 9]] #e
[[4 6]
[5 9]] #f
tensor的转置主要用tf.transpose函数,tf.transpose(a, perm=None, conjugate=False, name=‘transpose’),其中a是源tensor,perm是排列顺序,conjugate是bool参数用于复数共轭配置。在一些维度变换场景很有用。
import tensorflow as tf
a = tf.constant([[[1,2],[3,4]],[[5,6],[7,8]]])
b = tf.transpose(a)
c = tf.transpose(a, [0,2,1])
sess = tf.Session()
print(sess.run(a))
print(sess.run(b))
print(sess.run(c))
结果:
[[[1 2]
[3 4]]
[[5 6]
[7 8]]] # a
[[[1 5]
[3 7]]
[[2 6]
[4 8]]] # b
[[[1 3]
[2 4]]
[[5 7]
[6 8]]] # c
默认perm是将源tensor的维度逆向,原始a是3维tensor,那么对应的转置b应该是将a的[0,1,2]维向量放到[2,1,0]维的位置,比如a中的7的坐标是(1, 1, 0),那么转置之后其坐标刚好颠倒是(0, 1, 1)。对于c是指定了perm参数,也就指定了转置顺序是[0, 2, 1],也就是第0维不变,第1和2维互换位置,那么a中7在c中的位置就是(1, 0, 1)。
上面可能有些抽象,在实际场景中,transpose常常用于多维tensor的调整。如下,获取特征embedding的过程:
# 一个常见的特征embedding过程
def get_features_embedding(self, features):
multi_field_embedings = []
for fea in features:
# every fea is batch_size*multi_value_size
field_embedding = tf.nn.embedding_lookup(self.embeddings, fea)
# multi_value feature embedding mean
field_embedding = tf.reduce_mean(field_embedding, [1])
multi_field_embedings.append(field_embedding)
# multi_field_size * batch_size * embedding_size
features_embedding = tf.stack(multi_field_embedings)
# batch_size * multi_field_size * embedding_size
features_embedding = tf.transpose(features_embedding, (1, 0, 2))
# batch_size * (multi_field_size * embedding_size)
features_embedding = tf.reshape(
features_embedding, (-1, self.fields_size * self.embedding_size))
return features_embedding