tensorflow2基础 2节

1.合并与分割

合并张量是指将多个张量在某个维度上合并为一个张量。以某学校某年级成绩册数据为例,设张量A的shape = [4,35,8]。表示1~4号班级,每个班级35名学生的8门科目成绩。张量B的shape = [6,35,8]。表示5~10号班级的乘积。我们通过合并两个张量就可以得到这个学校这个年级的成绩册。这就是合并张量的意义所在。

1.1 拼接 tf.concat(tensors, axis)

拼接操作不会产生新的维度,仅仅在现有维度上进行合并。注意除了拼接维度,其他维度必须相同,否则不合法。

import tensorflow as tf

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

1.2 堆叠 tf.stack(tensors, axis)

堆叠:如果合并数据时希望创建一个新的维度,则需要使用tf.stack操作。考虑张量A保存了某个班级成绩A.shape=[35,8],张量B保存了另一个班级的成绩,B.shape=[35,8]。我们堆叠两个张量就可以得到张量C,C.shape=[2,35,8]。表示两个班级的成绩。

import tensorflow as tf

a = tf.random.normal([35,8])
b = tf.random.normal([35,8])
c = tf.stack([a,b],axis=0)#axis表示新增的维度位置
print(c.shape)
#(2, 35, 8)

1.3 分割tf.split(x,num_or_size_splits,axis)

分割就是合并的逆操作,返回的是分割后的张量的列表。

import tensorflow as tf

a = tf.random.normal([10,35,8])
b = tf.split(a,num_or_size_splits=10,axis=0)#分为10个张量
c = tf.split(a,[2,2,6],axis=0)#分成2,2,6三个张量

2.数据统计

在神经网络的计算过程中,经常需要统计数据的各种属性,如最值、最值位置、均值、范数等信息。由于张量通常较大,直观观察数据很难获得有用信息,通过获取这些张量的统计信息可以较轻松地推测张量数值的分布。

2.1向量范数

向量范数(vector norm):是表征向量“长度”的一种度量方法,它可以推广到张量上。在神经网络中,常用来表示张量的权值大小,梯度大小等。常用的向量范数有:

L1范数,定义为向量x的所有元素绝对值之和:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PadTQoUt-1647417873726)(tensorflow基础2.assets/p1.png)]

L2范数, 定义为向量x的所有元素的平方和,再开根号:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3aEMku6p-1647417873727)(tensorflow基础2.assets/p2.png)]

∞ - 范数,定义为向量x的所有元素绝对值的最大值:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-09M8zhez-1647417873728)(tensorflow基础2.assets/p3.png)]

import tensorflow as tf
import numpy as np

a = tf.ones([2,2])
print(a)
print(tf.norm(a,ord=1))#L1范数
print(tf.norm(a,ord=2))#L2范数
print(tf.norm(a,ord=np.inf))#∞-范数

"""打印结果:
tf.Tensor(
[[1. 1.]
 [1. 1.]], shape=(2, 2), dtype=float32)
tf.Tensor(4.0, shape=(), dtype=float32)
tf.Tensor(2.0, shape=(), dtype=float32)
tf.Tensor(1.0, shape=(), dtype=float32)
"""
2.2最值、均值、和

最大值、最小值tf.redunce_max(),tf.reduce_min()

import tensorflow as tf

a = tf.random.normal([4,10])
b = tf.reduce_max(a,axis=1)#求索引1维度的最大值
c = tf.reduce_min(a,axis=1)#求索引1维度的最小值
print(b)
print(c)
"""打印结果:一维的张量,四个元素就是每一维度的最大值
tf.Tensor([0.2986992  0.6242858  1.6938254  0.70986885], shape=(4,), dtype=float32)
tf.Tensor([-1.4581685 -3.1063654 -1.5195384 -2.1331983], shape=(4,), dtype=float32)
"""

均值与和:tf.reduce_mean(),tf.reduce_sum()

import tensorflow as tf

