【TensorFlow2.0】张量合并&分割、数据统计、比较、填充与复制、数据限幅、高级操作

一、张量合并与分割

1.1合并

  合并是将多个张量在某个维度上合并为一个张量。合并的两种方式:拼接和堆叠。
  张量的合并:
  (1)拼接concat:语法:
tf.concat(tensor_list,axis),tensor_list保存了所有要拼接的张量,是一个列表,axis参数指定需要合并的维度索引。拼接操作不会产生新的维度,仅在现有的维度上合并。 拼接操作的唯一约束是非拼接的维度长度必须一致。

import tensorflow as tf

#拼接案例1
a=tf.random.normal([4,35,8])
b=tf.random.normal([6,35,8])
c=tf.concat([a,b],axis=0)
print(c)
print(c.shape)#(10, 35, 8)

#拼接案例2
a=tf.random.normal([10,35,4])
b=tf.random.normal([10,35,4])
c=tf.concat([a,b],axis=2)
print(c)
print(c.shape)#(10, 35, 8)

   (2)堆叠stack:语法: tf.stack(tensors_list, axis)通过 tensors 列表堆叠合并多个张量,参数axis 指定新维度插入的位置,axis 的用法与 tf.expand_dims 的一致,当axis ≥ 0时,在 axis之前插入;当axis < 0时,在 axis 之后插入新维度堆叠会产生新的维度。堆叠合并操作的唯一约束是待合并的张量必须shape完全一致。

import tensorflow as tf

#堆叠,新维度在最前面
a=tf.random.normal([35,8])
b=tf.random.normal([35,8])
c=tf.stack([a,b],axis=0)
print(c)
print(c.shape)#(2, 35, 8)

#堆叠,新维度在末尾
a=tf.random.normal([35,4])
b=tf.random.normal([35,4])
c=tf.stack([a,b],axis=-1)
print(c)
print(c.shape)#( 35, 4,2)

1.2 分割

  合并的逆过程就是分割,将一个张量拆分成多个张量。
  语法:
  tf.split(x,num_or_size_splits,axis)可以完成张量的分割操作
,参数意义如下:

  • x 参数:待分割张量。
  • num_or_size_splits 参数:切割方案。当 num_or_size_splits 为单个数值时,如 10,表示等长切割为 10 份;当 num_or_size_splits 为 List 时,List 的每个元素表示每份的长度,如[2,4,2,2]表示切割为 4 份,每份的长度依次是 2、4、2、2。
  • axis 参数:指定分割的维度索引号。
import tensorflow as tf

x = tf.random.normal([10,35,8])
result = tf.split(x, num_or_size_splits=10, axis=0)
print(len(result))#10,每一份数据时shape=(35,8)

x = tf.random.normal([10,35,8])
result = tf.split(x, num_or_size_splits=[4,2,2,2] ,axis=0)
print(len(result))#4,每一份shape=(4,35,8)、(2,35,8 )、(2,35,8 )、(2,35,8 )

二、张量数据统计

  在神经网络中经常要统计各种数据:最值、最值位置、均值、范数等信息。

2.1 向量范数

  向量范数(Vector Norm)是表征向量“长度”的一种度量方法,它可以推广到张量上。在神经网络中,常用来表示张量的权值大小,梯度大小等。
  常用范数:
                  在这里插入图片描述
  对于矩阵和张量,同样可以利用向量范数的计算公式,等价于将矩阵和张量打平成向量后计算。
  语法:tf.norm(x,ord),参数ord指定为1、2时计算L1、L2范数,指定np.inf时计算无穷范数。

import tensorflow as tf
import numpy as np

x=tf.ones([2,2])
#计算L1范数
l1=tf.norm(x,1)
print(l1)#tf.Tensor(4.0, shape=(), dtype=float32)

#计算L2范数
l2=tf.norm(x,ord=2)
print(l2)#tf.Tensor(2.0, shape=(), dtype=float32)

#计算无穷范数
l=tf.norm(x,ord=np.inf)
print(l)#tf.Tensor(1.0, shape=(), dtype=float32)

