赞
踩
包括经典分类模型、卷积、正则化、激活函数、优化器、损失等
GoogleNet致力于增加网络深度/宽度、减少参数量/计算量:
Inception V1:
Inception V2:
因为MobileNet中使用了深度可分离卷积,首先执行Group为out_channels的深度卷积,使用更高维度的特征图可以捕获更有效的特征,但是依旧可以维持着较少的参数量。在深度可分离卷积的第二层pointwise convolution中,使用1x1卷积来线性聚合输入通道的特征,使用更大的通道数可以捕获更有效的特征。在MobileNet v2中提出逆向的残差结构(Inverted residuals),使用残差链接输入,以提升梯度的传播能力。
池化层主要用于采样,对特征进行降维压缩,加快运算速度:
import numpy as np ''' np.pad函数的使用?np.pad(x, pad_width=((0, 0), (0, 0), (pad, pad), (pad, pad)), mode='constant', constant_values=0.0) img2col的实现? .flatten() batch样本可否并行? 可以,利用 feat_matrix 和 weight_matrix 做dot时broadcast的机制 ''' # 只有batchsize需要循环 class Conv2D(object): def __init__(self, in_channels, out_channels, kernel_size, stride, padding, bias=False): # settings self.in_channels = in_channels self.out_channels = out_channels self.kernel_size = kernel_size self.stride = stride self.padding = padding self.use_bias = bias # 卷积的权重 self.weights = np.random.rand(out_channels, in_channels, kernel_size, kernel_size).astype(np.float) # self.weights = np.ones((out_channels, in_channels, kernel_size, kernel_size)).astype(np.float) if self.use_bias: self.bias = np.random.rand(out_channels).astype(np.float) # self.bias = np.ones(out_channels).astype(np.float) else: self.bias = None def __call__(self, input_feat): b, c, h, w = input_feat.shape # kernel展开 weight_matrix = self._kernel2col() # padding # print(input_feat.shape) padded_input_feat = np.pad(input_feat, pad_width=((0,0), (0,0), (self.padding, self.padding), (self.padding, self.padding)), mode='constant', constant_values=0.0) # # padded_input_feat = input_feat.astype(np.float) # print(padded_input_feat.shape) self.out_h = (h + 2*self.padding - self.kernel_size) // self.stride + 1 self.out_w = (w + 2*self.padding - self.kernel_size) // self.stride + 1 # print(self.out_h, self.out_w) # ''' 对样本进行循环 ''' # out_lis = [] # for batch_no in range(b): # # print(padded_input_feat[batch_no, :, :, :]) # feat_matrix = self._img2col(padded_input_feat[batch_no, :, :, :]) # output_for_one_sample = np.dot(feat_matrix, weight_matrix) # out_h*out_w行, out_channel列 # output_for_one_sample = output_for_one_sample.transpose((1, 0)) # out_channel行, out_h*out_w列 # output_for_one_sample = output_for_one_sample.reshape((self.out_channels, self.out_h, self.out_w)) # output_for_one_sample = np.expand_dims(output_for_one_sample, axis=0) # out_lis.append(output_for_one_sample) # output = np.concatenate(out_lis, axis=0) ''' 不对样本进行循环 ''' feat_matrix_lis = [] for batch_no in range(b): # print(padded_input_feat[batch_no, :, :, :]) feat_matrix_for_one_sample = self._img2col(padded_input_feat[batch_no, :, :, :]) feat_matrix_for_one_sample = np.expand_dims(feat_matrix_for_one_sample, axis=0) feat_matrix_lis.append(feat_matrix_for_one_sample) feat_matrix = np.concatenate(feat_matrix_lis, axis=0) output = np.dot(feat_matrix, weight_matrix) # batchsize, out_h*out_w行, out_channel列 output = output.transpose((0, 2, 1)).reshape((b, self.out_channels, self.out_h, self.out_w)) # output_for_one_sample = np.dot(feat_matrix, weight_matrix) # out_h*out_w行, out_channel列 # output_for_one_sample = output_for_one_sample.transpose((1, 0)) # out_channel行, out_h*out_w列 # output_for_one_sample = output_for_one_sample.reshape((self.out_channels, self.out_h, self.out_w)) # output_for_one_sample = np.expand_dims(output_for_one_sample, axis=0) # out_lis.append(output_for_one_sample) if self.use_bias: temp_bias = np.expand_dims(self.bias, axis=0) temp_bias = np.expand_dims(temp_bias, axis=-1) temp_bias = np.expand_dims(temp_bias, axis=-1) # print(temp_bias.shape, '00000') output += temp_bias # b, out_channels, out_h, out_w 和 out_channels return output def _img2col(self, input_x): c, h, w = input_x.shape # print(c, h, w) feat_mat_height = self.out_h * self.out_w feat_mat_width = self.kernel_size * self.kernel_size * c # print(feat_mat_height) # print(feat_mat_width) feat_matrix = np.empty(shape=(feat_mat_height, feat_mat_width), dtype=np.float) for m in range(self.out_h): for n in range(self.out_w): temp = input_x[:, m*self.stride:m*self.stride+self.kernel_size, n*self.stride:n*self.stride+self.kernel_size].flatten() # channel height width # print(m, n, temp) feat_matrix[m * self.out_w + n, :] = temp return feat_matrix def _kernel2col(self): out_channel, in_channel, kernel_size, kernel_size = self.weights.shape # out_channel, in_channel, kernel_size, kernel_size weight_matrix = np.empty((in_channel*kernel_size*kernel_size, out_channel)).astype(np.float) for m in range(out_channel): for n in range(in_channel): temp = self.weights[m, n, :, :].flatten() weight_matrix[n*self.kernel_size*self.kernel_size:(n+1)*self.kernel_size*self.kernel_size, m] = temp return weight_matrix if __name__=='__main__': b, c, h, w = 2, 1, 4, 4 inputa_ = np.array(range(b*c*h*w)).reshape((b, c, h, w)).astype(np.float) + 1 print(inputa_) print(inputa_.shape) # in_channels, out_channels, kernel_size, stride, padding conv_layer = Conv2D(c, 2, kernel_size=3, stride=1, padding=1, bias=True) out_ = conv_layer(inputa_) print(out_) print(out_.shape)
对于机器学习模型需要的数据,通常需要数据满足独立同分布,可以简化常规机器学习模型的训练、提升机器学习模型的预测能力。所以白化 (whitening) 是一个重要的数据预处理过程;
在深度学习模型中由于层数较多,每一层的的参数更新,都影响了传递到下一层的输入数据分布变化。当浅层的输出数据发生变化时,在深层的输入特征分布会发生显著变化,所以导致高层网络需要不断重新适应新的输入数据分布,即Internal Covariate Shift。Covariate Shift指的是源空间和目标空间的条件概率是一致的,但是其边缘概率不同。对于网络每层的输入与输出的分布不同,并且差异随着网络深度增大而增大,因为是对层间信号分析,成为internal。
在模型训练的过程中,使用可微(可以通过反向传播更新参数)的Normalization,对输入x进行平移和伸缩变换。同时添加再平移参数和再缩放参数,以保证模型的表达能力不因为规范化而下降。
好处:
BN针对单个神经元进行规范化,即针对单个维度定义的纵向规范化,利用网络训练时一个mini-batch的数据来计算该神经元输入的均值和方差。规范化的参数是一个mini-batch的一阶统计量和二阶统计量,要求每一个mini-batch的统计量是整体统计量的近似估计,满足近似同分布。适用于mini-batch比较大、数据分布比较接近的情况。
LN考虑一层所有维度的输入,计算该层的输入平均值和输入方差。LN针对单个训练样本进行归一化,不依赖于其他数据,所以不受mini-batch中数据分布的影响,适用于小mini-batch、动态网络场景和RNN。此外,LN不需要保存mini-batch的均值和方差,节省了额外的空间。
优化了BN在小mini-batch下的劣势,将Channels划分为多个Group,计算每个group内的均值和方差,以进行归一化。GN相当于BN和LN的折中,与Batch-Size无关,且同时处理多维度。
dropout是指在训练过程中随机丢弃部分神经元,以降低模型对数据分布的依赖性,用于解决过拟合。经过交叉验证,dropout率等于0.5时效果最好,当其为0.5时dropout随机生成的网络结构最多。增加了网络表达的稀疏性。
L1/L2可以看作是损失函数的惩罚项,对损失函数中的某些参数进行限制。通过最小化损失函数和正则项,使模型拟合训练数据,并且同时防止模型过分拟合训练数据。
L1正则化是指权值向量w中各个元素的绝对值之和,可以产生稀疏权值矩阵,即产生一个稀疏模型,用于特征选择。一定程度上,也可以防止过拟合。
L2范数,又被称为“岭回归”或者“权值衰减 weight decay”,计算权值向量w中各元素的平方和再开平方根,以解决过拟合问题,提升模型的泛化能力。
CSDN
激活函数的作用主要有:
为什么引入了Relu激活函数:
Sigmoid具有指数函数形状,常被用在二分类任务中约束输出在(0-1)范围内。
t
a
n
h
(
x
)
=
2
∗
s
i
g
m
o
i
d
(
2
x
)
−
1
tanh(x) = 2*sigmoid(2x)-1
tanh(x)=2∗sigmoid(2x)−1
tanh的收敛速度快于sigmoid,输出均值接近于0
ReLU能够解决Sigmoid带来的梯度消失,解决了深层网络训练困难的问题。Relu在大于0的区域里维持梯度为1,不会造成梯度的衰减,从而缓解梯度消失问题。Relu将小于0的区域置为0,通过硬饱和区提供了网络的稀疏表达能力,但是在PReLU论文中指明了稀疏性并非性能提升的必要条件。
ReLU同样存在着问题,偏移现象(输出均值恒大于0)、神经元死亡(硬饱和区权重无法更新)影响了网络的收敛性。
PReLU继承自ReLU和LReLU,为负半区提供可学习的斜率。PReLU的收敛速度更快,因为其输出均值接近于0,使得SGD更接近natural gradient。
给出向量,计算每个向量位置的概率,每个向量位置的概率为(0-1),向量位置概率和为1,常用于多分类任务。
在模型输出与真实值的误差服从高斯分布的假设下,最小化均方差损失函数与极大似然估计本质上是一致的,所以适用于解决回归问题。
MSE通常比MAE更快地收敛,MAE对于outlier更加鲁棒。
调整了损失梯度:
在KL( Kullback–Leibler Divergence)散度来衡量两个分布的相似性,给定分布p和分布q,两者散度公式,其中第一项为分布p的信息熵,第二项为分布p和分布q的交叉熵:
当希望分布尽可能的接近时,就要最小化KL散度,分布p的信息熵仅有p自身有关,所以可以通过实现最小化p、q的交叉熵来实现最小化KL散度。
在二分类任务中,使用Sigmoid函数将输出压缩到(0,1),使用BCE Loss。
在多分类任务中,使用Softmax将每个维度的输出范围限定在(0,1)之间,所有维度的输出和为1,又称softmax loss:
交叉熵对于所有样本‘一视同仁’,无法根据样本分布学习有效的特征。Focal Loss解决了分类问题中类别不平衡、分类难度差异的问题,其使用a作为类别权重,(1-p)^r作为难度权重。在解决二分类任务上,使用参数r来调整对该样本的重视程度,即对于标签为1的样本,预测得分越高,在训练的过程就降低其比重,从而学习到其他样本的信息,随着r的增大,对于样本的惩罚越大;当r为0时,Focal Loss退化为交叉熵损失。同时使用a来调整类别权重比例。
Dice Loss旨在应对语义分割中正负样本强烈不平衡的场景。相比于CE Loss、wCE Loss和Focal Loss的Pixel-level的损失,Dice Loss相当于Class-Level的Loss,把一个类别的所有像素作为一个整体去计算loss,当前像素的loss不仅和当前像素的预测值有关,与其他点的预测也相关,直接使用分割效果评估指标作为Loss去监督网络,并且忽略了大量的背景。
L
I
o
u
=
1
−
I
o
u
L_{Iou} = 1-Iou
LIou=1−Iou
资料
各种优化器的差异出现在第一步和第二步,设计出了不同的优化梯度、一阶动量和二阶动量的方法。
一阶动量: 指数平均梯度
二阶动量: 梯度和
梯度下降算法用来计算函数的最小值点/局部最小值点。对于凸函数,最小值点为梯度为0的位置。当前位置的函数梯度指向函数增长最快的方向,则当前梯度的反方向则指向函数减少最快的方向,朝着梯度下降的方向前进,当梯度趋向于0时,就会找到局部最优点/最优点。学习率Lr则为前进的步长。
问题:
梯度下降根据使用多少数据来计算目标函数的损失,被分为三类:
Batch gradient descent: 由于需要计算整个数据集的梯度以执行一次更新,因此批量梯度下降可能非常慢,并且难以处理对于内存敏感的数据集。 批量梯度下降也不允许在线更新模型,即即时更新新示例。Batch gradient descent保证能够收敛到凸平面的全局最优和非凸平面的局部最优。
Stochastic gradient descent:随机梯度下降对每个训练样本和真值执行一次参数更新。Batch梯度下降对大型数据集执行冗余计算,因为它在每次更新参数之前重新计算相似示例的梯度。 SGD 通过根据单样本依次执行更新来消除这种冗余,速度较快多,也可用于在线学习。SGD 以高方差执行频繁的更新,导致目标函数剧烈波动。
Mini-batch gradient descent
根据数据量,我们在参数更新的准确性和执行更新所需的时间之间进行权衡。
如何在尝试收敛到全局最优值的同时摆脱局部极小值点和鞍点?使用随机梯度下降。
之前的方法对训练集上的所有可能样本的损失值求和得到的损失函数进行梯度下降,当进入局部极小值点或者鞍点时,无法继续优化。在随机梯度下降中,不是对所有损失函数求和来计算函数的梯度,而是通过计算一个随机抽样的样本的损失来执行梯度下降。
批梯度下降:我们使用固定数量的样本采样成一个mini-batch来构建损失函数。选择mini-batch的大小来保证我们有足够的随机性摆脱局部最小值,同时可以利用足够的并行计算力。
在SGD中没有动量的概念:
存在一些问题:
为了抑制SGD的震荡,添加一阶动量(一阶动量是各个时刻梯度方向的指数移动平均值,约等于最近
1
/
(
1
−
β
1
)
1/(1-\beta_{1})
1/(1−β1)个时刻梯度向量和的平均值):
对于与动量方向相同的梯度更新,动量会增加;对于与动量方向相反,动量项会减少。即当下降方向相同时,加速下降;当下降方向不同时,抑制不同方向的下降;从而实现了快速的收敛并抑制震荡。
β
\beta
β通常被设置为0.9,表示在梯度下降的过程中依赖的方向主要来自于之前的累积方向,可以在相关方向加速SGD,抑制震荡,从而加速收敛。
NAG是基于SGD-M的改进,用于解决momentum梯度下降过猛的情况,即避免前进的太快,同时提升灵敏度。(即小球需要在上坡前减速)。SGDM没有直接改变计算梯度,而是使用先前的梯度动量影响当前的决策。在当前的位置的下降方向主要由累计动量决定,先按照该累阶动量前进一步,按照新位置的梯度方向与历史累计的动量结合,计算当前位置的累积动量。NAG的改变则是让之前的累积动量直接影响当前计算的梯度。
在AdaGrad中累积全部历史梯度的平方和,对学习率进行了单调递减处理;而Adadelta累积固定窗口大小w的下降梯度的平方和,不是低效地存储 w 个先前的平方梯度,而是将梯度总和递归地定义为所有过去的平方梯度的衰减平均值,使用指数移动平均来计算二阶累积动量。
RMSprop是Adadelta的特例,
Adam利用梯度的一阶矩估计和二阶矩估计动态调整每个参数的学习率。
对于梯度使用一阶动量来约束,对于学习率使用二阶动量来约束:
在Adam中引入了偏置较正:
在梯度更新的过程中引入一阶动量和二阶动量:
Warm-up指在早期epoch中使用较小的学习率,在之后增加到初始学习率,并执行正常的学习率衰减。
作用:
当模型训练时出现损失为NaN时或者过拟合时,可以尝试Warm-up。
每过固定的迭代次数,学习率乘以一个固定的衰减倍数,实现学习率的均匀降低。
l
r
=
l
r
∗
α
e
p
c
o
h
/
/
l
r
−
s
t
e
p
lr = lr * \alpha^{epcoh//lr-step}
lr=lr∗αepcoh//lr−step
lr-step为学习率衰减间隔,使用Step衰减在一定迭代次数内维持学习率的稳定。
l
r
=
l
r
∗
(
1
−
i
t
e
r
/
t
o
t
a
l
−
i
t
e
r
)
p
o
w
e
r
lr = lr * (1-iter/total-iter)^{power}
lr=lr∗(1−iter/total−iter)power
power控制着学习率曲线的形状,当power<1,曲线为凸,学习率下降先慢再快;当power>1,曲线为凹,学习率下降先快再慢;当power=1时,为线性曲线。
poly学习率衰减被广泛地应用在分割任务中
梯度爆炸原因:
梯度消失原因:
python中的
∗
*
∗
∗
∗
**
∗∗都代表了什么意思?
∗
a
r
g
s
*args
∗args、
∗
∗
k
w
a
r
g
s
**kwargs
∗∗kwargs 都表示函数形参、表示未知数目的函数参数传递。
∗
a
r
g
s
*args
∗args为位置参数,表示任意多个无名参数,以tuple的形式传递。
∗
∗
k
w
a
r
g
s
**kwargs
∗∗kwargs为关键词参数,表示一一对应的参数名,以dict的形式传递。在同时使用
∗
*
∗、
∗
∗
**
∗∗时,
∗
a
r
g
s
*args
∗args必须写在
∗
∗
k
w
a
r
g
s
**kwargs
∗∗kwargs 之前。
∗
*
∗和
∗
∗
**
∗∗还可以表示实参,为定长函数传入参数,对元组和字典进行解引用。(额外的,
∗
*
∗表示函数乘法,
∗
∗
**
∗∗表示乘方;
∗
*
∗还可以被用来解耦序列。)
深拷贝、浅拷贝、赋值引用
赋值引用,默认浅拷贝传递对象的引用,相当于添加一个标签,并没有产生新对象;跟随原始对象的改变而改变;
浅拷贝,拷贝父对象(顶层引用),当顶层引用中的引用改变时,浅拷贝对象元素改变;为原始对象添加顶层时,元素不改变;
深拷贝,完全拷贝父对象及其子对象,直到所有的引用都是不可修改引用,原始对象的改变不会造成深拷贝里任何子元素的改变。
is和==的区别
is 比较的是两个实例对象是否完全相同,是否为同一个对象,占用的内存地址是否相同;== 比较的是两个对象的内容是否相等,即内存地址可以不一样,内容一样就可以了,其不严格限定对象的数据类型(1.0与1);IsEqual实现判断元素类型是否相同,再判断具体内容是否一致。
list和tuple的区别
list可变,tuple不可变,所以tuple没有insert、pop、append方法,不可变的tuple相对于代码来说更安全可靠;tuple可以转成列表,但是不可以转成字典;对于tuple中只有一个元素,必须要加‘,’,才会被识别为元组,否则为单元素。
python怎么使用c扩展
在python应用中,为了对性能进行优化(对于一些和系统相关的模块或者对性能要求很高的模块,通常会把这个模块C化),需要使用python的C扩展,将一些关键代码用C进行重写以提高性能,有两种常用方式:
可以直接使用Python C API,在C文件中加载Python.h头文件,使用PyObject作为C语言中返回的python对象;把写好的C语言代码编译成.so文件,就可以使用调包的方式在python中使用。
cython可以使用python的语法,来调用c程序的接口,并且可以同时方便的地用c函数和python函数。
utf-8、unicode的区别
生成器和迭代器
迭代器是一个可以遍历容器的对象,比如dataloader就是一个迭代器,其中封装了继承自DataSet的可迭代对象(定义了返回一个迭代器的__iter__或者支持下标索引的__getitem__)。
迭代器:实现了__iter__和__next__方法的对象都称为迭代器,其中__iter__()返回一个特殊的迭代器,next() 方法会返回下一个迭代对象。其并不将所有结果存入内存中,而是在调用时迭代产生。**优点:**节省内存,使用了一种不需要索引的检索方式。**缺点:**只能单向索引,不能回退。
生成器:本质上是一种迭代器,但是只能迭代一次;以函数的形式遍历,却不返回值,使用了yeild函数来处理值,类似于生成一个返回迭代器的函数,只能用于迭代操作。生成器最佳应用场景是:你不想同一时间将所有计算出来的大量结果集分配到内存当中,特别是结果集里还包含循环。
装饰器
修饰器修改其他函数的功能的函数。在MMLab系列的代码中被用来置换backbone、head等部分。使用@来封装函数,从而改变函数中功能。
匿名函数 lambda
def biliner(x, y): x_1 = int(x) x_2 = x_1 + 1 y_1 = int(y) y_2 = y_1 + 1 Q_11 = temp[x_1][y_1] Q_21 = temp[x_2][y_1] Q_12 = temp[x_1][y_2] Q_22 = temp[x_2][y_2] # 对x方向进行插值 R_1 = (x_2-x)/(x_2-x_1) * Q_11 + (x-x_1)/(x_2-x_1) * Q_21 R_2 = (x_2-x)/(x_2-x_1) * Q_12 + (x-x_1)/(x_2-x_1) * Q_22 # 对y方向进行插值 Q = (y_2-y)/(y_2-y_1) * R_1 + (y-y_1)/(y_2-y_1) * R_2 return Q
对于输入特征为CxHxW,卷积核为3x3,输出通道为Cout
卷积层参数量为:Cx3x3xCout
卷积层计算量为:CoutxHxWx(3x3xC+1)
现有的分布式计算方法主要有:
torch.nn.DataParallel(DP)-----> 单机多卡
torch.nn.parallel.DistributedDataParallel (DDP)-----> 单机多卡、多机多卡
DP的代码部署相对简单,它使用一个进程来计算模型参数,然后在前向传递过程中将数据和参数分发到每个GPU,然后每个GPU计算各自的梯度,然后在主GPU中汇总平均进行反向传播更新参数,然后再把模型的参数由主GPU传播给其他的GPU。即在反向传播的过程中需要算出每张卡上的Loss在主卡上更新。在基于DP训练的过程传递的是模型的参数,所以速度较慢。
DistributedDataParallel为多进程,其每个进程都有独立的优化器,在每张卡上独立执行自己的更新过程,但是梯度通过通信协议传递到每个进程,所有执行的内容是相同的;反向传播过程在每张卡上计算Loss分别进行更新。DDP后端backend,默认为“nncl”,为多个机器之间交互数据的协议。
syrcBN提供了跨卡batch normalization通信协议,在前向传播的过程中拿到所有GPU全局的样本和方差,在后向传播时得到相应的全局梯度。
统计学中用来衡量二分类模型精确度的一种指标。
p
r
e
c
i
s
i
o
n
=
T
P
/
(
T
P
+
F
P
)
,
r
e
c
a
l
l
=
T
P
/
(
T
P
+
F
N
)
precision = TP / (TP+FP), recall = TP/(TP+FN)
precision=TP/(TP+FP),recall=TP/(TP+FN)
推断正确的像素点个数/全部像素点数量的比值,
P
i
j
P_{ij}
Pij表示类i元素被推断为类j。
对于每一个像素类别计算其PA,最后对所有类别计算平均值。
对每个类别计算其交集与并集之比,最后根据类别计算平均。相当于
TP/(TP+FN+FP)
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。