演算法動態圖
㈠ 機器學習中有哪些重要的優化演算法
梯度下降是非常常用的優化演算法。作為機器學習的基礎知識,這是一個必須要掌握的演算法。藉助本文,讓我們來一起詳細了解一下這個演算法。
前言
本文的代碼可以到我的Github上獲取:
https://github.com/paulQuei/gradient_descent
本文的演算法示例通過Python語言實現,在實現中使用到了numpy和matplotlib。如果你不熟悉這兩個工具,請自行在網上搜索教程。
關於優化
大多數學習演算法都涉及某種形式的優化。優化指的是改變x以最小化或者最大化某個函數的任務。
我們通常以最小化指代大多數最優化問題。最大化可經由最小化來實現。
我們把要最小化或最大化的函數成為目標函數(objective function)或准則(criterion)。
我們通常使用一個上標*表示最小化或最大化函數的x值,記做這樣:
[x^* = arg; min; f(x)]
優化本身是一個非常大的話題。如果有興趣,可以通過《數值優化》和《運籌學》的書籍進行學習。
模型與假設函數
所有的模型都是錯誤的,但其中有些是有用的。– George Edward Pelham Box
模型是我們對要分析的數據的一種假設,它是為解決某個具體問題從老洞數據中學習到的,因此它是機器學習最核心的概念。
針對一個問題,通常有大量的模型可以選擇。
本文不會深入討論這方面的內容,關於各種模型請參閱機器學習的相關書籍。本文僅以最簡單的線性模型為基礎來討論梯度下降演算法。
這里我們先介紹一下在監督學習(supervised learning)中常見的三個符號:
m,描述訓練樣本的數量
x,描述輸入變數或特徵
y,描述輸出變數或者叫目標值
- 請注意,一個樣本笑或可能有很多的特徵,因此x和y通常是一個向量。不過在剛開始學習的時候,為了便於理解,你可以暫時理解為這就是一個具體的數值。
- 代價函數也叫損失函數。
- 不同的模型可能會用不同的損失函數。例如,logistic回歸的假設函數是這樣的:。其代價函數是這樣的:
對於一個函數,怎麼確定下行的方向?
每一步該往前走多遠?
有沒有可能停留在半山腰的平台上?
- 這里的下標i表示第i個參數。 上標k指的是第k步的計算結果,而非k次方。在能夠理解的基礎上,下文的公式中將省略上標k。
收斂是指函數的變化率很小。具體選擇多少合適需要根據具體的項目來確定。在演示項目中我們可以選擇0.01或者0.001這樣的值。不同的值將影響演算法的迭代次數,因為在梯度下降的最後,我們會越來越接近平坦的地方,這個時候函數的變化率也越來越小。如果選擇一個很小的值,將可能導致演算法迭代次數暴增。
公式中的 稱作步長,也稱作學習率(learning rate)。它決定了每一步往前走多遠,關於這個值我們會在下文中詳細講解。你可以暫時人為它是一個類似0.01或0.001的固定值。
在具體的項目,我們不會讓演算法無休止的運行下去,所以通常會設置一個迭代次數的最大上限。
我們隨機選擇了 都為10作為起點
設置最多迭代1000次
收斂的范圍設為0.001
學習步長設為0.01
如果樣本數量較小(例如小於等於2000),選擇BGD即可。
如果樣本數量很大,選擇 來進行MBGD,例如:64,128,256,512。
- 《深度學習》一書中是這樣描述的:「與其說是科學,這更像是一門藝術,我們應該謹慎地參考關於這個問題的大部分指導。」。
對於凸函數或者凹函數來說,不存在局部極值的問題。其局部極值一定是全局極值。
最近的一些研究表明,某些局部極值並沒有想像中的那麼糟糕,它們已經非常的接近全局極值所帶來的結果了。
Wikipeida: Gradient descent
Sebastian Ruder: An overview of gradient descent optimization algorithms
吳恩達:機器學習
吳恩達:深度學習
Peter Flach:機器學習
李宏毅 - ML Lecture 3-1: Gradient Descent
PDF: 李宏毅 - Gradient Descent
Intro to optimization in deep learning: Gradient Descent
Intro to optimization in deep learning: Momentum, RMSProp and Adam
Stochastic Gradient Descent – Mini-batch and more
劉建平Pinard - 梯度下降(Gradient Descent)小結
多元函數的偏導數、方向導數、梯度以及微分之間的關系思考
[Machine Learning] 梯度下降法的三種形式BGD、SGD以及MBGD
- 作者:阿Paul https://paul.pub/gradient-descent/
訓練集會包含很多的樣本,我們用 表示其中第i個樣本。
x是數據樣本的特徵,y是其目標值。例如,在預測房價的模型中,x是房子的各種信息,例如:面積,樓層,位置等等,y是房子的價格。在圖像識別的任務中,x是圖形的所有像素點數據,y是圖像中包含的目標對象。
我們是希望尋找一個函數,將x映射到y,這個函數要足夠的好,以至於能夠預測對應的y。由於歷史原因,這個函數叫做假設函數(hypothesis function)。
學習的過程如下圖所示。即:首先根據已有的數據(稱之為訓練集)訓練我們的演算法模型,然後根據模型的假設函數來進行新數據的預測。
線性模型(linear model)正如其名稱那樣:是希望通過一個直線的形式來描述模式。線性模型的假設函數如下所示:
[h_{ heta}(x) = heta_{0} + heta_{1} * x]
這個公式對於大家來說應該都是非常簡單的。如果把它繪制出來,其實就是一條直線。
下圖是一個具體的例子,即: 的圖形:
在實際的機器學習工程中碰含伍,你會擁有大量的數據。這些數據會來自於某個數據源。它們存儲在csv文件中,或者以其他的形式打包。
但是本文作為演示使用,我們通過一些簡單的代碼自動生成了需要的數據。為了便於計算,演示的數據量也很小。
import numpy as np
max_x = 10
data_size = 10
theta_0 = 5
theta_1 = 2
def get_data:
x = np.linspace(1, max_x, data_size)
noise = np.random.normal(0, 0.2, len(x))
y = theta_0 + theta_1 * x + noise
return x, y
這段代碼很簡單,我們生成了x范圍是 [1, 10] 整數的10條數據。對應的y是以線性模型的形式計算得到,其函數是:。現實中的數據常常受到各種因素的干擾,所以對於y我們故意加上了一些高斯雜訊。因此最終的y值為比原先會有輕微的偏離。
最後我們的數據如下所示:
x = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
y = [6.66, 9.11, 11.08, 12.67, 15.12, 16.76, 18.75, 21.35, 22.77, 24.56]
我們可以把這10條數據繪制出來這樣就有一個直觀的了解了,如下圖所示:
雖然演示用的數據是我們通過公式計算得到的。但在實際的工程中,模型的參數是需要我們通過數據學習到的。所以下文我們假設我們不知道這里線性模式的兩個參數是什麼,而是通過演算法的形式求得。
最後再跟已知的參數進行對比以驗證我們的演算法是否正確。
有了上面的數據,我們可以嘗試畫一條直線來描述我們的模型。
例如,像下面這樣畫一條水平的直線:
很顯然,這條水平線離數據太遠了,非常的不匹配。
那我們可以再畫一條斜線。
我們初次畫的斜線可能也不貼切,它可能像下面這樣:
最後我們通過不斷嘗試,找到了最終最合適的那條,如下所示:
梯度下降演算法的計算過程,就和這種本能式的試探是類似的,它就是不停的迭代,一步步的接近最終的結果。
代價函數
上面我們嘗試了幾次通過一條直線來擬合(fitting)已有的數據。
二維平面上的一條直線可以通過兩個參數唯一的確定,兩個參數的確定也即模型的確定。那如何描述模型與數據的擬合程度呢?答案就是代價函數。
代價函數(cost function)描述了學習到的模型與實際結果的偏差程度。以上面的三幅圖為例,最後一幅圖中的紅線相比第一條水平的綠線,其偏離程度(代價)應該是更小的。
很顯然,我們希望我們的假設函數與數據盡可能的貼近,也就是說:希望代價函數的結果盡可能的小。這就涉及到結果的優化,而梯度下降就是尋找最小值的方法之一。
對於每一個樣本,假設函數會依據計算出一個估算值,我們常常用來表示。即 。
很自然的,我們會想到,通過下面這個公式來描述我們的模型與實際值的偏差程度:
[(h_ heta(x^i) - y^i)^2 = (widehat{y}^{i} - y^i)^2 = ( heta_{0} + heta_{1} * x^{i} - y^{i})^2]
請注意, 是實際數據的值, 是我們的模型的估算值。前者對應了上圖中的離散點的y坐標,後者對應了離散點在直線上投影點的y坐標。
每一條數據都會存在一個偏差值,而代價函數就是對所有樣本的偏差求平均值,其計算公式如下所示:
[L( heta) = frac {1}{m} sum_{i=1}^{m}(h_ heta(x^i) - y^i)^2 = frac {1}{m} sum_{i=1}^{m}( heta_{0} + heta_{1} * x^{i} - y^{i})^2]
當損失函數的結果越小,則意味著通過我們的假設函數估算出的結果與真實值越接近。這也就是為什麼我們要最小化損失函數的原因。
藉助上面這個公式,我們可以寫一個函數來實現代價函數:
def cost_function(x, y, t0, t1):
cost_sum = 0
for i in range(len(x)):
cost_item = np.power(t0 + t1 * x[i] - y[i], 2)
cost_sum += cost_item
return cost_sum / len(x)
這個函數的代碼應該不用多做解釋,它就是根據上面的完成計算。
我們可以嘗試選取不同的 和 組合來計算代價函數的值,然後將結果繪制出來:
import numpy as np
import matplotlib.pyplot as plt
from matplotlib import cm
from mpl_toolkits.mplot3d import Axes3D
theta_0 = 5
theta_1 = 2
def draw_cost(x, y):
fig = plt.figure(figsize=(10, 8))
ax = fig.gca(projection='3d')
scatter_count = 100
radius = 1
t0_range = np.linspace(theta_0 - radius, theta_0 + radius, scatter_count)
t1_range = np.linspace(theta_1 - radius, theta_1 + radius, scatter_count)
cost = np.zeros((len(t0_range), len(t1_range)))
for a in range(len(t0_range)):
for b in range(len(t1_range)):
cost[a][b] = cost_function(x, y, t0_range[a], t1_range[b])
t0, t1 = np.meshgrid(t0_range, t1_range)
ax.set_xlabel('theta_0')
ax.set_ylabel('theta_1')
ax.plot_surface(t0, t1, cost, cmap=cm.hsv)
在這段代碼中,我們對 和 各自指定了一個范圍進行100次的采樣,然後以不同的 組合對來計算代價函數的值。
如果我們將所有點的代價函數值繪制出來,其結果如下圖所示:
從這個圖形中我們可以看出,當 越接近 [5, 2]時其結果(偏差)越小。相反,離得越遠,結果越大。
直觀解釋
從上面這幅圖中我們可以看出,代價函數在不同的位置結果大小不同。
從三維的角度來看,這就和地面的高低起伏一樣。最高的地方就好像是山頂。
而我們的目標就是:從任意一點作為起點,能夠快速尋找到一條路徑並以此到達圖形最低點(代價值最小)的位置。
而梯度下降的演算法過程就和我們從山頂想要快速下山的做法是一樣的。
在生活中,我們很自然會想到沿著最陡峭的路往下行是下山速度最快的。如下面這幅圖所示:
針對這幅圖,細心的讀者可能很快就會有很多的疑問,例如:
這些問題也就是本文接下來要討論的內容。
演算法描述
梯度下降演算法最開始的一點就是需要確定下降的方向,即:梯度。
我們常常用 來表示梯度。
對於一個二維空間的曲線來說,梯度就是其切線的方向。如下圖所示:
而對於更高維空間的函數來說,梯度由所有變數的偏導數決定。
其表達式如下所示:
[ abla f({ heta}) = ( frac{partial f({ heta})}{partial heta_1} , frac{partial f({ heta})}{partial heta_2} , ... , frac{partial f({ heta})}{partial heta_n} )]
在機器學習中,我們主要是用梯度下降演算法來最小化代價函數,記做:
[ heta ^* = arg min L( heta)]
其中,L是代價函數,是參數。
梯度下降演算法的主體邏輯很簡單,就是沿著梯度的方向一直下降,直到參數收斂為止。
記做:
[ heta ^{k + 1}_i = heta^{k}_i - lambda abla f( heta^{k})]
這里有幾點需要說明:
線性回歸的梯度下降
有了上面的知識,我們可以回到線性模型代價函數的梯度下降演算法實現了。
首先,根據代價函數我們可以得到梯度向量如下:
[ abla f({ heta}) = (frac{partial L( heta)}{ partial heta_{0}}, frac{ partial L( heta)}{ partial heta_{1}}) = (frac {2}{m} sum_{i=1}^{m}( heta_{0} + heta_{1} * x^{i} - y^{i}) , frac {2}{m} sum_{i=1}^{m}( heta_{0} + heta_{1} * x^{i} - y^{i}) x^{i})]
接著,將每個偏導數帶入迭代的公式中,得到:
[ heta_{0} := heta_{0} - lambda frac{partial L( heta_{0})}{ partial heta_{0}} = heta_{0} - frac {2 lambda }{m} sum_{i=1}^{m}( heta_{0} + heta_{1} * x^{i} - y^{i}) heta_{1} := heta_{1} - lambda frac{partial L( heta_{1})}{ partial heta_{1}} = heta_{1} - frac {2 lambda }{m} sum_{i=1}^{m}( heta_{0} + heta_{1} * x^{i} - y^{i}) x^{i}]
由此就可以通過代碼實現我們的梯度下降演算法了,演算法邏輯並不復雜:
learning_rate = 0.01
def gradient_descent(x, y):
t0 = 10
t1 = 10
delta = 0.001
for times in range(1000):
sum1 = 0
sum2 = 0
for i in range(len(x)):
sum1 += (t0 + t1 * x[i] - y[i])
sum2 += (t0 + t1 * x[i] - y[i]) * x[i]
t0_ = t0 - 2 * learning_rate * sum1 / len(x)
t1_ = t1 - 2 * learning_rate * sum2 / len(x)
print('Times: {}, gradient: [{}, {}]'.format(times, t0_, t1_))
if (abs(t0 - t0_) < delta and abs(t1 - t1_) < delta):
print('Gradient descent finish')
return t0_, t1_
t0 = t0_
t1 = t1_
print('Gradient descent too many times')
return t0, t1
這段代碼說明如下:
如果我們將演算法迭代過程中求得的線性模式繪制出來,可以得到下面這幅動態圖:
最後演算法得到的結果如下:
Times: 657, gradient: [5.196562662718697, 1.952931052920264]
Times: 658, gradient: [5.195558390180733, 1.9530753071808193]
Times: 659, gradient: [5.194558335124868, 1.9532189556399233]
Times: 660, gradient: [5.193562479839619, 1.9533620008416623]
Gradient descent finish
從輸出中可以看出,演算法迭代了660次就收斂了。這時的結果[5.193562479839619, 1.9533620008416623],這已經比較接近目標值 [5, 2]了。如果需要更高的精度,可以將delta的值調的更小,當然,此時會需要更多的迭代次數。
高維擴展
雖然我們舉的例子是二維的,但是對於更高維的情況也是類似的。同樣是根據迭代的公式進行運算即可:
[ heta_{i} = heta_{i} - lambda frac {partial L( heta)}{partial heta_i} = heta_{i} - frac{2lambda}{m} sum_{i=1}^{m}(h_ heta(x^{k})-y^k)x_i^k]
這里的下標i表示第i個參數,上標k表示第k個數據。
梯度下降家族BGD
在上面的內容中我們看到,演算法的每一次迭代都需要把所有樣本進行遍歷處理。這種做法稱為之Batch Gradient Descent,簡稱BGD。作為演示示例只有10條數據,這是沒有問題的。
但在實際的項目中,數據集的數量可能是幾百萬幾千萬條,這時候每一步迭代的計算量就會非常的大了。
於是就有了下面兩個變種。
SGD
Stochastic Gradient Descent,簡稱SGD,這種演算法是每次從樣本集中僅僅選擇一個樣本來進行計算。很顯然,這樣做演算法在每一步的計算量一下就少了很多。
其演算法公式如下:
[ heta_{i} = heta_{i} - lambda frac {partial L( heta)}{partial heta_i} = heta_{i} - lambda(h_ heta(x^k)-y^k)x_i^k]
當然,減少演算法計算量也是有代價的,那就是:演算法結果會強依賴於隨機取到的數據情況,這可能會導致演算法的最終結果不太令人滿意。
MBGD
以上兩種做法其實是兩個極端,一個是每次用到了所有數據,另一個是每次只用一個數據。
我們自然就會想到兩者取其中的方法:每次選擇一小部分數據進行迭代。這樣既避免了數據集過大導致每次迭代計算量過大的問題,也避免了單個數據對演算法的影響。
這種演算法稱之為Mini-batch Gradient Descent,簡稱MBGD。
其演算法公式如下:
[ heta_{i} = heta_{i} - lambda frac {partial L( heta)}{partial heta_i} = heta_{i} - frac{2lambda}{m} sum_{i=a}^{a + b}(h_ heta(x^k)-y^k)x_i^k]
當然,我們可以認為SGD是Mini-batch為1的特例。
針對上面提到的演算法變種,該如何選擇呢?
下面是Andrew Ng給出的建議:
下表是 Optimization for Deep Learning 中對三種演算法的對比
方法准確性更新速度內存佔用在線學習BGD好慢高否SGD好(with annealing)快低是MBGD好中等中等是
演算法優化
式7是演算法的基本形式,在這個基礎上有很多人進行了更多的研究。接下來我們介紹幾種梯度下降演算法的優化方法。
Momentum
Momentum是動量的意思。這個演算法的思想就是藉助了動力學的模型:每次演算法的迭代會使用到上一次的速度作為依據。
演算法的公式如下:
[v^t = gamma v^{t - 1} + lambda abla f( heta) heta = heta - v_t]
對比式7可以看出,這個演算法的主要區別就是引入了,並且,每個時刻的受前一個時刻的影響。
從形式上看,動量演算法引入了變數 v 充當速度角色——它代表參數在參數空間移動的方向和速率。速度被設為負梯度的指數衰減平均。名稱動量來自物理類比,根據牛頓運動定律,負梯度是移動參數空間中粒子的力。動量在物理學上定義為質量乘以速度。在動量學習演算法中,我們假設是單位質量,因此速度向量 v 也可以看作是粒子的動量。
對於可以取值0,而是一個常量,設為0.9是一個比較好的選擇。
下圖是momentum演算法的效果對比:
對原來的演算法稍加修改就可以增加動量效果:
def gradient_descent_with_momentum(x, y):
t0 = 10
t1 = 10
delta = 0.001
v0 = 0
v1 = 0
gamma = 0.9
for times in range(1000):
sum1 = 0
sum2 = 0
for i in range(len(x)):
sum1 += (t0 + t1 * x[i] - y[i])
sum2 += (t0 + t1 * x[i] - y[i]) * x[i]
v0 = gamma * v0 + 2 * learning_rate * sum1 / len(x)
v1 = gamma * v1 + 2 * learning_rate * sum2 / len(x)
t0_ = t0 - v0
t1_ = t1 - v1
print('Times: {}, gradient: [{}, {}]'.format(times, t0_, t1_))
if (abs(t0 - t0_) < delta and abs(t1 - t1_) < delta):
print('Gradient descent finish')
return t0_, t1_
t0 = t0_
t1 = t1_
print('Gradient descent too many times')
return t0, t1
以下是該演算法的輸出:
Times: 125, gradient: [4.955453758569991, 2.000005017897775]
Times: 126, gradient: [4.955309381126545, 1.9956928964532015]
Times: 127, gradient: [4.9542964317327005, 1.9855674828684156]
Times: 128, gradient: [4.9536358220657, 1.9781180992510465]
Times: 129, gradient: [4.95412496254411, 1.9788858350530971]
Gradient descent finish
從結果可以看出,改進的演算法只用了129次迭代就收斂了。速度比原來660次快了很多。
同樣的,我們可以把演算法計算的過程做成動態圖:
對比原始的演算法過程可以看出,改進演算法最大的區別是:在尋找目標值時會在最終結果上下跳動,但是越往後跳動的幅度越小,這也就是動量所產生的效果。
Learning Rate 優化
至此,你可能還是好奇該如何設定學習率的值。
事實上,這個值的選取需要一定的經驗或者反復嘗試才能確定。
關鍵在於,這個值的選取不能過大也不能過小。
如果這個值過小,會導致每一次迭代的步長很小,其結果就是演算法需要迭代非常多的次數。
那麼,如果這個值過大會怎麼樣呢?其結果就是:演算法可能在結果的周圍來回震盪,卻落不到目標的點上。下面這幅圖描述了這個現象:
事實上,學習率的取值未必一定要是一個常數,關於這個值的設定有很多的研究。
下面是比較常見的一些改進演算法。
AdaGrad
AdaGrad是Adaptive Gradient的簡寫,該演算法會為每個參數設定不同的學習率。它使用歷史梯度的平方和作為基礎來進行計算。
其演算法公式如下:
[ heta_i = heta_i - frac{lambda}{sqrt{G_t + epsilon}} abla f( heta)]
對比式7,這里的改動就在於分號下面的根號。
根號中有兩個符號,第二個符號比較好理解,它就是為了避免除0而人為引入的一個很小的常數,例如可以設為:0.001。
第一個符號的表達式展開如下:
[G_t = sum_{i = 1}^{t} abla f( heta){i} abla f( heta){i}^{T}]
這個值其實是歷史中每次梯度的平方的累加和。
AdaGrad演算法能夠在訓練中自動的對learning rate進行調整,對於出現頻率較低參數採用較大的學習率;相反,對於出現頻率較高的參數採用較小的學習率。因此,Adagrad非常適合處理稀疏數據。
但該演算法的缺點是它可能導致學習率非常小以至於演算法收斂非常的慢。
關於這個演算法的直觀解釋可以看李宏毅教授的視頻課程:ML Lecture 3-1: Gradient Descent。
RMSProp
RMS是Root Mean Square的簡寫。RMSProp是AI教父Geoff Hinton提出的一種自適應學習率方法。AdaGrad會累加之前所有的梯度平方,而RMSProp僅僅是計算對應的平均值,因此可緩解Adagrad演算法學習率下降較快的問題。
該演算法的公式如下:
[E[ abla f( heta_{i})^2]^{t} = gamma E[ abla f( heta_{i})^2]^{t - 1} + (1-gamma)( abla f( heta_{i})^{t})^{2} heta_i = heta_i - frac{lambda}{sqrt{E[g^2]^{t+1} + epsilon}} abla f( heta_{i})]
類似的,是為了避免除0而引入。 是衰退參數,通常設為0.9。
這里的 是t時刻梯度平方的平均值。
Adam
Adam是Adaptive Moment Estimation的簡寫。它利用梯度的一階矩估計和二階矩估計動態調整每個參數的學習率。
Adam的優點主要在於經過偏置校正後,每一次迭代學習率都有個確定范圍,使得參數比較平穩。
該演算法公式如下:
[m^{t} = eta_{1} m^{t-1} + (1-eta_{1}) abla f( heta) v^{t} = eta_{2} v^{t-1} + (1-eta_{2}) abla f( heta)^2 widehat{m}^{t} = frac{m^{t}}{1 - eta^{t}_1} widehat{v}^{t} = frac{v^{t}}{1 - eta^{t}_2} heta = heta - frac{lambda}{sqrt{widehat{v}^{t}} + epsilon}widehat{m}^{t}]
,分別是對梯度的一階矩估計和二階矩估計。, 是對,的校正,這樣可以近似為對期望的無偏估計。
Adam演算法的提出者建議 默認值為0.9,默認值為0.999,默認值為 。
在實際應用中 ,Adam較為常用,它可以比較快地得到一個預估結果。
優化小結
這里我們列舉了幾種優化演算法。它們很難說哪種最好,不同的演算法適合於不同的場景。在實際的工程中,可能需要逐個嘗試一下才能確定選擇哪一個,這個過程也是目前現階段AI項目要經歷的工序之一。
實際上,該方面的研究遠不止於此,如果有興趣,可以繼續閱讀 《Sebastian Ruder: An overview of gradient descent optimization algorithms》 這篇論文或者 Optimization for Deep Learning 這個Slides進行更多的研究。
由於篇幅所限,這里不再繼續展開了。
演算法限制
梯度下降演算法存在一定的限制。首先,它要求函數必須是可微分的,對於不可微的函數,無法使用這種方法。
除此之外,在某些情況下,使用梯度下降演算法在接近極值點的時候可能收斂速度很慢,或者產生Z字形的震盪。這一點需要通過調整學習率來迴避。
另外,梯度下降還會遇到下面兩類問題。
局部最小值
局部最小值(Local Minima)指的是,我們找到的最小值僅僅是一個區域內的最小值,而並非全局的。由於演算法的起點是隨意取的,以下面這個圖形為例,我們很容易落到局部最小值的點裡面。
這就是好像你從上頂往下走,你第一次走到的平台未必是山腳,它有可能只是半山腰的一個平台的而已。
演算法的起點決定了演算法收斂的速度以及是否會落到局部最小值上。
壞消息是,目前似乎沒有特別好的方法來確定選取那個點作為起點是比較好的,這就有一點看運氣的成分了。多次嘗試不同的隨機點或許是一個比較好的方法,這也就是為什麼做演算法的優化這項工作是特別消耗時間的了。
但好消息是:
鞍點
除了Local Minima,在梯度下降的過程中,還有可能遇到另外一種情況,即:鞍點(Saddle Point)。鞍點指的是我們找到點某個點確實是梯度為0,但它卻不是函數的極值,它的周圍既有比它小的值,也有比它大的值。這就好像馬鞍一樣。
如下圖所示:
多類隨機函數表現出以下性質:在低維空間中,局部極值很普遍。但在高維空間中,局部極值比較少見,而鞍點則很常見。
不過對於鞍點,可以通過數學方法Hessian矩陣來確定。關於這點,這里就不再展開了,有興趣的讀者可以以這里提供的幾個鏈接繼續探索。
參考資料與推薦讀物
㈡ 動態圖上的異常檢測文獻綜述(2015)
動態圖上的異常檢測任務包括:發現異常的對象、關系、時點。動態圖上的異常檢測與靜態圖上的異常檢測不同的地方在於:
本文首先將異常類型分為:anomalous vertices, edges, subgraphs, and events(or change),將使用的方法分為:community detection, MDL(minimum description length) and compression, decompression, distance, probabilistic, 按每種方法使用的異常類型進行了文獻學分類。各方法的主要參考文獻見表1:
本文假設不同時點的節點和邊都有唯一標簽從而不會混淆,定義 為圖序列,其中 為總時間步, , 為節點集, 為邊集, 時稱 為圖流。本文的主要記號見表2:
給定 ,節點集 ,打分函數 ,定義異常節點集為 ,使得對於 , ,其中 為得分 的摘要式統計。
一個典型的異常節點如圖1,其可由基於社區檢測的方法識別,即: 其中 為節點所屬的社會劃分, 為異或操作。
給定 ,邊集 ,打分函數 ,定義異常邊集為 ,使得對於 , ,其中 為得分 的摘要式統計。
一個典型的異常邊如圖2,可令 ,其中 為時間步 時 的權重,可以為邊的概率。
給定 ,子圖集 ,打分函數 ,定義異常集為 ,使得對於 , ,其中 為得分 的摘要式統計。
兩種典型的異常子圖如圖3,其中(a)為圖的收縮,(b)為圖的分裂。圖的收縮可根據子圖中的的數量衡量,即 ,圖的分裂可由不同時間點社區的數量衡量。
與異常節點、邊、子圖檢測不同,異常事件或異常突變檢測檢驗的是時點。
給定 ,打分函數 ,若時點 滿足: , ,則稱時點 為一個事件。
給定 ,打分函數 ,若時點 滿足: , ,則稱時點 為一個突變。
通常的異常檢測都使用兩步法:第一步,基於特徵的圖表示;第二,基於機器學習的異常檢測。
基於社區檢測的方法關注的是社區和關聯節點的演化過程,特徵向量的生成亦基於圖中的社區結構。不同社區檢測方法的區別在於:(1)社區結構的領域,如社區內的連接性v.s.單個節點在每一步所屬的社區;(2)社區結構的定義,如基於概率的軟社區定義v.s.硬社區定義。基於社區檢測的方法可用於異常定點、子圖、突變的檢測。
基於軟社區匹配並單獨考察每一個社區,我們可以在連續時間步內計算每個節點歸屬的平均變化,如果某個節點歸屬的平均變化顯著異於其他節點,則稱其為演化社區異常點。
節點社區歸屬的變化可以構造一個時間模式,稱為軟時序模式。一些文獻使用了最小描述長度(MDL)結合非負矩陣分解的方法來自動檢測節點角色及構造轉移模型。多數文獻通過抽取圖中不同節點的共同模式,並比較每個節點與共同模式之間的差異來定義異常節點。部分文獻使用了交替迭代優化替代常用的兩步法。部分文獻使用了corenet的概念,該概念不同於單純使用density,molarity,hop-distance等概念,而是使用了節點間的加權路徑,即一個節點的corenet包含該節點與權重大於給定閾值的兩跳鄰居。假設兩個強連接的節點通常屬於同一社區,則如果移除一個節點的兩個鄰居,一個鄰域具有較高的邊權重,另一個具有較低的邊權重,則移除較高權重鄰居的影響應更大,在每一步,每個節點首先被賦予一個異常得分,該得分衡量了其corenet的變化,異常得分較高的 各節點將被視為異常節點。
文獻【69】定義了六種基於社區的異常:shrink, grow, merge, split, born, and vanish。其使用圖和社區代表(representatives)進行比較以減少計算量,圖代表為出現在t時刻,同時還出現在t-1、t+1或t+1與t-1時刻的節點集,社區代表是出現在其他社區最少的定點集合,基於社區代表和圖代表,基於規則,判斷社區是否落在六種異常中。
文獻【73】定義了一種基於社區的異常:comet,周期性出現或消失的社區,演化圖可表示為一個張量,然後基於低秩張量分解和MDL原則進行comet檢測。
文獻【3】基於多種信息源構造時序復網路,識別跨時間和網路的穩定社區結構。行為相似的網路可以用聚類或前驗知識分組,如何一個社區結構在組內跨時間步穩定,但在組外沒有對應社區,則該社區即為異常,如何兩個社區共享一定比例的定點則稱為對應。
社交網路可以根據特定時間窗口內的發文量定義事件,一個經歷共同事件的組即構成一個異常子圖。
通過劃分圖流為一致的分割來檢測,分割是依據劃分的相似性。
通過將最新圖的頂點分區與當前增長分割中的圖的分區進行比較,可以在線找到這些分割。【67】基於可返回隨機的相關矩陣和molarity最大化來進行定點劃分,當新圖的劃分與當前分割的劃分有很大不同時,一個新段開始,並將新圖的時間點輸出為檢測到的突變。兩個劃分的相似度使用Jaccard系數定義。GraphScope思路類似,但基於MDL來指導劃分和分割。
基於MDL原則和基於該原則的壓縮技術利用數據中的模式和規律性實現緊湊的圖表示,其主要通過將圖的鄰接矩陣表示為一個二進制串,如果矩陣的行和列可以重新排列使矩陣的二進制字元串表示的熵最小化,那麼壓縮損失(也稱為編碼損失)就會最小化。數據指向的特徵都來自於圖或其特定子結構的編碼代價;因此,異常被定義為抑制可壓縮性的圖或子結構(如邊)
對於一條邊和對應子圖,如果包含該邊的編碼損失比不包含該邊的編碼損失高,則稱該邊為異常邊。
【74】使用了一種兩步交替迭代法進行節點的自動劃分,當節點劃分的熵收斂時,根據包含和不包含該邊的編碼損失,該方法也給出了邊的異常度得分。
突變檢測的主要思路是:連續時間步間的圖是相似的,因而可以分為一組,從而降低壓縮比。壓縮比的上升表明新一個時間步的圖與已有的圖差異明顯,因此是一個突變。
該方法將圖集合表示為一個tensor,在該tensor上進行矩陣分解或降維,基於分解或降維後的圖發現其模式和規律性,該方法可以融合更多屬性信息,最常用的方法是SVD和PARAFAC(廣義SVD)。
矩陣分解可用於計算每個節點的活躍(activity)向量,如果某個節點的活躍向量在連續時間步間變化明顯,則稱為異常節點。
【87】首先抽取每個節點的邊相關矩陣 ,即該節點的每個鄰域都有一行一列,對於節點 的矩陣中的一個entry 代表了邊 和 間加權頻率的相關性,加權頻率由衰減函數獲得,時間越近權重越高。M的最大特徵值和對應特徵向量即頂點的活躍向量的summary及邊的相關性。通過尋找這些值的變化而形成的時間序列用於計算每個時間步長中每個頂點的分數,得分高於閾值的頂點將被輸出為異常。
基於分解的異常事件檢測有兩種方法:(1)先基於分解方法來近似原始數據,然後以重建損失作為近似優劣的指標。如果某個子張量、切片或元素的重建損失很高,則即可以視其與周圍數據不同特徵不同,將其標記為異常事件、子圖或節點。(2)跟蹤奇異值和向量,以及特徵值和特徵向量,以檢測異常頂點的顯著變化。
為解決 intermediate blowup 問題(即計算中輸入和輸出張量超過內存限制),【81】提出了momery-efficient tucker(MET)分解方法,該方法源於Tucker分解,Tucker分解將高階tensor用一個core tensor和每個mode(維度)矩陣表示。【80】使用了Compact Matrix Decomposition(CMD),其可以用來計算給定矩陣的稀疏低秩矩陣。使用CMD對圖流中的每個鄰接矩陣進行分解,可得到重建值的時間序列,基於重建值序列可進程事件檢測,典型應用有COLIBRI, PARCUBE,其中後者在斑點(spotting)異常中的表現更高效。
【84】使用了隨機圖模型進行基於概率模型的檢測,其將真實圖鄰接矩陣和期望圖的鄰接矩陣間的差異構造為殘差矩陣,對殘差矩陣執行SVD,再使用線性Ramp濾波器,基於top奇異值即可進行異常時間窗口檢測,通過檢查正確的奇異向量來確定相應的頂點。
除以上方法,我們還可以基於分解空間的顯著變化來識別事件。【77】通過對數據執行PCA,計算的特徵向量可以分為正常和異常兩個集合,方法是檢驗數據中的值映射到特徵向量。在每個時間步,根據特徵值對特徵向量進程降序排列,第一個特徵向量則包含一個在其餘值的3個標准差之外的投影點,此後的每個特徵向量,都構成了異常集。第二步即是將數據映射到正常和異常子空間,一旦完成了這些操作,當從上一個時間步長到當前時間步異常成分的修改超過一個閾值時,即將其視為一個事件。【83】擴展了該方法,提出了聯合稀疏PCA和圖引導的聯合稀疏PCA來定位異常和識別對應的頂點。通過為異常集使用稀疏的成分集,可以更容易識別負責的頂點。頂點根據它們在異常子空間中對應行的值得到一個異常分數,由於異常分量是稀疏的,不異常的頂點得分為0。
圖的活躍向量 為主成分,左奇異向量對應最大奇異值,奇異值和奇異向量通過對加權鄰接矩陣進行SVD得到。當活躍向量大幅異於「正常活躍"向量時,即定義該時點為突變點,」正常活躍「向量由前序向量得到。
正常活躍向量 ,它是對最後W時間步中活動向量形成的矩陣進行SVD得到的左奇異向量。每個時點都定義一個得分 ,其代表了當前活躍向量與正常向量的差異。異常可以使用動態閾值方案在線發現,其中得分高於閾值的時間點被輸出為變化。通過計算正常向量和活動向量之間的變化比率來找到負責的頂點,與變化最大的索引所對應的頂點被標記為異常,類似的方法也可以用於節點-節點相關矩陣的活躍向量,或基於鄰居相似度的節點-節點相關矩陣。
基於距離的異常檢測演算法的不同點在於選擇用於提取和比較距離度量,以及它們用於確定異常值和相應圖的方法。
如果一些邊的屬性演化異於正常演化,則該邊就是一個異常邊。
邊之間的權重使用衰減函數定義,在每個時間步長中,根據相似度得分的變化之和計算每條邊的異常值得分,使用閾值或簡單的 作為異常值標准。
將網路視為邊的流,意味著網路沒有固定的拓撲,一個邊的頻率和持久性可以用來作為其新穎性的指標,【48】定義了集合系統不一致性指標來度量頻率和持久性,當一條邊到達時,計算其差異,並與活動邊集的平均不一致性值進行比較,如果邊的加權不一致性大於平均不一致性的閾值水平,則聲明該邊為異常邊,基於異常邊,可以進一步識別其他異常圖元素(如頂點,邊,子圖)。
具有許多「異常」邊的子圖即是異常的子圖。
【52】將邊的權重視為異常得分,每個時間步長上的每條邊都有它自己的異常分數,給定了該邊權值在所有圖序列的分布,該分數表示在該特定的邊上看到該特定權值的概率函數。或者,為網路中的邊分配異常值分數的現有方法的輸出可以用作為該方法的輸入。後一種方法允許應用於任何能夠為邊分配異常值分數的網路,一旦完成每條邊的異常打分,即可發現顯著異常的區域(SARs),即一個窗口內的固定子圖,其類似於HDSs。【112】提出了一種迭代演算法,該演算法首先固定子圖發現最優時間窗口,然後固定時間窗口發現最優子圖。【97】拓展了該方法,允許子圖漸變,即在相鄰時間步間增加或移除頂點。
定義函數 為測度圖距離的函數,將其應用於連續圖序列,即得到距離序列,基於該距離序列應用一些啟發式演算法(如基於移動平均閾值的 取值)即可得到異常事件。
稱每個頂點及其egonet的特徵為局部特徵,整張圖的特徵為全局特徵。每個頂點的局部特徵可聚合為一個向量,基於該向量的各階矩可構造signature向量,利用signature向量間的Canberra距離(歸一化的曼哈頓距離)可構造圖之間的距離函數【93】。【92】利用全局特徵,定義了一種基於dK-2序列的距離測度,將高於閾值的特徵視為異常點。
【96】使用了頂點親和度(即一個頂點對另一個頂點的影響,可以用於快速信念傳播)得分作為signature向量,其基於連續時間步技術頂點親和度,基於馬氏距離度量兩個圖的相似度,親和度得分的變化反應並適應變化的影響水平,例如橋邊的移除比正常邊移除的得分更高。利用單個移動范圍的質量控制,可以對相似度得分的時間序列設置一個移動閾值,如指數移動平均加權。
作為特徵相似度的補充,我們也可以比較兩個圖的結構差異來度量突變的大小,這類方法致力於發現定義距離的函數而非發現特徵向量。【88】計算了異常網路的10種距離函數,使用ARMA模型構造特徵值的正常模型,然後基於正常模型計算時點的殘差,殘差超過給定閾值的時間即可標記為異常。10種距離函數中,基於最大共有子圖的方法表現最好。【90】使用了五中得分函數(頂點/邊重疊,頂點排序,向量相似度,序列相似度,signature相似度)來檢測三種異常(子圖缺失,頂點缺失,連通性變化),表現最好的方案是抽取每個頂點和邊的特徵構造signature向量,使用SimHash定義距離。
我們還可以通過計算每個圖的穩健性序列來檢測事件,穩健性序列是圖連通性的測度,具有高穩健性的圖即使在去除一些頂點或邊的情況下,也能保持相同的一般結構和連通性,事件檢測即發現穩健性值異常變化的時點【95】。【89】使用的是圖半徑的變體作為穩健性指標,圖半徑的定義是基於所有頂點的平均離心度,而非常用的最大離心度。
基於概率理論、分布、掃描統計學等方法可以構造「正常」樣本的模型,偏離該模型的樣本即視為異常,這類方法的主要區別在於構造方法、建模對象、離群值定義。
主要有兩種方法:一,構造掃描統計時間序列並檢測離均值若干標准差的點;二,頂點分類。
掃描統計常稱為滑動窗口分析,其在數據的特徵區域中發現測度統計量的局部最小或最大值。對某個特定圖,掃描統計量可以是圖不變特徵的最大值,如邊的數量。
【8】使用了一個適應測度統計量的變數,即每個節點的0-2度鄰居數,然後對每個頂點的局部統計量使用近期值的均值和標准差進行標准化,圖的掃描統計量即最大的標准化局部統計量。標准化可以解釋每個頂點的歷史信息,代表每個頂點的統計量只與自己的歷史信息有關而與其他頂點無關。這保證測度的最大變化與變化的絕對量無關而與比例有關。基於掃描統計量標准化時間序列,將序列均值的五個標准差作為異常值。最負責的頂點被確定為為整個圖的掃描統計值所選擇的頂點。
類似於使用鄰居進行掃描統計,我們還可以用Markov隨機場(MRF)來發現節點的狀態,並通過信念傳播演算法推斷最大似然分配,其中,每個頂點標簽取決於其鄰居節點。【99】通過發現二部核來檢測異常點(即詐騙犯),二部核定義為詐騙犯與從犯間的交互。利用邊的插入或刪除隻影響局部子圖這一事實,它在添加新邊時逐步更新模型。在傳播矩陣中,一個頂點可以處於三種狀態之一:欺詐者、共犯者或誠實者。
邊異常檢測通常使用計數過程建模,統計上顯著異於該模型的邊標記為異常邊。
【50】用貝葉斯離散時間計數過程來建模頂點間的通信次數(邊權重),並根據新圖更新模型。基於學習到的計數的分布,對新觀測的邊進行預測 值計算,基於 值標記異常頂點對。
首先用固定的子圖,多重圖,累積圖來構造預期行為的模型,對模型的偏離可作為子圖異常檢測的依據。
【104】結合掃描統計量和隱馬爾可夫模型(HMM)建模邊行為,其使用的局部掃描統計量是基於兩種圖形狀:k-path圖和星型圖,其將滑動窗口的掃描統計數據與其過去的值進行比較,並使用在線閾值系統識別局部異常,局部異常是所有統計上顯著的子圖(代表k個路徑或恆星)的並集。
另一個建模動態圖的方法是基於多重圖,其中平行邊對應於兩個連續時間步頂點間的通信,初始的多重圖可分解為多個針對每個時間窗口的疊套子圖(TSG),TSG滿足兩個條件:(1)對於任何兩個有共同點的邊,首先開始通信的邊最後完成通信;(2)存在一個根頂點r,它沒有傳入的邊,並且有一條到TSG中每個頂點的路徑。出現概率低的TSG視為異常子圖。【102】
累積圖即為包含直到當前時點的所有邊的圖,邊權重依據衰減函數定義,通過識別「持久模式」來定義子圖的正常行為。該持久模型識別模型如下:首先構造一種圖,該圖每個邊根據時間來加權,然後基於該圖迭代抽取最重連接成分來發現。隨著累積圖的發展,提取的子圖將被監控,並將其當前活動與基於最近行為的預期活動進行比較來進行子圖異常檢測。【101】
事件檢測可以基於偏離圖似然模型或特徵值分布的偏差來進行。
【103】提出了一種新的蓄水池抽樣方法來抽取圖流的結構摘要,這種在線抽樣方法維持多個網路劃分以構造統計上顯著的摘要,當一個新圖進入圖流,每個邊都根據不同分區的邊生成模型計算出一種似然性,然後以這些似然性的幾何均值作為全局圖似然性。
【98】使用了類似的邊生成模型,每個邊 的概率都存儲在矩陣 中,概率基於期望最大化估計,基於所有收發對的分布,然後為每個收發對給出潛在得分,基於所有邊似然得分的均值即得到每個圖的得分。
【100】計算了特徵值和壓縮特徵等式的分布(而非計算收發對的分布),基於每個頂點都存在一個頂點局部特徵時間序列的假設,可在每個時間步構造一個頂點-頂點相關矩陣,通過保留最大特徵值和一組低維矩陣(每個頂點對應一個矩陣),可對相關矩陣的特徵方程進行壓縮,通過學習特徵值和矩陣的分布,即可發現異常頂點和事件。當特徵值偏離期望分布時,即認為發生了事件,當頂點的矩陣偏離矩陣分布時,可認為該頂點為異常頂點。
㈢ 網頁常見gif出處
GIF出自網,各種網路熱門GIF圖片出自、來源介紹,邪惡GIF,影視GIF,動態圖出處,美女動態圖大全。
在早期,GIF所用的LZW壓縮演算法,是Compuserv所開發的一種免費演算法。然而令很多軟體開發商感到意外的是,GIF文件所採用的壓縮演算法忽然成了Unisys公司的專利。
據Unisys公司稱,他們已注冊了LZW演算法中的W部分。如果要開發生成(或顯示)GIF文件的程序,則需向該公司支付版稅。由此,人們開始尋求一種新技術,以減少開發成本。
PNG(Portable Network Graphics,便攜網路圖形)[2]標准就在這個背景下應運而生了。它一方面滿足了市場對更少的法規限制的需要,另一方面也帶來了更少的技術上的限制,如顏色的數量等。
㈣ 遺傳演算法的迭代次數是怎麼確定的,與什麼有關
1. 遺傳演算法簡介
遺傳演算法是用於解決最優化問題的一種搜索演算法,演算法的整體思路是建立在達爾文生物進化論「優勝劣汰」規律的基礎上。它將生物學中的基因編碼、染色體交叉、基因變異以及自然選擇等概念引入最優化問題的求解過程中,通過不斷的「種群進化」,最終得到問題的最優解。
2. 遺傳演算法實現步驟
在講下面幾個基於生物學提出的概念之前,首先我們需要理解為什麼需要在最優化問題的求解中引入生物學中的各種概念。
假設我們需要求一個函數的最大值,但這個函數異常復雜以至於無法套用一般化的公式,那麼就會想到:如果可以將所有可能的解代入方程,那麼函數最大值所對應的那個解就是問題的最優解。但是,對於較復雜的函數來說,其可能的解的個數的數量級是我們所無法想像的。因此,我們只好退而求其次,只代入部分解並在其中找到最優解。那麼這樣做的核心就在於如何設定演算法確定部分解並去逼近函數的最優解或者較好的局部最優解。
遺傳演算法就是為了解決上述問題而誕生的。假設函數值所對應的所有解是一個容量超級大的種群,而種群中的個體就是一個個解,接下去遺傳演算法的工作就是讓這個種群中的部分個體去不斷繁衍,在繁衍的過程中一方面會發生染色體交叉而產生新的個體。另一方面,基因變異也會有概率會發生並產生新的個體。接下去,只需要通過自然選擇的方式,淘汰質量差的個體,保留質量好的個體,並且讓這個繁衍的過程持續下去,那麼最後就有可能進化出最優或者較優的個體。這么看來原來最優化問題居然和遺傳變異是相通的,而且大自然早已掌握了這樣的機制,這著實令人興奮。為了將這種機制引入最優化問題並利用計算機求解,我們需要將上述提到的生物學概念轉化為計算機能夠理解的演算法機制。
下面介紹在計算機中這種遺傳變異的機制是如何實現的:
基因編碼與解碼:
在生物學中,交叉與變異能夠實現是得益於染色體上的基因,可以想像每個個體都是一串超級長的基因編碼,當兩個個體發生交叉時,兩條基因編碼就會發生交換,產生的新基因同時包含父親和母親的基因編碼。在交叉過程中或者完成後,某些基因點位又會因為各種因素發生突變,由此產生新的基因編碼。當然,發生交叉和變異之後的個體並不一定優於原個體,但這給了進化(產生更加優秀的個體)發生的可能。
因此,為了在計算機里實現交叉和變異,就需要對十進制的解進行編碼。對於計算機來說其最底層的語言是由二進制0、1構成的,而0、1就能夠被用來表示每個基因點位,大量的0、1就能夠表示一串基因編碼,因此我們可以用二進制對十進制數進行編碼,即將十進制的數映射到二進制上。但是我們並不關心如何將十進制轉換為二進制的數,因為計算機可以隨機生成大量的二進制串,我們只需要將辦法將二進制轉化為十進制就可以了。
二進制轉換為十進制實現方式:
假設,我們需要將二進制映射到以下范圍:
首先,將二進制串展開並通過計算式轉化為[0,1]范圍內的數字:
將[0,1]范圍內的數字映射到我們所需要的區間內:
交叉與變異:
在能夠用二進制串表示十進制數的基礎上,我們需要將交叉與變異引入演算法中。假設我們已經獲得兩條二進制串(基因編碼),一條作為父親,一條作為母親,那麼交叉指的就是用父方一半的二進制編碼與母方一半的二進制編碼組合成為一條新的二進制串(即新的基因)。變異則指的是在交叉完成產生子代的過程中,二進制串上某個數字發生了變異,由此產生新的二進制串。當然,交叉與變異並不是必然發生的,其需要滿足一定的概率條件。一般來說,交叉發生的概率較大,變異發生的概率較小。交叉是為了讓演算法朝著收斂的方向發展,而變異則是為了讓演算法有幾率跳出某種局部最優解。
自然選擇:
在成功將基因編碼和解碼以及交叉與變異引入演算法後,我們已經實現了讓演算法自動產生部分解並優化的機制。接下去,我們需要解決如何在演算法中實現自然選擇並將優秀的個體保留下來進而進化出更優秀的個體。
首先我們需要確定個體是否優秀,考慮先將其二進制串轉化為十進制數並代入最初定義的目標函數中,將函數值定義為適應度。在這里,假設我們要求的是最大值,則定義函數值越大,則其適應度越大。那是否在每一輪迭代過程中只需要按照適應度對個體進行排序並選出更加優秀的個體就可以了呢?事實上,自然選擇的過程中存在一個現象,並沒有說優秀的個體一定會被保留,而差勁的個體就一定被會被淘汰。自然選擇是一個概率事件,越適應環境則生存下去的概率越高,反之越低。為了遵循這樣的思想,我們可以根據之前定義的適應度的大小給定每個個體一定的生存概率,其適應度越高,則在篩選時被保留下來的概率也越高,反之越低。
那麼問題就來了,如何定義這種生存概率,一般來說,我們可以將個體適應度與全部個體適應度之和的比率作為生存概率。但我們在定義適應度時使用函數值進行定義的,但函數值是有可能為負的,但概率不能為負。因此,我們需要對函數值進行正數化處理,其處理方式如下:
定義適應度函數:
定義生存概率函數:
註:最後一項之所以加上0.0001是因為不能讓某個個體的生存概率變為0,這不符合自然選擇中包含的概率思想。
3. 遺傳算例
在這里以一個比較簡單的函數為例,可以直接判斷出函數的最小值為0,最優解為(0,0)
若利用遺傳演算法進行求解,設定交叉概率為0.8,變異概率為0.005,種群內個體數為2000,十進制數基因編碼長度為24,迭代次數為500次。
從遺傳演算法收斂的動態圖中可以發現,遺傳演算法現實生成了大量的解,並對這些解進行試錯,最終收斂到最大值,可以發現遺傳演算法的結果大致上與最優解無異,結果圖如下:
4. 遺傳演算法優缺點
優點:
1、 通過變異機制避免演算法陷入局部最優,搜索能力強
2、 引入自然選擇中的概率思想,個體的選擇具有隨機性
3、 可拓展性強,易於與其他演算法進行結合使用
缺點:
1、 遺傳演算法編程較為復雜,涉及到基因編碼與解碼
2、 演算法內包含的交叉率、變異率等參數的設定需要依靠經驗確定
3、 對於初始種群的優劣依賴性較強