【TF2-02】tensorflow2进阶

分割与合并

合并

concat

通过tf.concat(tensors, axis)函数拼接张量,其中参数tensors 保存了所有需要合并的张量List,axis 参数指定需要合并的维度索引。
设一个tensor为:a = [6, 35, 8],具体含义是:6个班级,每个班级35个学生, 8门学科

  • 此时需要A收集4个班的数据,B收集2个班的数据,并将A和B的数据合并起来交给C。
a = tf.ones([4, 35, 8])
b = tf.ones([2, 35, 8])
c = tf.concat([a, b], axis=0)

c.shape
TensorShape([6, 35, 8])
  • 此时需要A收集4个班每个班32个同学的数据,B收集4个班每个班3个同学的数据,并将A和B的数据合并起来交给C。
a = tf.ones([4, 32, 8])
b = tf.ones([4, 3, 8])
c = tf.concat([a, b], axis=1)

c.shape
TensorShape([4, 35, 8])

要合并的维度可以不相等,其他维度都要相等

堆叠

stack

假设学校A[4, 35, 8],学校B[4, 35, 8];把两个学校的数据合并到一起变成[2, 4, 35, 8]

a = tf.ones([4, 35, 8])
b = tf.ones([4, 35, 8])

c = tf.stack([a, b], axis=0)
d = tf.stack([a, b], axis=3)

c.shape
TensorShape([2, 4, 35, 8])
d.shape
TensorShape([4, 35, 8, 2])

所有的维度都要完全相等

切割

  • unstack
    以上面c = [2, 4, 35, 8]为例
aa, bb = tf.unstack(c, axis=0)
aa.shape, bb.shape
TensorShape([4, 35, 8]), TensorShape([4, 35, 8])

res = tf.unstack(c, axis=3)
res[0].shape, res[1].shape...res[7].shape
TensorShape([2, 4, 35])...

要分割的轴上是多少,就分割成多少个tensor。比如上面的axis=3为8,就分割成一个长度为8的List,每个list的shape如上

  • split
    tf.split(x, num_or_size_splits, axis)参数意义如下
    在这里插入图片描述

数据统计

范数

tf.norm(x, ord, axis)
其中参数ord 指定为1、2 时计算L1、L2 范数,指定为np.inf 时计算∞ −范数。

最值

  • tf.reduce_max(x, axis)
  • tf.reduce_min(x, axis)

均值

tf.reduce_mean(x, axis)

tf.reduce_sum(x, axis) 求解张量在axis 轴上所有特征的和
*当不指定axis 参数时,tf.reduce_函数会求解出全局元素的最大、最小、均值、和等数据

最值索引

通过 tf.argmax(x, axis)tf.argmin(x, axis)可以求解在axis 轴上,x 的最大值、最小值所在的索引号

a.shape = [4, 10]

tf.argmax(a).shape = [10]
tf.argmax(a) = array([3, 3, 3, 3, 3, 3, 3, 2, 1, 0])

tf.argmin(a, axis=1).shape = [4]
tf.argmin(a) = array([9, 8, 7, 6])

# 结合下面的矩阵好理解

[ 0 1 2 3 4 5 6 7 8 9 1 2 3 4 5 6 7 8 9 0 2 3 4 5 6 7 8 9 0 1 3 4 5 6 7 8 9 0 1 2 ] \begin{bmatrix} 0&1&2&3&4&5&6&7&8&9\\ 1&2&3&4&5&6&7&8&9&0\\ 2&3&4&5&6&7&8&9&0&1\\ 3&4&5&6&7&8&9&0&1&2\\ \end{bmatrix} 0123123423453456456756786789789089019012

比较

tf.equal(a, b)

# 假设
a = tf.constant([1, 2, 3, 3, 5])
b = tf.range(5)		# b = [1, 2, 3, 4, 5]

# 比较
tf.equal(a, b)
<tf.Tensor: shape=(5,), dtype=bool, numpy=array([False, False, False, True, False])>
# 返回
[False, False, False, True, False] 相当于 [0, 0, 0, 1, 0]

