基本设计到算法岗位,算法理论基础、paper、实战经验,最最重要的。
刚刚有一位同学面试了华为算法岗位,就在神经网络以及论文方面和面试官进行了深入的探讨。
有一个讨论的题目是:RNN优化算法:AdaGrad、RMSprop和Adam
趁着这个机会,咱们也和大家聊聊,感觉有用,可以在文末给一个三连~
训练RNN的过程中,选择合适的优化算法是非常重要的。
咱们今天详细介绍RNN中的三种常用优化算法:AdaGrad、RMSprop和Adam,并讨论它们之间的异同以及适用场景。
AdaGrad算法
AdaGrad算法是一种自适应学习率算法,它根据每个参数在训练过程中的更新情况,动态调整学习率的大小。具体来说,对于每个参数的更新,AdaGrad算法计算参数的梯度平方的累加,并将学习率按照参数的梯度平方根递减。这意味着参数的学习率在训练初期较大,在训练过程中逐渐减小。
AdaGrad算法的更新规则如下:
其中,
表示参数的梯度平方的累加,
表示参数的梯度,
表示学习率,
是一个微小的常数,用于防止除以零。
由于AdaGrad算法累加了参数梯度的平方,它在稀疏数据集上的表现效果不佳。
RMSprop算法
RMSprop算法也是一种自适应学习率算法,它对AdaGrad算法进行了改进,解决了AdaGrad算法在稀疏数据集上的不足。RMSprop算法引入了一个衰减系数,通过对梯度平方的指数加权平均来减小梯度累加带来的影响。
RMSprop算法的更新规则如下:
其中,
表示从训练开始到第
次迭代的梯度平方的指数加权平均,
表示衰减系数,
表示参数的梯度,
表示学习率,
是一个微小的常数。
通过引入衰减系数
,RMSprop算法能够在训练过程中自适应地调整学习率的大小,从而更好地适应不同的训练数据。
Adam算法
Adam算法是一种结合了动量(momentum)和自适应学习率的优化算法。Adam算法通过对梯度的一阶矩和二阶矩进行估计,并使用偏差修正来纠正估计的偏差。
Adam算法的更新规则如下:
其中,
和
分别表示参数梯度的一阶矩和二阶矩的估计,
和
是用于计算一阶矩和二阶矩的衰减系数,
表示参数的梯度,
和
分别表示修正后的一阶矩和二阶矩的估计,
表示学习率,
是一个微小的常数。
Adam算法通过动量的引入,能够更好地跳出局部最优解,同时通过自适应学习率的调整,进一步改善了模型的性能。
适用场景
根据不同的机器学习任务和数据集特点,选择合适的优化算法可以提高模型的训练效果。
AdaGrad算法适用于稀疏数据集和凸优化问题,因为它能够自适应地调整学习率,更好地适应数据的稀疏性,并且在凸优化问题中能够收敛到全局最优解。
RMSprop算法适用于非稀疏数据集和非凸优化问题,它通过引入衰减系数来缓解AdaGrad算法的过拟合问题,使得学习率能够更好地适应不同的训练数据。
Adam算法是目前应用最广泛的优化算法,适用于大多数机器学习任务和数据集。它结合了动量和自适应学习率的优点,能够更好地平衡全局搜索和局部搜索之间的权衡,达到更好的训练效果。
实现代码
在刚刚理论的基础之上,咱们用代码实现一遍,演示如何在RNN中使用Adam算法进行优化。
import numpy as np# RNN模型的参数初始化hidden_dim = 100input_dim = 50output_dim = 10learning_rate = 0.001num_iterations = 1000# 初始化RNN模型的参数Wxh = np.random.randn(hidden_dim, input_dim) * 0.01 # 输入到隐藏的权重矩阵Whh = np.random.randn(hidden_dim, hidden_dim) * 0.01 # 隐藏到隐藏的权重矩阵Why = np.random.randn(output_dim, hidden_dim) * 0.01 # 隐藏到输出的权重矩阵bh = np.zeros((hidden_dim, 1)) # 隐藏层的偏置项by = np.zeros((output_dim, 1)) # 输出层的偏置项# 训练数据准备X = np.random.randn(input_dim, num_iterations) # 输入数据Y = np.random.randn(output_dim, num_iterations) # 输出数据# Adam算法的初始化mWxh, mWhh, mWhy = np.zeros_like(Wxh), np.zeros_like(Whh), np.zeros_like(Why)vWxh, vWhh, vWhy = np.zeros_like(Wxh), np.zeros_like(Whh), np.zeros_like(Why)beta1 = 0.9beta2 = 0.999epsilon = 1e-8# 训练过程for t in range(num_iterations): # 前向传播 h = np.zeros((hidden_dim, 1)) for i in range(input_dim): h = np.tanh(np.dot(Wxh, X[:, t].reshape(-1, 1)) + np.dot(Whh, h) + bh) y = np.dot(Why, h) + by # 计算损失 loss = np.sum((y - Y[:, t].reshape(-1, 1)) ** 2) / 2 # 反向传播 dy = y - Y[:, t].reshape(-1, 1) dWhy = np.dot(dy, h.T) dby = dy dh = np.dot(Why.T, dy) * (1 - h * h) dWxh = np.dot(dh, X[:, t].reshape(1, -1)) dWhh = np.dot(dh, h.T) dbh = dh # 参数更新 mWxh = beta1 * mWxh + (1 - beta1) * dWxh vWxh = beta2 * vWxh + (1 - beta2) * (dWxh ** 2) mWhh = beta1 * mWhh + (1 - beta1) * dWhh vWhh = beta2 * vWhh + (1 - beta2) * (dWhh ** 2) mWhy = beta1 * mWhy + (1 - beta1) * dWhy vWhy = beta2 * vWhy + (1 - beta2) * (dWhy ** 2) Wxh -= learning_rate * mWxh / (np.sqrt(vWxh) + epsilon) Whh -= learning_rate * mWhh / (np.sqrt(vWhh) + epsilon) Why -= learning_rate * mWhy / (np.sqrt(vWhy) + epsilon) bh -= learning_rate * np.mean(dbh, axis=1, keepdims=True) by -= learning_rate * np.mean(dby, axis=1, keepdims=True) # 打印损失 if (t + 1) % 100 == 0: print("Iteration: {}/{} Loss: {:.4f}".format(t + 1, num_iterations, loss))
上面是一个简单的使用Adam算法优化RNN模型的示例代码。
在每次迭代中,通过前向传播计算模型的输出
,并计算损失。然后,通过反向传播计算损失对参数的梯度,根据Adam算法的更新规则更新参数。
训练数据
和
是随机生成的,输入维度为input_dim,输出维度为output_dim,共进行了num_iterations次迭代。
初始化Adam算法的参数
和
为0,并设定衰减系数
和
为0.9和0.999。
在参数的更新过程中,为了防止除以零,引入了一个微小的常数
。
最后,每隔100次迭代,打印当前的损失值。
通过合适调整参数和网络结构,可以根据具体任务和数据集选择合适的RNN优化算法,获得更好的训练效果。
最后
在实际的实验中,大家要根据不同的数据集和任务特点,选择合适的优化算法可以提高模型的训练效果。在实际应用中,常常使用Adam算法,因为它结合了动量和自适应学习率的优点,能够更好地平衡全局搜索和局部搜索之间的权衡,达到更好的训练效果。
所有以后想做算法的同学,记住:理论基础+论文!