合并是将多个张量在某个维度上合并为一个张量。合并的两种方式:拼接和堆叠。
张量的合并:
(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)
合并的逆过程就是分割,将一个张量拆分成多个张量。
语法:
tf.split(x,num_or_size_splits,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 )
在神经网络中经常要统计各种数据:最值、最值位置、均值、范数等信息。
向量范数(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)
(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)
对于图片数据的高和宽、序列信号的长度,维度长度可能各不相同。为了方便网络的并行计算,需要将不同长度的数据扩张为相同长度,通常的做法是,在需要补充长度的数据开始或结束处填充足够数量的特定数值,这些特定数值一般代表了无效意义,例如 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)
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)
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)
语法: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)
语法: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)
语法: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)
语法:过 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)
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)
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()