2.5 Tensor的API
Posted 王小小小草
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2.5 Tensor的API相关的知识,希望对你有一定的参考价值。
欢迎订阅本专栏:《PyTorch深度学习实践》
订阅地址:https://blog.csdn.net/sinat_33761963/category_9720080.html
- 第二章:认识Tensor的类型、创建、存储、api等,打好Tensor的基础,是进行PyTorch深度学习实践的重中之重的基础。
- 第三章:学习PyTorch如何读入各种外部数据
- 第四章:利用PyTorch从头到尾创建、训练、评估一个模型,理解与熟悉PyTorch实现模型的每个步骤,用到的模块与方法。
- 第五章:学习如何利用PyTorch提供的3种方法去创建各种模型结构。
- 第六章:利用PyTorch实现简单与经典的模型全过程:简单二分类、手写字体识别、词向量的实现、自编码器实现。
- 第七章利用PyTorch实现复杂模型:翻译机(nlp领域)、生成对抗网络(GAN)、强化学习(RL)、风格迁移(cv领域)。
- 第八章:PyTorch的其他高级用法:模型在不同框架之间的迁移、可视化、多个GPU并行计算。
Pytorch提供了很多tensor的API, 如若逐条去记忆想必自然不是程序员的学习方法,更不是AI从业者的学习方法,API是帮助我们快速开发的工具,绝不能成为学习的压力,因此相对有效的方法是“类”–> “查” -->“熟”。
-
“类”:对纷繁众多的API进行归类,先归大类,再在大类中归小类,对知识形成一个系统的认知;
-
“查”:当在实际的应用中忽然想实现某个功能的时候,在“类”的帮助下马上知道了是什么类别下的API能帮助实现,于是去官方文档中迅速查找到函数名、使用方法及例子;
-
“熟”:这是自然而然的过程,在不断高效“查”的过程中对“类”也逐渐熟悉,于是根本无需死记硬背,就对海量的API熟悉了。
pytorch tensor API的官方文档地址:http://pytorch.org/docs
文档中给API归了大类,但是每个大类罗列的API是根据首字母的顺序,也不方便大家快速认知,因此本章的小节中不但按照官方的思路对大类进行讲解,也根据笔者的思路对大类再做了更细致的归类,方便大家对API的认知。
2.5.1 调用API的方式
方式一:操作后创建新的变量
方式一中也有两种不同的方式可以选用
- (1)使用Torch module中的方法
用上文提到过的转置方法来举例, 可以调用torch.transpose(), 将原tensor:a作为参数传入, 生成新的tensor:a_t。
import torch
a = torch.ones(3, 2)
a_t = torch.transpose(a, 0, 1)
- (2)使用tensor object的中方法
直接在tensor:a上调用transpose方法,结果同上,
a = torch.ones(3, 2)
a_t = a.transpose(0, 1)
因此两种方法可以互相替换使用,但注意目前(2)中tensor对象的方法数目相对较少,用(1)torch moduel中的功能更全面。
方式二:在原变量上做操作
对tensor调用带有下划线结尾的方法,即为对原tensor进行操作,无需赋值新的变量
a = torch.ones(3, 2)
a.zero_()
tensor([[0., 0.],
[0., 0.],
[0., 0.]])
2.5.2 索引、切块
(1)简单索引与切块
对tensor的索引和对python中list的索引是一样的,只是tensor是多维数组,list是一维的。对list的索引不再赘述,下面看几个tensor索引的例子。
points = torch.tensor([[1.0, 4.0],[2.0, 1.0],[3.0, 5.0]])
points[1:] # 获取第2行开始的所有行 [[2.0, 1.0],[3.0, 5.0]]
points[1:, :] # 获取第2行开始的所有行的所有列,结果与上同 [[2.0, 1.0],[3.0, 5.0]]
points[1:, 0] # 获取第2行开始的所有行的第0列, [[2.0],[3.0]]
tensor([2., 3.])
(2)高级索引与切块
a.通过索引切割tensor: torch.index_select() & torch.take()
a = torch.rand(4,6)
b = torch.index_select(input=a, dim=1, index=torch.LongTensor([0,1,2,3]))
print(b)
tensor([[0.5042, 0.0299, 0.0558, 0.9661],
[0.0617, 0.8948, 0.4300, 0.0555],
[0.0531, 0.1290, 0.4504, 0.7697],
[0.4639, 0.8179, 0.8393, 0.6148]])
对a, 在维度1上,切出索引在[0,3)之间的元素。
注意:index必须是LongTensor类型的。
torch.take()也是通过索引取数,只是将Input平铺成一维的:
b = torch.take(input=a, index=torch.LongTensor([0,1,2,3]))
print(b)
tensor([0.5042, 0.0299, 0.0558, 0.9661])
b.通过掩码切割tensor:torch.masked_select()
mask = torch.ByteTensor([[0,0,1,0],[1,1,0,1]])
a = torch.rand(2,4)
b = torch.masked_select(input=a, mask=mask)
print(b)
tensor([0.5985, 0.8829, 0.7861, 0.3360])
c.选择非0tensor: torch.nonzeros(a)
d.等分tensor: torch.split & torch.chunck
# 在维度1上将a等分成大小为2的小块
a_split = torch.split(a, 5, dim=0)
print(a_split)
# 在维度1上将a等分成2块
a_chunk = torch.chunk(input=a, chunks=2, dim=1)
print(a_chunk)
(tensor([[0.7681, 0.5095, 0.5985, 0.7944],
[0.8829, 0.7861, 0.6407, 0.3360]]),)
(tensor([[0.7681, 0.5095],
[0.8829, 0.7861]]), tensor([[0.5985, 0.7944],
[0.6407, 0.3360]]))
e.通过tensor对象中的函数:
a.select(0,2):获取a的第1行第3列位置的元素
a.unfold(dim, size, step): 当step=1时返回a中维度为dim的所有大小为size的分片
2.5.3 连接、聚合、压缩、变形…
(1)tensor的连接:cat与stack
两个常用的连接tensor的方式:
torch.cat()拼接两个tensor, 但维度数量不变,如两个24的tensor在维度0上拼接,则生成一个44的新tensor,维度的数量仍然是2个;
torch.stack()将两个24的tensor拼接之后会产生22*4的新tensor, 总的维度数目变成了3.
a = torch.randn(2,4)
b = torch.randn(2,4)
a_b_cat = torch.cat(tensors=(a,b), dim=0)
a_b_stack = torch.stack(tensors=(a,b), dim=0)
print(a_b_cat.shape)
print(a_b_stack.shape)
torch.Size([4, 4])
torch.Size([2, 2, 4])
(2)tensor的压缩与扩张:sequenze与unbind
a = torch.rand(2,1,3,1)
# 不传入维度参数,则默认去掉所有大小为1的维度,变成(2,3)大小
a_squeeze = torch.squeeze(input=a)
# 传入指定维度参数,则只去掉该维度,如下变成(2,3,1)大小
a_squeeze = torch.squeeze(input=a, dim=1)
# 去掉0维
a_unbind = torch.unbind(a, 0)
同理,可以用torch.unsqueeze()来扩张指定维度
(3)tensor的聚合:ganther
(4)tensor的转换:t, transpose
t只适用于二维的Tensor的转置,即矩阵;而transpose是适合多维Tensor的维度转换.
a = torch.rand(2,3)
a_t = torch.t(a)
print(a_t.shape)
a_ts = torch.transpose(a,1,0)
print(a_ts.shape)
torch.Size([3, 2])
torch.Size([3, 2])
(5)tensor的变形:view
a = torch.rand(2,3,4)
print(a.shape)
a = a.view(2, 12)
print(a.shape)
# 若参数为-1则表示自动计算该维度的大小
a = a.view(-1, 12)
print(a.shape)
torch.Size([2, 3, 4])
torch.Size([2, 12])
torch.Size([2, 12])
2.5.4 数学操作
数学操作的API可多呢~总共大概有90多,各下面几节依次分类介绍。
(1)逐点操作
逐点操作是对tensor中的每个值都进行相同的操作,如torch.abs(a), 是将tensor中的每个value都绝对值化,其他逐点操作大致罗列如下表。
类型 | 功能 | 功能 | api |
---|---|---|---|
三角函数 | 余弦 | 余弦 | .cos(a) |
双曲余弦 | .cosh(a) | ||
反余弦 | .acos(a) | ||
正弦 | 正弦 | .sin(a) | |
双曲正弦 | .sinh(a) | ||
反正弦 | .asin(a) | ||
正切 | 正切 | .tan(a) | |
双曲正切 | .tanh(a) | ||
反正切 | .atan(a) | ||
2个张量的反正切 | .atan2(a,b) | ||
加减乘除 | 加法 | .add(a,b) | |
乘法 | .mul(a,b) #若张量标量:逐点都乘以标量; 若张量张量:对应元素乘 | ||
除法 | .div(a,b) | ||
先除后加 | .addcdiv(t, 0.5, t1, t2) # t+0.5(t1/t2) | ||
先乘后加 | .addcmul(t, 0.5, t1, t2) # t+0.5(t1·t2) | ||
除法余数 | .reminder(a,2) # a%2 | ||
指数对数 | 指数 | .exp(a) | |
自然对数 | .log(a) | ||
幂与根 | 幂 | .pow(a,2).pow(a,a) | |
平方根 | .sqrt(a) | ||
平方根的倒数 | .rsqrt(a) | ||
取整 | 向上取整 | .ceil(a) | |
向下取整 | .floor(a) | ||
四舍五入 | .round(a) | ||
截断 | tranc(a) | ||
激活函数 | sigmoid | .sigmoid(a) | |
其他 | 返回分数 | .frac(a) | |
取负 | .neg(a) | ||
取倒 | .recipocal(a) | ||
取正负号 | .sign(a) | ||
夹紧到某个区域 | .clamp(a, max, min) | ||
线性差值 | .lerp() |
(2)缩减操作
缩减操作是指操作之后维度变小了,如求22的tensor每行的均值,得到的结果是21的新tensor。常用的缩减操作如下表罗列:
基本运算 | 求均值 | .mean(a) # 求所有数值的均值,返回标量.mean(a, dim) # 求指定维度上的均值,返回数组 |
---|---|---|
求中位数 | .media(a) #同上 | |
求积 | .prod(a) | |
求标准差 | .std(a) | |
求方差 | .var(a) | |
求和 | .sum(a) | |
累计运算 | 求累计和 | .cumsum(a, dim) |
求累计积 | .cumprod(a,dim) | |
范数运算 | (a-b)的p范数 | dist(a, b, 3) |
a的p范数 | .norm(a,p) |
(3)比较操作
基本比较 | a == b ? | .eq(a,b) |
---|---|---|
a>b ? | .gt(a,b) | |
a <= b ? | .le(a,b) | |
a < b ? | .lt(a,b) | |
a != b ? | .ne(a,b) |
除了以上这些基本的比较操作,pytorch还封装了一些基于比较的常用方法:
取值 | 取指定维度第K个最小值 | .kthvalue(a,k) |
---|---|---|
取指定维度K个最大/小值 | .topk(a,k) | |
取最大值 | .max(a, dim) | |
取最小值 | .min(a, dim) | |
排序 | 排序, 返回排序后的tensor,与原index | .sort(a) |
(4)线性代数操作
点乘 | .dot(a,b) |
---|---|
特征值、特征向量 | .eig(a,True) |
对满秩矩阵计算最小二乘和最小范数 | .gels(B,A) |
OR分解 | gegrf(A) |
AX=B的解 | gesv(B,A) |
取逆 | invese(a) |
矩阵*矩阵 | .mm(x,y) |
矩阵*向量 | .mv(x,y) |
向量积 | .cross(a,b) |
获取对角矩阵 | .diag(a) |
返回上三角 | .tril() |
返回下三角 | .triu() |
有必要讲以下最常用的点乘、矩阵与向量乘、矩阵与矩阵乘的例子:
- 首先看点乘,调用torch.dot()实现向量与向量的点积,即将两个向量对应位置的元素相乘,并求和,其输出是标量。
a = torch.Tensor([1,2,3])
b = torch.Tensor([2,3,4])
c = torch.dot(a,b) # 1*2 + 2*3 + 3*3 = 20
print(c)
tensor(20.)
- torch.mv是实现矩阵与向量相乘,比如矩阵a:
[ 1 2 3 4 5 6 7 8 9 ] (3) \\left[ \\beginmatrix 1 & 2 & 3 \\\\ 4 & 5 & 6 \\\\ 7 & 8 & 9 \\endmatrix \\right] \\tag3 ⎣⎡147258369⎦⎤(3)
和向量b:
[ 1 2 3 ] (3) \\left[ \\beginmatrix 1 \\\\ 2 \\\\ 3 \\endmatrix \\right] \\tag3 ⎣⎡123⎦⎤(3)
相乘:
a = torch.Tensor([[1,2,3],[4,5,6],[7,8,9]])
b = torch.Tensor([1,2,3])
c = torch.mv(a, b)
print(c)
tensor([14., 32., 50.])
2.5.5 序列化
当我们想要把有价值的tensor保存在磁盘上以便下次读入使用时,就需要用到tensor的序列化操作。有两种方式可以操作,第一是使用torch 模块中的save/load功能,但是这样保存的结果只能适用于Pytorch读取,其他软件无法读取;因此第二种方法是使用HDF5格式, HDF5是一个接口,是很多软件支持的格式。
(1)使用torch.save/load存取tensor
保存:
points = torch.tensor([[1.0, 4.0],[2.0, 1.0],[3.0, 5.0]])
# 可以这样
torch.save(points, path)
# 也可以这样
with open(path, 'w') as f:
torch.save(points, f)
读取:
# 可以这样
points = torch.load(path)
# 也可以这样
with open(path, 'r') as f:
points = torch.load(f)
(2)使用hdf5存取tensor
先安装h5py
conda install h5py
保存:
注意,tensor是先转换成NumPy array, 再作为create_dataset的参数传入
import h5py
f = h5py.File(path, 'w')
dset = f.create_dataset('coords', data=points.numpy())
f.close()
读取:
f = h5py.File(path, 'r')
dset = f['coords']
last_points = dset[1:] # 返回的是NumPyArray
last_points = torch.from_numpy(dset[1:]) # 要将NumPyArray转换成tensor
f.close()
2.5.6 设备
tensor可以放在CPU上计算,也可以放在GPU上计算,GPU能更快速,并行化地计算。有三种方式可以让tensor在设备之间转换。
(1)将tensor放到GPU上的方式
- 创建时指定设备
point_gpu = torch.tensor([1,2], device=‘cuda’)
- 创建后移动到某设备
point_gpu = torch.tensor([1,2]).to(device=‘cuda’)
- 有多块GPU时可以使用’cuda:n’表示移动到第n块GPU上
point_gpu = torch.tensor([1,2]).to(device=‘cuda:1’)
(2)要注意的点
- 当CPU上的tensor移动到了GPU上,原来的CPU类型也随之转变维GPU类型,如:torch.FloatTensor --> torch.cuda.FloatTensor
- 当该tensor在已经在GPU上了,则在该Tensor上做的操作也都是在GPU上运算,运算后生成的新变量也是在GPU上的。
2.5.7 其他
(1)判断是否为张量或storage
- is_tensor
- is_storage
(2)设置打印
- set_printoptions (参考numpy)
(3)设置/获取并行数
- set_num_threads(n)
- get_num_threads()
(4)随机取样
- 设置随机种子: manel_seed()
- 设置初始种子: inital_seed()
- 设置/获取随机状态:set_rng_state() / get_rng_state()
以上是关于2.5 Tensor的API的主要内容,如果未能解决你的问题,请参考以下文章