import matplotlib.pyplot as plt

def gradient_descent(f, df, x0, learning_rate, num_iterations):
x = x0
x_history = [x]

for _ in range(num_iterations):
gradient = df(x)
x -= learning_rate * gradient
x_history.append(x)

return np.array(x_history)

# 定義函數f(x)
def f(x):
return x**2 + 10*np.sin(x)

# 定義函數f(x)的導數df(x)
def df(x):
return 2*x + 10*np.cos(x)

# 設置初始參數值和學習率
x0 = -5
learning_rate = 0.1
num_iterations = 100

# 運行梯度下降算法
x_history = gradient_descent(f, df, x0, learning_rate, num_iterations)

# 繪制函數曲線和梯度下降路徑
x_range = np.linspace(-10, 10, 100)
plt.plot(x_range, f(x_range), label='f(x)')
plt.scatter(x_history, f(np.array(x_history)), c='red', label='Gradient Descent')
plt.legend()
plt.xlabel('x')
plt.ylabel('f(x)')
plt.title('Gradient Descent')
plt.show()

這段代碼會繪制函數f(x)的曲線以及梯度下降過程中的路徑,以直觀地展示梯度下降算法的工作原理。

隨機梯度下降法(Stochastic Gradient Descent,SGD)

隨機梯度下降法常用于訓練機器學習模型。它的主要思想是通過迭代更新模型參數來最小化損失函數。相比于傳統的梯度下降法,SGD在每一次迭代中僅使用一個樣本數據進行參數更新,因此計算速度更快。SGD的公式如下:

下面是一個關于 SGD 的工作原理的一個例子。

import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D

# 定義損失函數
def loss_function(x, y):
return (x - 1) ** 2 + (y - 2) ** 2

# 定義梯度函數
def gradient(x, y):
return np.array([2 * (x - 1), 2 * (y - 2)])

# 生成數據
x = np.linspace(-5, 5, 100)
y = np.linspace(-5, 5, 100)
X, Y = np.meshgrid(x, y)
Z = loss_function(X, Y)

# 繪制3D圖形
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.plot_surface(X, Y, Z, cmap='viridis')

# SGD迭代更新參數
eta = 0.1
theta = np.array([0, 0])
num_iterations = 100
for i in range(num_iterations):
gradient_value = gradient(theta[0], theta[1])
theta = theta - eta * gradient_value
ax.scatter(theta[0], theta[1], loss_function(theta[0], theta[1]), color='red')

plt.show()

上面,我們定義了一個簡單的二維損失函數和對應的梯度函數,并使用matplotlib庫繪制了該函數的三維圖形。然后,我們使用SGD迭代更新參數,并在圖中標示出每次迭代后的參數值。通過觀察這些點的變化,可以更直觀地理解SGD在參數空間中的搜索過程。

小批量梯度下降法(Mini-batch Gradient Descent)

小批量梯度下降法是介于隨機梯度下降法(SGD)和批量梯度下降法(BGD)之間的一種折中方法。它將訓練樣本劃分為多個批次(mini-batches),每個批次包含若干個樣本。與SGD每次只使用一個樣本進行參數更新相比,MBGD每次使用一個批次的樣本進行參數更新。MBGD的主要區別和優勢如下:

  1. 計算效率: 與BGD相比,MBGD采用小批量樣本進行參數更新,可以減少計算時間。尤其在大規模數據集上,MBGD通常比BGD更快。而與SGD相比,MBGD每次更新的樣本數量更多,可以充分利用矩陣運算的并行性,加速參數更新過程。
  2. 穩定性: MBGD相對于SGD具有更好的穩定性。由于MBGD每次使用多個樣本進行參數更新,因此其參數更新方向相對于單個樣本更加準確,避免了SGD中參數更新的高度不穩定問題。這使得MBGD在訓練過程中更容易收斂到更好的局部最優解。
  3. 魯棒性: MBGD相對于SGD對噪聲數據具有更好的魯棒性。由于MBGD每次使用多個樣本進行參數更新,它對于單個樣本中的噪聲信息會有所平均化,從而減少了單個樣本對模型的影響。
  4. 泛化能力: MBGD相對于SGD和BGD在一定程度上具有更好的泛化能力。與SGD相比,MBGD使用了更多的樣本進行參數更新,可以更充分地表征數據集的特征;與BGD相比,MBGD采用了部分樣本進行參數更新,避免了過度擬合的問題。

