深度学习——激活函数

一、人工神经元

1.1 构建人工神经元

人工神经元接受多个输入信息,对它们进行加权求和,再经过激活函数处理,最后将这个结果输出。

 

1.2 组成部分

  • 输入(Inputs): 代表输入数据,通常用向量表示,每个输入值对应一个权重。
  • 权重(Weights): 每个输入数据都有一个权重,表示该输入对最终结果的重要性。
  • 偏置(Bias): 一个额外的可调参数,作用类似于线性方程中的截距,帮助调整模型的输出。
  • 加权求和: 神经元将输入乘以对应的权重后求和,再加上偏置。
  • 激活函数(Activation Function): 用于将加权求和后的结果转换为输出结果,引入非线性特性,使神经网络能够处理复杂的任务。常见的激活函数有Sigmoid、ReLU(Rectified Linear Unit)、Tanh等。

1.3 数学表示 

如果有 n 个输入 x1,x2,x3,....,xn,权重分别为w1,w2,w3,.....,w4,偏置为b,则神经元的输出y表示为:

 其中是激活函数。

二、深入神经网络 

2.1 基本结构

神经网络有下面三个基础层(Layer)构建而成:

  • 输入层(Input): 神经网络的第一层,负责接收外部数据,不进行计算。
  • 隐藏层(Hidden): 位于输入层和输出层之间,进行特征提取和转换。隐藏层一般有多层,每一层有多个神经元。
  • 输出层(Output): 网络的最后一层,产生最终的预测结果或分类结果

2.2 网络构建

 我们使用多个神经元来构建神经网络,相邻层之间的神经元相互连接,并给每一个连接分配一个权重,经典如下:

 

2.3 全连接神经网络

全连接(Fully Connected,FC)神经网络是前馈神经网络的一种,每一层的神经元与上一层的所有神经元全连接,常用于图像分类、文本分类等任务。

2.3.1 特点
  • 全连接层: 层与层之间的每个神经元都与前一层的所有神经元相连。
  • 权重数量: 由于全连接的特点,权重数量较大,容易导致计算量大、模型复杂度高。
  • 学习能力: 能够学习输入数据的全局特征,但对于高维数据却不擅长捕捉局部特征(如图像就需要CNN)。
2.3.2 计算步骤
  1. 数据传递: 输入数据经过每一层的计算,逐层传递到输出层。

  2. 激活函数: 每一层的输出通过激活函数处理。

  3. 损失计算: 在输出层计算预测值与真实值之间的差距,即损失函数值。

  4. 反向传播(Back Propagation): 通过反向传播算法计算损失函数对每个权重的梯度,并更新权重以最小化损失。

三、参数初始化

3.1 固定值初始化

固定值初始化是指在神经网络训练开始时,将所有权重或偏置初始化为一个特定的常数值。这种初始化方法虽然简单,但在实际深度学习应用中通常并不推荐。

3.1.1 全零初始化

将神经网络中的所有权重参数初始化为0。

方法:将所有权重初始化为零。

缺点:导致对称性破坏,每个神经元在每一层中都会执行相同的计算,模型无法学习。

应用场景:通常不用来初始化权重,但可以用来初始化偏置。

# 全0参数初始化
linear = nn.Linear(in_features=6, out_features=4)
# 初始化权重参数
nn.init.zeros_(linear.weight)

# 结果
# Parameter containing:
# tensor([[0., 0., 0., 0., 0., 0.],
          [0., 0., 0., 0., 0., 0.],
          [0., 0., 0., 0., 0., 0.],
          [0., 0., 0., 0., 0., 0.]], requires_grad=True)

3.1.2 全1初始化

全1初始化会导致网络中每个神经元接收到相同的输入信号,进而输出相同的值,这就无法进行学习和收敛。所以全1初始化只是一个理论上的初始化方法,但在实际神经网络的训练中并不适用。

# 全1参数初始化
linear = nn.Linear(in_features=6, out_features=4)
# 初始化权重参数
nn.init.ones_(linear.weight)


# 结果
# Parameter containing:
# tensor([[1., 1., 1., 1., 1., 1.],
          [1., 1., 1., 1., 1., 1.],
          [1., 1., 1., 1., 1., 1.],
          [1., 1., 1., 1., 1., 1.]], requires_grad=True)

