Python | 从零实现10种优化算法并比较

该文章已生成可运行项目,

🚀SGD

算法原理

随机梯度下降(Stochastic Gradient Descent,SGD)是一种基于梯度的优化算法,用于在机器学习和深度学习中最小化目标函数。以下是其基本原理和参数更新数学公式的简要说明:

  • 基本原理: SGD旨在通过迭代的方式,沿着目标函数梯度的反方向更新模型参数,以逐步找到使目标函数最小化的最优参数值。

  • 在每次迭代中,随机选取一个训练样本,计算该样本对应的损失函数关于模型参数的梯度,然后根据这个梯度来更新模型参数。通过不断地重复这个过程,模型参数逐渐向最优解靠近,使得损失函数的值不断减小。

  • 参数更新数学公式:设 θ \theta θ 为模型参数, J ( θ ) J(\theta) J(θ)为目标函数, η \eta η为学习率,在第 t t t次迭代时,随机选取一个样本 ( x i , y i ) (x_i, y_i) (xi,yi),计算该样本损失函数 L ( y i , f ( x i ; θ ) ) L(y_i, f(x_i; \theta)) L(yi,f(xi;θ))关于参数 θ \theta θ的梯度 ∇ L ( y i , f ( x i ; θ ) ) \nabla L(y_i, f(x_i; \theta)) L(yi,f(xi;θ)),则参数更新公式为:
    θ t + 1 = θ t − η ∇ L ( y i , f ( x i ; θ t ) ) \theta_{t + 1}=\theta_t - \eta \nabla L(y_i, f(x_i; \theta_t)) θt+1=θtηL(yi,f(xi;θt))
    其中, θ t \theta_t θt是第 t t t次迭代时的参数值, θ t + 1 \theta_{t + 1} θt+1是第 t + 1 t + 1 t+1次迭代时的参数值。学习率 η \eta η是一个超参数,用于控制参数更新的步长,通常需要根据具体问题进行调整。

代码实现

本文这里实际实现的是GD算法,因为样例优化问题比较简单: f ( x , y ) = 3 x 2 + 4 y 2 f(x,y)=3x^2+4y^2 f(x,y)=3x2+4y2

class SGD:
    def __init__(self, lr=0.01):
        self.lr = lr

    def update(self, w, grad_w):
        return w - self.lr * grad_w

可视效果

优化的损失函数为: f ( x , y ) = 3 x 2 + 4 y 2 f(x,y)=3x^2+4y^2 f(x,y)=3x2+4y2
在这里插入图片描述
在这里插入图片描述

🚀 Adagrad

算法原理

  • 基本原理:Adagrad根据每个参数的历史梯度平方和来调整学习率,对于频繁出现的参数,其学习率会逐渐减小,而对于不常出现的参数,学习率则相对较大,从而实现了自适应学习率的调整。
  • 参数更新数学公式
    G t , i i = ∑ k = 1 t g k , i 2 G_{t,ii}=\sum_{k = 1}^{t}g_{k,i}^2 Gt,ii=k=1tgk,i2
    θ t + 1 = θ t − η G t , i i + ϵ g t \theta_{t + 1}=\theta_t-\frac{\eta}{\sqrt{G_{t,ii}+\epsilon}}g_t θt+1=θtGt,ii+ϵ ηgt
    其中, g k , i g_{k,i} gk,i是第 k k k步参数 i i i的梯度, G t , i i G_{t,ii} Gt,ii是参数 i i i到第 t t t步为止的梯度平方和, η \eta η是初始学习率, ϵ \epsilon ϵ是一个小常数,用于防止分母为零。

代码实现

import numpy as np

class Adagrad:
    def __init__(self, eps=1e-8):
        self.eps = eps
        self.G = None

    def update(self, w, grad_w):
        if self.G is None:
            self.G = np.zeros_like(grad_w)

        self.G += grad_w ** 2
        dx = grad_w / (np.sqrt(self.G) + self.eps)
        return w - dx

可视效果

优化的损失函数为: f ( x , y ) = 3 x 2 + 4 y 2 f(x,y)=3x^2+4y^2 f(x,y)=3x2+4y2
在这里插入图片描述
在这里插入图片描述

🚀 Adadelta

