![TensorFlow.NET实战](https://wfqqreader-1252317822.image.myqcloud.com/cover/278/46418278/b_46418278.jpg)
第2章
数据类型与张量详解
2.1 数据类型
TensorFlow本质上是一个深度学习的科学计算库,这个库的主要数据类型为张量,所有的运算都是基于张量数据进行的操作,更复杂的网络模型也只是一些基础运算的组合拼接,只有深入理解基本的张量运算,才能在各种深度学习的网络模型中游刃有余,开发出有价值、有创意的算法模型。
TensorFlow中基本的数据类型有数值类型、字符串类型和布尔类型。下面简单举例介绍。
(1)数值类型:var x=tf.Variable(10,name:"x")。
(2)字符串类型:var mammal1=tf.Variable("Elephant",name:"var1",dtype:tf.@string)。
(3)布尔类型:var bo=tf.Variable(true)。
具体数据类型如下。
![](https://epubservercos.yuewen.com/E3272D/25638808101564006/epubprivate/OEBPS/Images/44309_22_1.jpg?sign=1739571024-dNjFAtwiB10gyOH0KDoFE6hKSVgqk1Tq-0-80f9e3aa50aaa96df0c21386fe3b9ef5)
2.2 张量详解
类似于NumPy中的N维数组对象NDArray,TensorFlow中数据的基本单位为张量(Tensor)。二者都是多维数组的概念。我们可以使用张量表示标量(0维数组)、向量(1维数组)、矩阵(2维数组)。
张量的主要特性为形状、类型和值,可以通过张量的属性shape、dtype和方法numpy()来获取特性。举例如下。
1.形状获取
![](https://epubservercos.yuewen.com/E3272D/25638808101564006/epubprivate/OEBPS/Images/44309_23_1.jpg?sign=1739571024-YGab1V3JGKl6LO9hBnY6zdOog3E4m6JE-0-a83856455c7a3d046a22829c5e3cfeb0)
上述代码运行后返回结果true,张量的属性shape通过返回整型1维数组的方式来显示张量的形状。
我们也可以直接通过TensorFlow.Binding封装的print()方法输出形状。
![](https://epubservercos.yuewen.com/E3272D/25638808101564006/epubprivate/OEBPS/Images/44309_23_2.jpg?sign=1739571024-wMoNcIc5L1TJkUKUHF1dkoMQyxF6Ap1y-0-1f4c3d77737fed66ab450d9ba059969d)
输出如下。
![](https://epubservercos.yuewen.com/E3272D/25638808101564006/epubprivate/OEBPS/Images/44309_23_3.jpg?sign=1739571024-n71Tk6setWUkVP11i5MQK5AJbJbB2bdI-0-8f9defdd81cc9e4d2ba89630f0335f8f)
2.类型获取
![](https://epubservercos.yuewen.com/E3272D/25638808101564006/epubprivate/OEBPS/Images/44309_23_4.jpg?sign=1739571024-uWEhBJuNRxSbtR77lQfM8UxFBu6fAweT-0-fc5470e5bc6114ef194b93710768bb54)
输出如下。
![](https://epubservercos.yuewen.com/E3272D/25638808101564006/epubprivate/OEBPS/Images/44309_23_5.jpg?sign=1739571024-uJvy0eSlGJnI2Q8tYXaWkfC0lQM2QtHu-0-ce22cb2cbb3c2340464279337dbbec44)
张量的属性dtype返回TF_DataType类型的枚举,可以很方便地通过print()方法进行输出。
3.值获取
![](https://epubservercos.yuewen.com/E3272D/25638808101564006/epubprivate/OEBPS/Images/44309_23_6.jpg?sign=1739571024-PLqyuftK5Dy5cZpCUr5ksz6fg7BVkUu6-0-76ebfb6684dd35d12aa28b86bc61266f)
输出如下。
![](https://epubservercos.yuewen.com/E3272D/25638808101564006/epubprivate/OEBPS/Images/44309_24_1.jpg?sign=1739571024-xZiDTisc4ehLXzJZ5CVqDVIb6A1baflQ-0-2c8dd55cf1ede47a127a4b381099962f)
张量的numpy()方法返回NumSharp.NDArray类型的值,内容为张量保存的值内容,可以很方便地通过print()方法进行输出。
4.类型转换
在C#中,可以快速对0维张量进行类型转换,通过在变量前加(type)进行强制类型转换,代码参考如下。
![](https://epubservercos.yuewen.com/E3272D/25638808101564006/epubprivate/OEBPS/Images/44309_24_2.jpg?sign=1739571024-m7hpbCNPJ4LEGHpVBy64Tdo92Xs4vvT3-0-efe6c565e99264ca965282214eb3f4d0)
结果输出如下。
![](https://epubservercos.yuewen.com/E3272D/25638808101564006/epubprivate/OEBPS/Images/44309_24_3.jpg?sign=1739571024-o0AglbcDIV0DhXfR95FdYdoXJ4PpA6tr-0-4a376e8d9be79ae823ae812061a91f46)
通过上述结果可以看到,原来的张量类型被快速转换成普通的数值类型。
2.3 常量与变量
从行为特性来看,有常量constant和变量Variable两种类型的张量。
常量在计算图中不可以被重新赋值;变量在计算图中可以用assign等算子重新赋值。
1.常量
一般的常量类型如下。
![](https://epubservercos.yuewen.com/E3272D/25638808101564006/epubprivate/OEBPS/Images/44309_24_4.jpg?sign=1739571024-pnuwDECUI16kMvqOnvKbrsV58dftRwFx-0-176f853c491bc2348344bee1c5b8cfdb)
![](https://epubservercos.yuewen.com/E3272D/25638808101564006/epubprivate/OEBPS/Images/44309_25_1.jpg?sign=1739571024-yjOdMZeepAtgryi192SMjALjUhOGlBJ9-0-7da6b2b746c7ad9a33a64d386e5a9b77)
输出如下。
![](https://epubservercos.yuewen.com/E3272D/25638808101564006/epubprivate/OEBPS/Images/44309_25_2.jpg?sign=1739571024-s1nyobp6qeRkxgrsVtd7Hj2eLttAgJe7-0-c6f587565b30da87d9af5126d949c500)
我们来写一个4维的常量,并通过tf.rank函数返回张量的秩。
一般来说,标量为0维张量,向量为1维张量,矩阵为2维张量。
彩色图像有r、g、b三个通道,可以表示为3维张量。
视频增加一个时间维,可表示为4维张量。
代码如下。
![](https://epubservercos.yuewen.com/E3272D/25638808101564006/epubprivate/OEBPS/Images/44309_25_3.jpg?sign=1739571024-cfDyEgYEn8KNDSgs8JmTkFT3esJWzVUD-0-63dc2b98addc2aee06ce8253f5841d22)
![](https://epubservercos.yuewen.com/E3272D/25638808101564006/epubprivate/OEBPS/Images/44309_26_1.jpg?sign=1739571024-SKcNC76rZhy1BqYv9rgqYKGI71T4v8q9-0-7d2e3142834c3ae4dc4ce95845905b20)
代码运行后输出结果如下。
![](https://epubservercos.yuewen.com/E3272D/25638808101564006/epubprivate/OEBPS/Images/44309_26_2.jpg?sign=1739571024-WSWiMz7pAqTvLIym5BJED1K2UlCDh8eG-0-7c90d3af47372949774227bdd9e10e8c)
2.变量
在深度学习模型中,一般被训练的参数需要定义为变量,变量的值可以在模型训练过程中被修改。
我们简单测试一个2维数组的变量,代码如下。
![](https://epubservercos.yuewen.com/E3272D/25638808101564006/epubprivate/OEBPS/Images/44309_26_3.jpg?sign=1739571024-YWQdZRZMBdyonW92rT3mssWdueM9m4SN-0-cea198bcb43c294ffc9fdf6849f0ed9a)
代码输出如下。
![](https://epubservercos.yuewen.com/E3272D/25638808101564006/epubprivate/OEBPS/Images/44309_26_4.jpg?sign=1739571024-wVFIwZCdaQDwrEdDGDdQ6CM7fMungdJE-0-d5bc46831caa421ac058e31b1c6615bb)
接下来我们一起看下常量和变量的差别:常量的值可以参与运算,也可以被重新赋值,但是重新赋值或运算后的结果会开辟新的内存空间;变量的值可以通过assign、assign_add等算子重新赋值。代码如下。
![](https://epubservercos.yuewen.com/E3272D/25638808101564006/epubprivate/OEBPS/Images/44309_26_5.jpg?sign=1739571024-n444SBilOWyIQBpiqLRILdcKfS5Y8zZB-0-0a505f770e8bab5f5582bbc1f0535656)
![](https://epubservercos.yuewen.com/E3272D/25638808101564006/epubprivate/OEBPS/Images/44309_27_1.jpg?sign=1739571024-3H3M0cZrT8mS2X0nGBFx5N3Xw4LbCAaZ-0-f16c00ab89a18f02787e96f82a50af10)
输出结果如下。
![](https://epubservercos.yuewen.com/E3272D/25638808101564006/epubprivate/OEBPS/Images/44309_27_2.jpg?sign=1739571024-PImdAKtkDKPyb2haCJODZ9cOGlXULUzd-0-1677f8d94bfd1550c6133e98fede6f46)
2.4 字符串常见操作
TensorFlow.NET中有专门的创建、转换和截取等常见的字符串操作。
1.通过byte数组创建字符串
传入Hex十六进制的byte数组,打印输出对应的转换后的字符串,代码如下。
![](https://epubservercos.yuewen.com/E3272D/25638808101564006/epubprivate/OEBPS/Images/44309_27_3.jpg?sign=1739571024-V0kv8x7zDROnWPeY1EeUpLpSrePiRo30-0-2d97eb2a1fe0ba2986ec549812549c02)
输出结果如下。
![](https://epubservercos.yuewen.com/E3272D/25638808101564006/epubprivate/OEBPS/Images/44309_27_4.jpg?sign=1739571024-23She4DQ6W4fIKUyE5EZYG6ZpNtKKf3X-0-d1d8e2db75fe3e37d72839f63825bcb7)
也可以通过ToString()方法将张量整体转换为字符串进行输出,代码如下。
![](https://epubservercos.yuewen.com/E3272D/25638808101564006/epubprivate/OEBPS/Images/44309_27_5.jpg?sign=1739571024-trfu3GUGMFIqMiuR1oz3wfMPRzCTa5tD-0-4ed0981c95e6ffb0fc045cf4e6628149)
输出结果如下。
![](https://epubservercos.yuewen.com/E3272D/25638808101564006/epubprivate/OEBPS/Images/44309_28_1.jpg?sign=1739571024-8auZyQWeV3tV0KKIgN7KNxkasLr9gyQG-0-ddd8d3fe1190f4fda77b3fa02d7837b1)
2.通过numpy()方法转换字符串的值
numpy()方法可以转换字符串的值,代码如下。
![](https://epubservercos.yuewen.com/E3272D/25638808101564006/epubprivate/OEBPS/Images/44309_28_2.jpg?sign=1739571024-HOEOwCZbHLz3mnkappKYLca7MaPT2aFP-0-0cf8ecb06316f17da4cd8b988e2c2b50)
输出结果如下。
![](https://epubservercos.yuewen.com/E3272D/25638808101564006/epubprivate/OEBPS/Images/44309_28_3.jpg?sign=1739571024-pWNaGspQb2GfM2vKYLzITU6pHsQWWpAt-0-66d71ca69c46cdb2fa2c142b652ced47)
3.通过tf.strings.substr()方法截取字符串
tf.strings.substr()方法可以截取字符串。下述代码演示字符串的截取,并对截取后的字符串进行比较,最后输出张量的布尔标量值。
![](https://epubservercos.yuewen.com/E3272D/25638808101564006/epubprivate/OEBPS/Images/44309_28_4.jpg?sign=1739571024-xZdYWEWniQmW4p9nHK3ZgQKwhKWTP6m6-0-3fe3b2228a1967a9d94a04e33e94da2e)
输出结果如下。
![](https://epubservercos.yuewen.com/E3272D/25638808101564006/epubprivate/OEBPS/Images/44309_28_5.jpg?sign=1739571024-Edgk9xHP26w4McqBvGNXzq2Hqrm7nUK7-0-27a4ada0da8975e605efc9a4b1affdbc)
主要参数说明如下。
方法名:tf.strings.substr(Tensor input,int pos,int len,string name=null,string@uint="BYTE")。
参数1:input,类型为Tensor,待截取的输入字符串。
参数2:pos,类型为int,起始位置。
参数3:len,类型为int,截取长度。
返回值:类型为Tensor,返回截取后输出的字符串。
4.字符串数组张量的创建和转换
下述代码演示了字符串数组张量的创建,并可以打印出张量的形状和张量的内容。ToString()方法可以将张量的完整内容转换为string;StringData()方法可以提取出张量的值并转换为string[]数组类型。
![](https://epubservercos.yuewen.com/E3272D/25638808101564006/epubprivate/OEBPS/Images/44309_29_1.jpg?sign=1739571024-JuQ8sE3UgEaQxz01YAPJok9wRWYxThDX-0-debd9109919e9b5e5e75525010d0bc56)
输出结果如下。
![](https://epubservercos.yuewen.com/E3272D/25638808101564006/epubprivate/OEBPS/Images/44309_29_2.jpg?sign=1739571024-p8dZPqPj7VdPb4AmTrh1cUI95Nd69dOf-0-a06dacbbf4dc274cd49cf8b9b1393231)
5.本地文件(图像)读取示例
我们可以通过tf.io.read_file()方法从本地读取文件(图像),并打印和测试该文件(图像)的前3个byte数据,代码如下。
![](https://epubservercos.yuewen.com/E3272D/25638808101564006/epubprivate/OEBPS/Images/44309_29_3.jpg?sign=1739571024-wHgvvBHsVbgfRi7OOwCceypzMc5p6b8Y-0-749f1aaaefcfb79e44696c7c5c947bda)
![](https://epubservercos.yuewen.com/E3272D/25638808101564006/epubprivate/OEBPS/Images/44309_30_1.jpg?sign=1739571024-lFIX2THtd2klBlo1VejGTw1I5NDlhmTO-0-e621a659dd5158d9563254f0516c4338)
输出结果如下。
![](https://epubservercos.yuewen.com/E3272D/25638808101564006/epubprivate/OEBPS/Images/44309_30_2.jpg?sign=1739571024-DA6Z4s7uIA2Oas6bJS7LWhtZ1wOBfQz1-0-4beca73b07899ec10a2ebcc7ece2cf6f)
2.5 基本张量操作
张量是TensorFlow.NET中常用的数据结构,TensorFlow.NET中内置了大量的基础张量操作方法,可以进行张量的创建、索引和修改等。
1.tf.cast改变张量的数据类型
下述例子演示的是将int32类型的值转换为float32类型的值。
![](https://epubservercos.yuewen.com/E3272D/25638808101564006/epubprivate/OEBPS/Images/44309_30_3.jpg?sign=1739571024-MaOFWLcGohG901KWWKBKdF80DNOc3XL0-0-c200f49519e744e6eaa5c5056d272a8d)
通过tf.cast将int32类型的值转换为float32类型的值,输出结果如下。
![](https://epubservercos.yuewen.com/E3272D/25638808101564006/epubprivate/OEBPS/Images/44309_30_4.jpg?sign=1739571024-e8aG05lPX0eC7eS2OvpX6FwvYts9SprA-0-165b220efd3ee28a4e4d593ac057c7f4)
2.tf.range创建区间张量值
![](https://epubservercos.yuewen.com/E3272D/25638808101564006/epubprivate/OEBPS/Images/44309_30_5.jpg?sign=1739571024-W6MO4ZSX4F1kgXc1Nt6qrE4QfNQe0vOs-0-82a545f0e058d701d41c11a6c341e04e)
常用参数说明如下。
参数1:start,区间初始值。
参数2:limit,区间限定值,取值<limit(不等于limit)。
参数3:delta,区间值递增的差量。
输出结果如下。
![](https://epubservercos.yuewen.com/E3272D/25638808101564006/epubprivate/OEBPS/Images/44309_31_1.jpg?sign=1739571024-4aUrr3r63JlK9bGBBmFHUaAANlluEIRQ-0-d5c04baa09215145ef4fbc24050a512f)
3.tf.zeros/tf.ones创建0值和1值的张量
下述例子创建了一个3×4的0值张量和4×5的1值张量,一般可用于张量的初始化。
![](https://epubservercos.yuewen.com/E3272D/25638808101564006/epubprivate/OEBPS/Images/44309_31_2.jpg?sign=1739571024-UKNzs8SWFivdI2YdbGh5pji554JobWTw-0-b79e398852f2774b941b4a5f1dd47a93)
输出结果如下。
![](https://epubservercos.yuewen.com/E3272D/25638808101564006/epubprivate/OEBPS/Images/44309_31_3.jpg?sign=1739571024-7P3zxU7wxOUWCp3cT4dUDas0dUXOJUL8-0-e17623214a423ecb575f7c798f14351c)
4.tf.random生成随机分布张量
tf.random.normal用于随机生成正态分布的张量;tf.random.truncated_normal用于随机生成正态分布的张量,并剔除2倍方差以外的数据。
![](https://epubservercos.yuewen.com/E3272D/25638808101564006/epubprivate/OEBPS/Images/44309_31_4.jpg?sign=1739571024-DNYCL0if086P9chwEtgI3CLRjoLkU51s-0-e0a2bf547182720e324a9a5a8076ae68)
常用参数说明如下。
参数1:shape,生成的正态分布张量的形状。
参数2:mean,正态分布的中心值。
参数3:stddev,正态分布的标准差。
输出结果如下。
![](https://epubservercos.yuewen.com/E3272D/25638808101564006/epubprivate/OEBPS/Images/44309_32_1.jpg?sign=1739571024-nHHTsX5ji8yl2NZ1KIStzcHukkdiJG0d-0-7e6c67ea9995acb5c4a48abfee813cce)
5.索引切片
可以通过张量的索引来读取元素;对于变量,可以通过索引对部分元素进行修改。
下述为张量的索引功能的演示。
![](https://epubservercos.yuewen.com/E3272D/25638808101564006/epubprivate/OEBPS/Images/44309_32_2.jpg?sign=1739571024-Kz6GDSdElywxhT6dYnyMipD2X1rSflSv-0-8ad25bce5a513f3ef76975a1df77d6d4)
输出结果如下。
![](https://epubservercos.yuewen.com/E3272D/25638808101564006/epubprivate/OEBPS/Images/44309_33_1.jpg?sign=1739571024-zV6R2CKAwZh8oX2BRrypTv8Av81fp0qw-0-a6f36ddc6413367d6759ae1e58bba4f9)
下述为张量的切片读取功能的演示。
![](https://epubservercos.yuewen.com/E3272D/25638808101564006/epubprivate/OEBPS/Images/44309_33_2.jpg?sign=1739571024-tnwk6S2YRT37ntWBgOgdLfMnkvvr6FC6-0-04164085c90a579cafd0dcb06f3bbd24)
输出结果如下。
![](https://epubservercos.yuewen.com/E3272D/25638808101564006/epubprivate/OEBPS/Images/44309_33_3.jpg?sign=1739571024-zRO9WwmcG9jQHMlaEkSGiCwjuVMUpEWq-0-1257eb71e116b9ffa02fe2d971abd5c0)
![](https://epubservercos.yuewen.com/E3272D/25638808101564006/epubprivate/OEBPS/Images/44309_34_1.jpg?sign=1739571024-FRaGi2fFkLQV3d7hzBQEQS4MfB798qNK-0-4acfe26ea25212c3a1163ddbc102807d)
下述为张量的切片赋值功能的演示,通过assign算子实现。
![](https://epubservercos.yuewen.com/E3272D/25638808101564006/epubprivate/OEBPS/Images/44309_34_2.jpg?sign=1739571024-4UzJ4RA4ZcJ3SYRVm1m4A3eSjhdUW3Rg-0-1e1a595482597efe9534018180801f21)
程序运行后,通过assign算子对[":2",":2"]的张量切片进行赋值,结果如下。
![](https://epubservercos.yuewen.com/E3272D/25638808101564006/epubprivate/OEBPS/Images/44309_34_3.jpg?sign=1739571024-r1KHckYuKhO6a1rM5il1dZkfDibHhXbX-0-f72a6b3f878156b582e2344f16303127)
![](https://epubservercos.yuewen.com/E3272D/25638808101564006/epubprivate/OEBPS/Images/44309_35_1.jpg?sign=1739571024-7zyL6BpnhhucN68NqTAM7prXd8CBlUBh-0-06d9f751e4ba636dcac0e3190c888852)
6.张量比较
tf.equal可以比较两个张量是否相同;ToScalar可以获取布尔标量值。代码如下。
![](https://epubservercos.yuewen.com/E3272D/25638808101564006/epubprivate/OEBPS/Images/44309_35_2.jpg?sign=1739571024-K3rCTfFfpiyWRKP06NdMRLESeXzYW1MG-0-80461dff62fe6700ef38b4cc429d60e9)
输出结果如下。
![](https://epubservercos.yuewen.com/E3272D/25638808101564006/epubprivate/OEBPS/Images/44309_35_3.jpg?sign=1739571024-RUUBu1IhlZcgzcwPinT8jgxkVzx7n6vW-0-f61957ca42960dc2b357566ed3df7cec)
2.6 维度变换
张量的维度变换操作主要是指改变张量的形状,主要方法有tf.reshape、tf.squeeze、tf.expand_dims和tf.transpose。
1.tf.reshape改变张量的形状
tf.reshape主要改变张量的形状,该操作不会改变张量在内存中的存储顺序,因此速度非常快,并且操作可逆。
![](https://epubservercos.yuewen.com/E3272D/25638808101564006/epubprivate/OEBPS/Images/44309_35_4.jpg?sign=1739571024-PTv8xINJEkcEZvNu2GGlV4boysVFaEOG-0-d5390d9e241d43ac1fb9f268aad89adb)
![](https://epubservercos.yuewen.com/E3272D/25638808101564006/epubprivate/OEBPS/Images/44309_36_1.jpg?sign=1739571024-ZXosDVwdVqxF5NlYTAekPlBqumTL6ovY-0-13bd86c220966a88380b85ceed1d9895)
输出结果如下。
![](https://epubservercos.yuewen.com/E3272D/25638808101564006/epubprivate/OEBPS/Images/44309_36_2.jpg?sign=1739571024-FhqUcglHUaCPdArFHz6q95XRdAMB2WTX-0-6a9ff634eeac82c12fa3e53af840f38a)
2.tf.squeeze维度压缩简化
tf.squeeze可以消除张量中的单个元素的维度。和tf.reshape一样,该操作不会改变张量在内存中的存储顺序。
![](https://epubservercos.yuewen.com/E3272D/25638808101564006/epubprivate/OEBPS/Images/44309_36_3.jpg?sign=1739571024-eBEYjpOOFNBecmuEEzJW7Xl5SDQ8uwWg-0-e2c98b54187c805855ac6b77be8d7ab1)
输出结果如下。
![](https://epubservercos.yuewen.com/E3272D/25638808101564006/epubprivate/OEBPS/Images/44309_36_4.jpg?sign=1739571024-9UslsekIyQ7hY511tQhZS8LOGrx7gYwv-0-273541326db37f56685384f659e096c6)
3.tf.expand dims增加维度
tf.squeeze的逆向操作为tf.expand_dims,即往指定的维度中插入长度为1的维度。
![](https://epubservercos.yuewen.com/E3272D/25638808101564006/epubprivate/OEBPS/Images/44309_37_1.jpg?sign=1739571024-COpfOInx7cQhSBfc6oIiD7vTg5PTyrA3-0-b1cef1ef8e86eafaf24e834eaa0aa6ff)
输出结果如下。
![](https://epubservercos.yuewen.com/E3272D/25638808101564006/epubprivate/OEBPS/Images/44309_37_2.jpg?sign=1739571024-6lURrempV0qifIp6QmAFgRIMIQTBOvwI-0-75ade21c4c3a0a93b8b6f79a64d4a5d0)
4.tf.transpose维度交换
tf.transpose可以交换张量的维度,与tf.reshape不同,它会改变张量在内存中的存储顺序。
![](https://epubservercos.yuewen.com/E3272D/25638808101564006/epubprivate/OEBPS/Images/44309_37_3.jpg?sign=1739571024-WJuHOgf2EOEfCw7Vuet0oPH5spbssltm-0-58dd16794faedfa2ed72523366a976d7)
输出结果如下。
![](https://epubservercos.yuewen.com/E3272D/25638808101564006/epubprivate/OEBPS/Images/44309_37_4.jpg?sign=1739571024-y0w4Ol4kS3KX4OGupgZCv7Uxk4eL5V7P-0-be459e3820153dbef6cfdd12d9d26d68)
![](https://epubservercos.yuewen.com/E3272D/25638808101564006/epubprivate/OEBPS/Images/44309_38_1.jpg?sign=1739571024-exYKiV2xTK2xYNY56j5GIakH6w8PFCyc-0-02c7fecf1ec5b1a9cb9298c0a79b66ed)
tf.transpose维度交换过程示意图如图2-1所示。
![](https://epubservercos.yuewen.com/E3272D/25638808101564006/epubprivate/OEBPS/Images/44309_38_2.jpg?sign=1739571024-1gZtKqS2COjFoDR3lb3D4GZHTdJBbOwZ-0-2a3c04ac1009315bf278dd62a8b7ca72)
图2-1 tf.transpose维度交换过程示意图
2.7 合并分割
张量的合并分割和NumPy类似,其中合并有两种不同的实现方式:tf.concat可以连接不同的张量,在同一设定的维度进行,不会增加维度;tf.stack采用维度堆叠的方式,会增加维度。
1.tf.concat
我们来测试一下使用tf.concat连接3个形状为[2,2]的张量。concatValue1通过在axis:0维度中的张量连接操作,将3个张量合并为1个形状为[6,2]的新张量;concatValue2通过在axis:-1维度中的张量连接操作,将3个张量合并为1个形状为[2,6]的新张量。
![](https://epubservercos.yuewen.com/E3272D/25638808101564006/epubprivate/OEBPS/Images/44309_38_3.jpg?sign=1739571024-zjAL2N97ClsiIlW23UQQU77E9fQAsuoN-0-11dc665290fc487b4852af8afe92469b)
输出如下,正确地实现了张量的连接合并功能。
![](https://epubservercos.yuewen.com/E3272D/25638808101564006/epubprivate/OEBPS/Images/44309_39_1.jpg?sign=1739571024-EtdRJapzzrdO0M9WPjbvOkAG9FW5Ioy1-0-c7f4b2300969a557e1274996a0de6770)
2.tf.stack
同样是上面的例子,我们将tf.concat替换为tf.stack。可以看到,tf.stack在指定的维度上创建了新的维度,并将输入张量在新维度上进行堆叠操作。通过代码的运行,我们可以看到两种方式的内部机制的差异。
![](https://epubservercos.yuewen.com/E3272D/25638808101564006/epubprivate/OEBPS/Images/44309_39_2.jpg?sign=1739571024-L5t28haKFWUM6vrj4105iU664dvQk5Kd-0-708b09f3969cec409f883ca48927efb5)
输出结果如下。
![](https://epubservercos.yuewen.com/E3272D/25638808101564006/epubprivate/OEBPS/Images/44309_39_3.jpg?sign=1739571024-ltNbf0RA1tGDL6r2ncFGeyoeQf39N8JX-0-7680a407f64856c2b46b94aa7e39cd7b)
上面两个例子演示了张量的合并,接下来我们来测试张量的分割。张量的分割方法tf.split是tf.concat方法的逆操作,可以将张量平均分割或按照指定的形状分割。
3.tf.split
我们利用下述代码首先将a、b、c合并为shape:[3,2,2]的concatValue,然后通过tf.split将concatValue的0维分割,还原为3个shape:[2,2]的张量数组splitValue。
![](https://epubservercos.yuewen.com/E3272D/25638808101564006/epubprivate/OEBPS/Images/44309_40_1.jpg?sign=1739571024-0YQx7UM30X7PXmFUOf0wXpg1YhDsFzRr-0-e55415609b1d03e731325a5592930131)
输出结果如下。
![](https://epubservercos.yuewen.com/E3272D/25638808101564006/epubprivate/OEBPS/Images/44309_40_2.jpg?sign=1739571024-VaifaJHQUAEGgGzZmGVeza2buGtGv1fE-0-a434065384052cbccb8317b7dd63c05b)
2.8 广播机制
本节我们聊聊在NumPy和张量中都很常用并很重要的一个特性:Broadcasting,即广播机制,又称作自动扩展机制。广播是一种十分轻量的张量复制操作,只会在逻辑上扩展张量的形状,而不会直接执行实际存储I/O的复制操作。经过广播后的张量在视图上会体现出复制后的形状。
在进行实际数据运算的时候,广播机制会通过深度学习框架的优化技术,避免实际复制数据而完成逻辑运算。对于用户来说,广播机制和tf.tile复制数据的最终实现效果是相同的,但是广播机制节省了大量的计算资源并自动优化了运算速度。
但是,广播机制并不是任何场合都适用的,下面我们来介绍广播机制的使用规则和实现效果。
(1)如果张量的维度不同,则对维度较小的张量左侧补齐进行扩展,直到两个张量的维度相同。
(2)如果两个张量在某个维度上的长度是相同的,或者其中一个张量在该维度上的长度为1,则我们说这两个张量在该维度上是相容的。
(3)如果两个张量在所有维度上或通过上述(1)的过程扩展后都是相容的,则它们能使用广播机制。这是广播机制的核心思想——普适性。
(4)广播之后,每个维度的长度取两个张量在该维度长度上的较大值。
(5)在任何一个维度上,如果一个张量的长度为1,另一个张量的长度大于1,那么在该维度上,就好像对第一个张量进行了复制。
我们通过图解的方式进一步举例说明。
首先来看可广播的情形:张量B的形状为[w,1],张量A的形状为[b,h,w,c],不同维度的张量相加运算A+B是可以正常运行的,这就是广播机制的作用,张量B通过广播机制扩展为和A相同的形状[b,h,w,c]。正常的广播扩展过程如图2-2所示,分为3步。
![](https://epubservercos.yuewen.com/E3272D/25638808101564006/epubprivate/OEBPS/Images/44309_41_1.jpg?sign=1739571024-2PD6Nclt0Jfj7mT7gem4jl1ozADy2GWz-0-2e925c8805f37d38f08554cbaf9d68d0)
图2-2 正常的广播扩展过程
然后来看不可广播的情形:同样是上面这个例子,如果张量B的形状为[w,2],同时张量A的形状为[b,h,w,c],其中c≠2,则这两个张量不符合普适性原则,无法应用广播机制,运行张量相加操作A+B会触发报错机制。无法应用广播机制的内部原理如图2-3所示。
广播机制的实现有两种方式。
1.隐式自动调用
在进行不同形状的张量运算时,隐式地自动调用广播机制,如用“+、-、*、/”等运算,先将参与运算的张量广播成统一的形状,再进行相应的运算。
![](https://epubservercos.yuewen.com/E3272D/25638808101564006/epubprivate/OEBPS/Images/44309_42_1.jpg?sign=1739571024-aexxEwQR019MAwlAQ3SJBTJFEjJjdUzY-0-ceca519106513d90295a98cdbf1ef78c)
图2-3 无法应用广播机制的内部原理
![](https://epubservercos.yuewen.com/E3272D/25638808101564006/epubprivate/OEBPS/Images/44309_42_2.jpg?sign=1739571024-1X76VzwAETBJ6qVgpvCHck0hbGwdbOUJ-0-6f98c93bfafc8cbc76102183e5cf779f)
运行结果如下。
![](https://epubservercos.yuewen.com/E3272D/25638808101564006/epubprivate/OEBPS/Images/44309_42_3.jpg?sign=1739571024-td14WpRFPjd3kR8K1ff41W1eTqy4xD69-0-98d0799e90c46ddecefcf87459c5a9e3)
2.显式广播方法
使用tf.broadcast_to显式地调用广播方法,将指定的张量广播至指定的形状。
![](https://epubservercos.yuewen.com/E3272D/25638808101564006/epubprivate/OEBPS/Images/44309_43_1.jpg?sign=1739571024-7lyzd0iF5wMMasY26bXRa4zUujRZOWWu-0-d2b3f89c2427c10b69e1ad1d66181565)
运行结果如下。
![](https://epubservercos.yuewen.com/E3272D/25638808101564006/epubprivate/OEBPS/Images/44309_43_2.jpg?sign=1739571024-n0xKVWHM4MX70vhcPMa9WYoBiANRjEbG-0-e1c2b325994ce0f80d475aeb2b5c7a83)