神经网络中的算法优化(皮毛讲解)

news2024/12/24 3:26:21

抛砖引玉

在深度学习中,优化算法是训练神经网络时至关重要的一部分。
优化算法的目标是最小化(或最大化)一个损失函数,通常通过调整神经网络的参数来实现。
这个过程可以通过梯度下降法来完成,其中梯度指的是损失函数关于参数的偏导数。
本文将介绍一阶优化算法和二阶优化算法,并详细讲解常用的梯度下降法,包括梯度下降法、随机梯度下降法、动量法、AdaGrad、RMSProp和Adam。
在这里插入图片描述

一阶优化算法

一阶优化算法主要根据损失函数的一阶导数(梯度)来更新模型参数。常见的一阶优化算法包括梯度下降法、随机梯度下降法、动量法等。

1. 梯度下降法(Gradient Descent)

梯度下降法是最基本的优化算法之一,它通过计算损失函数关于参数的梯度,并沿着梯度的反方向更新参数,从而使损失函数不断减小。
在这里插入图片描述
在这里插入图片描述
因为这里的损失函数是在整个数据集上进行计算得到的均值,所以每更新一次模型参数,就要对整个数据集进行一个计算,可想而知这样非常的慢,并且当数据集变得非常大的时候,如此多的数据没法都load到内存中。

void gradient_descent(float *params, float *gradients, float learning_rate, int n)
 {
    for (int i = 0; i < n; i++)
     {
        params[i] -= learning_rate * gradients[i];
    }
}

在这里插入图片描述

2. 随机梯度下降法(Stochastic Gradient Descent)

在这里插入图片描述
随机梯度下降法和梯度下降法其实是走的两个极端,梯度下降法是每次更新都计算整个数据集的loss,而随机梯度下降法每次更新都只用了一对样本,即上面公式中的一对样本(在这里插入图片描述由于每个样本都会对模型进行更新,所以模型更新的特别频繁,参数就会变成高方差,损失函数的波动也会有很大强度的变化。有时候,这是好事,因为这样的可以帮助我们探索新的更新方向,找到更加好的局部极值点。但是,由于频繁的更新和波动,会导致模型的损失收敛的非常不稳定。

在这里插入图片描述
上图就是随机梯度下降法更新过程中loss值的变化,可以发现loss值的变化非常大,这就是模型超调了,整个模型比较不稳定

随机梯度下降法是梯度下降法的一种变种,它在每次迭代中随机选取一部分样本来计算梯度,从而加快了训练速度。

void stochastic_gradient_descent(float *params, float *gradients, float learning_rate, int n) 
{
    for (int i = 0; i < n; i++) 
    {
        params[i] -= learning_rate * gradients[i];
    }
}

在这里插入图片描述

3. 动量法(Momentum)

带momentum(动量)的梯度下降法也是一种很常用的的优化算法。这种方法因为引入了momentum量,所以能够对梯度下降法起到加速的作用。

打个比方,一个球顺着斜坡往下滚动,会因为地心引力的原因而一直加速,速度越来越快的往坡低滚去。梯度下降法中的Momentum量就和地心引力的作用很类似,能够让梯度下降法沿着下降的方向逐渐扩大幅度。起到对梯度下降法进行加速的作用。在这里插入图片描述
从上述公式(1)可以看出,当当前的梯度方向在这里插入图片描述的正负号)和在这里插入图片描述的方向相同时,在这里插入图片描述
所以参数 θ 的变化幅度会增大,从而加快梯度下降法的幅度;而当方向不同时,会逐步减小当前更新的幅度。这样可以有效的对梯度下降法进行加速,同时提高模型的稳定性。

动量法通过引入动量项来加速收敛过程,它模拟了物体运动时的惯性,可以减少梯度更新的波动,从而加快了训练速度。

void momentum(float *params, float *gradients, float learning_rate, float momentum_rate, float *velocities, int n) {
    for (int i = 0; i < n; i++) {
        velocities[i] = momentum_rate * velocities[i] + learning_rate * gradients[i];
        params[i] -= velocities[i];
    }
}

二阶优化算法

二阶优化算法基于损失函数的二阶导数(Hessian矩阵)来更新模型参数。常见的二阶优化算法包括AdaGrad、RMSProp和Adam。

