【发布时间】:2014-03-26 03:49:28
【问题描述】:
我使用 OpenCV 已经有一段时间了。我最近决定检查它在机器学习方面的能力。所以我最终实现了一个用于人脸识别的神经网络。总结一下我的人脸识别策略:
- 从某个人脸数据库的 csv 中读取图像。
- 将图像逐行滚动到 Mat 数组。
- 应用 PCA 进行降维。
- 使用 PCA 的投影来训练网络。
-
使用经过训练的网络预测测试数据。
所以在预测阶段之前一切都很好。我正在使用最大响应输出单元对人脸进行分类。所以通常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 Baci,在那里阅读您的问题。除了 SO 链接,您能否在此处添加一些细节,例如有问题的 mlp.create(layers, CvANN_MLP::SIGMOID_SYM, 1, 1);线 ? (也许是一个解释,为什么默认值被破坏)它会好得多,如果这样的事情不需要那里的穷人解析 SO 噪音
标签: c++ opencv machine-learning neural-network