a = tf.random.normal([4,10])
b = tf.reduce_mean(a,axis=1)
c = tf.reduce_sum(a,axis=1)
print(b)
print(c)
"""打印结果:
tf.Tensor([ 0.06940475 -0.5237468  -0.26578826 -0.4367209 ], shape=(4,), dtype=float32)
tf.Tensor([ 0.6940475 -5.237468  -2.6578827 -4.367209 ], shape=(4,), dtype=float32)
"""

以上的方法,在不设置axis时对所有元素进行操作。

举个例子:在求解误差函数时计算样本平均误差

import tensorflow as tf
import numpy as np
from tensorflow.keras import losses

out = tf.random.normal([4,10])#模拟神经网络预测结果 4个数据分10类
y = tf.constant([1,2,2,0])#模拟正确解
y = tf.one_hot(y,depth=10)
loss = losses.mse(y, out)
loss = tf.reduce_mean(loss)
print(loss)
#tf.Tensor(1.086748, shape=(), dtype=float32)

通常我们还需要求最大值或最小值的索引,如下所示

import tensorflow as tf

a = tf.random.normal([4,10])
b = tf.argmax(a,axis=1)#求索引1维度的最大值索引
c = tf.argmin(a,axis=1)#求索引1维度的最小值索引
print(b)
print(c)
"""
tf.Tensor([7 6 8 1], shape=(4,), dtype=int64)
tf.Tensor([0 7 2 0], shape=(4,), dtype=int64)
"""

3.张量比较

一般我们为了计算分类任务的准确率等指标,需要将预测结果和真是标签比较,统计比较结果中正确的数量来计算准确率。举例如下:

import tensorflow as tf

out = tf.random.normal([100,10])
#100个样本的预测结果
pred = tf.argmax(out, axis = 1)
#张量pred是一维的,有一百个元素,每个元素就是预测正确解的索引
y = tf.random.uniform([100],dtype=tf.int64,maxval = 10)
#生成100个正确解索引

out = tf.equal(pred,y)
#比较两个张量,对应元素相等,则该位置是Ture,否则该位置是Fals

out = tf.cast(out, dtype=tf.int32)
#将bool类型转换为int型
correct = tf.reduce_sum(out)
#统计True的个数
accuracy = correct/out.y.shape
#正确率就是正确数量除以总数量

除了比较相等的tf.equal(a,b)函数,其他比较函数用法类似:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zvg6Gefg-1647417873729)(tensorflow基础2.assets/p4.png)]

4.填充与复制

4.1 填充

对于图片数据的宽和高、序列信号的长度,维度长度可能各不相同。为了方便网络的并行计算,需要将不同长度的数据扩张为相同长度,之前我们介绍了通过复制的方式可以增加数据的长度,但是重复复制数据会破坏原有的数据结构,并不适合此处。通常的做法是,在需要补充长度的数据开始或结束处填充足够数量的特定数值,这些特定数值一般代表了无效意义,例如0,使得填充后的长度满足系统要求。那么这种操作就叫作填充。

tf.pad(x,paddings) :paddings是填充策略的List包含了多个[left padding, right padding].如[[0,0],[2,1],[1,2]]表示第一个维度不填充,第二个维度左边填充两个单元,右边填充一个单元,第三个维度左边填充1个单元,右边填充2个单元。

举个例子:有一批图片数据[4,28,28,1], 将28 * 28的图片填充但32*32

import tensorflow as tf

x = tf.random.normal([4,28,28,1])

x = tf.pad(x, [[0,0],[2,2],[2,2],[0,0]])
print(x.shape)
#(4, 32, 32, 1)

4.2 复制

tf.title()可以对任意长度的维度进行复制。

import tensorflow as tf

x = tf.random.normal([4,28,28,1])

a = tf.tile(x,[2,1,1,3])
print(a.shape)
#(8, 28, 28, 3)

5.数据限幅

tf.maximum(x,a):把张量x的数据元素限制最大为a。

tf.minimum(x,a):把张量x的数据元素限制最小为a。

tf.clip_by_value(x,a,b):把张量x限制为最大b,最小a。

import tensorflow as tf