需要注意的是,MBGD的選擇要根據具體問題的需求來確定。較小的批次大小可能會導致更快的收斂速度,但也可能陷入局部最優解。較大的批次大小可能導致計算變慢,但可能會獲得更穩定的解。因此,在實踐中,我們通常需要根據數據集的規模、模型的復雜度和計算資源的限制等因素來選擇適當的批次大小。綜上所述,MBGD是在SGD和BGD之間取得折中的一種優化算法,它在計算效率、穩定性、魯棒性和泛化能力等方面都具有一定的優勢。

二階優化算法

牛頓法(Newton’s Method)

牛頓法用于求解無約束優化問題。它通過利用二階導數信息來近似地更新參數,從而更快地收斂到最優解。牛頓法的公式如下:

下面示例說明牛頓法的工作原理:

import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D

# 定義目標函數
def objective_function(x, y):
return x**2 + 2*y**2

# 定義梯度函數
def gradient(x, y):
return np.array([2*x, 4*y])

# 定義黑塞矩陣
def hessian_matrix():
return np.array([[2, 0], [0, 4]])

# 生成數據
x = np.linspace(-5, 5, 100)
y = np.linspace(-5, 5, 100)
X, Y = np.meshgrid(x, y)
Z = objective_function(X, Y)

# 繪制3D圖形
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.plot_surface(X, Y, Z, cmap='viridis')

# 牛頓法迭代更新參數
theta = np.array([0, 0])
num_iterations = 10
for i in range(num_iterations):
gradient_value = gradient(theta[0], theta[1])
hessian_inverse = np.linalg.inv(hessian_matrix())
theta = theta - np.dot(hessian_inverse, gradient_value)
ax.scatter(theta[0], theta[1], objective_function(theta[0], theta[1]), color='red')

plt.show()

在上述示例中,我們定義了一個簡單的二維目標函數以及對應的梯度函數和黑塞矩陣。然后,我們使用matplotlib庫繪制了該函數的三維圖形。接著,我們使用牛頓法迭代更新參數,并在圖中標示出每次迭代后的參數值。通過觀察這些點的變化,可以更直觀地理解牛頓法在參數空間中的搜索過程。

需要注意的是,牛頓法的收斂性和穩定性較好,但在某些情況下可能會受到黑塞矩陣的奇異性和計算復雜度的限制。因此,在實踐中可能會使用牛頓法的一些改進版本,例如擬牛頓法(Quasi-Newton Methods),來克服這些問題。

擬牛頓法(Quasi-Newton Methods),如BFGS、L-BFGS

擬牛頓法用于求解無約束非線性優化問題。它通過逐步近似目標函數的二階導數信息來更新搜索方向和步長,從而實現快速收斂。擬牛頓法的核心思想是使用一個正定矩陣來近似目標函數的Hessian矩陣(二階導數矩陣),從而避免了直接計算Hessian矩陣的復雜性。其中最經典的擬牛頓法包括DFP(Davidon-Fletcher-Powell)BFGS(Broyden-Fletcher-Goldfarb-Shanno)

DFP算法

DFP算法的思想是通過迭代更新一個正定矩陣來近似Hessian矩陣。其迭代公式如下:

BFGS算法

BFGS算法同樣是通過迭代更新一個正定矩陣來近似Hessian矩陣。其迭代公式如下:

以下是一個簡單的示例代碼,在二維平面上繪制目標函數的等高線和擬牛頓法的迭代路徑:

import numpy as np
import plotly.graph_objects as go

# 定義目標函數
def f(x, y):
return x**2 + y**2

# 定義梯度函數
def gradient(x, y):
return np.array([2*x, 2*y])

# 擬牛頓法迭代更新參數
def update_parameter(parameter, approx_hessian, gradient_value):
parameter_delta = -np.dot(approx_hessian, gradient_value)
new_parameter = parameter + parameter_delta
gradient_delta = gradient(new_parameter[0], new_parameter[1]) - gradient_value
rho = 1 / np.dot(gradient_delta, parameter_delta)
outer_product = np.outer(parameter_delta, parameter_delta)
approx_hessian += (rho * outer_product - np.dot(approx_hessian, outer_product) - np.dot(outer_product, approx_hessian)) / rho**2
return new_parameter