2.2 最值、均值、和

  (1)某维度最大、最小、均值、和:
  某维度最大:tf.reduce_max(x,axis)
  某维度最小:tf.reduce_min(x,axis)
  某维度均值:tf.reduce_mean(x,axis)
  某维度和: tf.reduce_sum(x,axis)

  (2)全局最大、最小、均值、和:
  全局最大:tf.reduce_max(x)
  全局最小:tf.reduce_min(x)
  全局平均:tf.reduce_mean(x)
  全局和: tf.reduce_sum(x)

  (3)获取张量最值信息和最值的索引号:
  最大值位置索引:tf.argmax(x,axis)
  最小值位置索引:tf.argmin(x,axis)

import tensorflow as tf
import numpy as np



'''某一维度:最值均值和'''
x=tf.random.normal([4,10])#第一维度代表样本数量,第二维度代表10个类别的概率值。
#统计概率维度上的最大值--每个样本的最大概率值
max=tf.reduce_max(x,axis=1)
print(max)#tf.Tensor([0.32707277 2.2314672  1.4582669  1.5522915 ], shape=(4,), dtype=float32)分别代表每个样本的最大概率值

#统计概率维度上的最小值--每个样本的最小概率值
min=tf.reduce_min(x,axis=1)
print(min)#tf.Tensor([-0.7575411  -1.144984   -0.61734384 -1.7668991 ], shape=(4,), dtype=float32)

#统计概率维度上的均值--每个样本的概率均值
mean=tf.reduce_mean(x,axis=1)
print(mean)#tf.Tensor([ 0.43950924  0.23992701 -0.05367586  0.26994142], shape=(4,), dtype=float32)

#求解张量在axis上所有特征和
sum=tf.reduce_sum(x,axis=-1)
print(sum)#tf.Tensor([ 0.06974554 -0.67806935 -2.8203702   2.9947762 ], shape=(4,), dtype=float32)


'''全局:最值均值和'''
x=tf.random.normal([4,10])#第一维度代表样本数量,第二维度代表10个类别的概率值。
#全局最大,最小,均值,和--返回的张量均为标量
print(tf.reduce_max(x),tf.reduce_min(x),tf.reduce_mean(x),tf.reduce_sum(x))
#tf.Tensor(1.5464976, shape=(), dtype=float32) tf.Tensor(-2.17722, shape=(), dtype=float32) tf.Tensor(-0.032227267, shape=(), dtype=float32) tf.Tensor(-1.2890906, shape=(), dtype=float32)

'''案例:求解误差函数时,通过tensorflow的MSE误差函数可以求得每个样本的误差,需要计算样本的平均误差,可以通过tf.reduce_mean()在样本维度上计算均值'''
#模拟网络预测输出
out=tf.random.normal([4,10])#第一维度代表样本数量,第二维度代表10个类别的概率值。
#模拟真实标签
y=tf.constant([1,2,2,0])
y=tf.one_hot(y,depth=10)#one_hot编码
#计算每个样本的误差
loss=tf.keras.losses.MSE(y,out)
print(loss)#tf.Tensor([1.3323901 1.2373894 1.2509155 1.4755952], shape=(4,), dtype=float32)
#计算平均误差,在样本维度上取均值
loss=tf.reduce_mean(loss)
print(loss)#tf.Tensor(1.3240726, shape=(), dtype=float32)

'''最值信息,最值的索引号'''
out=tf.random.normal([2,10])
out=tf.nn.softmax(out,axis=1)#通过softmax函数转换为概率值
print(out)
# tf.Tensor(
# [[0.02040164 0.12523262 0.20006388 0.13206287 0.23304975 0.02649408
#   0.01667572 0.03516654 0.03783604 0.17301682]
#  [0.06561878 0.19697422 0.01451845 0.0484349  0.15745974 0.3633224
#   0.04232501 0.02555983 0.05255225 0.03323451]], shape=(2, 10), dtype=float32)
pre=tf.argmax(out,axis=1)#选取概率最大的位置
print(pre)#tf.Tensor([6 2], shape=(2,), dtype=int64)

