1 . Tensor 支持与 numpy.ndarray 类似的索引操作,如无特殊说明,索引出来的结果与原 tensor 共享内存,也即修改一个,另一个也会跟着修改。

Input:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import torch as t

a = t.randn(3, 4)
print(a)

print(a[0]) # 第 0 行,下标从 0 开始

print(a[:, 0]) # 第 0 列

print(a[0, 2]) # 第 0 行第 2 个元素,等价于 a[0][2]

print(a[0][-1]) # 第 0 行最后一个元素

print(a[:2]) # 前两行

print(a[:2, 0:2]) # 前两行,第 0,1 列

print(a[0:1, :2]) # 第 0 行,前两列
print(a[0, :2]) # 注意两者的区别,形状不同

Output:

Input:

1
2
3
4
5
6
7
8
9
10
11
import torch as t

a = t.randn(3, 4)

# None 类似于 np.newaxis,为 a 新增了一个轴
# 等价于 a.view(1, a.shape[0], a.shape[1])
print(a[None].shape) # 等价于 a[None,:,:]

print(a[:, None, :].shape)

print(a[:, None, :, None, None].shape)

Output:

2 . 常用的选择函数。

函数 功能
index_select(input, dim, index) 在指定维度 dim 上选取,比如选取某些行、某些列
masked_select(input, mask) 使用 ByteTensor 进行选取
non_zero(input) 非 0 元素的下标
gather(input, dim, index) 根据 index,在 dim 维度上选取数据,输出的 size 与 index 一样

Input:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import torch as t

a = t.randn(3, 4)
print(a)

print(a > 1) # 返回一个 ByteTensor

# 等价于 a.masked_select(a>1)
print(a[a > 1]) # 选择结果与原 tensor 不共享内存空间

print(a[t.LongTensor([0, 1])]) # 第 0 行和第 1 行
```

Output:

![](http://wx3.sinaimg.cn/mw690/79225320gy1fx9osqbau0j214807lgmc.jpg)

`gather` 是一个比较复杂的操作,对于一个 2 维的 tensor,输出的每个元素如下:

out[i][j] = input[index[i][j]][j] # dim=0
out[i][j] = input[i][index[i][j]] # dim=1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
三维 tensor 的 `gather` 操作同理。  

`gather(input, dim, index)` 中的 dim 表示的就是第几维度,在二维的例子中,如果 dim=0,那么它表示的就是你接下来的操作是对第一维度进行的,也就是行;如果 dim=1,那么它表示的就是你接下来的操作是对第二个维度进行的,也就是列。index 的大小和 input 的大小是一样的,它表示的是你所选择的维度上的操作。特别注意,index 必须是 LongTensor 类型。

Input:

```python
import torch as t

a = t.arange(0, 16).view(4, 4)
print(a)

# 选取对角线上的元素
index = t.LongTensor([[0, 1, 2, 3]])
print(a.gather(0, index))

# 选取反对角线上的元素
index = t.LongTensor([[3, 2, 1, 0]]).t()
print(a.gather(1, index))

# 选取两个对角线上的元素
index = t.LongTensor([[0, 1, 2, 3], [3, 2, 1, 0]]).t()
b = a.gather(1, index)
print(b)

Output:

gather 相对应的逆操作是 scatter_gather 把数据从 input 中按照 index 取出,而 scatter_ 是把取出的数据再放回去(inplace 操作)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# 把两个对角线的元素放回到指定位置
c = t.zeros(4, 4)
b = b.float() # 将 b 转换成 FloatTensor
c.scatter_(1, index, b)
print(c)
```

对 tensor 的任何索引操作仍是一个 tensor,想要获取标准的 tensor 对象数值,需要调用 `tensor.item()`,这个方法只对包含一个元素的 tensor 适用。

3 . PyTorch 目前已支持绝大多数 numpy 的高级索引,高级索引可以看成是普通索引操作的扩展,但是高级索引操作的结果一般不和原始的 Tensor 共享内存。

Input:

```python
import torch as t

x = t.arange(0, 27).view(3, 3, 3)

print(x)

print(x[[1, 2], [1, 2], [2, 0]]) # x[1, 1, 2] 和 x[2, 2, 0]

print(x[[2, 1, 0], [0], [1]]) # x[2, 0, 1],x[1, 0, 1], x[0, 0, 1]

print(x[[0, 2], ...]) # x[0] 和 x[2]

Output:

4 . Tensor 有不同的数据类型,每种类型分别对应有 CPU 和GPU 版本(HalfTensor 除外),默认的 tensor 都是 FloatTensor,可通过 torch.set_default_tensor_type 来修改默认 tensor 类型,如果默认类型为 GPU tensor,则所有操作都在 GPU 上进行,HalftTensor 是专门为 GPU 版本设计的,同样的元素个数,显存占用只有 FloatTensor 的一半,所以可以极大缓解 GPU 显存不足的问题,但由于其数值大小和精度有限,所以可能出现溢出等问题。

各数据类型之间可以相互转换,type(new_type) 是通用的做法,同时还有 floatlonghalf 等快捷方法,CPU tensor 和 GPU tensor 之间的相互转换通过 tensor.cudatensor.cpu 方法来实现,此外还可以使用 tensor.to(device)

Tensor 还有一个 new 方法,用法与 t.Tensor 一样,会调用该 tensor 对应类型的构造函数,生成与当前 tensor 类型一致的 tensor,torch.*_like(tensor) 可以生成和 tensor 拥有同样属性(类型、形状、CPU?GPU)的新 tensor。tensor.new_*(new_shape) 新建一个不同形状的 tensor。


笔记来源:《pytorch-book》