jjzjj

c++ - 试图理解 adadelta 算法

coder 2024-02-23 原文

我正在尝试将 adadelta 实现到我的简单前馈神经网络 但我认为我在理解这篇文章时遇到了一些麻烦。 http://arxiv.org/pdf/1212.5701v1.pdf
这是一篇解释/介绍 adadelta 算法的小文章。 只有 1 个半页专注于公式。

从部分开始:

Algorithm 1 Computing ADADELTA update at time t


问题 1 部分:'3:计算梯度:gt'

这里我究竟如何计算梯度? 我的方法是否正确:

/* calculating gradient value for neuron what is inside the hidden layer
gradient = sum of ( outcoming connection target's gradient * outcoming connection's weight ) * derivative function */
double CalculatHiddenGradient() {
    double sum = 0.0;
    for (int i = 0; i < OutcomingConnections.size(); i++) {
        sum += OutcomingConnections[i]->weight * OutcomingConnections[i]->target->gradient;
    }
    return (1.0 - output * output) * sum; // tanh's derivative function
}

// calculating gradient value for output neurons where we know the desired output value
double CalculatGradient(double TargetOutput) {
    return (TargetOutput - output) * (1.0 - output * output);
}

问题 2 部分:'5:计算更新:Δxt'

公式(14) 说如下:

∆xt = -( RMS[∆x]t−1) / RMS[g]t) * gt;

是RMS[Δx]t−1计算如下:

RMS[∆x]t−1 = sqrt( E[∆x²]t-1 + e )

从公式(9)中取体?


根据我目前的理解,我能够写出这段代码:

class AdaDelta {
private:
    vector<double> Eg; // E[g²]
    vector<double> Ex; // E[∆x²]
    vector<double> g; // gradient
    int windowsize;
    double p; // Decay rate ρ
    double e; // Constant e, epsilon?

public:
    AdaDelta(int WindowSize = 32, double DecayRate = 0.95, double ConstantE = 0.001) { // initalizing variables
        Eg.reserve(WindowSize + 1);
        Ex.reserve(WindowSize + 1);

        Eg.push_back(0.0); // E[g²]t
        Ex.push_back(0.0); // E[∆x²]t
        g.push_back(0.0); // (gradient)t

        windowsize = WindowSize; // common value:?

        p = DecayRate; // common value:0.95
        e = ConstantE; // common value:0.001
    }

    // Does it return weight update value?
    double CalculateUpdated(double gradient) {
        double dx; // ∆xt
        int t;

        // for t = 1 : T do %% Loop over # of updates
        for (t = 1; t < Eg.size(); t++) {

            // Accumulate Gradient
            Eg[t] = (p * Eg[t - 1] + (1.0 - p) * (g[t] * g[t]));

            // Compute Update
            dx = -(sqrt(Ex[t - 1] + e) / sqrt(Eg[t] + e)) * g[t];

            // Accumulate Updates
            Ex[t] = Ex[t - 1] + (1.0 - p) * (dx * dx);
        }

        /* calculate new update
        =================================== */
        t = g.size();
        g.push_back(gradient);

        // Accumulate Gradient
        Eg.push_back((p * Eg[t - 1] + (1.0 - p) * (g[t] * g[t])));

        // Compute Update
        dx = -(sqrt(Ex[t - 1] + e) / sqrt(Eg[t] + e)) * g[t];

        // Accumulate Updates
        Ex.push_back(Ex[t - 1] + (1.0 - p) * (dx * dx));

        // Deleting adadelta update when window has grown bigger than we allow
        if (g.size() >= windowsize) {
            Eg[1] = 0.0;
            Ex[1] = 0.0;
            Eg.erase(Eg.begin());
            Ex.erase(Ex.begin());
            g.erase(g.begin());

        }
        return dx;
    }
};

问题三
在反向传播中,更新权重是这样的

target's gradient * source's output * learning rate

但是在 adadelta 算法中我没有看到那个 Action 。 我应该在调用之前将源的输出与目标的梯度混合吗 CalculateUpdated() 函数还是我应该将输出与返回值混合以获得新的权重值?


问题四
一路让我困惑的一部分

3.2. Idea 2: Correct Units with Hessian Approximation

我不太明白我们在这里更新了哪些公式部分或发生了什么变化。 我们在哪里应用下面的公式?

公式(13) ∆x = (∆x/∂f)/∂x;


问题 5
式(13)中的Δx、∂f、∂x分别代表什么?


谢谢!

最佳答案

关于 AdaDelta,您需要了解的是在线机器学习的一般背景。 在线机器学习是您一次获取一个数据的地方(因此必须在数据传入时更新模型的参数),而不是批量机器学习,您可以在其中生成机器学习模型,同时访问整个数据集。

