05_TensorFlow2张量奇遇记:玩转数据,让你的代码嗨翻天!

在这里插入图片描述

1. 张量

张量(Tensor)是 Tensorflow 的基本操作对象,可以看做是包含单一数据类型元素的多维矩阵。图像的实质是多维张量,对张量的认识和使用是我们开始深度学习的第一步。

2. 张量操作示例

2.1 索引与切片

2.1.1 索引

索引操作比较简单,直接通过维度编号进行索引。

import tensorflow as tf
# 创建2维张量
t = tf.constant([[1,2,3,4,5],[6,7,8,9,10]])
# 取0维度上的第一组数据
a = t[0]
# 取x[0]中的第二组数据
b = t[0][1]
print(a)
print('_'*50)
print(b)
tf.Tensor([1 2 3 4 5], shape=(5,), dtype=int32)
__________________________________________________
tf.Tensor(2, shape=(), dtype=int32)

2.1.2 切片

切片采用 [start🔚step] 的方式。start:end 为含有不含尾的切片操作,表示从 start 位开始,一直到 end-1 位结束;加入步长 step 后,从 start 到 end-1 间隔 step 取数。

# 先取0维度第二组数据:[6,7,8,9,10],再从[6 7 8 9] 中间隔2取数据
t[1,0:4:2]
<tf.Tensor: shape=(2,), dtype=int32, numpy=array([6, 8])>

2.2 维度变换

基本的维度变换包含改变视图的 tf.reshape,插入新维度 tf.expand_dims,删除维度 tf.squeeze,交换维度 tf.transpose 等

2.2.1 tf.reshape

tf.reshape(tensor, shape, name=None) 第一个参数为被调整维度的张量,第二个参数为要调整为的形状,返回一个 shape 形状的新 rensor。shape 里最多有一个维度的值可以为 -1,表示自动计算此维度。

# 生成一个从 0 开始的 24 个元素的数组
t = tf.range(24)
# 生成 2 二维数组,每个二维数组为 4 行 3 列
t1 = tf.reshape(t, [2, 4, 3])
print(t)
print('_'*50)
print(t1)
tf.Tensor([ 0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 21 22 23], shape=(24,), dtype=int32)
__________________________________________________
tf.Tensor(
[[[ 0  1  2]
  [ 3  4  5]
  [ 6  7  8]
  [ 9 10 11]]

 [[12 13 14]
  [15 16 17]
  [18 19 20]
  [21 22 23]]], shape=(2, 4, 3), dtype=int32)

2.2.2 tf.expand_dims

通过 tf.expand_dims(input, axis) 可在指定的 axis 轴前插入一个新的维度。axis 为正时,表示在当前维度之前插入一个新的维度,为负时,表示在当前维度之后插入一个新的维度。

# shape [2,3]
t = [[1,2,3],[4,5,6]]
# shape [1,2,3]
t1 = tf.expand_dims(t, axis=0)
# shape [2,1,3]
t2 = tf.expand_dims(t, axis=1)
# shape [2,3,1]
t3 = tf.expand_dims(t, axis=2)
# shape [2,3,1]
t4 = tf.expand_dims(t, axis=-1)
print(t)
print('-'*50)
print(t1)
print('-'*50)
print(t2)
print('-'*50)
print(t3)
print('-'*50)
print(t4)
[[1, 2, 3], [4, 5, 6]]
--------------------------------------------------
tf.Tensor(
[[[1 2 3]
  [4 5 6]]], shape=(1, 2, 3), dtype=int32)
--------------------------------------------------
tf.Tensor(
[[[1 2 3]]

 [[4 5 6]]], shape=(2, 1, 3), dtype=int32)
--------------------------------------------------
tf.Tensor(
[[[1]
  [2]
  [3]]

 [[4]
  [5]
  [6]]], shape=(2, 3, 1), dtype=int32)
--------------------------------------------------
tf.Tensor(
[[[1]
  [2]
  [3]]

 [[4]
  [5]
  [6]]], shape=(2, 3, 1), dtype=int32)

2.2.3 tf.squeeze

