前言
本博客主要用于记录本人学习pytorch过程中一些笔记,并非零基础入门,方便自己查询,主要是深度学习计算机视觉方向。
一些概念
- 深度学习模型输入一般为数个图像构成的张量,张量shape为**[B, C, H, W]**的形式。
- torch中分类损失函数如CrossEntropyLoss()、BCELoss(),会自动对输入标签进行进行one-hot。
以多分类问题为例,输入一张图像,其标签为2,计算时会将其变为(0, 0, 1)。
- torch中很多张量操作可以事先给出是在哪个dim上进行操作,这里对dim的理解,参照官方文档,就是以不要这个维度为目的进行的操作。
dim (int or tuple of python:ints) – the dimension or dimensions to reduce
tensor
- torch中创建tensor有两种方式。
import torch
torch.Tensor(3, 3) # 传入的是size
torch.tensor([[1, 2],[3, 4]]) # 传入的就是要创建的张量
tensor维度调整
- 在调整shape时,比如reshape、view,如果给定shape中有-1,那么torch会根据其余给定的数据推算-1代表的数值。
- 使用transpose进行维度转换时,一次只能交换两个数值,而permute方法一次可交换多个维度。
- 使用squeeze和unsqueeze可快速减少或添加数字为1的dim。
tensor堆叠
- 使用cat可拼接多个张量,可指定维度进行拼接,但除了指定的维度,其他维度上的数字必须相同。
对于两个张量来说,a.shape=(a, b, r),b.shape=(a, b, m),拼接只能在dim=2上进行,最终得到c.shape=(a, b, r+m)。
- 使用stack可堆积多个张量,但相较于cat会产生一个新的维度,且要求参与堆积的张量的shape必须一样。
对于两个张量来说,a.shape=(a, b, r),b.shape=(a, b, r),最终得到c.shape=(2, a, b, r)。
import torch
a1 = torch.tensor([1, 2, 3])
a2 = torch.tensor([4, 5, 6])
a = [a1, a2]
c = torch.stack(a, dim=1)
print(c)
d = torch.cat(a, dim=0)
print(d)
tensor([[1, 4],
[2, 5],
[3, 6]])
tensor([1, 2, 3, 4, 5, 6])
tensor筛选
- torch中常会采用生成一个mask的形式,对原张量中进行某种条件的筛选。
mask是一个与原张量shape相同的bool类型,采用a[mask]所返回的值,只是mask中True对应的值。
import torch
a = torch.tensor([1, 2, 3, 4, 5])
mask = a > 2
print(mask)
print(a[mask])
tensor([False, False, True, True, True])
tensor([3, 4, 5])
- torch中nonzero可获取tensor中满足条件的值的索引。
返回索引永远是一个二维张量,shape=(x, y),x表示满足条件的元素数目,y为a的维度,其内容为索引。
通过squeeze可获取到索引
import torch
a = torch.tensor([[[2, 1, 6],
[8, 5, 6]],
[[2, 1, 6],
[8, 5, 6]]])
b = torch.tensor([2, 1, 6, 8, 5, 6])
print(a.shape)
print(torch.nonzero(a > 4))
print('############')
print(torch.nonzero(b > 4))
torch.Size([2, 2, 3])
tensor([[0, 0, 2],
[0, 1, 0],
[0, 1, 1],
[0, 1, 2],
[1, 0, 2],
[1, 1, 0],
[1, 1, 1],
[1, 1, 2]])
############
tensor([[2],
[3],
[4],
[5]])
- torch中where可实现类似nonzero的筛选,但返回值不同。
返回值为一个tuple,len(tuple)等于tensor的dim,以a中第一个满足条件的索引为例,读取方式为(0, 0, 2),取三个tensor相同位置的数值
对于一维张量,取元组第一个即为索引
import torch
a = torch.tensor([[[2, 1, 6],
[8, 5, 6]],
[[2, 1, 6],
[8, 5, 6]]])
b = torch.tensor([2, 1, 6, 8, 5, 6])
print(torch.where(a > 4))
print(torch.where(b > 4))
(tensor([0, 0, 0, 0, 1, 1, 1, 1]), tensor([0, 1, 1, 1, 0, 1, 1, 1]), tensor([2, 0, 1, 2, 2, 0, 1, 2]))
(tensor([2, 3, 4, 5]),)
tensor排序
- torch中max可获取原张量进行取大值操作,若不指定dim,只返回一个值,即最大值,若指定dim,返回一个列表,第一个为数值,第二个为索引。
import torch
a = torch.tensor([[6, 3, 2],
[1, 5, 9]])
out =torch.max(a, dim=0)
print(out)
print('#####################')
print(out[0])
print(out[1])
torch.return_types.max(
values=tensor([6, 5, 9]),
indices=tensor([0, 1, 1]))
#####################
tensor([6, 5, 9])
tensor([0, 1, 1])
- torch中sort可实现与max一样的效果,但返回值不同,第一个返回排序后的数值,第二个返回索引。
默认为升序排列(descending=False)
import torch
a = torch.tensor([[6, 3, 2],
[1, 5, 9]])
out =torch.sort(a, dim=0, descending=False)
print(out)
print('#####################')
print(out[0])
print(out[1])
torch.return_types.sort(
values=tensor([[1, 3, 2],
[6, 5, 9]]),
indices=tensor([[1, 0, 0],
[0, 1, 1]]))
#####################
tensor([[1, 3, 2],
[6, 5, 9]])
tensor([[1, 0, 0],
[0, 1, 1]])
- torch.argmax(),或是torch.argsort(),本质用法和sort,max一样,只不过只返回索引,也可指定dim。
tensor替换数值
- torch中index_fill可根据索引替换tensor中数值。
torch中某些函数操作后面带有_,如index_fill_,相较于index_fill,直接返回修改后的数据,即:a.index_fill_(),等同于a = a.index_fill()
import torch
a = torch.tensor([[1, 2, 3],
[4, 5, 6]])
index = torch.tensor([0, 2])
a.index_fill_(1, index, 0) # 第一个代表修改的维度,第二个代表修改位置的索引(张量),第三个为填充的数值
print(a)
tensor([[0, 2, 0],
[0, 5, 0]])
tensor分割
- torch中split可对tensor进行分割取出的操作。
可以使用torch.split,也可以使用a.split
import torch
a = torch.tensor([[1, 3, 2],
[6, 9, 7]])
print(a.split(split_size=1, dim=0)) # 第一个参数表示分割的尺寸,第二个是维度,torch会自动计算,2/1=2,得到两个张量
(tensor([[1, 3, 2]]), tensor([[6, 9, 7]]))
其他操作
- torch中广播操作有时应用十分方便(None)。
广播:如果两个张量的后缘维度(shape),即从末尾开始算起的维度相同,或是其中一方的维度存在1,那么就会认为是广播兼容的,在计算时会自动在缺失或维度为1的方向进行扩充,使运算正常进行。
None的位置即代表维度1添加的位置,对于例子中a就变为(4, 1),这样可以进行广播,如果是a[None, :]这样是不行的
import torch
a = torch.tensor([1, 2, 3, 4])
b = torch.tensor([1, 1, 1])
print(a[:, None] + b)
tensor([[2, 2, 2],
[3, 3, 3],
[4, 4, 4],
[5, 5, 5]])
- a.to(b)可以将a转化成与b相同的数据类型和相同GPU或CPU类型。
常见的如a.to(cuda)这种
- 创建一个新的Tensor,该Tensor的type和device都和原有Tensor一致,且无内容,创建方法有两种。
import torch
b = a.new()
b = torch.Tensor.new(a)
import torch
a = torch.tensor([1, 2, 3])
b = a.new()
print(b)
print(b.dtype == a.dtype)
print(b.device == a.device)
tensor([], dtype=torch.int64)
True
True