梯度下降法和牛顿法计算开根号

本文介绍了如何仅使用基本运算求解根号x,通过梯度下降法和牛顿法两种数学方法实现。梯度下降法通过迭代寻找使目标函数最小化的值,牛顿法则利用切线找函数零点。文章详细阐述了两种方法的迭代过程,并提供了C++代码实现。讨论了学习率和步长选择对算法效率的影响。
摘要由CSDN通过智能技术生成

梯度下降法和牛顿法计算开根号

本文将介绍如何不调包,只能使用加减乘除法实现对根号x的求解。主要介绍梯度下降和牛顿法者两种方法,并给出 C++ 实现。

梯度下降法

思路/步骤

  1. 转化问题,将 x \sqrt{x} x 的求解转化为最小化目标函数: L ( t ) L(t) L(t) L ( t ) = ( t 2 − x ) L(t)=(t^2-x) L(t)=(t2x) ,当 L L L 趋近于 0 时, t t t 就是我们想要的结果;
  2. 迭代寻找使得 L L L 变小的 t t t
  3. 最终得到足够小的 L L L 时的 t t t ,即使得 L → 0 L\rightarrow 0 L0, 得到结果 t t t
  4. 求解 L L L 的极小值,就是导数为 0 的点

如何迭代

OK,现在的问题就是要如何进行迭代,从而得到尽可能小的 L L L,为此,我们要使得随着每一次迭代中 t t t 的变化, L L L 都朝着更小的方向变化一个合适的步长

在这里插入图片描述

确定如何迭代,无非就是要确定每次迭代的方向步长

最自然的想法,我们使得 t t t 朝政府两个方向都移动一个很小的步长,然后比一比,看哪个的 L L L 更小了,就向哪个方向移动。即:

  • L ( t + Δ t ) < L ( t ) L(t+\Delta t)<L(t) L(t+Δt)<L(t) ,则 t 1 = t + Δ t t_1=t+\Delta t t1=t+Δt
  • L ( t − Δ t ) < L ( t ) L(t-\Delta t)<L(t) L(tΔt)<L(t) ,则 t 1 = t − Δ t t_1=t-\Delta t t1=tΔt

注意这里的 Δ t \Delta t Δt 应当是一个大于零的无穷小数,即 0 + 0^+ 0+

在这里插入图片描述

我们接下来再对上面的式子进行一点变化:

  • L ( t + Δ t ) − L ( t ) < 0 L(t+\Delta t)-L(t)<0 L(t+Δt)L(t)<0 ,则 t 1 = t + Δ t t_1=t+\Delta t t1=t+Δt
  • L ( t ) − L ( t − Δ t ) > 0 L(t)-L(t-\Delta t)>0 L(t)L(tΔt)>0 ,则 t 1 = t − Δ t t_1=t-\Delta t t1=tΔt

将这两个式子写在一起:
t 1 = t − L ( t + Δ t ) − L ( t ) ∣ L ( t + Δ t ) − L ( t ) ∣ ⋅ Δ t t_1=t-\frac{L(t+\Delta t)-L(t)}{|L(t+\Delta t)-L(t)|}\cdot \Delta t t1=tL(t+Δt)L(t)L(t+Δt)L(t)Δt
这里的 L ( t + Δ t ) − L ( t ) ∣ L ( t + Δ t ) − L ( t ) ∣ \frac{L(t+\Delta t)-L(t)}{|L(t+\Delta t)-L(t)|} L(t+Δt)L(t)L(t+Δt)L(t) 用来指示正负号。再进行一点变形:
t 1 = t − L ( t + Δ t ) − L ( t ) ∣ L ( t + Δ t ) − L ( t ) ∣ ⋅ Δ t = t − L ( t + Δ t ) − L ( t ) Δ t ∣ L ( t + Δ t ) − L ( t ) Δ t ∣ ⋅ Δ t = t − L ( t + Δ t ) Δ t Δ t ∣ L ( t + Δ t ) − L ( t ) Δ t ∣ = t − α L ′ ( t ) ,     α = Δ t ∣ L ( t + Δ t ) − L ( t ) Δ t ∣ → 0 + ,     L ′ ( t ) = L ( t + Δ t ) − L ( t ) Δ t \begin{align} t_1&=t-\frac{L(t+\Delta t)-L(t)}{|L(t+\Delta t)-L(t)|}\cdot \Delta t\\ &=t-\frac{\frac{L(t+\Delta t)-L(t)}{\Delta t}}{|\frac{L(t+\Delta t)-L(t)}{\Delta t}|}\cdot \Delta t\\ &=t-\frac{L(t+\Delta t)}{\Delta t}\frac{\Delta t}{|\frac{L(t+\Delta t)-L(t)}{\Delta t}|}\\ &=t-\alpha L'(t), \ \ \ \alpha=\frac{\Delta t}{|\frac{L(t+\Delta t)-L(t)}{\Delta t}|}\rightarrow 0^+,\ \ \ L'(t)=\frac{L(t+\Delta t)-L(t)}{\Delta t} \end{align} t1=tL(t+Δt)L(t)L(t+Δt)L(t)Δt=tΔtL(t+Δt)L(t)ΔtL(t+Δt)L(t)Δt=tΔtL(t+Δt)ΔtL(t+Δt)L(t)Δt=tαL(t),   α=ΔtL(t+Δt)L(t)Δt0+,   L(t)=ΔtL(t+Δt)L(t)

  1. 当a取无穷小时,虽然一定保证下降,但效率太慢

  2. 日常设计的很多函数,可以允许使用相对大一些的步长,比如 α = 0.01 \alpha = 0.01 α=0.01。理由是,若步长大了,出现跳过合适位置,使得 L ( t 1 ) > L ( t 0 ) L(t1) > L(t0) L(t1)>L(t0)。再下一个时刻,依旧可能跳回来使得 L ( t 2 ) < L ( t 1 ) L(t2) < L(t1) L(t2)<L(t1)

  3. 大的步长不能保证一定收敛,但是大部分时候是可以很好的工作,也因此,步长 α \alpha α,我们称之为学习率,通常会给一个相对小的数字,但不会太小。

  4. 总之,学习率一般需要在不同的模型任务中手动调试。

