python游走代码_介绍一个全局最优化的方法:随机游走算法(Random Walk)
1. 關(guān)于全局最優(yōu)化求解
全局最優(yōu)化是一個(gè)非常復(fù)雜的問題,目前還沒有一個(gè)通用的辦法可以對(duì)任意復(fù)雜函數(shù)求解全局最優(yōu)值。上一篇文章講解了一個(gè)求解局部極小值的方法——梯度下降法。這種方法對(duì)于求解精度不高的情況是實(shí)用的,可以用局部極小值近似替代全局最小值點(diǎn)。但是當(dāng)要求精確求解全局最小值時(shí),梯度下降法就不適用了,需要采用其他的辦法求解。常見的求解全局最優(yōu)的辦法有拉格朗日法、線性規(guī)劃法、以及一些人工智能算法比如遺傳算法、粒子群算法、模擬退火算法等(可以參見我之前的博客)。而今天要講的是一個(gè)操作簡(jiǎn)單但是不易陷入局部極小值的方法:隨機(jī)游走算法。
2. 隨機(jī)游走算法操作步驟
設(shè)\(f(x)\)是一個(gè)含有\(zhòng)(n\)個(gè)變量的多元函數(shù),\(x=(x_1,x_2,…,x_n)\)為\(n\)維向量。
給定初始迭代點(diǎn)\(x\),初次行走步長(zhǎng)\(\lambda\),控制精度\(\epsilon\)(\(\epsilon\)是一個(gè)非常小的正數(shù),用于控制結(jié)束算法)。
給定迭代控制次數(shù)\(N\),\(k\)為當(dāng)前迭代次數(shù),置\(k=1\)。
當(dāng) \(k
計(jì)算函數(shù)值,如果 \(f(x_1)
如果連續(xù)\(N\)次都找不到更優(yōu)的值,則認(rèn)為,最優(yōu)解就在以當(dāng)前最優(yōu)解為中心,當(dāng)前步長(zhǎng)為半徑的\(N\)維球內(nèi)(如果是三維,則剛好是空間中的球體)。此時(shí),如果\(\lambda < \epsilon\),則結(jié)束算法;否則,令\(\lambda = \frac{\lambda}{2}\),回到第1步,開始新一輪游走。
3. 隨機(jī)游走的代碼實(shí)現(xiàn)(使用Python)
這里使用的測(cè)試函數(shù)為\(f(r) = \frac{sin(r)}{r} + 1,r=\sqrt{(x-50)^2+(y-50)^2}+e,0 \leq x,y \leq 100\),求\(f(r)\)的最大值。該函數(shù)是一個(gè)多峰函數(shù),在\((50,50)\)處取得全局最大值\(1.1512\),第二最大值在其全局最大值附近,采用一般的優(yōu)化方法很容易陷入局部極大值點(diǎn)。這里是求解函數(shù)的最大值問題,可以將其轉(zhuǎn)化為求目標(biāo)函數(shù)的相反數(shù)的最小值問題。具體代碼如下:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time : 2017/7/20 10:08
# @Author : Lyrichu
# @Email : 919987476@qq.com
# @File : random_walk.py
'''
@Description:使用隨機(jī)游走算法求解函數(shù)極值
這里求解:f = sin(r)/r + 1,r = sqrt((x-50)^2+(y-50)^2)+e,0<=x,y<=100 的最大值
求解f的最大值,可以轉(zhuǎn)化為求-f的最小值問題
'''
from __future__ import print_function
import math
import random
N = 100 # 迭代次數(shù)
step = 0.5 # 初始步長(zhǎng)
epsilon = 0.00001
variables = 2 # 變量數(shù)目
x = [49,49] # 初始點(diǎn)坐標(biāo)
walk_num = 1 # 初始化隨機(jī)游走次數(shù)
print("迭代次數(shù):",N)
print("初始步長(zhǎng):",step)
print("epsilon:",epsilon)
print("變量數(shù)目:",variables)
print("初始點(diǎn)坐標(biāo):",x)
# 定義目標(biāo)函數(shù)
def function(x):
r = math.sqrt((x[0]-50)**2 + (x[1]-50)**2) + math.e
f = math.sin(r)/r + 1
return -f
# 開始隨機(jī)游走
while(step > epsilon):
k = 1 # 初始化計(jì)數(shù)器
while(k < N):
u = [random.uniform(-1,1) for i in range(variables)] # 隨機(jī)向量
# u1 為標(biāo)準(zhǔn)化之后的隨機(jī)向量
u1 = [u[i]/math.sqrt(sum([u[i]**2 for i in range(variables)])) for i in range(variables)]
x1 = [x[i] + step*u1[i] for i in range(variables)]
if(function(x1) < function(x)): # 如果找到了更優(yōu)點(diǎn)
k = 1
x = x1
else:
k += 1
step = step/2
print("第%d次隨機(jī)游走完成。" % walk_num)
walk_num += 1
print("隨機(jī)游走次數(shù):",walk_num-1)
print("最終最優(yōu)點(diǎn):",x)
print("最終最優(yōu)值:",function(x))
輸出結(jié)果如下:
迭代次數(shù): 100
初始步長(zhǎng): 0.5
epsilon: 1e-05
變量數(shù)目: 2
初始點(diǎn)坐標(biāo): [49, 49]
第1次隨機(jī)游走完成。
第2次隨機(jī)游走完成。
第3次隨機(jī)游走完成。
......
第16次隨機(jī)游走完成。
隨機(jī)游走次數(shù): 16
最終最優(yōu)點(diǎn): [49.99999305065255, 50.00000102537616]
最終最優(yōu)值: -1.15111524497
基本的隨機(jī)游走算法對(duì)于初始點(diǎn)比較敏感,可以看出,當(dāng)初始點(diǎn)位于最優(yōu)點(diǎn)附件時(shí),可以很好地達(dá)到全局最優(yōu)點(diǎn);如果將初始點(diǎn)設(shè)置得離最優(yōu)點(diǎn)較遠(yuǎn),比如設(shè)置初始點(diǎn)為\((10,10)\)時(shí),其他參數(shù)不變,得到結(jié)果為:
隨機(jī)游走次數(shù): 16
最終最優(yōu)點(diǎn): [10.042835581532445, 11.648866165553416]
最終最優(yōu)值: -1.01720848747
可以發(fā)現(xiàn),隨機(jī)游走陷入了局部最優(yōu)點(diǎn)。當(dāng)然,如果增大迭代次數(shù)\(N\)以及初始步長(zhǎng)\(\lambda\),可以在一定程度上增加尋優(yōu)能力,比如設(shè)置\(N=3000,\lambda=10.0\),得到結(jié)果如下:
迭代次數(shù): 3000
初始步長(zhǎng): 10.0
epsilon: 1e-05
變量數(shù)目: 2
初始點(diǎn)坐標(biāo): [10, 10]
第1次隨機(jī)游走完成。
第2次隨機(jī)游走完成。
第3次隨機(jī)游走完成。
......
第20次隨機(jī)游走完成。
隨機(jī)游走次數(shù): 20
最終最優(yōu)點(diǎn): [49.99999900055026, 50.0000023931389]
最終最優(yōu)值: -1.15111697755
可以看出,當(dāng)增大迭代次數(shù)以及初始步長(zhǎng)之后,函數(shù)最終達(dá)到了全局最優(yōu)點(diǎn)。但是迭代次數(shù)增加的代價(jià)則是運(yùn)行時(shí)間的增加。總得來(lái)說(shuō),基本的隨機(jī)游走算法可以很好地達(dá)到全局最優(yōu)點(diǎn),但是有時(shí)會(huì)依賴于初始點(diǎn)的選擇。
4. 改進(jìn)的隨機(jī)游走算法
改進(jìn)的隨機(jī)游走算法的不同之處是在于第3步,原來(lái)是產(chǎn)生一個(gè)隨機(jī)向量\(u\),現(xiàn)在則是產(chǎn)生\(n\)個(gè)隨機(jī)向量\(u_1,u_2,\cdots,u_n\),\(n\)是給定的一個(gè)正整數(shù)。將\(n\)個(gè)\(u_i(i=1,2,\cdots,n)\)標(biāo)準(zhǔn)化得到\(u_1^{‘},u_2^{‘},\cdots,u_n^{‘}\),利用公式\(x_i = x + \lambda u_i^{‘}\),令\(min\{x_1,x_2,\cdots,x_n\}\)替換原來(lái)的\(x_1\),其他步驟保持不變。通過(guò)這種方式改進(jìn)之后,隨機(jī)游走算法的尋優(yōu)能力大大提高,而且對(duì)于初始值的依賴程度也降低了。令\(n=10\),初始點(diǎn)為\((-100,-10)\),\(N=100,\lambda=10.0,\epsilon = 0.00001\),改進(jìn)的隨機(jī)游走算法實(shí)現(xiàn)代碼如下:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time : 2017/7/20 10:48
# @Author : Lyrichu
# @Email : 919987476@qq.com
# @File : improve_random_walk.py
'''
@Description:改進(jìn)的隨機(jī)游走算法
這里求解:f = sin(r)/r + 1,r = sqrt((x-50)^2+(y-50)^2)+e,0<=x,y<=100 的最大值
求解f的最大值,可以轉(zhuǎn)化為求-f的最小值問題
'''
from __future__ import print_function
import math
import random
N = 100 # 迭代次數(shù)
step = 10.0 # 初始步長(zhǎng)
epsilon = 0.00001
variables = 2 # 變量數(shù)目
x = [-100,-10] # 初始點(diǎn)坐標(biāo)
walk_num = 1 # 初始化隨機(jī)游走次數(shù)
n = 10 # 每次隨機(jī)生成向量u的數(shù)目
print("迭代次數(shù):",N)
print("初始步長(zhǎng):",step)
print("每次產(chǎn)生隨機(jī)向量數(shù)目:",n)
print("epsilon:",epsilon)
print("變量數(shù)目:",variables)
print("初始點(diǎn)坐標(biāo):",x)
# 定義目標(biāo)函數(shù)
def function(x):
r = math.sqrt((x[0]-50)**2 + (x[1]-50)**2) + math.e
f = math.sin(r)/r + 1
return -f
# 開始隨機(jī)游走
while(step > epsilon):
k = 1 # 初始化計(jì)數(shù)器
while(k < N):
# 產(chǎn)生n個(gè)向量u
x1_list = [] # 存放x1的列表
for i in range(n):
u = [random.uniform(-1,1) for i1 in range(variables)] # 隨機(jī)向量
# u1 為標(biāo)準(zhǔn)化之后的隨機(jī)向量
u1 = [u[i3]/math.sqrt(sum([u[i2]**2 for i2 in range(variables)])) for i3 in range(variables)]
x1 = [x[i4] + step*u1[i4] for i4 in range(variables)]
x1_list.append(x1)
f1_list = [function(x1) for x1 in x1_list]
f1_min = min(f1_list)
f1_index = f1_list.index(f1_min)
x11 = x1_list[f1_index] # 最小f1對(duì)應(yīng)的x1
if(f1_min < function(x)): # 如果找到了更優(yōu)點(diǎn)
k = 1
x = x11
else:
k += 1
step = step/2
print("第%d次隨機(jī)游走完成。" % walk_num)
walk_num += 1
print("隨機(jī)游走次數(shù):",walk_num-1)
print("最終最優(yōu)點(diǎn):",x)
print("最終最優(yōu)值:",function(x))
輸出結(jié)果如下:
迭代次數(shù): 100
初始步長(zhǎng): 10.0
每次產(chǎn)生隨機(jī)向量數(shù)目: 10
epsilon: 1e-05
變量數(shù)目: 2
初始點(diǎn)坐標(biāo): [-100, -10]
第1次隨機(jī)游走完成。
第2次隨機(jī)游走完成。
第3次隨機(jī)游走完成。
.....
第20次隨機(jī)游走完成。
隨機(jī)游走次數(shù): 20
最終最優(yōu)點(diǎn): [49.999997561093195, 49.99999839875969]
最終最優(yōu)值: -1.15111685082
可以發(fā)現(xiàn),即使迭代次數(shù)\(N=100\)不大,初始點(diǎn)\((-100,-10)\)離最優(yōu)點(diǎn)\((50,50)\)非常遠(yuǎn),改進(jìn)的隨機(jī)游走算法依然可以達(dá)到最優(yōu)點(diǎn)。這說(shuō)明了改進(jìn)的隨機(jī)游走算法具有更強(qiáng)大的尋優(yōu)能力以及對(duì)于初始點(diǎn)更低的依賴性。
注:經(jīng)過(guò)多次試驗(yàn)發(fā)現(xiàn),無(wú)論是隨機(jī)游走算法還是改進(jìn)的隨機(jī)游走算法,對(duì)于步長(zhǎng)都是非常依賴的。步長(zhǎng)\(\lambda\)越大,意味著初始可以尋找最優(yōu)解的空間越大,但同時(shí)也意味著更多的迭代次數(shù)(要搜索空間變大,尋找次數(shù)變多,相應(yīng)時(shí)間自然要增加)。如果步長(zhǎng)取得過(guò)小,即使\(N\)很大,也很難達(dá)到最優(yōu)解。無(wú)論對(duì)于隨機(jī)游走算法還是改進(jìn)的隨機(jī)游走算法皆是如此。所以理論上步長(zhǎng)\(\lambda\)越大越好。但是步長(zhǎng)越大,迭代總次數(shù)越高,算法運(yùn)行時(shí)間越長(zhǎng)。所以實(shí)踐中可以多試驗(yàn)幾次,將\(\lambda\)取得適當(dāng)?shù)卮蠹纯伞?/p>
總結(jié)
以上是生活随笔為你收集整理的python游走代码_介绍一个全局最优化的方法:随机游走算法(Random Walk)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 海信为什么要出一个Vidda品牌?有啥区
- 下一篇: python 复制文件夹内容 并结构一致