【问题标题】:opencv neural network, incorrect predictopencv神经网络,不正确的预测
【发布时间】:2016-07-28 23:41:41
【问题描述】:

我正在尝试使用 OpenCV 在 C++ 中创建神经网络。目的是识别路标。我以这种方式创建了网络,但它的预测很糟糕,因为它返回了奇怪的结果:

训练选择的示例图像如下所示:

有人可以帮忙吗?

  trainNN() {
    char* templates_directory[] = {
        "speed50ver1\\", 
        "speed60ver1\\", 
        "speed70ver1\\",
        "speed80ver1\\"
    };

    int const numFilesChars[]={ 213, 100, 385, 163};

    char const strCharacters[] = { '5', '6', '7', '8' };

    Mat trainingData; 
    Mat trainingLabels(0, 0, CV_32S);

    int const numCharacters = 4;  

    // load images from directory
    for (int i = 0; i != numCharacters; ++i) {
        int numFiles = numFilesChars[i];

        DIR *dir;
        struct dirent *ent;

        char* s1 = templates_directory[i];

        if ((dir = opendir (s1)) != NULL) {
            Size size(80, 80);

            while ((ent = readdir (dir)) != NULL) {
                string s = s1;
                s.append(ent->d_name);

                if(s.substr(s.find_last_of(".") + 1) == "jpg") {
                    Mat img = imread(s,0);
                    Mat img_mat;
                    resize(img, img_mat, size);
                    Mat new_img = img_mat.reshape(1, 1);
                    trainingData.push_back(new_img);
                    trainingLabels.push_back(i);

                }

            }
            int b = 0;
            closedir (dir);
        } else {
            /* could not open directory */
            perror ("");
        }
    }

    trainingData.convertTo(trainingData, CV_32FC1);

    Mat trainClasses(trainingData.rows, numCharacters, CV_32FC1);
    for( int i = 0; i !=  trainClasses.rows; ++i){
        int const labels = *trainingLabels.ptr<int>(i);
        auto train_ptr = trainClasses.ptr<float>(i);
        for(int k = 0; k != trainClasses.cols; ++k){
            *train_ptr = k != labels ? 0 : 1;
            ++train_ptr;
        }
    }

    int layers_d[] = { trainingData.cols, 10,  numCharacters};
    Mat layers(1, 3, CV_32SC1, layers_d);
    ann.create(layers, CvANN_MLP::SIGMOID_SYM, 1, 1);

    CvANN_MLP_TrainParams params = CvANN_MLP_TrainParams(
        // terminate the training after either 1000
        // iterations or a very small change in the
        // network wieghts below the specified value
        cvTermCriteria(CV_TERMCRIT_ITER+CV_TERMCRIT_EPS, 1000, 0.000001),

        // use backpropogation for training
        CvANN_MLP_TrainParams::BACKPROP,

        // co-efficents for backpropogation training
        // (refer to manual)
        0.1,
        0.1);

    int iterations = ann.train(trainingData, trainClasses, cv::Mat(), cv::Mat(), params);

    CvFileStorage* storage = cvOpenFileStorage( "neural_network_2.xml", 0, CV_STORAGE_WRITE );
    ann.write(storage,"digit_recognition");
    cvReleaseFileStorage(&storage);

}  


void analysis(char* file, bool a) {
    //trainNN(a);
    read_nn();


    // load image
    Mat img = imread(file,  0);

    Size my_size(80,80);
    resize(img, img, my_size);

    Mat r_img = img.reshape(1,1);

    r_img.convertTo(r_img, CV_32FC1);   

    Mat classOut(1,4,CV_32FC1); 

    ann.predict(r_img, classOut);

    double min1, max1;
    cv::Point min_loc, max_loc;
    minMaxLoc(classOut, &min1, &max1, &min_loc, &max_loc);
    int x = max_loc.x;


    //create windows
    namedWindow("Original Image", CV_WINDOW_AUTOSIZE);
    imshow("Original Image", img);

    waitKey(0); //wait for key press

    img.release();
    rr.release();

    destroyAllWindows(); //destroy all open windows
}

奇怪的结果:对于这个输入,答案是 3(因为我只有 4 个类 - 限速 50、60、70、80)。限速80标志是正确的。

但是对于其余的输入结果是不正确的。它们对于符号 50、60、70 是相同的。max1 = min1 = 1.02631...(如第一张图片所示)这很奇怪。

