s32 main() { srand((u32)time(0)); //setup data depending on which function will be run //TrainData will contain random values for teaching the network //TestData is for testing the network after it's trained #if A const char *filename = "nn1a.csv"; r32 TrainData[DataPointCount][2]; r32 TestData[DataPointCount][2]; for(u32 i = 0; i < ArrayCount(TrainData); ++i) { TrainData[i][0] = RandomBetween(-1,7); TrainData[i][1] = FunctionProblemOne(TrainData[i][0]); TestData[i][0] = RandomBetween(-1,7); TestData[i][1] = FunctionProblemOne(TrainData[i][0]); } u32 numLayers = 3; u32 lSz[3] = {1,25,1}; #endif #if B const char *filename = "nn2a.csv"; r32 TrainData[DataPointCount][3]; r32 TestData[DataPointCount][3]; for(u32 i = 0; i < ArrayCount(TrainData); ++i) { TrainData[i][0] = RandomBetween(-3,3); TrainData[i][1] = RandomBetween(-3,3); TrainData[i][2] = FunctionProblemTwo(TrainData[i][0], TrainData[i][1]); TestData[i][0] = RandomBetween(-3,3); TestData[i][1] = RandomBetween(-3,3); TestData[i][2] = FunctionProblemTwo(TrainData[i][0], TrainData[i][1]); } u32 numLayers = 4; u32 lSz[4] = {2,25,10,1}; #endif #if C const char *filename = "nn1b.csv"; r32 TrainData[DataPointCount][2]; r32 TestData[DataPointCount][2]; for(u32 i = 0; i < ArrayCount(TrainData); ++i) { TrainData[i][0] = RandomBetween(-1,7); TrainData[i][1] = FunctionProblemOneWithNoise(TrainData[i][0]); TestData[i][0] = RandomBetween(-1,7); TestData[i][1] = FunctionProblemOneWithNoise(TrainData[i][0]); } u32 numLayers = 3; u32 lSz[3] = {1,25,1}; #endif #if D const char *filename = "nn2b.csv"; r32 TrainData[DataPointCount][3]; r32 TestData[DataPointCount][3]; for(u32 i = 0; i < ArrayCount(TrainData); ++i) { TrainData[i][0] = RandomBetween(-3,3); TrainData[i][1] = RandomBetween(-3,3); TrainData[i][2] = FunctionProblemTwoWithNoise(TrainData[i][0], TrainData[i][1]); TestData[i][0] = RandomBetween(-3,3); TestData[i][1] = RandomBetween(-3,3); TestData[i][2] = FunctionProblemTwoWithNoise(TrainData[i][0], TrainData[i][1]); } u32 numLayers = 4; u32 lSz[4] = {2,25,10,1}; #endif //crash if I missed a number change Assert(numLayers == ArrayCount(lSz)); r32 beta = 0.3f, alpha = 0.1f; u32 num_iter = 5000000; CBackProp *bp = new CBackProp(numLayers, lSz, beta, alpha); u32 DataPointSize = lSz[0] + lSz[numLayers - 1]; //iterate up to the max iterations for (u32 IterationIndex = 0; IterationIndex < num_iter; ++IterationIndex) { r32 MeanSquareError = 0; for(u32 DataPointIndex = 0; DataPointIndex < DataPointCount; ++DataPointIndex) { //backpropogate the training data and caluculate the mse r32 *target = &TrainData[DataPointIndex][lSz[0]]; bp->bpgt(TrainData[DataPointIndex], target); MeanSquareError += bp->mse(target); } //if average of MSE over the set of test data is below the threshold, end training MeanSquareError /= DataPointCount; if(MeanSquareError < Thresh) { printf("network trained, MSE: %f\n", MeanSquareError); break; } else { printf("training... MSE: %f\n", MeanSquareError); } } #if 1 //create ofs to create csvs of the data const char *path_prefix = "../data/"; char OutputFilename[80]; strcpy_s(OutputFilename, path_prefix); strcat_s(OutputFilename, filename); char TestDataFilename[80]; strcpy_s(TestDataFilename, path_prefix); strcat_s(TestDataFilename, "test"); strcat_s(TestDataFilename, filename); printf("%s\n%s\n", OutputFilename, TestDataFilename); std::ofstream NetworkOutput, TestDataOutput; NetworkOutput.open(OutputFilename, std::ofstream::out); TestDataOutput.open(TestDataFilename, std::ofstream::out); //iterate through each test data point, feed forward, and save out the results for (u32 i = 0 ; i < DataPointCount ; i++ ) { r32 *DataPoint = TestData[i]; bp->ffwd(DataPoint); r32 output = DataPoint[lSz[0]]; r32 prediction = bp->Out(0); r32 reNormalized = (prediction * 10) - 5; for(u32 InputIndex = 0; InputIndex < lSz[0]; ++InputIndex) { NetworkOutput << DataPoint[InputIndex] << ','; TestDataOutput << DataPoint[InputIndex] << ','; } NetworkOutput << reNormalized << std::endl; TestDataOutput << ((output*10)-5) << std::endl; } #endif NetworkOutput.close(); return 1; }
void TrainBackProp(TRAINING_TYPE type, const std::string& filename) { // defining a net with 4 layers having 3,3,3, and 1 neuron respectively, // the first layer is input layer i.e. simply holder for the input parameters // and has to be the same size as the no of input parameters, in out example 3 int numLayers = 3; int layerSize[3] = {10, 30, 1}; switch (type) { case TRAINING_TYPE_FULL: break; case TRAINING_TYPE_SPEED: layerSize[1] = 30; break; case TRAINING_TYPE_STEER: layerSize[1] = 10; break; case TRAINING_TYPE_GEAR: layerSize[0] = 1; break; default: break; } // Learning rate - beta // momentum - alpha // Threshold - thresh (value of target mse, training stops once it is achieved) double beta = 0.0001, alpha = 0.5, Thresh = 0.2; std::vector<Car*> trainingData; bool success = loadCarData(filename, trainingData); if (!success) throw("Failed"); std::cout << std::endl << "Now training the network...." << std::endl; CBackProp* bp = new CBackProp(numLayers, layerSize, beta, alpha); unsigned int size = trainingData.size(); Car* car = NULL; int counter = 0; int iterations = 0; double error = 0; double percent = 0; bool trained = false; while (!trained) { int nrOfCorrect = 0; int total = 0; auto it_end = trainingData.cend(); for (auto it = trainingData.cbegin(); it != it_end; it++) { int distance = std::distance(trainingData.cbegin(), it); car = (*it); double data[] = { car->speed, car->angle, car->distR, car->distFR, car->distFFR, car->distF, car->distL, car->distFL, car->distFFL, car->clutch}; double outputVal = 0.5; switch (type) { case TRAINING_TYPE_FULL: break; case TRAINING_TYPE_SPEED: if (car->accel > 0.0) outputVal = car->accel; else if(car->brake > 0.0) outputVal = car->brake; outputVal = 0.5 * (outputVal + 1.0); break; case TRAINING_TYPE_STEER: outputVal = 0.5 * (car->steer + 1.0); break; case TRAINING_TYPE_GEAR: outputVal = 0.5 * (car->gear + 1.0); break; default: break; } bp->bpgt(data, &outputVal); } double totalValue = 0.0; for (auto it = trainingData.cbegin(); it != it_end; it++) { int distance = std::distance(trainingData.cbegin(), it); car = (*it); double outputVal = 0.0; if (car->accel > 0.0) outputVal = car->accel; else if(car->brake > 0.0) outputVal = car->brake; double data[] = { car->speed, car->angle, car->distR, car->distFR, car->distFFR, car->distF, car->distL, car->distFL, car->distFFL, car->clutch}; bp->ffwd(data); double net_Out = bp->Out(0); double value = abs(net_Out - outputVal); totalValue += value; if (value < Thresh) nrOfCorrect++; total++; } error = totalValue / trainingData.size(); percent = (double)((double)nrOfCorrect / (double)total); trained = error < Thresh || (1 - percent) < Thresh; counter++; if (trained || counter >= 1000) { iterations += counter; std::cout << std::endl << "Iteration " << iterations << std::endl << "Average Error " << error << std::endl << "Percentage correct "<< percent << std::endl; counter = 0; } } std::cout << std::endl << "Iteration " << iterations << std::endl << "Average Error " << error << std::endl << "Percentage correct "<< percent << std::endl; switch (type) { case TRAINING_TYPE_SPEED: bp->WriteWeights("Bp_Speed.txt"); break; case TRAINING_TYPE_STEER: bp->WriteWeights("Bp_Steer.txt"); break; case TRAINING_TYPE_GEAR: bp->WriteWeights("Bp_Gear.txt"); break; case TRAINING_TYPE_FULL: default: bp->WriteWeights("Bp_Full.txt"); break; } std::cout << "Press Enter to quit" << std::endl; std::cin.ignore(1); }