代码

float sqrt_grad_decent(float x) {
    float t = x / 2;
    float L = (t * t - x) * (t * t - x);
    float alpha = 0.001;
    while ( L > 1e-5 ) {
        float delta = 2 * (t * t - x) * 2 * t;
        t = t - alpha * delta;
        L = (t * t - x) * (t * t - x);
        printf("t=%f\n", t);
    }
    return t;
}

总结

  1. 梯度下降法是通过观察局部,决定如何调整的算法。如果函数具有多个极值,则可能陷入局部极值,此时初始点的选择直接影响收敛结果

  2. 大的步长在一定程度上可能跨过局部极值,但也可能造成震荡导致不收敛

  3. 步长的选择,需要根据函数的特性来找到合适取值,若导数特别大时,则步长取小,导数小时,步长可大。否则很容易造成收敛问题

  4. 存在一类算法,可以在一定范围内搜索一个合适步长,使得每一次迭代更加稳定

牛顿法1

梯度下降法常用语求解函数极小值的情况,而牛顿法常用于求解函数零点的情况,即 L = 0 L=0 L=0 时方程的根。

思路/步骤

  1. 转化问题,将求解 x \sqrt{x} x 转换为求解 L ( t ) = t 2 − x = 0 L(t)=t^2-x=0 L(t)=t2x=0 时的根,即函数的零点
  2. 迭代寻找 t t t

如何迭代

用曲线在 t 0 t_0 t0 处切线与 x x x 轴的交点作为 t 1 t_1 t1 ,来逼近函数的零点。图/牛顿法

在这里插入图片描述

切线斜率,同样可以用导数来表示 。

考虑两个坐标系:原坐标系 o 1 o1 o1 ,新坐标系 o 2 o2 o2 ,其中 o 2 o2 o2 o 1 o1 o1 中的 ( x 1 , f ( x 1 ) ) (x_1,f(x_1)) (x1,f(x1)) 为原点。则在 o 2 o2 o2 坐标系中,下图红色切线可表示为:
f o 2 ( x ) = f ′ ( x 1 ) x f_{o2}(x)=f'(x_1)x fo2(x)=f(x1)x
则该切线与 x x x 轴交点:
f o 2 ( x 2 ) = f ′ ( x 1 ) ( x 2 − x 1 ) = − f ( x 1 ) f_{o2}(x_2)=f'(x_1)(x_2-x_1)=-f(x_1) fo2(x2)=f(x1)(x2x1)=f(x1)
则有:
x 2 − x 1 = − f ( x 1 ) f ′ ( x 1 ) x 2 = x 1 − f ( x 1 ) f ′ ( x 1 ) x_2-x_1=-\frac{f(x_1)}{f'(x_1)}\\ x_2=x_1-\frac{f(x_1)}{f'(x_1)} x2x1=f(x1)f(x1)x2=x1f(x1)f(x1)

在这里插入图片描述

代码

我们经过上一小节已经知道迭代的方法:
t 1 = t − L ( t ) L ′ ( t ) t_1=t-\frac{L(t)}{L'(t)} t1=tL(t)L(t)
代码:

float sqrt_newton1(float x) {
    float t = x / 2;
    float L = t * t - x;
    while ( abs(L) > 1e-5 ) {
        float dL = 2 * t;
        t = t - L / dL;
        L = t * t - x;
    }
    return t;
}

牛顿法2

思路

既然牛顿法是对函数求零点,那我们能不能对函数的导函数求零点呢?这样就可以得到函数的极值了。

与梯度下降法的目标函数 L ( t ) = ( t 2 − x ) L(t)=(t^2-x) L(t)=(t2x) 是相同的,而区别在于,迭代式不同 t 1 = t − f ′ ( t ) f ′ ′ ( t ) t_1=t-\frac{f'(t)}{f''(t)} t1=tf′′(t)f(t),并且其中步长(学习率)为 1。

代码

float sqrt_newton2(float x) {
    float t = x / 2;
    float L = (t * t - x) * (t * t - x);
    while ( L > 1e-5 ) {
        float dL = 2 * (t * t - x) * 2 * t;
        float d2L = 12 * t * t - 4 * x;
        t = t - dL / d2L;
        L = (t * t - x) * (t * t - x);
    }
    return t;
}

Ref

  1. 牛顿法
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值