在看了案例二中的BP神经网络训练及预测代码后,我开始不明白BP神经网络究竟能做啥了。。。 程序最后得到

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了在看了案例二中的BP神经网络训练及预测代码后,我开始不明白BP神经网络究竟能做啥了。。。 程序最后得到相关的知识,希望对你有一定的参考价值。

在看了BP神经网络训练及预测代码后,我开始不明白BP神经网络究竟能做什么了。。。

程序最后得到的结果好像就是预测输出值与实际输出值之间的误差吧,但是在应用中,实际输出值应该是没法作为已知条件出现的,只有给控制器给定一个输入,才能得到作为输出信号的实际输出值。也就是说在代码中的实际输出值应该是不可知的,这样就无法得到BP神经网络预测的误差了。

在以上分析的基础上,BP神经网络仅能得到一个控制器的预测输出值,而无法根据误差值的大小对其进行调整优化,BP神经网络的作用仅限于此吗?

我知道我上面的这些理解肯定在哪里出现了一点偏差,但是我无法找到问题出在哪里,往高手指教。。谢谢。。

网络的训练过程与使用过程了两码事。
比如BP应用在分类,网络的训练是指的给你一些样本,同时告诉你这些样本属于哪一类,然后代入网络训练,使得这个网络具备一定的分类能力,训练完成以后再拿一个未知类别的数据通过网络进行分类。这里的训练过程就是先伪随机生成权值,然后把样本输入进去算出每一层的输出,并最终算出来预测输出(输出层的输出),这是正向学习过程;最后通过某种训练算法(最基本的是感知器算法)使得代价(预测输出与实际输出的某范数)函数关于权重最小,这个就是反向传播过程。
您所说的那种不需要预先知道样本类别的网络属于无监督类型的网络,比如自组织竞争神经网络。追问

能具体举个应用的例子么?比如我想用在股票走势预测上,应该怎么处理?

追答

经济学的具体应用我不太了解,你说的这个例子叫做回归型神经网络。具体的应用例子很简单,比如你拿到一组特征x=[x1 x2 x3 x4 ...],然后有一组输出y,现在知道x和y满足某种函数关系y=f(x),假如知道这个函数是哪一类函数,那么通过数论(数值计算方法)就可以解决,这个就是典型的数学上的回归问题,但是假如你连f(x)长的什么样子都不知道,那么就可以使用神经网络。方法是采集到x和y的数据,比如x=x0的时候y=y0,x=x1的时候y=y1,依次类推,这个就是训练样本,通过训练样本训练网络,训练完成以后开始应用,这个应用解决的问题就是我们拿到一个未知的x,可以通过网络运算出来对应的y是多少。
你要用在股票走势上,首先就是要确定特征,y肯定是你要知道的股票走势,这组x是你要确定的哪些经济学上的数据,然后采集过去的股票数据(x,y),产生样本,对网络进行训练。训练完成以后,这个网络就可以解答:当前的x出现的时候,股票走势y是什么样的数据。
您下面提到的那个输出节点设置的问题,很简单,输出的数据就是你要预测的数据,比如上证指数。假如已知上证指数和某些经济学参数x有关,那么就采集过去的x和上证指数去训练网络,最后得到的网络目的就是当获取一组新的x而需要知道上证指数的时候,运算出来上证指数。

追问

意思我明白了,但是具体操作还是有点迷糊。。。比如程序编写,在MATLAB中有现成的神经网络函数,训练我是会的,但是 怎样用一组新的x去推未知的上证指数,这一步我就不知道怎么处理了

追答

训练完成以后把网络保存下来,然后使用命令a=sim(net,x),这里a是你的返回变量,它就等于你预测出来的数据,net是你训练好的网络名,x就是你那组新的x。

追问

x不是程序开头设定的输入值么?怎么又变成新的了?

追答

x是代表的输入,例如通过纽约股指推断上证的,这个x就是指代的纽约股指,你训练的时候用的是昨天的x,前天的x,大前天的x,依次类推,那么训练好以后拿来算的是今天的x,我在前面的说明当中不是给样本加了下标吗?“比如x=x0的时候y=y0,x=x1的时候y=y1,依次类推,这个就是训练样本”。我们算的时候用的就是x=今天的x这种情况。

追问

