3.0 常见operators算子
1.1 卷积相关
1)卷积 2)反卷积 (只能做到近似恢复,无法完全恢复原图像)
参考:https://blog.csdn.net/qq_27261889/article/details/86304061
1.2 线性变换相关
1)Linear
2)矩阵相乘类:【mm:二维矩阵相乘;bmm:三维矩阵相乘;matmul:多维矩阵相乘, 只要两个矩阵能够broadcast即可。】
1.3 标准化、归一化相关
区别在于:计算 均值&方差 所使用得数据范围不同。
1)Batch_Norm,常用于cv领域;2)Layer_Norm,常用于nlp的RNN中;3)Instance_Norm;4)Group_Norm。
5)Switchable_Norm,结合BN和LN:E = a1*BN + a2*LN,δ = b1*BN + b2*LN。
6)RMS_Norm,root mean square均方根,认为LN成功关键是 缩放不变性而不是 平移不变性,所以计算过程:省去了 减均值 操作,只保留了除 方差 操作。
BN对batch_size比较敏感,BN对批次中所有图片的同一层通道做归一化,需要处理的数据能大体代表所有数据整体上的特征分布。因此,batch_size 较大(>16)时,BN才能起到较好的效果。
归一化参数(u, δ)在训练和推理时候的联系:
训练时,每个batch得到的参数 按比例累加 得到最终 推理时模型适用的参数。即 移动指数平均法:ui = (1 - β)*ui-1 + β*ui ,β为超参数。
LN分别在CV和NLP中的区别(从哪个维度做归一化,取决于传给LN的参数):
CV中:
LN:input = [N, C, H, W] ,以 [C, H, W] 为单位,在 N 的维度上进行归一化。
NLP中:
在NLP领域,句子中每个词的词向量特征长度相同,但是每个句子中单词的个数不定即 sequence 长度不定。
LN:input = [N, sentence_length, embedding_dim] ,对每个词向量分别进行归一化。
def test_LN():
# 选择哪个范围内的数据做Norm,取决于定义LN的时候传入的参数
# 传入三维参数,则所有的后三个维度[1, C,H,W]做一次Norm;传入一维参数,则所有的最后一个维度[1, 1, embedding]做一次Norm
input_cv = torch.randn(4, 3, 2, 2)
ln_cv = nn.LayerNorm([3, 2, 2]) # 用 三个维度 定义LN,对 input_cv 计算 3 次 mean和var。
res_cv = ln_cv(input_cv)
print('cv__res shape: ', res_cv.shape)
print('cv__LN weight shape: ', ln_cv.weight.shape) # [3, 2, 2]
batch, seq_length, embedding = 20, 5, 10
input_nlp = torch.randn(batch, seq_length, embedding)
ln_nlp = nn.LayerNorm(embedding) # 用 一个维度 定义LN,对 input_nlp 计算 batch*seq_length 次 mean和var。
res_nlp = ln_nlp(input_nlp)
print("nlp__res shape: ", res_nlp.shape)
print("nlp__LN weight shape: ", ln_nlp.weight.shape) # [10]
1.4 Pooling池化相关
一般在卷积后面会紧跟池化层,池化作用:1)增大感受野,2)减小特征图尺寸但保留重要特征信息,3)抑制噪声,4)降低信息冗余减少计算量, 5)防止过拟合
MaxPooling:更多保留图像纹理信息。
AveragePooling:更多保留图像背景等整体信息。
GlobalAveragePooling:用于模型末尾部分。例如在图像分类中,将中间过程的 [N, C, H, W ] 转换到最终的 [N, 1000] ,最开始用全连接层进行降维但是参数量太大。于是改进操作:将 feature_map 用GAP池化到 [N, C, 1, 1 ],然后 reshape [N, C],最后再用全连接到 [N, 1000]。 改进后:依然可以得到 [N, 1000] 的 Output,且极大减小了计算过程的参数量。( 两种操作,网络结构不同,计算过程不同,模型训练过程中的参数也不同,但是 各自的结构+各自的参数 最终效果是相同。 )
1.5 Dropout相关
1.5.1 目的
降低神经网络过拟合,正则化技术的一种,减少神经元对部分上层神经元的依赖。
1.5.2 训练&推理过程
a. 训练过程:
1)前向传播的时候,每层神经元随机失活一定比例,然后在反向传播的时候对没有失活的神经元的权重进行更新,
2)恢复被失活的神经元
3)重复上述 1、2步骤
b. 推理过程:
在训练过程随机失活部分神经元是为了降低过拟合,在推理的时候,使用的是整个模型结构,不会对神经元失活处理。
1.5.2 如何平衡训练过程和推理时的差异
差异性来源于,训练的时候会开启dropout,导致输出结果值偏小,训练时关闭dropout启用全部神经元,导致输出结果偏大。假设dropout_rate = p,有两种解决方案:一是在推理时对推理结果值乘以(1 - p),二是在训练时对没有失活的神经元权重乘以(1 / p)。
1.6 transpose/permute、reshape/view
pytorchh中,将n维张量在显存中一个一个按序存放的,即:将n维张量打平成一维数组的形式存放。tensor的属性 stride 表示了如何根据索引从这一串数据中找到想要的元素。如:t = torch.tensor(np.arange(24).reshape(2, 3, 4)),张量 t 的stride属性:[12, 4, 1],表示 如果索引为 (x,y,z),则从张量 t 的起始存储位置偏移 12*x + 4*y + z 个单位长度。定义:如果张量的 shape 和stride 符合上述性质,则称数据是连续的。
'''
transpose/permute 和 reshape/view 都可以修改shape,区别:
transpose只能换两个轴但可以tensor对象直接调用;permute可以换多个轴但只能通过 Tensor.permute() 的方式来调用。
view必须对连续的数据进行view,view从定义开始就只是视图,没有重新开辟内存的操作。
reshape如果修改非连续的tensor会重新生成一份新数据,但是对连数据的操作不会复制生成新数据。
transpose和reshape:
reshape/view 操作后张量的stride会根据变换后的shape计算得到,而transpose操作后的stride是根据换轴操作计算得到的,不再保持连续。
注:transpose操作只是让stride和shape失去了数据连续的性质,并不会重新复制一份新数据。
'''
import numpy as np
import torch
t = torch.tensor(np.arange(24).reshape(2, 3, 4))
print('t stride: ', t.stride())
view = t.view(6, 4)
print('view stride: ', view.stride())
reshape = t.reshape(6, 4)
print('reshape stride: ', reshape.stride())
trans = t.transpose(0, 1)
print('trans shape: ', trans.shape)
print('trans stride: ', trans.stride())
# 验证 transpose 是否生成了新的张量
print(t.data_ptr())
print(trans.data_ptr())
1.7 其它算子
'''
concat/stack/expand/flatten ,区别:
concat: 在既有轴上进行拼接;
stack: 新建轴,并拼接
expand: 对 在某个维度上的长度为1 的地方扩展到 目标 shape
'''
'''
split/slice,区别:
split:根据指定的维度进行拆分,如果 split(tensor, 2, dim=0):表对第0维每两个组合拆分出来。
如果 split(tensor, [1,2,2], dim=0): 表对第0维按照 1 2 2 个组合拆分出来。
slice:同 python list 的切片
'''
'''
reduce规约类算子:按照指定维度做 reduce
torch.
mean:(input_tensor: tensor, dim: int, keepdim: bool)
var:
sum:
max:
'''
'''
embedding:
用于将整数标识符映射到密集向量表示。
这在自然语言处理(NLP)和推荐系统等任务中非常有用。
简单来说,它是一个查找表,将输入的整数索引(例如单词或项的索引)映射到一个向量空间。
'''