# 初始化參數和近似黑塞矩陣
parameter = np.array([8, 8])
approx_hessian = np.eye(2)

# 進行擬牛頓法迭代
num_iterations = 20
path = [parameter]
for i in range(num_iterations):
gradient_value = gradient(parameter[0], parameter[1])
parameter = update_parameter(parameter, approx_hessian, gradient_value)
path.append(parameter)

# 生成等高線數據
x = np.linspace(-10, 10, 100)
y = np.linspace(-10, 10, 100)
X, Y = np.meshgrid(x, y)
Z = f(X, Y)

# 繪制等高線和迭代路徑
fig = go.Figure(data=[
go.Contour(x=x, y=y, z=Z, contours=dict(coloring='lines')),
go.Scatter3d(x=[p[0] for p in path], y=[p[1] for p in path], z=[f(p[0], p[1]) for p in path], mode='markers', marker=dict(size=5))
])

fig.show()

在上述代碼示例中,我們首先定義了一個目標函數f(x, y),它是一個簡單的二次函數。然后,我們生成一組網格點,并計算對應的函數值,以便繪制等高線圖。接下來,我們使用擬牛頓法進行迭代更新參數的過程。在每次迭代中,我們通過調用update_parameter函數來更新參數和近似黑塞矩陣。該函數實現了DFP或BFGS算法中的公式,根據選擇的算法進行參數的更新。在迭代過程中,我們將每次迭代得到的參數保存到path數組中。這樣,我們就可以使用go.Scatter3d繪制擬牛頓法的迭代路徑。go.Scatter3d會將參數在三維空間中的路徑以散點的形式呈現出來。最后,我們使用go.Figure創建一個圖形對象,并將等高線圖和迭代路徑圖添加到其中。通過調用fig.show(),可以在瀏覽器中顯示生成的圖形。

共軛梯度法(Conjugate Gradient)

共軛梯度法是一種常用的無約束優化算法,特別適用于解決大規模線性方程組的求解問題。它利用梯度和殘差的共軛性質,通過迭代尋找最優解。共軛梯度法的基本思想是在每次迭代中選擇一個共軛方向進行搜索,并通過最小化目標函數沿該方向的步長來更新參數。具體而言,假設我們要求解一個二次型目標函數:

共軛梯度法的步驟

自適應學習率優化算法

ADAM(Adaptive Moment Estimation)

ADAM 是一種自適應學習率優化算法,結合了RMSprop和Momentum的優點。在深度學習中廣泛應用,能夠有效地調整學習率,加速模型收斂,并且具有較好的泛化性能。ADAM算法的核心思想是根據梯度的一階矩估計和二階矩估計自適應地調整每個參數的學習率。下面是ADAM算法的公式:

使用Python可以利用plotly庫進行三維繪圖,可以展示優化過程中損失函數在參數空間上的變化情況,以便更直觀地理解ADAM算法的工作原理。舉一個例子:

import plotly.graph_objects as go

# 定義損失函數
def loss_function(x, y):
return x**2 + y**2

# 設置參數空間
theta_range = np.linspace(-5, 5, 100)
X, Y = np.meshgrid(theta_range, theta_range)
Z = loss_function(X, Y)

# 繪制三維圖像
fig = go.Figure(data=[go.Surface(z=Z, x=X, y=Y)])
fig.update_layout(title='Loss Function',
scene=dict(
xaxis_title='Theta1',
yaxis_title='Theta2',
zaxis_title='Loss'))
fig.show()

這段代碼可以繪制出一個損失函數在參數空間中的曲面圖,從而可視化ADAM算法優化過程中參數收斂的情況。

RMSProp(Root Mean Square Propagation)

RMSProp 是一種自適應學習率優化算法,用于調整神經網絡中每個參數的學習率。它通過計算梯度歷史信息的均方根來自適應地調整學習率大小,從而加快模型收斂速度。RMSProp算法的公式如下:

AdaGrad

AdaGrad 是一種自適應學習率優化算法,用于調整神經網絡中每個參數的學習率。它根據梯度的歷史信息來自適應地調整學習率的大小,使得對于經常出現的稀疏特征,其學習率較小,而對于不經常出現的特征,其學習率較大。AdaGrad算法的公式如下:

基于線性規劃的優化算法

線性規劃(Linear Programming)

線性規劃旨在找到一個線性目標函數的最小值或最大值,并滿足一組線性等式和不等式約束條件。線性規劃的一般形式可以表示為:最小化(或最大化)

import numpy as np
import plotly.graph_objects as go

# 定義目標函數和約束條件
def objective_function(x, y):
return 3 * x + 4 * y

def constraint1(x, y):
return x + y - 6

def constraint2(x, y):
return 2 * x + y - 8

# 設置參數空間
x_range = np.linspace(0, 10, 100)
y_range = np.linspace(0, 10, 100)
X, Y = np.meshgrid(x_range, y_range)
Z = objective_function(X, Y)

# 繪制等高線圖
fig = go.Figure(data=[go.Contour(z=Z, x=X, y=Y)])
fig.update_layout(title='Objective Function',
xaxis_title='x',
yaxis_title='y')
fig.show()

使用線性規劃算法,我們可以找到目標函數在約束條件下的最小(或最大)值,并確定使其最小(或最大)的決策變量值。

整數規劃(Integer Programming)

整數規劃是線性規劃的一種擴展形式,在整數規劃中,決策變量被限制為整數值。與線性規劃相比,整數規劃更加復雜且計算上更具挑戰性。整數規劃的一般形式可以表示為:

整數規劃問題通常比線性規劃問題更難求解,因為整數變量的離散性質使得問題空間更大。求解整數規劃問題的方法包括分支定界法(branch and bound)、割平面法(cutting plane method)、混合整數線性規劃(mixed integer linear programming, MILP)等。

具有約束條件的優化算法

條件梯度法(Conditional Gradient Method),也稱為Frank-Wolfe算法

條件梯度法(Method of Constrained Gradients)是一種用于求解具有約束條件的優化問題的數值方法。它結合了梯度下降法和拉格朗日乘子法,通過在梯度方向上進行搜索來找到滿足約束條件的最優解。考慮一個帶有等式約束條件的優化問題:

條件梯度法的基本思想是在每個迭代步驟中,使用拉格朗日乘子法構造一個逼近的目標函數,并沿著該目標函數的負梯度方向更新變量。這樣可以逐步接近原始問題的最優解,并同時滿足約束條件。條件梯度法的迭代步驟如下:

5、如果滿足終止條件(例如達到最大迭代次數或目標函數的收斂性),則停止迭代;否則返回第2步。

通過Python和plotly庫,我們可以繪制優化問題的目標函數在參數空間中的等高線圖,并可視化約束條件。

import numpy as np
import matplotlib.pyplot as plt
import plotly.graph_objects as go

# 定義目標函數和約束條件
def objective_function(x, y):
return x**2 + y**2

def constraint(x, y):
return x - y

# 設置參數空間
x = np.linspace(-10, 10, 100)
y = np.linspace(-10, 10, 100)
X, Y = np.meshgrid(x, y)
Z = objective_function(X, Y)

# 繪制等高線圖
plt.contourf(X, Y, Z, levels=30, cmap='viridis')
plt.colorbar(label='Objective Function')

# 繪制約束條件
plt.contour(X, Y, constraint(X, Y), levels=[0], colors='r')

# 執行條件梯度法迭代過程
x_init = -5.0
y_init = 5.0
alpha = 0.1 # 步長

for _ in range(100):
x_grad = 2 * x_init
y_grad = 2 * y_init

x_init -= alpha * x_grad
y_init -= alpha * y_grad

plt.plot(x_init, y_init, 'bo', markersize=3)

plt.xlabel('x')
plt.ylabel('y')
plt.title('Constrained Optimization with Method of Constrained Gradients')

plt.show()

這段代碼使用numpy庫定義目標函數和約束條件,并使用matplotlib庫繪制出目標函數的等高線圖。通過執行條件梯度法的迭代過程,我們可以在參數空間中看到優化過程的軌跡。

