Tips
var.item()
- 如果张量 var 中只有一个元素,使用该方法取出该元素
属性
tensor.size
- shapes
tensor的拼接
tensor的拼接操作经常用到、特地将其整理如下
- cat - dim=all
- stack - dim=new_dim
- dstack - dim=2
- hstack - dim=1
- vstack- dim=0
cat
功能:将给定的 tensors 在给定的维度上拼接
注意:除了拼接的维度其余维度大小应一致
参数:
tensors - 多个tensor组成的元组(序列)
dim - 想要拼接的维度
Test
1 | x = torch.randn(2, 3, 3) |
Output
1 | x.size() = torch.Size([2, 3, 3]) |
stack
功能:将给定的 tensors 在新的维度进行拼接
注意:每一个 tensor 的大小都应一致
参数:tensors
- dim - 所要插入的维度,最小为 0 ,最大为输入数据的维度值
Test
1 | a = torch.zeros(3, 4) |
Output
1 | c.size() = torch.Size([2, 3, 4]) |
dstack
功能:将给定的 tensors 沿着深度(depth)方向 (dim=2) 叠加
注意:其余维度大小一致
参数:tensors
Test 1
a = torch.randn(2, 3, 4, 2) |
Output 1
c.size() = torch.Size([2, 3, 8, 2]) |
Test 2 如果输入数据小于三维呢?
a = torch.randn(2) |
Output 2 会扩增维度
c.size() = torch.Size([1, 2, 2]) |
hstack
功能:将给定的 tensors 沿着水平(horizontal)方向 (dim=1) 叠加
注意:其余维度大小一致
参数:tensors
Test
1 | a = torch.randn(2, 3, 4) |
Output
c.size() = torch.Size([2, 7, 4]) |
vstack
功能:将给定的 tensors 沿着竖直(vertical)方向 (dim=0) 叠加
注意:其余维度大小一致
参数:tensors
Test
1 | a = torch.randn(2, 3, 4) |
Output
c.size() = torch.Size([5, 3, 4]) |
tensor的切分
数据的预处理以及数据集的构建会经常使用到tensor的切分操作,现整理如下:
- chunk
- split
- numpy中的切片(slice)操作
- unbind
chunk
功能:输入数据与想要切分的块数 chunks ,将数据尽可能 (如果数据个数与块数能整除的话) 平均的切分为 chunks 块
注意:没有进行数据的拷贝
参数
- input - tensor
- chunks - 切分的块数
- dim - int - 切分的维度
Test
x = torch.randn(33, 16) |
Output
1 | # 尽可能平均的切分为了四块 |
split
功能:
- 可以输入整型数据 size 表示将数据尽可能 按照大小 size 进行分割,自行计算分割的块数
- 可以输入序列数据 list 将数据分割为 len(list) 块,每块的大小对应于list中的值
注意:没有对输入数据进行拷贝
参数:
- input - tensor
- split_size_or_sections - int or (ints) - 详见功能介绍
- dim - int - 切分的维度
Test 1 输入整型数据
a = torch.arange(10).view(2, 5) |
Output 1
1 | a = tensor([[0, 1, 2, 3, 4], |
Test 2 输入为整型序列
a = torch.arange(10).view(2, 5) |
Output
1 | a = tensor([[0, 1, 2, 3, 4], |
slice
功能:torch支持numpy中对数据的切片操作
Test
x = torch.randn(3, 2) |
Output
1 | x = tensor([[-0.2893, -1.1715], |
unbind
功能:删除tensor的一个维度,返回各个子块组成的 tuple
参数:
- input - tensor
- dim - int - 想要删除的维度
Test
a = torch.randint(-5, 5, (2, 3, 4)) |
Output
1 | # a |
tensor的索引
根据索引获取数据中特定位置的值
- gather
- index_select
- masked_select
- narrow
- nonzero
- where
- take
gather
功能:沿指定的维度收集值
注意:除了指定的维度、其余维度都遍历一遍
参数:
- input - tensor
- dim - int - 收集的维度
- index - LongTensor - 要收集的元素的索引,维度数和 input 一致
- sparse_grad - bool - 如果 input 为 sparse tensor 那么设定为 true
$$
out[i][j][k] = input[\ index[i][j][k]\ ][j][k]\ with\ dim=0 \
out[i][j][k] = input[i][\ index[i][j][k]\ ][k]\ with\ dim=1 \
out[i][j][k] = input[i][j][\ index[i][j][k]\ ]\ with\ dim=2 \
$$
**Test 1 **
1 | a = torch.arange(6).view(2, 3) |
Output
1 | a = tensor([[0, 1, 2], |
index_select
功能:在指定的维度上根据索引取值
注意:进行了拷贝
参数:
- input - tensor
- dim - int
- index - LongTensor - 一维 tensor 指定索引
Test
a = torch.arange(6).view(2, 3) |
Output
1 | a = tensor([[0, 1, 2], |
masked_select
功能:根据 booltensor 进行索引,将索引到的值以一维 tensor 的形式返回
注意:boolTensor 支持广播
参数:
- input - tensor
- mask - boolTensor
Test 1
1 | a = torch.arange(12).view(3, 4) |
Output
1 | a = tensor([[False, False, False, False], |
Test 2 广播测试
a = torch.arange(12).view(3, 4) |
Output 2
1 | a = tensor([[ 0, 1, 2, 3], |
narrow
功能:类似于 numpy中的切片操作,针对某一维度进行索引,(连续)取值
参数:
input - tensor
dim - int - 所要操作的维度
start - int - 开始的索引
length - 保留长度
简单理解:
torch.narrow(input, dim=1, start, length) = input[:,start:start+length,:,:...] |
Test
x = torch.arange(12).view(2, 2, 3) |
Output
1 | x = tensor([[[ 0, 1, 2], |
nonzero
功能:找出给定 tensor 中非零元素的索引
注意:as_tuple 参数与输出样式有关
- True - 返回一个二维 tensor,每一行表示一个非零值的索引
- False - 返回 n 个大小为 z 的一维 tensor - n 表示输入数据的维度 - z表示非零元素的个数
参数
- input - tensor
- as_tuple - default (False)
Test 1
a = torch.randint(0, 2, (3, 3)) |
Output 1
1 | a = tensor([[0, 0, 0], |
扩展:
结合 torch 中类似 numpy 的 bool索引,我们可以构造条件索引的形式
- 通过条件语句生成 bool tensor
- True为1,False为0,即nonzero会找到所有Ture值的索引(条件筛选出来的元素)
Test 2 利用条件语句实现逆 nonzero
a = torch.randint(0, 2, (3, 3)) |
Output 2
1 | # a |
Test 3 如何合并多个条件呢
利用集合操作即可
根据原子条件分别生成多个 booltensor
根据需求采用交或并等的方式合并多个 booltensor
1 | a = torch.randint(0, 8, (2, 5)) # 1 < a < 4: a = 2 or 3 |
Output 3
1 | # a |
where
功能 1:根据 booltensor 返回目标值的索引
简单理解
torch.where(condition) == torch.nonzero(condition, as_tuple=True) |
参数:condition - booltensor
Test 1
x = torch.randn(3, 2) |
Output
1 | x = tensor([[ 1.2484, -0.4649], |
功能 2:根据 booltensor 定位到目标值,选择性进行 值替换
注意:支持广播
简单理解
$$
out_i =
\begin{cases}
x_i \ &if\ condition_i \
y_i \ &otherwise
\end{cases}
$$
参数:
- condition - booltensor
- x - tensor
- y - tensor
Test 2 大于0不变 小于等于0改变
1 | x = torch.randn(3, 2) |
Output
1 | x = tensor([[-1.9040, -0.3891], |
take
功能:根据一维索引进行取值,返回一维tensor (内部将输入的tensor铺平后进行索引)
功能:根据一维索引进行取值,返回一维tensor (内部将输入的tensor铺平后进行索引)
注意:进行了数据拷贝
参数
- input
- indices - 一维索引
Test
x = torch.arange(6).view(2, 3) |
Output
1 | x = tensor([[0, 1, 2], |
tensor 的填充
ref:https://pytorch.org/docs/stable/tensors.html#torch.Tensor.scatter_
scatter
scatter 是撒播的意思,希望能先入为主的理解一下这个函数的功能,就是往目标矩阵撒一些数值进去,往哪撒(dim?index?)与撒什么值(src)将由我们输入的参数决定
官方一些的说明:将 src 中数据根据 index 中的索引按照 dim 的方向填进 input 中
tensor.scatter(dim, index, src) |
从数学公式上来看执行流程:
self[index[i][j][k]][j][k] = src[i][j][k] # if dim == 0 |
1、原始的对应填充方式 self[i][j][k] = src[i][j][k]
将被 index
索引张量影响,因此才能体现出撒(scatter)的感觉
2、dim 决定影响的维度,其余维度不变
3、我们对 index 进行遍历时,dim 影响的那一个维度会由 index 内部的值决定,其余维度索引保持一致
希望以上三点能加深对下面例子的理解
为了保证索引对应 index 索引张量的维度应与 src 张量的维度一致,但是 shape 可以不一致
让我们以一个二维的情形为例:
从 index 出发,因为 dim = 1,所以我们能够得知目标填充索引为 (0, 3)
可以认为先从 (i = 0, j=0) 找到了 index 和 value 的值(3, 9),又因为 dim = 1,因此 index 的值将作用于列索引所以得到最终索引为 (i=0, j=3)
其实再次看这句话
我们对 index 进行遍历时,dim 影响的那一个维度会由 index 内部的值决定,其余维度索引保持一致
那我们看 value 中的 5,它的行索引是 1,因此它必然撒到 dest 中的第一行(dim=1),但是撒在第几列将由 index 决定,index 说撒在第 4 列,done!
Example: Lable 转 one-hot
Label 通常是一维的 shape=(N,)
,而模型的 output 通常是 softmax 之后的二维结果shape=(N, dim)
,因此将 label 变为 二维的 one-hot 形式非常常见
首先指定 dim = 1,是因为我们填充值要修改的维度索引是列向维度,行索引值将与 Label 的索引值对应,即通过控制列向维度保证哪个地方值是 1
1 | # ref: https://www.cnblogs.com/dogecheng/p/11938009.html |
label 即是我们要索引的列,我们需要完成对 label 的遍历
1、第一个值为 6
告知第一行第 6
列
1、第二个值为 0
告知第二行第 0
列
..
tensor的变换
- movedim
- reshape
- view
- squeeze
- unsqueeze
- t
- transpose
movedim
功能:进行(多个)维度的移动
注意:其余维度保持原有不变,并按照原顺序依次落位
参数
- input
- source - int or tuple - 维度移动前的索引
- destination - int or tuple - 维度移动后的索引
Test 1 其余维度保持原有不变,并按照原顺序依次落位
a = torch.randn(2, 3, 4, 5) |
Output
a = torch.Size([2, 3, 4, 5]) |
Test 2 输入为tuple
a = torch.randn(2, 3, 4, 5) |
Output
a = torch.Size([2, 3, 4, 5]) |
reshape
功能:改变输入 tensor 的维度分配
注意:应默认该函数不会对源数据进行拷贝
参数
- input
- shape - int of tuple - 其余维度确定的情况下,可以使用 -1 用于推算某一维度的大小
Test
a = torch.randn(32, 16) |
Output
a = torch.Size([32, 16]) |
view
squeeze
功能:默认移除 tensor 中维度大小为 1 的维度 - 给定 dim 后只考虑给定的 dim 是否移除
注意:输入 dim 必须为整型,不能为整型序列
参数:
- input - tensor
- dim - default(None) - int
Test
1 | a = torch.randn(2, 1, 2, 1, 1, 3) |
Output
1 | torch.Size([2, 1, 2, 1, 1, 3]) |
unsqueeze
功能:与 squeeze 方法想反,增加一个大小为1的维度
参数
- input - tensor
- dim - int
Test
x = torch.tensor([1, 2, 3, 4]) |
Output
x = torch.Size([4]) |
t
功能:对二维张量进行转置处理
注意:对于一维 tensor 返回的是它本身
参数:input - tensro
Test
1 | a = torch.randn(2) |
Output
1 | a = torch.Size([2]) |
transpose
功能:将给定的两个维度进行交换
参数:
- input - tensor
- dim0 - int
- dim1 - int
Test
a = torch.randn(2, 3, 4, 5) |
Output
a = torch.Size([2, 3, 4, 5]) |
与Numpy转换
Tips:Torch Tensor 与 Numpy array 共享底层的内存空间
Tips:所有在 CPU 上的 tensor (except CharTensor)都可与 Numpy array 互转换
to numpy
:tensor.numpy()
to tensor
:torch.from_numpy(array)
与设备交互
1 | if torch.cuda.is_available(): |
自动求导
定义变量时设定:torch.tensor([1, 2, 3], requires_grad=True)
后续更改设定:tensor.requires_grad_(True)
终止某Tensor在计算图中的追踪回溯:tensor.detach()
终止整个流程的反向传播:with torch.no_grad():
相关属性
.grad_fn
- 代表引用了那个 Function 创建了该 Tensor,自定义则值为 None
.grad
- 在该 Tensor 上的所有梯度将被累加进该属性