x = tf.range(-8,8)
x = tf.reshape(x,[4,4])
a = tf.maximum(x,0)
b = tf.minimum(x,0)
c = tf.clip_by_value(x,-2,2)
print(x)
print(a)
print(b)
print(c)
"""
tf.Tensor(
[[-8 -7 -6 -5]
 [-4 -3 -2 -1]
 [ 0  1  2  3]
 [ 4  5  6  7]], shape=(4, 4), dtype=int32)
tf.Tensor(
[[0 0 0 0]
 [0 0 0 0]
 [0 1 2 3]
 [4 5 6 7]], shape=(4, 4), dtype=int32)
tf.Tensor(
[[-8 -7 -6 -5]
 [-4 -3 -2 -1]
 [ 0  0  0  0]
 [ 0  0  0  0]], shape=(4, 4), dtype=int32)
tf.Tensor(
[[-2 -2 -2 -2]
 [-2 -2 -2 -1]
 [ 0  1  2  2]
 [ 2  2  2  2]], shape=(4, 4), dtype=int32)
"""

6. 进阶操作

6.1 tf.gather

功能:根据索引号收集数据。

考虑班级成绩册的例子,假设共有4个班级,每个班级35个学生,8门科目,保存成绩册的张量shape为[4,35,8]。

现在需要收集1~2班的成绩册,给定索引号[0,1],并指定班级的维度axis=0,代码如下:

import tensorflow as tf

a = tf.random.uniform([4,35,8],maxval=100,dtype=tf.int32)
b = tf.gather(a,[0,1],axis=0)
c = a[0:2]
print(b)
print(c)
#结果太长,但是可以发现b与c是一样的,也就是我们可以通过切片简单的得到

但是如果索引不是连续的,切片就很麻烦,比如我们要抽查所有班级的第1、4、9、12、13、27号学生的成绩数据,tf.gather可以很简单的实现:

import tensorflow as tf

a = tf.random.uniform([4,35,8],maxval=100,dtype=tf.int32)
b = tf.gather(a,[0,3,8,11,12,26],axis = 1)
print(a)
"""
tf.Tensor(
[[[17  8 39 ... 40 75 77]
  [32  8 17 ... 41 77 21]
  [17 24 80 ...  5 75 50]
  ...
  [44 14 34 ... 67 38 49]
  [73 87 93 ... 11  6 28]
  [19 92 17 ... 53 54 36]]

 [[31 61  3 ... 32 22 90]
  [29 18 17 ... 52 85 90]
  [24 15 73 ... 99 13 62]
  ...
  [51 70 58 ... 78  5 68]
  [27 75 39 ... 82 40 77]
  [ 7 43 58 ... 68  7  3]]

 [[15  5 94 ... 20 24  7]
  [73 67 35 ...  7 46 97]
  [49 53 73 ... 26 59 85]
  ...
  [24 81 33 ... 61 46 38]
  [ 1 54 63 ... 89 81 61]
  [58 34 37 ... 43 80 12]]

 [[75 58  3 ... 73 72 96]
  [36 79 75 ... 22 70 63]
  [70 23 76 ... 91 24 21]
  ...
  [59  6 74 ... 76 63 10]
  [54 84 43 ... 11 61 41]
  [61 23  3 ... 62 48 76]]], shape=(4, 35, 8), dtype=int32)
  """

接下来让问题更复杂一些,我们需要抽查第[2,3,]班级的第[3,4,6,27]号同学的成绩,我们可以组合多个tf.gather来实现。

import tensorflow as tf

a = tf.random.uniform([4,35,8],maxval=100,dtype=tf.int32)
b = tf.gather(a,[1,2],axis = 0)
c = tf.gather(b,[2,3,5,26],axis=1)
print(c)
"""
tf.Tensor(
[[[40 57 22 51 17 82 33 28]
  [86  4 28 25 48 88  0 16]
  [86 95 87 72 35 39 76 17]
  [72 40 82 48 23 53 42 30]]

 [[ 8 46 42 65 10 17 93 38]
  [95 70 84 43 43 89 44 52]
  [92  8 28 94 25 99 37 90]
  [85  7 35 28 38 13 70 63]]], shape=(2, 4, 8), dtype=int32)

Process finished with exit code 0

tf.Tensor(
[[[40 57 22 51 17 82 33 28]
  [86  4 28 25 48 88  0 16]
  [86 95 87 72 35 39 76 17]
  [72 40 82 48 23 53 42 30]]

 [[ 8 46 42 65 10 17 93 38]
  [95 70 84 43 43 89 44 52]
  [92  8 28 94 25 99 37 90]
  [85  7 35 28 38 13 70 63]]], shape=(2, 4, 8), dtype=int32)

"""