三、张量比较

  张量比较函数:
  语法:
  (1)相等:tf.equal(a,b)
  (2)其他函数:

              在这里插入图片描述

import tensorflow as tf
import numpy as np

#模拟输出
out=tf.random.normal([100,10])
#输出转概率
out=tf.nn.softmax(out,axis=1)#输出转换为概率:通过softmax函数转换为概率值
#计算预测值
pred=tf.argmax(out,axis=1)
print(pred)#变量保存了100个样本的预测类别值。
# tf.Tensor(
# [2 9 7 6 5 7 2 9 8 0 2 4 4 8 3 2 0 3 1 8 8 2 0 6 6 4 9 4 4 8 2 3 4 4 2 0 1
#  1 7 1 8 4 7 4 3 9 6 8 4 3 5 6 3 0 0 0 0 3 2 0 8 6 3 7 5 7 1 6 0 6 9 5 3 0
#  1 4 5 6 5 4 8 5 4 7 4 7 1 0 9 9 8 9 8 1 2 3 0 0 0 2], shape=(100,), dtype=int64)

#模拟真实标签
y=tf.random.uniform([100],dtype=tf.int64,maxval=10)

#用100个样本预测值与真实标签比较
out=tf.equal(pred,y)#返回布尔张量
print(out)
# tf.Tensor(
# [False False False  True False False False False False False False False
#  False False False False False False False False False  True False False
#  False False False False False False False False False False False False
#  False  True False False False False False False  True False False False
#  False  True False False False False  True False False False False False
#  False False False  True False False False False False False False False
#  False False False False False False  True False False False False False
#  False False False False False False False False False False False False
#  False False False  True], shape=(100,), dtype=bool)

#布尔张量转换为整形张量
out=tf.cast(out,dtype=tf.int16)
print(out)
# tf.Tensor(
# [1 1 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0
#  0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0
#  0 0 0 0 0 0 0 0 1 0 0 1 0 1 0 0 0 1 0 0 0 0 1 0 0 0], shape=(100,), dtype=int16)

#统计正确预测的个数
correct=tf.reduce_sum(out)
print(correct)#tf.Tensor(14, shape=(), dtype=int16)

四、张量填充与复制

4.1 填充

  对于图片数据的高和宽、序列信号的长度,维度长度可能各不相同。为了方便网络的并行计算,需要将不同长度的数据扩张为相同长度,通常的做法是,在需要补充长度的数据开始或结束处填充足够数量的特定数值,这些特定数值一般代表了无效意义,例如 0,使得填充后的长度满足系统要求。那么这种操作就叫作填充(Padding)。
  语法:tf.pad(x,paddings),参数paddings是包含多个[left padding,right paddings]的嵌套list。
  例:[[0,0],[2,1],[1,2]]表示第一个维度不填充,第二个维度左边(起始处)填充两个单元,右边(结束处)填充一个单元,第三个维度左边填充一个单元,右边填充两个单元。
  实践1:

import tensorflow as tf
import numpy as np
a=tf.constant([1,2,3,4,5,6])#第一个句子
old_b=tf.constant([7,8,1,6])#第二个句子

#第二个句子填充使两个句子长度相同
new_b=tf.pad(old_b,[[0,2]])
print(new_b)#tf.Tensor([7 8 1 6 0 0], shape=(6,), dtype=int32)

#两个句子拼接
c=tf.stack([a,new_b])
# print(c)
# #tf.Tensor(
# [[1 2 3 4 5 6]
#  [7 8 1 6 0 0]], shape=(2, 6), dtype=int32)

'''案例:以IMDB数据集为例,如何将不等长的句子变为等长结构'''
total_words=10000#设定词汇量大小
#最大句子长度
max_review_len=80
#词向量长度
embadding_len=100

#加载IMDB数据集
(x_train,y_train),(x_test,y_test)=tf.keras.datasets.imdb.load_data(num_words=total_words)
#将句子填充或截断到相同的长度,设置末尾填充或截断方式
x_train=tf.keras.preprocessing.sequence.pad_sequences(x_train,maxlen=max_review_len,truncating='post',padding='post')
x_test=tf.keras.preprocessing.sequence.pad_sequences(x_test,maxlen=max_review_len,truncating='post',padding='post')
print(x_train.shape,x_test.shape)#(25000, 80) (25000, 80)

  实践2:对图片进行填充
                  在这里插入图片描述

