pytorch深度指南-torch与Tensor常用操作方法
import torch
torch.Tensor
会继承某些torch
的某些数学运算,例如sort, min/max….不需要调用相应的torch.funciton
进行处理,下文中如果是torch/Tensor
即表示该函数可以直接对self的tensor使用,也可以使用torch给的相应函数接口
torch/Tensor.reshape(input, shape) → Tensor
指定tensor新的shape,reshape过后不会更该数据量和数据格式,只是对数据的shape做了调整,因此要保证reshape前后元素个数一致。 参数:
input(tensor) - 输入tensor
shape(tuple or *size) - 新的shape 如果还剩下一个维度,很好,你可以直接使用-1来替代,表示这个维度中应该有的元素数量
torch/Tensor.view()
与reshape功能类似,将源tensor的shape改变指定形状。
原文中这样描述 Returned tensor will be a view of input. Otherwise, it will be a copy. Contiguous inputs and inputs with compatible strides can be reshaped without copying, but you should not depend on the copying vs. viewing behavior.
二者区别:当tensor都为contiguous类型(邻近模式)时,两个函数并无差异,使用原来的数据内容,不会复制一份新的出来;如果tensor不是,例如经过了transpose或permute之后,需要contiguous然后再使用view。reshape其实就是.contiguous+view,这样不会开辟新的空间存放tensor,而是共享原来的数据内存。
torch.arange(10).reshape((2,5))
tensor([[ 0., 1., 2., 3., 4.],
[ 5., 6., 7., 8., 9.]])
torch.arange(10).reshape(5, -1)#可以看到新的shape是(5,2),使用-1自动求剩余最后一个维度
tensor([[ 0., 1.],
[ 2., 3.],
[ 4., 5.],
[ 6., 7.],
[ 8., 9.]])
torch.index_select(input, dim, index, out=None)
指定在哪个轴上,index是多少,注意index要是一个tensor, dim和index确定了一个维度的坐标$(dim_1=index_i,….dim_n=index)$
a = torch.randn([3,4])
print(a)
a.index_select(0,torch.tensor([2])).reshape(2,2)#
tensor([[ 0.0334, 0.9123, -1.2300, -0.9336],
[-0.8364, 0.6584, 0.6878, -2.5896],
[ 0.1862, -0.3752, 0.4150, -1.4008]])
tensor([[ 0.1862, -0.3752],
[ 0.4150, -1.4008]])
torch.linespace(start, end, steps=100, out=None)
返回一个一维tensor,包含step个元素,每个元素之间等间距,依次递增$\frac{end-start}{step}$
torch.linspace(0,1,10, dtype=torch.float32)
tensor([ 0.0000, 0.1111, 0.2222, 0.3333, 0.4444, 0.5556, 0.6667,
0.7778, 0.8889, 1.0000])
Tensor.repeat(input, *size)
把输入的input当做一个基本模块m,扩张成size的tensor,其中每个元素为m,最后返回的Tensor的shape为() *size必须比input的维度要高,
if input和size维度相等:
input = (a,b)
*size = (c,d)
out = (a×c, b×d)
size > input
input = (a,b)
*size = (c,d,e)
out = (c, d×a,e×b)
torch.Tensor.repeat(torch.tensor([2,3]),2,4,3).shape
torch.Size([2, 4, 6])
torch/Tensor.nonzero()
返回一个包含输入input中非零元素索引的张量,输出张量中非零元素的索引 若输入input有n
维,则输出的索引张量output形状为z * n
, 这里z是输入张量input中所有非零元素的个数
a = torch.eye(3,3)
print('a:', a)
a.nonzero()#所有非0的坐标,注意返回的每个元素都是一个完整的坐标index~
a: tensor([[ 1., 0., 0.],
[ 0., 1., 0.],
[ 0., 0., 1.]])
tensor([[ 0, 0],
[ 1, 1],
[ 2, 2]])
b = torch.arange(8).reshape(2,2,2)
print('b:', b)
b.nonzero()#z=7,n=3,输出(7*3)矩阵
b: tensor([[[ 0., 1.],
[ 2., 3.]],
[[ 4., 5.],
[ 6., 7.]]])
tensor([[ 0, 0, 1],
[ 0, 1, 0],
[ 0, 1, 1],
[ 1, 0, 0],
[ 1, 0, 1],
[ 1, 1, 0],
[ 1, 1, 1]])
torch/Tensor.chunk(tensor, chunks, dim=0)
将一个tensor在指定维度上分成chunks个数据块,为cat的逆过程,最后一个块可能会小一些,返回的是一个元组,每个元素都是其中一块 参数: tensor (Tensor) – 输入Tensor chunks (int) – 分成几块的数量 dim (int) – 沿着哪个维度进行切分
可以看成
torch.cat()
的逆运算过程
c = torch.randn(7,4)
c.chunk(chunks=4,dim=0)#,在dim=0上划分,返回的是一个元组,共分为4块
(tensor([[ 0.0722, 0.2573, -0.2504, 1.7426],
[-3.3098, 0.8971, 0.0274, -0.2365]]),
tensor([[ 1.1137, 0.3401, -1.4004, 1.2823],
[-0.5553, 0.8056, -0.1764, 0.7666]]),
tensor([[ 1.3739, -1.4938, 1.8446, 0.4783],
[-1.5898, -0.2520, -0.4873, 1.6098]]),
tensor([[ 0.5421, -0.2846, 0.1441, -0.5456]]))
torch/Tensor.clamp(input, min, max, out=None)
功能:将tensor所有元素裁剪到指定范围[min, max]并返回
c = torch.tensor([1,2,3,4,5,6,7,8])
c = c.clamp(3,6)#裁剪并返回
c
tensor([ 3, 3, 3, 4, 5, 6, 6, 6])
torch/Tensor.sort(input, dim=None, descending=False, out=None)
沿着指定维度排序,如果没有指定维度,默认最后一个维度,descending选择升序还是降序,返回一个元组(排序好的tensor和相应的索引)
a = torch.randint(0,10,(2,6)).squeeze().int()
a
tensor([[ 0, 9, 7, 6, 3, 0],
[ 8, 1, 8, 3, 6, 4]], dtype=torch.int32)
a.sort(dim=0)#返回排序好的值和索引
(tensor([[ 0, 1, 7, 3, 3, 0],
[ 8, 9, 8, 6, 6, 4]], dtype=torch.int32),
tensor([[ 0, 1, 0, 1, 0, 0],
[ 1, 0, 1, 0, 1, 1]]))
torch/Tensor.topk(input, k, dim=None, largest=True, sorted=True, out=None) -> (Tensor, LongTensor)
返回在指定维度上k个最大的元素,默认最后一个维度,返回值是一个元组包括值和索引(values, indices) 参数:
input (Tensor) – 输入tensor
k (int) – k个最值元素
dim (int) – 沿着哪个维度排许
largest (bool) – 选取最大元素还是最小元素
sorted (bool) – 返回元素是否有序
torch.randn(12).topk(4)#返回topK数值和位置索引
(tensor([ 2.0778, 1.6199, 0.8411, 0.2411]), tensor([ 0, 1, 9, 4]))
torch.split(tensor, split_size_or_sections, dim=0)
torch/Tensor.flatten(input, start_dim=0, end_dim=-1) → Tensor
将一个tensor按照存储位置顺序展平
a = torch.randn(3,3)
print(a)
# torch.flatten(a)
# a.flatten()
tensor([[-1.6724, -0.0280, 0.0100],
[ 0.3437, 0.9472, -0.3655],
[-0.3134, -2.6223, -0.7097]])
torch.numel()
返回tensor包含所有元素的数量
torch.stack(seq, dim=0, out=None) → Tensor
在一个新的维度上,拼接原有的tensor,注意该操作会产生新的维度,待组合的tensor要有相同的size
参数:
seq (sequence of Tensors) – 待拼接的tensor,要以seq形式
dim (int) – dimension to insert. Has to be between 0 and the number of dimensions of concatenated tensors (inclusive)
torch/Tensor.squeeze(input, dim=None, out=None) → Tensor
去除tensor中维度=1所在的那个维度,很多时候,为了保持tensor的shape对齐会提升维度,提升一些无关紧要的1维,然而在使用的时候我们不希望这些无关紧要的维度干扰我们的操作。
例如,如果输出shape:(A×1×B×1×D),经过squeeze后(A×B×D)
注意:返回的tensor与输入共享存储空间,改变其中任何一个都会改变相应其他那个
a = torch.arange(10).reshape(1,1,2,5)
print('a:', a)
b = a.squeeze()
b += 2
a#可以看到虽然对b操作,但是原始a的值也发生了变化
a: tensor([[[[ 0., 1., 2., 3., 4.],
[ 5., 6., 7., 8., 9.]]]])
tensor([[[[ 2., 3., 4., 5., 6.],
[ 7., 8., 9., 10., 11.]]]])
torch/Tensor.unsqueeze(dim)
提升一个新的维度,该dim=1,例如:(2,6)->(1,2,6)
torch.transpose(input, dim0, dim1) → Tensor
轴/坐标索引 交换
torch.where(condition, x, y) → Tensor
逐个位置元素判断,返回一个tensor可能来自源数据x或者y。
**注意:**
条件,x,y都必须是可广播的
**参数:**
condition (ByteTensor) – When True (nonzero), yield x, otherwise yield y
x (Tensor) – values selected at indices where condition is True
y (Tensor) – values selected at indices where condition is False
Returns:
返回的tensor的shape与条件,x和y都是一致的!!)
x = torch.randn(3,2)
y = torch.ones(3,2)
print('x:', x)
print('y', y)
torch.where(x > 0 , x, y)
x: tensor([[ 0.8968, 3.3511],
[-0.8421, -1.1878],
[-0.0903, 0.6168]])
y tensor([[ 1., 1.],
[ 1., 1.],
[ 1., 1.]])
tensor([[ 0.8968, 3.3511],
[ 1.0000, 1.0000],
[ 1.0000, 0.6168]])
Tensor.type(torch.type)tensor数据类型转换
Tensor.int()
将数据转为int
Tensor.long()
将数据转为longInt
Tensor.byte()
将数据转换为无符号整型
Tensor.float()
将数据转换为float类型
Tensor.double()
将数据转换为double类型
a = torch.tensor([1,2,3,4])
a.long().type()
torch.LongTensor
a.float().type()
torch.FloatTensor
a.byte().type()
torch.ByteTensor
Tensor.cuda(device, non_blocking=False)
Returns a copy of this object in CUDA memory. 返回一个CUDA内存数据的副本,将输入数据存入cuda
a = torch.arange(1200, dtype=torch.float64).cuda()
Tensor.clone()
Returns a copy of the self tensor. The copy has the same size and data type as self. 返回self
tensor的一个拷贝,与原数据有相同的size和数据类型
clone()得到的Tensor不仅拷贝了原始的value,而且会计算梯度传播信息,copy_()只拷贝数值
a = torch.tensor([1,2,3,4,5], dtype=torch.float32, requires_grad=True)
b = a.clone()#a经过克隆得到b,
c = (b ** 2).mean()#
c.backward()
print('a_grad:', a.grad)#但是梯度传播没有因此中断
a_grad: tensor([ 0.4000, 0.8000, 1.2000, 1.6000, 2.0000])
Tensor.copy_(src, non_blocking=False)
只拷贝src
的数据到self
tensor,并返回self
,src
和self
可以有不同的数据类型和不同的设备上.
参数: src (Tensor) – 源数据 non_blocking (bool) – 如果是True,copy操作跨CPU和GPU,但可能会出现异步问题
a = torch.tensor([1,2,3,4,5], dtype=torch.float32, requires_grad=True)
b = (a ** 2).mean()
b.backward()
print('a_grad:', a.grad)
c = torch.zeros(5)
c.copy_(a)
print('c_grad:', c.grad)
a_grad: tensor([ 0.4000, 0.8000, 1.2000, 1.6000, 2.0000])
c_grad: None
Tensor.contiguous()
将tensor改为连续存储模式
Tensor.fill_()内容填充
tensor内部全部填充value元素
Tensor.zero_()
tensor内容全部填充0
Tensor.normal_(mean, std, out=None)
a = torch.randn(3,3)
a.fill_(3)#指定内容填充
tensor([[ 3., 3., 3.],
[ 3., 3., 3.],
[ 3., 3., 3.]])
a.zero_()
tensor([[ 0., 0., 0.],
[ 0., 0., 0.],
[ 0., 0., 0.]])
a.normal_()
tensor([[ 0.1044, -0.1353, -0.7540],
[-0.6852, 0.2683, 0.8297],
[ 2.8920, 0.2846, -1.1742]])
torch生成常用矩阵
torch.zeros(*size)
生成全零矩阵
torch.ones(*size)
生成全1矩阵
torch.eye(*size)
生成对角矩阵,对角线元素全为1
torch.arange(start=0, end, step=1, out=None, dtype=None, layout=torch.strided, device=None, requires_grad=False)
返回指定区间,指定步长的1-D tensor
torch.zeros(3,3)
tensor([[ 0., 0., 0.],
[ 0., 0., 0.],
[ 0., 0., 0.]])
torch.ones(3,3)
tensor([[ 1., 1., 1.],
[ 1., 1., 1.],
[ 1., 1., 1.]])
torch.eye(3,3)
tensor([[ 1., 0., 0.],
[ 0., 1., 0.],
[ 0., 0., 1.]])
torch.arange(0, 10, 2)#区间是左壁右开,不包含end
tensor([ 0., 2., 4., 6., 8.])
torch/Tensor.round(input, out=None) → Tensor
对tensor内所有元素取整
a = torch.randint(0,10,(2,2))
a.round()
tensor([[ 7., 5.],
[ 1., 5.]])
torch.randomtorch自带随机模块
生成随机数的功能模块
torch.random.manual_seed(seed)
设置随机数种子
torch.randint(low, high, size)
返回一个服从uniform分布的int随机矩阵
torch.randn(*sizes, out=None, dtype=None, layout=torch.strided, device=None, requires_grad=False)
$\text{out}_{i} \sim \mathcal{N}(0, 1)$ 生成一个服从(0,1)标准正态分布的矩阵,传入size使用参数收集机制。
torch.randperm(n, out=None, dtype=torch.int64, layout=torch.strided, device=None, requires_grad=False) → LongTensor
生成一个0→n-1
随机序列 参数:
n (int) – 生成序列最大上界(不包含n)
torch.randint(0, 10, (2,2))#使用参数收集机制
tensor([[ 6., 9.],
[ 3., 8.]])
torch.randn(2,2)#使用参数收集机制,服从搞死分布
tensor([[-0.7565, 1.2032],
[-0.7030, 1.7259]])
torch.randperm(4)#返回一个生成的序列
tensor([ 0, 1, 2, 3])
torch.arange(0,10,1).type(torch.int32)
tensor([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9], dtype=torch.int32)