Доброго времени суток, Господа.
Меня заинтересовала тема нейронных сетей и я решил почитать литературу по этой теме и поэкспериментировать. Для экспериментов выбрал библиотеку opencv и нашел тестовый пример, в котором на вход сети подается два числа (a, в диапазоне [0..100] а на выходе получаем середину отрезка (a+B)/2
Итак, диспозиция:
opencv 2.3.1
IDE - Visual Studio 2010
тип нейронной сети - многослойный перцептрон, два нейрона во входном слое, два скрытых слоя и один нейрон на выходном слое.
метод обучения - метод обратного распространения ошибки
Я написал небольшое консольное приложение (код в конце поста), генерирующее обучающую выборку заданного размера (функция generateTrainData) и далее заданное количество итераций (эпох) обучающее нейронную сеть на этой выборке. После каждого обучения (эпохи) я считаю суммарную ошибку сети - как сумму ошибок в 10 точках (массив quality_array), деленную на количество этих точек. Если Вы посмотрите на лог-файл, который генерирует программа, то увидите, что точность после каждой эпохи может улучшится, а может и ухудшится (строки Train quality ). Например первые две эпохи точность вроде бы улучшалась: была 0.509696, потом стала 0.467227, а потом снова ухудшилась 0.643969.
Вопрос: в чем причина того, что ошибка не уменьшается монотонно, как я предполагал?
Для увеличения точности, я варьировал параметрами самой сети и обучения - увеличил число нейронов в скрытом слое ажно до 100 !!! Увеличивал точность и число итераций при обучении (константы Epsilon и MaxIter). Увеличивал число эпох обучения и размер выборки - но все тщетно: точность не увеличивалась от эпохи к эпохе и ошибка не достигала 3 знака после запятой.
Вопрос: что можно предпринять для увеличения точности?
Лог-файл:
Train quality 0.509696
Train quality 0.467227
Train quality 0.643969
Train quality 0.986835
Train quality 0.718875
Train quality 0.781358
Train quality 0.826931
Train quality 0.855752
Train quality 0.617246
Train quality 0.778907
Predict input 1.000000 8.000000 Result 4.738886 Error 0.238886
Predict input 2.000000 14.000000 Result 8.184313 Error 0.184313
Predict input 30.000000 40.000000 Result 35.144043 Error 0.144043
Predict input 50.000000 54.000000 Result 51.961819 Error 0.038181
Time elapsed 119 sec
Код программы
#include "stdafx.h"
#include "cv.h"
#include "ml.h"
#include <cstdlib>
#include <iostream>
#include <stdlib.h>
#include <math.h>
// The neural network
CvANN_MLP machineBrain;
using namespace std;
float td[100000][3];
#define train_sample_count 2000
#define MaxIter 1000000
#define Epsilon 0.0000001
#define Param1 0.1
#define Param2 0.5
#define Epoch 10
#define Range 100
#define quality_test 10
float quality_array[quality_test][2] = {{1,8}, {12,20}, {18,28}, {30,36}, {42,49}
, {50,54},{54,60}, {1,80}, {90,30}, {80,90}};
float round_2 (float val) {
return floorf(val * 100) / 100;
}
void generateTrainData (float parts, float over, FILE * ftrain) {
int j = 0;
for (float p = 0; p < 1.0; p+=parts) {
for (int i=0;i<train_sample_count*parts;i++,j++)
{
td[j][0] = int((rand()/float(RAND_MAX))*(((int)(Range*(parts+over))) + 0.001) + Range*p + 1); //(rand()%((int)(Range*(parts+over)))) + Range*p + 1;
td[j][1] = int((rand()/float(RAND_MAX))*(((int)(Range*(parts+over))) + 0.001) + Range*p + 1); //(rand()%((int)(Range*(parts+over)))) + Range*p + 1;
td[j][2] = round_2((td[j][0] + td[j][1]) / 2.0);
fprintf(ftrain,"%f\t%f\t%f\n",td[j][0],td[j][1],td[j][2]);
}
}
}
void trainMachine(FILE * flog)
{
int i;
printf("Found training file with %d samples...\n", train_sample_count);
//Input data samples. Matrix of order (train_sample_count x 2)
CvMat* trainData = cvCreateMat(train_sample_count, 2, CV_32FC1);
//Output data samples. Matrix of order (train_sample_count x 1)
CvMat* trainClasses = cvCreateMat(train_sample_count, 1, CV_32FC1);
//The weight of each training data sample. We'll later set all to equal weights.
CvMat* sampleWts = cvCreateMat(train_sample_count, 1, CV_32FC1);
CvMat trainData1, trainClasses1, sampleWts1;
cvGetRows(trainData, &trainData1, 0, train_sample_count);
cvGetRows(trainClasses, &trainClasses1, 0, train_sample_count);
cvGetRows(trainClasses, &trainClasses1, 0, train_sample_count);
cvGetRows(sampleWts, &sampleWts1, 0, train_sample_count);
//Assemble the ML training data.
for (i=0; i<train_sample_count; i++)
{
//Input 1
cvSetReal2D(&trainData1, i, 0, td[i][0]);
//Input 2
cvSetReal2D(&trainData1, i, 1, td[i][1]);
//Output
cvSet1D(&trainClasses1, i, cvScalar(td[i][2]));
//Weight (setting everything to 1)
cvSet1D(&sampleWts1, i, cvScalar(1));
}
//Train it with our data.
//See the Machine learning reference at http://www.seas.upenn.edu/~bensapp/opencvdocs/ref/opencvref_ml.htm#ch_ann
machineBrain.train(
trainData,
trainClasses,
sampleWts,
0,
CvANN_MLP_TrainParams(
cvTermCriteria(
CV_TERMCRIT_ITER+CV_TERMCRIT_EPS,
MaxIter,
//! 1.0
Epsilon
),
CvANN_MLP_TrainParams::BACKPROP,
//!0.01,
Param1,
//!0.05
Param2
)
);
fprintf(flog,"Settings:\ntrain_sample_count %d MaxIter %d Epsilon %f Param1 %f Param2 %f\n",train_sample_count,MaxIter,Epsilon,Param1,Param2);
}
void createMachine() {
//The matrix representation of our ANN. We'll have four layers.
CvMat* neuralLayers = cvCreateMat(4, 1, CV_32SC1);
CvMat neuralLayers1;
cvGetRows(neuralLayers, &neuralLayers1, 0, 4);
cvSet1D(&neuralLayers1, 0, cvScalar(2));
cvSet1D(&neuralLayers1, 1, cvScalar(100));
cvSet1D(&neuralLayers1, 2, cvScalar(100));
cvSet1D(&neuralLayers1, 3, cvScalar(1));
//Create our ANN.
machineBrain.create(neuralLayers);
}
// Predict the output with the trained ANN given the two inputs.
float Predict(float data1, float data2,FILE * flog)
{
float _sample[2];
CvMat sample = cvMat(1, 2, CV_32FC1, _sample);
float _predout[1];
CvMat predout = cvMat(1, 1, CV_32FC1, _predout);
sample.data.fl[0] = data1;
sample.data.fl[1] = data2;
machineBrain.predict(&sample, &predout);
if (flog != NULL) {
fprintf(flog,"Predict input\t%f\t%f\tResult\t%f\tError\t%f\n",data1,data2,predout.data.fl[0],abs(abs((data2+data1)/2.0)-abs(predout.data.fl[0])));
}
return predout.data.fl[0];
}
float train_quality (FILE * flog) {
float a,b,summary_error;
summary_error=0;
for (int i = 0 ; i < quality_test; i++) {
a = quality_array[i][0];//int((rand()/float(RAND_MAX))*((int)(Range + 0.001))) + 1; //(rand()%((int)(Range*(parts+over)))) + Range*p + 1;
b = quality_array[i][1];//int((rand()/float(RAND_MAX))*((int)(Range + 0.001))) + 1; //(rand()%((int)(Range*(parts+over)))) + Range*p + 1;
summary_error += abs(abs((a + / 2.0)-abs(Predict(a,b,NULL)));
}
fprintf(flog,"%f\t%f\t%f\tPredict (a, %f\tTrain quality %f\n",a,b,summary_error,Predict(a,b,NULL),summary_error/quality_test );
return summary_error/quality_test;
}
int _tmain(int argc, _TCHAR* argv[])
{
time_t seconds;
seconds = time (NULL);
FILE * flog;
FILE * ftrain;
ftrain= fopen("C:\\train_data.txt", "a+");
fprintf(ftrain,"\nNext training set:\n");
flog = fopen("C:\\train_log.txt", "a+");
time_t rawtime;
struct tm * timeinfo;
float quality=10000;
time ( &rawtime );
timeinfo = localtime ( &rawtime );
fprintf(flog,"\nPredict transaction, date %s \n",asctime (timeinfo) );
srand((unsigned)time(0));
int wait;
createMachine();
generateTrainData (0.1,0.05,ftrain);
// Train the neural network with the samples
for (int i = 0; i < Epoch; i++) {
trainMachine(flog);
quality = train_quality(flog);
}
machineBrain.save("C:\\savednet.txt");
//machineBrain.load("C:\\savednet.txt");
Predict(1.0,8.0,flog);
Predict(2.0,14.0,flog);
Predict(30.0,40.0,flog);
Predict(50.0,54.0,flog);
Predict(50.0,54.0,flog);
seconds = time (NULL) - seconds;
fprintf(flog,"\nTime elapsed %ld sec",seconds );
fflush(flog);
fclose(flog);
//I'll wait for an integer.
scanf("%d",&wait);
fclose(ftrain);
return 0;
}
[/code]
Заранее благодарен за Ваши ответы!