zoukankan      html  css  js  c++  java
  • 神经网络与机器学习 笔记—LMS(最小均方算法)和学习率退火

    神经网络与机器学习 笔记—LMS(最小均方算法)和学习率退火

    LMS算法和Rosenblatt感知器算法非常想,唯独就是去掉了神经元的压制函数,Rosenblatt用的Sgn压制函数,LMS不需要压制函数,两者一样是只有单个神经元。

    LMS算法信号流图

     

    算法小结:


    然后在说下退火:

     

    #pragma once
    
    #include "stdafx.h"
    
    #include <string>
    
    #include <iostream>
    
    using namespace std;
    
    
    
    int gnM = 0;      //训练集空间维度
    
    int gnN = 0;      //突触权值个数
    
    
    
    double gdU0 = 0.1;  //初始学习率参数,用于退火,前期可以较大
    
    double gdT = 1;  //控制退火用的开始降温的时间点
    
    double gdN = 0;  //当前工作时间(神经网络学习次数)
    
    
    
    //退火
    
    //U=U0/(1+(N/T))
    
    double GetNowU() {
    
    gdN++;
    
    //cout<< gdU0 / (1.0 + (gdN / gdT))<<endl;
    
    return gdU0 / (1.0 + (gdN / gdT));
    
    }
    
    
    
    void LMSInit(double *dX, const int &nM, double *dW, const int &nN, const double &dB, const double &dU0 ,const double &dT) {
    
    //dX 本次训练数据集
    
    //nM 训练集空间维度
    
    //dW 权值矩阵
    
    //nN 突触权值个数 LMS只有一个神经元,所以nM==nM
    
    //dB 偏置,正常这个是应该 走退火动态调整的,以后再说,现在固定得了。
    
    //dU0 初始学习率参数,用于退火,前期可以较大
    
    //dT控制退火用的开始降温的时间点
    
    
    
    
    
    if (nM > 0) {
    
    dX[0] = 1;//把偏置永远当成一个固定的突触
    
    }
    
    for (int i = 0; i <= nN; i++) {
    
    if (i == 0) {
    
    dW[i] = dB;//固定偏置
    
    }
    
    else {
    
    dW[i] = 0.0;
    
    }
    
    }
    
    gnM = nM, gnN = nN, gdU0 = dU0, gdT = dT;
    
    }
    
    
    
    double Sgn(double dNumber) {
    
    return dNumber > 0 ? +1.0 : -1.0;
    
    }
    
    
    
    //感知器收敛算法-学习
    
    void LMSStudy(const double *dX, const double dD, double *dW) {
    
    //dX 本次训练数据集
    
    //dD 本次训练数据集的期望值
    
    //dW 动态参数,突触权值
    
    double dY = 0;
    
    for (int i = 0; i <= gnM && i <= gnN; i++) {
    
    dY = dY + dX[i] * dW[i];
    
    }
    
    //dY = Sgn(dY); LMS这个地方不用了,Rosenblatt是需要的
    
    if (dD == dY) {
    
    return;//不需要进行学习调整突触权值
    
    }
    
    for (int i = 1; i <= gnM && i <= gnN; i++) {
    
    dW[i] = dW[i] + GetNowU() * (dD - dY) * dX[i];
    
    }
    
    }
    
    
    
    //感知器收敛算法-泛化
    
    double LMSGeneralization(const double *dX, const double *dW) {
    
    //dX 本次需要泛化的数据集
    
    //dW 已经学习好的突触权值
    
    //返回的是当前需要泛化的数据集的泛化结果(属于那个域的)
    
    double dY = 0;
    
    for (int i = 0; i <= gnM && i <= gnN; i++) {
    
    dY = dY + dX[i] * dW[i];
    
    }
    
    return Sgn(dY);
    
    }
    
    
    
    //双月分类模型,随机获取一组值
    
    /*  自己稍微改了下
    
    域1:上半个圆,假设圆心位坐标原点(0,0)
    
    (x - 0) * (x - 0) + (y - 0) * (y - 0) = 10 * 10
    
    x >= -10 && x <= 10
    
    y >= 0 && y <= 10
    
    域2:下半个圆,圆心坐标(10 ,-1)
    
    (x - 10) * (x - 10) + (y + 1) * (y + 1) = 10 * 10;
    
    x >= 0 && x <= 20
    
    y >= -11 && y <= -1
    
    */
    
    
    
    const double gRegionA = 1.0; //双月上
    
    const double gRegionB = -1.0;//双月下
    
    
    
    void Bimonthly(double *dX, double *dY, double *dResult) {
    
    //dX      坐标x
    
    //dY      坐标y
    
    //dResult 属于哪个分类
    
    *dResult = rand() % 2 == 0 ? gRegionA : gRegionB;
    
    if (*dResult == gRegionA) {
    
    *dX = rand() % 20 - 10;//在区间内随机一个X
    
    *dY = sqrt(10 * 10 - (*dX) * (*dX));//求出Y
    
    }
    
    else {
    
    *dX = rand() % 20;
    
    *dY = sqrt(10 * 10 - (*dX - 10) * (*dX - 10)) - 1;
    
    *dY = *dY * -1;
    
    }
    
    }
    
    
    
    int main()
    
    {
    
    //system("color 0b");
    
    double dX[2 + 1], dD, dW[2 + 1]; //输入空间维度为3 平面坐标系+一个偏置
    
    double dB = 0;
    
    double dU0 = 0.1;
    
    double dT = 128; //128之后开始降温
    
    
    
    LMSInit(dX, 2, dW, 2, dB, dU0, dT);//初始化 感知器
    
    
    
    double dBimonthlyX, dBimonthlyY, dBimonthlyResult;
    
    int nLearningTimes =  1024 * 10;//进行10K次学习
    
    
    
    for (int nLearning = 0; nLearning <= nLearningTimes; nLearning++) {
    
    Bimonthly(&dBimonthlyX, &dBimonthlyY, &dBimonthlyResult);//随机生成双月数据
    
    dX[1] = dBimonthlyX;
    
    dX[2] = dBimonthlyY;
    
    dD = dBimonthlyResult;
    
    LMSStudy(dX, dD, dW);
    
    //cout <<"Study:" << nLearning << " :X= " << dBimonthlyX << "Y= " << dBimonthlyY << " D=" << dBimonthlyResult<< "----W1= " << dW[1] << "  W2= " << dW[2] << endl;
    
    }
    
    
    
    //进行LMS泛化能力测试 测试数据量1K
    
    int nGeneralizationTimes = 1 * 1024;
    
    int nGeneralizationYes = 0, nGeneralizationNo = 0;
    
    double dBlattGeneralizationSuccessRate = 0;
    
    for (int nLearning = 1; nLearning <= nGeneralizationTimes; nLearning++) {
    
    Bimonthly(&dBimonthlyX, &dBimonthlyY, &dBimonthlyResult);//随机生成双月数据
    
    dX[1] = dBimonthlyX;
    
    dX[2] = dBimonthlyY;
    
    //cout << "Generalization: " << dBimonthlyX << "," << dBimonthlyY;
    
    if (dBimonthlyResult == LMSGeneralization(dX, dW)) {
    
    nGeneralizationYes++;
    
    //cout << " Yes" << endl;
    
    }
    
    else {
    
    nGeneralizationNo++;
    
    //cout << " No" << endl;
    
    }
    
    }
    
    dBlattGeneralizationSuccessRate = nGeneralizationYes * 1.0 / (nGeneralizationNo + nGeneralizationYes) * 100;
    
    cout << "Study : " << nLearningTimes << "     Generalization : " << nGeneralizationTimes << "     SuccessRate:" << dBlattGeneralizationSuccessRate << "%" << endl;
    
    getchar();
    
    return 0;
    
    }
    
    

    执行结果:

        Study : 10240     Generalization : 1024     SuccessRate:96.6797%

    注意:

            相对于Rosenblatt算法,LMS如果直接把sgn去掉了可能出现泛化能力急剧下降的问题,我就是,直接变成50%了(和没学习一样),因为此时的学习率参数恒等于0.1有点大(为什么说0.1大,因为没有sgn了,算出的XW是比较大的,而这个时候我们训练数据集的期望结果,还是+1和-1)。同时,退火的那个地方,去动态调整那几个参数,会得到你意想不到的效果,挺微妙的。

  • 相关阅读:
    amaze(妹子~) 好像挺好玩
    php 获取图片base64编码格式数据
    一些laravel博文
    微信移动端(wap)开发调试工具
    深入理解控制反转(IoC)和依赖注入(DI)
    使用 composer 下载更新卸载类库
    ionic ui 框架
    laravel 添加 404 页面
    laravel 调试模式及日志配置
    iOS-方法之+ initialize 与 +load
  • 原文地址:https://www.cnblogs.com/csnd/p/12061930.html
Copyright © 2011-2022 走看看