基于投影的優化算法,如投影梯度下降法(Projected Gradient Descent)

基于投影的優化算法(Projected Gradient Algorithm)是一種用于求解具有約束條件的優化問題的方法。它通過在每個迭代步驟中將更新后的變量投影到可行域內來滿足約束條件。考慮一個帶有等式和不等式約束條件的優化問題:

基于投影的優化算法的基本思想是在每個迭代步驟中,計算目標函數的梯度,并根據梯度方向更新變量。然后將更新后的變量投影到可行域內,以滿足約束條件。這樣可以逐步接近原始問題的最優解,并同時滿足約束條件。

基于投影的優化算法的迭代步驟如下:

  1. 如果滿足終止條件(例如達到最大迭代次數或目標函數的收斂性),則停止迭代;否則返回第2步。

具有全局收斂性的優化算法

全局優化算法,如隨機搜索、模擬退火、遺傳算法等

具有全局收斂性的優化算法是用于求解全局最優解的優化算法。咱們這里用隨機搜索來舉例,是其中一種簡單但非常直觀的全局優化算法,它通過在搜索空間中隨機采樣候選解來尋找最優解。隨機搜索是一種簡單而直接的全局優化算法,它不依賴于梯度信息,而是通過在搜索空間中隨機采樣來探索可能的解。其基本流程如下:

隨機搜索的公式詳解可以表示為:

隨機搜索算法的優點是易于實現和理解,適用于沒有顯式表達式或梯度信息的目標函數。

然而,由于其隨機性,它可能需要更多的采樣次數才能達到較好的結果。

舉個例子:

import numpy as np
import plotly.graph_objects as go

# 定義目標函數
def objective_function(x, y):
return np.sin(x) + np.cos(y)

# 生成網格點
x = np.linspace(-5, 5, 100)
y = np.linspace(-5, 5, 100)
X, Y = np.meshgrid(x, y)
Z = objective_function(X, Y)

# 隨機搜索
num_iterations = 100
best_solution = None
best_fitness = float('inf')

for _ in range(num_iterations):
# 隨機采樣候選解
candidate_solution = [np.random.uniform(-5, 5), np.random.uniform(-5, 5)]

# 計算目標函數值
fitness = objective_function(candidate_solution[0], candidate_solution[1])

# 更新最優解
if fitness < best_fitness:
best_solution = candidate_solution
best_fitness = fitness

# 繪制三維圖像
fig = go.Figure(data=[go.Surface(x=X, y=Y, z=Z)])
fig.add_trace(go.Scatter3d(x=[best_solution[0]], y=[best_solution[1]], z=[best_fitness],
mode='markers', marker=dict(size=5, color='red')))
fig.update_layout(title='Objective Function with Best Solution from Random Search', autosize=False,
width=700, height=500, scene=dict(
xaxis_title='X',
yaxis_title='Y',
zaxis_title='Z'
))
fig.show()

首先定義了目標函數,然后生成網格點用于繪制曲面圖。在隨機搜索中,通過隨機采樣候選解,并計算其對應的目標函數值。然后,更新最優解,如果發現更好的解。最后,將最優解以紅色點的形式添加到三維圖中。

最后

今天介紹了最優化算法有一階優化算法、二階優化算法、自適應學習率優化算法、基于線性規劃的優化算法、具有約束條件的優化算法、具有全局收斂性的優化算法等。

文章轉自微信公眾號@深夜努力寫Python

上一篇:

使用kimi.ai API Key 密鑰快速接入Kimi智能助手的完整指南

下一篇:

Keras:深度學習的高級接口,讓模型訓練更快捷!
#你可能也喜歡這些API文章!

我們有何不同?

API服務商零注冊

多API并行試用

數據驅動選型,提升決策效率

查看全部API→
??

熱門場景實測,選對API

#AI文本生成大模型API

對比大模型API的內容創意新穎性、情感共鳴力、商業轉化潛力

25個渠道
一鍵對比試用API 限時免費

#AI深度推理大模型API

對比大模型API的邏輯推理準確性、分析深度、可視化建議合理性

10個渠道
一鍵對比試用API 限時免費