1. AdaGrad

在mini batch梯度下降法中,因为对所有的参数均使用相同的学习率,而当有的参数的梯度很大,有的很小时,显然不合适。另外,对于不同的样本,如果有的样本出现的较为频繁,导致其对应的一些参数更新较为频繁,而有的样本出现的频率很低,导致一些参数更新频率很低时,再采用相同的学习率有时候也不太合适。我们更加希望那些出现更新频率比较低的参数能够有更大的更新幅度。
在这里插入图片描述

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

在这里插入图片描述

AdaGrad算法通过动态调整学习率来提高收敛速度,它根据参数的历史梯度调整学习率,对于频繁出现的参数会降低学习率,对于不经常出现的参数会增加学习率。

void adagrad(float *params, float *gradients, float learning_rate, float epsilon, float *accumulators, int n)
 {
    for (int i = 0; i < n; i++)
     {
        accumulators[i] += gradients[i] * gradients[i];
        params[i] -= learning_rate * gradients[i] / (sqrt(accumulators[i]) + epsilon);
    }
}

2. RMSProp

RMSProp算法是对AdaGrad算法的改进,它通过引入一个衰减系数来控制历史梯度的衰减速度,从而减少了学习率的波动。

void rmsprop(float *params, float *gradients, float learning_rate, float decay_rate, float epsilon, float *accumulators, int n) 
{
    for (int i = 0; i < n; i++) 
    {
        accumulators[i] = decay_rate * accumulators[i] + (1 - decay_rate) * gradients[i] * gradients[i];
        params[i] -= learning_rate * gradients[i] / (sqrt(accumulators[i]) + epsilon);
    }
}

3. Adam

前面我们从最经典的梯度下降法开始,介绍了几个改进版的梯度下降法。
Momentum方法通过添加动量,提高收敛速度;
Nesterov方法在进行当前更新前,先进行一次预演,从而找到一个更加适合当前情况的梯度方向和幅度;
Adagrad让不同的参数拥有不同的学习率,并且通过引入梯度的平方和作为衰减项,而在训练过程中自动降低学习率;
AdaDelta则对Adagrad进行改进,让模型在训练后期也能够有较为适合的学习率。
在这里插入图片描述

Adam算法是一种结合了动量法和RMSProp算法的优化算法,它不仅考虑了梯度的一阶矩(均值),还考虑了梯度的二阶矩(方差),从而更加准确地更新参数。

void adam(float *params, float *gradients, float learning_rate, float beta1, float beta2, float epsilon, float *m, float *v, int t, int n) {
    for (int i = 0; i < n; i++) 
    {
        m[i] = beta1 * m[i] + (1 - beta1) * gradients[i];
        v[i] = beta2 * v[i] + (1 - beta2) * gradients[i] * gradients[i];
        float m_hat = m[i] / (1 - pow(beta1, t));
        float v_hat = v[i] / (1 - pow(beta2, t));
        params[i] -= learning_rate * m_hat / (sqrt(v_hat) + epsilon);
    }
}

代码实现

下面是一个简单示例,演示了如何使用上述优化算法训练一个简单的线性回归模型。

#include <iostream>
#include <cmath>

void gradient_descent(float *params, float *gradients, float learning_rate, int n) 
{
    for (int i = 0; i < n; i++)
     {
        params[i] -= learning_rate * gradients[i];
    }
}