3.1.3 任意常数初始化

将所有参数初始化为某个非零的常数(如 0.1,-1 等)。虽然不同于全0和全1,但这种方法依然不能避免对称性破坏的问题。

# 固定值参数初始化
linear = nn.Linear(in_features=6, out_features=4)
# 初始化权重参数
nn.init.constant_(linear.weight, 0.63)


# 结果
# Parameter containing:
# tensor([[0.6300, 0.6300, 0.6300, 0.6300, 0.6300, 0.6300],
          [0.6300, 0.6300, 0.6300, 0.6300, 0.6300, 0.6300],
          [0.6300, 0.6300, 0.6300, 0.6300, 0.6300, 0.6300],
          [0.6300, 0.6300, 0.6300, 0.6300, 0.6300, 0.6300]], requires_grad=True)

3.2 随机初始化

方法:将权重初始化为随机的小值,通常从正态分布或均匀分布中采样。

应用场景:这是最基本的初始化方法,通过随机初始化避免对称性破坏。

代码演示:随机分布之均匀初始化

# 均匀分布随机初始化
linear = nn.Linear(in_features=6, out_features=4)
# 初始化权重参数
nn.init.uniform_(linear.weight)


# 结果
# Parameter containing:
# tensor([[0.4080, 0.7444, 0.7616, 0.0565, 0.2589, 0.0562],
          [0.1485, 0.9544, 0.3323, 0.9802, 0.1847, 0.6254],
          [0.6256, 0.2047, 0.5049, 0.3547, 0.9279, 0.8045],
          [0.1994, 0.7670, 0.8306, 0.1364, 0.4395, 0.0412]], requires_grad=True)

代码演示: 正态分布初始化

# 正太分布初始化
linear = nn.Linear(in_features=6, out_features=4)
# 初始化权重参数
nn.init.normal_(linear.weight, mean=0, std=1)

# 结果
# Parameter containing:
# tensor([[ 1.5321,  0.2394,  0.0622,  0.4482,  0.0757, -0.6056],
          [ 1.0632,  1.8069,  1.1189,  0.2448,  0.8095, -0.3486],
          [-0.8975,  1.8253, -0.9931,  0.7488,  0.2736, -1.3892],
          [-0.3752,  0.0500, -0.1723, -0.4370, -1.5334, -0.5393]], requires_grad=True)

3.3 Xavier 初始化

也叫做Glorot初始化。

方法:根据输入和输出神经元的数量来选择权重的初始值。权重从以下分布中采样:

或者  

 

优点:平衡了输入和输出的方差,适合 Sigmoid 和 Tanh 激活函数。

应用场景:常用于浅层网络或使用 Sigmoid 、Tanh 激活函数的网络。

代码演示:

import torch
import torch.nn as nn


def test007():
    # Xavier初始化:正态分布
    linear = nn.Linear(in_features=6, out_features=4)
    nn.init.xavier_normal_(linear.weight)
    print(linear.weight)

    # Xavier初始化:均匀分布
    linear = nn.Linear(in_features=6, out_features=4)
    nn.init.xavier_uniform_(linear.weight)
    print(linear.weight)


if __name__ == "__main__":
    test007()


# 结果
Parameter containing:
tensor([[-0.4838,  0.4121, -0.3171, -0.2214, -0.8666, -0.4340],
        [ 0.1059,  0.6740, -0.1025, -0.1006,  0.5757, -0.1117],
        [ 0.7467, -0.0554, -0.5593, -0.1513, -0.5867, -0.1564],
        [-0.1058,  0.5266,  0.0243, -0.5646, -0.4982, -0.1844]], requires_grad=True)

Parameter containing:
tensor([[-0.5263,  0.3455,  0.6449,  0.2807, -0.3698, -0.6890],
        [ 0.1578, -0.3161, -0.1910, -0.4318, -0.5760,  0.3746],
        [ 0.2017, -0.6320, -0.4060,  0.3903,  0.3103, -0.5881],
        [ 0.6212,  0.3077,  0.0783, -0.6187,  0.3109, -0.6060]], requires_grad=True)

3.4 He初始化

也叫kaiming 初始化。

方法:专门为 ReLU 激活函数设计。权重从以下分布中采样:

