初始化
深度神经网络模型中,以单个神经元为例,该层()的输入个数为n,其输出为:
这里忽略了常数项b。为了让z不会过大或者过小,思路是让w与n有关,且n越大,w应该越小才好。这样能够保证z不会过大。一种方法是在初始化w时,令其方差为。激活函数是tanh,相应的python代码为:
parameters['W'] = np.random.randn(n[l], n[l - 1]) * np.sqrt(1 / n[l - 1])
激活函数是ReLU,权重w的初始化一般令其方差为
正则化
L2正则化
也可以表示为:
称为Frobenius范数,一个矩阵的Frobenius范数就是计算所有元素平方和再开方
python代码例子,在计算J成本函数时加上正则化成本,假设有w1,w2,w3:
L2_regularization_cost = lambd * (np.sum(np.square(W1)) + np.sum(np.square(W2)) + np.sum(np.square(W3))) / (2 * m)
在反向传播时,使用以下公式计算梯度
python代码:
dW3 = (1 / m) * np.dot(dZ3, A2.T) + ((lambd * W3) / m)
Dropout正则化
Dropout的原理就是每次迭代过程中随机将其中的一些节点失效。当我们关闭一些节点时,我们实际上修改了我们的模型。背后的想法是,在每次迭代时,我们都会训练一个只使用一部分神经元的不同模型。随着迭代次数的增加,我们的模型的节点会对其他特定节点的激活变得不那么敏感,因为其他节点可能在任何时候会失效。
正向传播python代码:
D1 = np.random.rand(A1.shape[0], A1.shape[1]) # 步骤1:初始化矩阵D1 = np.random.rand(..., ...)
D1 = D1 < keep_prob # 步骤2:将D1的值转换为0或1(使用keep_prob作为阈值)
A1 = A1 * D1 # 步骤3:舍弃A1的一些节点(将它的值变为0或False)
A1 = A1 / keep_prob # 步骤4:缩放未舍弃的节点(不为0)的值
除以 keep_prob
。这样做的话我们通过缩放就在计算成本的时候仍然具有相同的期望值。
假设第l层有50个神经元,经过dropout后,有10个神经元停止工作,这样只有40神经元有作用。那么得到的al只相当于原来的80%。缩放后,能够尽可能保持al的期望值相比之前没有大的变化。
后向传播:
使用正向传播存储在缓存中的掩码D1,python代码
dA1 = dA1 * D1 # 步骤1:使用正向传播期间相同的节点,舍弃那些关闭的节点(因为任何数乘以0或者False都为0或者False)
dA1 = dA1 / keep_prob # 步骤2:缩放未舍弃的节点(不为0)的值
梯度检查
接下来,计算梯度的反向传播值,最后计算误差:
当difference小于时,我们通常认为我们计算的结果是正确的。
python代码
def gradient_check(x,theta,epsilon=1e-7):
"""
参数:
x - 一个实值输入
theta - 参数,也是一个实数
epsilon - 使用公式(3)计算输入的微小偏移以计算近似梯度
返回:
近似梯度和后向传播梯度之间的差异
"""
#使用公式的计算gradapprox。
thetaplus = theta + epsilon
thetaminus = theta - epsilon
J_plus = forward_propagation(x, thetaplus)
J_minus = forward_propagation(x, thetaminus)
gradapprox = (J_plus - J_minus) / (2 * epsilon)
#检查gradapprox是否足够接近backward_propagation()的输出
grad = backward_propagation(x, theta)
numerator = np.linalg.norm(grad - gradapprox)
denominator = np.linalg.norm(grad) + np.linalg.norm(gradapprox)
difference = numerator / denominator
if difference < 1e-7:
print("梯度检查:梯度正常!")
else:
print("梯度检查:梯度超出阈值!")
return difference