我写的程序,训练过程是有的,但预测过程还是不清楚。想请你改一下,这里发不了,我发到你空间了,你帮我看看吧,谢谢了。

追答

你做的这个必然不行。首先是数据量太小,甚至连小样本问题都算不上。其次是违背客观规律,昨天的股指和今天的股指怎么可能存在某一个确定性函数关系呢?今天的股指肯定和今天的经济学数据相关。就好比你用昨天的温度去预测今天的温度一样荒唐,因为今天的温度肯定是和今天的气象学参数有关,忽视客观规律是不可能成功的。
神经网络不适合你的模型,你的这种情况需要使用数学方法解决。通过数论来拟合马尔科夫链模型,把问题转化为求昨天与今天股指的概率密度函数或者状态转移矩阵。
或者是你通过经济学的有关成果研究一下特征提取,但是我的观点即使是这样,恐怕这个模型只能是用来做理论探讨,不太可能用到股指的预测。经济学的参数本来就不靠谱,有着非常大的误差和干扰信息,神经网络做预测也并不向数学回归那样能给出准确的误差估计,说白了你用非常不靠谱数据来进行不太靠谱的处理,想得到一个靠谱的数据那是不现实的。科学的力量固然强大,但是也要遵循客观情况,千万不要陷入神经网络万能的误区。

追问

那请问有没有什么可以改进的办法?比如我用今晚的道指,以及其他因素比如投资者的情绪等做为因变量来预测明天的开盘价,这样可行么?至于样本假如我收集到近两百个样本,这样是否可行。还望指点迷津!

追答

对不起,这一点我帮不到你。我只能就模型本身的特点帮你分析,你提到的问题是属于建模、特征提取、样本预处理、网络优化的内容,如果是到了这样一个层面的话必须一个专门的课题或者项目支持才能做。这种工作凭借个人的力量和经费是难以完成的,您如果铁了心要做的话我建议您先写一份项目要求,带着它到您当地的经济学科研机构,他们如果有兴趣会接下项目并申请国家社会科学基金或者教育部、科工委的基金,然后给您经费预算,如果成功这些基金会替您分担项目经费的40%左右,失败的话只能按照自筹经费的项目来做,这样需要您提供全额经费,项目完成后他们会按照项目要求给您需要的成果。

参考技术A BP网络的作用类似于人脑的类推学习过程,
分为训练过程:已知条件+已知结果===神经网络
和应用过程:待解答条件+神经网络===模拟结果

比如我们在认知过程中,
看到[黑猫]我们会联想到[猫]
看到[白猫]我们会联想到[猫]
看到[黄猫]我们会联想到[猫]

神经网络训练完毕

在应用中
我们看到一只[花猫]
能够识别是[猫]

这就是神经网络,输入的是已知的条件和结果
就像举例说明
对于未知的输入进行变量匹配
如果匹配不成功,就算误差,然后更新认知
直到匹配成功

对神经网络进行训练后,追问

还是有点不明白,感觉自己陷入一个误区。。。可不可以加你Q谈一下,其实我现在的主要问题是在输出节点的设定上。不知道该怎么处理!

追答

通过输入/输出样本对产生一个网络,用这个网络来对新的输入值进行处理,这个就是神经网络
样本中一个输入对应一个输出,需要输出几个属性就设计几个节点

参考技术B bp网络只有预测效果,比如利用往年的业绩来预测今年的 参考技术C 不知道啊不知道

用C实现单隐层神经网络的训练和预测(手写BP算法)

实验要求:
•实现10以内的非负双精度浮点数加法,例如输入4.99和5.70,能够预测输出为10.69
•使用Gprof测试代码热度

