求函数最小值

全遍历计算


完全不管函数是个啥,直接全定义域上生成间隔较小的一组随机数,然后求结果的最小值
- 容易实现
- 定义域广的话,需要生成的随机数量大
- 因为是随机数,所以结果有些不稳定
- 数据量大时,效率低,完全是暴力计算


蒙特卡罗算法(Monte Carlo Algorithm)是一类利用随机数进行数值计算的方法,
特别适用于解决复杂且难以通过常规方法直接求解的问题。

其中,使用蒙特卡罗算法寻找函数的最小值是一个典型的应用。
这种方法通过大量随机采样和统计分析来逼近目标函数的最小值。

 

基本步骤

定义目标函数:
首先,你需要有一个待优化的目标函数 f(x),其中 x 通常是多维的向量。

生成随机样本:
在目标函数的定义域内生成大量的随机样本点。
例如,如果 x 是一个二维向量,
可以在 [x_1_{\min}, x_1_{\max}] \times [x_2_{\min}, x_2_{\max}] 的范围内生成随机点。

计算函数值:
对每个随机样本点计算目标函数的值。

记录最小值:
记录迄今为止遇到的最小函数值及其对应的样本点。

重复采样:
根据需要重复步骤2到步骤4,增加样本数量以提高估计的准确性。

输出结果:
在达到预定的样本数量或满足其他停止条件后,输出记录的最小值及其对应的样本点作为估计结果。


    

import numpy as np

# 定义目标函数
def f(x, y):
    return (x - 2)**2 + (y - 3)**2

# 设定定义域
x_min, x_max = -10, 10
y_min, y_max = -10, 10

# 生成随机样本
num_samples = 100000
x_samples = np.random.uniform(x_min, x_max, num_samples)
y_samples = np.random.uniform(y_min, y_max, num_samples)

# 计算函数值
values = f(x_samples, y_samples)

# 记录最小值
min_value = np.min(values)
min_index = np.argmin(values)
min_x, min_y = x_samples[min_index], y_samples[min_index]

print(f"Estimated minimum value: {min_value}")
print(f"Corresponding point: ({min_x}, {min_y})")




函数是有单调性,在一定范围内,会单调递增/递减

随机选一个起点,向前一小步,
- 如果函数值变大,就回退一点点
- 如果函数值变小,就前进一点点


def f23(x1,x2):
    y = (x1-2)**2 + (x2-3) **2
    return y


比如上面这个函数,有两个变量,在AI中默认两个变量相互独立,
虽然肉眼可见是x1=2,x2=3时可取得最小值,
但如何找到一个方法,让计算机对于任意函数都能求出最小值?

第一步,如何使用上面的方法,计算多变量函数的最小值?


A:一个变量还好说,现在有多个变量?

B:你说什么?

A:现在有多个变量

B:不是这一句,是上一句

A:一个变量还好说

B:对,就是这一句,既然当函数只有一个变量时,单调性变化少,那么就一个一个变量地观察;先解决一个再说下一个


def fn(x):
    return (x-2) ** 2

再回顾一下蒙特卡罗方法:全遍历比较


x = np.random.uniform(low=-100, high=100, size=10000)

def fn(x):
    return (x-2) ** 2


# 起点
x_min = x[0]

# 假定第一个就是最小值,若有值比它小,则将更小的值赋予它
y_min = fn(x_min)

for ele in x:
    y = fn(ele)
    if y < y_min:
        y_min = y
        x0 = ele

print(x0, y_min)  # 2.016519470488859 0.00027289290523228854

微调方法


#随机选择一个起点
x0 = np.random.uniform(low=-100, high=100, size=1)

print(x0)

delta = 0.01  #微调大小

for _ in range(10000): #尝试1万次
    if fn(x0 + delta) < fn(x0):  #前进一点点
        x0 += delta              #变小了
    elif fn(x0 + delta) > fn(x0):
        x0 -= delta              #变大小
    else:
        print("OK!!!")
        break

print(x0, fn(x0))



[81.24773959]
[1.98773959] [0.00015032]

结果说明当x=1.98773959时,fn取得最小值0.00015032

同样的方法解决另外一个变量



def fn(x):
    return (x-3) ** 2


#随机选择一个起点
x0 = np.random.uniform(low=-100, high=100, size=1)

print(x0)

delta = 0.01  #微调大小

for _ in range(10000): #尝试1万次
    if fn(x0 + delta) < fn(x0):  #前进一点点
        x0 += delta              #变小了
    elif fn(x0 + delta) > fn(x0):
        x0 -= delta              #变大小
    else:
        print("完美!!!")
        break

print(x0, fn(x0))


[-86.72279204]
[2.99720796] [7.79549379e-06]


算法说,起步并不重要,只要你不断学习,不断前进,就会有进步!


这个函数可以看作是两个变量的的函数的和,那如果是差呢?