基本上,您有一组数据点以及您试图在表单中预测的目标

D = {(A_1,b_1), (A_2,b_2), (A_3,b_3), ...}

其中A_k是第k条训练数据,b_k是正确答案。您通常希望您的机器学习模型(例如分类器或回归器,例如神经网络或线性模型)更新其内部参数

x = (x_1, x_2, ..., x_n)

因为它一次读取一个数据点 (A_k,b_k),即您希望模型在数据进入时“实时”更新 x。这与批处理学习相反,您的模型可以同时访问整个数据集 D。

现在,我们通常有一个“成本”的概念——在线性回归中,我们试图最小化的成本函数是预测目标值与实际值之间的差异的均方根 (RMS)目标值。

回顾一下在线线性回归的定义,你有一个stochastic gradient descent基于更新步骤,其中参数 x 根据模型到目前为止看到的所有数据进行更新:

x_new <- x_old - gradient(RMS[predicted-actual])

像 AdaGrad 和 AdaDelta 这样的更新规则所做的是提供一种“更好”的方式来执行更新——这可能意味着确保参数更快地收敛到它们的最佳值,或者在 AdaDelta 的情况下,这意味着参数 x 以适当大小的步长“更接近”它们的最佳值,步长大小根据过去的表现而变化。

让我们逐一解决您的问题,一次一个问题:

  • 问题 1:

更高维度的梯度(即当 x 由数组表示时)定义为

gt = (∂f/∂x_1, ∂f/∂x_2, ..., ∂f/∂x_n) (xt)

其中 f(x1,x2,...,x_n) 是您要最小化的函数;在大多数情况下,它是单个示例中的成本函数作为模型参数 x 的函数。换句话说:取成本函数的导数,然后在当前参数 xt 下对其进行评估。

  • 问题 2:

根据我的理解,delta-x的RMS定义为

RMS[\Delta x]_{t-1} = \sqrt{ E[\Delta x^2]_{t-1} + \epsilon },

在哪里

E[\Delta x^2]_t = \rho E[\Delta x^2]_{t-1} + (1-\rho) g^2_T,

初始化为

E[\Delta x^2]_0 = 0.
  • 问题 3:

AdaDelta 纯粹是一个更新规则。一般结构是这样的:

(new_weights @ T) := (old_weights @ T-1) - [adaptive_learning_rate] * (gradient @ T)

在哪里

adaptive_learning_rate := -(RMS[Delta-x] @ T-1)/(RMS[gradient] @ T)

因为AdaDelta的目的是让学习率成为一个动态值,而不是一开始就强制我们为它选择一个任意值。

  • 问题 4:

“用 Hessian 近似校正单位”背后的想法在某种意义上来自物理直觉;也就是说,如果您为每个变量指定某种单位(长度/米、时间/秒、能量/焦耳等),那么 Hessian 矩阵就有适当的单位来更正更新项,以便进行量纲分析。

  • 问题 5:

Delta-x 是更新后 x 的差异。因此,如果 x_i 是更新前的参数,x_{i+1} 是更新后的参数,则 Delta-x 是 (x_{i+1} - x_i)。

(∂f/∂x) 是您要最小化的函数的导数(通常在 ML 中,f 是成本函数)。

关于c++ - 试图理解 adadelta 算法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38467273/

