zoukankan      html  css  js  c++  java
  • 梯度下降的简单应用

            //应用
            static void GradientDescent2()
            {
                //现有一组线性相关的数据,要求通过训练得到一个最接近它们线性关系的函数
                //现假设它们的线性关系函数为 y = w * x + b,则有 cost(w,b) = |(w*x+b)-y| 的最小值接近0时越准确,这里x,y为给出的已知数,w,b为所求变量
                //即求cost(w,b)  = (w * x + b-y)^2的最小值
                //求出cost(w,b) w b偏导,即梯度grad(cost(w,b)) =(2*(wx+b-y)*x , 2*(wx+b-y)*1)
    
                //假设我们拿到的真实的数据dataXY, 这里用模拟数据代替
                double[][] dataXY = new double[300][];
                var r = new Random();
                Enumerable.Range(0, dataXY.Length-1).ToList().ForEach(m =>
                {
                    var x = r.NextDouble()*100;
                    var couple = new double[2];
                    couple[0] = x;
                    couple[1] = x * 3 + 3;
                    dataXY[m] = couple;
                });
    
                //y = weight * x + bias
                double weight = 0, bias = 0;
                double rate = 0.1;
                int repeatTrain = 30;//重复训练次数
                int trainTimes = 0; //实际训练次数
                //训练一对数据
                Action<double,double> trainOneData = (x,y) =>
                {
                    //模仿上面的写法运行后发现结果错误,是因为xy为随机数值,梯度数值跨度太大,
                    //不符合让weight和bias运行一次后略微左移右移的处理逻辑
                    //var w = weight - rate *  2 *(weight*x + bias - y)*x;
                    //var b = bias - rate *  2*(weight*x + bias - y)*1;
                    //weight = w;
                    //bias = b;
    
                    //这里我们需要对真实的梯度进行单位处理,不让它们摇摆的过于夸张,还要保证梯度的方向维持正确
                    var realgradw = 2 * (weight * x + bias - y) * x;
                    var realgradb = 2 * (weight * x + bias - y) * 1;
                    var unit = Math.Max(Math.Abs(realgradw), Math.Abs(realgradb));
                    unit = Math.Abs(unit) < double.Epsilon?1 : unit;
                    var unitw = realgradw/unit;
                    var unitb = realgradb / unit;
                    //同时除以2个梯度中绝对值的最大的值,这样梯度的大小合适了,比例未变
                    var w = weight - rate * unitw;
                    var b = bias - rate * unitb;
                    weight = w;
                    bias = b;
                    //1、当rate=0.001经过运行后发现 w =3.007 b=0.12, w下降的速度很快,b的下降速度太慢未达到最优解
                    //因为 realgradw 中存在一个x^2因子,所以w下降的速度更快,需要想办法加快b的下降速度
                    //2、首先我们尝试加大步长rate=0.1,(w=3.004 b=2.932)(w=3.1,b=2.64)(w=3.1,b=1.64)数据不太稳定和精确
                    //3、尝试加大训练次数此时的结果较精确,但训练的时间过长效率太低
                    //4、尝试训练开始的时候选一个较大的步长,并且在训练的过程中逐步减小步长的值
                    trainTimes++;
                    if (trainTimes < 1000&& trainTimes > 0) rate = 0.5;
                    if (trainTimes < 2000 && trainTimes > 1000) rate = 0.5;
                    if (trainTimes < 3000 && trainTimes > 2000) rate = 0.3;
                    if (trainTimes < 5000 && trainTimes > 3000) rate = 0.1;
                    if (trainTimes < 7000 && trainTimes > 5000) rate = 0.05;
                    if ( trainTimes > 7000) rate = 0.001;
                    //w=3.0001,b=2.9989基本准确,但是当训练的数据较大时(var x = r.NextDouble()*1000;)结果还是不太理想
                    //还有优化的空间
                };
                //把所有的数据训练一次
                Action<double[][]> trainAllData = data =>
                {
                    for (int i = 0; i < data.Length-1; i++)
                    {
                        trainOneData(data[i][0], data[i][1]);
                        Console.WriteLine($"过程 weight={weight}; bias={bias}");
                    }
                };
                //把所有数据重复训练30次
                for (int i = 0; i < repeatTrain; i++)
                {
                    trainAllData(dataXY);
                }
                Console.WriteLine($"结果 weight={weight}; bias={bias};\r\n 通过学习得到的方程为 y = {weight}*x+{bias}");
                Console.ReadKey();
            }
                    //5、这里我们引入sigmoid函数g(x)=1/(1+exp(-x)),将其求导后函数化简g'(x) =g(x)*( 1-g(x) )
                    //上面我们已经cost函数2个方向的偏导函数,这里我们只需要将原函数的值其带入g'(x)后乘以其偏导即可
                    //这里我们令rate = 5,之后不用调节rate的值,通过sigmoid函数后函数值会自动收敛
                    rate = 5;
                    var y1 = weight*x + bias;
                    var dgx = 1/(1 + Math.Exp(-y1))*(1 - 1/(1 + Math.Exp(-y1)));
                    unitw = unitw * dgx;
                    unitb = unitb * dgx;
                    var w = weight - rate * unitw;
                    var b = bias - rate * unitb;
                    weight = w;
                    bias = b;
  • 相关阅读:
    Explain详解
    InnoDB缓存---InnoDB Buffer Pool
    多线程之---线程同步
    多线程之--等待与通知
    谈算法与数据结构的学习
    分布式系统理论
    算法与数据结构基础
    算法与数据结构基础
    算法与数据结构基础
    算法与数据结构基础
  • 原文地址:https://www.cnblogs.com/gaobw/p/6747869.html
Copyright © 2011-2022 走看看