关于梯度下降,本文主要讲三个问题:
一、什么是梯度
二、什么是梯度下降
三、三种常见的梯度下降算法实现
什么是梯度
梯度是一个与函数相切的向量,指向此函数最大增量的方向。 函数在局部最大值或最小值处梯度为零。 在数学中,梯度被定义为函数的偏导数。 例如,我们有一个函数:
函数图形如下图所示,我们可以看到函数的最小值点在(0,0)。
即该函数的梯度为对x的偏导数与对y的偏导数,可表示为:
如果我们想要在点(1,2)处的梯度,只需要将(1,2)代入上面的公式即可得到梯度为:
什么是梯度下降
由于梯度是指向函数最大增量的向量,因此负梯度是指向函数最大减量的向量。 因此,梯度下降就是通过在负梯度方向上迭代来最小化损失函数。
在迭代的过程中,先定义一个起点:
然后得到迭代过程为
上面公式中参数alpha称为学习率,一般设置为一个较小的常量。还是用上面的例子来说,我们已经知道函数的梯度为:
因此,梯度下降的迭代过程就可以写成:
化简得:
如果我们假设alpha小于1,那么我们可以得到:
结论与我们在上图中观察到的结果相同。另一种解释梯度下降的直观方法是在下山的过程中,每一步都走下降最陡的地方即可最快到达山脚。
同样,在机器学习中我们更关注目标函数和参数之间的关系,机器学习模型使用梯度下降的核心思想就是迭代调整参数以便最小化成本函数。
在某些情况下,我们可以通过方程直接计算最适合模型到训练集的参数。 例如,要最小化线性回归的MSE,参数可以写为:
Gradient Descent中的一个重要参数是学习率,它决定了每次下降的步长。当学习速度太大时,梯度下降可能错过最优解。 当学习速率太小时,算法需要很长时间才能收敛。 因此,初始化适当的学习率是非常重要的。
归一化对梯度下降同样重要。 如果特征未归一化,大量的特征参数将会大大增加算法的复杂度。 在对所有特征进行归一化后可以加速梯度下降算法下降到最低。下图可以直接了解归一化对于梯度下降的作用。
三种常见的梯度下降算法实现
常用的梯度下降算法包括批量梯度下降,小批量梯度下降和随机梯度下降。下面我们将用Python来实现这三种算法。
批量梯度下降:批量梯度下降在每一步迭代时使用整个训练集。 它计算每条数据的误差,并取平均值来确定梯度。 批量梯度下降的优点是该算法计算效率更高,并且它产生稳定的学习路径,因此更容易收敛。 但是,当训练集很大时,批量梯度下降需要更长的时间。
# Function for batch gradient decent
def Batch_GD (Learning_Rate,num_iterations,X,y):
#Step 1: Initial Parameter
N=len(X)
w=np.zeros((X.shape[1],1))
b=0
costs=[]
# Starting Loop
for i in range(num_iterations):
#Step 2: Apply Sigmoid Function and get y prediction
Z=np.dot(wT,XT)+b
y_pred=1/(1+1/np.exp(Z))
#Step 3: Calculate Loss Function
cost=-(1/N)*np.sum(y*np.log(y_pred)+(1-y)*np.log(1-y_pred))
#Step 4: Calculate Gradient
dw=1/N*np.dot(XT,(y_pred-y).T)
db=1/N*np.sum(y_pred-y)
#Step 5: Update w & b
w = w - Learning_Rate * dw
b = b - Learning_Rate * db
# Records cost
if i % 1000 == 0:
costs.append(cost)
#print(cost)
return(w,b,costs)
# Run a function
Result_BatchGD=Batch_GD(Learning_Rate=0.01,num_iterations=100000,X=X,y=y)
随机梯度下降:随机梯度下降只是从每个迭代的训练集中选择一个误差,并且仅基于该单个记录更新梯度。 随机梯度下降的优点是算法在每次迭代时速度较快。 与批量梯度下降相比,该算法在迭代的过程中成本函数不会平滑地减少,而是会上下跳动。 经过几轮迭代后,算法可能会找到一个好的参数,但最终结果不一定是全局最优的。
# Function for Stochastic Gradient Descent
def Stochastic_GD (Learning_Rate,num_iterations,X,y):
# Step 1: Initial Parameter
N=len(X)
w=np.zeros((X.shape[1],1))
b=0
costs=[]
# Starting two layer of loops
for i in range(num_iterations):
for j in range(N):
# Choose 1 record
XX=X[j,:]
yy=y[j]
# Step 2: Apply Sigmoid Function and get y prediction
Z=np.dot(wT,XX.T)+b
y_pred=1/(1+1/np.exp(Z))
#Step 3: Calculate Loss Function
cost=-(yy*np.log(y_pred)+(1-yy)*np.log(1-y_pred))
#Step 4: Calculate Gradient
dw=np.multiply(XX,(y_pred-yy)).reshape((2,1))
db=y_pred-yy
#Step 5: Update w & b
w = w - Learning_Rate * dw
b = b - Learning_Rate * db
#Step 6: Calculate Loss Function
Z_full=np.dot(wT,XT)+b
y_pred_full=1/(1+1/np.exp(Z_full))
cost=-(1/N)*np.sum(y*np.log(y_pred_full)+(1-y)*np.log(1-y_pred_full))
#Records cost
if i % 100 == 0:
costs.append(cost)
#print(cost)
return(w,b,costs)
# Run a function
Result_Stoc_GD=Stochastic_GD(Learning_Rate=0.01,num_iterations=2000,X=X,y=y)
小批量梯度下降:小批量梯度下降结合了Batch和随机梯度下降的概念。算法每次迭代是基于训练集的子集而不是完整数据集。小批量梯度下降的优点是该算法在计算过程中利用矩阵运算,并且损失函数可以比随机梯度下降更平稳和稳定地降低。
# Function for mini batch Gradient Descent
def Minibatch_GD (Learning_Rate,num_iterations,X,y,Minibatch):
# Part 1: Mini Batch
np.random.seed(1000)
N=len(X)
mini_batches=[]
#Step 1: Shuffle (X,y)
permutation=list(np.random.permutation(N))
shuffled_X=X[permutation,:]
shuffled_y=y[permutation]
#Step 2: Partition
num_complete_minibatches=int(np.floor(N/Minibatch))
for i in range(num_complete_minibatches):
mini_batch_X=shuffled_X[i*Minibatch:(i+1)*Minibatch,:]
mini_batch_y=shuffled_y[i*Minibatch:(i+1)*Minibatch]
mini_batch = (mini_batch_X, mini_batch_y)
mini_batches.append(mini_batch)
if N % Minibatch !=0:
mini_batch_X=shuffled_X[N-Minibatch:N,:]
mini_batch_y=shuffled_y[N-Minibatch:N]
mini_batch = (mini_batch_X, mini_batch_y)
mini_batches.append(mini_batch)
# Part 2: Gradient Descent
w=np.zeros((X.shape[1],1))
b=0
costs=[]
for i in range(num_iterations):
for j in range(num_complete_minibatches+1):
#Select Minibatch
XX=mini_batches[j][0]
yy=mini_batches[j][1]
#Step 2: Apply Sigmoid Function and get y prediction
Z=np.dot(wT,XX.T)+b
y_pred=1/(1+1/np.exp(Z))
#Step 3: Calculate Gradient
dw=1/Minibatch*np.dot(XX.T,(y_pred-yy).T)
db=1/Minibatch*np.sum(y_pred-yy)
#Step 4: Update w & b
w = w - Learning_Rate * dw
b = b - Learning_Rate * db
#Step 5: Calculate Loss Function
Z_full=np.dot(wT,XT)+b
y_pred_full=1/(1+1/np.exp(Z_full))
cost=-(1/N)*np.sum(y*np.log(y_pred_full)+(1-y)*np.log(1-y_pred_full))
if i % 1000 ==0:
costs.append(cost)
#print(cost)
return(w,b,costs)
# Run a function
Result_MiniGD=Minibatch_GD(Learning_Rate=0.01,num_iterations=100000,X=X,y=y,Minibatch=50)
留言与评论(共有 0 条评论) |