优点:适用于 ReLU 和 Leaky ReLU 激活函数。

应用场景:深度网络,尤其是使用 ReLU 激活函数时。

代码演示:

import torch
import torch.nn as nn


def test006():
    # He初始化:正态分布
    linear = nn.Linear(in_features=6, out_features=4)
    nn.init.kaiming_normal_(linear.weight, nonlinearity="relu")
    print(linear.weight)

    # He初始化:均匀分布
    linear = nn.Linear(in_features=6, out_features=4)
    nn.init.kaiming_uniform_(linear.weight, nonlinearity="relu")
    print(linear.weight)


if __name__ == "__main__":
    test006()



# 结果
Parameter containing:
tensor([[ 1.4020,  0.2030,  0.3585, -0.7419,  0.6077,  0.0178],
        [-0.2860, -1.2135,  0.0773, -0.3750, -0.5725,  0.9756],
        [ 0.2938, -0.6159, -1.1721,  0.2093,  0.4212,  0.9079],
        [ 0.2050,  0.3866, -0.3129, -0.3009, -0.6659, -0.2261]], requires_grad=True)

Parameter containing:
tensor([[-0.1924, -0.6155, -0.7438, -0.2796, -0.1671, -0.2979],
        [ 0.7609,  0.9836, -0.0961,  0.7139, -0.8044, -0.3827],
        [ 0.1416,  0.6636,  0.9539,  0.4735, -0.2384, -0.1330],
        [ 0.7254, -0.4056, -0.7621, -0.6139, -0.6093, -0.2577]], requires_grad=True)

四、激活函数

激活函数的作用是在隐藏层引入非线性,使得神经网络能够学习和表示复杂的函数关系,使网络具备非线性能力,增强其表达能力。

4.1 sigmoid

Sigmoid激活函数是一种常见的非线性激活函数,特别是在早期神经网络中应用广泛。它将输入映射到0到1之间的值,因此非常适合处理概率问题。

4.1.1 公式

Sigmoid函数的数学表达式为:

其中,e 是自然常数(约等于2.718),x 是输入。

4.1.2 特征

  1. 将任意实数输入映射到 (0, 1)之间,因此非常适合处理概率场景。
  2. sigmoid函数一般只用于二分类的输出层。
  3. 微分性质: 导数计算比较方便,可以用自身表达式来表示:

4.1.3 缺点

  • 梯度消失:
    • 在输入非常大或非常小时,Sigmoid函数的梯度会变得非常小,接近于0。这导致在反向传播过程中,梯度逐渐衰减。
    • 最终使得早期层的权重更新非常缓慢,进而导致训练速度变慢甚至停滞。
  • 信息丢失:输入100和输入10000经过sigmoid的激活值几乎都是等于 1 的,但是输入的数据却相差 100 倍。
  • 计算成本高: 由于涉及指数运算,Sigmoid的计算比ReLU等函数更复杂,尽管差异并不显著。

 

4.2 tanh 

tanh(双曲正切)是一种常见的非线性激活函数,常用于神经网络的隐藏层。tanh 函数也是一种S形曲线,输出范围为(−1,1)。

4.2.1 公式

tanh数学表达式为:

4.2.2 特征

  1. 输出范围: 将输入映射到(-1, 1)之间,因此输出是零中心的。相比于Sigmoid函数,这种零中心化的输出有助于加速收敛。
  2. 对称性: Tanh函数关于原点对称,因此在输入为0时,输出也为0。这种对称性有助于在训练神经网络时使数据更平衡。
  3. 平滑性: Tanh函数在整个输入范围内都是连续且可微的,这使其非常适合于使用梯度下降法进行优化。

4.2.3 缺点

  1. 梯度消失: 虽然一定程度上改善了梯度消失问题,但在输入值非常大或非常小时导数还是非常小,这在深层网络中仍然是个问题。
  2. 计算成本: 由于涉及指数运算,Tanh的计算成本还是略高,尽管差异不大。

4.3 ReLU

ReLU(Rectified Linear Unit)是深度学习中最常用的激活函数之一,它的全称是修正线性单元。ReLU 激活函数的定义非常简单,但在实践中效果非常好。

4.3.1 公式

ReLU 函数定义如下:

 即ReLU对输入x进行非线性变换:

4.3.2 特征

  1. 计算简单:ReLU 的计算非常简单,只需要对输入进行一次比较运算,这在实际应用中大大加速了神经网络的训练。
  2. ReLU 函数的导数是分段函数:

  3. 缓解梯度消失问题:相比于 Sigmoid 和 Tanh 激活函数,ReLU 在正半区的导数恒为 1,这使得深度神经网络在训练过程中可以更好地传播梯度,不存在饱和问题。
  4. 稀疏激活:ReLU在输入小于等于 0 时输出为 0,这使得 ReLU 可以在神经网络中引入稀疏性(即一些神经元不被激活),这种稀疏性可以提升网络的泛化能力。 

4.3.3 缺点

神经元死亡:由于ReLU在x≤0时输出为0,如果某个神经元输入值是负,那么该神经元将永远不再激活,成为“死亡”神经元。随着训练的进行,网络中可能会出现大量死亡神经元,从而会降低模型的表达能力。

4.4 LeakyReLU

Leaky ReLU是一种对 ReLU 函数的改进,旨在解决 ReLU 的一些缺点,特别是Dying ReLU 问题。Leaky ReLU 通过在输入为负时引入一个小的负斜率来改善这一问题。

4.4.1 公式

Leaky ReLU 函数的定义如下:

其中,\alpha 是一个非常小的常数(如 0.01),它控制负半轴的斜率。这个常数 \alpha是一个超参数,可以在训练过程中可自行进行调整。

 

4.4.2 特征 

  1. 避免神经元死亡:通过在 x<=0 区域引入一个小的负斜率,这样即使输入值小于等于零,Leaky ReLU仍然会有梯度,允许神经元继续更新权重,避免神经元在训练过程中完全“死亡”的问题。
  2. 计算简单:Leaky ReLU 的计算与 ReLU 相似,只需简单的比较和线性运算,计算开销低。

4.4.3 缺点

  1. 参数选择:\alpha 是一个需要调整的超参数,选择合适的\alpha 值可能需要实验和调优。
  2. 出现负激活:如果\alpha 设定得不当,仍然可能导致激活值过低。

4.5 softmax

Softmax激活函数通常用于分类问题的输出层,它能够将网络的输出转换为概率分布,使得输出的各个类别的概率之和为 1。Softmax 特别适合用于多分类问题。

4.5.1 公式

 假设神经网络的输出层有n个节点,每个节点的输出为z_{i},则 Softmax 函数的定义如下:

4.5.2 特征

  1. 将输出转化为概率:通过Softmax,可以将网络的原始输出转化为各个类别的概率,从而可以根据这些概率进行分类决策。

  2. 概率分布:Softmax的输出是一个概率分布,即每个输出值$$\text{Softmax}(z_i)$$都是一个介于0和1之间的数,并且所有输出值的和为 1:

  3. 突出差异:Softmax会放大差异,使得概率最大的类别的输出值更接近1,而其他类别更接近0。

  4. 在实际应用中,Softmax常与交叉熵损失函数Cross-Entropy Loss结合使用,用于多分类问题。在反向传播中,Softmax的导数计算是必需的。

4.5.3 缺点

1、数值不稳定性:在计算过程中,如果z_{i}的数值过大,e^{z_{i}}可能会导致数值溢出。因此在实际应用中,经常会对z_{i}进行调整,如减去最大值以确保数值稳定。

解释:

z_{i}-max(z)是一个非正数,那么e^{z_{i}-max(z)}的值就位于0到1之间,有效避免了数值溢出。

这中调整不会改变Softmax的概率分布结果,因为从数学的角度讲相当于分子、分母都除以了e^{max(z)}。  

2、难以处理大量类别:Softmax在处理类别数非常多的情况下(如大模型中的词汇表)计算开销会较大。

如何选择

隐藏层

  1. 优先选ReLU;
  2. 如果ReLU效果不咋地,那么尝试其他激活,如Leaky ReLU等;
  3. 使用ReLU时注意神经元死亡问题, 避免出现过多神经元死亡;
  4. 不使用sigmoid,尝试使用tanh;

输出层

  1. 二分类问题选择sigmoid激活函数;
  2. 多分类问题选择softmax激活函数;
  3. 回归问题选择identity激活函数;

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