代码框架
•随机初始化1000对数值在0~10之间的浮点数,保存在二维数组a[1000][2]中。
•计算各对浮点数的相加结果,保存在数组b[1000]中,即b[0] = a[0][0] + a[0][1],以此类推。数组a、b即可作为网络的训练样本。
•定义浮点数组w、v分别存放隐层和输出层的权值数据,并随机初始化w、v中元素为-1~1之间的浮点数。
•将1000组输入(a[1000][2])逐个进行前馈计算,并根据计算的输出结果与b[1000]中对应标签值的差值进行反馈权值更新,调整w、v中各元素的数值。
•1000组输入迭代完成后,随机输入两个浮点数,测试结果。若预测误差较大,则增大训练的迭代次数(训练样本数)。 

 

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <math.h>
//归一化二维数组
void normalization(float num[1000][2]){
    float max1 = 0.0,max2 = 0.0;
    float min1 = 0.0,min2 = 0.0;
    for(int i = 0;i<1000;i++){
        if(num[i][0]>max1||num[i][0]<min1){
            if(num[i][0]>max1){
                max1 = num[i][0];
            }
            if(num[i][0]<min1){
                min1 = num[i][0];
            }
        }
        if(num[i][1]>max2||num[i][1]<min2){
            if(num[i][1]>max2){
                max2 = num[i][1];
            }
            if(num[i][1]<min2){
                min2 = num[i][1];
            }
        }
    }
    for(int i = 0;i<1000;i++){
        num[i][0] = (num[i][0]-min1+1)/(max1-min1+1);
        num[i][1] = (num[i][1]-min2+1)/(max2-min1+1);
    }
    printf("a[][0]的最大值和最小值分别为:%f\\t%f",max1,min1);
    printf("\\na[][1]的最大值和最小值分别为:%f\\t%f",max2,min2);
    printf("\\n");
}
//归一化一维数组
void normalization_b(float num[1000]){
    float max = 0.0,min = 0.0;
    for(int i = 0;i<1000;i++){
        if(num[i]>max||num[i]<min){
            if(num[i]>max){
                max = num[i];
            }else{
                min = num[i];
            }
        }
    }
    for(int i = 0;i<1000;i++){
        num[i] = (num[i]-min+1)/(max-min+1);
    }
    printf("b数组归一化的最大值和最小值为:%f,%f",max,min);
}
//后向隐藏层公式计算
float compute_hidden(float a,float b,float *w_a,float *w_b,float *bias_c){
    float value = 0.0;
    value = a*(*w_a)+b*(*w_b)+(*bias_c);
    value = 1/(1+exp(-value));
    return value;
}
//后向输出层公式计算
float compute_output(float c,float *w_c,float *bias_d){
    float value = 0.0;
    value = c*(*w_c)+(*bias_d);
    value = 1/(1+exp(-value));
    return value;
}
//前向输出层公式计算
float pro_output(float predict_num,float real_num){
    float error = 0.0;
    error = predict_num*(1-predict_num)*(real_num-predict_num);
    return error;
}
//bp算法
void bp(float a,float b,float real_num,float *w_a,float *w_b,float *v,float *bias_c,float *bias_d){
    //前向计算
    //隐藏层
    float output = compute_hidden(a,b,w_a,w_b,bias_c);
    //输出层
    float output_final = compute_output(output,v,bias_d);
    //反向计算
    float error_output = 0.0;
    //输出层
    error_output = pro_output(output_final,real_num);
    //更新权重和偏向!
    //定义学习率
    double learning_rate = 0.01;
    *v = *v + learning_rate*error_output*output;
    *bias_d = *bias_d + learning_rate*error_output;
    //前向隐藏层
    float error_hidden = 0.0;
    error_hidden = output*(1-output)*(error_output*(*v));
    //更新权重和偏向
    *w_a = *w_a + learning_rate*(error_hidden*a);
    *w_b = *w_b + learning_rate*(error_hidden*b);
    *bias_c = *bias_c + learning_rate*error_hidden;
}
int main(int argc, const char * argv[]) {
    //随机初始化1000对数值在0-10之间的双精度浮点数,保存在二维数组a[1000][2]中
    srand((unsigned) (time(NULL)));
    float a[1000][2],b[1000];
    for(int i = 0;i<1000;i++){
        for(int j = 0;j<2;j++){
            int rd = rand()%1001;
            a[i][j] = rd/100.0;
        }
    }
    for(int i = 0;i<1000;i++){
        b[i] = a[i][0] +a[i][1];
    }
    //归一化处理
    normalization(a);
    normalization_b(b);
    //定义浮点数组w,v分别存放隐层和输出层的权值数据,并随机初始化w,v为(-1,1)之间的浮点数
    int w_a_rand = rand()%200001;
    int w_b_rand = rand()%200001;
    float w_a = w_a_rand/100000.0-1;
    float w_b = w_b_rand/100000.0-1;
    int v_rand = rand()%200001;
    float v = v_rand/100000.0-1;
    int bias_c_rand = rand()%200001;
    float bias_c = bias_c_rand/100000.0-1;
    int bias_d_rand = rand()%200001;
    float bias_d = bias_d_rand/100000.0-1;
    printf("w_a,w_b,v初始随机值分别是:%f    %f    %f\\n",w_a,w_b,v);
    //将1000组输入(a[1000][2])逐个进行前馈计算,并根据计算的输出结果与b[1000]中对应标签值的差值进行反馈权值更新,调整w、v中各元素的数值。
    //对于每一个训练实例:执行bp算法
    float max1 ,max2 ,min1 ,min2,max,min;
    printf("x0的归一化参数(最大最小值):");
    scanf("%f,%f",&max1,&min1);
    printf("x1的归一化参数(最大最小值):");
    scanf("%f,%f",&max2,&min2);
    printf("b的归一化参数(最大最小值):");
    scanf("%f,%f",&max,&min);
    int mark = 0;
    float trainnig_data_a[800][2],trainnig_data_b[800],test_data_a[200][2],test_data_b[200];
    int i = 0;
    while (i<1000) {
        if(i == mark){
            //设置测试集
        for(int k = i;k<(i+200);k++){
                test_data_a[k][0] = a[k][0];
                test_data_a[k][1] = a[k][1];
                test_data_b[k] = b[k];
            }
            i +=200;
        }
        //设置训练集
        if(i<mark){
        trainnig_data_a[i][0] = a[i][0];
        trainnig_data_a[i][1] = a[i][1];
        trainnig_data_b[i] = b[i];
        i++;
        }
        if(i>mark){
            trainnig_data_a[i-200][0] = a[i][0];
            trainnig_data_a[i-200][1] = a[i][1];
            trainnig_data_b[i-200] = b[i];
            i++;
        }
    }
    for(int i = 0;i<800;i++){
        //迭代600次
        int times = 0;
        for(int i= 0;i<600;i++){
            bp(trainnig_data_a[i][0],trainnig_data_a[i][1],trainnig_data_b[i],&w_a,&w_b,&v,&bias_c,&bias_d);
            times++;
        }
    }
    //进行预测
    float pre_1,pre_2,predict_value,true_value;
    
    float MSE[200];
    for(int i = 0;i<200;i++){
        pre_1 = test_data_a[i][0];
        pre_2 = test_data_a[i][1];
        true_value = test_data_b[i];
        //进行计算
        float pre_hidden = compute_hidden(pre_1, pre_2, &w_a, &w_b, &bias_c);
        predict_value = compute_output(pre_hidden, &v, &bias_d);
        //求均方误差
        MSE[i] = (predict_value - true_value)*(predict_value-true_value);
        predict_value = (predict_value*(max-min+1))-1+min;
        true_value = (true_value*(max-min+1))-1+min;
        printf("预测值为:%f   真实值为:%f\\n",predict_value,true_value);
    }
    float mean_square_error = 0;
    for(int i = 0;i<200;i++){
        mean_square_error += MSE[i];
    }
    mean_square_error = mean_square_error/200;
    printf("均方误差为:%lf",mean_square_error);
}