用来做精确度计算
假设样本预测结果a= [ 0.1 0.2 0.7 0.9 0.05 0.05 ] \begin{bmatrix} 0.1&0.2&0.7\\ 0.9&0.05&0.05\\ \end{bmatrix} [0.10.90.20.050.70.05],则pred = argmax(a, axis=1)的结果为[2, 0],样本实际值y为[2, 1]

# 比较预测值和实际值的误差
tf.equal(pred, y)
# 得到 [True, False]即[1, 0]
# 将比较结果的数据相加
correct = tf.reduce_sum(tf.cast(tf.equal(pred, y), dtype=tf.int32))
# 得到 correct = 1
# 然后除以样本数量2
correct / 2 = 0.5
# 所以精确度为0.5

去除重复

tf.unique


张量排序

随机打散

tf.random.shuffle

Sort/argsort

a = tf.random.shuffle(tf.range(5)) => tf.Tensor([4 2 1 3 0], shape=(5,), dtype=int32)

  • tf.sort 返回排序后的结果
tf.sort(a, direction='DESCENDING')
<tf.Tensor: shape=(5,), dtype=int32, numpy=array([4, 3, 2, 1, 0])>
  • tf.argsort 返回排序的索引,比如这个索引0对应a中的值4;索引3对应a中的值3;索引1对应a中的值2…
tf.argsort(a, direction='DESCENDING')
<tf.Tensor: shape=(5,), dtype=int32, numpy=array([0, 3, 1, 2, 4])>

这里都是默认对左后一个轴进行排序

Top_k

返回前k个排序结果
res = tf.matg.top_k(a, k),a是待排序的张量,k是前k个结果

res.indices返回前k个的索引

res.values返回前k个的值


填充与复制

填充

tf.pad(a, padding) a为待填充的tensor,参数paddings 是包含了多个**[** Left Padding, Right Padding **]**的嵌套方案List。

如[[0,0], [2,1], [1,2]]表示第一个维度不填充,第二个维度左边(起始处)填充两个单元,右边(结束处)填充一个单元,第三个维度左边填充一个单元,右边填充两个单元。
在这里插入图片描述

复制

tf.tile(a, copy_list) a为待操作张量,copy_list为每个维度需要复制的次数的List。

比如tf.tile(a, [1, 2]),把a在第一个维度保持不变,第二个维度变成2倍
在这里插入图片描述


张量限幅

[ a , + ∞ ) [a, +\infty) [a,+)​​​

tf.maximum(x, a)

( − ∞ , a ] (-\infty, a] (,a]​​​

tf.minimum(x, a)

[ a , b ] [a, b] [a,b]​​

tf.clip_by_value(x, a, b)


高级操作

  • tf.where(tensor)
    where是一个查询元素为true的方法
    在这里插入图片描述
    在这里插入图片描述
  • scatter_nd(indices, updates, shape)
    在这里插入图片描述
    在这里插入图片描述
  • meshgrid
    通过 tf.meshgrid 函数可以方便地生成二维网格的采样点坐标,方便可视化等应用场合

经典数据集加载

keras.datasets

通过 datasets.xxx.load_data()函数即可实现经典数据集的自动加载,其中xxx 代表具体的数据集名称,如“CIFAR10”、“MNIST”。TensorFlow 会默认将数据缓存在用户目录下的.keras/datasets 文件夹

import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import datasets # 导入经典数据集加载模块

# 加载MNIST 数据集
(x, y), (x_test, y_test) = datasets.mnist.load_data()
print('x:', x.shape, 'y:', y.shape, 'x test:', x_test.shape, 'y test:',y_test)

# 返回数组的形状
Out [66]: x: (60000, 28, 28) y: (60000,) x test: (10000, 28, 28) y test: [7 2 1 ... 4 5 6]

Dataset.from_tensor_slices

数据加载进入内存后,需要转换成Dataset 对象,才能利用TensorFlow 提供的各种便捷功能,比如:随机打散(Dataset.shuffle)、批训练(Dataset.batch)等。通过Dataset.from_tensor_slices 可以将训练部分的数据图片x 和标签y 都转换成Dataset 对象

train_db = tf.data.Dataset.from_tensor_slices((x, y)) # 构建Dataset 对象