通过tf.squeeze(input, axis)可以删除长度为1的维度,axis参数为待删除维度的索引号,删除维度只能删除长度为1的维度,如果不指定维度参数axis,即tf.sequeeze(input),则其会默认删除所有长度为1的维度。

# [0 1 2 3 4 5]
t = tf.range(6)
t1 = tf.reshape(t, [1,2,1,3,1])
t2 = tf.squeeze(t1)
print(t1)
print('-'*50)
print(t2)
tf.Tensor(
[[[[[0]
    [1]
    [2]]]


  [[[3]
    [4]
    [5]]]]], shape=(1, 2, 1, 3, 1), dtype=int32)
--------------------------------------------------
tf.Tensor(
[[0 1 2]
 [3 4 5]], shape=(2, 3), dtype=int32)

2.2.4 tf.transpose

交换维度操作是十分常见的,可以通过tf.transpose(x, perm)函数完成维度交换操作,其中perm表示新维度的顺序List。考虑图片张量shape为[2, 5, 5, 3],图片数量、行、列、通道数的维度索引为[0, 1, 2, 3],将其交换为[b, c, h, w]格式,则新维度的索引号为[0, 3, 1, 2]。

#sahpe [2, 5, 5, 3]
t = tf.random.normal([2, 5, 5, 3])   
t1 = tf.transpose(t, perm = [0, 3, 1, 2])
print(t1.shape)
(2, 3, 5, 5)

2.3 合并与分割

2.3.1 合并

合并是指将多个张量沿某个维度合并为一个张量。按照是否产生新的维度,张量合并分为张量拼接(concatenate)和张量堆叠(stack)。 张量拼接在Tensorflow中通过tf.concat(tensors,axis)实现,其中tensors为list,每个元素为一个需要合并的张量,axis为需要合并的维度。

a = tf.constant([[1, 2, 3], [4, 5, 6]])
b = tf.constant([[7, 8, 9], [10, 11, 12]])
c1 = tf.concat([a, b], 0)
c2 = tf.concat([a, b], 1)
print(c1)   # 未产生新维度
print('-'*50)
print(c2)   # 未产生新维度
tf.Tensor(
[[ 1  2  3]
 [ 4  5  6]
 [ 7  8  9]
 [10 11 12]], shape=(4, 3), dtype=int32)
--------------------------------------------------
tf.Tensor(
[[ 1  2  3  7  8  9]
 [ 4  5  6 10 11 12]], shape=(2, 6), dtype=int32)

需要注意的是:张量合并在非合并维度的长度必须一致。

张量堆叠会产生新的维度,通过tf.stack(tensors, axis) 实现,tensors为可以合并的多个张量,axis 指定插入新维度的位 置。当axis ≥ 0时,在 axis 之前插入;当axis < 0时, 在 axis 之后插入新维度。

a = tf.constant([[1, 2, 3], [4, 5, 6]])
b = tf.constant([[7, 8, 9], [10, 11, 12]])
tf.stack([a, b])   # axis默认为0
<tf.Tensor: shape=(2, 2, 3), dtype=int32, numpy=
array([[[ 1,  2,  3],
        [ 4,  5,  6]],

       [[ 7,  8,  9],
        [10, 11, 12]]])>

需要注意的是:需要合并的张量 shape 完全一致才可堆叠,否则会出现错误。

2.3.2 分割

tf.unstack

tf.unstack(tensor, num, axis),tf.unstack()将tensor根据axis分解成num个张量,返回的值是list类型,如果没有指定num则根据axis推断出。

a = tf.constant([[3,2,4,5,6],[1,6,7,8,0]])
c = tf.unstack(a,axis=0)
d = tf.unstack(a,axis=1)
print(c)
print('-'*50)
print(d)
[<tf.Tensor: shape=(5,), dtype=int32, numpy=array([3, 2, 4, 5, 6])>, <tf.Tensor: shape=(5,), dtype=int32, numpy=array([1, 6, 7, 8, 0])>]
--------------------------------------------------
[<tf.Tensor: shape=(2,), dtype=int32, numpy=array([3, 1])>, <tf.Tensor: shape=(2,), dtype=int32, numpy=array([2, 6])>, <tf.Tensor: shape=(2,), dtype=int32, numpy=array([4, 7])>, <tf.Tensor: shape=(2,), dtype=int32, numpy=array([5, 8])>, <tf.Tensor: shape=(2,), dtype=int32, numpy=array([6, 0])>]