void stochastic_gradient_descent(float *params, float *gradients, float learning_rate, int n)
 {
    for (int i = 0; i < n;```cpp
 i++) {
        params[i] -= learning_rate * gradients[i];
    }
}

void momentum(float *params, float *gradients, float learning_rate, float momentum_rate, float *velocities, int n) 
{
    for (int i = 0; i < n; i++)
     {
        velocities[i] = momentum_rate * velocities[i] + learning_rate * gradients[i];
        params[i] -= velocities[i];
    }
}

void adagrad(float *params, float *gradients, float learning_rate, float epsilon, float *accumulators, int n)
 {
    for (int i = 0; i < n; i++)
     {
        accumulators[i] += gradients[i] * gradients[i];
        params[i] -= learning_rate * gradients[i] / (sqrt(accumulators[i]) + epsilon);
    }
}

void rmsprop(float *params, float *gradients, float learning_rate, float decay_rate, float epsilon, float *accumulators, int n)
 {
    for (int i = 0; i < n; i++) 
    {
        accumulators[i] = decay_rate * accumulators[i] + (1 - decay_rate) * gradients[i] * gradients[i];
        params[i] -= learning_rate * gradients[i] / (sqrt(accumulators[i]) + epsilon);
    }
}

void adam(float *params, float *gradients, float learning_rate, float beta1, float beta2, float epsilon, float *m, float *v, int t, int n) 
{
    for (int i = 0; i < n; i++)
     {
        m[i] = beta1 * m[i] + (1 - beta1) * gradients[i];
        v[i] = beta2 * v[i] + (1 - beta2) * gradients[i] * gradients[i];
        float m_hat = m[i] / (1 - pow(beta1, t));
        float v_hat = v[i] / (1 - pow(beta2, t));
        params[i] -= learning_rate * m_hat / (sqrt(v_hat) + epsilon);
    }
}

int main()
 {
    // 参数初始化
    float params[2] = {0};
    float gradients[2] = {0};
    float velocities[2] = {0};
    float accumulators[2] = {0};
    float m[2] = {0};
    float v[2] = {0};
    
    // 数据初始化
    float x[5] = {1, 2, 3, 4, 5};
    float y[5] = {2, 4, 6, 8, 10};
    
    // 学习率
    float learning_rate = 0.01;
    // 动量因子
    float momentum_rate = 0.9;
    // AdaGrad参数
    float epsilon_adagrad = 1e-8;
    // RMSProp参数
    float decay_rate_rmsprop = 0.9;
    float epsilon_rmsprop = 1e-8;
    // Adam参数
    float beta1_adam = 0.9;
    float beta2_adam = 0.999;
    float epsilon_adam = 1e-8;
    
    // 训练
    int epochs = 100;
    int n = 2;
    for (int epoch = 1; epoch <= epochs; epoch++) {
        float loss = 0;
        for (int i = 0; i < 5; i++) {
            float prediction = params[0] * x[i] + params[1];
            float error = prediction - y[i];
            loss += error * error;
            gradients[0] = 2 * error * x[i];
            gradients[1] = 2 * error;
            
            // 使用各种优化算法更新参数
            // gradient_descent(params, gradients, learning_rate, n);
            // stochastic_gradient_descent(params, gradients, learning_rate, n);
            // momentum(params, gradients, learning_rate, momentum_rate, velocities, n);
            // adagrad(params, gradients, learning_rate, epsilon_adagrad, accumulators, n);
            // rmsprop(params, gradients, learning_rate, decay_rate_rmsprop, epsilon_rmsprop, accumulators, n);
            adam(params, gradients, learning_rate, beta1_adam, beta2_adam, epsilon_adam, m, v, epoch, n);
        }
        loss /= 5;
        std::cout << "Epoch " << epoch << ", Loss = " << loss << ", Params = " << params[0] << ", " << params[1] << std::endl;
    }
    
    return 0;
}

这段代码演演示了实现梯度下降法、随机梯度下降法、动量法、AdaGrad、RMSProp和Adam等优化算法来训练一个简单的线性回归模型
在这里插入图片描述

总结 Gradient Descent Algorithm

Gradient Descent is one of the fundamental optimization algorithms used in machine learning and deep learning. It is used to minimize a loss function by iteratively adjusting the parameters of a model. The basic idea behind Gradient Descent is to compute the gradient of the loss function with respect to the model’s parameters and update the parameters in the opposite direction of the gradient to minimize the loss.

Algorithm Steps:

  1. Initialize Parameters: Start by initializing the parameters of the model with random values.

  2. Compute Gradients: Compute the gradient of the loss function with respect to each parameter of the model using backpropagation.

  3. Update Parameters: Update the parameters of the model using the following update rule:

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

  5. Repeat: Repeat steps 2 and 3 until the loss converges to a minimum or for a fixed number of iterations.

Pseudocode:

function gradient_descent(params, gradients, learning_rate):
    for each parameter theta in params:
        theta = theta - learning_rate * gradient

Implementation in C++:

void gradient_descent(float *params, float *gradients, float learning_rate, int n) {
    for (int i = 0; i < n; i++) {
        params[i] -= learning_rate * gradients[i];
    }
}

Conclusion:

Gradient Descent is a powerful optimization algorithm used to train machine learning and deep learning models. It is simple to implement and computationally efficient, making it the go-to choice for optimizing a wide range of models.


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1644369.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Windows查找JDK的安装路径

如果很久之前安装了JDK&#xff0c;或者在别人的电脑上&#xff0c;想要快速指导JDK 的安装路径&#xff0c;可以通过啥方式指导JDK的安装路径是在哪里呢&#xff1f; 一、确认是否安装了JDK 首先我们打开命令行&#xff0c;如果输入 java -version 如果显示这种&#xff0c;…

IBM收购HashiCorp:开源工具的未来与“好软件的坟墓”

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

VBA 创建透视表,录制宏,自动化报表

目录 一. 数据准备二. 需求三. 准备好报表模板四. 执行统计操作&#xff0c;录制宏4.1 根据数据源创建透视表4.2 填充数据到报表4.3 结束宏录制 五. 执行录制好的宏&#xff0c;自动化报表 一. 数据准备 ⏹数据源1 姓名学科成绩丁志敏语文91李平平语文81王刚语文64张伊语文50…

场景文本检测识别学习 day08(无监督的Loss Function、代理任务、特征金字塔)

无监督的Loss Function&#xff08;无监督的目标函数&#xff09; 根据有无标签&#xff0c;可以将模型的学习方法分为&#xff1a;无监督、有监督两种。而自监督是无监督的一种无监督的目标函数可以分为以下几种&#xff1a; 生成式网络的做法&#xff0c;衡量模型的输出和固…

【C++STL详解(六)】--------list的模拟实现

目录 前言 一、接口总览 一、节点类的模拟实现 二、迭代器类的模拟实现 迭代器的目的 list迭代器为何要写成类&#xff1f; 迭代器类模板参数说明 模拟实现 1.构造函数 2.*运算符重载 3.->运算符重载 4.前置 5.后置 6.前置-- 7.后置-- 8.! 9. 三、list类的…

【知识加油站】——机电产品数字孪生机理模型构建

明确一种多领域、多层次、参数化、一致性的机电一体化装备数字孪生机理模型构建准则&#xff01; 关键词英文简称&#xff1a; 数字孪生&#xff1a;DT物联网&#xff1a;IoT网络物理系统&#xff1a;CPS高级架构&#xff1a;HLA统一建模语言&#xff1a;UML数控机床&#xf…

2-qt之信号与槽-简单实例讲解

前言、因实践课程讲解需求&#xff0c;简单介绍下qt的信号与槽。 一、了解信号与槽 怎样使用信号与槽&#xff1f; 概览 还记得 X-Window 上老旧的回调函数系统吗&#xff1f;通常它不是类型安全的并且很复杂。&#xff08;使用&#xff09;它&#xff08;会&#xff09;有很多…

精析React与Vue架构异同及React核心技术——涵盖JSX、组件、Props、State、生命周期与16.8版后Hooks深化解析

React&#xff0c;Facebook开源的JavaScript库&#xff0c;用于构建高性能用户界面。通过组件化开发&#xff0c;它使UI的构建、维护变得简单高效。利用虚拟DOM实现快速渲染更新&#xff0c;适用于单页应用、移动应用&#xff08;React Native&#xff09;。React极大推动了现代…

【链表】:链表的带环问题

&#x1f381;个人主页&#xff1a;我们的五年 &#x1f50d;系列专栏&#xff1a;数据结构 &#x1f337;追光的人&#xff0c;终会万丈光芒 前言&#xff1a; 链表的带环问题在链表中是一类比较难的问题&#xff0c;它对我们的思维有一个比较高的要求&#xff0c;但是这一类…

51单片机入门:DS1302时钟

51单片机内部含有晶振&#xff0c;可以实现定时/计数功能。但是其缺点有&#xff1a;精度往往不高、不能掉电使用等。 我们可以通过DS1302时钟芯片来解决以上的缺点。 DS1302时钟芯片 功能&#xff1a;DS1302是一种低功耗实时时钟芯片&#xff0c;内部有自动的计时功能&#x…

Spring Boot:国际化

Spring Boot 前言国际化 前言 在 Spring MVC&#xff1a;视图与视图解析器 的文章中&#xff0c;介绍过使用 Jstl 的 fmt 标签实现国际化&#xff0c;Spring MVC 会把视图由 InternalResourceViewResolver 转换为 JstlView&#xff08;InternalResourceView 的子类&#xff09…

【DPU系列之】如何通过带外口登录到DPU上的ARM服务器?(Bluefield2举例)

文章目录 1. 背景说明2. 详细操作步骤2.1 目标拓扑结构2.2 连接DPU带外口网线&#xff0c;并获取IP地址2.3 ssh登录到DPU 3. 进一步看看系统的一些信息3.1 CPU信息&#xff1a;8核A723.2 内存信息 16GB3.3 查看ibdev设备 3.4 使用小工具pcie2netdev查看信息3.5 查看PCIe设备信息…

【JavaEE 初阶(一)】初识线程

❣博主主页: 33的博客❣ ▶️文章专栏分类:JavaEE◀️ &#x1f69a;我的代码仓库: 33的代码仓库&#x1f69a; &#x1faf5;&#x1faf5;&#x1faf5;关注我带你了解更多线程知识 目录 1.前言2.进程3.线程4.线程和进程的区别5.Thread创建线程5.1继承Thread创建线程5.2实现R…

【深度优先搜索 图论 树】2872. 可以被 K 整除连通块的最大数目

本文涉及知识点 深度优先搜索 图论 树 图论知识汇总 LeetCode 2872. 可以被 K 整除连通块的最大数目 给你一棵 n 个节点的无向树&#xff0c;节点编号为 0 到 n - 1 。给你整数 n 和一个长度为 n - 1 的二维整数数组 edges &#xff0c;其中 edges[i] [ai, bi] 表示树中节点…

课题学习(二十三)---三轴MEMS加速度计芯片ADXL372

声明&#xff1a;本人水平有限&#xff0c;博客可能存在部分错误的地方&#xff0c;请广大读者谅解并向本人反馈错误。 一、基础配置 测量范围-200g-200g&#xff0c;分辨率为12位&#xff0c; V s 、 V D D I / O V_s、V_{DDI/O} Vs​、VDDI/O​范围为1.6V-3.5V 1.1 引脚配…

Apache和Nginx的区别以及如何选择

近来遇到一些客户需要lnmp环境的虚拟主机&#xff0c;但是Hostease这边的虚拟主机都是基于Apache的&#xff0c;尽管二者是不同的服务器软件&#xff0c;但是大多数情况下&#xff0c;通过适当的配置和调整两者程序也是可以兼容的。 目前市面上有许多Web服务器软件&#xff0c;…

Microsoft Remote Desktop Beta for Mac:远程办公桌面连接工具

Microsoft Remote Desktop Beta for Mac不仅是一款远程桌面连接工具&#xff0c;更是开启远程办公新篇章的利器。 它让Mac用户能够轻松访问和操作远程Windows计算机&#xff0c;实现跨平台办公的无缝衔接。无论是在家中、咖啡店还是旅途中&#xff0c;只要有网络连接&#xff0…

Windows平台通过MobaXterm远程登录安装在VMware上的Linux系统(CentOS)

MobaXterm是一个功能强大的远程计算工具&#xff0c;它提供了一个综合的远程终端和图形化的X11服务器。MobaXterm旨在简化远程计算任务&#xff0c;提供了许多有用的功能&#xff0c;使远程访问和管理远程服务器变得更加方便&#xff0c;它提供了一个强大的终端模拟器&#xff…

【人工智能基础】RNN实验

一、RNN特性 权重共享 wordi weight bais 持久记忆单元 wordi weightword baisword hi weighth baish 二、公式化表达 ht</sub f(ht - 1, xt) ht tanh(Whhht - 1 Wxhxt) yt Whyht 三、RNN网络正弦波波形预测 环境准备 import numpy as np import torch …

如何快速找出文件夹里的全部带有中文纯中文的文件

首先&#xff0c;需要用到的这个工具YTool&#xff1a; 度娘网盘 提取码&#xff1a;qwu2 蓝奏云 提取码&#xff1a;2r1z 步骤 1、打开工具&#xff0c;切换到批量复制文件 2、鼠标移到右侧&#xff0c;点击搜索添加 3、设定查找范围、指定为文件、勾选 包含全部子文件夹&…