import tensorflow as tf
import numpy as np
x=tf.random.normal([4,28,28,3])
x=tf.pad(x,[[0,0],[2,2],[2,2],[0,0]])
print(x.shape)#(4, 32, 32, 3)

4.2 复制

  tf.tile 函数除了可以对长度为 1 的维度进行复制若干份,还可以对任意长度的维度进行复制若干份,进行复制时会根据原来的数据次序重复复制。
  语法:tf.tile(x,multiples=[])
   例:通过 tf.tile 函数可以在任意维度将数据重复复制多份,如 shape [4,32,32,3]的数据,复制方案为 multiples=[2,3,3,1],即通道数据不复制,高和宽方向分复制 2 份,图片数再复制 1 份。

import tensorflow as tf
x=tf.random.normal([4,32,32,3])
x=tf.tile(x,multiples=[2,2,2,1])#数据复制
print(x.shape)#(8, 64, 64, 3)

五、数据限幅

  在 TensorFlow 中:
  (1)通过 tf.maximum(x, a)实现数据的下限幅,即𝑥 ∈ [𝑎, +∞);
  (2)通过 tf.minimum(x, a)实现数据的上限幅,即𝑥 ∈ (−∞,𝑎];

  实现上下边界限幅:
  (1)通过 tf.minimum(tf.maximum(x,b), a);
  (2)通过tf.clip_by_value(x,min,max)

import tensorflow as tf

x=tf.range(9)
print(x)#tf.Tensor([0 1 2 3 4 5 6 7 8], shape=(9,), dtype=int32)

#下限为2
x1=tf.maximum(x,2)
print(x1)#tf.Tensor([2 2 2 3 4 5 6 7 8], shape=(9,), dtype=int32)


#上限为7
x2=tf.minimum(x,7)
print(x2)#tf.Tensor([0 1 2 3 4 5 6 7 7], shape=(9,), dtype=int32)

'''组合maximum和minimum可以同时实现数据上下限限制即x∈【a,b】/通过tf.clip_by_value实现上下幅限制'''
x=tf.range(9)
print(x)#tf.Tensor([0 1 2 3 4 5 6 7 8], shape=(9,), dtype=int32)

x1=tf.minimum(tf.maximum(x,2),5)
print(x1)#tf.Tensor([2 2 2 3 4 5 5 5 5], shape=(9,), dtype=int32)

x2=tf.clip_by_value(x,2,5)#限幅2-5
print(x2)#tf.Tensor([2 2 2 3 4 5 5 5 5], shape=(9,), dtype=int32)

六、高级操作

6.1 tf.gather()

  语法:tf.gather(x,[索引],axis)   根据索引号搜集x张量的axis维度的数据

import tensorflow as tf
#成绩张量【4,35,8】四个班级,35个学生,8个成绩
x=tf.random.uniform([4,35,8],maxval=100,dtype=tf.int32)

'''索引号:有顺序'''
#收集1-2号班级的成绩
x1=tf.gather(x,[0,1],axis=0)#在班级维度收集1-2班
print(x1.shape)#(2, 35, 8)

#收集第1,4,9,12,13,27,号同学的成绩
x2=tf.gather(x,[1,4,9,12,13,27],axis=1)
print(x2.shape)
print(x2)#(4, 6, 8)
# tf.Tensor(
# [[[25 94 99 16 61 10 67 41]
#   [40 35 39 91  4 98 46 73]
#   [68 76 17 83 28 99 17 39]
#   [67 28 16 93 98 67 69 86]
#   [30  6 88  5 51 79  4  2]
#   [45 28 92 42 20 53 84 63]]
#   。。。
#
#  [[82 68 48 57 81 36  3 17]
#   [31 24 48 20 26 36 20 60]
#   [15 63 39 17 90 94 47 96]
#   [52  4 66  8 91 93 65  1]
#   [37 96  6 41 96  4 76 82]
#   [ 8 71 28 64 55 15 90 91]]], shape=(4, 6, 8), dtype=int32)

