ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

TensorFlow 2 张量结构操作实战:创建、索引切片、维度变换与合并分割(基于 eat_tensorflow2_in_30_days)

TensorFlow 2 张量结构操作实战:创建、索引切片、维度变换与合并分割(基于 eat_tensorflow2_in_30_days) 教程深度学习机器学习【免费下载链接】eat_tensorflow2_in_30_daysTensorflow2.0 is delicious, just eat it! 项目地址https://gitcode.com/gh_mirrors/ea/eat_tensorflow2_in_30_days点击查看免费下载张量Tensor是 TensorFlow 中最基本的数据结构TensorFlow 程序可以概括为「张量数据结构 图中的算法」。张量操作分为结构操作与数学运算两大类结构操作包括张量创建、索引切片、维度变换、合并分割数学运算包括标量运算、向量运算、矩阵运算及广播机制。本文以开源仓库 eat_tensorflow2_in_30_days 的 english/Chapter4-1.md对应中文版 4-1,张量的结构操作.md为主体系统讲解张量结构操作的全部 API并结合仓库中低阶 APIenglish/Chapter3-1.md、中阶 APIenglish/Chapter3-2.md等章节的真实代码展示这些操作在数据管道、模型训练与评估中的落地用法。读完本文你将掌握用 TensorFlow 2 完成张量创建、任意切片、维度重排与合并分割的完整工具箱并能直接复用文中代码。一、先看全局结构操作与数学运算的边界在仓库中Tensor 操作被明确划分为两大分支见 english/Chapter4.md 章节导言结构操作张量创建、索引切片、维度变换、合并分割数学运算标量运算、向量运算、矩阵运算、广播机制见 english/Chapter4-2.md。如果把模型比作一栋房子这些低阶 API 就是砖块。TensorFlow 提供的张量操作方法比 numpy 更完备、执行效率更高且在必要时可被 GPU 进一步加速。本章Chapter 4与第 3 章english/Chapter3-1.md 低阶 API 示范同属低阶 API体系本章更侧重系统性地讲解张量操作本身。运行环境说明仓库所有示例在 Jupyter 中测试通过代码基于 TensorFlow 2.1见 README_eng.md 的环境说明可用 jupytext 将 Markdown 文件转换为 ipynb 后在 Jupyter 中交互运行。二、创建张量与 numpy 一一对应的构造器张量创建的许多方法与 numpy 创建 array 的方法极其相似。首先引入依赖import tensorflow as tf import numpy as np1. 从数值/序列直接构造a tf.constant([1,2,3],dtype tf.float32) tf.print(a)输出[1 2 3]tf.constant是创建常量张量的基础方法dtype参数可显式指定数据类型。关于张量的数据类型与阶rank可参见 english/Chapter2-1.md常量张量的值在图中不能被重新赋值而tf.Variable可以通过assign等操作重新赋值。2. 等差序列与等间距序列b tf.range(1,10,delta 2) tf.print(b)输出[1 3 5 7 9]tf.range(start, limit, delta)遵循左闭右开区间[start, limit)步长为delta因此 1 到 10不含以 2 为步长得到 5 个元素。c tf.linspace(0.0,2*3.14,100) tf.print(c)输出[0 0.0634343475 0.126868695 ... 6.15313148 6.21656609 6.28]与tf.range不同tf.linspace(start, stop, num)是闭区间均匀取点在[0, 2π]上均匀取出 100 个点——这是画三角函数曲线、构造正弦输入时最常用的序列生成方式。3. 全 0 / 全 1 / 填充张量d tf.zeros([3,3]) tf.print(d)输出[[0 0 0] [0 0 0] [0 0 0]]a tf.ones([3,3]) b tf.zeros_like(a,dtype tf.float32) tf.print(a) tf.print(b)输出[[1 1 1] [1 1 1] [1 1 1]] [[0 0 0] [0 0 0] [0 0 0]]b tf.fill([3,2],5) tf.print(b)输出[[5 5] [5 5] [5 5]]要点对照与 numpy 语义一致方法语义关键参数tf.zeros(shape)全 0 张量shape可以是列表[3,3]tf.ones(shape)全 1 张量shapetf.zeros_like(x, dtype...)形状与x相同的全 0 张量可另指定dtypetf.fill(shape, value)用标量value填充适合生成形状确定的填充张量4. 随机张量均匀、正态、截断正态# 均匀分布随机 tf.random.set_seed(1.0) a tf.random.uniform([5],minval0,maxval10) tf.print(a)输出[1.65130854 9.01481247 6.30974197 4.34546089 2.9193902]tf.random.uniform(shape, minval, maxval)在[minval, maxval)上采样tf.random.set_seed用于固定随机种子保证结果可复现。# 正态分布随机 b tf.random.normal([3,3],mean0.0,stddev1.0) tf.print(b)输出[[0.403087884 -1.0880208 -0.0630953535] [1.33655667 0.711760104 -0.489286453] [-0.764221311 -1.03724861 -1.25193381]]# 正态分布随机剔除2倍方差以外数据重新生成 c tf.random.truncated_normal((5,5), mean0.0, stddev1.0, dtypetf.float32) tf.print(c)输出[[-0.457012236 -0.406867266 0.728577733 -0.892977774 -0.369404584] [0.323488563 1.19383323 0.888299048 1.25985599 -1.95951891] [-0.202244401 0.294496894 -0.468728036 1.29494202 1.48142183] [0.0810953453 1.63843894 0.556645 0.977199793 -1.17777884] [1.67368948 0.0647980496 -0.705142677 -0.281972528 0.126546144]]tf.random.truncated_normal与tf.random.normal的区别在于前者会剔除超出均值 2 倍标准差以外的样本并重新生成从而避免出现极端的离群初始化值——这在深度网络参数初始化中非常实用能有效抑制早期梯度爆炸。5. 特殊矩阵单位阵与对角阵# 特殊矩阵 I tf.eye(3,3) #单位矩阵 tf.print(I) tf.print( ) t tf.linalg.diag([1,2,3]) #对角阵 tf.print(t)输出[[1 0 0] [0 1 0] [0 0 1]] [[1 0 0] [0 2 0] [0 0 3]]tf.eye(N, M)生成单位矩阵tf.linalg.diag(diagonal)以向量为对角线生成对角矩阵。这类矩阵在正则化项、线性代数运算中频繁出现仓库 english/Chapter4-2.md 的矩阵运算章节就使用了tf.linalg.diag构造奇异值对角阵以完成 SVD 分解验证。三、索引切片从规则切片到不规则提取张量的索引切片方式与 numpy 几乎一样切片时支持缺省参数和省略号...。先构造一个 5×5 的随机整数张量作为演示对象tf.random.set_seed(3) t tf.random.uniform([5,5],minval0,maxval10,dtypetf.int32) tf.print(t)输出[[4 7 4 2 9] [9 1 2 4 7] [7 2 7 4 0] [9 6 9 7 2] [3 7 0 0 3]]1. 基础下标与负索引# 第0行 tf.print(t[0])输出[4 7 4 2 9]# 倒数第一行 tf.print(t[-1])输出[3 7 0 0 3]# 第1行第3列 tf.print(t[1,3]) tf.print(t[1][3])输出4 4t[1,3]与t[1][3]完全等价说明张量支持逗号分隔的多维下标。2. 连续区域切片切片语法与 tf.slice# 第1行至第3行 tf.print(t[1:4,:]) tf.print(tf.slice(t,[1,0],[3,5])) #tf.slice(input,begin_vector,size_vector)输出[[9 1 2 4 7] [7 2 7 4 0] [9 6 9 7 2]] [[9 1 2 4 7] [7 2 7 4 0] [9 6 9 7 2]]t[1:4,:]与tf.slice(t,[1,0],[3,5])输出完全一致。tf.slice(input, begin_vector, size_vector)的参数含义为起始坐标向量[1,0]与尺寸向量[3,5]。对于提取张量的连续子区域官方推荐使用tf.slice。# 第1行至最后一行第0列到最后一列每隔两列取一列 tf.print(t[1:4,:4:2])输出[[9 2] [7 7] [9 9]]t[1:4,:4:2]同时演示了行方向的范围切片第 1 行到第 3 行与列方向的步长切片第 0 列到第 3 列、每隔 2 列取一列。3. 对 tf.Variable 的索引赋值# 对变量来说还可以使用索引和切片修改部分元素 x tf.Variable([[1,2],[3,4]],dtype tf.float32) x[1,:].assign(tf.constant([0.0,0.0])) tf.print(x)输出[[1 2] [0 0]]tf.Variable支持通过索引和切片配合.assign()修改部分元素的值这是常量张量不具备的能力也是模型训练中就地更新参数如某些自定义层的基础手段。4. 省略号代表多个冒号a tf.random.uniform([3,3,3],minval0,maxval10,dtypetf.int32) tf.print(a)输出[[[7 3 9] [9 0 7] [9 6 7]] [[1 3 3] [0 8 1] [3 1 0]] [[4 0 6] [6 2 2] [7 9 5]]]# 省略号可以表示多个冒号 tf.print(a[...,1])输出[[3 0 6] [3 8 1] [0 2 9]]a[...,1]等价于a[:,:,1]省略号...自动展开为补齐中间所有维度所需的冒号在操作高维张量如取所有通道的某个分量时非常省事。5. 不规则切片tf.gather / tf.gather_nd / tf.boolean_mask以上切片方式相对规则。对于不规则的切片提取可以使用tf.gather、tf.gather_nd、tf.boolean_mask。其中tf.boolean_mask功能最为强大它可以实现tf.gather、tf.gather_nd的功能并且还支持布尔索引。考虑班级成绩册的例子有 4 个班级每个班级 10 个学生每个学生 7 门科目成绩可用一个4×10×7的张量表示scores tf.random.uniform((4,10,7),minval0,maxval100,dtypetf.int32) tf.print(scores)输出节选[[[52 82 66 ... 17 86 14] [8 36 94 ... 13 78 41] [77 53 51 ... 22 91 56] ... [24 99 38 ... 97 44 74]] [[79 73 73 ... 35 3 81] [83 36 31 ... 75 38 85] [54 26 67 ... 60 68 98] ... [0 21 89 ... 53 10 90]] ...用tf.gather按某个维度抽取不连续的下标# 抽取每个班级第0个学生第5个学生第9个学生的全部成绩 p tf.gather(scores,[0,5,9],axis1) tf.print(p)输出[[[52 82 66 ... 17 86 14] [24 80 70 ... 72 63 96] [24 99 38 ... 97 44 74]] [[79 73 73 ... 35 3 81] [46 10 94 ... 23 18 92] [0 21 89 ... 53 10 90]] ...tf.gather(params, indices, axis)沿指定axis抽取下标列表对应的子张量下标可以是不连续的、任意顺序的。这里axis1表示沿学生维度抽取第 0、5、9 号学生。# 抽取每个班级第0个学生第5个学生第9个学生的第1门课程第3门课程第6门课程成绩 q tf.gather(tf.gather(scores,[0,5,9],axis1),[1,3,6],axis2) tf.print(q)输出[[[82 55 14] [80 46 96] [99 58 74]] [[73 48 81] [10 38 92] [21 86 90]] ...tf.gather可以嵌套使用先沿axis1抽出目标学生再沿axis2抽出目标课程最终得到 4×3×3 的成绩子集。用tf.gather_nd按多维坐标批量取样# 抽取第0个班级第0个学生第2个班级的第4个学生第3个班级的第6个学生的全部成绩 # indices的长度为采样样本的个数每个元素为采样位置的坐标 s tf.gather_nd(scores,indices [(0,0),(2,4),(3,6)]) s输出tf.Tensor: shape(3, 7), dtypeint32, numpy array([[52, 82, 66, 55, 17, 86, 14], [99, 94, 46, 70, 1, 63, 41], [46, 83, 70, 80, 90, 85, 17]], dtypeint32)tf.gather_nd的参数indices是一个坐标列表列表长度等于采样样本个数每个元素是采样位置的完整多维坐标此处为班级,学生二元坐标输出形状为(3, 7)——3 个样本每个样本 7 门课成绩。用tf.boolean_mask实现上述两种功能# 抽取每个班级第0个学生第5个学生第9个学生的全部成绩 p tf.boolean_mask(scores,[True,False,False,False,False, True,False,False,False,True],axis1) tf.print(p)输出[[[52 82 66 ... 17 86 14] [24 80 70 ... 72 63 96] [24 99 38 ... 97 44 74]] [[79 73 73 ... 35 3 81] [46 10 94 ... 23 18 92] [0 21 89 ... 53 10 90]] ...这是tf.boolean_mask的轴掩码用法掩码长度为 10与学生维度对齐True的位置即被保留的位置与tf.gather(scores,[0,5,9],axis1)结果一致。# 抽取第0个班级第0个学生第2个班级的第4个学生第3个班级的第6个学生的全部成绩 s tf.boolean_mask(scores, [[True,False,False,False,False,False,False,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,True,False,False,False]]) tf.print(s)输出[[52 82 66 ... 17 86 14] [99 94 46 ... 1 63 41] [46 83 70 ... 90 85 17]]这是tf.boolean_mask的全维掩码用法掩码形状与scores前两维 4×10 完全一致True的位置对应需要保留的坐标效果等价于tf.gather_nd(scores, [(0,0),(2,4),(3,6)])。布尔索引tf.boolean_mask的语法糖# 利用tf.boolean_mask可以实现布尔索引 # 找到矩阵中小于0的元素 c tf.constant([[-1,1,-1],[2,2,-2],[3,-3,3]],dtypetf.float32) tf.print(c,\n) tf.print(tf.boolean_mask(c,c0),\n) tf.print(c[c0]) # 布尔索引为boolean_mask的语法糖形式输出[[-1 1 -1] [2 2 -2] [3 -3 3]] [-1 -1 -2 -3] [-1 -1 -2 -3]c[c0]是tf.boolean_mask(c, c0)的语法糖直接把条件表达式作为掩码筛选出所有满足条件的元素并展平返回。6. 通过修改元素生成新张量tf.where 与 tf.scatter_nd以上这些方法仅能提取张量的部分元素值但不能更改张量的部分元素值以得到新的张量。如果需要通过修改张量的部分元素值得到新张量可以使用tf.where和tf.scatter_nd。tf.where可以理解为 if 的张量版本此外它还可以用于找到满足条件的所有元素的位置坐标。tf.scatter_nd的作用与tf.gather_nd有些相反tf.gather_nd用于收集张量给定位置的元素而tf.scatter_nd可以将某些值插入到给定 shape 的全 0 张量的指定位置处。# 找到张量中小于0的元素,将其换成np.nan得到新的张量 # tf.where和np.where作用类似可以理解为if的张量版本 c tf.constant([[-1,1,-1],[2,2,-2],[3,-3,3]],dtypetf.float32) d tf.where(c0,tf.fill(c.shape,np.nan),c) d输出tf.Tensor: shape(3, 3), dtypefloat32, numpy array([[nan, 1., nan], [ 2., 2., nan], [ 3., nan, 3.]], dtypefloat32)三参数形式的tf.where(condition, x, y)逐元素执行if 条件成立取x否则取y这里把小于 0 的元素全部替换为np.nan。# 如果where只有一个参数将返回所有满足条件的位置坐标 indices tf.where(c0) indices输出tf.Tensor: shape(4, 2), dtypeint64, numpy array([[0, 0], [0, 2], [1, 2], [2, 1]])单参数形式的tf.where(condition)返回所有满足条件位置的坐标张量这正是配合tf.scatter_nd、tf.gather_nd使用的坐标生成器。# 将张量的第[0,0]和[2,1]两个位置元素替换为0得到新的张量 d c - tf.scatter_nd([[0,0],[2,1]],[c[0,0],c[2,1]],c.shape) d输出tf.Tensor: shape(3, 3), dtypefloat32, numpy array([[ 0., 1., -1.], [ 2., 2., -2.], [ 3., 0., 3.]], dtypefloat32)这里先用tf.scatter_nd(indices, updates, shape)把[c[0,0], c[2,1]]两个值插到全 0 张量的[0,0]、[2,1]位置再用原张量减去它等效于将这两个位置置 0。# scatter_nd的作用和gather_nd有些相反 # 可以将某些值插入到一个给定shape的全0的张量的指定位置处。 indices tf.where(c0) tf.scatter_nd(indices,tf.gather_nd(c,indices),c.shape)输出tf.Tensor: shape(3, 3), dtypefloat32, numpy array([[-1., 0., -1.], [ 0., 0., -2.], [ 0., -3., 0.]], dtypefloat32)tf.gather_nd(c, indices)先把负元素收集成一维向量tf.scatter_nd(indices, updates, c.shape)再把这些值按原坐标插回全 0 张量——一收一放正好演示了tf.gather_nd与tf.scatter_nd的互逆关系。四、维度变换reshape、squeeze、expand_dims、transpose维度变换相关函数主要有tf.reshape、tf.squeeze、tf.expand_dims、tf.transpose函数作用tf.reshape改变张量的形状tf.squeeze减少维度消除长度为 1 的维tf.expand_dims增加维度插入长度为 1 的维tf.transpose交换维度1. tf.reshape不改变元素存储顺序极快且可逆tf.reshape可以改变张量的形状但其本质上不会改变张量元素的存储顺序所以该操作实际上非常迅速并且是可逆的。a tf.random.uniform(shape[1,3,3,2], minval0,maxval255,dtypetf.int32) tf.print(a.shape) tf.print(a)输出TensorShape([1, 3, 3, 2]) [[[[135 178] [26 116] [29 224]] [[179 219] [153 209] [111 215]] [[39 7] [138 129] [59 205]]]]# 改成 3,6形状的张量 b tf.reshape(a,[3,6]) tf.print(b.shape) tf.print(b)输出TensorShape([3, 6]) [[135 178 26 116 29 224] [179 219 153 209 111 215] [39 7 138 129 59 205]]# 改回成 [1,3,3,2] 形状的张量 c tf.reshape(b,[1,3,3,2]) tf.print(c)输出[[[[135 178] [26 116] [29 224]] [[179 219] [153 209] [111 215]] [[39 7] [138 129] [59 205]]]]从输出可见[1,3,3,2]→[3,6]→[1,3,3,2]的两次 reshape 完全复原了数据元素值及其相对顺序没有任何变化。约束条件reshape 前后元素总数必须一致此处 1×3×3×2 18 3×6。另外可借助-1让 TensorFlow 自动推断某一维的长度例如tf.reshape(a, [3,-1])。2. tf.squeeze消除长度为 1 的维度如果张量在某个维度上只有一个元素利用tf.squeeze可以消除这个维度。和tf.reshape相似它本质上不会改变张量元素的存储顺序。张量的各个元素在内存中是线性存储的其一般规律是同一层级中的相邻元素的物理地址也相邻。s tf.squeeze(a) tf.print(s.shape) tf.print(s)输出TensorShape([3, 3, 2]) [[[135 178] [26 116] [29 224]] [[179 219] [153 209] [111 215]] [[39 7] [138 129] [59 205]]]tf.squeeze默认消除所有长度为 1 的维度也可用tf.squeeze(x, axis[0])精确指定只消除某个轴。这在模型输出形状为(1, N)需要降为(N,)时非常常用——仓库 english/Chapter3-1.md 中就用tf.squeeze(model(X)0.5)把(batch,1)的预测掩码压缩成一维后配合tf.boolean_mask使用。3. tf.expand_dims插入长度为 1 的新维度d tf.expand_dims(s,axis0) # 在第0维插入长度为1的一个维度 d输出tf.Tensor: shape(1, 3, 3, 2), dtypeint32, numpy array([[[[135, 178], [ 26, 116], [ 29, 224]], [[179, 219], [153, 209], [111, 215]], [[ 39, 7], [138, 129], [ 59, 205]]]], dtypeint32)tf.expand_dims(s, axis0)在第 0 维插入一个长度为 1 的新维度形状由(3,3,2)变为(1,3,3,2)与tf.squeeze互为逆操作。这是给单样本数据补 batch 维度、给向量补特征维如(N,)→(N,1)的标准手段。4. tf.transpose交换维度并改变存储顺序tf.transpose可以交换张量的维度与tf.reshape不同它会改变张量元素的存储顺序。tf.transpose常用于图片存储格式的变换上。# Batch,Height,Width,Channel a tf.random.uniform(shape[100,600,600,4],minval0,maxval255,dtypetf.int32) tf.print(a.shape) # 转换成 Channel,Height,Width,Batch s tf.transpose(a,perm[3,1,2,0]) tf.print(s.shape)输出TensorShape([100, 600, 600, 4]) TensorShape([4, 600, 600, 100])tf.transpose(a, perm[3,1,2,0])的含义是新张量的第 0 维取原张量的第 3 维Channel第 1、2 维保持 Height、Width 不变第 3 维取原第 0 维Batch从而把NHWCBatch, Height, Width, ChannelTensorFlow 默认图片布局转换为CHWBChannel, Height, Width, Batch。这种转换在跨框架加载预训练权重、调整存储布局时经常需要。仓库 english/Chapter4-2.md 的 SVD 分解演示中也用到了tf.transpose(v)求右奇异向量的转置。五、合并分割tf.concat、tf.stack 与 tf.split与 numpy 类似可以用tf.concat和tf.stack方法对多个张量进行合并用tf.split方法把一个张量分割成多个张量。tf.concat和tf.stack有略微的区别tf.concat是连接不会增加维度而tf.stack是堆叠会增加维度。a tf.constant([[1.0,2.0],[3.0,4.0]]) b tf.constant([[5.0,6.0],[7.0,8.0]]) c tf.constant([[9.0,10.0],[11.0,12.0]]) tf.concat([a,b,c],axis 0)输出tf.Tensor: shape(6, 2), dtypefloat32, numpy array([[ 1., 2.], [ 3., 4.], [ 5., 6.], [ 7., 8.], [ 9., 10.], [11., 12.]], dtypefloat32)tf.concat([a,b,c], axis0)沿第 0 维行方向拼接形状(2,2)(2,2)(2,2) → (6,2)维度数不变。tf.concat([a,b,c],axis 1)输出tf.Tensor: shape(2, 6), dtypefloat32, numpy array([[ 1., 2., 5., 6., 9., 10.], [ 3., 4., 7., 8., 11., 12.]], dtypefloat32)沿axis1列方向拼接则得到(2,6)。注意tf.concat要求所有待拼接张量在非拼接维度上的形状一致。tf.stack([a,b,c])输出tf.Tensor: shape(3, 2, 2), dtypefloat32, numpy array([[[ 1., 2.], [ 3., 4.]], [[ 5., 6.], [ 7., 8.]], [[ 9., 10.], [11., 12.]]], dtypefloat32)tf.stack([a,b,c],axis1)输出tf.Tensor: shape(2, 3, 2), dtypefloat32, numpy array([[[ 1., 2.], [ 5., 6.], [ 9., 10.]], [[ 3., 4.], [ 7., 8.], [11., 12.]]], dtypefloat32)tf.stack([a,b,c])默认沿新插入的第 0 维堆叠(2,2)×3 → (3,2,2)指定axis1则在中间插入新维→ (2,3,2)。堆叠的本质是把一组张量排成一层因此必然增加一个维度。tf.split是tf.concat的逆运算可以指定分割份数平均分割也可以通过指定每份的记录数量进行分割a tf.constant([[1.0,2.0],[3.0,4.0]]) b tf.constant([[5.0,6.0],[7.0,8.0]]) c tf.constant([[9.0,10.0],[11.0,12.0]]) c tf.concat([a,b,c],axis 0)# tf.split(value,num_or_size_splits,axis) tf.split(c,3,axis 0) # 指定分割份数平均分割输出[tf.Tensor: shape(2, 2), dtypefloat32, numpy array([[1., 2.], [3., 4.]], dtypefloat32), tf.Tensor: shape(2, 2), dtypefloat32, numpy array([[5., 6.], [7., 8.]], dtypefloat32), tf.Tensor: shape(2, 2), dtypefloat32, numpy array([[ 9., 10.], [11., 12.]], dtypefloat32)]tf.split(c,[2,2,2],axis 0) # 指定每份的记录数量输出[tf.Tensor: shape(2, 2), dtypefloat32, numpy array([[1., 2.], [3., 4.]], dtypefloat32), tf.Tensor: shape(2, 2), dtypefloat32, numpy array([[5., 6.], [7., 8.]], dtypefloat32), tf.Tensor: shape(2, 2), dtypefloat32, numpy array([[ 9., 10.], [11., 12.]], dtypefloat32)]tf.split(value, num_or_size_splits, axis)的第二个参数有两种传法传整数3表示均分成 3 份传列表[2,2,2]表示按每份的长度切分各份长度之和必须等于该维的总长度此处 2226。两种方式在本例中得到相同结果。tf.split返回的是张量列表。六、结构操作在仓库项目中的真实应用以上 API 并非孤立概念而是贯穿仓库全部章节的基础能力。下面列举几个可直接追溯源码的真实用例。1. 数据管道中的乱序取批tf.gatherenglish/Chapter3-1.md 的低阶 API 线性回归示例中作者手写了一个基于tf.gather的批数据生成器def data_iter(features, labels, batch_size8): num_examples len(features) indices list(range(num_examples)) np.random.shuffle(indices) # 随机化样本读取顺序 for i in range(0, num_examples, batch_size): indexs indices[i: min(i batch_size, num_examples)] yield tf.gather(features,indexs), tf.gather(labels,indexs)先用np.random.shuffle打乱整数下标再用tf.gather按下标批量取出特征与标签——这正是tf.gather在自定义训练循环中最重要的应用场景之一。2. 构造分类数据集tf.concat同一章节english/Chapter3-1.md在构造 DNN 二分类样本时把正负两类样本拼接成完整数据集Xp tf.concat([r_p*tf.cos(theta_p),r_p*tf.sin(theta_p)],axis 1) Xn tf.concat([r_n*tf.cos(theta_n),r_n*tf.sin(theta_n)],axis 1) X tf.concat([Xp,Xn],axis 0) Y tf.concat([Yp,Yn],axis 0)先沿axis1把极坐标的半径与角度分量合成二维坐标再沿axis0拼接正负样本得到用于训练的特征矩阵与标签向量。tf.concat的这种用法在 english/Chapter3-2.md 与 english/Chapter3-3.md 中完全一致地复现。3. 预测阈值化tf.whereenglish/Chapter3-1.md 在评估模型时用tf.where把连续概率输出转换为离散类别y_pred tf.where(y_pred0.5,tf.ones_like(y_pred,dtype tf.float32), tf.zeros_like(y_pred,dtype tf.float32))这正是if 的张量版本预测概率大于 0.5 置 1否则置 0全程无 Python 循环、可被图模式编译。4. 按预测类别分离样本tf.boolean_maskenglish/Chapter3-1.md 在绘制分类边界时用tf.boolean_mask配合布尔条件把正负样本分开着色Xp_pred tf.boolean_mask(X,tf.squeeze(model(X)0.5),axis 0) Xn_pred tf.boolean_mask(X,tf.squeeze(model(X)0.5),axis 0)先tf.squeeze把(batch,1)的布尔掩码压成一维再沿axis0过滤样本——tf.squeeze与tf.boolean_mask的组合用法在这里体现得淋漓尽致。5. 展平标签计算损失tf.reshapeenglish/Chapter3-2.md 中中阶 API 的自定义损失函数里用tf.reshape将预测与标签统一展平为[-1]后计算损失loss model.loss_func(tf.reshape(labels,[-1]), tf.reshape(predictions,[-1]))-1让 TensorFlow 自动推断该维长度这一写法在仓库的多个损失计算处如 english/Chapter3-2.md反复出现。6. 指标计算中的按序重排tf.gatherenglish/Chapter5-6.md 在实现排序类评估指标如 AUC 类指标计算时用tf.gather按排序索引重排预测值与真实值y_pred_sorted tf.gather(y_pred,t.indices) y_true_sorted tf.gather(y_true,t.indices)tf.gather在这里承担了按任意顺序取下标的通用重排能力。7. 矩阵分解中的转置tf.transposeenglish/Chapter4-2.md 数学运算章节在 SVD 分解后重建矩阵时使用tf.transpose(v)获取右奇异向量的转置与本文介绍的维度交换操作一脉相承。七、小结与延伸阅读本文系统梳理了 TensorFlow 2 张量的全部结构操作创建tf.constant、tf.range、tf.linspace、tf.zeros/ones/zeros_like/fill、tf.random.uniform/normal/truncated_normal、tf.eye、tf.linalg.diag索引切片规则切片下标、负索引、步长、省略号、tf.slice、tf.Variable的assign与不规则提取tf.gather、tf.gather_nd、tf.boolean_mask修改元素生成新张量tf.whereif 的张量版本与tf.scatter_ndtf.gather_nd的逆操作维度变换tf.reshape不改存储顺序、可逆、tf.squeeze降维、tf.expand_dims升维、tf.transpose交换维度并改变存储顺序常用于图片布局转换合并分割tf.concat连接、不增维、tf.stack堆叠、增维、tf.split均分或按份数切分。在此基础上可以继续阅读english/Chapter4-2.md张量的数学运算标量、向量、矩阵运算与广播机制english/Chapter3-1.md低阶 API 示范线性回归与 DNN 二分类的完整实现english/Chapter2-1.md张量数据类型与阶的详细说明english/Chapter4-3.mdAutoGraph 使用规范理解为何本教程统一使用tf.print、tf.range等 TensorFlow 定义的函数而非原生 Python 函数README_eng.md仓库学习路线与环境配置说明。掌握结构操作是流畅书写 TensorFlow 2 代码的基础功——无论是手写数据管道、自定义训练循环还是实现排序类评估指标这些操作都会反复出现值得像熟悉 numpy 一样彻底掌握。赞分享教程深度学习机器学习【免费下载链接】eat_tensorflow2_in_30_daysTensorflow2.0 is delicious, just eat it! 项目地址https://gitcode.com/gh_mirrors/ea/eat_tensorflow2_in_30_days点击查看免费下载相关推荐TensorFlow2 张量结构操作全解创建、索引切片、维度变换与合并分割《30天吃掉那只TensorFlow2》第4-1节TensorFlow2 张量结构操作全解创建、索引切片、维度变换与合并分割《30天吃掉那只TensorFlow2》第4 1节 张量的结构操作是 Tenso教程深度学习机器学习如何免费把QQ空间历史说说批量备份到本地如何免费把QQ空间历史说说批量备份到本地 凌晨两点你想找几张几年前旅行时发说说的配图QQ空间的时间线却越刷越短那一页早就不见了。GetQzonehisto网页爬虫数据分析TensorFlow2 张量数据结构全解析从常量、变量到多维张量eat_tensorflow2_in_30_days 第 2-1 节TensorFlow2 张量数据结构全解析从常量、变量到多维张量eat_tensorflow2_in_30_days 第 2 1 节 本文基于开源教程《e教程深度学习机器学习创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表