调参过程中的参数 学习率,权重衰减,冲量(learning_rate , weight_decay , momentum)

无论是深度学习还是机器学习,大多情况下训练中都会遇到这几个参数,今天依据我自己的理解具体的总结一下,可能会存在错误,还请指正.

learning_rate , weight_decay , momentum这三个参数的含义. 并附上demo.

我们会使用一个例子来说明一下:

比如我们有一堆数据,我们只知道这对数据是从一个黑盒中得到的,我们现在要寻找到那个具体的函数f(x),我们定义为目标函数T.

我们现在假定有存在这个函数并且这个函数为:

我们现在要使用这对数据来训练目标函数. 我们可以设想如果存在一个这个函数,必定满足{x,y}所有的关系,也就是说:

那么最理想的情况下 :   ,那么我们不妨定义这样一个优化目标函数:

对于这堆数据,我们认为当Loss(W)对于所有的pair{x,y}都满足 Loss(W)趋近于或者等于0时,我们认为我们找到这个理想的目标函数T. 也就是此时 .

以上,我们发现寻找的目标函数的问题,已经成功的转移为求解:

也就是Loss 越小, f(x)越接近我们寻找的目标函数T.

那么说了这么多,这个和我们说的学习率learning_rate有什么关系呢?

既然我们知道了我们当前的f(x)和目标函数的T的误差,那么我们可以将这个误差转移到每一个参数上,也就是变成每一个参数w和目标函数T的参数w_t的误差. 然后我们就以一定的幅度stride来缩小和真实值的距离,我们称这个stride为学习率learning_rate 而且我们就是这么做的.

我们用公式表述就是:

我们的误差(损失)Loss:

我们这一个凸函数. 我们先对这个函数进行各个分量求偏导.

对于w0的偏导数:

那么对于分量w0承担的误差为:

  并且这个误差带方向.

那么我们需要使我们当前的w0更加接近目标函数的T的w0_t参数.我们需要做运算:

(梯度下降算法)

来更新wo的值. 同理其他参数w,而这个学习率就是来控制我们每次靠近真实值的幅度,为什么要这么做呢?

因为我们表述的误差只是一种空间表述形式我们可以使用均方差也可以使用绝对值,还可以使用对数,以及交叉熵等等,所以只能大致的反映,并不精确,就想我们问路一样,别人告诉我们直走五分钟,有的人走的快,有的人走的慢,所以如果走的快的话,当再次问路的时候,就会发现走多了,而折回来,这就是我们训练过程中的loss曲线震荡严重的原因之一. 所以学习率要设置在合理的大小.


好了说了这么多,这是学习率. 那么什么是权重衰减weight_decay呢? 有什么作用呢?

我们接着看上面的这个Loss(w),我们发现如果参数过多的话,对于高位的w3,我们对其求偏导:

我们发现w3开始大于1的时候,w3会调节的很快,幅度很大,从而使得特征x3变为异常敏感.从而出现过拟合(overfitting).

这个时候,我们需要约束一下w2,w3等高阶参数的大小,于是我们对Loss增加一个惩罚项,使得Loss的正反方向,不应该只由f(x) -y 决定,而还应该加上一个;于是Loss变成了:

我们继续对Loss求解偏导数:

对wo求偏导:

对w3求偏导:

我们发现当x3值过大时,会改变Loss的导数的方向.而来抑制w2,w3等高阶函数的继续增长. 然而这样抑制并不是很灵活,所以我们在前面加入一个系数,这个系数在数学上称之为拉格朗日乘子系数,也就是我们用到的weight_decay. 这样我们可以通过调节weight_decay系数,来调节w3,w2等高阶的增长程度。加入weight_decay后的公式:

从公式可以看出 ,weight_decay越大,抑制越大,w2,w3等系数越小,weight_decay越小,抑制越小,w2,w3等系数越大


那么冲量momentum又是啥?

我们在使用梯度下降法,来调整w时公式是这样的:

我们每一次都是计算当前的梯度:

这样会发现对于那些梯度比较小的地方,参数w更新的幅度比较小,训练变得漫长,或者收敛慢.有时候遇到非最优的凸点,会出现冲不出去的现象.

而冲量加进来是一种快速效应.借助上一次的势能来和当前的梯度来调节当前的参数w.

公式表达为:

