Ask Your Question
2

Neural Network in OpenCV 3.1.0

asked 2016-05-13 03:17:15 -0600

RubixCube gravatar image

updated 2016-05-13 04:51:28 -0600

Hello everyone!

I am currently trying to get OpenCV's neural network module running, unluckily so far with less success. Initialization and training works fine (at least as far as I can verify it) but as soon as I try to do a prediction, I'm receiving segmentation fault errors... I tried training / predicting on both Windows 8 as well as Ubuntu 16.04 on a custom Linux build as well as on a third-party Windows build respectively, as soon as I try a prediction, the same error occurs.

I also prepared some usable example code. Of course I know that training on randomly generated data makes not too much sense in practice, I only wanted to keep things simple for a minimum running example:

#include <opencv2/ml/ml.hpp>

using namespace cv;
using namespace cv::ml;

int main(int argc, char *argv[])
{
    //create random training data
    Mat_<float> data(100, 100);
    randn(data, Mat::zeros(1, 1, data.type()), Mat::ones(1, 1, data.type()));

    //half of the samples for each class
    Mat_<float> responses(data.rows, 1);
    for (int i=0; i<responses.rows; ++i)
        responses(i, 0) = i < responses.rows / 2 ? 0 : 1;

    //create the neural network
    Mat_<int> layerSizes(1, 3);
    layerSizes(0, 0) = data.cols;
    layerSizes(0, 1) = 20;
    layerSizes(0, 2) = 1;

    Ptr<ANN_MLP> networkPtr = ANN_MLP::create();
    ANN_MLP* network = networkPtr.get();
    network->setLayerSizes(layerSizes);
    network->setActivationFunction(0, 0.1, 0.1);
    network->setTrainMethod(0, 0.1, 0.1);

    /*
    //test to change variable type flags -> problem stays the same
    Mat_<int> varType = Mat(1, data.cols+1, CV_8U);
    for (int i = 0; i<data.cols; ++i)
        varType(0, i) = VAR_ORDERED;
    varType(0, varType.cols-1) = VAR_CATEGORICAL;
    //varType(0, varType.cols-1) = VAR_ORDERED;
    Ptr<TrainData> trainData = TrainData::create(data, ROW_SAMPLE, responses, noArray(), noArray(), noArray(), varType);
    */

    Ptr<TrainData> trainData = TrainData::create(data, ROW_SAMPLE, responses);
    network->train(trainData);

    if (network->isTrained())
    {
        printf("Predict:\n");
        network->predict(Mat::ones(1, data.cols, data.type())); //SEGMENTATION FAULT
        printf("Prediction done!\n");
    }

    return 0;
}

Does anyone got the Neural Network running in OpenCV 3.1.0? For me either I'm doing something wrong (in case, please let me know) or this is a bug in OpenCV... I would appreciate any comments :-)

edit - updated source code:

#include <opencv2/ml/ml.hpp>

using namespace cv;
using namespace cv::ml;