#收集所有同学的第3和第5门成绩
x2=tf.gather(x,[3,5],axis=2)
print(x2.shape)#(4, 35, 2)

'''索引号:无顺序'''
a=range(8)
a=tf.reshape(a,[4,2])
print(a)
#收集4,2,1,3号数据
out=tf.gather(a,[3,1,0,2],axis=0)
print(out)

'''实践:'''
#成绩张量【4,35,8】四个班级,35个学生,8个成绩
x=tf.random.uniform([4,35,8],maxval=100,dtype=tf.int32)

#抽查【2,3】班级第【3,4,6,27】号同学的科目成绩
classs=tf.gather(x,[1,2],axis=0)
print(classs.shape)#(2, 35, 8)
student=tf.gather(classs,[2,3,5,26],axis=1)
print(student.shape)#(2, 4, 8)

6.2 tf.gather_nd()

  语法:tf.gather_nd(x,[索引])   指定每次采样点的多维坐标索引来实现采样多个点
  例:抽查第 2 个班级的第 2 个同学的所有科目,第 3 个班级的第 3 个同学的所有科目,第 4 个班级的第 4 个同学的所有科目。那么这 3 个采样点的索引坐标可以记为:[1,1]、[2,2]、[3,3],我们将这个采样方案合并为一个 List 参数,即[[1,1],[2,2],[3,3]],通过 tf.gather_nd 函数即可实现。

import tensorflow as tf
#成绩张量【4,35,8】四个班级,35个学生,8个成绩
x=tf.random.uniform([4,35,8],maxval=100,dtype=tf.int32)

#根据多维坐标收集数据:2班2号同学,3班3号同学,4班4号同学的成绩
a=tf.gather_nd(x,[[1,1],[2,2],[3,3]])
print(a.shape)#(3, 8)
print(a)
# tf.Tensor(
# [[79 12 92 85 52 91 32 40]
#  [79 97 71 34 15 73 27 17]
#  [33 69 93 18 99 52 18 30]], shape=(3, 8), dtype=int32)

#根据多维坐标收集数据:2班2号同学3门课的成绩,,,,
a=tf.gather_nd(x,[[1,1,2],[2,2,3],[3,3,3]])
print(a.shape)#(3,)
print(a)#tf.Tensor([92 34 18], shape=(3,), dtype=int32)

6.3 tf.boolean_mask()

  语法:tf.boolean_mask(x,mask,axis)   给定axis轴上根据mask方案进行采样。掩码的长度必须与轴维度的长度相同。

import tensorflow as tf
'''一维掩码采样'''
#成绩张量【4,35,8】四个班级,35个学生,8个成绩
x=tf.random.uniform([4,35,8],maxval=100,dtype=tf.int32)

#根据掩码方案采样班级
c=tf.boolean_mask(x,mask=[True,False,True,True],axis=0)
print(c.shape)#(3, 35, 8)

#根据掩码方案采样科目
b=tf.boolean_mask(x,mask=[True,False,True,True,True,False,True,True],axis=2)
print(b.shape)#(4, 35, 6)

'''多维掩码采样:'''
#成绩张量【2,3,8】2个班级,3个学生,8个成绩
x=tf.random.uniform([2,3,8],maxval=100,dtype=tf.int32)
#多维采集三个同学成绩
s=tf.gather_nd(x,[[0,0],[0,1],[1,1],[1,2]])
print(s.shape)#(4, 8)
#或
s=tf.boolean_mask(x,[[True,True,False],[False,True,True]])
print(s.shape)#(4, 8)

6.4 tf.where()

   语法:过 tf.where(cond, a, b)操作可以根据 cond 条件的真假从参数𝑨或𝑩中读取数据,条件判定规则如下:
                  在这里插入图片描述
  其中𝑖为张量的元素索引,返回的张量大小与𝑨和𝑩一致,当对应位置的cond𝑖为 True,𝑜𝑖从𝑎𝑖中复制数据;当对应位置的cond𝑖为 False,𝑜𝑖从𝑏𝑖中复制数据。
  如果a=b=None时,tf.where会返回cond张量中所有True的元素的索引坐标。