运行结果截图:

 

 将隐藏层改为5个神经元

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <math.h>
struct tag{
    float value[5];
}x,y;
//归一化二维数组
void normalization(float num[1000][2]){
    float max1 = 0.0,max2 = 0.0;
    float min1 = 0.0,min2 = 0.0;
    for(int i = 0;i<1000;i++){
        if(num[i][0]>max1||num[i][0]<min1){
            if(num[i][0]>max1){
                max1 = num[i][0];
            }
            if(num[i][0]<min1){
                min1 = num[i][0];
            }
        }
        if(num[i][1]>max2||num[i][1]<min2){
            if(num[i][1]>max2){
                max2 = num[i][1];
            }
            if(num[i][1]<min2){
                min2 = num[i][1];
            }
        }
    }
    for(int i = 0;i<1000;i++){
        num[i][0] = (num[i][0]-min1+1)/(max1-min1+1);
        num[i][1] = (num[i][1]-min2+1)/(max2-min1+1);
    }
    printf("a[][0]的最大值和最小值分别为:%f\\t%f",max1,min1);
    printf("\\na[][1]的最大值和最小值分别为:%f\\t%f",max2,min2);
    printf("\\n");
}
//归一化一维数组
void normalization_b(float num[1000]){
    float max = 0.0,min = 0.0;
    for(int i = 0;i<1000;i++){
        if(num[i]>max||num[i]<min){
            if(num[i]>max){
                max = num[i];
            }else{
                min = num[i];
            }
        }
    }
    for(int i = 0;i<1000;i++){
        num[i] = (num[i]-min+1)/(max-min+1);
    }
    printf("b数组归一化的最大值和最小值为:%f,%f",max,min);
}
//后向隐藏层公式计算
struct tag compute_hidden(float a,float b,float *w_a,float *w_b,float *bias_c){
    for(int i=0;i<5;i++){
        x.value[i] = a*(w_a[i])+b*(w_b[i])+(bias_c[i]);
        x.value[i] = 1/(1+exp(-(x.value[i])));
    }
    return x;
}
//后向输出层公式计算
float compute_output(struct tag c,float *w_c,float *bias_d){
    float value_output = 0;
    for(int i = 0;i<5;i++){
        c.value[i] = c.value[i]*(w_c[i]);
        value_output+=c.value[i];
    }
    value_output = (value_output+(*bias_d))/5;
    value_output = 1/(1+exp(-(value_output)));
    return value_output;
}
//前向输出层公式计算
float pro_output(float predict_num,float real_num){
    float error = 0.0;
    error = predict_num*(1-predict_num)*(real_num-predict_num);
    return error;
}
//bp算法
void bp(float a,float b,float real_num,float *w_a,float *w_b,float *v,float *bias_c,float *bias_d){
    //前向计算
    //隐藏层
    struct tag output = compute_hidden(a,b,w_a,w_b,bias_c);
    //输出层
    float output_final = compute_output(output,v,bias_d);
    //反向计算
    float error_output = 0.0;
    //输出层
    error_output = pro_output(output_final,real_num);
    //更新权重和偏向!
    //定义学习率
    double learning_rate = 0.00003;
    for(int i = 0;i<5;i++){
        v[i] = v[i] + learning_rate*error_output*output.value[i];
    }
    *bias_d = *bias_d + learning_rate*error_output;
    //前向隐藏层
    float error_hidden[5];
    for(int i = 0;i<5;i++){
        error_hidden[i] = output.value[i]*(1-output.value[i])*(error_output*v[i]);
    }
    //更新权重和偏向
    for(int i = 0;i<5;i++){
        w_a[i] = w_a[i] + learning_rate*(error_hidden[i]*a);
        w_b[i] = w_b[i] + learning_rate*(error_hidden[i]*b);
        bias_c[i] = bias_c[i] + learning_rate*error_hidden[i];
    }
}
int main(int argc, const char * argv[]) {
    //随机初始化1000对数值在0-10之间的双精度浮点数,保存在二维数组a[1000][2]中
    srand((unsigned) (time(NULL)));
    float a[1000][2],b[1000];
    for(int i = 0;i<1000;i++){
        for(int j = 0;j<2;j++){
            int rd = rand()%1001;
            a[i][j] = rd/100.0;
        }
    }
    for(int i = 0;i<1000;i++){
        b[i] = a[i][0] +a[i][1];
    }
    //归一化处理
    normalization(a);
    normalization_b(b);
    //定义浮点数组w,v分别存放隐层和输出层的权值数据,并随机初始化w,v为(-1,1)之间的浮点数
    int w_a_rand[5];
    int w_b_rand[5];
    for(int i = 0;i<5;i++){
        w_a_rand[i] = rand()%200001;
    }
    for(int i = 0;i<5;i++){
        w_b_rand[i] = rand()%200001;
    }
    float w_a[5];
    for(int i = 0;i<5;i++){
        w_a[i] = w_a_rand[i]/100000.0-1;
    }
    float w_b[5];
    for(int i = 0;i<5;i++){
        w_b[i] = w_b_rand[i]/100000.0-1;
    }
    int v_rand[5];
    for(int i = 0;i<5;i++){
        v_rand[i] = rand()%200001;
    }
    float v[5];
    for(int i = 0;i<5;i++){
        v[i] = v_rand[i]/100000.0-1;
    }
    int bias_c_rand[5];
    for(int i = 0;i<5;i++){
        bias_c_rand[i] = rand()%200001;
    }
    float bias_c[5];
    for(int i = 0;i<5;i++){
        bias_c[i] = bias_c_rand[i]/100000.0-1;
    }
    int bias_d_rand = rand()%200001;
    float bias_d = bias_d_rand/100000.0-1;
    printf("w_a[1-5],w_b[1-5],v[1-5]初始随机值分别是:");
    for(int i = 0;i<5;i++){
        printf("w_a[%d]=%f,w_b[%d]=%f,v[%d]=%f\\n",i,w_a[i],i,w_b[i],i,v[i]);
    }
    //将1000组输入(a[1000][2])逐个进行前馈计算,并根据计算的输出结果与b[1000]中对应标签值的差值进行反馈权值更新,调整w、v中各元素的数值。
    //对于每一个训练实例:执行bp算法
    float max1 ,max2 ,min1 ,min2,max,min;
    printf("x0的归一化参数(最大最小值):");
    scanf("%f,%f",&max1,&min1);
    printf("x1的归一化参数(最大最小值):");
    scanf("%f,%f",&max2,&min2);
    printf("b的归一化参数(最大最小值):");
    scanf("%f,%f",&max,&min);
    int mark = 0;
    float trainnig_data_a[800][2],trainnig_data_b[800],test_data_a[200][2],test_data_b[200];
    int i = 0;
    while (i<1000) {
        if(i == mark){
            //设置测试集
            for(int k = i;k<(i+200);k++){
                test_data_a[k][0] = a[k][0];
                test_data_a[k][1] = a[k][1];
                test_data_b[k] = b[k];
            }
            i +=200;
        }
        //设置训练集
        if(i<mark){
            trainnig_data_a[i][0] = a[i][0];
            trainnig_data_a[i][1] = a[i][1];
            trainnig_data_b[i] = b[i];
            i++;
        }
        if(i>mark){
            trainnig_data_a[i-200][0] = a[i][0];
            trainnig_data_a[i-200][1] = a[i][1];
            trainnig_data_b[i-200] = b[i];
            i++;
        }
    }
    for(int i = 0;i<800;i++){
        //迭代600次
        int times = 0;
        for(int j= 0;j<300000;j++){
            bp(trainnig_data_a[i][0],trainnig_data_a[i][1],trainnig_data_b[i],w_a,w_b,v,bias_c,&bias_d);
            times++;
        }
    }
    //进行预测
    float pre_1,pre_2,predict_value,true_value;
    
    float MSE[200];
    for(int i = 0;i<200;i++){
        pre_1 = test_data_a[i][0];
        pre_2 = test_data_a[i][1];
        true_value = test_data_b[i];
        //进行计算
        struct tag pre_hidden = compute_hidden(pre_1, pre_2,w_a,w_b,bias_c);
        predict_value = compute_output(pre_hidden, v, &bias_d);
        //求均方误差
        MSE[i] = (predict_value - true_value)*(predict_value-true_value);
        predict_value = (predict_value*(max-min+1))-1+min;
        true_value = (true_value*(max-min+1))-1+min;
        printf("预测值为:%f   真实值为:%f\\n",predict_value,true_value);
    }
    float mean_square_error = 0;
    for(int i = 0;i<200;i++){
        mean_square_error += MSE[i];
    }
    mean_square_error = mean_square_error/200;
    printf("均方误差为:%lf",mean_square_error);
}

但结果没什么优化,估计要批量训练可以将结果更优

以上是关于在看了案例二中的BP神经网络训练及预测代码后,我开始不明白BP神经网络究竟能做啥了。。。 程序最后得到的主要内容,如果未能解决你的问题,请参考以下文章

用MATLAB做bp神经网络的预测,训练的挺好。但是预测误差很大,是啥原因,怎么解决啊

基于BP 神经网络算法的住院天数建模及预测

用C实现单隐层神经网络的训练和预测(手写BP算法)

Matlab基于BP神经网络实现多分类预测(源码可直接替换数据)

Matlab基于BP神经网络实现多分类预测(源码可直接替换数据)

python做BP神经网络,进行数据预测,训练的输入和输出值都存在负数,为啥预测值永远为正数?