deeplearning.ai 总结 - C++实现 Adma优化

deeplearning.ai 总结 - C++实现 Adma优化

flyfish

编译环境
VC++2017

理论摘自《深度学习》

Adam一种学习率自适应的优化算法“Adam”这个名字派生自短语”adaptive moments”。
早期算法背景下,它也许最好被看作结合RMSProp和具有一些重要区别的动量的变种。
首先,在Adam中,动量直接并入了梯度一阶矩(指数加权)的估计。 将动量加入RMSProp最直观的方法是将动量应用于缩放后的梯度。
结合缩放的动量使用没有明确的理论动机。 其次,Adam包括偏置修正,修正从原点初始化的一阶矩(动量项)和(非中心的)二阶矩的估计。
RMSProp也采用了(非中心的)二阶矩估计,然而缺失了修正因子。 因此,不像Adam,RMSProp二阶矩估计可能在训练初期有很高的偏置。
Adam通常被认为对超参数的选择相当鲁棒,尽管学习率有时需要从建议的默认修改。

//论文地址
//http://arxiv.org/abs/1412.6980

#include <vector>
#include <unordered_map>

template <typename T, typename Func>
inline void for_i(T size, Func f) {
    for (size_t i = 0; i < size; ++i) {
        f(i);
    }
}

typedef std::vector<double> Tensor2D;
class adam
{
public:
    adam()
        : alpha(double(0.001)),
        b1(double(0.9)),
        b2(double(0.999)),
        b1_t(double(0.9)),
        b2_t(double(0.999)),
        eps(double(1e-8)) {}

    void update(const Tensor2D &dW, Tensor2D &W)
    {
        Tensor2D &mt = get<0>(W);
        Tensor2D &vt = get<1>(W);

        for (auto it = dW.begin(); it != dW.end(); it++)
            std::cout << *it << "\t";
        std::cout << "dW \n";

        for (auto it = mt.begin(); it != mt.end(); it++)
            std::cout << *it << "\t";
        std::cout << "mt \n";

        for (auto it = vt.begin(); it != vt.end(); it++)
            std::cout << *it << "\t";
        std::cout << "vt \n";




        for (const auto& n : E_) //地址的hash作为key
        {
            for (auto it = n.begin(); it != n.end(); it++)
            {
                std::cout << (*it).first << ": ";// << (*it).second << std::endl;


                for (auto s = (*it).second.begin(); s != (*it).second.end(); s++)
                {
                    std::cout << (*s);
                }
                std::cout << "complete \n";
            }

        }


        for_i(W.size(), [&](size_t i) {
            mt[i] = b1 * mt[i] + (double(1.0) - b1) * dW[i];//Momentum
            vt[i] = b2 * vt[i] + (double(1.0) - b2) * dW[i] * dW[i];//RMSprop

            double mt_hat = mt[i] / (double(1) - b1_t);
            double vt_hat = vt[i] / (double(1.0) - b2_t);
            // L2 norm 
            W[i] -= alpha * (mt_hat) / (std::sqrt(vt_hat) + eps);
        });

        b1_t *= b1;
        b2_t *= b2;
    }

    //学习率或步长因子,它控制了权重的更新比率(如 0.001)。
    //较大的值(如 0.3)在学习率更新前会有更快的初始学习,
    //而较小的值(如 1.0E-5)会令训练收敛到更好的性能。
    double alpha;  // learning rate

    //一阶矩估计的指数衰减率(如 0.9)。
    double b1;     // 

    //二阶矩估计的指数衰减率(如 0.999)。
    //该超参数在稀疏梯度(如在 NLP 或计算机视觉任务中)中应该设置为接近 1 的数
    double b2;     //

    double b1_t;   // b1的平方
    double b2_t;   // b2的平方

private:
    //该参数是非常小的数,其为了防止在实现中除以零(如 10E-8)。
    double eps;  
private:
    template <int Index>
    Tensor2D &get(const Tensor2D &key) 
    {
        if (E_[Index][&key].empty()) 
            E_[Index][&key].resize(key.size(), double());
        return E_[Index][&key];
    }
    std::unordered_map<const Tensor2D *, Tensor2D> E_[2];
};

猜你喜欢

转载自blog.csdn.net/flyfish1986/article/details/80199585