用逻辑回归BP神经网络做二分预测的例子

该代码示例展示了如何利用逻辑回归和BP神经网络对平面上的曲线进行二分预测,判断其是否位于单位圆的上半侧。通过调整特征向量的维数和训练样本的数量,可以在较少的样本下实现高精度预测。程序中定义了生成测试和训练数据的函数,并进行了训练和测试过程,最后计算并输出了错误率。
摘要由CSDN通过智能技术生成

用逻辑回归BP神经网络做二分预测的例子
平面上指定区域的一些点组成一条曲线,预测该曲线是否位于固定圆内的某半侧.
曲线的采样点:X轴范围[-1,1],Y轴范围[-1,1],由这些采样点组成曲线的特征向量(即输入节点)
单位圆中分线:y=-x,第一象限方向为上半侧圆
训练集中,如果曲线处于圆上半侧,期望值是1,否则为0

结论:特征向量维数比训练样本数量更加重要,增加输入节点可以很少的训练样本数达到很高精度

/代码如下/
#include <cstdio>
#include <windows.h>
#include<math.h>
#include<assert.h>
#include "LMNISTParser.h"
#include "LRegression.h"


//用逻辑回归BP神经网络做二分预测的例子
//平面上指定区域的一些点组成一条曲线,预测该曲线是否位于固定圆内的某半侧.
//曲线的采样点:X轴范围[-1,1],Y轴范围[-1,1],由这些采样点组成曲线的特征向量(即输入节点)
//单位圆中分线:y=-x,第一象限方向为上半侧圆
//训练集中,如果曲线处于圆上半侧,期望值是1,否则为0

//最大随机数,用于生成足够精度的特征值
const int MAX_resolution = 2000000000;

//检测(x,y)点是否在上侧半圆内
//单位圆被y=-x斜线划分成上下两个半圆
int InCell(const float x, const float y);

//生成测试数据的函数
//单位圆被y=-x斜线划分成上下两个半圆
//根据给定x轴位置index,生成y轴随机值,可指定检测是否在上半侧半圆内
int GetXi(float& y, const int index, const bool check_r);

 
int main()
{     
    unsigned int LOGISTIC_X_DIM = 150;//特征向量维数(输入节点数)
    const unsigned int LOGISTIC_TRAIN_SAMPLES = 50; //训练集样本数
    const unsigned int LOGISTIC_TEST_SAMPLES = 10000;//测试集样本数

    const unsigned int trainTimes = 1; // 训练次数
    float learnRate = 0.1f; // 学习速度,学习率

    int RANGE_X = int((float)MAX_resolution * 0.7 / 2);//便于生成所需样本数据的设定范围
    int step_x = (int)round(((RANGE_X * 2) / LOGISTIC_X_DIM) * 0.90);//生成特征值的步长

    printf("用逻辑回归BP神经网络做二分预测的例子\n\n特征向量维数:%d\n", LOGISTIC_X_DIM);
    printf("训练集样本数量:%d\n学习速率:%0.2f\n", LOGISTIC_TRAIN_SAMPLES, learnRate);

    LRegressionMatrix xMatrix(LOGISTIC_TRAIN_SAMPLES, LOGISTIC_X_DIM, 0.0f);//训练集数据矩阵
    LRegressionMatrix yVector(LOGISTIC_TRAIN_SAMPLES, 1, 0.0f);//训练集标签向量
    LLogisticRegression logisticReg(LOGISTIC_TRAIN_SAMPLES, LOGISTIC_X_DIM);//softmax二分类

    srand(GetTickCount());

    int max_no = int(round(LOGISTIC_TRAIN_SAMPLES * 0.10) + 1);//训练集中曲线不在上半圆侧的样本数量
    int YES = 0;//曲线位于上侧半圆内的训练样本数量
    int NO = 0;

    //生成训练集数据
    for (int row = 0;row < LOGISTIC_TRAIN_SAMPLES;row++)
    {
        int R=1;//R==0生成一条不在上半侧圆内的曲线,R==1生成的曲线在上半侧圆内

        if (NO < max_no)
        {
            R = rand() % 2;
            if (0 == R) NO++;
        }

        if (1 == R) YES++;

        float y;
        int ret = 0;
        int index = -RANGE_X;//从左到右生成曲线特征值

        for (unsigned int c = 0;c < LOGISTIC_X_DIM;c++)
        {
            index = index + step_x;
            do {
                ret = GetXi(y, index, R == 1);
            } while (ret != R);
            xMatrix[row][c] = y;
        }
        if (1 == ret)
        {
            yVector[row][0] = 1;
        }
        else
        {
            yVector[row][0] = 0;
        }
    }

    printf("训练集中位于上侧圆内样本比例:%0.1f%%=%d/%d\n", 100.0 * (float)YES / (float)LOGISTIC_TRAIN_SAMPLES, YES, LOGISTIC_TRAIN_SAMPLES);

    for (unsigned int t = 1;t <= trainTimes;t++)
    {
        logisticReg.TrainModel(xMatrix, yVector, learnRate);
        printf("循环训练:%d/%d\r", t, trainTimes);
    }


    printf("\n开始测试...\n测试集样本数量:%d\n", LOGISTIC_TEST_SAMPLES);

    LRegressionMatrix x_t_Matrix(LOGISTIC_TEST_SAMPLES, LOGISTIC_X_DIM, 0.0f);//测试集数据矩阵
    LRegressionMatrix y_t_Vector(LOGISTIC_TEST_SAMPLES, 1, 0.0f);//测试集标签向量
    LRegressionMatrix y_out_Vector(LOGISTIC_TEST_SAMPLES, 1, 0.0f);//测试集输出向量

    srand(GetTickCount());

    int t_YES = 0;
    //生成测试集数据
    for (int row = 0;row < LOGISTIC_TEST_SAMPLES;row++)
    {
        int R = rand() % 2;//R==0生成一条不在上半侧圆内的曲线,R==1生成的曲线在上半侧圆内
        float y;
        int ret = 0;
        int index = -RANGE_X;//从左到右生成曲线特征值

        for (unsigned int c = 0;c < LOGISTIC_X_DIM;c++)
        {
            index = index + step_x;
            do {
                ret = GetXi(y, index, R == 1);
            } while (ret != R);
            x_t_Matrix[row][c] = y;
        }

        if (1 == R)
        {
            y_t_Vector[row][0] = 1.0f;
            t_YES++;
        }
        else
        {
            y_t_Vector[row][0] = 0.0f;
        }
    }

    logisticReg.Predict(x_t_Matrix, y_out_Vector);

    int er = 0;

    for (int row = 0;row < LOGISTIC_TEST_SAMPLES;row++)
    {
        float y_t = y_t_Vector[row][0];
        float ret_y = y_out_Vector[row][0];
        if (y_t > ret_y || y_t < ret_y)
        {
            er++;
        }
    }

    float error_rate = float(er) / (LOGISTIC_TEST_SAMPLES);

    printf("测试集中位于上侧圆内样本数:%d\n识别出错:%d\t出错率:%.2f%%\n", t_YES, er, error_rate * 100);

    system("pause");

    return 0;

   
}


