张量的结构操作
1.创建张量
常数张量:
a = tf.constant([1,2,3],dtype = tf.float32)
区间内恒定步长的张量:
b = tf.range(1,10,delta = 2)
tf.print(b) ==>[1 3 5 7 9]
区间内以总长度的n分之一为步长的张量
c = tf.linspace(0.0,2*3.14,100)
tf.print(c) ==> [0 0.0634343475 0.126868695 ... 6.15313148 6.21656609 6.28]
全零张量以及与某一张量结构相等的张量
d = tf.zeros([3,3])
b = tf.zeros_like(,dtype= tf.float32)
全1张量
a = tf.ones([3,3])
以某一数填充指定形状的张量
b = tf.fill([3,2],5)
均匀分布随机张量
tf.random.set_seed(1.0)
a = tf.random.uniform([5],minval=0,maxval=10)
tf.print(a) ===> [1.65130854 9.01481247 6.30974197 4.34546089 2.9193902]
正态分布随机张量
b = tf.random.normal([3,3],mean=0.0,stddev=1.0)
正态分布随机,剔除2倍方差以外数据重新生成
c = tf.random.truncated_normal((5,5), mean=0.0, stddev=1.0, dtype=tf.float32)
单位矩阵
I = tf.eye(3,3)
对角阵
t = tf.linalg.diag([1,2,3])
2.索引切片
提取张量的连续子区域:tf.slice.
不规则的切片提取:tf.gather,tf.gather_nd,tf.boolean_mask。
2.2.tf.slice.
tf.slice(input_, begin, size, name=None)
- size:切片的尺寸
- begin:开始位置,相当于相对输入数据
- input_的每一个偏移量
2.3.tf.gather
只能取某一维的不连续索引数据
tf.gather(
params, indices, validate_indices=None, axis=None, batch_dims=0, name=None
)
- params:输入
- indices:想要获取维度上的索引值
- axis:进行操作的维度
2.3.tf.gather_nd
tf.gather只能对低维度进行操作,gather_nd可以进行高维度的操作,允许在多维上进行索引,直接通过坐标取数(索引维度与tensor维度相同)
tf.gather_nd(
params, indices, batch_dims=0, name=None)
示例:
scores = tf.random.uniform((4,10,7),minval=0,maxval=100,dtype=tf.int32)
#抽取每个班级第0个学生,第5个学生,第9个学生的全部成绩
p = tf.gather(scores,[0,5,9],axis=1)
#抽取每个班级第0个学生,第5个学生,第9个学生的第1门课程,第3门课程,第6门课程成绩
q = tf.gather(tf.gather(scores,[0,5,9],axis=1),[1,3,6],axis=2)
# 抽取第0个班级第0个学生,第2个班级的第4个学生,第3个班级的第6个学生的全部成绩
#indices的长度为采样样本的个数,每个元素为采样位置的坐标
s = tf.gather_nd(scores,indices = [(0,0),(2,4),(3,6)])
2.4.tf.boolean_mask
tf.boolean_mask(tensor,mask,name='boolean_mask',axis=None)
tf.gather和tf.gather_nd的功能也可以用tf.boolean_mask来实现。
#抽取每个班级第0个学生,第5个学生,第9个学生的全部成绩
p = tf.boolean_mask(scores,[True,False,False,False,False,
True,False,False,False,True],axis=1)
#利用tf.boolean_mask可以实现布尔索引
#找到矩阵中小于0的元素
c = tf.constant([[-1,1,-1],[2,2,-2],[3,-3,3]],dtype=tf.float32)
tf.print(c,"\n")
tf.print(tf.boolean_mask(c,c<0),"\n")
tf.print(c[c<0]) #等价
3.修改张量的某些元素
如果要通过修改张量的部分元素值得到新的张量,可以使用tf.where和tf.scatter_nd
tf.where可以理解为if的张量版本,此外它还可以用于找到满足条件的所有元素的位置坐标。
tf.scatter_nd可以将某些值插入到一个给定shape的全0的张量的指定位置处。
3.1.tf.where
#将返回所有满足条件的位置坐标
tf.where(input, name=None)
#将a中对应input中true的位置的元素值不变
#其余元素进行替换,替换成b中对应位置的元素值。
tf.where(input, a,b)
3.2.tf.scatter_nd
tf.scatter_nd(indices,updates,shape,name=None)
示例
indices = tf.constant([[4], [3], [1], [7]])
updates = tf.constant([9, 10, 11, 12])
shape = tf.constant([8])
scatter = tf.scatter_nd(indices, updates, shape)
with tf.Session() as sess:
print(sess.run(scatter))
将全零张量[4][3][1][7]对应位置的元素变为
9、10、11、12
》》[0, 11, 0, 10, 9, 0, 0, 12]
相当于先生成一个形状为shape的全零张量,然后根据按照indices顺序下来的数字,将全零张量对应位置的元素变为updates顺序下来的数字
4.维度变换
维度变换相关函数主要有 tf.reshape, tf.squeeze, tf.expand_dims, tf.transpose.
4.1.tf.reshape ——改变张量的形状。
a = tf.random.uniform(shape=[1,3,3,2],
minval=0,maxval=255,dtype=tf.int32)
tf.print(a.shape)
tf.print(a)
# 改成 (3,6)形状的张量
b = tf.reshape(a,[3,6])
tf.print(b.shape)
tf.print(b)
运行结果对比:
TensorShape([1, 3, 3, 2])
[[[[135 178]
[26 116]
[29 224]]
TensorShape([3, 6])
[[179 219] ==========》 [[135 178 26 116 29 224]
[153 209] [179 219 153 209 111 215]
[111 215]] [39 7 138 129 59 205]]
[[39 7]
[138 129]
[59 205]]]]
4.2.tf.squeeze ——减少维度。
如果张量在某个维上只有一个元素,利用tf.squeeze可以消除这个维度。
和tf.reshape相似,它本质上不会改变张量元素的存储顺序。
张量的各个元素在内存中是线性存储的,其一般规律是,同一层级中的相邻元素的物理地址也相邻。
s = tf.squeeze(a)
tf.print(s.shape)
tf.print(s)
运行结果
TensorShape([3, 3, 2])
[[[135 178]
[26 116]
[29 224]]
[[179 219]
[153 209]
[111 215]]
[[39 7]
[138 129]
[59 205]]]
4.3.tf.expand_dims ——增加维度。
tf.expand_dims(input, axis, name=None)
在第axis位置增加一个维度
d = tf.expand_dims(s,axis=0) #在第0维插入长度为1的一个维度
#运行后,d又变回了a一样的形状:shape=(1, 3, 3, 2)
4.4.tf.transpose ——交换维度。
tf.transpose可以交换张量的维度,与tf.reshape不同,它会改变张量元素的存储顺序。
tf.transpose常用于图片存储格式的变换上
tf.transpose(a, perm=None, conjugate=False, name='transpose')
置换 a,根据 perm 重新排列尺寸,返回的张量的维度 i 将对应于输入维度 perm[i].如果 perm 没有给出,它被设置为(n-1 … 0)
5.合并分割
tf.concat和tf.stack方法对多个张量进行合并,可以用tf.split方法把一个张量分割成多个张量。
tf.concat和tf.stack有略微的区别,tf.concat是连接,不会增加维度,而tf.stack是堆叠,会增加维度。
5.1.tf.concat
tf.concat([tensor1, tensor2, tensor3,...], axis)
示例
a = tf.constant([[1.0,2.0],[3.0,4.0]])
b = tf.constant([[5.0,6.0],[7.0,8.0]])
c = tf.constant([[9.0,10.0],[11.0,12.0]])
tf.concat([a,b,c],axis = 0)
tf.concat([a,b,c],axis = 1)
结果对比:
<tf.Tensor: shape=(6, 2), dtype=float32, numpy=
array([[ 1., 2.],
[ 3., 4.], <tf.Tensor: shape=(2, 6), dtype=float32, numpy=
[ 5., 6.], ===》 array([[ 1., 2., 5., 6., 9., 10.],
[ 7., 8.], [ 3., 4., 7., 8., 11., 12.]], dtype=float32)>
[ 9., 10.],
[11., 12.]], dtype=float32)>
5.2.tf.stack
tf.stack(values, axis=0, name='stack')
示例:
tf.stack([a,b,c])
tf.stack([a,b,c],axis=1)
结果对比:
<tf.Tensor: shape=(3, 2, 2), dtype=float32, numpy=
tf.stack([a,b,c],axis=1)
array([[[ 1., 2.], <tf.Tensor: shape=(2, 3, 2), dtype=float32, numpy=
[ 3., 4.]], array([[[ 1., 2.],
[ 5., 6.],
[[ 5., 6.], ========》 [ 9., 10.]],
[ 7., 8.]],
[[ 3., 4.],
[[ 9., 10.], [ 7., 8.],
[11., 12.]]], dtype=float32)> [11., 12.]]], dtype=float32)>
5.3.tf.split
tf.concat的逆运算,可以指定分割份数平均分割,也可以通过指定每份的记录数量进行分割。
tf.split( value, num_or_size_splits, axis=0, num=None, name='split')
如果num_or_size_splits是一个整数,则value是沿着维度axis成num_or_size_splits分裂较小张量。这要求value.shape[axis]是整除num_or_size_splits
如果num_or_size_splits是1 d张量(或列表),然后value被分成len(num_or_size_splits)个小张量,沿着维度axis每个小张量的大小为尺寸是value在axis维的长度/len(num_or_size_splits)
x = tf.Variable(tf.random.uniform([5, 30], -1, 1))
# Split `x` into 3 tensors along dimension 1
s0, s1, s2 = tf.split(x, num_or_size_splits=3, axis=1)
tf.shape(s0).numpy()
==》array([5,10],dtype=32)
# Split `x` into 3 tensors with sizes [4, 15, 11] along dimension 1
split0, split1, split2 = tf.split(x, [4, 15, 11], 1)
tf.shape(split0).numpy()
==》array([5,4],dtype=32)
tf.shape(split1).numpy()
==》array([5,15],dtype=32)
tf.shape(split2).numpy()
==》array([5,11],dtype=32)