梯度下降的简单应用

        //应用
        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;

 

你可能感兴趣的:(梯度下降的简单应用)