OpenCV MLP UPDATE_WEIGHTS действует вяло?
Я столкнулся с этой проблемой, пытаясь построить кривую обучения MLP, которую я использовал, чтобы предсказать 4 выходных значения в 30000 выборок. Я хотел использовать UPDATE_WEIGHTS для вывода ошибки после каждой эпохи обучения. Таким образом, я могу построить график и посмотреть на тенденции.
При обучении сети и установке критериев завершения COUNT=1000 сеть получила ошибку ~5%. Проблема в том, что когда я использовал UPDATE_WEIGHTS для итеративного обучения сети 1 эпоха, ошибка не сходилась к одному и тому же значению или с похожим трендом.
Ниже приведен код для простого примера, иллюстрирующего ту же проблему UPDATE_WEIGHTS, просто чтобы вы могли ясно увидеть, в чем проблема. В примере используется MLP, чтобы узнать, как добавить два числа, и сравнивается итеративное обучение сети, используя количество раз UPDATE_WEIGHTS nEpoch (network1) для переобучения сети и используя критерии завершения COUNT = nEpochs (network2).
OpenCV 4.0.1
MacBook Pro 64 бит
Eclipse C++
// create train data
int nTrainRows = 1000;
cv::Mat trainMat(nTrainRows, 2, CV_32F);
cv::Mat labelsMat(nTrainRows, 1, CV_32F);
for(int i = 0; i < nTrainRows; i++) {
double rand1 = rand() % 100;
double rand2 = rand() % 100;
trainMat.at<float>(i, 0) = rand1;
trainMat.at<float>(i, 1) = rand2;
labelsMat.at<float>(i, 0) = rand1 + rand2;
}
// create test data
int nTestRows = 100;
cv::Mat testMat(nTestRows, 2, CV_32F);
cv::Mat truthsMat(nTestRows, 1, CV_32F);
for(int i = 0; i < nTestRows; i++) {
double rand1 = rand() % 100;
double rand2 = rand() % 100;
testMat.at<float>(i, 0) = rand1;
testMat.at<float>(i, 1) = rand2;
truthsMat.at<float>(i, 0) = rand1 + rand2;
}
// initialize network1 and set network parameters
cv::Ptr<cv::ml::ANN_MLP > network1 = cv::ml::ANN_MLP::create();
cv::Mat layersMat(1, 2, CV_32SC1);
layersMat.col(0) = cv::Scalar(trainMat.cols);
layersMat.col(1) = cv::Scalar(labelsMat.cols);
network1->setLayerSizes(layersMat);
network1->setActivationFunction(cv::ml::ANN_MLP::ActivationFunctions::SIGMOID_SYM);
network1->setTermCriteria(cv::TermCriteria(cv::TermCriteria::COUNT + cv::TermCriteria::EPS, 1, 0));
cv::Ptr<cv::ml::TrainData> trainData = cv::ml::TrainData::create(trainMat,cv::ml::ROW_SAMPLE,labelsMat,cv::Mat(),cv::Mat(),cv::Mat(),cv::Mat());
network1->train(trainData);
// loop through each epoch, one at a time, and compare error between the two methods
for(int nEpochs = 2; nEpochs <= 20; nEpochs++) {
// train network1 with one more epoch
network1->train(trainData,cv::ml::ANN_MLP::UPDATE_WEIGHTS);
cv::Mat predictions;
network1->predict(testMat, predictions);
double totalError = 0;
for(int i = 0; i < nTestRows; i++)
totalError += abs( truthsMat.at<float>(i, 0) - predictions.at<float>(i, 0) );
double aveError = totalError / (double) nTestRows;
//recreate network2
cv::Ptr<cv::ml::ANN_MLP > network2 = cv::ml::ANN_MLP::create();
network2->setLayerSizes(layersMat);
network2->setActivationFunction(cv::ml::ANN_MLP::ActivationFunctions::SIGMOID_SYM);
network2->setTermCriteria(cv::TermCriteria(cv::TermCriteria::COUNT + cv::TermCriteria::EPS, nEpochs, 0));
// train network2 from scratch, specifying to train with nEpochs
network2->train(trainData);
network2->predict(testMat, predictions);
totalError = 0;
for(int i = 0; i < nTestRows; i++)
totalError += abs( truthsMat.at<float>(i, 0) - predictions.at<float>(i, 0) );
aveError = totalError / (double) nTestRows;
}
Я изобразил среднюю ошибку в сравнении с количеством использованных тренировочных эпох:
Вы можете видеть, что network1 (с использованием UPDATE_WEIGHTS) и network2 (с использованием COUNT) действуют очень по-разному, даже если количество обучающих эпох одинаково. Ошибка из сети 2 сходится быстрее, а сеть 1 сходится с более высокой ошибкой. Я не могу найти причину, почему это будет так, поскольку они должны быть одинаковыми?
-Тим