将数据转换成Dataset 对象后,一般需要再添加一系列的数据集标准处理步骤,如随机打散、预处理、按批装载等。

随机打散

通过 Dataset.shuffle(buffer_size)工具可以设置Dataset 对象随机打散数据之间的顺序,防止每次训练时数据按固定顺序产生,从而使得模型尝试“记忆”住标签信息,代码实现如下:

train_db = train_db.shuffle(10000) # 随机打散样本,不会打乱样本与标签映射关系

其中,buffer_size 参数指定缓冲池的大小,一般设置为一个较大的常数即可

批训练

为了利用显卡的并行计算能力,一般在网络的计算过程中会同时计算多个样本,我们把这种训练方式叫做批训练,其中一个批中样本的数量叫做Batch Size。为了一次能够从Dataset 中产生Batch Size 数量的样本,需要设置Dataset 为批训练方式,实现如下:

train_db = train_db.batch(128) # 设置批训练,batch size 为128

其中128 为Batch Size 参数,即一次并行计算128 个样本的数据。Batch Size 一般根据用户的GPU 显存资源来设置,当显存不足时,可以适量减少Batch Size 来减少算法的显存使用量。

预处理

从 keras.datasets 中加载的数据集的格式大部分情况都不能直接满足模型的输入要求,因此需要根据用户的逻辑自行实现预处理步骤。Dataset 对象通过提供map(func)工具函数,可以非常方便地调用用户自定义的预处理逻辑,它实现在func 函数里。例如,下方代码调用名为preprocess 的函数完成每个样本的预处理:

# 预处理函数实现在preprocess 函数中,传入函数名即可
train_db = train_db.map(preprocess)

考虑 MNIST 手写数字图片,从keras.datasets 中经.batch()后加载的图片x shape 为[𝑏, 28,28],像素使用0~255 的整型表示;标签shape 为[𝑏],即采样数字编码方式。实际的神经网络输入,一般需要将图片数据标准化到[0,1]或[−1,1]等0 附近区间,同时根据网络的设置,需要将shape 为[28,28]的输入视图调整为合法的格式;对于标签信息,可以选择在预处理时进行One-hot 编码,也可以在计算误差时进行One-hot 编码。

我们将MNIST 图片数据映射到𝑥 ∈ [0,1]区间,视图调整为[𝑏, 28 ∗ 28];对于标签数据,我们选择在预处理函数里面进行One-hot 编码。preprocess 函数实现如下:

def preprocess(x, y): # 自定义的预处理函数
    # 调用此函数时会自动传入x,y 对象,shape 为[b, 28, 28], [b]
    # 标准化到0~1
    x = tf.cast(x, dtype=tf.float32) / 255.
    x = tf.reshape(x, [-1, 28*28]) # 打平
    y = tf.cast(y, dtype=tf.int32) # 转成整型张量
    y = tf.one_hot(y, depth=10) # one-hot 编码
    # 返回的x,y 将替换传入的x,y 参数,从而实现数据的预处理功能
    return x,y

循环训练

对于 Dataset 对象,在使用时可以通过

for step, (x,y) in enumerate(train_db): # 迭代数据集对象,带step 参数

或者

for x,y in train_db: # 迭代数据集对象

方式进行迭代,每次返回的x 和y 对象即为批量样本和标签。当对train_db 的所有样本完成一次迭代后,for 循环终止退出。这样完成一个Batch 的数据训练,叫做一个Step;通过多个step 来完成整个训练集的一次迭代,叫做一个Epoch。在实际训练时,通常需要对数据集迭代多个Epoch 才能取得较好地训练效果。例如,固定训练20 个Epoch,实现如下:

for epoch in range(20): # 训练Epoch 数
    for step, (x,y) in enumerate(train_db): # 迭代Step 数
        # training...

此外,也可以通过设置Dataset 对象,使得数据集对象内部遍历多次才会退出,实现如下:

train_db = train_db.repeat(20) # 数据集迭代20 遍才终止

上述代码使得for x,y in train_db 循环迭代20 个epoch 才会退出。不管使用上述哪种方式,都能取得一样的效果。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值