tf.split

tf.split(tensor, num_or_size_splits, axis),tensor为待分割张量,num_or_size_splits控制分割后对应维度上元素的个数,axis为指定分割的维度索引号。

x = [[1,2,3],[4,5,6]]
tf.split(x, 3, 1)
[<tf.Tensor: shape=(2, 1), dtype=int32, numpy=
 array([[1],
        [4]])>,
 <tf.Tensor: shape=(2, 1), dtype=int32, numpy=
 array([[2],
        [5]])>,
 <tf.Tensor: shape=(2, 1), dtype=int32, numpy=
 array([[3],
        [6]])>]

2.4 统计

2.4.1 范数

范数(Vector norm)是表征向量“长度”的一种度量方法,在神经网络中,常用来 表示张量的权值大小,梯度大小等。常用的范数有:L1 范数、L2 范数、∞ −范数。在 TensorFlow 中,可以通过 tf.norm(x, ord)求解张量的 L1, L2, ∞等范数,其中参数 ord 指定为 1,2 时计算 L1, L2 范数,指定为 np.inf 时计算∞ −范数:

import numpy as np
x=tf.ones([3,3])
print(x)
# L1 范数 
L1=tf.norm(x,ord=1) 
print("L1 norm is: {}".format(L1))
# L2范数 
L2=tf.norm(x,ord=2) 
print("L2 norm is: {}".format(L2))
# ∞范数 
L_inf=tf.norm(x,ord=np.inf) 
print("∞ norm is: {}".format(L_inf))
tf.Tensor(
[[1. 1. 1.]
 [1. 1. 1.]
 [1. 1. 1.]], shape=(3, 3), dtype=float32)
L1 norm is: 9.0
L2 norm is: 3.0
∞ norm is: 1.0

2.4.2 最值、均值

通过 tf.reduce_max, tf.reduce_min, tf.reduce_mean可以求取指定维度上的最大、最小和均值,也可求取全部数组中的最大、最小和均值。

#创建张量
x = tf.random.normal([3,3])
print(x)
#统计最大值
max=tf.reduce_max(x,axis=1)
print("max is: {}".format(max))
#统计最小值
min=tf.reduce_min(x,axis=1)
print("min is: {}".format(min))
# 统计均值 
mean=tf.reduce_mean(x,axis=1) 
print("mean is: {}".format(mean))
tf.Tensor(
[[ 0.7039088  -1.3010858  -0.26340982]
 [-0.9290817  -1.6276046   0.22816275]
 [ 0.30339584  0.2684896   0.96004856]], shape=(3, 3), dtype=float32)
max is: [0.7039088  0.22816275 0.96004856]
min is: [-1.3010858 -1.6276046  0.2684896]
mean is: [-0.28686228 -0.77617455  0.5106447 ]

当不指定 axis 参数时,tf.reduce_*函数会求解出全局元素的最大、最小、均值。

#创建张量
x = tf.random.normal([3,3])
#统计最大值
max=tf.reduce_max(x)
print("max is: {}".format(max))
#统计最小值
min=tf.reduce_min(x)
print("min is: {}".format(min))
# 统计均值 
mean=tf.reduce_mean(x) 
print("mean is: {}".format(mean))
max is: 1.9886242151260376
min is: -1.1376621723175049
mean is: 0.13465966284275055

2.5 张量比较

在深度学习中,通常需要将预测结果与真实标签进行比较,从而计算准确率。常用的张量比较函数有以下几种:

在这里插入图片描述

以下以tf.equal(a,b)为例说明其用法。 tf.equal()函数返回布尔型的张量比较结果,通过统计张量中True元素的个数即可获得预测正确的数量。一般情况下,我们先将布尔型转换为整型张量0和1,再求和即可得到1的个数,也就是True元素的数量。