算法基础 - 求解非线性方程(二分迭代法)

文章目录 1. 基本思想2. 编程实现2.1. 非递归2.2. 递归方案 3. 总结 二分迭代法使用了二分算法思想求解非线性方程式。 下面要求使用二分迭代法求解&#xff1a; 2x3-5x-10 方程式&#xff0c;且要求误差不能大于10e-5。 二分迭代法也只是近似求解算法。 所谓求解&#xff…

如何将 GitHub 私有仓库(private)转换为公共仓库(public)

文章目录 如何将 GitHub 私有仓库转换为公共仓库步骤 1: 登录 GitHub步骤 2: 导航到目标仓库步骤 3: 访问仓库设置步骤 4: 更改仓库可见性步骤 5: 确认更改步骤 6: 验证更改注意事项 如何将 GitHub 私有仓库转换为公共仓库 在软件开发领域&#xff0c;GitHub 是一个广受欢迎的…

SSM搭建(1)——配置MyBatis

目录 一、框架概述 1.什么是JDBC&#xff1f; 2.JDBC基本流程 3.JDBC的缺点 二、MyBatis的入门程序 1. 创建数据库和表结构 2. MyBatis入门流程总结 3. MyBatis的入门步骤 &#xff08;1&#xff09; 创建maven的项目&#xff0c;创建Java工程即可。 &…

Cesium 当前位置矩阵的获取

Cesium 位置矩阵的获取 在 3D 图形和地理信息系统&#xff08;GIS&#xff09;中&#xff0c;位置矩阵是将地理坐标&#xff08;如经纬度&#xff09;转换为世界坐标系的一种重要工具。Cesium 是一个强大的开源 JavaScript 库&#xff0c;用于创建 3D 地球和地图应用。在 Cesi…

大米中的虫子检测-检测储藏的大米中是否有虫子 支持YOLO,VOC,COCO格式标注,4070张图片的数据集

大米中的虫子检测-检测储藏的大米中是否有虫子 支持YOLO&#xff0c;VOC&#xff0c;COCO格式标注&#xff0c;4070张图片的数据集 数据集分割 4070总图像数 训练组 87&#xff05; 3551图片 有效集 9&#xff05; 362图片 测试集 4% 157图片 预处理 自动定向…

Nginx:反向代理

目录 反向代理原理 反向代理配置 日志对比 反向代理原理 网站通过代理服务器发布&#xff0c;用户无需得知网站的实际地址&#xff0c;通过代理服务器进行请求与响应。 用户所有的网站请求报文与响应报文都被代理服务器拦截&#xff0c;在网络层将源地址和目的地址进行了修改…

【c++篇】:解读Set和Map的封装原理--编程中的数据结构优化秘籍

✨感谢您阅读本篇文章&#xff0c;文章内容是个人学习笔记的整理&#xff0c;如果哪里有误的话还请您指正噢✨ ✨ 个人主页&#xff1a;余辉zmh–CSDN博客 ✨ 文章所属专栏&#xff1a;c篇–CSDN博客 文章目录 前言一.set和map的初步封装1.树的节点封装修改2.Find()查找函数3.红…

HASH256开源代码计算错误问题

计算量超500KB报错 OTA升级中可能会涉及到CRC、hash校验等算法&#xff0c;小编从网上抄到了HASH256的源码&#xff0c;拿来使用的时候却发现了一个问题&#xff0c;当源文件约大于500KB的时候会发现其计算出的hash值出现错误。 经过实际测试得知&#xff0c;当源文件大于约50…

vue3项目搭建-6-axios 基础配置

axios 基础配置 安装 axios npm install axios 创建 axios 实例&#xff0c;配置基地址&#xff0c;配置拦截器,目录&#xff1a;utils/http.js 基地址&#xff1a;在每次访问时&#xff0c;自动作为相对路径的根 // axios 基础封装 import axios from "axios";…

Golang项目:实现生产者消费者模式

one-one 先创建out.go目录与文件夹 // 定义了一个名为out的包&#xff0c;用于处理输出相关的功能。 package outimport "fmt"// Out结构体定义了一个channel&#xff0c;用于存储需要输出的数据。 type Out struct {data chan interface{} // data字段是一个inter…

说说Elasticsearch拼写纠错是如何实现的?

