几乎所有深度学习框架背后的设计核心都是张量与计算图;
Tensor 即张量,在 tf 中也有这个概念,tensor 是 pytorch 和 tf 非常重要的数据结构,可以理解为多维数组,它可以是一个数、一个向量、一个矩阵、多维数组;
Tensor 可以用 GPU 加速;
在 pytorch 中其用法类似于 numpy;
本教程环境 pytorch 1.3以上
创建 Tensor
方式1:直接用 list. np.array 等创建
示例
a = t.Tensor([1, 2]) print(a) # tensor([1., 2.]) print(a.type()) # torch.FloatTensor b = t.Tensor([[1,2], [3, 4]]) print(b) # tensor([[1., 2.], # [3., 4.]]) c = t.tensor(3.) print(c) # tensor(3.) print(c.type()) # torch.FloatTensor d = t.tensor(4) print(d, d.type()) # tensor(4) torch.LongTensor
Tensor vs tensor
可以看到上面用了两个方法 Tensor 和 tensor,有什么区别呢?
1. 首先, 在 1.3.1 版本中,tensor 已经被废弃,但是还能用
2. torch.Tensor 是 python 的一个类,确切的说它是默认张量类型 torch.FloatTensor 的别名,生成单精度浮点型张量
3. torch.tensor 是 python 的一个函数,它的输入可以是 data、list、ndarray 等,根据输入类型生成对应类型的张量
4. Tensor 不管输入什么,都生成单精度浮点型张量,而 tensor 根据输入生成对应类型的张量,可以是 torch.LongTensor、torch.FloatTensor和torch.DoubleTensor
e = np.array([1, 2], dtype=np.float64) print(e) print(t.Tensor(e).type()) # torch.FloatTensor print(t.tensor(e).type()) # torch.DoubleTensor
也可以用 t.FloatTensor
方式2:用方法创建 Tensor
- torch.Tensor(size):
- torch.empty(size):
- torch.zeros(size)、torch.zeros_like(input):返回跟 input 同 size 的全 0 tensor
- torch.ones(size)、torch.ones_like(input)
- torch.arange(start=0, end, step=1):
- torch.full(size, value):见示例
- torch.eye(size):单元矩阵
- torch.linspace(s, e, step)
查看尺寸用 size 或者 shape
注意:torch.Tensor 创建 Tensor 后,不会马上分配空间,只是计算剩余空间是否够用,当使用该 Tensor 时才会分配空间,而其他创建方式会立即分配空间
示例
import torch as t x = t.Tensor(2, 3) ### 构建 2x3 矩阵 print(t.ones_like(x)) print(t.full((2, 3), 5)) # tensor([[5., 5., 5.], # [5., 5., 5.]]) print(t.arange(5)) # tensor([0, 1, 2, 3, 4]) print(x.size()) # torch.Size([2, 3]) ### 查看尺寸 print(x.size()[0]) # 2 查看行数 print(x.size(0)) # 2 查看行数 print(t.Size([2, 3])) print(x.shape) # torch.Size([2, 3])
方式3:随机数创建
- torch.rand(size):生成 (0,1) 内均匀分布的随机数
- torch.randn(size):生成标准正态分布 (0,1) 的随机数
- torch.normal(mean, std, out=None):生成正态分布的随机数,注意 mean 和 std 都是 tensor 格式,mean 默认 0,std 默认 1
更多的随机抽样方法,参见链接:https://pytorch.org/docs/stable/torch.html#random-sampling
数据类型
torch 支持 各种常见的数据类型
########## Tensor 只能生成 float32 单精度浮点,手动dtype无法指定其他类型 a = t.Tensor([1]) print(a.dtype) # torch.float32 # b = t.Tensor([2], dtype=t.int32) # 报错,手动无法指定 # b = t.Tensor([2], dtype=t.float64) # b = t.Tensor([2], dtype=t.float32) # 即使指定 float32 也报错 a = a.int() # 类型转换 float32 -> int32 print(a.dtype) # torch.int32 c = t.Tensor(np.arange(12, dtype=np.int)) print(c.dtype) # torch.float32 ########## tensor 可生成各种类型数据,也可手动指定数据类型 # 输入什么类型,输出就是什么类型;指定什么类型,输出什么类型 x = t.tensor([1]) print(x.dtype) # torch.int64 y = t.tensor([2], dtype=t.int32) # 手动指定 int32 类型 # y = t.tensor([2], dtype=t.float64) # y = t.tensor([2], dtype=t.float32) print(y.dtype) # torch.int32 y = y.long() # int32 -> int64 print(y.dtype) # torch.int64 x = x.int() # int64->int32 print(x.dtype) # torch.int32 z = t.tensor(np.arange(12, dtype=np.int)) print(z.dtype) # torch.int32
基本操作
有很多操作,这里只介绍简单的,具体查看官网
从接口的角度讲,对 Tensor 的操作可分为两类
1. torch.function,调用 torch 方法处理 Tensor
2. tensor.function,调用 tensor 的方法
如,torch.sum(a, b) 和 a.sum(b);
大多数情况下,二者等价,本文不做区分;
item
获取 Tensor 数值,只有当 tensor 为 1 个数时才可用
f = t.Tensor([1]) print(f) # tensor([1.]) print(f.data) # tensor([1.]) print(f.item()) # 1.0
获取元素个数
h = t.Tensor(2, 3) print(h.numel()) # 6 print(h.nelement()) # 6
转成 list
g = t.Tensor([2]) print(g.tolist()) # [2.0]
索引
Tensor 的索引和 numpy 几乎一模一样,请自行测试;
注意,索引出来的 Tensor 与 原 Tensor 共享内存
m = t.Tensor(3, 5) print(m) # tensor([[1.3130e-32, 0.0000e+00, 1.3130e-32, 0.0000e+00, 1.3131e-32], # [0.0000e+00, 1.3131e-32, 0.0000e+00, 1.3131e-32, 0.0000e+00], # [1.3131e-32, 0.0000e+00, 1.3131e-32, 0.0000e+00, 1.3131e-32]]) print(m[:, 1]) # tensor([0.0000e+00, 1.3131e-32, 0.0000e+00]) ### 3 row #### 共享内存 n = m[0] # 索引,只有一个代表行 n[0] = 10000 ### 改变 n,m 也会变化 print(m) # tensor([[1.0000e+04, 0.0000e+00, 1.3130e-32, 0.0000e+00, 1.3131e-32], # [0.0000e+00, 1.3131e-32, 0.0000e+00, 1.3131e-32, 0.0000e+00], # [1.3131e-32, 0.0000e+00, 1.3131e-32, 0.0000e+00, 1.3131e-32]]) m[0][0] = 558555 ### 改变 m,n 也会变化 print(n) # tensor([5.5856e+05, 0.0000e+00, 1.3130e-32, 0.0000e+00, 1.3131e-32])
也可以是条件索引
print(m>1) ### 返回 bool 值 print(m[m>1])
注意,条件索引不共享内存
x = m[m>1] x[0] = 99999 ### 改变 x,m 不会变化 print(m)
选择函数
torch.
index_select
(input, dim, index, out=None) → Tensor
-
input (Tensor) – the input tensor.
-
dim (python:int) – the dimension in which we index
-
index (LongTensor) – the 1-D tensor containing the indices to index
-
out (Tensor, optional) – the output tensor
x = t.randn(3, 4) print(x) # tensor([[ 0.1427, 0.0231, -0.5414, -1.0009], # [-0.4664, 0.2647, -0.1228, -1.1068], # [-1.1734, -0.6571, 0.7230, -0.6004]]) indices = t.tensor([0, 2]) print(t.index_select(x, 0, indices)) # tensor([[ 0.1427, 0.0231, -0.5414, -1.0009], # [-1.1734, -0.6571, 0.7230, -0.6004]])
torch.
masked_select
(input, mask, out=None) → Tensor
-
input (Tensor) – the input tensor.
-
mask (ByteTensor) – the tensor containing the binary mask to index with
-
out (Tensor, optional) – the output tensor.
类似于条件索引
x = t.randn(3, 4) print(x) # tensor([[ 0.3552, -2.3825, -0.8297, 0.3477], # [-1.2035, 1.2252, 0.5002, 0.6248], # [ 0.1307, -2.0608, 0.1244, 2.0139]]) mask = x.ge(0.5) ### x > 0.5 print(mask) ### 相当于条件索引 # tensor([[False, False, False, False], # [False, True, True, True], # [False, False, False, True]]) print(t.masked_select(x, mask)) # tensor([ 1.2252, 0.5002, 0.6248, 2.0139])
torch.
nonzero
(input, *, out=None, as_tuple=False) → LongTensor or tuple of LongTensors
获取非 0 元素
print(t.nonzero(t.tensor([1, 1, 1, 0, 1]))) # tensor([[0], # [1], # [2], # [4]]) print(t.nonzero(t.tensor([1, 1, 1, 0, 1]), as_tuple=True)) # (tensor([0, 1, 2, 4]),)
Tensor-Numpy 互转
操作如下
n = t.ones(2, 3) print(n.numpy()) ### Tensor 转 Numpy # [[1. 1. 1.] # [1. 1. 1.]] import numpy as np p = np.ones((2, 3)) q = t.from_numpy(p) ### Numpy 转 Tensor print(p) # tensor([[1., 1., 1.], # [1., 1., 1.]], dtype=torch.float64)
Tensor 与 Numpy 共享内存,使得他们之间的转换很快,而且几乎不会消耗资源;
共享内存意味着,一个变了,另一个也跟着变;
q.add_(n) ### q 被改变 print(q) ### # tensor([[2., 2., 2.], # [2., 2., 2.]], dtype=torch.float64) print(p) ### p 竟然也被改变了 # [[2. 2. 2.] # [2. 2. 2.]]
GPU 加速
注意,GPU 的优势体现在大规模数据集和复杂运算上,把数据从内存转移到显存产生额外开销,导致小数据反而不占优势
print(t.cuda.is_available()) # False if t.cuda.is_available(): x = x.cuda() ### Tensor 通过 cuda 方法转换为 GPU 的 Tensor y = y.cuda() x + y
共享内存
共享内存的操作汇总如下
1. 下标索引 取出的 Tensor 与 原 Tensor
2. reshape、view 生成的新 Tensor 与 原 Tensor
3. Tensor 与 Numpy 互转
参考资料:
《深度学习框架PyTorch:入门与实践_陈云(著)》
https://www.jianshu.com/p/7dbfc7076e5a