【问题讨论】:

  • 也许this link 会有用。
  • 使用 MNIST 手写数字集是检查您自己的实现的好方法 - 对于该数据集,众所周知不同算法的性能应该有多好。
  • 您使用什么传递函数,您的样本量是多少? (还有你的 eta/alpha)你可能训练过度/训练不足。对于一个简单的测试,尝试使用神经网络创建一个 XOR 门,然后在 MNIST 数据集上作为 MSalters 工作。为了节省一些时间,请查看stackoverflow.com/questions/8286668/how-to-read-mnist-data-in-c,了解如何在 c++ 中读取 MNIST。

标签: c++ opencv neural-network


【解决方案1】:

我只使用 OpenCV 实现了 NN 用于布尔分类,但我认为对于需要对两个以上不同类进行分类的任务,这可能也适用:

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

那么,你在哪里做:

*train_ptr = k != labels ? 0 : 1;

你可能想试试:

*train_ptr = k != labels ? -1 : 1;

如果我在这里偏离轨道,请忽略。

【讨论】:

  • 很遗憾,没用,不过还是谢谢大家的帮助
  • 如果您不介意,我可以尝试实现我自己的分类器版本。我只需要 ANN 的训练和测试图像,以及您感兴趣的课程。
  • 好的,这是训练选择dropbox.com/s/zdf840zmhvgav46/training2.rar?dl=0 classes: 50, 60, 70, 80
  • 我不知道你是否已经解决了这个问题,但这是我想出的:onedrive.live.com/…。这确实是 Aenimated1 所解释的,即您当前的 ANN 架构可能存在高偏差。
【解决方案2】:

我已经调整了您的代码,以在 4 个手部位置上训练分类器(因为这是我拥有的图像数据)。我使您的逻辑尽可能相似,只更改了绝对必要的内容,以使其在我的图像上的 Windows 机器上运行。长话短说,您的代码根本没有任何问题 - 我没有看到您描述的故障模式。

您遗漏的一件事是 read_nn() 的代码。我假设它只是执行以下操作: ann.load("neural_network_2.xml");

无论如何,我的怀疑是您的神经网络根本没有收敛,或者严重过度拟合。也许训练数据没有足够的变化。您是否对 ANN 未经过训练的单独测试数据运行 analysis()?如果是这样,ANN 至少能够正确预测训练数据吗?

编辑:好的,我刚刚下载了您的图像数据并进行了尝试,并看到了相同的行为。经过一些分析,您的 ANN 似乎没有收敛。即使您仅为 cvTermCriteria 指定 CV_TERMCRIT_ITER,训练操作仅在大约 250 次迭代后退出。在将隐藏层大小从 10 增加到 20 后,我看到了显着的改进,将 212、72、94 和 143 图像的训练数据分别成功分类到类别(50、60、70 和 80) .这不是很好,但它表明你在正确的轨道上。

基本上,网络架构的表达能力不足以充分模拟您要解决的问题,因此网络权重永远不会收敛,并且会提前放弃反向传播。对于一个课程,您可能会看到一些成功,但我相信这主要是由于缺乏训练数据的洗牌。如果它在刚刚对几百个非常相似的图像进行训练后停止,它可能能够正确地对这些图像进行分类。

简而言之,我建议执行以下操作:

  1. 构建一种方法来测试结果 - 例如:创建一个函数来对所有训练数据运行预测,并在理想情况下留出一些图像作为验证集,以确认模型没有过度拟合训练数据。
  2. 在训练之前打乱训练数据。否则,反向传播将不会那么容易收敛。
  3. 尝试不同的架构,例如多个不同大小的隐藏层。

确实,这是一个可以从使用卷积神经网络中受益匪浅的问题,但是 OpenCV 的机器学习设施非常有限。最终,如果您对创建 ANN 很认真,您可能想要研究一些更强大的工具。我个人使用 Tensorflow,但我也听说过 Theano 的好消息。

【讨论】:

  • 我什至给出了输入测试中训练选择的图像。它没有用。
  • 请查看我的进一步编辑 - 希望这会让您进一步努力。
猜你喜欢
  • 2021-09-12
  • 1970-01-01
  • 1970-01-01
  • 2017-12-02
  • 2015-12-11
  • 2018-06-08
  • 1970-01-01
  • 2012-05-06
  • 2017-12-28
相关资源
最近更新 更多