大家好&#xff0c;我是锋哥。今天分享关于【说说Elasticsearch拼写纠错是如何实现的&#xff1f;】面试题。希望对大家有帮助&#xff1b; 说说Elasticsearch拼写纠错是如何实现的&#xff1f; 1000道 互联网大厂Java工程师 精选面试题-Java资源分享网 在 Elasticsearch 中&…

【Leecode】Leecode刷题之路第62天之不同路径

题目出处 62-不同路径-题目出处 题目描述 个人解法 思路&#xff1a; todo代码示例&#xff1a;&#xff08;Java&#xff09; todo复杂度分析 todo官方解法 62-不同路径-官方解法 方法1&#xff1a;动态规划 思路&#xff1a; 代码示例&#xff1a;&#xff08;Java&…

Windows修复SSL/TLS协议信息泄露漏洞(CVE-2016-2183) --亲测

漏洞说明&#xff1a; 打开链接&#xff1a;https://docs.microsoft.com/zh-cn/troubleshoot/windows-server/windows-security/restrict-cryptographic-algorithms-protocols-schannel 可以看到&#xff1a; 找到&#xff1a;应通过配置密码套件顺序来控制 TLS/SSL 密码 我们…

第六届国际科技创新(IAECST 2024)暨第四届物流系统与交通运输(LSTT 2024)

重要信息 会议官网&#xff1a;www.lstt.org 大会时间&#xff1a;2024年12月6-8日 大会地点&#xff1a;中国-广州 简介 第六届国际科技创新暨第四届物流系统与交通运输国际&#xff08;LSTT 2024&#xff09;将于2024年12月6-8日在广州举办&#xff0c;这是一个集中探讨…

ArcGIS 软件中路网数据的制作

内容导读 路网数据是进行网络分析的基础&#xff0c;它是建立网络数据集的数据来源。 本文我们以OSM路网数据为例&#xff0c;详细介绍OSM路网数据从下载&#xff0c;到数据处理&#xff0c;添加属性&#xff0c;完成符合网络分析的网络数据集的全部过程。 01 数据获取 比较…

【0346】Postgres内核 Startup Process 通过 signal 与 postmaster 交互实现 (5)

1. Startup Process 进程 postmaster 初始化过程中, 在进入 ServerLoop() 函数之前,会先通过调用 StartChildProcess() 函数来开启辅助进程,这些进程的目的主要用来完成数据库的 XLOG 相关处理。 如: 核实 pg_wal 和 pg_wal/archive_status 文件是否存在Postgres先前是否发…

PYNQ 框架 - OV5640驱动 + Linux 驱动分析

目录 1. 简介 1.1 博文要点 1.2 V4L2 2. 极简 Char 驱动 2.1 源码 2.2 Makefile 2.3 加载驱动 2.4 设备文件 2.5 测试驱动程序 2.6 卸载驱动程序 2.7 自动创建设备文件 2.8 日志等级 3. 极简 V4L2 驱动 3.1 源码 3.2 Makefile 3.3 设备节点类型 3.4 测试 V4L2…

RNN详解及其实现

目录 概述为什么需要 RNN&#xff1f;RNN 理解及其简单实现RNN 完成文本分类任务RNN 存在的问题 概述 提及 RNN&#xff0c;绝大部分人都知道他是一个用于序列任务的神经网络&#xff0c;会提及他保存了时序信息&#xff0c;但是&#xff0c;为什么需要考虑时序的信息&#xf…

Redis开发03:常见的Redis命令

1.输入以下命令&#xff0c;启动redis。 sudo service redis-server start 如果你是直接安装在WSL的&#xff0c;搜索栏搜索Ubuntu或者点击左下角Windows图表找到U那一栏&#xff0c;直接打开Ubentu&#xff0c;输入账密后&#xff0c;输入“sudo service redis-server start”…

【webrtc】 mediasoup中m77的IntervalBudget及其在AlrDetector的应用

IntervalBudget 用于带宽控制和流量整形 mediasoup中m77 代码的IntervalBudget ,版本比较老IntervalBudget 在特定时间间隔内的比特预算管理,从而实现带宽控制和流量整形。 一。 pacedsender 执行周期: 下一次执行的时间的动态可变的 int64_t PacedSender::TimeUntilNextPr…