我们进一步深化问题,我们将抽查第2个班级的第二个同学的所有科目成绩,第三个班级的第三个同学的所有科目成绩,第四个班级的第四个同学的所有科目成绩。那怎么实现呢?我们可以结合切片和堆叠操作实现。

import tensorflow as tf

x = tf.random.uniform([4,35,8],maxval=100,dtype=tf.int32)

a = tf.stack([x[1,1],x[2,2],x[3,3]],axis=0)
print(a)
"""
tf.Tensor(
[[90  4 69 81 47 50 92 57]
 [34 82 62 48 69 20 43 91]
 [86 76 17 38 71 46 67 77]], shape=(3, 8), dtype=int32)
 """

上述方式我们道德到了正确结果,但是它的问题在于手动串行方式地执行采样,计算效率极低。我们介绍更好的方式tf.gather_nd

6.2 tf.gather_nd

功能:可以通过指定每次采样点的多为坐标来实现采样多个点的目的。

上述问题我们可以如下解决:

import tensorflow as tf

x = tf.random.uniform([4,35,8],maxval=100,dtype=tf.int32)

a = tf.gather_nd(x,[[1,1],[2,2],[3,3]])
print(a)
"""
tf.Tensor(
[[20 90 36  8 39 95 78 53]
 [34 71 58 70 57 58 76 27]
 [98 55 57 13 25 27 12 85]], shape=(3, 8), dtype=int32)
 """
6.3 tf.boolean_mask

功能:一种掩码采样方案。

我们对1班级班级采样如下和

import tensorflow as tf

x = tf.random.uniform([4,35,8],maxval=100,dtype=tf.int32)

a = tf.boolean_mask(x,[True,False,False,True],axis =0)

print(a)
#太长了此处不表

结果太长了,我们将班级数量减少到2个,学生3个,shape=[2,3,8]。

下面举例,采样1班级12号学生,2班级23号学生:

import tensorflow as tf

x = tf.random.uniform([2,3,8],maxval=100,dtype=tf.int32)

a = tf.boolean_mask(x,[[True,True,False],[False,True,True]],axis =0)

print(a)
"""
tf.Tensor(
[[37  0 36 43 20 25 73 77]
 [98 75 51 74 55 87 80 76]
 [72 40  6 40 10 54 29  0]
 [35 44 30 73 11 75 83 25]], shape=(4, 8), dtype=int32)
 """
6.4 tf.where

tf.where(cond, a, b):cond是一个bool类型的张量,a,b,cond的shape是一样的。当cond对应元素取值True,复制a该位置的值,当cond对应元素取False时,复制b该位置的值。最后返回一个与a,b,cond同型的张量,其元素来自a或b。

import tensorflow as tf

a = tf.ones([3,3])#全1张量
b = tf.zeros([3,3])#全0张量
cond = tf.constant([[True,False,False],[False,True,False], [True,True,False]])

c = tf.where(cond,a,b)
print(c)
"""
tf.Tensor(
[[1. 0. 0.]
 [0. 1. 0.]
 [1. 1. 0.]], shape=(3, 3), dtype=float32)
 """

当a和b参数不指定时,tf.where会返回cond张量中所有True的元素的索引坐标。

import tensorflow as tf

#a = tf.ones([3,3])#全1张量
#b = tf.zeros([3,3])#全0张量
cond = tf.constant([[True,False,False],[False,True,False], [True,True,False]])

c = tf.where(cond)
print(c)
"""
tf.Tensor(
[[0 0]
 [1 1]
 [2 0]
 [2 1]], shape=(4, 2), dtype=int64)
 """