这样可以有效的避免掉入凸点无法冲出来,而且收敛速度也快很多.

附上demo: 使用mxnet编码.

  1 //
  2 // Created by xijun1 on 2017/12/14.
  3 //
  4
  5 #include <iostream>
  6 #include <vector>
  7 #include <string>
  8 #include <mxnet/mxnet-cpp/MxNetCpp.h>
  9 #include <mxnet/mxnet-cpp/op.h>
 10
 11 namespace  mlp{
 12     class MlpNet{
 13     public:
 14         static mx_float OutputAccuracy(mx_float* pred, mx_float* target) {
 15             int right = 0;
 16             for (int i = 0; i < 128; ++i) {
 17                 float mx_p = pred[i * 10 + 0];
 18                 float p_y = 0;
 19                 for (int j = 0; j < 10; ++j) {
 20                     if (pred[i * 10 + j] > mx_p) {
 21                         mx_p = pred[i * 10 + j];
 22                         p_y = j;
 23                     }
 24                 }
 25                 if (p_y == target[i]) right++;
 26             }
 27             return right / 128.0;
 28         }
 29
 30        static void net(){
 31             using mxnet::cpp::Symbol;
 32             using mxnet::cpp::NDArray;
 33
 34             Symbol x = Symbol::Variable("X");
 35             Symbol y = Symbol::Variable("label");
 36
 37             std::vector<std::int32_t> shapes({512 , 10});
 38             //定义一个两层的网络. wx + b
 39             Symbol weight_0 = Symbol::Variable("weight_0");
 40             Symbol biases_0 = Symbol::Variable("biases_0");
 41
 42             Symbol fc_0 = mxnet::cpp::FullyConnected("fc_0",x,weight_0,biases_0
 43                     ,512);
 44
 45             Symbol output_0 = mxnet::cpp::LeakyReLU("relu_0",fc_0,mxnet::cpp::LeakyReLUActType::kLeaky);
 46
 47             Symbol weight_1 = Symbol::Variable("weight_1");
 48             Symbol biases_1 = Symbol::Variable("biases_1");
 49             Symbol fc_1 = mxnet::cpp::FullyConnected("fc_1",output_0,weight_1,biases_1,10);
 50             Symbol output_1 = mxnet::cpp::LeakyReLU("relu_1",fc_1,mxnet::cpp::LeakyReLUActType::kLeaky);
 51             Symbol pred = mxnet::cpp::SoftmaxOutput("softmax",output_1,y);  //目标函数,loss函数
 52             mxnet::cpp::Context ctx = mxnet::cpp::Context::cpu( 0);
 53
 54             //定义输入数据
 55             std::shared_ptr< mx_float > aptr_x(new mx_float[128*28] , [](mx_float* aptr_x){ delete [] aptr_x ;});
 56             std::shared_ptr< mx_float > aptr_y(new mx_float[128] , [](mx_float * aptr_y){ delete [] aptr_y ;});
 57
 58             //初始化数据
 59             for(int i=0 ; i<128 ; i++){
 60                 for(int j=0;j<28 ; j++){
 61                     //定义x
 62                     aptr_x.get()[i*28+j]= i % 10 +0.1f;
 63                 }
 64
 65                 //定义y
 66                 aptr_y.get()[i]= i % 10;
 67             }
 68            std::map<std::string, mxnet::cpp::NDArray> args_map;
 69            //导入数据
 70            NDArray arr_x(mxnet::cpp::Shape(128,28),ctx, false);
 71            NDArray arr_y(mxnet::cpp::Shape( 128 ),ctx,false);
 72            //将数据转换到NDArray中
 73            arr_x.SyncCopyFromCPU(aptr_x.get(),128*28);
 74            arr_x.WaitToRead();
 75
 76            arr_y.SyncCopyFromCPU(aptr_y.get(),128);
 77            arr_y.WaitToRead();
 78
 79            args_map["X"]=arr_x.Slice(0,128).Copy(ctx) ;
 80            args_map["label"]=arr_y.Slice(0,128).Copy(ctx);
 81            NDArray::WaitAll();
 82             //绑定网络
 83            mxnet::cpp::Executor *executor = pred.SimpleBind(ctx,args_map);
 84             //选择优化器
 85            mxnet::cpp::Optimizer *opt = mxnet::cpp::OptimizerRegistry::Find("sgd");
 86            mx_float learning_rate = 0.0001; //学习率
 87            mx_float weight_decay = 1e-4; //权重
 88            opt->SetParam("momentum", 0.9)
 89                    ->SetParam("lr", learning_rate)
 90                    ->SetParam("wd", weight_decay);
 91            //定义各个层参数的数组
 92            NDArray arr_w_0(mxnet::cpp::Shape(512,28),ctx, false);
 93            NDArray arr_b_0(mxnet::cpp::Shape( 512 ),ctx,false);
 94            NDArray arr_w_1(mxnet::cpp::Shape(10 , 512 ) , ctx , false);
 95            NDArray arr_b_1(mxnet::cpp::Shape( 10 ) , ctx , false);
 96
 97            //初始化权重参数
 98            arr_w_0 = 0.01f;
 99            arr_b_1 = 0.01f;
100            arr_w_1 = 0.01f;
101            arr_b_1 = 0.01f;
102
103             //初始化参数
104             executor->arg_dict()["weight_0"]=arr_w_0;
105             executor->arg_dict()["biases_0"]=arr_b_0;
106             executor->arg_dict()["weight_1"]=arr_w_1;
107             executor->arg_dict()["biases_1"]=arr_b_1;
108
109             mxnet::cpp::NDArray::WaitAll();
110             //训练
111             std::cout<<" Training "<<std::endl;
112
113             int max_iters = 20000;  //最大迭代次数
114            //获取训练网络的参数列表
115            std::vector<std::string>  args_name = pred.ListArguments();
116             for (int iter = 0; iter < max_iters ; ++iter) {
117                 executor->Forward(true);
118                 executor->Backward();
119
120                 if(iter % 100 == 0){
121                     std::vector<NDArray> & out = executor->outputs;
122                     std::shared_ptr<mx_float> tp_x( new mx_float[128*28] ,
123                                                     [](mx_float * tp_x){ delete [] tp_x ;});
124                     out[0].SyncCopyToCPU(tp_x.get(),128*10);
125                     NDArray::WaitAll();
126                     std::cout<<"epoch "<<iter<<"  "<<"Accuracy: "<<  OutputAccuracy(tp_x.get() , aptr_y.get())<<std::endl;
127                 }
128                 //args_name.
129                 for(size_t arg_ind=0; arg_ind<args_name.size(); ++arg_ind){
130                     //执行
131                     if(args_name[arg_ind]=="X" || args_name[arg_ind]=="label")
132                         continue;
133
134                     opt->Update(arg_ind,executor->arg_arrays[arg_ind],executor->grad_arrays[arg_ind]);
135                 }
136                 NDArray::WaitAll();
137
138             }
139
140
141         }
142     };
143 }
144
145 int main(int argc , char * argv[]){
146     mlp::MlpNet::net();
147     MXNotifyShutdown();
148     return EXIT_SUCCESS;
149 }

