OpenCV神经网络Sigmoid输出

时间:2014-02-24 12:57:56

标签: c++ opencv machine-learning neural-network

我一直在使用OpenCV。我最近决定检查它的机器学习能力。所以我最终实现了一个用于人脸识别的神经网络。总结我的人脸识别策略:

  1. 从某个面部数据库的csv中读取图像。
  2. 将图像滚动到Mat数组。
  3. 应用PCA以减少维数。
  4. 使用PCA的预测来训练网络。
  5. 使用经过培训的网络预测测试数据。

    所以一切都好,直到预测阶段。我使用最大响应输出单元对脸部进行分类。因此,通常OpenCV的sigmoid实现应该给出-1到1范围内的值,这在文档中说明。 1是类的最大闭包。在我获得接近0的准确度之后,我检查了每个测试数据的每个类的输出响应。我对这些值感到惊讶: 14.53,-1.7,#IND 。如果应用了sigmoid,我怎么能得到这些值?我在哪里做错了?

    为了帮助您了解此事以及那些想知道如何应用PCA并将其与NN一起使用的人我分享了我的代码:

  6. 阅读csv

    void read_csv(const string& filename, vector& images, vector& labels, char separator = ';') 
    {
        std::ifstream file(filename.c_str(), ifstream::in);
        if (!file) 
        {
            string error_message = "No valid input file was given, please check the given filename.";
            CV_Error(1, error_message);
        }
        string line, path, classlabel;
        while (getline(file, line)) 
        {
            stringstream liness(line);
    
            getline(liness, path, separator);
            getline(liness, classlabel);
    
            if(!path.empty() && !classlabel.empty()) 
            {
                Mat im = imread(path, 0);
    
                images.push_back(im);
                labels.push_back(atoi(classlabel.c_str()));
            }
        }
    }
    

    逐行滚动图片:

    Mat rollVectortoMat(const vector<Mat> &data)
    {
       Mat dst(static_cast<int>(data.size()), data[0].rows*data[0].cols, CV_32FC1);
       for(unsigned int i = 0; i < data.size(); i++)
       {
          Mat image_row = data[i].clone().reshape(1,1);
          Mat row_i = dst.row(i);                                       
          image_row.convertTo(row_i,CV_32FC1, 1/255.);
       }
       return dst;
    }
    

    将标签矢量转换为标签垫

    Mat getLabels(const vector<int> &data,int classes = 20)
    {
        Mat labels(data.size(),classes,CV_32FC1);
    
        for(int i = 0; i <data.size() ; i++)
        {
            int cls = data[i] - 1;  
            labels.at<float>(i,cls) = 1.0;  
        }
    
        return labels;
    }
    

    主要

    int main()
    {
    
        PCA pca;
    
        vector<Mat> images_train;
        vector<Mat> images_test;
        vector<int> labels_train;
        vector<int> labels_test;
    
        read_csv("train1k.txt",images_train,labels_train);
        read_csv("test1k.txt",images_test,labels_test);
    
        Mat rawTrainData = rollVectortoMat(images_train);                       
        Mat rawTestData  = rollVectortoMat(images_test);                
    
        Mat trainLabels = getLabels(labels_train);
        Mat testLabels  = getLabels(labels_test);
    
        int pca_size = 500;
    
        Mat trainData(rawTrainData.rows, pca_size,rawTrainData.type());
        Mat testData(rawTestData.rows,pca_size,rawTestData.type());
    
    
        pca(rawTrainData,Mat(),CV_PCA_DATA_AS_ROW,pca_size);
    
        for(int i = 0; i < rawTrainData.rows ; i++)
            pca.project(rawTrainData.row(i),trainData.row(i));
    
        for(int i = 0; i < rawTestData.rows ; i++)
            pca.project(rawTestData.row(i),testData.row(i));
    
    
    
        Mat layers = Mat(3,1,CV_32SC1);
        int sz = trainData.cols ;
    
        layers.row(0) = Scalar(sz);
        layers.row(1) = Scalar(1000);
        layers.row(2) = Scalar(20);
    
        CvANN_MLP mlp;
        CvANN_MLP_TrainParams params;
        CvTermCriteria criteria;
    
        criteria.max_iter = 1000;
        criteria.epsilon  = 0.00001f;
        criteria.type     = CV_TERMCRIT_ITER | CV_TERMCRIT_EPS;
    
        params.train_method    = CvANN_MLP_TrainParams::BACKPROP;
        params.bp_dw_scale     = 0.1f;
        params.bp_moment_scale = 0.1f;
        params.term_crit       = criteria;
    
        mlp.create(layers,CvANN_MLP::SIGMOID_SYM);
        int i = mlp.train(trainData,trainLabels,Mat(),Mat(),params);
    
        int t = 0, f = 0;
    
        for(int i = 0; i < testData.rows ; i++)
        {
            Mat response(1,20,CV_32FC1);
            Mat sample = testData.row(i);
    
            mlp.predict(sample,response);
    
            float max = -1000000000000.0f;
            int cls = -1;
    
            for(int j = 0 ; j < 20 ; j++)   
            {
                float value = response.at<float>(0,j);
    
                if(value > max)
                {
                    max = value;
                    cls = j + 1;
                }
            }
    
            if(cls == labels_test[i])
                t++;
            else
                f++;
        }
    
    
        return 0;
    }
    

    注意:我使用AT&amp; T的前20个类作为我的数据集。

1 个答案:

答案 0 :(得分:4)

感谢Canberk Ba​​ci的评论,我设法克服了sigmoid输出差异。 问题似乎是mlp的创建函数的默认参数,它将alpha和beta 0视为默认值。当它们都被给定为1时,sigmoid函数的工作方式与文档中所述的相同,神经网络可以预测某些东西,但当然会有错误。

神经网络的结果:

通过修改动量等一些参数,并且没有任何照明校正算法,我从opencv教程中获得了72个精确度(随机抽样的936列车,262个测试图像)前20个类的CroppedYaleB。对于提高准确性的其他因素;当我应用PCA时,我直接将缩小的尺寸大小设为500.这也可能降低准确性,因为保留的方差可能低于%95或更差。因此,当我有空闲时间时,我将应用这些来提高准确性:

  1. Tan Triggs照度校正
  2. 使用0.95作为pca大小训练PCA以保留%95差异。
  3. 修改神经网络参数(我希望我们在OpenCV库中使用参数较少的NN)
  4. 我分享了这些,以便有人可能想知道如何提高NN的分类准确性。我希望它有所帮助。

    顺便提一下,您可以在此处跟踪此问题: http://code.opencv.org/issues/3583