算法原理

  • 基本原理:Adadelta是Adagrad的一种改进算法,旨在解决Adagrad学习率单调递减的问题。它通过引入一个随时间衰减的平均梯度平方项和一个自适应的学习率来调整参数更新步长,使得在训练过程中学习率能够根据问题的复杂度自适应调整。
  • 参数更新数学公式
    E [ g 2 ] t = ρ E [ g 2 ] t − 1 + ( 1 − ρ ) g t 2 E[g^2]_t=\rho E[g^2]_{t - 1}+(1-\rho)g_t^2 E[g2]t=ρE[g2]t1+(1ρ)gt2
    Δ θ t = − E [ Δ θ 2 ] t − 1 + ϵ E [ g 2 ] t + ϵ g t \Delta\theta_t=-\frac{\sqrt{E[\Delta\theta^2]_{t - 1}+\epsilon}}{\sqrt{E[g^2]_t+\epsilon}}g_t Δθt=E[g2]t+ϵ E[Δθ2]t1+ϵ gt
    θ t + 1 = θ t + Δ θ t \theta_{t + 1}=\theta_t+\Delta\theta_t θt+1=θt+Δθt
    其中, g t g_t gt是第 t t t步的梯度, E [ g 2 ] t E[g^2]_t E[g2]t是梯度平方的指数移动平均, ρ \rho ρ是衰减率, Δ θ t \Delta\theta_t Δθt是参数更新量, E [ Δ θ 2 ] t − 1 E[\Delta\theta^2]_{t - 1} E[Δθ2]t1是参数更新量平方的指数移动平均, ϵ \epsilon ϵ是一个小常数,用于防止分母为零。

代码实现

import numpy as np

class Adadelta:
    def __init__(self, rho=0.95, eps=1e-6):
        self.rho = rho
        self.eps = eps
        self.Eg2 = None
        self.Edx2 = None
        self.delta_x = None

    def update(self, w, grad_w):
        if self.Eg2 is None:
            self.Eg2 = np.zeros_like(grad_w)
            self.Edx2 = np.zeros_like(w)
            self.delta_x = np.zeros_like(w)

        self.Eg2 = self.rho * self.Eg2 + (1 - self.rho) * grad_w ** 2
        dx = np.sqrt((self.Edx2 + self.eps) / (self.Eg2 + self.eps)) * grad_w
        self.Edx2 = self.rho * self.Edx2 + (1 - self.rho) * dx ** 2
        self.delta_x = -dx
        return w + self.delta_x

可视效果

在这里插入图片描述
在这里插入图片描述

🚀 RMSProp

算法原理

  • 基本原理:RMSProp通过对梯度平方的指数移动平均来调整学习率,使得学习率能够根据参数的重要性和梯度的变化情况自适应调整,在一定程度上解决了Adagrad中学习率单调递减的问题,提高了训练的稳定性和收敛速度。
  • 参数更新数学公式
    E [ g 2 ] t = ρ E [ g 2 ] t − 1 + ( 1 − ρ ) g t 2 E[g^2]_t=\rho E[g^2]_{t - 1}+(1-\rho)g_t^2 E[g2]t=ρE[g2]t1+(1ρ)gt2
    θ t + 1 = θ t − η E [ g 2 ] t + ϵ g t \theta_{t + 1}=\theta_t-\frac{\eta}{\sqrt{E[g^2]_t+\epsilon}}g_t θt+1=θtE[g2]t+ϵ ηgt
    其中,各参数含义与Adadelta中的类似。

代码实现

import numpy as np

class RMSProp:
    def __init__(self, lr=0.01, rho=0.9, eps=1e-8):
        self.lr = lr
        self.rho = rho
        self.eps = eps
        self.Eg2 = None

    def update(self, w, grad_w):
        if self.Eg2 is None:
            self.Eg2 = np.zeros_like(grad_w)

        self.Eg2 = self.rho * self.Eg2 + (1 - self.rho) * grad_w ** 2
        dx = self.lr * grad_w / (np.sqrt(self.Eg2) + self.eps)
        return w - dx

可视效果

在这里插入图片描述
在这里插入图片描述

🚀 Adam

