概述
dropout正则化(Dropout Regularization)
为了防止过拟合的问题,除了使用L2正则化,还有一个非常实用的正则化方法--“Dropout Regularization(随机失活或者翻译为丢弃)”,dropout正则化是Srivastava在2014年提出来的Dropout: A Simple Way to Prevent Neural Networks from Overfitting。Dropout的思想其实非常简单粗暴:对于网络的每一层,随机的丢弃一些单元。如下图所示(图片来自Srivastava的dropout论文):
假设你在训练a图这样的神经网络,它存在过拟合,这就是dropout所要处理的,dropout会遍历网络的每一层,并设置消除神经网络节点的概率。假设网路中的每一层,每个节点都是以抛硬币的方式设置概率,每个节点得以保留和消除的概率都是0.5,设置完节点概率,我们会消除一些节点,然后删除掉从节点进出的连线,最后得到一个节点更少,规模更小的网络,让后用backprop方法进行训练。这是网络节点精简后的一个样本,对于其他样本,我们照旧以抛硬币的方式设置概率,保留一类节点集合,删除其他类型的节点集合。对于每个样本我们将采用一个精简后的神经网络训练它。
关于为什么dropout能够减轻过拟合,ng给出了两个比较直观的解释:
- 正是因为在每一层随机的丢弃了一些单元,所以相当于训练出来的网络要比正常的网络小的多,在一定程度上解释了避免过拟合的问题。
- 如下图所示的一个简单单层网络,因为每一个特征都有可能被丢弃,所以整个网络不会偏向于某一个特征(把某特征的权重的值赋的很大),会把每一个特征的权重都赋的很小,这就有点类似于L2正则化了,能够起到减轻过拟合的作用。
这个方法看起来有点疯狂,但是他确实是有效的。下面开始从技术实现方面来看下dropout正则项,这里最重要的一个参数就是 keep_prob,它表示保留某个隐藏单元的概率(同样,1−keep_prob则为丢弃概率),比如某一层的 keep_prob=0.8,则意味着某一层随机的保留80%的神经单元(也即有20%的单元被丢弃)。通常实现dropout regularization的技术称为 inverted dropout (反向随机失活),我们用一个3层的网络来举例说明。编码中会有很多涉及到3的地方,我只举例说明如何在某一层中实施dropout ,假设对于第三层,则inverted dropout的具体实现为:
1. d3 = np.random.rand(a3.shape[0],a3.shape[1]) < keep_prob
2. a3 = np.multiply(a3,d3)
3. a3 = a3 / keep_prob
4. z4 = np.dot(w4,a3) + b4
关于上面的步骤的一些说明:
- 第1步,首先要定义向量d, 表示一个3层的dropout向量,大小和a3一样的概率矩阵,其实这一样代码,因为每次都是随机数,所以只能做到近似保留 keep_prob 这么多,比如, keep_prob=0.8可能d3只有79%的1,也就意味着只有79%的单元被保留,但是如果隐藏层单元数量越多,越能够逼近80%。
- 第2步,第3层中获取激活函数,这里我们叫它 ,含有要计算的激活函数,a3等于a3与d3点乘,即保留keep_prob的单元,剩下的1−keep_prob 单元被失活,也就是过滤掉所有等于0的元素。
- 第3步,因为有1−keep_prob 的单元失活了,这样a3的期望值也就减少了1−keep_prob, 所以我们要用a3/keep_prob,这样可以确保a3的期望值不变。这就是inverted dropout。
这就是inverted dropout的内容。下面用两个动态图来演示下dropout的过程(素材来自ng的deep learning课):
接下来主要来代码实现,假设我们的网络激活函数使用relu,输出层使用sigmoid,我们只要在前面一步步手写神经网络的基础上把前向传播(forward propagation)和后向传播(backward propagation)稍作修改就可以了:
前向传播(forward propagation)
def forward_propagation_with_dropout(X, parameters, keep_prob = 0.8):
"""
X -- input dataset, of shape (input size, number of examples)
parameters -- python dictionary containing your parameters "W1", "b1", "W2", "b2",...,"WL", "bL"
W -- weight matrix of shape (size of current layer, size of previous layer)
b -- bias vector of shape (size of current layer,1)
keep_prob: probability of keeping a neuron active during drop-out, scalar
:return:
AL: the output of the last Layer(y_predict)
caches: list, every element is a tuple:(W,b,z,A_pre)
"""
np.random.seed(1) #random seed
L = len(parameters) // 2 #number of layer
A = X
caches = [(None,None,None,X,None)] #用于存储每一层的,w,b,z,A,D第0层w,b,z用none代替
# calculate from 1 to L-1 layer
for l in range(1, L):
A_pre = A
W = parameters["W" + str(l)]
b = parameters["b" + str(l)]
z = np.dot(W, A_pre) + b # 计算z = wx + b
A = relu(z) # relu activation function
D = np.random.rand(A.shape[0], A.shape[1]) #initialize matrix D
D = (D < keep_prob) #convert entries of D to 0 or 1 (using keep_prob as the threshold)
A = np.multiply(A, D) #shut down some neurons of A
A = A / keep_prob #scale the value of neurons that haven't been shut down
caches.append((W, b, z, A,D))
# calculate Lth layer
WL = parameters["W" + str(L)]
bL = parameters["b" + str(L)]
zL = np.dot(WL, A) + bL
AL = sigmoid(zL)
caches.append((WL, bL, zL, A))
return AL, caches
反向传播(backward propagation)
def backward_propagation_with_dropout(AL, Y, caches, keep_prob = 0.8):
"""
Implement the backward propagation presented in figure 2.
Arguments:
X -- input dataset, of shape (input size, number of examples)
Y -- true "label" vector (containing 0 if cat, 1 if non-cat)
caches -- caches output from forward_propagation(),(W,b,z,pre_A)
keep_prob: probability of keeping a neuron active during drop-out, scalar
Returns:
gradients -- A dictionary with the gradients with respect to dW,db
"""
m = Y.shape[1]
L = len(caches) - 1
# print("L: " + str(L))
# calculate the Lth layer gradients
prev_AL = caches[L - 1][3]
dzL = 1. / m * (AL - Y)
dWL = np.dot(dzL, prev_AL.T)
dbL = np.sum(dzL, axis=1, keepdims=True)
gradients = {"dW" + str(L): dWL, "db" + str(L): dbL}
# calculate from L-1 to 1 layer gradients
for l in reversed(range(1, L)): # L-1,L-2,...,1
post_W = caches[l + 1][0] # 要用后一层的W
dz = dzL # 用后一层的dz
dal = np.dot(post_W.T, dz)
Dl = caches[l][4] #当前层的D
dal = np.multiply(dal, Dl) #Apply mask Dl to shut down the same neurons as during the forward propagation
dal = dal / keep_prob #Scale the value of neurons that haven't been shut down
Al = caches[l][3] #当前层的A
dzl = np.multiply(dal, relu_backward(Al))#也可以用dzl=np.multiply(dal, np.int64(Al > 0))来实现
prev_A = caches[l-1][3] # 前一层的A
dWl = np.dot(dzl, prev_A.T)
dbl = np.sum(dzl, axis=1, keepdims=True)
gradients["dW" + str(l)] = dWl
gradients["db" + str(l)] = dbl
dzL = dzl # 更新dz
return gradients
关于dropout有几点是要非常注意的:
- 只有在训练网络的时候使用dropout,在测试集上(预测的时候)不要使用dropout,也就意味着我们在预测(分类)的时候,用训练好的参数做前向传播的时候,要把dropout关掉!
- dropout是一个正则化技术
参考了如下内容,在这里衷心感谢!
- 吴恩达(Ng)老师的深度学习课程。
- https://blog.csdn.net/u012328159/article/details/80210363
最后
以上就是欢呼人生为你收集整理的『DL笔记』dropout正则化(Dropout Regularization)的全部内容,希望文章能够帮你解决『DL笔记』dropout正则化(Dropout Regularization)所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复