1. 隨機梯度下降(SGD)
- 迭代格式:
x k + 1 = x k ? η k ? f i ( x k ) x_{k+1} = x_k - \eta_k \nabla f_i(x_k) xk+1?=xk??ηk??fi?(xk?)
其中, η k \eta_k ηk? 為步長(可能遞減), ? f i ( x k ) \nabla f_i(x_k) ?fi?(xk?) 是隨機采樣樣本 i i i 的梯度估計。- 優點:
- 計算效率高,適合大規模數據集,每次迭代僅需單個樣本的梯度 。
- 在強凸問題中收斂速度為 O ( 1 / t ) O(1/t) O(1/t),非凸問題中為 O ( 1 / log ? t ) O(1/\log t) O(1/logt) 。
- 理論分析成熟,易于實現 。
- 缺點:
- 收斂速度較慢,尤其在非凸問題中易陷入局部最優 。
- 對步長敏感,需要精心調整參數以保證穩定性 。
2. 重球隨機梯度方法(SHB)
- 迭代格式:
x k + 1 = x k ? η k ? f i ( x k ) + β ( x k ? x k ? 1 ) x_{k+1} = x_k - \eta_k \nabla f_i(x_k) + \beta (x_k - x_{k-1}) xk+1?=xk??ηk??fi?(xk?)+β(xk??xk?1?)
其中, β ∈ ( 0 , 1 ) \beta \in (0,1) β∈(0,1) 為動量參數,通過歷史更新方向加速收斂。- 優點:
- 動量項可加速收斂,尤其在光滑強凸問題中表現優于固定步長的SGD 。
- 對梯度噪聲具有一定魯棒性,通過歷史梯度平均降低方差 。
- 缺點:
- 早期迭代可能表現不佳,收斂速度不一定始終優于SGD 。
- 參數選擇(如 β \beta β 和 η k \eta_k ηk?)需謹慎,否則可能導致震蕩或發散 。
- 在有限和隨機設置中,缺乏嚴格的加速收斂證明 。
3. Nesterov隨機梯度方法(SNAG)
- 迭代格式:
y k = x k + γ k ( x k ? x k ? 1 ) x k + 1 = y k ? η k ? f i ( y k ) y_k = x_k + \gamma_k (x_k - x_{k-1}) \\ x_{k+1} = y_k - \eta_k \nabla f_i(y_k) yk?=xk?+γk?(xk??xk?1?)xk+1?=yk??ηk??fi?(yk?)
其中, γ k \gamma_k γk? 為動量系數,通常在Nesterov方法中設計為時變參數。- 優點:
- 在凸問題中理論收斂速度可達 O ( 1 / t 2 ) O(1/t^2) O(1/t2),顯著快于SGD 。
- 通過“前瞻梯度”設計,減少震蕩并提高穩定性 。
- 實驗顯示在分類和圖像任務中優于傳統動量方法 。
- 缺點:
- 隨機環境下(如有限和設置)可能發散,需額外條件保證收斂 。
- 實現復雜度較高,需同時維護多個變量(如 x k x_k xk? 和 y k y_k yk?)。
- 參數調節更復雜,尤其在非凸問題中收斂性理論尚不完善 。
以上段落來自 秘塔 AI 綜述的結果(先搜索后擴展選項, 文獻均來自中英文論文而非全網)。該完整版請移步至鏈接
https://metaso.cn/s/ThPU2bK
以下我們給出一組實驗來探討 Nesterov 加速方法的參數選擇, 收斂效果請大家自行驗證,這里放上一個數值結果圖作為代表
其中一點比較尷尬的現象是確定問題中 θ k = k ? 1 k + 2 \theta_k=\frac{k-1}{k+2} θk?=k+2k?1? 類型的外插參數在隨機問題中的數值實驗中的表現并不好,有一子列不收斂到0,但是仍有大量文獻包括教材,論文仍然推薦使用這類策略。但是換成任何一個介于開區間 ( 0 , 1 ) (0,1) (0,1) 的常數,例如 0.9, 0.99 則有明顯的序列收斂至0的趨勢, 從本文給的算例來看是非常簡單的凸二次 x 0 2 + x 1 2 + 2 ξ 0 x 0 + 2 ξ 1 x 0 x_0^2+x_1^2+2\xi_0 x_0+2\xi_1x_0 x02?+x12?+2ξ0?x0?+2ξ1?x0?,其中 ξ i \xi_i ξi? 服從 N ( 0 , I ) N(0,I) N(0,I) 二維標準正態分布。為了壓縮噪聲影響,采用遞減步長 α k = 1 ( k + 2 ) γ \alpha_k=\frac{1}{(k+2)^\gamma} αk?=(k+2)γ1?。
- 規模小:僅2維問題
- 強凸
- 可微,且隨機梯度關于自變量 x x x 是李普希茲連續的
- 隨機樣本噪聲期望存在,方差有界
很難相信這樣二維簡單的例子參數 θ k = k ? 1 k + 2 \theta_k=\frac{k-1}{k+2} θk?=k+2k?1? 都不收斂,其在大規模以及大數據問題中會具有較好的收斂效果,歡迎大家參與實驗與討論。
Python 代碼如下:
import numpy as np
import matplotlib.pyplot as plt
import numpy.linalg as la
iters=1000000
root=np.array([1.0,3.0])
vec1=root.copy()
vec2=root.copy()
dim=len(root)
path=np.zeros([iters,dim])
def gobj(x,xi):return(2*(x+xi))
gamma=1# (k-1)/(k+2) ===============================
np.random.seed(0)
for k in range(iters): theta= (k-1)/(k+2)root=(1.0+theta)*vec2-theta*vec1a=1/(k+1)**gammaxi=np.random.randn(2)vec1=vec2.copy()vec2=root - a*gobj(root,xi)path[k,:]=root
V=np.zeros(iters)
for k in range(iters):V[k]=la.norm(path[k,:])
plt.loglog(V,'-.')
plt.grid(True)# 0.99 ===============================
iters=1000000
root=np.array([1.0,3.0])
vec1=root.copy()
vec2=root.copy()
dim=len(root)
path=np.zeros([iters,dim])
np.random.seed(0)
for k in range(iters): theta= 0.99root=(1.0+theta)*vec2-theta*vec1a=1/(k+1)**gammaxi=np.random.randn(2)vec1=vec2.copy()vec2=root - a*gobj(root,xi)path[k,:]=root
V=np.zeros(iters)
for k in range(iters):V[k]=la.norm(path[k,:])
plt.loglog(V,'--')
plt.grid(True)# 0.9 ===============================
iters=1000000
root=np.array([1.0,3.0])
vec1=root.copy()
vec2=root.copy()
dim=len(root)
path=np.zeros([iters,dim])
np.random.seed(0)
for k in range(iters): theta= 0root=(1.0+theta)*vec2-theta*vec1a=1/(k+1)**gammaxi=np.random.randn(2)vec1=vec2.copy()vec2=root - a*gobj(root,xi)path[k,:]=root
V=np.zeros(iters)
for k in range(iters):V[k]=la.norm(path[k,:])
plt.loglog(V,'.-')
plt.grid(True)plt.legend(['(k-1)/(k+2)',0.99,0.5,'2/(k+2)'])
plt.show()
Matlab 代碼如下
% (k-1)/(k+2) ===============================
init=[1,3];
lth=length(init);
fobj=@(x,xi)(x*x'+2*xi*x');
gobj=@(x,xi)(2*x+2*xi);
iters=1000000;
path=ones(iters+1,length(init));
path(1,:)=init;
root=init;
randn('seed',1)
for k =1:itersif k<2xi=randn(1,lth);a=1/(k+2)^(2/3);root=root-a*gobj(root,xi);path(k+1,:)=root;elsexi=randn(1,lth);a=1/(k+2)^(2/3);v=root-a*gobj(root,xi);path(k+1,:)=v;theta=(k-1)/(k+2);th=theta;root=(1+th)*path(k+1,:)-theta*path(k,:);end
end
Vk=ones(iters+1,1);
for k=1:iters+1Vk(k)= path(k,:)*path(k,:)';
end
loglog(Vk,'--')
grid on;
hold on;% theta=0.99 ===============================
init=[1,3];
iters=1000000;
path=ones(iters+1,length(init));
path(1,:)=init;
root=init;
randn('seed',1)
for k =1:itersif k<2xi=randn(1,lth);a=1/(k+2)^(2/3);root=root-a*gobj(root,xi);path(k+1,:)=root;elsexi=randn(1,lth);a=1/(k+2)^(2/3);v=root-a*gobj(root,xi);path(k+1,:)=v;theta=0.99;th=theta;root=(1+th)*path(k+1,:)-theta*path(k,:);end
end
Vk=ones(iters+1,1);
for k=1:iters+1Vk(k)= path(k,:)*path(k,:)';
end
loglog(Vk,'--')
grid on;
hold on;% theta=0.9 ===============================
init=[1,3];
iters=1000000;
path=ones(iters+1,length(init));
path(1,:)=init;
root=init;
randn('seed',1)
for k =1:itersif k<2xi=randn(1,lth);a=1/(k+2)^(2/3);root=root-a*gobj(root,xi);path(k+1,:)=root;elsexi=randn(1,lth);a=1/(k+2)^(2/3);v=root-a*gobj(root,xi);path(k+1,:)=v;theta=0.9;th=theta;root=(1+th)*path(k+1,:)-theta*path(k,:);end
end
Vk=ones(iters+1,1);
for k=1:iters+1Vk(k)= path(k,:)*path(k,:)';
end
loglog(Vk,'--')
grid on;
hold on;% theta=0.9 ===================================================================
init=[1,3];iters=1000000;
path=ones(iters+1,length(init));
path(1,:)=init;
root=init;
randn('seed',1)
for k =1:itersif k<2xi=randn(1,lth)a=1/(k+2)^(2/3);root=root-a*gobj(root,xi);path(k+1,:)=root;elsexi=randn(1,lth);a=1/(k+2)^(2/3);v=root-a*gobj(root,xi);path(k+1,:)=v;theta=0.5;th=theta;root=(1+th)*path(k+1,:)-theta*path(k,:);end
end
Vk=ones(iters+1,1);
for k=1:iters+1Vk(k)= path(k,:)*path(k,:)';
end
loglog(Vk,'--')
grid on;
hold on;
legend('(k-1)/(k+2)','0.99','0.9','0.5')