- Java锁的逻辑(结合对象头和ObjectMonitor)
- 还在用饼状图?来瞧瞧这些炫酷的百分比可视化新图形(附代码实现)⛵
- 自动注册实体类到EntityFrameworkCore上下文,并适配ABP及ABPVNext
- 基于Sklearn机器学习代码实战
授人以鱼不如授人以渔,原汁原味的知识才更富有精华,本文只是对张量基本操作知识的理解和学习笔记,看完之后,想要更深入理解,建议去 pytorch 官方网站,查阅相关函数和操作,英文版在 这里 ,中文版在 这里 。本文的代码是在 pytorch1.7 版本上测试的,其他版本一般也没问题.
Pytorch 中,张量的操作分为 结构操作和数学运算 ,其理解就如字面意思。结构操作就是改变张量本身的结构,数学运算就是对张量的元素值完成数学运算.
tranpose
、 view
等)、合并分割( split
、 chunk
等)、索引切片( index_select
、 gather
等)。 squeeze()
:对 tensor 进行维度的压缩,去掉维数为 1
的维度。用法: torch.squeeze(a)
将 a 中所有为 1 的维度都删除,或者 a.squeeze(1)
是去掉 a
中指定的维数为 1
的维度。 unsqueeze()
:对数据维度进行扩充,给指定位置加上维数为 1
的维度。用法: torch.unsqueeze(a, N)
,或者 a.unsqueeze(N)
,在 a
中指定位置 N
加上一个维数为 1
的维度。 squeeze 用例程序如下:
a = torch.rand(1,1,3,3)
b = torch.squeeze(a)
c = a.squeeze(1)
print(b.shape)
print(c.shape)
程序输出结果如下:
torch.Size([3, 3]) torch.Size([1, 3, 3]) 。
unsqueeze 用例程序如下:
x = torch.rand(3,3)
y1 = torch.unsqueeze(x, 0)
y2 = x.unsqueeze(0)
print(y1.shape)
print(y2.shape)
程序输出结果如下:
torch.Size([1, 3, 3]) torch.Size([1, 3, 3]) 。
torch.transpose() 只能交换两个维度,而 .permute() 可以自由交换任意位置。函数定义如下:
transpose(dim0, dim1) → Tensor # See torch.transpose()
permute(*dims) → Tensor # dim(int). Returns a view of the original tensor with its dimensions permuted.
在 CNN 模型中,我们经常遇到交换维度的问题,举例:四个维度表示的 tensor: [batch, channel, h, w] ( nchw ),如果想把 channel 放到最后去,形成 [batch, h, w, channel] ( nhwc ),如果使用 torch.transpose() 方法,至少要交换两次(先 1 3 交换再 1 2 交换),而使用 .permute() 方法只需一次操作,更加方便。例子程序如下:
import torch
input = torch.rand(1,3,28,32) # torch.Size([1, 3, 28, 32]
print(b.transpose(1, 3).shape) # torch.Size([1, 32, 28, 3])
print(b.transpose(1, 3).transpose(1, 2).shape) # torch.Size([1, 28, 32, 3])
print(b.permute(0,2,3,1).shape) # torch.Size([1, 28, 28, 3]
张量的索引切片方式和 numpy 、python 多维列表几乎一致,都可以通过索引和切片对部分元素进行修改。切片时支持缺省参数和省略号。实例代码如下:
>>> t = torch.randint(1,10,[3,3])
>>> t
tensor([[8, 2, 9],
[2, 5, 9],
[3, 9, 9]])
>>> t[0] # 第 1 行数据
tensor([8, 2, 9])
>>> t[2][2]
tensor(9)
>>> t[0:3,:] # 第1至第3行,全部列
tensor([[8, 2, 9],
[2, 5, 9],
[3, 9, 9]])
>>> t[0:2,:] # 第1行至第2行
tensor([[8, 2, 9],
[2, 5, 9]])
>>> t[1:,-1] # 第2行至最后行,最后一列
tensor([9, 9])
>>> t[1:,::2] # 第1行至最后行,第0列到最后一列每隔两列取一列
tensor([[2, 9],
[3, 9]])
以上切片方式相对规则,对于不规则的切片提取,可以使用 torch.index_select , torch.take , torch.gather , torch.masked_select .
gather 算子的用法比较难以理解,在翻阅了官方文档和网上资料后,我有了一些自己的理解.
1, gather 是不规则的切片提取算子(Gathers values along an axis specified by dim. 在指定维度上根据索引 index 来选取数据)。函数定义如下:
torch.gather(input, dim, index, *, sparse_grad=False, out=None) → Tensor
参数解释 :
input
(Tensor) – the source tensor. dim
(int) – the axis along which to index. index
(LongTensor) – the indices of elements to gather. gather 算子的注意事项:
input
和索引 index
具有相同数量的维度,即 input.shape = index.shape
d != dim
,index.size(d) <= input.size(d),即对于可以不用索引维数 d
上的全部数据。 out
和 索引 index
具有相同的形状。输入和索引不会相互广播。 对于 3D tensor, output 值的定义如下: gather 的官方定义如下:
out[i][j][k] = input[index[i][j][k]][j][k] # if dim == 0
out[i][j][k] = input[i][index[i][j][k]][k] # if dim == 1
out[i][j][k] = input[i][j][index[i][j][k]] # if dim == 2
通过理解前面的一些定义,相信读者对 gather 算子的用法有了一个基本了解,下面再结合 2D 和 3D tensor 的用例来直观理解算子用法。 (1),对于 2D tensor 的例子:
>>> import torch
>>> a = torch.arange(0, 16).view(4,4)
>>> a
tensor([[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11],
[12, 13, 14, 15]])
>>> index = torch.tensor([[0, 1, 2, 3]]) # 选取对角线元素
>>> torch.gather(a, 0, index)
tensor([[ 0, 5, 10, 15]])
output 值定义如下:
# 按照 index = tensor([[0, 1, 2, 3]])顺序作用在行上索引依次为0,1,2,3
a[0][0] = 0
a[1][1] = 5
a[2][2] = 10
a[3][3] = 15
(2),索引更复杂的 2D tensor 例子:
>>> t = torch.tensor([[1, 2], [3, 4]])
>>> t
tensor([[1, 2],
[3, 4]])
>>> torch.gather(t, 1, torch.tensor([[0, 0], [1, 0]]))
tensor([[ 1, 1],
[ 4, 3]])
output 值的计算如下:
output[i][j] = input[i][index[i][j]] # if dim = 1
output[0][0] = input[0][index[0][0]] = input[0][0] = 1
output[0][1] = input[0][index[0][1]] = input[0][0] = 1
output[1][0] = input[1][index[1][0]] = input[1][1] = 4
output[1][1] = input[1][index[1][1]] = input[1][0] = 3
总结: 可以看到 gather 是通过将索引在指定维度 dim 上的值替换为 index 的值,但是其他维度索引不变的情况下获取 tensor 数据 。直观上可以理解为对矩阵进行重排,比如对每一行(dim=1)的元素进行变换,比如 torch.gather(a, 1, torch.tensor([[1,2,0], [1,2,0]])) 的作用就是对 矩阵 a 每一行的元素,进行 permtute(1,2,0) 操作。 2,理解了 gather 再看 index_select 就很简单,函数作用是返回沿着输入张量的指定维度的指定索引号进行索引的张量子集。函数定义如下:
torch.index_select(input, dim, index, *, out=None) → Tensor
函数返回一个新的张量,它使用数据类型为 LongTensor 的 index 中的条目沿维度 dim 索引输入张量。返回的张量具有与原始张量(输入)相同的维数。 维度尺寸与索引长度相同; 其他尺寸与原始张量中的尺寸相同。实例代码如下:
>>> x = torch.randn(3, 4)
>>> 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 = torch.tensor([0, 2])
>>> torch.index_select(x, 0, indices)
tensor([[ 0.1427, 0.0231, -0.5414, -1.0009],
[-1.1734, -0.6571, 0.7230, -0.6004]])
>>> torch.index_select(x, 1, indices)
tensor([[ 0.1427, -0.5414],
[-0.4664, -0.1228],
[-1.1734, 0.7230]])
可以用 torch.cat 方法和 torch.stack 方法将多个张量合并,也可以用 torch.split 方法把一个张量分割成多个张量。 torch.cat 和 torch.stack 有略微的区别, torch.cat 是连接,不会增加维度,而 torch.stack 是堆叠,会增加一个维度。两者函数定义如下:
# Concatenates the given sequence of seq tensors in the given dimension. All tensors must either have the same shape (except in the concatenating dimension) or be empty.
torch.cat(tensors, dim=0, *, out=None) → Tensor
# Concatenates a sequence of tensors along **a new** dimension. All tensors need to be of the same size.
torch.stack(tensors, dim=0, *, out=None) → Tensor
torch.cat 和 torch.stack 用法实例代码如下:
>>> a = torch.arange(0,9).view(3,3)
>>> b = torch.arange(10,19).view(3,3)
>>> c = torch.arange(20,29).view(3,3)
>>> cat_abc = torch.cat([a,b,c], dim=0)
>>> print(cat_abc.shape)
torch.Size([9, 3])
>>> print(cat_abc)
tensor([[ 0, 1, 2],
[ 3, 4, 5],
[ 6, 7, 8],
[10, 11, 12],
[13, 14, 15],
[16, 17, 18],
[20, 21, 22],
[23, 24, 25],
[26, 27, 28]])
>>> stack_abc = torch.stack([a,b,c], axis=0) # torch中dim和axis参数名可以混用
>>> print(stack_abc.shape)
torch.Size([3, 3, 3])
>>> print(stack_abc)
tensor([[[ 0, 1, 2],
[ 3, 4, 5],
[ 6, 7, 8]],
[[10, 11, 12],
[13, 14, 15],
[16, 17, 18]],
[[20, 21, 22],
[23, 24, 25],
[26, 27, 28]]])
>>> chunk_abc = torch.chunk(cat_abc, 3, dim=0)
>>> chunk_abc
(tensor([[0, 1, 2],
[3, 4, 5],
[6, 7, 8]]),
tensor([[10, 11, 12],
[13, 14, 15],
[16, 17, 18]]),
tensor([[20, 21, 22],
[23, 24, 25],
[26, 27, 28]]))
torch.split() 和 torch.chunk() 可以看作是 torch.cat() 的逆运算。 split() 作用是将张量拆分为多个块,每个块都是原始张量的视图。 split() 函数定义 如下:
"""
Splits the tensor into chunks. Each chunk is a view of the original tensor.
If split_size_or_sections is an integer type, then tensor will be split into equally sized chunks (if possible). Last chunk will be smaller if the tensor size along the given dimension dim is not divisible by split_size.
If split_size_or_sections is a list, then tensor will be split into len(split_size_or_sections) chunks with sizes in dim according to split_size_or_sections.
"""
torch.split(tensor, split_size_or_sections, dim=0)
chunk() 作用是将 tensor 按 dim (行或列)分割成 chunks 个 tensor 块,返回的是一个元组。 chunk() 函数定义如下:
torch.chunk(input, chunks, dim=0) → List of Tensors
"""
Splits a tensor into a specific number of chunks. Each chunk is a view of the input tensor.
Last chunk will be smaller if the tensor size along the given dimension dim is not divisible by chunks.
Parameters:
input (Tensor) – the tensor to split
chunks (int) – number of chunks to return
dim (int) – dimension along which to split the tensor
"""
实例代码如下:
>>> a = torch.arange(10).reshape(5,2)
>>> a
tensor([[0, 1],
[2, 3],
[4, 5],
[6, 7],
[8, 9]])
>>> torch.split(a, 2)
(tensor([[0, 1],
[2, 3]]),
tensor([[4, 5],
[6, 7]]),
tensor([[8, 9]]))
>>> torch.split(a, [1,4])
(tensor([[0, 1]]),
tensor([[2, 3],
[4, 5],
[6, 7],
[8, 9]]))
>>> torch.chunk(a, 2, dim=1)
(tensor([[0],
[2],
[4],
[6],
[8]]),
tensor([[1],
[3],
[5],
[7],
[9]]))
上采样大致被总结成了三个类别:
nearest
)、双线性插值算法( bilinear
)、双三次插值算法( bicubic
)等,这是传统图像处理方法。 Conv2dTranspose2d
等) Unpooling
的方法(简单的补零或者扩充操作) 计算效果:最近邻插值算法 < 双线性插值 < 双三次插值。计算速度:最近邻插值算法 > 双线性插值 > 双三次插值.
Pytorch 老版本有 nn.Upsample 函数,新版本建议用 torch.nn.functional.interpolate ,一个函数可实现定制化需求的上采样或者下采样功能,.
F.interpolate() 函数全称是 torch.nn.functional.interpolate() ,函数定义如下:
def interpolate(input, size=None, scale_factor=None, mode='nearest', align_corners=None, recompute_scale_factor=None): # noqa: F811
# type: (Tensor, Optional[int], Optional[List[float]], str, Optional[bool], Optional[bool]) -> Tensor
pass
参数解释如下:
input
(Tensor):输入张量数据; size
: 输出的尺寸,数据类型为 tuple: ([optional D_out], [optional H_out], W_out),和 scale_factor
二选一。 scale_factor
:在高度、宽度和深度上面的放大倍数。数据类型既可以是 int ——表明高度、宽度、深度都扩大同一倍数;也可是
tuple`——指定高度、宽度、深度等维度的扩大倍数。 mode
: 上采样的方法,包括最近邻( nearest
),线性插值( linear
),双线性插值( bilinear
),三次线性插值( trilinear
),默认是最近邻( nearest
)。 align_corners
: 如果设为 True
,输入图像和输出图像角点的像素将会被对齐(aligned),这只在 mode = linear, bilinear, or trilinear
才有效,默认为 False
。 例子程序如下:
import torch.nn.functional as F
x = torch.rand(1,3,224,224)
y = F.interpolate(x * 2, scale_factor=(2, 2), mode='bilinear').squeeze(0)
print(y.shape) # torch.Size([3, 224, 224)
转置卷积(有时候也称为反卷积,个人觉得这种叫法不是很规范),它是一种特殊的卷积,先 padding 来扩大图像尺寸,紧接着跟正向卷积一样,旋转卷积核 180 度,再进行卷积计算.
最后此篇关于Pytorch基础-张量基本操作的文章就讲到这里了,如果你想了解更多关于Pytorch基础-张量基本操作的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
已关闭。此问题不符合Stack Overflow guidelines 。目前不接受答案。 这个问题似乎与 help center 中定义的范围内的编程无关。 . 已关闭 3 年前。 此帖子于去年编辑
据我所知,在使用 GPU 训练和验证模型时,GPU 内存主要用于加载数据,向前和向后。据我所知,我认为 GPU 内存使用应该相同 1) 训练前,2) 训练后,3) 验证前,4) 验证后。但在我的例子中
我正在尝试在 PyTorch 中将两个复数矩阵相乘,看起来 the torch.matmul functions is not added yet to PyTorch library for com
我正在尝试定义二分类问题的损失函数。但是,目标标签不是硬标签0,1,而是0~1之间的一个 float 。 Pytorch 中的 torch.nn.CrossEntropy 不支持软标签,所以我想自己写
我正在尝试让 PyTorch 与 DataLoader 一起工作,据说这是处理小批量的最简单方法,在某些情况下这是获得最佳性能所必需的。 DataLoader 需要一个数据集作为输入。 大多数关于 D
Pytorch Dataloader 的迭代顺序是否保证相同(在温和条件下)? 例如: dataloader = DataLoader(my_dataset, batch_size=4,
PyTorch 的负对数似然损失,nn.NLLLoss定义为: 因此,如果以单批处理的标准重量计算损失,则损失的公式始终为: -1 * (prediction of model for correct
在PyTorch中,new_ones()与ones()有什么区别。例如, x2.new_ones(3,2, dtype=torch.double) 与 torch.ones(3,2, dtype=to
假设我有一个矩阵 src带形状(5, 3)和一个 bool 矩阵 adj带形状(5, 5)如下, src = tensor([[ 0, 1, 2], [ 3, 4,
我想知道如果不在第 4 行中使用“for”循环,下面的代码是否有更有效的替代方案? import torch n, d = 37700, 7842 k = 4 sample = torch.cat([
我有三个简单的问题。 如果我的自定义损失函数不可微会发生什么? pytorch 会通过错误还是做其他事情? 如果我在我的自定义函数中声明了一个损失变量来表示模型的最终损失,我应该放 requires_
我想知道 PyTorch Parameter 和 Tensor 的区别? 现有answer适用于使用变量的旧 PyTorch? 最佳答案 这就是 Parameter 的全部想法。类(附加)在单个图像中
给定以下张量(这是网络的结果 [注意 grad_fn]): tensor([121., 241., 125., 1., 108., 238., 125., 121., 13., 117., 12
什么是__constants__在 pytorch class Linear(Module):定义于 https://pytorch.org/docs/stable/_modules/torch/nn
我在哪里可以找到pytorch函数conv2d的源代码? 它应该在 torch.nn.functional 中,但我只找到了 _add_docstr 行, 如果我搜索conv2d。我在这里看了: ht
如 documentation 中所述在 PyTorch 中,Conv2d 层使用默认膨胀为 1。这是否意味着如果我想创建一个简单的 conv2d 层,我必须编写 nn.conv2d(in_chann
我阅读了 Pytorch 的源代码,发现它没有实现 convolution_backward 很奇怪。函数,唯一的 convolution_backward_overrideable 函数是直接引发错
我对编码真的很陌生,现在我正在尝试将我的标签变成一种热门编码。我已经完成将 np.array 传输到张量,如下所示 tensor([4., 4., 4., 4., 4., 4., 4., 4., 4.
我正在尝试实现 text classification model使用CNN。据我所知,对于文本数据,我们应该使用一维卷积。我在 pytorch 中看到了一个使用 Conv2d 的示例,但我想知道如何
我有一个多标签分类问题,我正试图用 Pytorch 中的 CNN 解决这个问题。我有 80,000 个训练示例和 7900 个类;每个示例可以同时属于多个类,每个示例的平均类数为 130。 问题是我的
我是一名优秀的程序员,十分优秀!