结果:

Training
epoch 0  Accuracy: 0.09375
epoch 100  Accuracy: 0.304688
epoch 200  Accuracy: 0.195312
epoch 300  Accuracy: 0.203125
epoch 400  Accuracy: 0.304688
epoch 500  Accuracy: 0.296875
epoch 600  Accuracy: 0.304688
epoch 700  Accuracy: 0.304688
epoch 800  Accuracy: 0.398438
epoch 900  Accuracy: 0.5
epoch 1000  Accuracy: 0.5
epoch 1100  Accuracy: 0.40625
epoch 1200  Accuracy: 0.5
epoch 1300  Accuracy: 0.398438
epoch 1400  Accuracy: 0.40625
epoch 1500  Accuracy: 0.703125
epoch 1600  Accuracy: 0.609375
epoch 1700  Accuracy: 0.507812
epoch 1800  Accuracy: 0.703125
epoch 1900  Accuracy: 0.703125
epoch 2000  Accuracy: 0.804688
epoch 2100  Accuracy: 0.703125
epoch 2200  Accuracy: 0.804688
epoch 2300  Accuracy: 0.804688
epoch 2400  Accuracy: 0.804688
epoch 2500  Accuracy: 0.90625
epoch 2600  Accuracy: 0.90625
epoch 2700  Accuracy: 0.90625
epoch 2800  Accuracy: 1
epoch 2900  Accuracy: 1
时间: 2024-10-05 04:56:18