那这有什么用呢?我们考虑这样一个场景,我们要提取张量中所有的正数数据和索引。

import tensorflow as tf

x = tf.random.normal([3,3])
mask = x>0 #mask是与x同型的张量,元素大于0位置为True否则为False
indices = tf.where(mask)
a = tf.gather_nd(x,indices)
b = tf.boolean_mask(x,mask)
print(x)
print(a)
print(b)
"""我们可以发现
a和b是相同的
[[ 1.4371932   0.07402689 -0.6966804 ]
 [-1.5648468  -0.8848997   1.3896387 ]
 [-1.4169993  -0.10606533 -0.9919792 ]], shape=(3, 3), dtype=float32)
tf.Tensor([1.4371932  0.07402689 1.3896387 ], shape=(3,), dtype=float32)
tf.Tensor([1.4371932  0.07402689 1.3896387 ], shape=(3,), dtype=float32)

"""

6.5 tf.scatter_nd

通过tf.scatter_nd(indices, updates, shape)函数可以高效地刷新张量的部分数据,但是这个函数只能在全0的白板张量上面执行刷新操作,因此可能需要结合其他操作来实现有张量的数据刷新功能。

举例:如下图,将updates的数据按索引indices插入到shape张量中。其实shape是个形状,因为只能在全0的白板张量上插入。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-n54Mq6n5-1647417873730)(tensorflow基础2.assets/p5.png)]

import tensorflow as tf

indices = tf.constant([[4],[3],[1],[7]])

updates = tf.constant([4.4,3.3,1.1,7.7])

x = tf.scatter_nd(indices,updates,[8])
print(x)
#tf.Tensor([0.  1.1 0.  3.3 4.4 0.  0.  7.7], shape=(8,), dtype=float32)

下面考虑3维张量的例子,shape=[4,4,4]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8Z2BxvF9-1647417873730)(tensorflow基础2.assets/p6.png)]

import tensorflow as tf

indices = tf.constant([[1],[3]])

updates = tf.constant([[[5,5,5,5],[6,6,6,6],[7,7,7,7],[8,8,8,8]],
                       [[1,1,1,1],[2,2,2,2],[3,3,3,3],[4,4,4,4]]])

x = tf.scatter_nd(indices,updates,[4,4,4])
print(x)
"""
tf.Tensor(
[[[0 0 0 0]
  [0 0 0 0]
  [0 0 0 0]
  [0 0 0 0]]

 [[5 5 5 5]
  [6 6 6 6]
  [7 7 7 7]
  [8 8 8 8]]

 [[0 0 0 0]
  [0 0 0 0]
  [0 0 0 0]
  [0 0 0 0]]

 [[1 1 1 1]
  [2 2 2 2]
  [3 3 3 3]
  [4 4 4 4]]], shape=(4, 4, 4), dtype=int32)
"""
6.6 tf.meshgrid

通过tf.meshgrid函数可以方便地生成二维网格的采样坐标,方便可视化等应用场合。

举例:我们要画出三维图像Sinc函数:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2YhOJvdD-1647417873731)(tensorflow基础2.assets/p7.png)]

绘制x,y均在[-8,8]。可以通过如下方式获得坐标采样点

def sinc(x,y):
    return tf.math.sin(x**2+y**2)/(x**2+y**2)

points = []
for x in range(-8,8,100):
    for y in range(-8,8,100):
        z = sinc(float(x),float(y))
        points.append([x,y,z])

通过tf.meshgrid(x,y)我们可以轻松实现:

import tensorflow as tf
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import numpy as np

x = tf.linspace(-8.,8,100)
y = tf.linspace(-8.,8,100)
x,y = tf.meshgrid(x,y)
z = tf.sqrt(x**2+y**2)#书上这样写,但是这不是求平方根了吗 我觉得错了自己调整下
z = tf.sin(z)/z
fig = plt.figure()
ax = Axes3D(fig)
ax.contour3D(x.numpy(),y.numpy(),z.numpy())
print(x.numpy().shape)
plt.show()
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值