import tensorflow as tf
a=tf.ones([3,3])
b=tf.zeros([3,3])
#构造采样条件
cond=tf.constant([[True,False,False],[False,True,False],[True,True,False]])

'''a,b参数指定:'''
#根据条件在a,b中采样
out=tf.where(cond,a,b)
print(out)
# tf.Tensor(
# [[1. 0. 0.]
#  [0. 1. 0.]
#  [1. 1. 0.]], shape=(3, 3), dtype=float32)

'''a,b为None即参数不指定:返回cond中True的坐标索引'''
print(cond)
# tf.Tensor(
# [[ True False False]
#  [False  True False]
#  [ True  True False]], shape=(3, 3), dtype=bool)
out=tf.where(cond)
print(out)
# tf.Tensor(
# [[0 0]
#  [1 1]
#  [2 0]
#  [2 1]], shape=(4, 2), dtype=int64)

'''实践:'''
#构造a
a=tf.random.normal([3,3])
print(a)
# tf.Tensor(
# [[ 0.15166153  0.87628734  0.07919102]
#  [ 1.5394714  -0.45083565  1.4338578 ]
#  [-1.2263311  -2.1671493   0.77366763]], shape=(3, 3), dtype=float32)

#通过比较运算得到正数掩码
mask=a>0
print(mask)
# tf.Tensor(
# [[ True  True  True]
#  [ True False  True]
#  [False False  True]], shape=(3, 3), dtype=bool)

#通过tf.where提取掩码为True处的索引坐标
indices=tf.where(mask)
print(indices)
# tf.Tensor(
# [[0 0]
#  [0 1]
#  [0 2]
#  [1 0]
#  [1 2]
#  [2 2]], shape=(6, 2), dtype=int64)

#提取所有正数的数据
z=tf.gather_nd(a,indices)
print(z)#tf.Tensor([0.15166153 0.87628734 0.07919102 1.5394714  1.4338578  0.77366763], shape=(6,), dtype=float32)

6.5 scatter_nd()

   tf.scatter_nd(indices, updates, shape)  函数可以高效地刷新张量的部分数据,但是这个函数只能在全 0 的白板张量上面执行刷新操作。
  白板的形状通过 shape 参数表示,需要刷新的数据索引号通过 indices 表示,新数据为 updates。根据 indices 给出索引位置将 updates 中新的数据依次写入白板中,并返回更新后的结果张量。
            在这里插入图片描述

import tensorflow as tf

#创建需要刷新数据的位置索引
indices=tf.constant([[4],[3],[1],[7]])
#构造需要写入的数据,4号为写入4.4,3号位写入3.3
updates=tf.constant([4.4,3.3,1.1,7.7])

#在长度为8的全0向量上根据indicate写入updates数据。
new=tf.scatter_nd(indices, updates, [8])
print(new)#.Tensor([0.  1.1 0.  3.3 4.4 0.  0.  7.7], shape=(8,), dtype=float32)

6.6 meshgrid()

  tf.meshgrid 函数可以方便地生成二维网格的采样点坐标,方便可视化。

import tensorflow as tf

x = tf.linspace(-8.,8,100) # 设置 x 轴的采样点
y = tf.linspace(-8.,8,100) # 设置 y 轴的采样点
x,y = tf.meshgrid(x,y) # 生成网格点,并内部拆分后返回
print(x.shape,y.shape)#(100, 100) (100, 100)

z = tf.sqrt(x**2+y**2)
z = tf.sin(z)/z # sinc 函数实现

import matplotlib
from matplotlib import pyplot as plt
# 导入 3D 坐标轴支持
from mpl_toolkits.mplot3d import Axes3D
fig = plt.figure()
ax = Axes3D(fig) # 设置 3D 坐标轴
# 根据网格点绘制 sinc 函数 3D 曲面
ax.contour3D(x.numpy(), y.numpy(), z.numpy(), 50)
plt.show()
  • 0
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值