调参过程中的参数 学习率,权重衰减,冲量(learning_rate , weight_decay , momentum)的相关文章

DeepLearning tutorial(2)机器学习算法在训练过程中保存参数

我是小白,说的不是很好,请原谅 @author:wepon @blog:http://blog.csdn.net/u012162613/article/details/43169019 参考:pickle - Python object serialization.DeepLearning Getting started 一.python读取"***.pkl.gz"文件 用到Python里的gzip以及cPickle模块,简单的使用代码如下,如果想详细了解可以参考上面给出的链接. [p

(转)理解YOLOv2训练过程中输出参数含义

最近有人问起在YOLOv2训练过程中输出在终端的不同的参数分别代表什么含义,如何去理解这些参数?本篇文章中我将尝试着去回答这个有趣的问题. 刚好现在我正在训练一个YOLOv2模型,拿这个真实的例子来讨论再合适不过了,下边是我训练中使用的 .cfg 文件(你可以在cfg文件夹下找到它): 以下是训练过程中终端输出的一个截图: 以上截图显示了所有训练图片的一个批次(batch),批次大小的划分根据我们在 .cfg 文件中设置的subdivisions参数.在我使用的 .cfg 文件中 batch =

实现能够在训练过程中手动更改学习率

在深度学习框架PyTorch一书的学习-第六章-实战指南和pytorch Debug —交互式调试工具Pdb (ipdb是增强版的pdb)-1-在pytorch中使用 和 pytorch实现性别检测三篇文章的基础上写的这篇文章 之前我们使用的是: exp_lr_scheduler = optim.lr_scheduler.StepLR(optimizer_conv, step_size=3, gamma=0.1) 去自动递减学习率,但是这种方法还是十分死板的,希望实现能够手动根据收敛地效果去更改

Python说文解字_继承过程中的参数集合

1. 先看一段属性继承的代码: class User: def __init__(self,name,age): self.name = name self.age = age class User1(User): def __init__(self,name,age,height,weight): self.height = height self.weight = weight # 此处像继承父类的name 和 age super().__init__(name, age) user1 =

Moses翻译过程中的参数,程序运行弹出的列表,记录在这了

Moses - A beam search decoder for phrase-based statistical machine translation models Copyright (C) 2006 University of Edinburgh This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public

调参必备---GridSearch网格搜索

什么是Grid Search 网格搜索? Grid Search:一种调参手段:穷举搜索:在所有候选的参数选择中,通过循环遍历,尝试每一种可能性,表现最好的参数就是最终的结果.其原理就像是在数组里找最大值.(为什么叫网格搜索?以有两个参数的模型为例,参数a有3种可能,参数b有4种可能,把所有可能性列出来,可以表示成一个3*4的表格,其中每个cell就是一个网格,循环过程就像是在每个网格里遍历.搜索,所以叫grid search) Simple Grid Search:简单的网格搜索 以2个参数的

机器学习系列(11)_Python中Gradient Boosting Machine(GBM)调参方法详解

原文地址:Complete Guide to Parameter Tuning in Gradient Boosting (GBM) in Python by Aarshay Jain 原文翻译与校对:@酒酒Angie && 寒小阳([email protected]) 时间:2016年9月. 出处:http://blog.csdn.net/han_xiaoyang/article/details/52663170 声明:版权所有,转载请联系作者并注明出 1.前言 如果一直以来你只把GBM

Python中Gradient Boosting Machine(GBM)调参方法详解

原文地址:Complete Guide to Parameter Tuning in Gradient Boosting (GBM) in Python by Aarshay Jain 原文翻译与校对:@酒酒Angie([email protected]) && 寒小阳([email protected]) 时间:2016年9月. 出处:http://blog.csdn.net/han_xiaoyang/article/details/52663170 1.前言 如果一直以来你只把GBM当

grid-search建模过程中自动调优

1.梯度下降法 先是将需要调整的参数以字典形式存储到param_grid列表中,梯度下降法可调整参数,可参考以下链接 https://scikit-learn.org/stable/modules/generated/sklearn.linear_model.SGDClassifier.html#sklearn.linear_model.SGDClassifier # 导入GridSearch包 from sklearn.model_selection import GridSearchCV s