算法原理

  • 基本原理:Adam结合了Adagrad和RMSProp的优点,通过计算梯度的一阶矩估计(均值)和二阶矩估计(方差)来调整学习率,能够在训练初期利用较大的学习率快速收敛,在后期根据梯度的变化情况自适应地调整学习率,从而提高训练的稳定性和收敛速度。
  • 参数更新数学公式
    m t = β 1 m t − 1 + ( 1 − β 1 ) g t m_t=\beta_1m_{t - 1}+(1-\beta_1)g_t mt=β1mt1+(1β1)gt
    v t = β 2 v t − 1 + ( 1 − β 2 ) g t 2 v_t=\beta_2v_{t - 1}+(1-\beta_2)g_t^2 vt=β2vt1+(1β2)gt2
    m ^ t = m t 1 − β 1 t \hat{m}_t=\frac{m_t}{1-\beta_1^t} m^t=1β1tmt
    v ^ t = v t 1 − β 2 t \hat{v}_t=\frac{v_t}{1-\beta_2^t} v^t=1β2tvt
    θ t + 1 = θ t − η v ^ t + ϵ m ^ t \theta_{t + 1}=\theta_t-\frac{\eta}{\sqrt{\hat{v}_t}+\epsilon}\hat{m}_t θt+1=θtv^t +ϵηm^t
    其中, m t m_t mt是一阶矩估计, v t v_t vt是二阶矩估计, β 1 \beta_1 β1 β 2 \beta_2 β2是指数衰减率, m ^ t \hat{m}_t m^t v ^ t \hat{v}_t v^t是偏差修正后的一阶矩估计和二阶矩估计, η \eta η是学习率, ϵ \epsilon ϵ是一个小常数,用于防止分母为零。

代码实现

import numpy as np

class Adam:
    def __init__(self, lr=0.01, beta1=0.9, beta2=0.999, eps=1e-8):
        self.lr = lr
        self.beta1 = beta1
        self.beta2 = beta2
        self.eps = eps
        self.m = None
        self.v = None
        self.t = 0

    def update(self, w, grad_w):
        self.t += 1
        if self.m is None:
            self.m = np.zeros_like(grad_w)
            self.v = np.zeros_like(grad_w)

        self.m = self.beta1 * self.m + (1 - self.beta1) * grad_w
        self.v = self.beta2 * self.v + (1 - self.beta2) * grad_w ** 2

        m_hat = self.m / (1 - self.beta1 ** self.t)
        v_hat = self.v / (1 - self.beta2 ** self.t)

        dx = self.lr * m_hat / (np.sqrt(v_hat) + self.eps)
        return w - dx

可视效果

在这里插入图片描述
在这里插入图片描述

🚀 AdamW

算法原理

  • 基本原理:AdamW在Adam的基础上,对权重衰减进行了更合理的处理,将权重衰减从优化器的参数更新中分离出来,直接作用于参数本身,而不是像传统的方法那样将权重衰减与学习率耦合在一起,从而在一定程度上提高了模型的泛化能力和训练效果。
  • 参数更新数学公式:与Adam类似,只是在更新参数时多了一项权重衰减项:
    θ t + 1 = θ t − η v ^ t + ϵ m ^ t − λ θ t \theta_{t + 1}=\theta_t-\frac{\eta}{\sqrt{\hat{v}_t}+\epsilon}\hat{m}_t-\lambda\theta_t θt+1=θtv^t +ϵηm^tλθt
    其中, λ \lambda λ是权重衰减系数,其他参数含义与Adam中相同。

代码实现

import numpy as np

class AdamW:
    def __init__(self, lr=0.001, beta1=0.9, beta2=0.999, eps=1e-8, weight_decay=0.01):
        self.lr = lr
        self.beta1 = beta1
        self.beta2 = beta2
        self.eps = eps
        self.weight_decay = weight_decay
        self.m = None
        self.v = None
        self.t = 0

    def update(self, w, grad_w):
        self.t += 1
        if self.m is None:
            self.m = np.zeros_like(grad_w)
            self.v = np.zeros_like(grad_w)

        self.m = self.beta1 * self.m + (1 - self.beta1) * grad_w
        self.v = self.beta2 * self.v + (1 - self.beta2) * grad_w ** 2

        m_hat = self.m / (1 - self.beta1 ** self.t)
        v_hat = self.v / (1 - self.beta2 ** self.t)

        # 加入权重衰减项
        update = (self.lr * m_hat / (np.sqrt(v_hat) + self.eps)) + self.weight_decay * w
        return w - update

可视效果

在这里插入图片描述
在这里插入图片描述

🚀 SparseAdam

