具有Sigmoid神经​​元的OpenCV MLP,输出范围

时间:2014-09-09 15:25:04

标签: opencv neural-network

我在SO上搜索了答案并谷歌搜索了以下问题,但是没有找到任何答案,所以这是我的情况:

我想要实现一个学习一些相似性功能的MLP。我有训练和测试样本,MLP设置和运行。我的问题是如何向网络提供教师输出(从哪个值范围)。

以下是我的代码的相关部分:

CvANN_MLP_TrainParams params(
    cvTermCriteria(CV_TERMCRIT_ITER+CV_TERMCRIT_EPS, 1000, 0.000001),
    CvANN_MLP_TrainParams::BACKPROP,
    0.1,
    0.1);

Mat layers = (Mat_<int>(3,1) << FEAT_SIZE, H_NEURONS, 1);

CvANN_MLP net(layers, CvANN_MLP::SIGMOID_SYM, 1, 1);

int iter = net.train(X, Y, Mat(), Mat(), params);

net.predict(X_test, predictions);

输入和隐藏神经元的数量设置在其他地方,网络有1个输出神经元。 X,Y,X_test是包含训练和测试样本的Mats,这里没问题。问题在于,我的Y必须来自什么价值范围,以及预测将来自什么价值范围。

documentation我发现了以下陈述:

培训:

  

如果您使用默认的cvANN_MLP :: SIGMOID_SYM激活函数,那么输出应该在[-1,1]范围内,而不是[0,1],以获得最佳结果。

由于我没有使用默认的sigmoid函数(alpha = 0和beta = 0的函数),我从[0,1]中提供了我的Y'。这是正确的,还是用默认的sigmoid函数表示其他东西&#39;?我问这个,因为预测他们明确提到alpha和beta:

  

如果您使用默认的cvANN_MLP :: SIGMOID_SYM激活函数,默认参数值为fparam1 = 0和fparam2 = 0,则使用的函数为y = 1.7159 * tanh(2/3 * x),因此输出范围为从[-1.7159,1.7159],而不是[0,1]。

同样,由于我没有使用默认的sigmoid函数,我假设从[0,1]得到预测。我到目前为止对吗?

令我困惑的是,我发现another question关于OpenCV的sigmoid函数的输出范围,该范围必须是[-1,1]。

现在出现了真正的混乱:当我训练网并让它做出一些预测时,我得到的值略大于1(大约1.03),无论我的Y是来自[0,1]还是[-1,1]。在任何一种情况下都不会发生这种情况。

有人可以赐教吗?我在这里错过了什么吗?

提前致谢。

修改

为了使事情变得非常清楚,我想出了一个显示问题的小例子:

#include <iostream>
#include <opencv2/core/core.hpp>
#include <opencv2/ml/ml.hpp>

using namespace cv;
using namespace std;

int main() {

    int POS = 1;
    int NEG = -1;

    int SAMPLES = 100;
    float SPLIT = 0.8;

    float C_X = 0.5;
    float C_Y = 0.5;
    float R = 0.3;

    Mat X(SAMPLES, 2, CV_32FC1);
    Mat Y(SAMPLES, 1, CV_32FC1);

    randu(X, 0, 1);

    for(int i = 0; i < SAMPLES; i++){
        Y.at<float>(i,0) = pow((X.at<float>(i,0) - C_X),2) + pow((X.at<float>(i,1) - C_Y),2) < pow(R,2) ? POS : NEG;
    }

    Mat X_train = X(Range(0, (int)(SAMPLES*SPLIT)), Range::all());
    Mat Y_train = Y(Range(0, (int)(SAMPLES*SPLIT)), Range::all());

    Mat X_test = X(Range((int)(SAMPLES*SPLIT), SAMPLES), Range::all());
    Mat Y_test = Y(Range((int)(SAMPLES*SPLIT), SAMPLES), Range::all());

    CvANN_MLP_TrainParams params(
                 cvTermCriteria(CV_TERMCRIT_ITER+CV_TERMCRIT_EPS, 1000, 0.000001),
                 CvANN_MLP_TrainParams::BACKPROP,
                 0.1,
                 0.1);

    Mat layers = (Mat_<int>(3,1) << 2, 4, 1);

    CvANN_MLP net(layers, CvANN_MLP::SIGMOID_SYM, 1, 1);
    net.train(X_train, Y_train, Mat(), Mat(), params);

    Mat predictions(Y_test.size(), CV_32F); 
    net.predict(X_test, predictions);

    cout << predictions << endl;

    Mat error = predictions-Y_test;
    multiply(error, error, error);

    float mse = sum(error)[0]/error.rows;

    cout << "MSE: " << mse << endl;

    return 0;
}

此代码从单位正方形生成一组随机点,并将标签POS或NEG分配给它们,这取决于它们是否在C_X,C_Y和R给出的圆内。然后生成测试和训练集并且MLP受过训练。现在我们有两种情况:

  1. POS = 1,NEG = -1:
  2. 输出提供给网络,因为它应该是tanh神经元(来自[-1,1]),我期望从该范围预测。但我也得到-1.018或1.052的预测。在这种情况下,均方误差为0.13071。

    1. POS = 1,NEG = 0:
    2. 输出被认为是最佳的(至少我理解文档的方式)。由于我没有使用默认的sigmoid函数,我期待[0,1]的预测。但我也得到像1.0263158甚至是负面的价值观。在这种情况下,MSE在0.0326775时变得更好。

      我知道,这个例子是一个分类问题,通常我只是将值舍入到最接近的标签,但我想学习一个相似度函数,并且必须依赖于预测来自某个固定范围。

2 个答案:

答案 0 :(得分:1)

我的回答很晚,所以我用同样的问题写给其他人。

如果在ann_mlp.cpp中看到setActivationFunction()和calc_activ_func(),则当您将fparam1,fparam2设置为0,0时,sigmoid将返回[-1.7159,1.7159]输出中的值。您可以更改斜率和范围通过调整fparam1,fparam2。

这些函数称为对称sigmoid,但它实际上计算 tanh 。如果你想要真正的sigmoid函数,我认为你需要实现它。

答案 1 :(得分:0)

这实际上归结为正在应用于MLP的激活功能。

可以应用许多不同的激活函数,将人工神经元的值压缩到一个定义的范围(我最常见的是双曲正切和逻辑函数,但存在许多其他函数)。也许你用于神经元的那个被缩放到超出0到1的范围。

至于上面用于生成最佳结果的注释,它鼓励数据在函数的整个输出范围内进行格式化,以便MLP可以在整个范围内学习而不是它的一部分,这可能会减少它的学习能力。