int main(int argc, char *argv[])
{
    //create random training data
    Mat_<float> data(100, 100);
    randn(data, Mat::zeros(1, 1, data.type()), Mat::ones(1, 1, data.type()));

    //half of the samples for each class
    Mat_<float> responses(data.rows, 2);
    for (int i = 0; i<data.rows; ++i)
    {
        if (i < data.rows/2)
        {
            data(i, 0) = 1;
            data(i, 1) = 0;
        }
        else
        {
            data(i, 0) = 0;
            data(i, 1) = 1;
        }
    }

    //Mat_<float> responses(data.rows, 1);
    //for (int i=0; i<responses.rows; ++i)
    //    responses(i, 0) = i < responses.rows / 2 ? 0 : 1;

    //create the neural network
    Mat_<int> layerSizes(1, 3);
    layerSizes(0, 0) = data.cols;
    layerSizes(0, 1) = 20;
    layerSizes(0 ...
(more)
edit retag flag offensive close merge delete

Comments

1

it neither segfaults on my win box, nor on ubuntu14 , but:

ANN_MLP* network = networkPtr.get(); -- please don't extract the raw pointer, use cv::Ptr consistently:

Ptr<ANN_MLP> network = ANN_MLP::create();
network->setLayerSizes(layerSizes);

then, for a real classification task, you responses should be a 2d Mat. for 2 classes, it should have 2 cols, and each row should look like e.g. (1, 0) for label "0" and (0,1) for label"1" (also, last layer should have 2 neurons then)

berak gravatar imageberak ( 2016-05-13 03:41:56 -0600 )edit

Thanks for your comment! I changed the code according to your suggestions (cf. edit of my post), training still works fine but at prediction it keeps seg-faulting. Am I doing something else wrong?

RubixCube gravatar imageRubixCube ( 2016-05-13 04:42:26 -0600 )edit
1

layerSizes(0, 2) = 2;

and:

Mat sample = Mat::ones(1, data.cols, data.type());
Mat result;
network->predict(sample, result);
cerr << result << endl;
berak gravatar imageberak ( 2016-05-13 05:06:12 -0600 )edit

Thanks for your help! Actually I found out what's the problem (or at least what seems to be a major problem): The problem is the activation function, i.e. the line

network->setActivationFunction(0, 0.1, 0.1);

where 0 is equivalent to IDENTITY. Writing a 1 there (i.e. SIGMOID_SYM) solves the problem, at least the predictions do work and return some results. I'll post some working example code here soon.

Finally I would like to fully understand your point regarding the output layer size: Using SIGMOID_SYM the predictions work with both configurations, but actually do I need the explicit 1-of-k encoding? If I use a different classifier from OpenCV using a single response vector containing the class indices works fine, does this not hold for neural nets or is there a major difference?

RubixCube gravatar imageRubixCube ( 2016-05-13 06:34:20 -0600 )edit

2 answers

Sort by » oldest newest most voted
5

answered 2016-05-17 01:52:47 -0600

RubixCube gravatar image

As already mentioned in above comments, here is a working minimum example in case anyone is into the same problem:

#include <opencv2/ml/ml.hpp>

using namespace std;
using namespace cv;
using namespace cv::ml;

int main(int argc, char* argv[])
{
    //create random training data
    Mat_<float> data(100, 100);
    randn(data, Mat::zeros(1, 1, data.type()), Mat::ones(1, 1, data.type()));

    //half of the samples for each class
    Mat_<float> responses(data.rows, 2);
    for (int i = 0; i<data.rows; ++i)
    {
        if (i < data.rows/2)
        {
            data(i, 0) = 1;
            data(i, 1) = 0;
        }
        else
        {
            data(i, 0) = 0;
            data(i, 1) = 1;
        }
    }

    /*
    Mat_<float> responses(data.rows, 1);
    for (int i=0; i<responses.rows; ++i)
        responses(i, 0) = i < responses.rows / 2 ? 0 : 1;
    */

    //create the neural network
    Mat_<int> layerSizes(1, 3);
    layerSizes(0, 0) = data.cols;
    layerSizes(0, 1) = 20;
    layerSizes(0, 2) = responses.cols;

    Ptr<ANN_MLP> network = ANN_MLP::create();
    network->setLayerSizes(layerSizes);
    network->setActivationFunction(ANN_MLP::SIGMOID_SYM, 0.1, 0.1);
    network->setTrainMethod(ANN_MLP::BACKPROP, 0.1, 0.1);
    Ptr<TrainData> trainData = TrainData::create(data, ROW_SAMPLE, responses);

    network->train(trainData);
    if (network->isTrained())
    {
        printf("Predict one-vector:\n");
        Mat result;
        network->predict(Mat::ones(1, data.cols, data.type()), result);
        cout << result << endl;

        printf("Predict training data:\n");
        for (int i=0; i<data.rows; ++i)
        {
            network->predict(data.row(i), result);
            cout << result << endl;
        }
    }

    return 0;
}
edit flag offensive delete link more

Comments

3

Would you be up to supplying this up to date samples as a C++ sample to the library through a PR?

StevenPuttemans gravatar imageStevenPuttemans ( 2016-05-17 07:16:30 -0600 )edit
1

good idea, created the PR :-)

RubixCube gravatar imageRubixCube ( 2016-05-18 08:58:28 -0600 )edit
2

Great! You are awesome!

StevenPuttemans gravatar imageStevenPuttemans ( 2016-05-18 10:52:33 -0600 )edit
0

answered 2018-11-21 07:48:13 -0600

microchips gravatar image

updated 2018-11-21 07:51:56 -0600

Using activation SIGMOID_SYM paramerters are supposed to be 0 or 1 not 0.1

SIGMOID_SYM
Symmetrical sigmoid: f(x)=β∗(1−e−αx)/(1+e−αx . . . . from Open CV documentation it says:-

Note If you are using the default sigmoid activation function with the default parameter values fparam1=0 and fparam2=0 then the function used is y = 1.7159*tanh(2/3 * x), so the output will range from [-1.7159, 1.7159], instead of [0,1].

edit flag offensive delete link more

Question Tools

1 follower

Stats

Asked: 2016-05-13 03:17:15 -0600

Seen: 2,604 times

Last updated: Nov 21 '18