算法原理

  • 基本原理:SparseAdam是Adam的一种变体,专门用于处理稀疏数据。它在计算梯度的一阶矩估计和二阶矩估计时,只对非零梯度进行更新,从而提高了计算效率,同时也能在一定程度上保证模型的训练效果。
  • 参数更新数学公式:与Adam类似,但在计算 m t m_t mt v t v_t vt时只考虑非零梯度:
    m t = β 1 m t − 1 + ( 1 − β 1 ) g t m_t=\beta_1m_{t - 1}+(1-\beta_1)g_t mt=β1mt1+(1β1)gt
    v t = β 2 v t − 1 + ( 1 − β 2 ) g t 2 v_t=\beta_2v_{t - 1}+(1-\beta_2)g_t^2 vt=β2vt1+(1β2)gt2
    m ^ t = m t 1 − β 1 t \hat{m}_t=\frac{m_t}{1-\beta_1^t} m^t=1β1tmt
    v ^ t = v t 1 − β 2 t \hat{v}_t=\frac{v_t}{1-\beta_2^t} v^t=1β2tvt
    θ t + 1 = θ t − η v ^ t + ϵ m ^ t \theta_{t + 1}=\theta_t-\frac{\eta}{\sqrt{\hat{v}_t}+\epsilon}\hat{m}_t θt+1=θtv^t +ϵηm^t
    其中, g t g_t gt为稀疏梯度,其他参数含义与Adam中相同。

代码实现

import numpy as np

class SparseAdam:
    def __init__(self, lr=0.01, beta1=0.9, beta2=0.999, eps=1e-8):
        self.lr = lr
        self.beta1 = beta1
        self.beta2 = beta2
        self.eps = eps
        self.m = None
        self.v = None
        self.t = 0

    def update(self, w, grad_w):
        self.t += 1
        if self.m is None:
            self.m = {}
            self.v = {}

        for index in np.ndindex(grad_w.shape):
            if index not in self.m:
                self.m[index] = np.zeros(1)
                self.v[index] = np.zeros(1)

            g = grad_w[index]
            self.m[index] = self.beta1 * self.m[index] + (1 - self.beta1) * g
            self.v[index] = self.beta2 * self.v[index] + (1 - self.beta2) * g ** 2

            m_hat = self.m[index] / (1 - self.beta1 ** self.t)
            v_hat = self.v[index] / (1 - self.beta2 ** self.t)

            dx = self.lr * m_hat / (np.sqrt(v_hat) + self.eps)
            w[index] -= dx

        return w

可视效果

在这里插入图片描述
在这里插入图片描述

🚀 Adamax

算法原理

  • 基本原理:Adamax是Adam的一种变体,它对Adam中的二阶矩估计进行了修改,使用了无穷范数来代替原来的 L 2 L_2 L2范数,在一些情况下可能具有更好的性能和稳定性。
  • 参数更新数学公式
    m t = β 1 m t − 1 + ( 1 − β 1 ) g t m_t=\beta_1m_{t - 1}+(1-\beta_1)g_t mt=β1mt1+(1β1)gt
    u t = max ⁡ ( β 2 u t − 1 , ∣ g t ∣ ) u_t=\max(\beta_2u_{t - 1},\vert g_t\vert) ut=max(β2ut1,gt)
    m ^ t = m t 1 − β 1 t \hat{m}_t=\frac{m_t}{1-\beta_1^t} m^t=1β1tmt
    θ t + 1 = θ t − η u t m ^ t \theta_{t + 1}=\theta_t-\frac{\eta}{u_t}\hat{m}_t θt+1=θtutηm^t
    其中, m t m_t mt β 1 \beta_1 β1 m ^ t \hat{m}_t m^t的含义与Adam中相同, u t u_t ut是无穷范数的指数移动平均, ∣ g t ∣ \vert g_t\vert gt是第 t t t步梯度的绝对值, η \eta η是学习率。

代码实现

import numpy as np

class Adamax:
    def __init__(self, lr=0.01, beta1=0.9, beta2=0.999, eps=1e-8):
        self.lr = lr
        self.beta1 = beta1
        self.beta2 = beta2
        self.eps = eps
        self.m = None
        self.u = None
        self.t = 0

    def update(self, w, grad_w):
        self.t += 1
        if self.m is None:
            self.m = np.zeros_like(grad_w)
            self.u = np.zeros_like(grad_w)

        self.m = self.beta1 * self.m + (1 - self.beta1) * grad_w
        self.u = np.maximum(self.beta2 * self.u, np.abs(grad_w))

        m_hat = self.m / (1 - self.beta1 ** self.t)
        dx = self.lr * m_hat / (self.u + self.eps)
        return w - dx

可视效果

