介绍一个全局最优化的方法:随机游走算法(Random Walk)
2017-08-12 12:13
197 查看
1. 关于全局最优化求解
全局最优化是一个非常复杂的问题,目前还没有一个通用的办法可以对任意复杂函数求解全局最优值。上一篇文章讲解了一个求解局部极小值的方法——梯度下降法。这种方法对于求解精度不高的情况是实用的,可以用局部极小值近似替代全局最小值点。但是当要求精确求解全局最小值时,梯度下降法就不适用了,需要采用其他的办法求解。常见的求解全局最优的办法有拉格朗日法、线性规划法、以及一些人工智能算法比如遗传算法、粒子群算法、模拟退火算法等(可以参见我之前的博客)。而今天要讲的是一个操作简单但是不易陷入局部极小值的方法:随机游走算法。2. 随机游走算法操作步骤
设\(f(x)\)是一个含有\(n\)个变量的多元函数,\(x=(x_1,x_2,...,x_n)\)为\(n\)维向量。给定初始迭代点\(x\),初次行走步长\(\lambda\),控制精度\(\epsilon\)(\(\epsilon\)是一个非常小的正数,用于控制结束算法)。
给定迭代控制次数\(N\),\(k\)为当前迭代次数,置\(k=1\)。
当 \(k<N\)时,随机生成一个\((-1,1)\)之间的\(n\)维向量\(u = (u_1,u_2,\cdots,u_n),(-1<u_i<1,i=1,2,\cdots,n)\),并将其标准化得到\(u^{'}
= \frac{u}{\sqrt{\sum_{i=1}^{n} u_i ^2 }}\)。令\(x_1 = x + \lambda u^{'}\),完成第一步游走。
计算函数值,如果 \(f(x_1)<f(x)\),即找到了一个比初始值好的点,那么\(k\)重新置为1,将\(x_1\)变为\(x\),回到第2步;否则\(k = k+1\),回到第3步。
如果连续\(N\)次都找不到更优的值,则认为,最优解就在以当前最优解为中心,当前步长为半径的\(N\)维球内(如果是三维,则刚好是空间中的球体)。此时,如果\(\lambda < \epsilon\),则结束算法;否则,令\(\lambda = \frac{\lambda}{2}\),回到第1步,开始新一轮游走。
3. 随机游走的代码实现(使用Python)
这里使用的测试函数为\(f(r) = \frac{sin(r)}{r} + 1,r=\sqrt{(x-50)^2+(y-50)^2}+e,0 \leq x,y \leq 100\),求\(f(r)\)的最大值。该函数是一个多峰函数,在\((50,50)\)处取得全局最大值\(1.1512\),第二最大值在其全局最大值附近,采用一般的优化方法很容易陷入局部极大值点。这里是求解函数的最大值问题,可以将其转化为求目标函数的相反数的最小值问题。具体代码如下:#!/usr/bin/env python # -*- coding: utf-8 -*- # @Time : 2017/7/20 10:08 # @Author : Lyrichu # @Email : 919987476@qq.com # @File : random_walk.py ''' @Description:使用随机游走算法求解函数极值 这里求解:f = sin(r)/r + 1,r = sqrt((x-50)^2+(y-50)^2)+e,0<=x,y<=100 的最大值 求解f的最大值,可以转化为求-f的最小值问题 ''' from __future__ import print_function import math import random N = 100 # 迭代次数 step = 0.5 # 初始步长 epsilon = 0.00001 variables = 2 # 变量数目 x = [49,49] # 初始点坐标 walk_num = 1 # 初始化随机游走次数 print("迭代次数:",N) print("初始步长:",step) print("epsilon:",epsilon) print("变量数目:",variables) print("初始点坐标:",x) # 定义目标函数 def function(x): r = math.sqrt((x[0]-50)**2 + (x[1]-50)**2) + math.e f = math.sin(r)/r + 1 return -f # 开始随机游走 while(step > epsilon): k = 1 # 初始化计数器 while(k < N): c678 u = [random.uniform(-1,1) for i in range(variables)] # 随机向量 # u1 为标准化之后的随机向量 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)): # 如果找到了更优点 k = 1 x = x1 else: k += 1 step = step/2 print("第%d次随机游走完成。" % walk_num) walk_num += 1 print("随机游走次数:",walk_num-1) print("最终最优点:",x) print("最终最优值:",function(x))
输出结果如下:
迭代次数: 100 初始步长: 0.5 epsilon: 1e-05 变量数目: 2 初始点坐标: [49, 49] 第1次随机游走完成。 第2次随机游走完成。 第3次随机游走完成。 ...... 第16次随机游走完成。 随机游走次数: 16 最终最优点: [49.99999305065255, 50.00000102537616] 最终最优值: -1.15111524497
基本的随机游走算法对于初始点比较敏感,可以看出,当初始点位于最优点附件时,可以很好地达到全局最优点;如果将初始点设置得离最优点较远,比如设置初始点为\((10,10)\)时,其他参数不变,得到结果为:
随机游走次数: 16 最终最优点: [10.042835581532445, 11.648866165553416] 最终最优值: -1.01720848747
可以发现,随机游走陷入了局部最优点。当然,如果增大迭代次数\(N\)以及初始步长\(\lambda\),可以在一定程度上增加寻优能力,比如设置\(N=3000,\lambda=10.0\),得到结果如下:
迭代次数: 3000 初始步长: 10.0 epsilon: 1e-05 变量数目: 2 初始点坐标: [10, 10] 第1次随机游走完成。 第2次随机游走完成。 第3次随机游走完成。 ...... 第20次随机游走完成。 随机游走次数: 20 最终最优点: [49.99999900055026, 50.0000023931389] 最终最优值: -1.15111697755
可以看出,当增大迭代次数以及初始步长之后,函数最终达到了全局最优点。但是迭代次数增加的代价则是运行时间的增加。总得来说,基本的随机游走算法可以很好地达到全局最优点,但是有时会依赖于初始点的选择。
4. 改进的随机游走算法
改进的随机游走算法的不同之处是在于第3步,原来是产生一个随机向量\(u\),现在则是产生\(n\)个随机向量\(u_1,u_2,\cdots,u_n\),\(n\)是给定的一个正整数。将\(n\)个\(u_i(i=1,2,\cdots,n)\)标准化得到\(u_1^{'},u_2^{'},\cdots,u_n^{'}\),利用公式\(x_i= x + \lambda u_i^{'}\),令\(min\{x_1,x_2,\cdots,x_n\}\)替换原来的\(x_1\),其他步骤保持不变。通过这种方式改进之后,随机游走算法的寻优能力大大提高,而且对于初始值的依赖程度也降低了。令\(n=10\),初始点为\((-100,-10)\),\(N=100,\lambda=10.0,\epsilon
= 0.00001\),改进的随机游走算法实现代码如下:
#!/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:改进的随机游走算法 这里求解:f = sin(r)/r + 1,r = sqrt((x-50)^2+(y-50)^2)+e,0<=x,y<=100 的最大值 求解f的最大值,可以转化为求-f的最小值问题 ''' from __future__ import print_function import math import random N = 100 # 迭代次数 step = 10.0 # 初始步长 epsilon = 0.00001 variables = 2 # 变量数目 x = [-100,-10] # 初始点坐标 walk_num = 1 # 初始化随机游走次数 n = 10 # 每次随机生成向量u的数目 print("迭代次数:",N) print("初始步长:",step) print("每次产生随机向量数目:",n) print("epsilon:",epsilon) print("变量数目:",variables) print("初始点坐标:",x) # 定义目标函数 def function(x): r = math.sqrt((x[0]-50)**2 + (x[1]-50)**2) + math.e f = math.sin(r)/r + 1 return -f # 开始随机游走 while(step > epsilon): k = 1 # 初始化计数器 while(k < N): # 产生n个向量u x1_list = [] # 存放x1的列表 for i in range(n): u = [random.uniform(-1,1) for i1 in range(variables)] # 随机向量 # u1 为标准化之后的随机向量 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对应的x1 if(f1_min < function(x)): # 如果找到了更优点 k = 1 x = x11 else: k += 1 step = step/2 print("第%d次随机游走完成。" % walk_num) walk_num += 1 print("随机游走次数:",walk_num-1) print("最终最优点:",x) print("最终最优值:",function(x))
输出结果如下:
迭代次数: 100 初始步长: 10.0 每次产生随机向量数目: 10 epsilon: 1e-05 变量数目: 2 初始点坐标: [-100, -10] 第1次随机游走完成。 第2次随机游走完成。 第3次随机游走完成。 ..... 第20次随机游走完成。 随机游走次数: 20 最终最优点: [49.999997561093195, 49.99999839875969] 最终最优值: -1.15111685082
可以发现,即使迭代次数\(N=100\)不大,初始点\((-100,-10)\)离最优点\((50,50)\)非常远,改进的随机游走算法依然可以达到最优点。这说明了改进的随机游走算法具有更强大的寻优能力以及对于初始点更低的依赖性。
注:经过多次试验发现,无论是随机游走算法还是改进的随机游走算法,对于步长都是非常依赖的。步长\(\lambda\)越大,意味着初始可以寻找最优解的空间越大,但同时也意味着更多的迭代次数(要搜索空间变大,寻找次数变多,相应时间自然要增加)。如果步长取得过小,即使\(N\)很大,也很难达到最优解。无论对于随机游走算法还是改进的随机游走算法皆是如此。所以理论上步长\(\lambda\)越大越好。但是步长越大,迭代总次数越高,算法运行时间越长。所以实践中可以多试验几次,将\(\lambda\)取得适当地大即可。
相关文章推荐
- 介绍一个全局最优化的方法:随机游走算法(Random Walk)
- 介绍一个生成随机密码的方法
- Random walk 算法总结(一) :基于随机游走的图像分割算法及问题
- 一个随机数组的算法问题
- 有一个大数组,var a = ['1', '2', '3', ...];a的长度是100,内容填充随机整数的字符串.请先构造此数组a,然后设计一个算法将其内容去重
- 使用Jquery随机删除一个顺序列表中某个子元素的方法,保持效果统一性
- 介绍一个判断3D中N个点共线的方法
- 基础算法测试——生成一个1-10之间的随机整数组合
- 记录一个 关于 python 普通方法,静态方法和类方法 的介绍。@classmethod @staticmethod
- 我的本科毕业设计(非水文,设计了一个新算法):一种字符编码猜测工具的实现方法
- 基于随机游走的社团划分算法hadoop MR实现
- Linux下如何结束一个应用程序(比如死循环的程序)?两种方法介绍给大家
- 一组连续的数据,打乱次序后,随机取出某一个数字,用最简单的方法查找出取出的数字(求解)
- javascript中全局对象的parseInt()方法使用介绍
- 一起学libcef--libcef的基本类和方法介绍(如何产生一个你自己的浏览器)
- 算法战斗:给定一个号码与通配符问号W,问号代表一个随机数字。 给定的整数,得到X,和W它具有相同的长度。 问:多少整数协议W的形式和的比率X大?
- 模板方法模式(Template Method)-定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。
- 设计技巧15:模板方法 Template Method 在一个方法中定义一个算法的骨架,而将一些步骤延迟的子类中,实现Ioc
- 程序员面试金典——解题总结: 9.18高难度题 18.3编写一个方法,从大小为n的数组中随机选出m个整数。要求每个元素被选中的概率相同。
- [面试算法]有一无符号整型数组,大小为10, 初始的数值随机,但在[0, 99]之间。请用C语言写一个过滤程序,令数组内的数据互不相等。