-
Numpy是支持大量维度数组与矩阵运算的常用扩展库。但是对于计算图,深度学习或者梯度,Numpy似乎真的有心无力,因为它的计算无法像Tensor一样在GPU上加速。Tensors与Numpy中的 ndarrays类似,但是在PyTorch中 Tensors 可以使用GPU进行计算.
-
在PyTorch中,
torch.Tensor
是存储和变换数据的主要工具。如果之前用过NumPy,会发现Tensor
和NumPy的多维数组非常类似。然而,Tensor
提供GPU计算和自动求梯度等更多功能,这些使Tensor
更加适合深度学习。 -
"tensor"这个单词一般可译作“张量”,张量可以看作是一个多维数组。标量可以看作是0维张量,向量可以看作1维张量,矩阵可以看作是二维张量。
-
创建一个 5x3 矩阵, 但是未初始化,empty方法创建的矩阵不是空矩阵,而是未初始化的矩阵,所以里面的值不一定是0。
-
import torch x = torch.empty(5, 3) print(x,type(x))x)
-
tensor([[0.0000e+00, 0.0000e+00, 0.0000e+00],
[0.0000e+00, 0.0000e+00, 7.3008e-43],
[7.0295e+28, 6.1949e-04, 4.5095e+27],
[7.6831e+31, 4.7429e+30, 1.7053e+28],
[1.6020e-19, 4.4721e+21, 4.4330e+27]]) <class ‘torch.Tensor’>
-
创建一个随机初始化的矩阵:
-
x = torch.rand(5, 3) print(x)
-
tensor([[0.6972, 0.0231, 0.3087],[0.2083, 0.6141, 0.6896],[0.7228, 0.9715, 0.5304],[0.7727, 0.1621, 0.9777],[0.6526, 0.6170, 0.2605]])
-
创建一个0填充的矩阵,数据类型为long:
-
x = torch.zeros(5, 3, dtype=torch.long) print(x,type(x),x.dtype))
-
tensor([[0, 0, 0],
[0, 0, 0],
[0, 0, 0],
[0, 0, 0],
[0, 0, 0]]) <class ‘torch.Tensor’> torch.int64
-
创建tensor并使用现有数据初始化:
-
x = torch.tensor([5.5, 3]) print(x,type(x),x.dtype))
-
tensor([5.5000, 3.0000]) <class ‘torch.Tensor’> torch.float32
-
根据现有的张量创建张量。 这些方法将重用输入张量的属性,例如, dtype,除非设置新的值进行覆盖
-
x = x.new_ones(5, 3, dtype=torch.double) # new_* 方法来创建对象 print(x,type(x),x.dtype) x = torch.randn_like(x, dtype=torch.float) # 覆盖 dtype! print(x,type(x),x.dtype) # 对象的size 是相同的,只是值和类型发生了变化)
-
tensor([[1., 1., 1.],
[1., 1., 1.],
[1., 1., 1.],
[1., 1., 1.],
[1., 1., 1.]], dtype=torch.float64) <class ‘torch.Tensor’> torch.float64
tensor([[ 0.4735, -1.4062, 0.6846],
[ 2.1270, 1.0104, -0.6296],
[-1.4242, -1.8123, 1.0814],
[-0.8284, -0.2131, 0.8163],
[-0.7036, -0.0401, 0.4185]]) <class ‘torch.Tensor’> torch.float32
-
加法运算: 【tips:任何 以
_
结尾的操作都会用结果替换原变量. 例如:x.copy_(y)
,x.t_()
, 都会改变x
.】-
y = torch.rand(5, 3) print("随机生成的y",y) print("加法结果",x + y) res =torch.zeros_like(x) torch.add(x, y,out=res) print("加法结果",res,res.size()) y.add_(x) print("新y:",y)
-
随机生成的y tensor([[0.0976, 0.0699, 0.3251],
[0.9541, 0.2497, 0.7962],
[0.5003, 0.1983, 0.3777],
[0.4165, 0.2731, 0.6123],
[0.5100, 0.7458, 0.3145]])
加法结果 tensor([[ 0.5710, -1.3363, 1.0097],
[ 3.0812, 1.2601, 0.1666],
[-0.9239, -1.6140, 1.4591],
[-0.4119, 0.0599, 1.4286],
[-0.1937, 0.7057, 0.7329]])
加法结果 tensor([[ 0.5710, -1.3363, 1.0097],
[ 3.0812, 1.2601, 0.1666],
[-0.9239, -1.6140, 1.4591],
[-0.4119, 0.0599, 1.4286],
[-0.1937, 0.7057, 0.7329]]) torch.Size([5, 3])
新y: tensor([[ 0.5710, -1.3363, 1.0097],
[ 3.0812, 1.2601, 0.1666],
[-0.9239, -1.6140, 1.4591],
[-0.4119, 0.0599, 1.4286],
[-0.1937, 0.7057, 0.7329]])
-
可以使用与NumPy索引方式相同的操作来进行对张量的操作
-
print(x[:, 1]) print(x[2, :]) print(x[1:3, 0:2])
-
tensor([-1.4062, 1.0104, -1.8123, -0.2131, -0.0401])
tensor([-1.4242, -1.8123, 1.0814])
tensor([[ 2.1270, 1.0104],
[-1.4242, -1.8123]])
-
torch.view
: 可以改变张量的维度和大小,torch.view 与Numpy的reshape类似-
x = torch.randn(4, 4) y = x.view(16) z = x.view(-1, 8) # size -1 从其他维度推断 print(x.size(), y.size(), z.size())
-
torch.Size([4, 4]) torch.Size([16]) torch.Size([2, 8])
-
使用
.item()
来得到Python数据类型的数值-
print(x[0][0]) print(x[0][0].item())
-
tensor(1.6635)
1.6634777784347534
-
函数 功能 Tensor(*sizes) 基础构造函数 tensor(data,) 类似np.array的构造函数 ones(*sizes) 全1Tensor zeros(*sizes) 全0Tensor eye(*sizes) 对角线为1,其他为0 arange(s,e,step) 从s到e,步长为step linspace(s,e,steps) 从s到e,均匀切分成steps份 rand/randn(*sizes) 均匀/标准分布 normal(mean,std)/uniform(from,to) 正态分布/均匀分布 randperm(m) 随机排列 -
函数 功能 index_select(input, dim, index) 在指定维度dim上选取,比如选取某些行、某些列 masked_select(input, mask) 例子如上,a[a>0],使用ByteTensor进行选取 nonzero(input) 非0元素的下标 gather(input, dim, index) 根据index,在dim维度上选取数据,输出的size与index一样 -
更多关于tensor的操作可查看官方文档:torch — PyTorch 1.13 documentation
-
# 创建相同元素的Tensor torch_tensor1 = torch.full([2,3],2) # 创建全为1的Tensor torch_tensor2 = torch.ones([2,3]) # 创建全为0的Tensor torch_tensor3 = torch.zeors([2,3]) # 创建对角阵的Tensor torch_tensor4 = torch.eye(3) # 在区间[1,10]中随机创建Tensor torch_tensor5 = torch.randint(1,10,[2,2])
-
tensor与NumPy 转换
-
Torch Tensor与NumPy数组共享底层内存地址,修改一个会导致另一个的变化。将一个Torch Tensor转换为NumPy数组:
-
a = torch.ones(5) print(a) b = a.numpy() print(b) b[2]=6 print(a,b) ############ tensor([1., 1., 1., 1., 1.]) [1. 1. 1. 1. 1.] tensor([1., 1., 6., 1., 1.]) [1. 1. 6. 1. 1.] ########### a.add_(1) print(a,type(a),b,type(b)) ########### tensor([2., 2., 7., 2., 2.]) <class 'torch.Tensor'> [2. 2. 7. 2. 2.] <class 'numpy.ndarray'>
-
-
NumPy Array 转化成 Torch Tensor,使用from_numpy自动转化
-
import numpy as np a = np.ones(5) b = torch.from_numpy(a) np.add(a, 1, out=a) print("a:",a,a.dtype,type(a)) print("b:",b,b.dtype,type(b)) a: [2. 2. 2. 2. 2.] float64 <class 'numpy.ndarray'> b: tensor([2., 2., 2., 2., 2.], dtype=torch.float64) torch.float64 <class 'torch.Tensor'>
-
直接用
torch.tensor()
将NumPy数组转换成Tensor
,该方法总是会进行数据拷贝,返回的Tensor
和原来的数据不再共享内存。 -
# 用torch.tensor()转换时不会共享内存 import numpy as np a = np.ones((3,2)) c = torch.tensor(a) a += 1 print(a, c)
-
[[2. 2.][2. 2.][2. 2.]] tensor([[1., 1.],[1., 1.],[1., 1.]], dtype=torch.float64)
-
-
所有的 Tensor 类型默认都是基于CPU, CharTensor 类型不支持到 NumPy 的转换. CUDA 张量使用.to 方法 可以将Tensor移动到任何设备中。
-
如果不想共享内存,推荐先用
clone
创造一个副本然后再使用view
。-
x_cp = x.clone().view(15) x -= 1 print(x) print(x_cp)
-
tensor([[-1., -1., -1.],[-1., -1., -1.],[-1., -1., -1.],[-1., -1., -1.],[-1., -1., -1.]]) tensor([8.9082e-39, 1.0194e-38, 9.1837e-39, 8.4490e-39, 1.0102e-38, 1.0653e-38,9.9184e-39, 5.9695e-39, 8.9082e-39, 1.0194e-38, 9.1837e-39, 8.4490e-39,1.0102e-38, 1.0561e-38, 9.0918e-39])
-
-
Tensor的广播机制:当对两个形状不同的Tensor按元素运算时,可能会触发广播机制(broadcasting)机制:先适当复制元素使这两个Tensor形状相同后再按元素运算。
-
x = torch.arange(1, 3).view(1, 2) print(x) y = torch.arange(1, 4).view(3, 1) print(y) print(x + y)
-
tensor([[1, 2]])
tensor([[1],
[2],
[3]])
tensor([[2, 3],
[3, 4],
[4, 5]])
-
tensor运算的内存开销:索引,view()是不会开辟新的内存的,而像y=x+y这样的运算是会开辟新的内存的,然后y指向新的内存。
-
x = torch.tensor([1, 2]) y = torch.tensor([3, 4]) id_before = id(y) torch.add(x, y, out=y) print(id(y) == id_before) y += x # 与y=y+x不同 print(id(y) == id_before) y.add_(x) print(id(y) == id_before) y[:] = y + x # 索引 print(id(y) == id_before) y = y+ x print(id(y) == id_before)
-
True
True
True
True
False
-
另外,PyTorch还支持一些线性函数,这里提一下,免得用起来的时候自己造轮子,具体用法参考官方文档。如下表所示:
-
函数 功能 trace 对角线元素之和(矩阵的迹) diag 对角线元素 triu/tril 矩阵的上三角/下三角,可指定偏移量 mm/bmm 矩阵乘法,batch的矩阵乘法 addmm/addbmm/addmv/addr/baddbmm… 矩阵运算 t 转置 dot/cross 内积/外积 inverse 求逆矩阵 svd 奇异值分解
-