有关c++ - 试图理解 adadelta 算法的更多相关文章

  1. ruby-on-rails - 如何优雅地重启 thin + nginx? - 2

    我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server

  2. 区块链之加解密算法&数字证书 - 2

    目录一.加解密算法数字签名对称加密DES(DataEncryptionStandard)3DES(TripleDES)AES(AdvancedEncryptionStandard)RSA加密法DSA(DigitalSignatureAlgorithm)ECC(EllipticCurvesCryptography)非对称加密签名与加密过程非对称加密的应用对称加密与非对称加密的结合二.数字证书图解一.加解密算法加密简单而言就是通过一种算法将明文信息转换成密文信息,信息的的接收方能够通过密钥对密文信息进行解密获得明文信息的过程。根据加解密的密钥是否相同,算法可以分为对称加密、非对称加密、对称加密和非

  3. ruby - 使用 `+=` 和 `send` 方法 - 2

    如何将send与+=一起使用?a=20;a.send"+=",10undefinedmethod`+='for20:Fixnuma=20;a+=10=>30 最佳答案 恐怕你不能。+=不是方法,而是语法糖。参见http://www.ruby-doc.org/docs/ProgrammingRuby/html/tut_expressions.html它说Incommonwithmanyotherlanguages,Rubyhasasyntacticshortcut:a=a+2maybewrittenasa+=2.你能做的最好的事情是:

  4. CAN协议的学习与理解 - 2

    最近在学习CAN,记录一下,也供大家参考交流。推荐几个我觉得很好的CAN学习,本文也是在看了他们的好文之后做的笔记首先是瑞萨的CAN入门,真的通透;秀!靠这篇我竟然2天理解了CAN协议!实战STM32F4CAN!原文链接:https://blog.csdn.net/XiaoXiaoPengBo/article/details/116206252CAN详解(小白教程)原文链接:https://blog.csdn.net/xwwwj/article/details/105372234一篇易懂的CAN通讯协议指南1一篇易懂的CAN通讯协议指南1-知乎(zhihu.com)视频推荐CAN总线个人知识总

  5. TimeSformer:抛弃CNN的Transformer视频理解框架 - 2

    Transformers开始在视频识别领域的“猪突猛进”,各种改进和魔改层出不穷。由此作者将开启VideoTransformer系列的讲解,本篇主要介绍了FBAI团队的TimeSformer,这也是第一篇使用纯Transformer结构在视频识别上的文章。如果觉得有用,就请点赞、收藏、关注!paper:https://arxiv.org/abs/2102.05095code(offical):https://github.com/facebookresearch/TimeSformeraccept:ICML2021author:FacebookAI一、前言Transformers(VIT)在图

  6. ruby - 如何计算 Liquid 中的变量 +1 - 2

    我对如何计算通过{%assignvar=0%}赋值的变量加一完全感到困惑。这应该是最简单的任务。到目前为止,这是我尝试过的:{%assignamount=0%}{%forvariantinproduct.variants%}{%assignamount=amount+1%}{%endfor%}Amount:{{amount}}结果总是0。也许我忽略了一些明显的东西。也许有更好的方法。我想要存档的只是获取运行的迭代次数。 最佳答案 因为{{incrementamount}}将输出您的变量值并且不会影响{%assign%}定义的变量,我

  7. ruby - 易于初学者理解的 Ruby 库 - 2

    关闭。这个问题不符合StackOverflowguidelines.它目前不接受答案。我们不允许提问寻求书籍、工具、软件库等的推荐。您可以编辑问题,以便用事实和引用来回答。关闭3年前。Improvethisquestion我正处于学习Ruby的阶段,我想查看一些小型库的源代码以了解它们是如何构建的。我不知道什么是小型图书馆,但希望SO能推荐一些易于理解的图书馆来学习。因此,如果有人知道一两个非常小的库,这是新手Rubyists学习的好例子,请推荐!我想使用Manveru'sInnatelib,因为它试图保持在2000LOC以下,但我还不熟悉其中经常使用的Ruby速记。也许大约100-5

  8. ruby - 无法理解 `puts{}.class` 和 `puts({}.class)` 之间的区别 - 2

    由于匿名block和散列block看起来大致相同。我正在玩它。我做了一些严肃的观察,如下所示:{}.class#=>Hash好的,这很酷。空block被视为Hash。print{}.class#=>NilClassputs{}.class#=>NilClass为什么上面的代码和NilClass一样,下面的代码又显示了Hash?puts({}.class)#Hash#=>nilprint({}.class)#Hash=>nil谁能帮我理解上面发生了什么?我完全不同意@Lindydancer的观点你如何解释下面几行:print{}.class#NilClassprint[].class#A

  9. arrays - Ruby 数组 += vs 推送 - 2

    我有一个数组数组,想将元素附加到子数组。+=做我想做的,但我想了解为什么push不做。我期望的行为(并与+=一起工作):b=Array.new(3,[])b[0]+=["apple"]b[1]+=["orange"]b[2]+=["frog"]b=>[["苹果"],["橙子"],["Frog"]]通过推送,我将推送的元素附加到每个子数组(为什么?):a=Array.new(3,[])a[0].push("apple")a[1].push("orange")a[2].push("frog")a=>[[“苹果”、“橙子”、“Frog”]、[“苹果”、“橙子”、“Frog”]、[“苹果”、“

  10. += 的 Ruby 方法 - 2

    有没有办法让Ruby能够做这样的事情?classPlane@moved=0@x=0defx+=(v)#thisiserror@x+=v@moved+=1enddefto_s"moved#{@moved}times,currentxis#{@x}"endendplane=Plane.newplane.x+=5plane.x+=10putsplane.to_s#moved2times,currentxis15 最佳答案 您不能在Ruby中覆盖复合赋值运算符。任务在内部处理。您应该覆盖+,而不是+=。plane.a+=b与plane.a=

随机推荐