【问题标题】:OpenCV Neural Network Sigmoid OutputOpenCV 神经网络 Sigmoid 输出
【发布时间】:2014-03-26 03:49:28
【问题描述】:

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

  1. 从某个人脸数据库的 csv 中读取图像。
  2. 将图像逐行滚动到 Mat 数组。
  3. 应用 PCA 进行降维。
  4. 使用 PCA 的投影来训练网络。
  5. 使用经过训练的网络预测测试数据。

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

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

读取 csv

void read_csv(const string& filename, vector& images, vector& labels, char separator = ';') { std::ifstream 文件(filename.c_str(), ifstream::in); 如果(!文件) { string error_message = "没有给出有效的输入文件,请检查给定的文件名。"; CV_Error(1, error_message); } 字符串行、路径、类标签; 而(getline(文件,行)) { 串流线(线); getline(线条,路径,分隔符); getline(线条,类标签); if(!path.empty() && !classlabel.empty()) { Mat im = imread(path, 0); images.push_back(im); 标签.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&T 的前 20 个类作为我的数据集。

【问题讨论】:

  • 能否手动设置参数,即mlp.create(layers, CvANN_MLP::SIGMOID_SYM, 1, 1);
  • 如果可行,请提交错误报告,因为默认值 0 对 alpha 和 beta 没有意义。
  • 它似乎出乎意料地将 sigmoid 输出值更正到了建议的范围。现在,我正在使用其他参数以获得更好的准确性。我将很快发布我在神经网络方面的经验。顺便谢谢你:)
  • @Canberk Ba​​ci,在那里阅读您的问题。除了 SO 链接,您能否在此处添加一些细节,例如有问题的 mlp.create(layers, CvANN_MLP::SIGMOID_SYM, 1, 1);线 ? (也许是一个解释,为什么默认值被破坏)它会好得多,如果这样的事情不需要那里的穷人解析 SO 噪音

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


【解决方案1】:

感谢 Canberk Ba​​ci 的评论,我设法克服了 sigmoid 输出差异。 问题似乎在于 mlp 的 create 函数的默认参数,该函数将 alpha 和 beta 0 作为默认值。当它们都为 1 时,sigmoid 函数按照文档中的说明工作,神经网络可以预测某些东西,但当然会有错误。

对于神经网络的结果:

通过修改一些参数,如动量等,并且没有任何光照校正算法,我在 opencv 教程中的前 20 类 CroppedYaleB 的数据集(随机采样 936 个训练,262 个测试图像)上获得了 %72 的准确度。对于提高准确性的其他因素;当我应用 PCA 时,我直接将缩减后的维度大小设为 500。这也可能会降低准确性,因为保留的方差可能低于 %95 或更差。所以当我有空闲时间时,我会应用这些来提高准确性:

  1. Tan Triggs 光照校正
  2. 以 0.95 作为 pca 大小训练 PCA 以保留 %95 方差。
  3. 修改神经网络参数(我希望我们在 OpenCV 库中有一个参数较少的 NN)

我分享了这些,所以有人可能想知道如何提高 NN 的分类准确度。希望对你有帮助。

顺便说一句,您可以在此处跟踪有关此问题: http://code.opencv.org/issues/3583

【讨论】:

    猜你喜欢
    • 2017-07-28
    • 1970-01-01
    • 2016-09-19
    • 2019-01-17
    • 2015-02-23
    • 2014-11-03
    • 2014-01-06
    • 2021-02-05
    相关资源
    最近更新 更多