在这里插入图片描述
在这里插入图片描述

🚀 NAdam

算法原理

  • 基本原理:NAdam是在Adam的基础上结合了Nesterov加速梯度(NAG)的思想,通过对未来梯度的近似估计来调整参数更新的方向,使得参数更新能够更快速地向最优解收敛,进一步提高了训练的效率和收敛速度。
  • 参数更新数学公式
    m t = β 1 m t − 1 + ( 1 − β 1 ) g t m_t=\beta_1m_{t - 1}+(1-\beta_1)g_t mt=β1mt1+(1β1)gt
    m ^ t = m t 1 − β 1 t \hat{m}_t=\frac{m_t}{1-\beta_1^t} m^t=1β1tmt
    g t ′ = β 1 m t − 1 1 − β 1 t + ( 1 − β 1 ) g t g_t^\prime=\frac{\beta_1m_{t - 1}}{1-\beta_1^t}+(1-\beta_1)g_t gt=1β1tβ1mt1+(1β1)gt
    v t = β 2 v t − 1 + ( 1 − β 2 ) g t 2 v_t=\beta_2v_{t - 1}+(1-\beta_2)g_t^2 vt=β2vt1+(1β2)gt2
    v ^ t = v t 1 − β 2 t \hat{v}_t=\frac{v_t}{1-\beta_2^t} v^t=1β2tvt
    θ t + 1 = θ t − η v ^ t + ϵ g t ′ \theta_{t + 1}=\theta_t-\frac{\eta}{\sqrt{\hat{v}_t}+\epsilon}g_t^\prime θt+1=θtv^t +ϵηgt
    其中,各参数含义与Adam中类似。

代码实现

import numpy as np

class NAdam:
    def __init__(self, lr=0.01, beta1=0.9, beta2=0.999, eps=1e-8):
        self.lr = lr
        self.beta1 = beta1
        self.beta2 = beta2
        self.eps = eps
        self.m = None
        self.v = None
        self.t = 0

    def update(self, w, grad_w):
        self.t += 1
        if self.m is None:
            self.m = np.zeros_like(grad_w)
            self.v = np.zeros_like(grad_w)

        self.m = self.beta1 * self.m + (1 - self.beta1) * grad_w
        self.v = self.beta2 * self.v + (1 - self.beta2) * grad_w ** 2

        m_hat = self.beta1 * self.m / (1 - self.beta1 ** self.t) + (1 - self.beta1) * grad_w / (1 - self.beta1 ** self.t)
        v_hat = self.v / (1 - self.beta2 ** self.t)

        dx = self.lr * m_hat / (np.sqrt(v_hat) + self.eps)
        return w - dx

可视效果

在这里插入图片描述
在这里插入图片描述

🚀 RProp

