torch.gather(input, dim, index, *, sparse_grad=False, out=None) → Tensor
- 例如对于一个3D的输入来说,index就是让输入的第几维的索引变成index[i,j,k]
- 例如index=1,那么
ouput[i,j,k[ = input[i,index[i,j,k],k]
sample.cuda(non_blocking=True)
#不阻塞的把一些东西放入cuda中
torch.meshgrid(*tensors)
这个函数,传入一个张量列表
- 例如传入了x:[1,2,3],y[4,5,6,7]。
torch.meshgrid([x,y])
- 那么输出两个张量a,b维度都为 ( d x , d y ) 即 ( 3 , 4 ) (d_x,d_y)即(3,4) (dx,dy)即(3,4),并且( a [ i , j ] , b [ i , j ] ) a[i,j],b[i,j]) a[i,j],b[i,j])这个坐标对就是笛卡尔坐标系中的一个个坐标
- numpy中输出的类似,但是输出张量维度是 d y , d x d_y,d_x dy,dx
torch.stack(tensors, dim=0, *, out=None) → Tensor
这个函数对多个shape相同的张量在某个维度上进行堆叠,采用插入式堆叠
torch.cat(tensors, dim=0, *, out=None) → Tensor
这个函数在某个维度上进行拼接,要求其他维度相同
torch.flatten(input, start_dim=0, end_dim=-1) → Tensor
把输入的数据某些维度给推平,推平后的会拓展到后面的维度
- 如x.shape=(2,3,4)
flatten(x,1,1).shape
就变成了(2,12)
Tensor.masked_fill_(mask, value)
根据mask二值矩阵来进行填充,对True的位置进行填充
torch.chunk(input, chunks, dim=0) → List of Tensors
在某一个维度上拆分为chunks个张量,返回一个列表
关于transpose,permute后面接view前需要先.contiguous()一下
因为view不改变原数据,只是对一些布局进行的设置,所以view需要使用连续的内存,但是transpose,permute后很可能就不是连续的内存占用了,所以要先.contiguous()一下。
关于torch.utils.checkpoint.checkpoint(function, *args, **kwargs)
&esmp;该函数通过反向传播中重新运行一个前向传播过段来实现检查点。可以会导致像RNG state这种持久的状态比没有使用checkpoint更advanced。
- 参数
preserve_rng_state
控制是否存储rng状态,默认情况下,检查点默认处理RNG状态的逻辑,使用checkpoint的传播利用RNG(例如Drop)产生确定的输出而不是之前的不确定的输出。可以设置为False,不让他记录。 - 参数
function
是一个callable的参数,并且知道自己应该如何处理数据 - 参数
args
是一个元组,传给function执行需要的参数
*torch.utils.checkpoint.checkpoint_sequential(functions, segments, input, **kwargs)
和上面的函数实现的是类似的功能
对einsum求和方法的一些总结
- 首先确定哪些维度应该用同样的标识符。看看相乘的时候哪些位置是需要一一对应的,比方说在矩阵的乘法 A i , k B k , j A_{i,k}B_{k,j} Ai,kBk,j中,A的行一定要和B的列相互对应,即对每一个元素 a i , j 和 b m , n 中 a_{i,j}和b_{m,n}中 ai,j和bm,n中,其中做乘法的时候 a a a的列坐标一定要和 b b b的行坐标一一对应,那么就决定了在进行表达式前半部分的描述中,应出现i j , j k这种的字样。表示做乘法的过程中两个维度一定要是一一对应的。如果有些维度不希望它里面的内容交叉运算也需要确定为同样的标识符,比如说Batch。
- 其次确定哪些坐标轴需要被求和,注意求和会消除一个维度。矩阵乘法就是把重复的维度消除掉。
一个例子:假如在Transformer中Q,K,V矩阵 d i m = ( B , H , L , D ) , H 为 多 头 , L 是 序 列 长 度 , D 是 特 征 维 度 dim=(B,H,L,D),H为多头,L是序列长度,D是特征维度 dim=(B,H,L,D),H为多头,L是序列长度,D是特征维度的计算,
第一步:计算QK得到一个每个序列之间的注意力方阵(针对最后两维来说)
- 1.这两个维度里面的不同取值的内容需要隔离,不能交叉计算,所以可以确定B,H要采用相同的标识符。
2.抛开BH这两个无关的要素来看,有L个q向量还有L个v向量,首先我们要做的每一个q向量和v向量对应的点积,那就要求q向量中的每一个要素和k向量中的每一个要素需要一一对应。要求最后一个维度需要采用相同的标识符。 - 其次可以很明显的知道最后一个维度需要进行求和,那就最后的维度中不应该出现这个维度。
- 最终的表达式可以写成:
atten_matrix = einsum('b h i d, b h j d -> b h i j',q,v)
第二步:根据得到的注意力方阵得到
可以知道一个单独的注意力方阵可以
a
i
:
d
i
m
=
(
1
∗
n
)
可
以
表
示
第
i
个
位
置
关
于
各
个
位
置
的
相
关
性
a_i:dim=(1*n)可以表示第i个位置关于各个位置的相关性
ai:dim=(1∗n)可以表示第i个位置关于各个位置的相关性
那么我们首先把这个相关性进行一个softmax取概率操作即atten = softmax(atten,-1)
。
然后我们就要根据这个新的注意力方阵
a
t
t
e
n
:
d
i
m
=
(
B
,
H
,
N
,
N
)
atten:dim = (B,H,N,N)
atten:dim=(B,H,N,N)和
V
:
d
i
m
=
(
B
,
H
,
N
,
C
)
V:dim=(B,H,N,C)
V:dim=(B,H,N,C)来计算最后的输出。
- 首先同理使用相同的标识符隔离开B,H维度,然后可以发现,乘积过程中
a
t
t
e
n
atten
atten阵列的最后一个维度需要和V的表示序列长度的维度(也就是倒数第二个维度)进行相乘,并且需要求和这个维度,那么就可以写
V_{out} = einsum('b h i j ,b h j k -> b h i c ', atten,V)
从而实现了多头注意力机制。是不是很easy呢?