前言 在PyTorch快速入门中我们大概知道了一个神经网络模型的构成模块以及如何从数据处理到模型训练。但是没有具体去了解每部分的细节,本章节我们来学习一些PyTorch必备的知识,为后续学习奠定基础。 深度学习能够超过传统的机器学习算法离不开神经网络,然而神经网络最基本的数据结构就是张量,神经网络的输入是张量,然后通过每个张量进行线性变换,再经过激活函数的非线性变换,通过层层计算最终使得损失函数的最小化,完成模型的训练。所以要想学好深度学习,对基础的数据结构还是要非常了解。目录:回顾一下相关的线性代数的基础知识向量、矩阵和张量Pytorch如何表示向量、矩阵和张量的计算Pytorch中张量的一些基本操作向量、矩阵和张量及其运算 1、向量 向量(1维数组)定义为一行或者一列数,分别称之为行向量和列向量,如图1和图2所示(这里用T代表转置,意思是行列互换)。向量是最基本的一种数据排列方式,组成向量的每个数称为向量的分量,这里用来表示,其中的n代表向量分量的数目,即向量的大小。 图1行向量 图2列向量 向量与向量之间一个重要的运算是点积(DotProduct),或者称之为内积(InnerProduct),表现为两个相同大小的向量按分量相乘并且求和。。如图3所示 图3两个向量的内积 内积的几何解释:两个向量的内积等于向量的模长乘以向量之间夹角的余弦,如图4所示。 图4 我们把向量与自身内积的平方根称之为向量的长度(或模,即L2norm)。 在神经网络中,向量往往不是某事物的特征。例如,房子的价格是受多种因素(是否为学区房、附近有无地铁、房子面积、房间数量、楼层等)来影响,那么我们将这多种因素来表示为房子的特征,这一组特征值就可以用向量表示。 2、矩阵 矩阵由一组向量组成的集合。矩阵也称为2维数组。 图矩阵的定义和矩阵运算的例子 在神经网络中,在刚才的例子中,一套房子的特征可以用一个向量来表示。那么我们要建m套房子的数据集,那么就是m个向量的组合,也即是得到一个m行n列的矩阵。(n为一套房子的向量的长度)。 3、张量 张量是矩阵的推广,可以用来描述N维数据。其实在计算机领域内,大家叫法都不那么严格,一个矩阵,你可以叫它矩阵,也可以叫它二阶张量,也可以叫它二维数组。 向量、矩阵和三维向量示意图 在神经网络中,张量在图像领域用的是很普遍的。如一张彩色图像,有宽度和高度,同时又有R,G,B三个通道。所以一张彩色图像就是三阶张量(通道宽度高度)。 再比如高一阶的四阶张量,可以理解为一个批次(批次简单理解为多张图片)的彩色图像。因为在做图像识别过程中,我们训练和推理过程中可以一次推理N张图像,这个N称为批次。即是批次通道宽度高度的四阶张量。在深度学习中,我们要处理不止一张图片或一篇文档我们要处理一个集合。我们可能有10,000张郁金香的图片,这意味着,我们将用到4阶张量 4、向量、矩阵和张量比较 几何代数中定义的张量是基于向量和矩阵的推广,比如我们可以将标量视为零阶张量,矢量可以视为一阶张量,矩阵就是二阶张量。 张量维度 代表含义 0维张量 代表的是标量(数字) 1维张量 代表的是向量 2维张量 代表的是矩阵 3维张量 时间序列数据股价文本数据单张彩色图片(RGB) 1。标量,也称Scalar,是一个只有大小,没有方向的量,比如1。8、e、10等。 2。向量,也称Vector,是一个有大小也有方向的量,比如(1,2,3,4)等。 3。矩阵,也称Matrix,是多个向量合并在一起得到的量,比如〔(1,2,3),(4,5,6)〕等。 不难发现,几种数据表示其实都是有着联系的,标量可以组合成向量,向量可以组合成矩阵。那么,我们可否将它们看作是一种数据形式呢? 答案是可以的,这种统一的数据形式,在PyTorch中我们称之为张量(Tensor)。从标量、向量和矩阵的关系来看,大致可以认为它们就是不同维度的Tensor。 张量是深度学习的基础。它的核心是一个数据容器,多数情况下,它包含数字,有时候它也包含字符串,但这种情况比较少。Pytorch如何表示向量、矩阵和张量的计算 1、向量:一个向量表示一组有序排列的数,通过次序中的索引我们能够找到每个单独的数,向量通常用粗体的小写字母表示,如x。importnumpyasnp行向量anp。array(〔1,2,3,4〕) 2、矩阵:是一个二维数组,其中的每一个元素由两个索引来决定(),矩阵通常用加粗斜体的大写字母表示,如X。importnumpyasnp矩阵anp。array(〔〔1,2,3〕,〔4,5,6〕,〔7,8,9〕〕) 3、张量: 张量是一种特殊的数据结构,与数组和矩阵非常相似。在PyTorch中,我们使用张量对模型的输入和输出以及模型的参数进行编码。 张量类似于NumPy的ndarray,除了张量可以在GPU或其他硬件加速器上运行。事实上,张量和NumPy数组通常可以共享相同的底层内存,从而无需复制数据(请参阅BridgewithNumPy)。张量也针对自动微分进行了优化(我们将在稍后的Autograd部分中看到更多相关内容)。如果您熟悉ndarrays,那么您对TensorAPI会很熟悉。如果没有,请跟随!importtorchimportnumpyasnp 3。1初始化张量 张量可以以各种方式初始化。请看以下示例: 直接创建张量 首先来看直接创建的方法,这也是最简单创建的方法。我们可以通过torch。tensor()直接使用数据,构造一个张量。数据类型是自动推断的。data〔〔1,2〕,〔3,4〕〕xdatatorch。tensor(data)xdatatensor(〔〔1,2〕,〔3,4〕〕) NumPy数组创建张量 在实际应用中,我们在处理数据的阶段多使用的是NumPy,而数据处理好之后想要传入PyTorch的深度学习模型中,则需要借助Tensor,所以PyTorch提供了一个从NumPy转到Tensor的语句。并且可以从NumPy数组创建,反之亦然。nparraynp。array(data)xnptorch。fromnumpy(nparray)xnptensor(〔〔1,2〕,〔3,4〕〕) 随机初始化张量 我们可以通过torch。rand()的方法,构造一个随机初始化的矩阵(2阶张量):importtorchxtorch。rand(6,4)print(x) 注意:torch。rand用于生成数据类型为浮点型且维度指定的随机Tensor,随机生成的浮点数据在01区间均匀分布。torch。randn用于生成数据类型为浮点型且维度指定的随机Tensor,随机生成的浮点数的取值满足均值为0、方差为1的标准正态分布。torch。normal用于生成数据类型为浮点型且维度指定的随机Tensor,可以指定均值和标准差。torch。randint用于生成随机整数的Tensor,其内部填充的是在〔low,high)均匀生成的随机整数。 全0矩阵的构建 我们可以通过torch。zeros()构造一个矩阵全为0,并且通过dtype设置数据类型为long。importtorchxtorch。zeros(53,dtypetorch。long)print(x) 根据一个张量构建形状相同的张量: 新张量保留参数张量的属性(形状、数据类型),除非显式覆盖。xtorch。ones(2,2,dtypetorch。double)print(x)x1torch。randnlike(x,dtypetorch。float)print(x1)结果会有一样的size获取它的维度信息print(x。size())print(x1。shape)tensor(〔〔1,1〕,〔1,1〕〕)tensor(〔〔0。0809,0。7885〕,〔0。0739,0。3876〕〕) 使用随机值和定值: shape是张量维度的元组。在下面的函数中,它决定了输出张量的维度。shape(2,3,)randtensortorch。rand(shape)onestensortorch。ones(shape)zerostensortorch。zeros(shape)print(fRandomTensor:{randtensor})print(fOnesTensor:{onestensor})print(fZerosTensor:{zerostensor})RandomTensor:tensor(〔〔0。0312,0。8956,0。5396〕,〔0。0653,0。3294,0。7575〕〕)OnesTensor:tensor(〔〔1。,1。,1。〕,〔1。,1。,1。〕〕)ZerosTensor:tensor(〔〔0。,0。,0。〕,〔0。,0。,0。〕〕) Tensor的转换 在实际项目中,我们接触到的数据类型有很多,比如Int、list、NumPy等。为了让数据在各个阶段畅通无阻,不同数据类型与Tensor之间的转换就非常重要了。接下来我们一起来看看int、list、NumPy是如何与Tensor互相转换的。 Int与Tensor的转换:atorch。Tensor(1)ba。item() 我们通过torch。Tensor将一个数字(或者标量)转换为Tensor,又通过item()函数,将Tensor转换为数字(标量),item()函数的作用就是将Tensor转换为一个pythonnumber。 list与tensor的转换:a〔1,2,3〕btorch。Tensor(a)cb。numpy()。tolist() 在这里对于一个lista,我们仍旧直接使用torch。Tensor,就可以将其转换为Tensor了。而还原回来的过程要多一步,需要我们先将Tensor转为NumPy结构,之后再使用tolist()函数得到list。 张量到NumPy数组 背后原理:CPU中张量和NumPy数组上的张量可以共享它们的底层内存位置,改变一个会改变另一个。ttorch。ones(5)print(ft:{t})nt。numpy()print(fn:{n})t:tensor(〔1。,1。,1。,1。,1。〕)n:〔1。1。1。1。1。〕 张量的变化反映在NumPy数组中。t。add(1)print(ft:{t})print(fn:{n})t:tensor(〔2。,2。,2。,2。,2。〕)n:〔2。2。2。2。2。〕 NumPy数组到张量nnp。ones(5)ttorch。fromnumpy(n)print(n)print(t)〔1。1。1。1。1。〕tensor(〔1。,1。,1。,1。,1。〕,dtypetorch。float64) NumPy数组的变化反映在张量中。np。add(n,1,outn)print(ft:{t})print(fn:{n})t:tensor(〔2。,2。,2。,2。,2。〕,dtypetorch。float64)n:〔2。2。2。2。2。〕 常见的构造张量(Tensor)的方法总结 函数 功能 Tensor(sizes) 基础构造函数 tensor(data) 类似于np。array ones(sizes) 全1 zeros(sizes) 全0 eye(sizes) 对角为1,其余为0 arange(s,e,step) 从s到e,步长为step linspace(s,e,steps) 从s到e,均匀分成step份 randrandn(sizes) rand是〔0,1)均匀分布;randn是服从N(0,1)的正态分布 normal(mean,std) 正态分布(均值为mean,标准差是std) randperm(m) 随机排列 3。2张量的属性 张量属性描述了它们的形状、数据类型和存储它们的设备tensortorch。rand(3,4)Getcpuorgpudevicefortraining。devicecudaiftorch。cuda。isavailable()elsecpuprint(fUsing{device}device)print(fShapeoftensor:{tensor。shape})print(fDatatypeoftensor:{tensor。dtype})print(fDevicetensorisstoredon:{tensor。device})UsingcudadeviceShapeoftensor:torch。Size(〔3,4〕)Datatypeoftensor:torch。float32Devicetensorisstoredon:cpu 3。3张量运算 在PyTorch中有超过100种张量运算,包括算术、线性代数、矩阵操作(转置、索引、切片)、采样等。 这些操作中的每一个都可以在GPU上运行(通常以比CPU更高的速度)。如果您使用的是Colab,请转到运行时更改运行时类型GPU来分配GPU。 默认情况下,张量是在CPU上创建的。我们需要使用。to方法明确地将张量移动到GPU(在检查GPU可用性之后)。请记住,跨设备复制大张量在时间和内存方面可能会很昂贵! 标准的类似numpy的索引和切片:tensortorch。ones(4,4)print(fFirstrow:{tensor〔0〕})print(fFirstcolumn:{tensor〔:,0〕})print(fLastcolumn:{tensor〔。。。,1〕})tensor〔:,1〕0print(tensor)Firstrow:tensor(〔1。,1。,1。,1。〕)Firstcolumn:tensor(〔1。,1。,1。,1。〕)Lastcolumn:tensor(〔1。,1。,1。,1。〕)tensor(〔〔1。,0。,1。,1。〕,〔1。,0。,1。,1。〕,〔1。,0。,1。,1。〕,〔1。,0。,1。,1。〕〕) 拼接张量 您可以用来torch。cat沿给定维度连接一系列张量t1torch。cat(〔tensor,tensor,tensor〕,dim1)print(t1)tensor(〔〔1。,0。,1。,1。,1。,0。,1。,1。,1。,0。,1。,1。〕,〔1。,0。,1。,1。,1。,0。,1。,1。,1。,0。,1。,1。〕,〔1。,0。,1。,1。,1。,0。,1。,1。,1。,0。,1。,1。〕,〔1。,0。,1。,1。,1。,0。,1。,1。,1。,0。,1。,1。〕〕)t2torch。cat(〔tensor,tensor,tensor〕,dim0)print(t2)tensor(〔〔1。,0。,1。,1。〕,〔1。,0。,1。,1。〕,〔1。,0。,1。,1。〕,〔1。,0。,1。,1。〕,〔1。,0。,1。,1。〕,〔1。,0。,1。,1。〕,〔1。,0。,1。,1。〕,〔1。,0。,1。,1。〕,〔1。,0。,1。,1。〕,〔1。,0。,1。,1。〕,〔1。,0。,1。,1。〕,〔1。,0。,1。,1。〕〕)t2torch。stack(〔tensor,tensor,tensor〕,dim2)print(t2。shape)torch。Size(〔4,4,3〕) 算术运算:加法、减法、乘法加法操作:importtorch方式1xtorch。rand(4,3)ytorch。rand(4,3)print(xy)方式2print(torch。add(x,y))方式3inplace,原值修改y。add(x)print(y) 2。减法操作importtorchxtorch。rand(4,3)ytorch。rand(4,3)print(xy) 3。乘法操作相同位置的元素之间相乘。,计算出来的张量形状不变。如z1,z2,z3将是相同值。tensortorch。ones(4,4)z1tensortensorprint(z1)z2tensor。mul(tensor)print(z2)z3torch。randlike(tensor)print(z2)torch。mul(tensor,tensor,outz3)print(z3)tensor(〔〔1。,0。,1。,1。〕,〔1。,0。,1。,1。〕,〔1。,0。,1。,1。〕,〔1。,0。,1。,1。〕〕)tensor(〔〔1。,0。,1。,1。〕,〔1。,0。,1。,1。〕,〔1。,0。,1。,1。〕,〔1。,0。,1。,1。〕〕)tensor(〔〔1。,0。,1。,1。〕,〔1。,0。,1。,1。〕,〔1。,0。,1。,1。〕,〔1。,0。,1。,1。〕〕)tensor(〔〔1。,0。,1。,1。〕,〔1。,0。,1。,1。〕,〔1。,0。,1。,1。〕,〔1。,0。,1。,1。〕〕)小结 1、认识了向量、矩阵和张量之间的区别和联系 2、向量、矩阵和张量在PyTorch如何实现 3、张量的基本操作,如算术运行、Numpy转Tensor等 思考题 谈谈torch。Tensor()和torch。tensor()两种函数区别??