将这看作一个新的问题

如果单变量的函数值都变得很小,至少从现在的结果来看,不管是和还是差,最终的函数值也会很小
- 其实这里是想让一个函数趋于0,所以使用正的函数举例
- 如果是负的,让其绝对值趋于0即可


该方法的问题,实际上只能求极小值
局部最优

很可能有个地方有个最小值就在那来回摆动,不再尝试了,
至于其他地方有没有更小的值,该方法就无能为力了


如果有一种方法能取得 单个变量函数 的变化趋势 就好了

就是知道单个变量函数在一定范围内,是增还是减,

在数学上,导数可以解决这个问题
- 函数增,对应区域的导数为 正
- 函数减,对应区域的导数为 负
- 不管函数再复杂,只要它可导,就有此规律




导数的正负


y=fn(x)在x处的导函数值记为dx

x = x - 步长*dx
- 当函数增加时,dx为正,x变小, y变小
- 当函数减小时,dx为负,x变大,y变小

该公式可以保证x总体,在大趋势上,大方向上,是朝着y的最小值处前进的

导数的大小


步长,
- 如果起点离最小值点的距离大的时候,步长大一些,可以加速
- 如果快到最小值点附近了,那么步长小一点,会更准一些

导数可以解决这个问题吗?
- 有些函数在极值附近变化缓慢,导数值就小,这样就可以
- 可现实是,这个函数正是要求的,不知道的,或者说函数是复杂的,
- 所以导数解决不了这个问题


该问题在深度学习中,由优化器解决,
- 在训练开始时,步长大一些
- 之后,步长小一些 








遇到一个问题,想解决...于是定下目标,解决该问题
- 设定目标 
- 众


如何解决,怎么解决,收集了多种方法
- 模型定义,要选择的是效率高的方法 
- 技,高效解决问题的方法

当前是什么情况,起点在哪些,结合前面的目标,就可以知道两者之间的距离
- 身,一切行为的起点是自身


有了起点和目标,两者之间就产生了高度差,中间有各种障碍,其特性产生了结构 
- 当你的目标高于你的起点时,从目标到起点应该是容易的,就像顺水而下,下山
- 但上山是累的...需要你不断做功...
- 要想办法将目标变成低俗,自己的起点在高处,这样...就可以轻松的,自动的向目标前进了
- 局,做局/入局,做/入 有利于自己,甚至是推动自动前往目标的局  

局其实就是实现了自动化,即便你什么都不用做,就有外力推着你向目标靠近
但问题是你的目标要高于起点才行,你之所想所需也是多数人所想所需啊
这就需要智慧了,
比如你想不劳而获,就必须有大量勤劳的人...你可以给他们荣誉,让他们以劳动为美

现代社会,也不一定是人力,电也可以,插上电,计算机就可以自动计算了 
- 又比如,上天可以坐飞机


w = w - learning_rate*w.grad 就是智慧的结晶
- 在下坡时w.grad为负,让w可以不断前进靠近最低点;当上坡时,其为正时,可以不断倒退靠近最低点
- 不仅如此,w.grad越靠近最低点,其值越小,前进/后退的 幅度就越小,防止了大幅度来回振荡的无奈行为
- 在远离最低点的地方w.grad是大的,w改变的幅度也大 
- 这是不是有点智能的感觉了
- 心,代表智慧 





局部最小·全局最小

 
现实问题的函数是复杂的,是有范围的 
- 并且这个范围有 普遍意义上的通用范围,也有少数情况下的范围,就是特定情况/极端情况 
- 并且这个范围是多维度的,时间上的,空间上的... 
    

 
函数最小值 与 函数极小值 
- 正常思维是想办法求函数的最小值,然而代价太大 
- 同时,局部极小值 能 解决大多数实际问题
- 所以,工程中使用的是 极小值  


比如买菜,通常是走段距离看见差不多好的菜就买了,而不是逛遍整个菜市场选择最好的那个菜
- 大多数物品的的购买也是这样,比如APP上买东西,你看到的最好的,肯定不是最好的,
- 只是一段时间内你接触到的差不多好的... 

比如,找工作
- 要考虑薪水,位置,行业,加班,个人能力等多个因素
- 可能是某个因素不是最优的选择,但综合起来相对不错就可以了 

现实中局部最优/最小 是常态
- 极致的追求也存在,但它付出与回报的性价比不高... 

    

 
在现实中,你要是想花费大量的时间/精力 去追寻一个 大多人数看不结果/不确定的 的目标... 
- 大多数人会反对你,阻止你...
- 你只有/只能/最好 拿出一个个的短期/局部最优解 引导大多数人...你才能一点点走下去...
- 比如,说话,吃饭,穿衣,买房,买车,找工作,找对象,教育...都是如此!


 

    

 

    

 

    

 


 

  

 


参考