最优化问题——一维搜索
1. 一维搜索的引入
1.1 从非线性规划问题到一维搜索
在前面的文章中,我们提到了基于迭代的非线性规划问题的求解思路。在求解过程中,我们提到了在每一步的迭代中都需要对计算步长因子,其计算公式为:
λ
k
=
m
i
n
λ
f
(
x
k
+
λ
p
)
λ_k=min_{λ}f(x_k+λp)
λk=minλf(xk+λp)
我们将
f
(
x
k
+
λ
p
)
f(x_k+λp)
f(xk+λp)视为λ的一元函数,我们的目标就是求这个一元函数的极小值。对于这个问题,我通常的求解方式为一维搜索。
1.2 一维搜索的基本形式
一元函数求极小值以及线性的搜索均为一维搜索,求常用求:
m
i
n
f
(
x
k
+
λ
d
k
)
=
φ
(
λ
)
,
s
.
t
.
λ
∈
S
minf(x_k+λd_k)=φ(λ),s.t. λ∈S
minf(xk+λdk)=φ(λ),s.t.λ∈S
这里我们给出对于一维搜索能够解决的问题的基本形式,我们将原来对于x的函数f看做是对于λ的函数φ。然后对于φ函数求极值。进一步。对于结果的范围λ,包括以下几个范围情况:
(
−
∞
,
+
∞
)
,
(
0
,
+
∞
)
,
[
a
,
b
]
(-∞,+∞),(0,+∞),[a,b]
(−∞,+∞),(0,+∞),[a,b]
同时,根据我们目标值的精确度,我们可以将这种一维搜索分成精确搜索和近似搜索,则本篇文章中,我们重点关注精确搜索的相关思路和算法。
通常的,我们对于参数λ的搜索是在一个在能够确定的区间内进行的,所以我们把关注点放在对于缩小区间[a,b]上的搜索。其具体的形式为:
m
i
n
φ
(
λ
)
s
.
t
.
λ
∈
[
α
,
β
]
min φ(λ)\\ s.t. λ∈[α,β]
minφ(λ)s.t.λ∈[α,β]
注意:这里的φ函数为
R
−
>
R
R->R
R−>R
1.3 缩小区间的精确一维搜索
上一个小节,我们给出了对于缩小区间一维搜索的一般形式。同时,我们的搜索目标是在区间 [ α , β ] [α,β] [α,β]s上面寻找含有 φ ( λ ) φ(λ) φ(λ)最小点。为了便于搜索,我们先给出两个概念和常见的定理。
单谷和强单谷:
对于任意的 λ 1 , λ 2 λ_1,λ_2 λ1,λ2,存在 α ≤ λ 1 < λ 2 ≤ β α≤λ_1<λ_2≤β α≤λ1<λ2≤β,其满足:
- 如果 λ 2 ≤ λ ∗ λ_2≤λ^* λ2≤λ∗,则 φ ( λ 1 ) > φ ( λ 2 ) φ(λ_1)>φ(λ_2) φ(λ1)>φ(λ2)
- 如果 λ 1 ≥ λ ∗ λ_1≥λ^* λ1≥λ∗,则 φ ( λ 1 ) < φ ( λ 2 ) φ(λ_1)<φ(λ_2) φ(λ1)<φ(λ2)
则称φ(λ)在[α,β]上强单谷。下面,有图来理解一下这个概念:
从上面的图示中我们不难发现,当在α到β这段曲线中,只存在一个极小值点的时候,当
λ
1
,
λ
2
λ_1,λ_2
λ1,λ2都在极小值点
λ
∗
λ^*
λ∗的左侧的时候,满足第一个条件描述,都在其右侧的时候满足第二个条件描述。
进一步,当这一段曲线存在一段极小值的区域的时候,我们想要满足上述的两个条件,就需要保证的是当 φ ( λ 1 ) ≠ φ ( λ ∗ ) φ(λ_1)≠φ(λ^*) φ(λ1)=φ(λ∗) φ ( λ 1 ) ≠ φ ( λ ∗ ) φ(λ_1)≠φ(λ^*) φ(λ1)=φ(λ∗)时才能满足上面的两个描述。此时,我们称其为单谷。
最后,我们给出一个关于单谷的搜索定理。
定理:设函数φ:R->R在[α,β]上单谷,α≤λ<μ≤β,则有如下:
- 如果φ(λ)≥φ(μ),则φ(ρ)≥φ(μ),任意的ρ∈[α,λ]。
- 如果φ(λ)<φ(μ),则φ(ρ)≥φ(λ),任意的ρ∈[μ,β]。
进一步,我们使用两个图来理解一下这两个条件:
首先,对于[α,β]内部是单谷的区域,也就是存在一片最小值的区域,并且曲线是先降后增的趋势,在此时,若
φ
(
λ
)
≥
φ
(
μ
)
φ(λ)≥φ(μ)
φ(λ)≥φ(μ),对于先降后增的趋势,我们可以知道对于λ左侧的区域的φ函数值是要高于在φ点的函数值的,也就是
φ
(
ρ
)
>
φ
(
λ
)
≥
φ
(
μ
)
φ(ρ)>φ(λ)≥φ(μ)
φ(ρ)>φ(λ)≥φ(μ),所以有
φ
(
ρ
)
>
φ
(
μ
)
φ(ρ)>φ(μ)
φ(ρ)>φ(μ)。
同理,我们就能够理解第二个描述。
2. 一维搜索相关算法
首先,在介绍这个部分之前,我们先来分析,使用搜索区间的思路来求解极小值点的基本思路。
- 首先,确定包含最小值的初始搜索区间。
- 其次,利用某些区间的分割技术或者插值技术来迭代减小该区间,直到区间的宽度小于预先设定的精度,即可以获得其近似解。
下面我们来介绍具体的相关算法。
2.1 黄金分割法
2.1.1 算法引入和区间推导
在使用黄金分割法之前,我们需要知道的,这种方法主要是针对单谷有效的。
回顾我们上面描述的对于单谷的定理,根据定理的描述很容易知道,在区域[ α,β]内选择两个点λ和μ,满足λ<μ。通过比较φ(λ)和φ(μ),则可以去掉[α,λ]或者[μ,β]。这样就可以进一步的去缩减搜索区域。
现在有了一个新的问题,我们应该如何确定缩减之后区域的大小?基本上可以有以下两种思路:
- 对称选择,使得 λ-α=β-μ,通过这样选择的λ和μ可以将“坏”的区间去掉,区间的长度不小于“好”的情况。
- 保持缩减的比例。t=(保留的区间长度/原区间的长度)不变。通过这种思路,使得每一个保留下来的节点λ或者节点μ,在下一次的比较中称为一个相应比例位置的点。
进一步,我们从第二种思路出发,假设经过一次缩减之后,当前的保留的区域为[α,μ],则当前的缩减比例为:
t
=
μ
−
α
β
−
α
t= \frac{μ-α}{β-α}
t=β−αμ−α
同理,假设我们下一步保留的区间长度为[α,λ],则有缩减比例为:
t
=
λ
−
α
μ
−
α
t=\frac{λ-α}{μ-α}
t=μ−αλ−α
由于缩减比例相同,则有:
t
=
μ
−
α
β
−
α
=
λ
−
α
μ
−
α
t=\frac{μ-α}{β-α}=\frac{λ-α}{μ-α}
t=β−αμ−α=μ−αλ−α
最后,我们可以推导出来:
{
μ
=
α
+
t
(
β
−
α
)
λ
=
α
+
t
(
μ
−
α
)
t
2
+
t
−
1
=
0
\begin{cases} μ=α+t(β-α)\\ λ=α+t(μ-α)\\ t^2+t-1=0 \end{cases}
⎩⎪⎨⎪⎧μ=α+t(β−α)λ=α+t(μ−α)t2+t−1=0
获得最后的结果t≈0.618,(由于是比例,这里我们的t只需要取正值)
同理,根据t的值,我们也可以推导出来:
{ μ = α + t ( β − α ) λ = α + ( 1 − t ) ( β − α ) \begin{cases} μ=α+t(β-α)\\ λ=α+(1-t)(β-α)\\ \end{cases} {μ=α+t(β−α)λ=α+(1−t)(β−α)
最后,我们就确定了关于λ和μ的取值,以及区间的比例为0.618。
2.1.2 算法描述
2.1.3 代码描述
#encoding=utf-8
'''
黄金分割法
1. φ函数为 φ(λ)= λ*λ-4λ+3
2. 给定的初始区间 α和 beta为 1.5,2.5
'''
def fai_function(par):
return par * par - 4 * par + 3
def gold_search(alpha,beta,e):
'''
:param alpha: 区间开始
:param beta: 区间结束
:param e: 精度系数
:return:
'''
t = 0.618
lam = alpha + (1-t) * (beta - alpha)
miu = alpha + t * (beta - alpha)
while (beta - alpha) >= e:
if fai_function(lam) > fai_function(miu):
alpha = lam
beta = miu
miu = alpha + t * (beta - alpha)
else:
beta = miu
miu = lam
lam = alpha + (1-t) * (beta-alpha)
print("the alpha is {}, the beta is {}".format(alpha,beta))
best_lam = (alpha + beta) / 2
return best_lam
if __name__ == '__main__':
best = gold_search(1.5,2.5,0.01)
print(fai_function(best))
2.1.4 算法扩展—斐波那契区间
和黄金分割法类似的方法还包括斐波那契算法,区别在于搜索区间长度的缩短率笔试黄金分割数,而是斐波那契数。
简单的推导一下:
假设当前的上下边界为
a
k
,
b
k
a_k,b_k
ak,bk,则我们要推导的下一轮迭代的区间车长度为:
b
k
+
1
−
a
k
+
1
=
F
n
−
k
F
n
−
k
+
1
(
b
k
−
a
k
)
b_{k+1}-a_{k+1}=\frac{F_{n-k}}{F_{n-k+1}}(b_k-a_k)
bk+1−ak+1=Fn−k+1Fn−k(bk−ak)
同时要求,在经历了n次迭代之后,有:
b
n
−
a
n
≤
δ
b_n-a_n≤δ
bn−an≤δ
实际上,当n->∞的时候,有:
l
i
m
F
n
F
n
+
1
=
5
−
1
2
;
b
n
−
a
n
=
1
F
n
(
b
1
−
a
1
)
lim\frac{F_n}{F_{n+1}}=\frac{\sqrt{5}-1}{2};b_n-a_n=\frac{1}{F_n}(b_1-a_1)
limFn+1Fn=25−1;bn−an=Fn1(b1−a1)
2.1.5 算法扩展—中分法
假设和φ(λ)在区间[α,β]内部是可微的,并且当导数为0的时候是最优解,在取λ=(α+β)/2,那么则有:
- 当 φ ′ ( λ ) = 0 φ'(λ)=0 φ′(λ)=0时,λ为最小点, λ = λ ∗ λ=λ^* λ=λ∗
- 当 φ ′ ( λ ) > 0 φ'(λ)>0 φ′(λ)>0时,λ为在上升段, λ > λ ∗ λ>λ^* λ>λ∗,去掉[λ,β]。
- 当 φ ′ ( λ ) < 0 φ'(λ)<0 φ′(λ)<0时,λ为在下降段, λ < λ ∗ λ<λ^* λ<λ∗,去掉[α,λ]。
进一步,给出其实现的代码:
'''
1. φ函数为 φ(λ)= λ*λ-4λ+3
2. 给定的初始区间 α和 beta为 1.5,2.5
'''
def grad_value(x):
return 2*x - 4
def middle_search(alpha,beta):
lam = (alpha + beta) / 2
while grad_value(lam) != 0:
if grad_value(lam) > 0:
beta = lam
else:
alpha = lam
lam = (beta+alpha) / 2
return (beta+alpha) / 2
if __name__ == '__main__':
best = middle_search(1.0,5.0)
print(fai_function(best))
2.2 进退法确定初始区间
在上一个小结中,我们主要介绍了三种方法来进行搜索,在三种搜索中,我们初始都需要给点最优点所在的上下区间α和β。所有,这里来介绍如何利用进退法来确定初始的取值区间。其思路描述如下:
初始:任取 λ 0 λ_0 λ0,步长 δ > 0 δ>0 δ>0,取 λ 1 = λ 0 + δ λ_1=λ_0+δ λ1=λ0+δ
- 如果有:
φ
(
λ
0
)
<
φ
(
λ
1
)
φ(λ_0)<φ(λ_1)
φ(λ0)<φ(λ1),令δ=2δ(步长加倍),
λ
1
=
λ
0
−
δ
λ_1=λ_0-δ
λ1=λ0−δ
{ 如 果 φ ( λ 2 ) < φ ( λ 0 ) , 则 令 λ 1 = λ 0 , λ 0 = λ 2 , 重 复 第 一 步 如 果 φ ( λ 2 ) > φ ( λ 0 ) , 则 停 止 , 令 α = λ 2 , β = λ 1 \begin{cases} 如果 φ(λ_2)<φ(λ_0),则令λ_1=λ_0,λ_0=λ_2,重复 第一步\\ 如果 φ(λ_2)>φ(λ_0),则停止,令α=λ_2,β=λ_1 \end{cases} {如果φ(λ2)<φ(λ0),则令λ1=λ0,λ0=λ2,重复第一步如果φ(λ2)>φ(λ0),则停止,令α=λ2,β=λ1 - 如果有:
φ
(
λ
0
)
>
φ
(
λ
1
)
,
令
δ
=
2
δ
(
步
长
加
倍
)
,
λ
2
=
λ
1
+
δ
φ(λ_0)>φ(λ_1),令δ=2δ(步长加倍),λ_2=λ_1+δ
φ(λ0)>φ(λ1),令δ=2δ(步长加倍),λ2=λ1+δ
{ 如 果 φ ( λ 2 ) < φ ( λ 1 ) , 则 令 λ 0 = λ 1 , λ 1 = λ 2 , 重 复 2 如 果 φ ( λ 2 ) > φ ( λ 1 ) , 则 停 止 , 令 α = λ 0 , β = λ 2 \begin{cases} 如果 φ(λ_2)<φ(λ_1),则令λ_0=λ_1,λ_1=λ_2,重复 2\\ 如果 φ(λ_2)>φ(λ_1),则停止,令α=λ_0,β=λ_2 \end{cases} {如果φ(λ2)<φ(λ1),则令λ0=λ1,λ1=λ2,重复2如果φ(λ2)>φ(λ1),则停止,令α=λ0,β=λ2
这个思路考虑起来并不是很麻烦,首先,我们需要的是一个包含最优点的区间,假设我们给定的初始 λ 0 λ_0 λ0点就在最小点的区域内,那就从初始点向左右两个方向扩展即可。对于第一种情况,说明初始点比第一个点 λ 1 λ_1 λ1更能对应最小点,则从 λ 0 λ_0 λ0向左侧扩展生成 λ 2 λ_2 λ2,进一步对于扩展生成的第二个点 λ 2 λ_2 λ2,其对应的函数值和当前更接近最优点的 λ 0 λ_0 λ0去比较也会有两种情况出现,第一种情况是 λ 2 λ_2 λ2对应的函数值更大,那就说明我们通过 λ 2 , λ 1 λ_2,λ_1 λ2,λ1,已经将最优点所在区域囊括进去了。此时可以直接确定初始的范围。第二种情况是 λ 0 λ_0 λ0对应的函数值更大,那么也就是说 λ 2 λ_2 λ2更接近与最小的区域,那就让整个区间范围左移,也就是让 λ 1 λ_1 λ1左移到 λ 0 λ_0 λ0的位置,让 λ 0 λ_0 λ0左移到 λ 2 λ_2 λ2的位置,然后继续向左侧进行扩展寻找下界。同理,当 λ 1 λ_1 λ1对应的函数值小于 λ 0 λ_0 λ0对应的函数值的时候,整个区间右移,分析方法和上面类似。不在赘述。
同样,我们也给出关于进退法的代码:
def forward_back(delta):
lam_0 = random.uniform(0,10)
lam_1 = lam_0 + delta
alpha = -1
beta = -1
while True:
if fai_function(lam_0) < fai_function(lam_1):
delta = 2 * delta
lam_2 = lam_0 - delta
if fai_function(lam_2) > fai_function(lam_0):
alpha = lam_2
beta = lam_1
return alpha,beta
else:
lam_1 = lam_0
lam_0 = lam_2
else:
delta = 2 * delta
lam_2 = lam_1 + delta
if fai_function(lam_2) > fai_function(lam_1):
alpha = lam_0
beta = lam_2
return alpha,beta
else:
lam_0 = lam_1
lam_1 = lam_2
注意: 我们在使用进退法来 确定初始区间的时候,有以下几个点需要着重的强调:
- 选择合适的δ,δ太大会导致整个区域内包含多个局部的极小值,整个区间太小可能会导致迭代次数多的增加。
- 当φ函数是单调函数的时候,这种方法并不适用。
- 可以考虑和上一节描述的中点法配合使用来寻找确定。
3 总结
在本篇文章中,我们重点关注的是一维搜索的精确搜索的基本形式,相关定理和不使用梯度信息的黄金分割搜索,斐波那契搜索以及利用一阶导数的重点法搜索,在最后,我们给出了如何确定初始区间的进退法的算法描述和代码实现。
4 参考
- 哈工大—组合优化和凸优化