//检测(x,y)点是否在上侧半圆内
//单位圆被y=-x斜线划分成上下两个半圆
int InCell(const float x, const float y)
{
    const float R = 1.0f;
    int ret = 0;
    if (x > R || x<-R || y>R || y < -R)
    {
        return ret;
    }
    if (x < 0 && y < -x)
    {
        return ret;
    }
    if (x > 0 && -y > x)
    {
        return ret;
    }

    float yLimit = (float)sqrt(R * R - x * x);
    if (x < 0 && y>0)
    {
        if (yLimit > y)
        {
            ret = 1;
        }
    }
    if (x > 0 && y <= 0)
    {
        if (-yLimit < y)
        {
            ret = 1;
        }
    }
    if (x >= 0 && y >= 0)
    {
        float Rxy = x * x + y * y;
        if (Rxy < R)
        {
            ret = 1;
        }
    }

    return ret;
}

//生成测试数据的函数
//单位圆被y=-x斜线划分成上下两个半圆
//根据给定x轴位置index,生成y轴随机值,可指定检测是否在上半侧半圆内
int GetXi(float& y, const int index, const bool check_r)
{
    float max_y = 1.5f;//如果无须检测生成的点是否在上半侧圆内,生成的值可以超出单位圆半径
    float min_y = -max_y;

    float x = (1.0f / ((float)MAX_resolution / 2)) * index;
    float r = 0;//原点为圆心,新生成的点(x,y)的圆半径

    if (check_r)
    {
        min_y = -x;
        float z = x;
        max_y = (float)(sqrt(1 - z * z));
    }
    float step_y = (max_y - min_y) / (float)MAX_resolution;

    do {
        int ry = rand();
        ry = ry << 15;
        ry = ry + rand();
        ry = ry % MAX_resolution;
        y = step_y * ry + min_y;
    } while (y<min_y || y>max_y);

    r = (float)(x * x + y * y);

    int ret = 0;

    if (x >= 0 && y >= 0)
    {
        ret = 1;
    }
    if (x >= 0 && y <= 0)
    {
        if (x > -y)
        {
            ret = 1;
        }
    }
    if (x <= 0 && y >= 0)
    {
        if (-x < y)
        {
            ret = 1;
        }
    }

    if (r > 1)
    {
        ret = 0;
    }

#ifdef _DEBUG
    if (ret)
    {
        int cell = InCell(x, y);
        assert(ret == cell);
    }
#endif // _DEBUG


    return ret;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值