目录
2、pytorch.range() 和 pytorch.arange() 的区别
4、pytorch学习 中 torch.squeeze() 和torch.unsqueeze()的用法
1、torch.meshgrid
x1 ,y1 = torch.meshgrid(x,y)
参数是两个,第一个参数我们假设是x,第二个参数假设就是y
输出的是两个tensor,size就是x.size * y.size(行数是x的个数,列数是y的个数)
具体输出看下面
注意:两个参数的数据类型要相同,要么都是float,要么都是int,否则会报错。
# 【1】
import torch
a = torch.tensor([1, 2, 3, 4])
print(a)
b = torch.tensor([4, 5, 6])
print(b)
x, y = torch.meshgrid(a, b)
print(x)
print(y)
结果显示:
tensor([1, 2, 3, 4])
tensor([4, 5, 6])
tensor([[1, 1, 1],
[2, 2, 2],
[3, 3, 3],
[4, 4, 4]])
tensor([[4, 5, 6],
[4, 5, 6],
[4, 5, 6],
[4, 5, 6]])
# 【2】
import torch
a = torch.tensor([1, 2, 3, 4, 5, 6])
print(a)
b = torch.tensor([7, 8, 9, 10])
print(b)
x, y = torch.meshgrid(a, b)
print(x)
print(y)
结果显示:
tensor([1, 2, 3, 4, 5, 6])
tensor([ 7, 8, 9, 10])
tensor([[1, 1, 1, 1],
[2, 2, 2, 2],
[3, 3, 3, 3],
[4, 4, 4, 4],
[5, 5, 5, 5],
[6, 6, 6, 6]])
tensor([[ 7, 8, 9, 10],
[ 7, 8, 9, 10],
[ 7, 8, 9, 10],
[ 7, 8, 9, 10],
[ 7, 8, 9, 10],
[ 7, 8, 9, 10]])
2、pytorch.range() 和 pytorch.arange() 的区别
https://blog.csdn.net/m0_37586991/article/details/88830026
https://pytorch.org/docs/stable/torch.html#torch.range
>>> y=torch.range(1,6)
>>> y
tensor([1., 2., 3., 4., 5., 6.])
>>> y.dtype
torch.float32
>>> z=torch.arange(1,6)
>>> z
tensor([1, 2, 3, 4, 5])
>>> z.dtype
torch.int64
总结:
torch.range(start=1, end=6)
的结果是会包含end
的,
而torch.arange(start=1, end=6)
的结果并不包含end
。- 两者创建的
tensor
的类型也不一样。
3、Pytorch中contiguous()函数理解
在使用transpose()
进行转置操作时,pytorch并不会创建新的、转置后的tensor,而是修改了tensor中的一些属性(也就是元数据),使得此时的offset和stride是与转置tensor相对应的。转置的tensor和原tensor的内存是共享的!
transpose()后改变元数据,
代码示例:
import torch
x = torch.randn(3, 2)
y = torch.transpose(x, 0, 1)
print("修改前:")
print("x-", x)
print("y-", y)
print("\n修改后:")
y[0, 0] = 11
print("x-", x)
print("y-", y)
修改前:
x- tensor([[ 0.9611, -0.6472],
[ 0.5917, 0.3073],
[-0.6873, -0.3117]])
y- tensor([[ 0.9611, 0.5917, -0.6873],
[-0.6472, 0.3073, -0.3117]])
修改后:
x- tensor([[11.0000, -0.6472],
[ 0.5917, 0.3073],
[-0.6873, -0.3117]])
y- tensor([[11.0000, 0.5917, -0.6873],
[-0.6472, 0.3073, -0.3117]])
Process finished with exit code 0
可以看到,改变了y的元素的值的同时,x的元素的值也发生了变化。
因此可以说,x是contiguous的,但y不是(因为内部数据不是通常的布局方式)。注意不要被contiguous的字面意思“连续的”误解,tensor中数据还是在内存中一块区域里,只是布局的问题!
为什么这么说:因为,y里面数据布局的方式和从头开始创建一个常规的tensor布局的方式是不一样的。这个可能只是python中之前常用的浅拷贝,y还是指向x变量所处的位置,只是说记录了transpose这个变化的布局。
使用contiguous()
如果想要断开这两个变量之间的依赖(x本身是contiguous的),就要使用contiguous()针对x进行变化,感觉上就是我们认为的深拷贝。
当调用contiguous()时,会强制拷贝一份tensor,让它的布局和从头创建的一模一样,但是两个tensor完全没有联系。
x = torch.randn(3, 2)
y = torch.transpose(x, 0, 1).contiguous()
print("修改前:")
print("x-", x)
print("y-", y)
print("\n修改后:")
y[0, 0] = 11
print("x-", x)
print("y-", y)
修改前:
x- tensor([[-0.0392, -1.2368],
[-1.6313, 0.7148],
[ 0.6547, 0.0560]])
y- tensor([[-0.0392, -1.6313, 0.6547],
[-1.2368, 0.7148, 0.0560]])
修改后:
x- tensor([[-0.0392, -1.2368],
[-1.6313, 0.7148],
[ 0.6547, 0.0560]])
y- tensor([[11.0000, -1.6313, 0.6547],
[-1.2368, 0.7148, 0.0560]])
Process finished with exit code 0
4、pytorch学习 中 torch.squeeze() 和torch.unsqueeze()的用法
https://zhuanlan.zhihu.com/p/86763381
squeeze的用法主要就是对数据的维度进行压缩或者解压。
https://pytorch.org/docs/stable/generated/torch.squeeze.html#torch.squeeze
torch.squeeze(input, dim=None, out=None)
- 参数:
input (Tensor)
– 输入张量dim (int, optional)
– 如果给定,则input只会在给定维度挤压out (Tensor, optional)
– 输出张量
为何只去掉 1 呢?
多维张量本质上就是一个变换,如果维度是 1 ,那么,1 仅仅起到扩充维度的作用,而没有其他用途,因而,在进行降维操作时,为了加快计算,是可以去掉这些 1 的维度。
注意: 返回张量与输入张量共享内存,所以改变其中一个的内容会改变另一个。
>>> x = torch.zeros(2, 1, 2, 1, 2)
>>> x.size()
torch.Size([2, 1, 2, 1, 2])
>>> y = torch.squeeze(x)
>>> y.size()
torch.Size([2, 2, 2])
>>> y = torch.squeeze(x, 0)
>>> y.size()
torch.Size([2, 1, 2, 1, 2])
>>> y = torch.squeeze(x, 1)
>>> y.size()
torch.Size([2, 2, 1, 2])
unsqueeze的作用
torch.unsqueeze(input, dim, out=None)
参数:
tensor (Tensor)
– 输入张量dim (int)
– 插入维度的索引out (Tensor, optional)
– 结果张量
- 扩展维度
返回一个新的张量,对输入的既定位置插入维度 1
- 注意: 返回张量与输入张量共享内存,所以改变其中一个的内容会改变另一个。
如果dim为负,则将会被转化dim+input.dim()+1
import torch
x = torch.Tensor([1, 2, 3, 4]) # torch.Tensor是默认的tensor类型(torch.FlaotTensor)的简称。
print('-' * 50)
print(x) # tensor([1., 2., 3., 4.])
print(x.size()) # torch.Size([4])
print(x.dim()) # 1
print(x.numpy()) # [1. 2. 3. 4.]
print('-' * 50)
print(torch.unsqueeze(x, 0)) # tensor([[1., 2., 3., 4.]])
print(torch.unsqueeze(x, 0).size()) # torch.Size([1, 4])
print(torch.unsqueeze(x, 0).dim()) # 2
print(torch.unsqueeze(x, 0).numpy()) # [[1. 2. 3. 4.]]
print('-' * 50)
print(torch.unsqueeze(x, 1))
# tensor([[1.],
# [2.],
# [3.],
# [4.]])
print(torch.unsqueeze(x, 1).size()) # torch.Size([4, 1])
print(torch.unsqueeze(x, 1).dim()) # 2
print('-' * 50)
print(torch.unsqueeze(x, -1))
# tensor([[1.],
# [2.],
# [3.],
# [4.]])
print(torch.unsqueeze(x, -1).size()) # torch.Size([4, 1])
print(torch.unsqueeze(x, -1).dim()) # 2
print('-' * 50)
print(torch.unsqueeze(x, -2)) # tensor([[1., 2., 3., 4.]])
print(torch.unsqueeze(x, -2).size()) # torch.Size([1, 4])
print(torch.unsqueeze(x, -2).dim()) # 2
5、grid_sample()函数及双线性采样
https://zhuanlan.zhihu.com/p/112030273
首先Pytorch中grid_sample函数的接口声明如下:
torch.nn.functional.grid_sample(input, grid, mode='bilinear', padding_mode='zeros', align_corners=None)
在官方文档里面关于该函数的作用是这样描述的:
Given an input and a flow-field grid, computes the output using input values and pixel locations from grid.
简单来说就是,提供一个input的Tensor以及一个对应的flow-field网格(比如光流,体素流等),然后根据grid中每个位置提供的坐标信息(这里指input中pixel的坐标),将input中对应位置的像素值填充到grid指定的位置,得到最终的输出。
关于input、grid以及output的尺寸如下所示:(input也可以是5D的Tensor,这里我们只考虑4D的情况)
这里的input和output就是输入的图片,或者是网络中的feature map。关键的处理过程在于grid,grid的最后一维的大小为2,即表示input中pixel的位置信息(x,y),这里一般会将x和y的取值范围归一化到[-1. 1]之间, (-1,-1)表示input左上角的像素的坐标, (1,1)表示input右下角的像素的坐标,对于超出这个范围的坐标,函数将会根据参数padding_mode的设定进行不同的处理。
- padding_mode='zeros':对于越界的位置在网格中采用pixel value=0进行填充。
- padding_mode='border':对于越界的位置在网格中采用边界的pixel value进行填充。
- padding_mode='reflection':对于越界的位置在网格中采用关于边界的对称值进行填充。
对于mode='bilinear'参数,则定义了在input中指定位置的pixel value中进行插值的方法,为什么需要插值呢?因为前面我们说了,grid中表示的位置信息x和y的取值范围在[-1,1]之间,这就意味着我们要根据一个浮点型的坐标值在input中对pixel value进行采样,mode有nearest和bilinear
两种模式。 nearest就是直接采用与(x,y)距离最近处的像素值来填充grid,而bilinear则是采用双线性插值的方法来进行填充,总之其与nearest的区别就是nearest只考虑最近点的pixel value,而bilinear则采用(x,y)周围的四个pixel value进行加权平均值来填充grid
双线性插值:
上面讲到双线性插值会对(x,y)周围的四个pixel value进行加权平均