lecture3中主要讲了如何构建一个ML/DL任务,主要包括:选择问题、获得数据、设计模型、训练模型、测试模型、部署以及维护。然后coursera中的课程主要讲实际的应用例如调参、正则化等,以及几个DL常用优化算法。
深度学习的超参数一般包括:网络的深度(层数) L L L、隐层的大小 n [ l ] n^{[l]} n[l]、学习率 α \alpha α、迭代次数、以及正则化参数等。
一般把数据集分为:训练集(Train set)、开发/验证集(Dev set)、测试集(Test set)。
在大数据量下一般开发集和测试集所占比例都很小;
调参过程是在训练集上训练出模型,然后再开发集上看效果来调整具体的超参数。
高偏差(high bias)/ 欠拟合(underfitting):
更大、更深的网络;
增加迭代次数 / 尝试其他的优化算法;
尝试其他的神经网络模型
高方差(high variance)/ 过拟合(overfitting):
更多的数据;
采取正则化手段;
尝试其他的神经网络模型
初始参数中心化:
随机初始化参数用来打破对称性,确保不同的隐藏单元可以学习不同的东西;合适的参数初始化可以在一定程度上缓解梯度消失/梯度爆炸(vanishing / exploding gradients)的问题。
随机初始化不要过大,保证随机生成的参数满足0为均值, 2 n [ l − 1 ] \sqrt{2\over n^{[l-1]}} n[l−1]2或 1 n [ l − 1 ] \sqrt{1\over n^{[l-1]}} n[l−1]1为标准差的正态分布。
He初始化适用于ReLu,即初始化需要乘上 2 n [ l − 1 ] \sqrt{2\over n^{[l-1]}} n[l−1]2;
Xavier初始化的乘数为 1 n [ l − 1 ] \sqrt{1\over n^{[l-1]}} n[l−1]1
输入特征标准化(Normalizing inputs)
让输入特征满足0为均值,1为标准差的正态分布;
这样做可以加速训练,让代价函数优化起来更简单快速。
但值得注意的是,训练集和测试集需要做同样的归一化操作,即用同样的方法调整测试集,而不是在训练集和测试集上分别进行归一化处理。
dW3 = 1./n * np.dot(dZ3, A2.T) + lambd/n * W3
这样在后面更新权重时需要多减去一项,即 W [ l ] = W [ l ] − α ⋅ d W [ l ] = W [ l ] − α ⋅ ( d W o [ l ] + λ n W [ l ] ) = ( 1 − α λ n ) W [ l ] − α ⋅ d W o [ l ] \begin{aligned}W^{[l]}&=W^{[l]}-\alpha \cdot dW^{[l]}\\ &=W^{[l]}-\alpha \cdot (dW^{[l]}_o+{\lambda\over n}W^{[l]})\\ &=(1-{\alpha\lambda\over n})W^{[l]}-\alpha \cdot dW^{[l]}_o\end{aligned} W[l]=W[l]−α⋅dW[l]=W[l]−α⋅(dWo[l]+nλW[l])=(1−nαλ)W[l]−α⋅dWo[l]
其中 d W o [ l ] dW^{[l]}_o dWo[l]表示没有正则化之前的导数。因此,由于 ( 1 − α λ n ) < 1 (1-{\alpha\lambda\over n})<1 (1−nαλ)<1,所以每次迭代更新参数都会让原本的参数衰减之后再进行更新。
# 在前向传播时:
D1 = np.random.randn(A1.shape[0], A1.shape[1]) < keep_prob # 设置一个阈值
A1 = A1 * D1 # 超过阈值的位置就dropout
A1 = A1 / keep_prob # 使得期望值不变
# 在反向传播是需要进行相同的操作:
dA1 = np.dot(W2.T, dZ2) * D1 / keep_prob # 这里的D1要一样
为什么能起到正则化的作用?
使用dropout可以使得下一层的神经元不能完全依赖上层的某一个神经元(因为他们可以随机失活),这样减少了对单个神经元的信任程度,所以只能分散权重(shrink weight),这样就起到了类似L2正则化的作用。
缺点:
使用dropout后由于每次迭代都会随机地移除一些神经元,导致代价函数并不是每次迭代后都会下降,尽管总的趋势还是随着迭代次数增加而下降,所以不能根据这样的调试工具来直接地评价优化算法的性能以及学习率的调整。
可以让每层的留存率都一样,或者不一样。一般说来,神经元数量多的隐层可以设置一个较小的留存率。
批量梯度下降(GD)就是将所有的训练样本全都进行一次计算,得到参数的梯度来更新一次;而随机梯度下降(SGD)则是只随机的选取其中一个样本进行计算,来更新一次参数;小批量梯度下降则是介于两者中间,每次迭代只随机选取部分(大于1且小于n)的样本来进行计算,然后更新一次参数,这样将所有的样本全部用完一次就称为一次epoch。
具体做法是:
1、先随机打乱训练集,得到一个重排的训练集
2、给定mini_batch_size,第一次迭代选取前mini_batch_size的样本来更新参数,第二次迭代选择第mini_batch_size到2*mini_batch_size的样本来更新参数,这样依次直到最后一个batch中样本数量小于或等于mini_batch_size,这样就完成了一次epoch
优点:
1、与GD相比,这样可以不用一次就遍历所有的数据,特别是在数据量很大时,可以加速优化过程
2、与SGD相比,可以利用向量化并行加速,也在一定程度上减少了随机性
V t = β V t − 1 + ( 1 − β ) θ t , 0 < β < 1 V_t=\beta V_{t-1}+(1-\beta)\theta_t,\ \ 0<\beta<1 Vt=βVt−1+(1−β)θt, 0<β<1
其中 V t V_t Vt表示到 t t t为止的累积量, θ t \theta_t θt为 t t t时刻的量。上式表示到当前时刻的累积量是由之前的累积量与当前量加权求和得到。将上式展开得到: V t = ( 1 − β ) θ t + β [ ( 1 − β ) θ t − 1 + β V t − 2 ] = ( 1 − β ) θ t + β ( 1 − β ) θ t − 1 + β 2 [ ( 1 − β ) θ t − 2 + β V t − 3 ] = ( 1 − β ) θ t + β ( 1 − β ) θ t − 1 + β 2 ( 1 − β ) θ t − 2 + ⋯ + β t − 1 ( 1 − β ) θ 1 + β t V 0 \begin{aligned} V_t&=(1-\beta)\theta_t+\beta[ (1-\beta)\theta_{t-1}+\beta V_{t-2}]\\ &=(1-\beta)\theta_t+\beta(1-\beta)\theta_{t-1}+\beta^2[(1-\beta)\theta_{t-2}+\beta V_{t-3}]\\ &=(1-\beta)\theta_t+\beta(1-\beta)\theta_{t-1}+\beta^2(1-\beta)\theta_{t-2}+\cdots+\beta^{t-1} (1-\beta)\theta_{1}+\beta^tV_0\\ \end{aligned} Vt=(1−β)θt+β[(1−β)θt−1+βVt−2]=(1−β)θt+β(1−β)θt−1+β2[(1−β)θt−2+βVt−3]=(1−β)θt+β(1−β)θt−1+β2(1−β)θt−2+⋯+βt−1(1−β)θ1+βtV0由于 V 0 = 0 V_0=0 V0=0,所以 V t V_t Vt就是前面 t t t次量的一个加权平均,而且这个权重是指数衰减的,离当前时间越近权重越大。
偏差修正(bias correction)解决冷启动问题
一般来说, β ⩾ 0.9 \beta\geqslant0.9 β⩾0.9,如果取 β = 0.9 \beta=0.9 β=0.9,由于 V 0 = 0 V_0=0 V0=0,所以 V 1 = 0.1 θ 1 , V 2 = 0.09 θ 1 + 0.1 θ 2 , … V_1=0.1\theta_1, V_2=0.09\theta_1+0.1\theta_2, \dots V1=0.1θ1,V2=0.09θ1+0.1θ2,…,这样导致刚开始的值都会特别小,随着 t t t的增加才会慢慢接近正常值。因此为了避免这种冷启动问题,需要对每个权重都进行偏差修正,即每个权重乘上一个修正系数 1 1 − β t 1\over 1-\beta^t 1−βt1
从这个系数可以看出,当 t t t很小时 β t \beta^t βt还是接近于1,例如 t = 2 t=2 t=2时 β 2 = 0.81 \beta^2=0.81 β2=0.81,那么乘上这个系数就相当于乘上一个比较大的数,将比较小的初始值放大;而当 t t t越来越大时, β t \beta^t βt趋于0,这时这个系数趋于1,基本上就不进行放大了,就和正常的值差不多。
但是为什么是 1 1 − β t 1\over 1-\beta^t 1−βt1呢?因为 V t = ( 1 − β ) θ t + β ( 1 − β ) θ t − 1 + β 2 ( 1 − β ) θ t − 2 + ⋯ + β t − 1 ( 1 − β ) θ 1 V_t=(1-\beta)\theta_t+\beta(1-\beta)\theta_{t-1}+\beta^2(1-\beta)\theta_{t-2}+\cdots+\beta^{t-1} (1-\beta)\theta_{1} Vt=(1−β)θt+β(1−β)θt−1+β2(1−β)θt−2+⋯+βt−1(1−β)θ1这 t t t个权重构成一个等比数列,求和得到权重之和为 1 − β t 1-\beta^t 1−βt,因此,修正系数取为 1 1 − β t 1\over 1-\beta^t 1−βt1,这样 V t V_t Vt就是所有 θ \theta θ的加权求和了(权重之和为1)。
近似解释:
在数学上有 lim n → ∞ ( 1 − 1 n ) n = 1 e ≈ 0.3679 \lim_{n\to\infin}(1-{1\over n})^{n}={1\over e}\approx0.3679 limn→∞(1−n1)n=e1≈0.3679
令 n = 1 1 − β n={1\over 1-\beta} n=1−β1,则 ( 1 − 1 n ) n = ( 1 − ( 1 − β ) ) n = β 1 1 − β (1-{1\over n})^{n}=(1-(1-\beta))^n=\beta^{1\over 1-\beta} (1−n1)n=(1−(1−β))n=β1−β1,当 β → 1 \beta\to1 β→1时, n → ∞ n\to\infin n→∞,所以 β 1 1 − β → 1 e \beta^{1\over 1-\beta}\to{1\over e} β1−β1→e1
这意味着当 β \beta β的次数等于 1 1 − β {1\over 1-\beta} 1−β1时, θ \theta θ的权重就已经衰减为 ( 1 − β ) (1-\beta) (1−β)的大概1/3了。
因此,若将 1 e ≈ 0.3679 {1\over e}\approx0.3679 e1≈0.3679当做阈值,即小于它就认为权重过小可以忽略不计,那么 V t V_t Vt就相当于只是对最近的 1 1 − β {1\over 1-\beta} 1−β1个 θ \theta θ值进行加权平均。
所以当 β = 0.9 \beta=0.9 β=0.9时, 1 1 − 0.9 = 10 {1\over 1-0.9}=10 1−0.91=10, V t V_t Vt近似是对最近的10个 θ \theta θ值进行加权平均。
所以当 β = 0.98 \beta=0.98 β=0.98时, 1 1 − 0.98 = 50 {1\over 1-0.98}=50 1−0.981=50, V t V_t Vt近似是对最近的50个 θ \theta θ值进行加权平均。
RMSprop也采用了EWMA,但与动量法不同的是,它是对梯度的平方求指数加权滑动平均,然后用梯度除以这个EWMA的均方根来更新参数。
我个人结合参考资料从两个方面来理解RMSprop:
1、从梯度的角度来理解:RMSprop计算了梯度平方的指数加权滑动平均,对于震荡较大的梯度方向,它的平方的EWMA也比较大,我们希望在更新的时候尽可能减少它对于优化方向的影响,所以除上较大的EWMA的均方根后这个梯度变小;而对于震荡较小的梯度方向,则它的平方的EWMA也较小,所以除上较小的EWMA的均方根后放大了这个梯度对于优化方向的指导性,所以能保持较为一致的优化方向。
2、从学习率的角度来理解:RMSprop适应地调整所有参数的学习率,它将参数的学习率缩放反比于其所有历史梯度平方的指数加权滑动平均的平方根。这样,如果参数的梯度较大,那么这个参数的学习率将下降较大,而梯度小的参数在学习率上有相对较小的下降,从而达到加速的目的,其净效果是在参数空间中更为平缓的倾斜方向会取得更大的进步。
具体的做法是:
先初始化EWMA为零(矩阵)
在每次迭代时,计算当前梯度平方的EWMA,即: S d W = β S d W + ( 1 − β ) d W 2 S d b = β S d b + ( 1 − β ) d b 2 S_{dW}=\beta S_{dW}+(1-\beta)dW^2\\S_{db}=\beta S_{db}+(1-\beta)db^2 SdW=βSdW+(1−β)dW2Sdb=βSdb+(1−β)db2然后除以梯度的EWMA的均方根(这里对应第一种理解方式),即: W = W − α d W S d W + ϵ b = b − α d b S d b + ϵ W=W-\alpha {dW\over \sqrt{S_{dW}+\epsilon}}\\b=b-\alpha {db\over \sqrt{S_{db}+\epsilon}} W=W−αSdW+ϵdWb=b−αSdb+ϵdb为了防止分母为零, ϵ \epsilon ϵ是为了维持数值稳定性而添加的常数,一般取值为1e-6(如果放在根号外面就取1e-8)
在对比了Batch Gradient Descent、Mini-batch Gradient Descent、Momentum、RMSprop以及Adam在数据集上的效果之后,得到他们的精度分别为0.66、0.796667、0.796667、0.94以及0.94,收敛速度反应在下图(第一幅是Batch Gradient Descent,也就是mini_batch_size=n时):
由于小批量的随机性导致损失函数的震荡,这里我把每100次或者每1000次epoch的损失改成这100次或者这1000次epoch的平均损失,然后得到下图:
可以看出在这个数据集上,动量法作用基本上可以忽略不计,作业中也指出在学习率较小且数据集较简单时,单纯的动量法与普通参数更新效果差异不大。而RMSprop带来的效果十分明显,而且Adam效果好也是由于RMSprop所带来的,他们俩之间有些微区别是因为在RMSprop中没有使用偏差修正,这似乎让RMSprop在实际表现中下降得更快,但是从震荡的代价图中看出Adam在迭代初期似乎更加稳健一些。
在核对我的代码时发现GitHub上的那个同学在写random_mini_batches函数的时候把打乱后的数据和源数据用混了,所以导致那个作业结果有错误,根据作业最后的描述来说我这里是正确的。
import numpy as np
import matplotlib.pyplot as plt
import scipy.io
import math
import sklearn
import sklearn.datasets
from opt_utils import load_params_and_grads, initialize_parameters, forward_propagation, backward_propagation
from opt_utils import compute_cost, predict, predict_dec, plot_decision_boundary, load_dataset
from testCases import *
%matplotlib inline
plt.rcParams['figure.figsize'] = (7.0, 4.0) # set default size of plots
plt.rcParams['image.interpolation'] = 'nearest'
plt.rcParams['image.cmap'] = 'gray'
# 导入数据
train_X, train_Y = load_dataset()
'''批量梯度下降'''
def update_parameters(parameters, grads, learning_rate):
L = len(parameters) // 2
for i in range(1, L+1):
parameters['W'+str(i)] += - learning_rate * grads['dW'+str(i)]
parameters['b'+str(i)] += - learning_rate * grads['db'+str(i)]
return parameters
def model_gb(X, Y, learning_rate = 0.0007, num_iterations = 10000, print_cost = True):
grads = {}
costs = [] # to keep track of the loss
m = X.shape[1] # number of examples
layers_dims = [X.shape[0], 5, 2, 1]
# Initialize parameters dictionary.
parameters = initialize_parameters(layers_dims)
# Loop (gradient descent)
for i in range(0, num_iterations):
# Forward propagation: LINEAR -> RELU -> LINEAR -> RELU -> LINEAR -> SIGMOID.
a3, cache = forward_propagation(X, parameters)
# cost
cost = compute_cost(a3, Y)
# Backward propagation.
grads = backward_propagation(X, Y, cache)
# Update parameters.
parameters = update_parameters(parameters, grads, learning_rate)
# Print the loss every 1000 iterations
if print_cost and i % 1000 == 0:
print("Cost after iteration {}: {}".format(i, cost))
costs.append(cost)
# plot the loss
plt.plot(costs)
plt.ylabel('cost')
plt.xlabel('iterations (per hundreds)')
plt.title("Learning rate =" + str(learning_rate))
plt.show()
return parameters
parameters = model_gb(train_X, train_Y)
predictions = predict(train_X, train_Y, parameters)
# Plot decision boundary
plt.title("Model with Gradient Descent optimization")
axes = plt.gca()
axes.set_xlim([-1.5,2.5])
axes.set_ylim([-1,1.5])
plot_decision_boundary(lambda x: predict_dec(parameters, x.T), train_X, np.squeeze(train_Y))
# 在上面的基础上一点点扩充优化方法
def model(X, Y, optimizer, num_epochs=10000, mini_batch_size=64, learning_rate=0.0007,
beta1=0.9, beta2=0.999, epsilon=1e-6, print_cost=True):
grads = {}
costs = [] # to keep track of the loss
costs_ave = [] # to plot
m = X.shape[1] # number of examples
t = 0
layers_dims = [X.shape[0], 5, 2, 1]
# Initialize parameters dictionary.
parameters = initialize_parameters(layers_dims)
if optimizer == 'mini_batch_gd':
pass
if optimizer == 'momentum':
V = initialize_v(parameters)
if optimizer == 'RMSprop':
S = initialize_v(parameters)
if optimizer == 'Adam':
V = initialize_v(parameters)
S = initialize_v(parameters)
# Loop
for i in range(num_epochs):
mini_batches = random_mini_batches(X, Y, mini_batch_size)
for mini_batch in mini_batches:
(mini_batch_X, mini_batch_Y) = mini_batch
# Forward propagation: LINEAR -> RELU -> LINEAR -> RELU -> LINEAR -> SIGMOID.
a3, cache = forward_propagation(mini_batch_X, parameters)
# cost 代价应该是一次epoch的平均代价
cost = compute_cost(a3, mini_batch_Y)
costs.append(cost)
# Backward propagation.
grads = backward_propagation(mini_batch_X, mini_batch_Y, cache)
# Update parameters.
if optimizer == 'mini_batch_gd':
parameters = update_parameters(parameters, grads, learning_rate)
if optimizer == 'momentum':
parameters, V = update_parameters_with_momentum(parameters, grads, V, beta1, learning_rate)
if optimizer == 'RMSprop':
parameters, S = update_parameters_with_RMSprop(parameters, grads, S, beta2, epsilon, learning_rate)
if optimizer == 'Adam':
t = t + 1
parameters, V, S = update_parameters_with_Adam(parameters, grads, V, S, beta1, beta2, t, epsilon, learning_rate)
# Print the cost every 1000 epoch
if print_cost and i % 1000 == 0:
if i == 0:
print("Average cost after epoch {}: {}".format(i, cost))
costs_ave.append(cost)
else:
cost_ave = np.sum(costs[i-1000:i]) / 1000
print("Average cost after epoch {}: {}".format(i, cost_ave))
if print_cost and i % 100 == 0 and i > 0:
costs_ave.append(np.sum(costs[i-100:i]) / 100)
plt.plot(costs_ave)
plt.title(optimizer)
plt.ylabel('average cost')
plt.xlabel('epoch (per hundreds)')
plt.show()
return parameters
''' mini_batch gradient descent '''
# 对训练集进行分批,输出一个list,里面每个元素是X和Y切片的tuple
def random_mini_batches(X, Y, mini_batch_size = 64):
n = X.shape[1]
mini_batches = []
# np.random.seed(0)
permutation = np.random.permutation(n)
shuffled_X = X[:, permutation]
shuffled_Y = Y[:, permutation]
batch_floor = n//mini_batch_size
for i in range(0, batch_floor):
mini_batch_X = shuffled_X[:, i*mini_batch_size:(i+1)*mini_batch_size]
mini_batch_Y = shuffled_Y[:, i*mini_batch_size:(i+1)*mini_batch_size]
mini_batch = (mini_batch_X, mini_batch_Y)
mini_batches.append(mini_batch)
if n % mini_batch_size != 0:
mini_batch_X = shuffled_X[:, batch_floor*mini_batch_size:n]
mini_batch_Y = shuffled_Y[:, batch_floor*mini_batch_size:n]
mini_batch = (mini_batch_X, mini_batch_Y)
mini_batches.append(mini_batch)
return mini_batches
p_mini_batch = model(train_X, train_Y, optimizer='mini_batch_gd')
# Predict
predictions = predict(train_X, train_Y, p_mini_batch)
# Plot decision boundary
plt.title("Model with Gradient Descent optimization")
axes = plt.gca()
axes.set_xlim([-1.5,2.5])
axes.set_ylim([-1,1.5])
plot_decision_boundary(lambda x: predict_dec(p_mini_batch, x.T), train_X, np.squeeze(train_Y))
''' momentum '''
def initialize_v(parameters):
V = {}
L = len(parameters) // 2
for i in range(1, L+1):
V['dW'+str(i)] = np.zeros(parameters['W'+str(i)].shape)
V['db'+str(i)] = np.zeros(parameters['b'+str(i)].shape)
return V
def update_parameters_with_momentum(parameters, grads, V, beta1, learning_rate):
L = len(parameters) // 2
for i in range(1, L+1):
V['dW'+str(i)] = beta1 * V['dW'+str(i)] + (1-beta1) * grads['dW'+str(i)]
V['db'+str(i)] = beta1 * V['db'+str(i)] + (1-beta1) * grads['db'+str(i)]
parameters['W'+str(i)] += - learning_rate * V['dW'+str(i)]
parameters['b'+str(i)] += - learning_rate * V['db'+str(i)]
return parameters, V
p_momentum = model(train_X, train_Y, optimizer='momentum')
# Predict
predictions = predict(train_X, train_Y, p_momentum)
# Plot decision boundary
plt.title("Model with Momentum optimization")
axes = plt.gca()
axes.set_xlim([-1.5,2.5])
axes.set_ylim([-1,1.5])
plot_decision_boundary(lambda x: predict_dec(p_momentum, x.T), train_X, np.squeeze(train_Y))
''' RMSprop '''
def update_parameters_with_RMSprop(parameters, grads, S, beta2, epsilon, learning_rate):
L = len(parameters) // 2
for i in range(1, L+1):
S['dW'+str(i)] = beta2 * S['dW'+str(i)] + (1-beta2) * grads['dW'+str(i)]**2
S['db'+str(i)] = beta2 * S['db'+str(i)] + (1-beta2) * grads['db'+str(i)]**2
parameters['W'+str(i)] += - learning_rate * (grads['dW'+str(i)] / (np.sqrt(S['dW'+str(i)] + epsilon)))
parameters['b'+str(i)] += - learning_rate * (grads['db'+str(i)] / (np.sqrt(S['db'+str(i)] + epsilon)))
return parameters, S
p_RMSprop = model(train_X, train_Y, optimizer='RMSprop')
# Predict
predictions = predict(train_X, train_Y, p_RMSprop)
# Plot decision boundary
plt.title("Model with RMSprop optimization")
axes = plt.gca()
axes.set_xlim([-1.5,2.5])
axes.set_ylim([-1,1.5])
plot_decision_boundary(lambda x: predict_dec(p_RMSprop, x.T), train_X, np.squeeze(train_Y))
''' Adam '''
def update_parameters_with_Adam(parameters, grads, V, S, beta1, beta2, t, epsilon, learning_rate):
L = len(parameters) // 2
for i in range(1, L+1):
V['dW'+str(i)] = beta1 * V['dW'+str(i)] + (1-beta1) * grads['dW'+str(i)]
V['db'+str(i)] = beta1 * V['db'+str(i)] + (1-beta1) * grads['db'+str(i)]
S['dW'+str(i)] = beta2 * S['dW'+str(i)] + (1-beta2) * grads['dW'+str(i)]**2
S['db'+str(i)] = beta2 * S['db'+str(i)] + (1-beta2) * grads['db'+str(i)]**2
parameters['W'+str(i)] += - learning_rate * ((V['dW'+str(i)]/(1-beta1**t)) / (np.sqrt(S['dW'+str(i)]/(1-beta2**t) + epsilon)))
parameters['b'+str(i)] += - learning_rate * ((V['db'+str(i)]/(1-beta1**t)) / (np.sqrt(S['db'+str(i)]/(1-beta2**t) + epsilon)))
return parameters, V, S
p_Adam = model(train_X, train_Y, optimizer='Adam')
# Predict
predictions = predict(train_X, train_Y, p_Adam)
# Plot decision boundary
plt.title("Model with Adam optimization")
axes = plt.gca()
axes.set_xlim([-1.5,2.5])
axes.set_ylim([-1,1.5])
plot_decision_boundary(lambda x: predict_dec(p_Adam, x.T), train_X, np.squeeze(train_Y))
# 用震荡的代价
def model(X, Y, optimizer, num_epochs=10000, mini_batch_size=64, learning_rate=0.0007,
beta1=0.9, beta2=0.999, epsilon=1e-6, print_cost=True):
grads = {}
costs = [] # to keep track of the loss
m = X.shape[1] # number of examples
t = 0
layers_dims = [X.shape[0], 5, 2, 1]
# Initialize parameters dictionary.
parameters = initialize_parameters(layers_dims)
if optimizer == 'mini_batch_gd':
pass
if optimizer == 'momentum':
V = initialize_v(parameters)
if optimizer == 'RMSprop':
S = initialize_v(parameters)
if optimizer == 'Adam':
V = initialize_v(parameters)
S = initialize_v(parameters)
# Loop
for i in range(num_epochs):
mini_batches = random_mini_batches(X, Y, mini_batch_size)
for mini_batch in mini_batches:
(mini_batch_X, mini_batch_Y) = mini_batch
# Forward propagation: LINEAR -> RELU -> LINEAR -> RELU -> LINEAR -> SIGMOID.
a3, cache = forward_propagation(mini_batch_X, parameters)
# cost 代价应该是一次epoch的平均代价
cost = compute_cost(a3, mini_batch_Y)
# Backward propagation.
grads = backward_propagation(mini_batch_X, mini_batch_Y, cache)
# Update parameters.
if optimizer == 'mini_batch_gd':
parameters = update_parameters(parameters, grads, learning_rate)
if optimizer == 'momentum':
parameters, V = update_parameters_with_momentum(parameters, grads, V, beta1, learning_rate)
if optimizer == 'RMSprop':
parameters, S = update_parameters_with_RMSprop(parameters, grads, S, beta2, epsilon, learning_rate)
if optimizer == 'Adam':
t = t + 1
parameters, V, S = update_parameters_with_Adam(parameters, grads, V, S, beta1, beta2, t, epsilon, learning_rate)
# Print the cost every 1000 epoch
if print_cost and i % 1000 == 0:
print ("Cost after epoch %i: %f" %(i, cost))
if print_cost and i % 100 == 0:
costs.append(cost)
# plot the cost
plt.plot(costs)
plt.ylabel('cost')
plt.xlabel('epochs (per 100)')
plt.title(optimizer)
plt.show()
return parameters
额外的参考资料:
《动手学深度学习》李沐
《深度学习》‘’花书‘’