Tensor的理解
数学中有标量、向量和矩阵的概念,它们的维度分别是0、1、2。其中:
-
标量可以看成的一个数字,
1
,标量中元素的位置固定。 -
向量可以看成是一维表格,向量中元素的位置需要通过其索引确定,表示为
-
矩阵可以看成是二维表格,矩阵中的元素位置需要通过其行号和列号确定,表示为
张量(Tensor) 可以视为矩阵的扩展,可以用于表示无穷维度的数据
如果我们用标量、向量或矩阵描述一个事物时,该事物最多可用 [H,W]的维度表示。在现实与客观世界中,我们经常会碰到的物体的维度可能会更高维度,很难通过向量或矩阵来描述,这时我们就需要张量。也就是说,我们可以通过张量来描述任意维度的物体 H * W * C
,其中C为C维的特征图(特征图是深度学习中的一个概念),除外我们还可以用Tensor描述更高维度的物体:H * W * C* D
,其中D为未知的更高维空间。
总之,张量是对于标量、向量、矩阵之上进行更加泛化的定义。标量可以看成是0阶的张量,向量是1阶段张量,矩阵是2阶的张量,除了0,1,2阶的张量之外,还有3阶、4阶、5阶..n阶
的张量。引申到深度学习,其 数据输入的维度是不确定的(可以是任意维度),这时就需要采用一个更加广泛的概念去描述这些量,Tensor就可以更便利解决该问题的。
Tensor的基本概念
其中标量是0维的张量,向量是1维的张量,矩阵是2维的张量。
举例:如下所示,左侧为一个长方体某一切面的矩阵(二阶张量),该矩阵包含N*M个元素,其中每一个元素是一个标量,每一张都是一个向量。一个物体有N个切面,将C 个 N * M 拼接到一起,就会得到一个三阶的张量C*N*M
用于表示长方体(如下右图)。
在用张量描述物体时,我们需要确定这个张量具体是一个什么样的量,用变量或常量来描述。
Tensor与机器学习的关系
完整的机器学习的任务,会涉及到样本、模型等元素(如下所示)。
对于样本(机器学习中用到的数据)我们就可通过Tensor来对其进行描述。比如一条语音数据,我们可有能会采用向量来进行描述,该向量就是1阶的张量。此时向量描述的是语音数据被采样后在当前时刻的声音特征,图形化之后可能为波行。而对于灰度图,我们通常采用矩阵描述(二阶Tensor),表示成H*W
,彩色图则会描述成[H * W * C]
,为一个三阶Tensor,其中C=3。
而模型(模型分为有参数模型与无参数模型),有参数模型一般被描述为 Y = WX + b
函数,其中X是指样本,W,B是指参数。当W与B未知的情况下为变量,该变量也是通过Tensor来表示,Y为最后的标签,而标签在进行数字化时也会通过Tensor来对其进行描述。
当样本标签与属性关系描述为
y=f(x)
,其中x为属性(样本),f为模型。
结论:Tensor可以用来描述机器学习过程中的样本或模型。
Tensor的操作
- 类型:Tensor类型
- 创建:如何创建Tensor
- 属性:Tensor的属性
- 运算:Tensor的算术运算
- 操作:切片、索引、变型等
- 与
numpy
互转:Tensor可以与numpy互转
Tensor类型
张量(Tensor)是Pytorch库中的基本数据类型,在 Pytorch中各种基本数字类型都有其对应的Tensor类型(但在Pytorch中没有内嵌的字符串类型)。
类型列表
Tensor的每种类型分别有对应CPU和GPU版本。加粗部分为常用类型。Tensor默认的数据类型FloatTensor
。
Tensor类型常见的操作见 **Tensor的操作
**章节
- | 数据类型 | torch | CPU Tensor | GPU Tensor |
---|---|---|---|---|
32-bit float point | 32 bit 浮点 | torch.float32 or torch.float | torch.FloatTensor | torch.cuda.FloatTensor |
64-bit float point | 64 bit 浮点 | torch.float64 or torch.double | torch.DoubleTensor | torch.cuda.DoubleTensor |
16-bit float point | 16 bit 半精度浮点 | torch.float16 or torch.half | torch.HalfTensor | torch.cuda.HalfTensor |
8-bit integer(unsigned) | 8 bit 无符号整形(0~255)**** | torch.uint8 | torch.ByteTensor | torch.cuda.ByteTensor |
8-bit integer(signed) | 8 bit 有符号整形(-128~127) | torch.int8 | torch.CharTensor | torch.cuda.CharTensor |
16-bit integer(signed) | 16 bit 有符号整形 | torch.int16 or torch.short | torch.ShortTensor | torch.cuda.ShortTensor |
32-bit integer(signed) | 32 bit 有符号整形 | torch.int32 or torch.int | torch.IntTensor | torch.cuda.IntTensor |
64-bit integer(signed) | 64 bit 有符号整形 | torch.int64 or torch.long | torch.LongTensor | torch.cuda LongTensor |
Boolean | 布尔 | torch.bool | torch.BooleanTensor | torch.cuda.BooleanTensor |
List vs Nparray
Numpy中的Nparray采用连续地址存储,原生list只能通过寻址方式找到下一种元素;
这是因为Numpy制定了其存储的数据类型,可以统一分配内存空间,而List中的数据类型是确定的。
-
Nparray在科学计算方面性能远高于List, 可以省掉许多循环语句
-
Nparray支持并行化运算,底层采用C语言编写,接触了Python解释器的性能限制,所以效率远高于纯Python代码
Numpy vs Tensor
Numpy和Tensor相比较,他们的区别如下:
- Tensor 和 Numpy都是矩阵,区别是前者可以在GPU上运行,后者只能在CPU上。
- Tensor可以直接通过print显示数据类型,而Numpy不可以。
在GPU上运行时: Tensor内部的数据类型为ndarray,GPU不具有更改元素值的能力,这时Tensor内部元素的数值不可改变
类型常见操作
-
将普通张量类型转化为GPU张量类型的方法:
普通张量变量名.cuda()
, 返回一个GPU张量的引用。 -
Tensor默认的数据类型
- 默认的Tensor是FloatTensor(如果默认类型为GPU tensor,则所有操作都将在GPU上进行)。
- 设置默认的数据类型:
torch.set_default_tensor_type(类型名)
- 增强学习中使用DoubleTensor的使用会更多
-
将张量转换为其他数据类型
- 将张量转换为numpy数组:
张量名.numpy()
- 将只有一个元素的张量转换为标量:
张量名.item()
。
- 将张量转换为numpy数组:
-
查看张量数据类型的方法
- type方法:使用
张量名.type()
可以查看张量的具体类型。 - isinstance:isinstance是Python的自带函数。用法
isinstance(torch.randn(2,3),torch.FloatTensor)
,返回布尔值。
- type方法:使用
-
生成元素数据类型指定的张量
浮点型张量
tensor.FloatTensor(标量/列表/numpy数组) # 生成元素均为单精度浮点型的张量
tensor.DoubleTensor(标量/列表/numpy数组) # 生成元素均为双精度浮点型的张量
tensor.HalfTensor(标量/列表/numpy数组) # 生成元素均为半精度浮点型的张量整型张量
tensor.IntTensor(标量/列表/numpy数组) # 生成元素均为基本整型的张量
tensor.ShortTensor(标量/列表/numpy数组) # 生成元素均为短整型的张量
tensor.LongTensor(标量/列表/numpy数组) # 生成元素均为长整型的张量布尔型张量
tensor.BoolTensor(标量/列表/numpy数组) # 生成元素均为布尔类型的张量
[python、numpy、Pytorch中的索引方式](
Tensor的创建
加粗为常用
创建函数
函数 | 功能 | 备注 |
---|---|---|
Tensor(*size) | 基础构造函数 | size: 直接根据形状定义Tensor, 例:torch.tensor(标量|列表), |
Tensor(data) | 类似np.array | data: 使用数据直接初始化, 例:torch.from_numpy(numpy数组) |
*ones(size) | 全1Tensor | 常用结构:全部为1的张量 |
*zeros(size) | 全0Tensor | 常用结构:全部为0的常量 |
*eye(size) | 对角线为1,其他为0 | 常用结构:对角线为1,其他为0 |
arange(s,e,step) | 从s到e,步长为step | 从s到e, 中间的间隔为step,即步长 |
linspace(s,e,steps) | 从s到e,均匀切分成steps份 | 从s到e, 均匀切分成steps份 |
rand/randn(*size) | 均匀/标准分布 | size: 根据形状定义Tensor, 值为随机赋值,均匀/标准分布的随机采样 |
normal(mean,std)/uniform (from,to) | 正态分布/均匀分布 | 满足正态分布或均匀分布 |
randperm(m) | 随机排列 | 对一个序列进行随机排列 |
empty(*size) | 生成不经过元素初始化的指定形状的张量 | |
rand_like(tensor) | 生成指定填充值的指定形状的张量 | |
full(*size) | 指定值的Tensor |
编程实例
import numpy as np |
Tensor的属性
- 每一个Tensor有torch.dtype、torch.device、torch.layout三种属性
- torch.device 标识了torch.Tensor对象在创建之后所存储在的设备名称
- torch.layout表示torch.Tensor内存布局的对象
torch.dtype: 在使用tensor函数创建tensor张量对象时还可以使用dtype参数指定数据类型
torch.device: 张量所创建的数据,到底应该存储在哪个设备上,CPU或GPU, GPU是通过CUDA来表示,多个则用cuda:0, cuda:1,以此类推
torch.layout: 张量的排布方式,对应到内存中连续的区别。稠密或稀疏的方式。
稠密的张量
稠密的张量定义方法
import torch |
稀疏的张量
稀疏或低秩是机器学习中两个很重要的概念,描述了当前数据是否满足某种性质
-
稀疏表达了当前数据中,非0元素的个数,非0元素的个数越少,说明越稀疏。如果全部为0,则说明最稀疏。
-
低秩描述了数据本身的关联性,也是线性代码中的一个概念。秩从线性相关的角度来看,主要是描述了当前矩阵中的向量间线性可表示的关系。
稀疏的张量在机器学习中的优势
- 从模型角度:能够使模型变的非常简单。对于有参数的模型,如果参数中0的个数非常多,意味着可以对模型进行简化。即参数为0的项(item) 是可以减掉的,因为0乘以任何数都等于0。这样参数个数变少,意味着模型变的更简单,对于参数稀疏化的约束在机器学习中是一个非常重要的性质。这是我们从机器学习模型的角度上介绍稀疏的意义。
- 从数据角度,通过对数据进行稀疏化的表示,可以减少数据在内存中的开销。假设存在一个100*100的矩阵,哪果用稠密方式表示数据,则需要100**100单位的空间,而如果用稀疏张量表示,我们只要记住非0元素的坐标即可。
torch.sparse_coo_tensor
PyTorch中用torch.sparse_coo_tensor
表示稀疏矩阵。使用torch.sparse_coo_tenso
r可以方便地将稀疏矩阵转换为PyTorch张量,并进行各种操作。同时,由于只存储了非零元素的位置和值,因此可以节省大量的内存空间。
名称是 'coo’代表非零元素的坐标。即coo类型: coo类型表示了非零元素的坐标形式
torch.sparse_coo_tensor
参数说明:
-
indices: 一个二维的LongTensor, 表示非零元素在原矩阵中的位置,其形状为(N, 2),其中N为非零元素个数。
-
values: 一个一维的Tensor, 表示非零元素的值,其形状为(N,)。
-
size: 一个元组,表示输出张量的形状,例如(M, N)。
torch.sparse_coo_tensor
参数解说:
- indices: 表示非零元素在原矩阵中的位置,即哪些位置是非零的。它的形状为(N, 2), 其中N为非零元素个数。每个元素包含两个值,分别表示该非零元素在行和列上的位置。
- values: 表示非零元素的值,即这些位置上的数值。它的形状为(N,)
- size: 表示输出张量的形状,即输出张量的行数和列数。例如,如果输入矩阵是一个4x5的矩阵,但是只有第2行和第4行、第3列和第5列上的元素是非零的,那么输出张量的形状就是(2, 2)。
torch.sparse_coo_tensor
用法
import torch |
控制台输出
例:将数据落地对角线上
indices = torch.tensor([[0, 1, 2], [0, 1, 2]]) |
解释:
i的坐标 (0,0)(1,1)(2,2),第0行代表x,第1行代表y
矩阵的坐标: [(0,0) (0,1) (0,2)
(1,0) (1,1) (1,2)
(2,0) (2,1) (2,2) ]
数据正好在对角线
Tensor的算术运算
四则运算
- 加减乘除
- 矩阵运算
其他运算
- torch.pow - 幂运算
- torch.exp(input, out=None) - e指数,注意只支持浮点型
- torch.sqrt(input, out=None) - 开方
- torch.log(input, out=None) - 对数运算,以e为底
- ceil/round/floor/trunc - 取整/四舍五入/下取整/只保留整数部分 - 如
torch.ceil(input, out=None)
- clamp(input, min, max) - 超过min和max部分截断 -
torch.clamp(input, min, max, out=None)
- torch.abs(input, out=None)- 求绝对值
- …
加减法运算
import torch |
减法:- / …sub() / …sub_()
乘法: * /c = torch.mul(a,b)
/a.mul(b)
/a.mul_(b)
哈达玛积
哈达玛积(element wise,对应元素相乘) - mul乘法 如果一个tensor是shape是2 * 2
的话,则另外一个tensor也是(2 * 2)
, 这样保证所有元素都保证每个元素都可以被相乘。
c = a * b |
矩阵运算
二维矩阵的乘法运算
**二维矩阵的乘法运算 **包括torch.mm(),torch.matmul(),@
规则 a * b
时,即两个矩阵相乘,m * n
, n * p
, 一定要保证 两个矩阵的’n’是相同的。
a = torch.ones(2,1) |
高维矩阵的乘法运算
对于高维的Tensor(dim>2)
,假如矩阵的size=(a1,a2,m,n)
,我们要保证除最后两维m,n
之外的前几维的值保持一致, 最后两维的规则同二维矩阵,即n相同 。就像矩阵的索引一样并且运算操只有``torch.matmul()`
同样是除了矩阵内的数值之外,要保证维度的每个元素都可以被计算。
mm
()与matmul()
不存在下划线类的计算.。
如下所示:n
相同,a,b
相同。
a = torch.ones(a, b, m, n) |
举例:
a = torch.ones(1, 2, 4, 5) |
幂运算
a = torch.full((2, 3), fill_value=2) |
指数运算
指数函数:函数y=a^x(a>0且a≠1) 叫做指数函数,a是常数,x是自变量,定义域为R,值域为(0,+∞)。要求:a^x前的系数必须是数1,自变量x必须在指数的位置上,且不能是x的其他表达式,否则就不是指数函数。
- a>1时,则指数函数单调递增;若0<a<1,则为单调递减的。
- 对于a不大于0的情况,函数的定义域不连续,不考虑; a等于0函数无意义一般也不考虑。
- 指数函数恒过(0,1)点,即水平直线y=1是从递减到递增的一个过渡位置。
- 指数函数是非奇非偶函数。
- …
指数函数应用到自然常数e上写为exp(x),现常写为e^x(表示为x=lny),其图像是单调递增,n∈R,y>0,与y轴相交于(0,1)点。,图像位于X轴上方,第二象限无限接近X轴。
e的n次方
$$
y = e^n \ n∈R,y>0,与y轴相交于(0,1)点
$$
a = torch.full((2, 3), fill_value=2) |
开方运算
a = torch.full((2, 3), fill_value=4) |
对数运算
对数源于指数,是指数函数反函数 因为:N = ax 所以:x = log(aN)
如果 N=a^x(a>0,a≠1),即a的x次方等于N(a>0,且a≠1),那么数x叫做以a为底N的对数(logarithm),记作:x=log(aN) 其中,a叫做对数的底数,N叫做真数,x叫做 “以a为底N的对数”。
a = torch.full((2, 3), fill_value=4) |
Tensor的更多操作
维度调整
-
查看维度:
torch.shape
-
变换维度:
torch.reshape([d0,d1,d2])
-
unsqueeze
和squeeze
-
b=a.squeeze(a)
去掉维度值为1的维度 -
b=a.unsqueeze(n)
增加一个维度在shape的第n个c = torch.rand(2, 3)
c = c.unsqueeze(1)
print(c.shape)
-
两个tensor合并
torch.cat(tensors, dim=0, out=None)
torch.stack(tensors)
合并时候新建一个维度
与numpy互换
- 图解PyTorch中的torch.gather函数 - 知乎
- pytorch和numpy的互转 ,有以下几种方式:
torch.gather
对应的numpy
操作:torch.view
对应的numpy
操作torch.argmax
对应的numpy
操作torch.max
对应的numpy
操作
参考