Ask Your Question
0

Why is my C++ OpenCV 3.4.1 Neural Network predicting so badly?

asked 2018-06-01 12:26:42 -0600

Leticia FS gravatar image

Hello everyone!!

I am trying to develop an Artificial Neural Network in C++ using OpenCV 3.4.1 with the aim of being able to recognise 33 different characters, including both numbers and letters, but the results I am obtaining are always wrong.

I have tested my code with different parameters' values like the alpha and beta of the sigmoid function that I am using for training, the backpropagation parameters, or the number of hidden nodes but, although the result varies sometimes, it normally tends to be a vector of the following shape:

Classification result: [20.855789, -0.033862107, -0.0053131776, 0.026316155, -0.0032050854, 0.036046479, -0.025410429, -0.017537225, 0.015429396, -0.023276867, 0.013653283, -0.025660357, -0.051959664, -0.0032470606, 0.032143779, -0.011631044, 0.022339549, 0.041757714, 0.04414707, -0.044756029, 0.042280547, 0.012204648, 0.026924053, 0.016814215, -0.028257577, 0.05190875, -0.0070033628, -0.0084492415, -0.040644459, 0.00022287761, -0.0376678, -0.0021550131, -0.015310903]

That is, independently of which character I test, it is always predicting that the analysed character is the one in the first position of the characters vector, which corresponds to number '1'.

The training data is obtained from an .XML I have created, which contains 474 samples (rows) with 265 attributes each (cols). As for the training classes, following some advice I found in a previous question in this forum, it is obtained from another .XML file that contains 474 rows, one for each training sample, and 33 columns, one for each character/class.

I attach the code below so that you can perhaps kindly guess what I am doing wrong and I am so thankful in advance for any help you can offer! :)

//Create the Neural Network
Mat_<int> layerSizes(1, 3);
layerSizes(0, 0) = numFeaturesPerSample;
layerSizes(0, 1) = nlayers;
layerSizes(0, 2) = numClasses;

//Set ANN params
Ptr<ANN_MLP> network = ANN_MLP::create();
network->setLayerSizes(layerSizes);
network->setActivationFunction(ANN_MLP::SIGMOID_SYM, 0.6, 1); 
network->setTrainMethod(ANN_MLP::BACKPROP, 0.1, 0.1);
Ptr<TrainData> trainData = TrainData::create(TrainingData, ROW_SAMPLE, classes);
network->train(trainData);

//Predict
if (network->isTrained())
{
    trained = true;
    Mat results;
    cout << "Predict:" << endl;
    network->predict(features, results); 
    cout << "Prediction done!" << endl;
    cout << endl << "Classification result: " << endl << results << endl;

    //We need to know where in output is the max val, the x (cols) is the class.
    Point maxLoc;
    double maxVal;
    minMaxLoc(results, 0, &maxVal, 0, &maxLoc);

    return maxLoc.x;
}
edit retag flag offensive close merge delete

1 answer

Sort by ยป oldest newest most voted
0

answered 2018-06-01 13:49:39 -0600

berak gravatar image

updated 2018-06-01 13:59:05 -0600

you seem to confuse rows and cols a lot here.

your code will throw errors, unless you meant:

  • there are 474 features per image (cols in the train / test dataset)
  • there are 256 train images (rows in the train dataset)
  • there are 33 classes (cols in the ann network output)

and the obvious answer to your problem is:

  1. your network is not large enough to discriminate your data. also a plain "dense" network might be too primitive (cnn's rule here, as of today ..)
  2. you do not have enough data to train it. 256/33 == ~7 images per class. not enough.
edit flag offensive delete link more

Comments

Thank you so much berak!

The thing is that my code is not throwing any errors with the rows and cols I have specified in the description, which are not the ones that you say, as there are 474 train images and 256 features per image. I really don't see why it should throw errors...maybe I am missing something?

I will try to increase the training set as you say, because it might still be insufficient as you mention. And as for the kind of ann, I know that cnns are much better than plain anns but it is a university task in which I am supposed to use this kind of network so I have no choice there...

Leticia FS gravatar imageLeticia FS ( 2018-06-02 11:19:32 -0600 )edit

yea, i only meant: you confused it in the question description, no you're not missing anything. if your code works, you got that part right.

your network is most probably overfitting, due to poor and not enough training data, see, there is a digits.png in the opencv samples. (handwritten numbers), that has 1000 samples per digit, and you do get nice results with that !

also, how did you arrive at 474 features per image ? maybe you made it too small. (MNIST has28*28==784 features per image.

maybe you also need another hidden layer ? like: 784 -> 512 -> 256 -> 33

opencv's ANN does not have any proper regularization (like dropout), but at least you could try to fight the overfitting with a smaller initial learning rate.

http://theorangeduck.com/page/neural-...

berak gravatar imageberak ( 2018-06-02 11:46:47 -0600 )edit

ok thanks again berak! I will try increasing both the training data set as I have told you and the number of features per image then. And I will also study the possibility of adding another hidden layer to see if it works better. However, I don't understand what you mean in your last point about the smaller initial learning rate... And thank you so much for the useful web page!! :)

Leticia FS gravatar imageLeticia FS ( 2018-06-02 12:58:00 -0600 )edit

Question Tools

1 follower

Stats

Asked: 2018-06-01 12:25:55 -0600

Seen: 911 times

Last updated: Jun 01 '18