torch
transpose
torch.transpose(input, dim0, dim1) → Tensor
对input
上的第dim0
维和第dim1
维进行转置
假设
>>>input.shape=(128,32,12,64)
torch.transpose(input,1,2).shape=(128,12,32,64)
masked_select
torch.masked_select(input, mask, *, out=None) → Tensor
根据mask上的bool取值,对input上的值进行取舍,若mask位置上取值为1那么input对应位置上的值保留下来,最终输出一个一维数据
参数
- input:input tensor
- mask:这个tensor值应当为bool类型(就是0、1或者True、False这种二取值类型)
>>>a = torch.Tensor([[4,5,7], [3,9,8],[2,3,4]])
>>>b = torch.Tensor([[1,1,0], [0,0,1],[1,0,1]]).type(torch.ByteTensor)
>>>c = torch.masked_select(a,b)
>>>print(c)
tensor([4.,5.8.2.,4.])
max
torch.Tensor
scatter
scatter_(dim, index, src, reduce=None) → Tensor
官网地址
pytorch中torch.Tensor.scatter用法
将src
中所有相应的值根据index
中的坐标值来写入到目标值中。
参数
- dim:表示在某个维度上进行操作,可以是
0,1,2.....
- index:索引数组,
tensor
,数据类型为整数 - src:根据里面的值进行填充,src可以为一个数值或者
tensor
- reduce
For a 3-D tensor, self is updated as:
self[index[i][j][k]][j][k] = src[i][j][k] # if dim == 0
self[i][index[i][j][k]][k] = src[i][j][k] # if dim == 1
self[i][j][index[i][j][k]] = src[i][j][k] # if dim == 2
示例
import torch
>>>input = torch.randn(2, 4)
>>>print(input)
tensor([[-0.6482, 1.1430, 0.4962, 0.9425],
[ 0.0092, -0.2958, 0.2240, -0.6358]])
>>>output = torch.zeros(2, 5)
>>>index = torch.tensor([[3, 1, 2, 0], [1, 2, 0, 3]])
>>>output = output.scatter(1, index, input)
>>>print(output)
tensor([[ 0.9425, 1.1430, 0.4962, -0.6482, 0.0000],
[ 0.2240, 0.0092, -0.2958, -0.6358, 0.0000]])
示例中是对dim=1
进行修改,故其修改是
- output[0][index[0][0]] = src[0][0] ,即output[0][3] = -0.6482
- output[0][index[0][1]] = src[0][1] ,即output[0][1] = 1.1430
- output[0][index[0][2]] = src[0][2] ,即output[0][2] = 0.4962
- output[0][index[0][3]] = src[0][3] ,即output[0][0] = 0.9425
- output[1][index[1][0]] = src[1][0] ,即output[1][1] = 0.0092
- ⋯ \cdots ⋯
- 最终得到上面示例的值
unsqueeze
torch.unsqueeze(input, dim) → Tensor
相当于在指定的dim上增加一维
>>>a = torch.Tensor([1,2,3,4,5,6])
>>>b = a.unsqueeze(0)
>>>b #b.shape=(1,6)
tensor([[1., 2., 3., 4., 5., 6.]])
>>>b = a.unsqueeze(1)
>>>b #b.shape(6,1)
tensor([[1.],
[2.],
[3.],
[4.],
[5.],
[6.]])
squeeze
这个与unsqueeze相反,去掉相应维数
repeat
对某个tensor在相应的维度上进行重复
>>> import torch
>>>
>>> a = torch.randn(33, 55)
>>> a.size()
torch.Size([33, 55])
>>> 这个(1,1)相当于在第0维和第1维分别重复1次,即不变
>>> a.repeat(1, 1).size()
torch.Size([33, 55])
>>> 这个(2,1)相当于在第0维和第1维分别重复2次和1次,即行的维度变为2倍
>>> a.repeat(2,1).size()
torch.Size([66, 55])
>>>
>>> a.repeat(1,2).size()
torch.Size([33, 110])
>>> 若是repeat参数的个数超过tensor的维数,则会添加一维
>>> a.repeat(1,1,2).size()
torch.Size([1, 33, 110])
参数的长度必须长于tensor的维度个数,否则报错
>>>a.repeat(1).size()
>RuntimeError: Number of dimensions of repeat dims can not be smaller than number of dimensions of tensor
masked_fill
masked_fill(mask, value)
参数
- mask:必须是一个二值型,
0
0
0或
1
1
1,
True
或False
等,mask.size(0)必须与tensor的size(0)相等 - value: 根据mask中的True对应的位置填充为这个值
>>> a=torch.tensor([1,0,2,3])
>>> a.masked_fill(mask = torch.ByteTensor([1,1,0,0]), value=torch.tensor(-1e9))
>>> tensor([-1.0000e+09, -1.0000e+09, 2.0000e+00, 3.0000e+00])
contiguous
contiguous(memory_format=torch.contiguous_format) → Tensor
view只能用在contiguous的variable上。
如果在view之前用了transpose,permute等,需要用contiguous来返回一个contiguous copy
有些tensor并不是占用一整块内存,而是由不同的数据块组成,而tensor的view()操作依赖于内存是整块的,这需要执行contiguous()这个函数,把tensor变成在内存中连续分布的形式。
判断是否contiguous用torch.Tensor.is_contiguous()
expand
torch.nn
torch.nn.utils.rnn.pad_packed_sequence
rnn.pad_packed_sequence(sequence, batch_first=False, padding_value=0.0, total_length=None)
Pytorch中的RNN之pack_padded_sequence()和pad_packed_sequence()
为什么有pad和pack操作?
举例,假如这个batch有5个sample
如果不用pack和pad操作会有一个问题,什么问题呢?
上图中,句子"Yes"只有一个单词,但是padding了多余的符号来填充,这回导致LSTM对它的表示通过了很多无用的字符,这样得到的句子表示会有误差,更直观的如下图:
正确的做法应该是什么样呢?
在上面这个例子,我们想要得到的表示仅仅是LSTM过完单词"Yes"之后的表示,通过了多个无用的得到的表示:如下图
torch.nn.utils.rnn.pack_padded_sequence()
这里的pack,理解成压紧比较好。将一个填充过的变长序列压紧。(填充时候,会有冗余,所以压紧)
pack之后,原来填充的占位符被删掉。
输入的形状可以是 T × B × ∗ T \times B \times * T×B×∗.
- T是最长序列长度
- B是batch size
- * 表示任意维度
- batch_first=True,那么相应的input size就是 B × T × ∗ B \times T \times * B×T×∗.
参数说明
- input(Variable):变长序列 被填充后的 batch
- lengths(list[int]) Variable中每个序列的长度,保证序列的长度是从大到小排列
- batch_first(bool,optional):若是 T r u e True True,input的形状应该是 B × T × s i z e B \times T \times size B×T×size
返回值:
一个PackedSequence对象
示例
import torch
import torch.nn as nn
from torch.nn.utils.rnn import pack_padded_sequence,pad_packed_sequence
tensor_in = torch.FloatTensor([[2,3,4],[1,0,0]]).resize_(2,3,1)
#表示
>>>seq_lengths=[3,1]
>>>pack = pack_padded_sequence(tensor_in,seq_lengths,batch_first=True)
>>>pack
PackedSequence(data=tensor([[2.],
[1.],
[3.],
[4.]]), batch_sizes=tensor([2, 1, 1]), sorted_indices=None, unsorted_indices=None)
torch.nn.utils.rnn.pad_packed_sequence()
填充packed_sequence
上面提到的函数的功能是将一个填充后的变长序列压紧。 这个操作和pack_padded_sequence()是相反的。把压紧的序列再填充回来。填充时会初始化为0。
返回的Varaible的值的size是 T × B × ∗ , T×B×*, T×B×∗, T T T 是最长序列的长度,B 是 batch_size,如果 batch_first= T r u e True True,那么返回值是 B × T × ∗ B×T×* B×T×∗。
Batch中的元素将会以它们长度的逆序排列。
参数说明:
- sequence (PackedSequence) – 将要被填充的 batch
- batch_first (bool, optional) – 如果为 T r u e True True,返回的数据的格式为 B × T × ∗ B×T×* B×T×∗。
nn.LSTM
CLASStorch.nn.LSTM(*args, **kwargs)
参数
-
input_size – 输入特征维数:(特征向量的长度,如
2048
) -
hidden_size – 隐层状态的维数:(每个
LSTM
单元或者时间步的输出的ht的维度,单元内部有权重与偏差计算) -
num_layers –
RNN
层的个数:(在竖直方向堆叠的多个相同个数单元的层数),默认为1 -
bias – 隐层状态是否带
bias
,默认为true
-
batch_first – 是否输入输出的第一维为
batchsize
-
dropout – 是否在除最后一个
RNN
层外的RNN
层后面加dropout层,默认False
-
bidirectional – 是否是双向
RNN
,默认为false
输入
Inputs: input, (h_0, c_0)
-
input:
(seq_len, batch, input_size)
时间步数或序列长度,batch数,输入特征维度。如果设置了batch_first
,则batch
为第一维,即( batch,seq_len, input_size)
-
(h_0,c_0):设置下图中输入到第一层的隐藏状态的参数
输出
Outputs: output, (h_n, c_n)
-
output:
(seq_len, batch, hidden_size * num_directions)
包含每一个时刻的输出特征,如果设置了batch_first
,则batch
为第一维,( batch,seq_len, input_size)
-
(h_n, c_n) :隐层状态各个层的最后一个时步的隐含状态,所以与序列长度
seq_len
是没有关系的
全面理解LSTM网络及输入,输出,hidden_size等参数
nn.ZeroPad2d
官方地址
torch.nn.ZeroPad2d(padding: Union[T, Tuple[T, T, T, T]])
用于卷积网络中的填充,使用0进行填充
参数
padding
:若是int
类型,则在上下左右全部填充padding
个,若是一个四元组,则分别表示(left,right,top,bottom)
>>> m = nn.ZeroPad2d(2)
>>> input = torch.randn(1, 1, 3, 3)
>>> input
tensor([[[[-0.1678, -0.4418, 1.9466],
[ 0.9604, -0.4219, -0.5241],
[-0.9162, -0.5436, -0.6446]]]])
>>> m(input)
tensor([[[[ 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000],
[ 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000],
[ 0.0000, 0.0000, -0.1678, -0.4418, 1.9466, 0.0000, 0.0000],
[ 0.0000, 0.0000, 0.9604, -0.4219, -0.5241, 0.0000, 0.0000],
[ 0.0000, 0.0000, -0.9162, -0.5436, -0.6446, 0.0000, 0.0000],
[ 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000],
[ 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000]]]])
>>> # using different paddings for different sides
>>> m = nn.ZeroPad2d((1, 1, 2, 0))
>>> m(input)
tensor([[[[ 0.0000, 0.0000, 0.0000, 0.0000, 0.0000],
[ 0.0000, 0.0000, 0.0000, 0.0000, 0.0000],
[ 0.0000, -0.1678, -0.4418, 1.9466, 0.0000],
[ 0.0000, 0.9604, -0.4219, -0.5241, 0.0000],
[ 0.0000, -0.9162, -0.5436, -0.6446, 0.0000]]]])
nn.NLLLoss
参考文章
Pytorch详解NLLLoss和CrossEntropyLoss
输入
m
m
m张图片,每张图片有
n
n
n个类别。
例如,三张图片三个分类,如下
In [1]: input = torch.randn((3,3))
Out[1]:
tensor([[-0.4020, -0.5205, 0.7815],
[ 0.0290, -1.6085, 0.0041],
[-1.3974, -0.5234, -1.1656]])
假设图片的三个类别分别是🐱、🐕、🐖(猫、狗、猪)
上面的输出就是机器认为每张图应该被分为的类别是什么,对上面使用Softmax
查看概率分布
In [2]: sm = nn.Softmax(dim=1)
In [3]: sm(input)
Out[3]:
tensor([[0.1940, 0.1723, 0.6336],
[0.4609, 0.0896, 0.4495],
[0.2147, 0.5146, 0.2707]])
对softmax
取对数,这是为了防止概率值太小造成溢出
In [4]: torch.log(sm(input))
Out[4]:
tensor([[-1.6398, -1.7583, -0.4563],
[-0.7747, -2.4122, -0.7996],
[-1.5384, -0.6644, -1.3066]])
概率值越小,取对数后越小,概率值越大,取对数之后越接近0
NLLLoss
的结果就是把上面的输出与Label
对应的那个值拿出来,再去掉负号,再求均值。
假设我们现在Target
是[0,2,1]
(第一张图片是猫,第二张是猪,第三张是狗)。
第一行取第
0
0
0个元素,第二行取第
2
2
2个,第三行取第
1
1
1个,去掉负号,结果是:
[
1.6398
,
0.7996
,
0.6644
]
[1.6398,0.7996,0.6644]
[1.6398,0.7996,0.6644]。再求个均值,结果是:
1.0346
1.0346
1.0346
In [5]: loss = nn.NLLLoss()
In [6]: target = torch.tensor([0,2,1])
In [7]: loss(input,target)
Out[7]: tensor(0.3071)
In [8]: loss(torch.log(sm(input)),target)
Out[8]: tensor(1.0346)
nn.LogSoftmax
上一节中的torch.log(sm(input))
就等价于这个函数
nn.CrossEntropyLoss
它就相当于nn.LogSoftmax+nn.NLLLoss