算法原理

  • 基本原理:RProp基于梯度的符号来调整参数更新的步长,而不依赖于梯度的大小。如果当前梯度与上一次梯度的符号相同,则增加步长;如果符号相反,则减小步长。这种方法可以在一定程度上避免梯度消失或爆炸问题,提高训练的稳定性和收敛速度。
  • 参数更新数学公式
    Δ θ t = { − η + Δ θ t − 1 , g t g t − 1 > 0 − η − Δ θ t − 1 , g t g t − 1 < 0 Δ θ t − 1 , g t g t − 1 = 0 \Delta\theta_t=\begin{cases}-\eta^+\Delta\theta_{t - 1},&g_tg_{t - 1}>0\\-\eta^-\Delta\theta_{t - 1},&g_tg_{t - 1}<0\\\Delta\theta_{t - 1},&g_tg_{t - 1}=0\end{cases} Δθt= η+Δθt1,ηΔθt1,Δθt1,gtgt1>0gtgt1<0gtgt1=0
    θ t + 1 = θ t + Δ θ t \theta_{t + 1}=\theta_t+\Delta\theta_t θt+1=θt+Δθt
    其中, η + \eta^+ η+ η − \eta^- η分别是步长增加和减小的因子, g t g_t gt是第 t t t步的梯度, Δ θ t \Delta\theta_t Δθt是参数更新量。

代码实现

import numpy as np

class RProp:
    def __init__(self, lr_plus=1.2, lr_minus=0.5, delta_max=50, delta_min=1e-6, initial_delta=0.1):
        self.lr_plus = lr_plus
        self.lr_minus = lr_minus
        self.delta_max = delta_max
        self.delta_min = delta_min
        self.initial_delta = initial_delta
        self.delta = None
        self.sign_grad_prev = None

    def update(self, w, grad_w):
        if self.delta is None:
            self.delta = np.ones_like(grad_w) * self.initial_delta
            self.sign_grad_prev = np.sign(grad_w)

        sign_grad = np.sign(grad_w)
        self.delta *= (sign_grad == self.sign_grad_prev) * self.lr_plus + (sign_grad!= self.sign_grad_prev) * self.lr_minus
        self.delta = np.minimum(self.delta_max, np.maximum(self.delta_min, self.delta))
        self.sign_grad_prev = sign_grad

        dx = -self.delta * sign_grad
        return w + dx

可视效果

在这里插入图片描述
在这里插入图片描述

🚀 代码结构

github项目链接

preject
	|--optim
	|--result
	|--main.py
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D

from optim import Adadelta, Adagrad, Adam, Adamax, AdamW, NAdam, RMSProp, RProp, SGD, SparseAdam

# 定义二维损失函数
def loss_function(x, y):
    return 3 * x ** 2 + 4 * y ** 2

# 计算损失函数关于x和y的偏导数(针对单个样本的情况)
def gradient(x, y):
    grad_x = 6 * x
    grad_y = 8 * y
    return np.array([grad_x, grad_y])

def train(optimizer_name, num_iterations=500):
    # 初始参数
    params = np.array([4.5, 4.5])
    x, y = params[0], params[1]
    # 创建优化器实例
    if optimizer_name == "Adadelta":
        optimizer = Adadelta()
    elif optimizer_name == "Adagrad":
        optimizer = Adagrad()
    elif optimizer_name == "Adam":
        optimizer = Adam()
    elif optimizer_name == "Adamax":
        optimizer = Adamax()
    elif optimizer_name == "AdamW":
        optimizer = AdamW()
    elif optimizer_name == "NAdam":
        optimizer = NAdam()
    elif optimizer_name == "RMSProp":
        optimizer = RMSProp()
    elif optimizer_name == "RProp":
        optimizer = RProp()
    elif optimizer_name == "SGD":
        optimizer = SGD()
    elif optimizer_name == "SparseAdam":
        optimizer = SparseAdam()
    else:
        raise Exception("Not Support This Optimizer!")

    # 用于存储每次迭代的x、y和损失值,方便可视化
    x_history = []
    y_history = []
    loss_history = []

    for _ in range(num_iterations):
        grads = gradient(x, y)
        params = np.array([x, y])
        updated_params = optimizer.update(params, grads)
        x, y = updated_params[0], updated_params[1]
        loss = loss_function(x, y)
        x_history.append(x)
        y_history.append(y)
        loss_history.append(loss)

    # 创建3D图形对象
    fig = plt.figure()
    ax = fig.add_subplot(111, projection='3d')

    # 生成用于绘制损失函数曲面的网格数据
    x_range = np.linspace(-5, 5, 100)
    y_range = np.linspace(-5, 5, 100)
    X, Y = np.meshgrid(x_range, y_range)
    Z = loss_function(X, Y)

    # 绘制损失函数曲面
    ax.plot_surface(X, Y, Z, alpha=0.5, cmap='viridis')

    # 绘制参数x、y变化以及对应损失函数值的散点图
    ax.plot(x_history, y_history, loss_history, c='r', marker='.', label=f'{optimizer_name} Optimization Path')

    # 设置坐标轴标签
    ax.set_xlabel('x')
    ax.set_ylabel('y')
    ax.set_zlabel('Loss')

    # 设置图形标题
    ax.set_title(f'Parameter and Loss Change with {optimizer_name}')

    # 添加图例
    ax.legend()

    # 显示图形
    plt.savefig(f'result\\{optimizer_name}.png')
    plt.close()

    # 可视化损失下降过程
    plt.plot(loss_history)
    plt.xlabel('Iteration')
    plt.ylabel('Loss')
    plt.title(f'Loss Decrease with {optimizer_name}')
    # 显示图形
    plt.savefig(f'result\\{optimizer_name}_loss.png')
    plt.close()

if __name__ == "__main__":
    names = ["Adadelta", "Adagrad", "Adam", "Adamax", "AdamW", "NAdam", "RMSProp", "RProp", "SGD", "SparseAdam"]
    for name in names:
        train(optimizer_name=name)
本文章已经生成可运行项目
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

四口鲸鱼爱吃盐

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值