pre_out=tf.convert_to_tensor(np.array([[1,2,3,4,2,3,5,6,7,8,9,2,3,4,5,4]])) 
label=tf.convert_to_tensor(np.array([[1,7,3,4,2,3,4,6,7,3,9,2,7,4,2,4]])) 
# 预测值与真实值比较 
acc=tf.equal(pre_out,label) 
print("acc is: {}".format(acc))
 # 布尔型转 int 型
acc = tf.cast(acc, dtype=tf.float32)
# 统计 True 的个数 
correct = tf.reduce_sum(acc)
print("correct is: {}".format(correct))
acc is: [[ True False  True  True  True  True False  True  True False  True  True
  False  True False  True]]
correct is: 11.0

其它的比较运算函数请读者自行测试。

2.6 填充和复制

2.6.1 填充

tf.pad(tensor,paddings,mode=“CONSTANT”,constant_values=0)主要是用来对tensor的大小进行扩展,包括水平、垂直、深度等,tensor为输入的张量,paddings为设置填充的大小,mode为填充方式(可选择CONSTANT、REFLECT和SYMMETRIC,默认是CONSTANT),constant_values为CONSTANT填充方式的填充值,默认为0,当填充方式为REFLECT和SYMMETRIC时,constant_values无效,使用tensor中的值进行填充。

a = tf.fill([3,3],2)
# 第一维度,前面补一维度,后面补一维度;第二维度,前面补两维度,后面补两维度。
tf.pad(a,[[1,1],[2,2]])   
<tf.Tensor: shape=(5, 7), dtype=int32, numpy=
array([[0, 0, 0, 0, 0, 0, 0],
       [0, 0, 2, 2, 2, 0, 0],
       [0, 0, 2, 2, 2, 0, 0],
       [0, 0, 2, 2, 2, 0, 0],
       [0, 0, 0, 0, 0, 0, 0]])>

2.6.2 复制

可以通过tf.tile(tensor, multiples)函数完成数据在指定维度上的复制操作,multiples分别指定了每个维度上的复制倍数,对应位置为1表明不复制,为2表明新长度为原来长度的2倍,即数据复制一份,以此类推。 如下,通过tf.tile(x, multiples=[2, 1])可以在axis = 0维度复制一次,在axis=1维度不复制。

a = tf.constant([[1,2],[3,4]])
# 在axis=0维度复制一次,在axis=1维度不复制。
tf.tile(a, multiples=[2, 1])   
<tf.Tensor: shape=(4, 2), dtype=int32, numpy=
array([[1, 2],
       [3, 4],
       [1, 2],
       [3, 4]])>

2.7 数据限幅操作

通过简单的数据限幅运算可以限制数据的范围,在Tensorflow中,通过tf.maximum(x,a)实现数据的下限幅:x ∈ [𝑎,+∞);通过 tf.minimum(x, a)实现数据的上幅限制:𝑥 ∈(-∞,a] 。

x=tf.range(100)
#下限幅 50
tf.maximum(x,50)
<tf.Tensor: shape=(100,), dtype=int32, numpy=
array([50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50,
       50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50,
       50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50,
       51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67,
       68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84,
       85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99])>
#上限幅80
tf.minimum(x,80)
<tf.Tensor: shape=(100,), dtype=int32, numpy=
array([ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15, 16,
       17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33,
       34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50,
       51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67,
       68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 80, 80, 80, 80,
       80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80])>

通过组合 tf.maximum(x, a)和 tf.minimum(x, b)可以实现同时对数据的上下边界限幅: 𝑥 ∈ [𝑎,𝑏]:

# 上下限幅为 
x = tf.range(10) 
tf.minimum(tf.maximum(x,3),8) 
<tf.Tensor: shape=(10,), dtype=int32, numpy=array([3, 3, 3, 3, 4, 5, 6, 7, 8, 8])>

数据限幅操作主要用在激活函数中,如relu函数中限制输出的上下限,读者可自行实现一下限幅relu激活函数。

  • 16
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

腾飞开源

你的鼓励将是我创作的最大动力!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值