// TODO: move this constant to some other area or make it derived based on number of training std::vector<float>s void StochasticGradientDescent::RunRef( const std::vector< std::vector<float> > &trainingData, const std::vector<int> &trainingLabels, const std::vector<std::vector<float>> &validationData, const std::vector<int> &validationLabels, unsigned int max_iterations, SkyNetDiagnostic &diagnostic, SkynetTerminalInterface& exitter) { std::uniform_int_distribution< int > sample_index( 0, trainingData.size() -1 ); std::random_device rd; int i=0; bool finish = false; //TODO: Store proper error diagnostic.storeWeightsAndError(m_weights,0.0f,0.0f); while((i<max_iterations)&&(finish == false)) { auto ridx = sample_index(rd); finish = updateWeights(trainingData[ridx],trainingLabels[ridx]); //TODO: Store proper error diagnostic.storeWeightsAndError(m_weights,0.0f, 0.0f); // Check if user want to cease learning finish = finish || exitter(); if(finish == false) { ++i; } else { // TODO: If flatness was reached then // check if error is below certain error threshold } } if(finish == false) { printf("Warning: Stochastic Gradient Descent Learning alogorithm exhusted all iterations. TODO: Make proper termination criteria\n"); } return; }
bool NeuralGas::trainOneEpoch(const std::vector<std::shared_ptr<wv::Point>>& points, double epsilon) { //create vector with order of iterating by points std::vector<uint32_t> order; for (uint32_t i = 0; i < points.size(); i++) order.push_back(i); std::random_shuffle(order.begin(), order.end()); uint32_t iteration = 1; alr::AdaptLearnRateNeuralGas alrn(0, m_AdaptLearnRateWinner, m_AdaptLearnRateNotWinner); double error_before = getErrorOnNeuron(); for (uint32_t i = 0; i < order.size(); i++) { findWinners(points[order[i]].get()); updateWeights(points[order[i]].get(), &alrn); incrementEdgeAgeFromWinner(); updateEdgeWinSecWin(); deleteOldEdges(); if (iteration % m_Lambda == 0) { insertNode(); } decreaseAllErrors(); iteration++; } double error_after = getErrorOnNeuron(); log_netw->info((boost::format("Error before %g. Error after %g") % error_before % error_after).str()); log_netw->info((boost::format("Network size: %d neurons") % m_Neurons.size()).str()); return (error_before - getErrorOnNeuron() > epsilon); }
void trainNetwork(DATASET *trainData, float *weightsFromInputToHidden,float *weightsFromHiddenToOutput,float *biasesOfHidden,float *biasesOfOutput, int INPUTLAYERNODES, int HIDDENLAYERNODES, int OUTPUTLAYERNODES){ for (int epoch = 0; epoch < EPOCHS; epoch++){ float error = 0; for(int train = 0; train < DATATOREAD; train++){ float input[INPUTLAYERNODES]; float hidden[HIDDENLAYERNODES]; float output[OUTPUTLAYERNODES]; float target[OUTPUTLAYERNODES]; for(int j = 0; j < OUTPUTLAYERNODES; j++){ if(trainData[train].value[7] == j){ target[j] = 1; }else{ target[j] = 0; } } feedForward(input, hidden, output, trainData, train, weightsFromInputToHidden, weightsFromHiddenToOutput, biasesOfHidden, biasesOfOutput, INPUTLAYERNODES, HIDDENLAYERNODES, OUTPUTLAYERNODES); for(int i = 0; i < OUTPUTLAYERNODES; i++){ error += pow(target[i] - sigmoid(output[i]),2); } float deltaHidden[HIDDENLAYERNODES]; float deltaOutput[OUTPUTLAYERNODES]; backPropagateError(input, hidden, output, target, deltaHidden, deltaOutput, weightsFromHiddenToOutput, HIDDENLAYERNODES, OUTPUTLAYERNODES); updateWeights(input, hidden, deltaHidden, deltaOutput,weightsFromInputToHidden, weightsFromHiddenToOutput, biasesOfHidden, biasesOfOutput, INPUTLAYERNODES, HIDDENLAYERNODES, OUTPUTLAYERNODES); } printf("EPOCH %i | error = %f\n",epoch, error); //int q = evaulate(trainData, weightsFromInputToHidden, weightsFromHiddenToOutput, biasesOfHidden, biasesOfOutput, INPUTLAYERNODES, HIDDENLAYERNODES, OUTPUTLAYERNODES); printf("Epoch %i: %i\n", epoch, DATATOREAD); } }
//return true if we need to continue training, false - otherwise bool KohonenNN::trainOneEpoch(const std::vector<std::shared_ptr<wv::Point>>& points, double epsilon) { //Erase offset vector for (uint32_t i = 0; i < m_NumClusters; i++) m_Neurons.at(i).getWv()->eraseOffset(); alr::AdaptLearnRateKohonenSchema alrks(m_IterNumber, m_Kp); //make iteration for (const auto p: points) { findWinner(p.get()); updateWeights(p.get(), &alrks); } //check offset value double summary_offset_value = 0; for (uint32_t i = 0; i < m_NumClusters; i++) { summary_offset_value += m_Neurons.at(i).getWv()->getOffsetValue(); } log_netw->info(" --------------------------------------------------------------------"); log_netw->info((boost::format("After %d iteration") % m_IterNumber).str()); log_netw->info((boost::format("Summary offset value = %g") % summary_offset_value).str()); for (uint32_t i = 0; i < m_NumClusters; i++) { for (uint32_t j = 0; j < m_NumDimensions; j++) log_netw->info((boost::format("%g,") % m_Neurons.at(i).getWv()->getConcreteCoord(j)).str(), true); log_netw->info("\n", true); } m_IterNumber++; return (summary_offset_value / m_NumClusters > epsilon); }
int trainNet(NeuralNetwork* net, Sample* samples, unsigned int numberOfSamples, unsigned int epochs, unsigned int batchSize, double learningRate) { unsigned int epoch = 0, startIndex, i, currentBatchSize; if(!samples || epochs < 1 || batchSize < 1 || batchSize > numberOfSamples || learningRate <= 0.0 || !isValidNet(net)) { return -2; } while(epoch < epochs) { shuffleSamples(samples, numberOfSamples); startIndex = 0; //while there are still mini batches while(startIndex < numberOfSamples) { currentBatchSize = fmin(numberOfSamples - startIndex, batchSize); printf("epoch: %d, currentBatchSize: %d\n", epoch, currentBatchSize); initializeDeltas(net); for(i = 0; i < currentBatchSize; i++) { //feedForward feedForward(net, samples[startIndex + i].inputs); //update deltas updateDeltas(net, samples[startIndex + i].outputs); } updateWeights(net, learningRate/(double)currentBatchSize); startIndex += currentBatchSize; } epoch++; } return 0; }
void train(Matrix sampleInputs, Matrix targetOutputs){ for(int i = 0; i < sampleInputs.size(); i++){ inputs = sampleInputs[i]; outputs = computeOutputs(sampleInputs[i]); updateWeights(targetOutputs[i], 0.5, 0.3); } }
float MultilayerNN::trainOne(vector<float> tuple) { float error; // Set up topography & randomize weights if first run if (!topoSet) { setTopo(tuple); } // Set previous weights if size = 0 //if (previousWeights.size() == 0) previousWeights = weights; // Set input nodes to training tuple values for (int i = 0; i < inputNodes.size(); i++) { inputNodes.at(i) = tuple.at(i); } // FIRST PASS: Feed forward through network feedForward(); // SECOND PASS: Calculate error, propagate deltas back through network given desired output error = addErrorForIteration(tuple.back()); backProp(tuple.back()); // THIRD PASS: Update weights updateWeights(); return error; }
void GRBM<VIS_DIM, HID_DIM>::train_epoch(const std::vector<VisVType, Eigen::aligned_allocator<VisVType> > &train_data) { int numMinibatches = (train_data.size() + minibatchSize - 1) / minibatchSize; double batchError = 0; VisVType currentVis = train_data[0]; std::vector < std::pair<VisVType, HidVType>, Eigen::aligned_allocator< std::pair<VisVType, HidVType> > > cd_data_pos; std::vector < std::pair<VisVType, HidVType>, Eigen::aligned_allocator< std::pair<VisVType, HidVType> > > cd_data_neg; //std::vector < std::pair<VisVType, HidVType>, Eigen::aligned_allocator< std::pair<VisVtype, HidVtype> > > cd_data_pos; //std::vector < std::pair<VisVType, HidVType>, Eigen::aligned_allocator< std::pair<VisVtype, HidVtype> > > cd_data_neg; //cd_data.resize(minibatchSize); for (int b = 0; b < numMinibatches; b++) { int miniStart = b * minibatchSize; int miniEnd = std::min(int(train_data.size()), (b + 1) * minibatchSize); for (int i = miniStart; i < miniEnd; ++i) { const VisVType &input = train_data[i]; // ***** POSITIVE PHASE ***** computeHiddenProb(input); // enqueue to positive examples cd_data_pos.push_back(make_pair(input, hiddenProb)); // ***** NEGATIVE PHASE ***** // PCD if (numCD == 0) { computeHiddenProb(currentVis); } // contrastive divergence for (int c = 0; c < numCD; c++) { computeVisibleProb(); computeHiddenProb(visibleProb); //computeHiddenProb(currentVis); } // enqueue to negative examples cd_data_neg.push_back(make_pair(visibleProb, hiddenProb)); } // compute cd correlations & gradients for positive and negative phase computeCDPositive( cd_data_pos); computeCDNegative( cd_data_neg); // update weights updateWeights(); // for PCD we want to compute the visible activation from the // current hidden activation here if (numCD == 0) computeVisibleProb(); // and reset cd_data cd_data_pos.clear(); cd_data_neg.clear(); } }
float FCNetwork::trainEpochs(const Samples &samples, unsigned int epochs) { for (int i = 0; i < epochs - 1; ++i) { // Without calculating error for (const Sample& sample : samples) { activate(sample.getInputs()); updateDeltas(sample); updateWeights(); } } // Calculating error float sum = 0; for (const Sample& sample : samples) { activate(sample.getInputs()); updateDeltas(sample); updateWeights(); sum = squaredError(sample.getOutputs()); } return sum / samples.size(); }
Move *Player::doMove(Move *opponentsMove, int msLeft) { /* * TODO: Implement how moves your AI should play here. You should first * process the opponent's opponents move before calculating your own move */ Side opside; if (side == BLACK) { opside = WHITE; } else { opside = BLACK; } board.doMove(opponentsMove, opside); updateWeights(opponentsMove); if(board.hasMoves(side)) { std::vector<Move*> moves = possibleMoves(); int max_index = 0; //index of the move whose square has the highest known heuristic value for (unsigned i = 0; i < moves.size(); i++) { if (getSquareWeight(moves[i]) > getSquareWeight(moves[max_index])) { max_index = i; } } board.doMove(moves[max_index], side); updateWeights(moves[max_index]); return moves[max_index]; } else { return NULL; } }
void update(Array in, int reward){ if(reward > 0 && random(5) % 2 == 0){ trainingInputs.push_back(inputs); trainingOutputs.push_back(outputs); updateWeights(outputs, 0.5, 0.3); } if(trainingInputs.size() > 300){ trainingInputs.erase(trainingInputs.begin()); trainingOutputs.erase(trainingOutputs.begin()); } inputs = in; outputs = computeOutputs(inputs); }
static void updateWeights_test( void ) { float weights[2][3] = {{0.25, 0.5, 0.25}, {-0.75, 0.25, -0.75}}; Node inputNodes[2] = {{NULL, 1}, {NULL, -1}}; Node currentNodes[2] = {{weights[0], 0, 2, 0.5}, {weights[1], 0, -2, 0.25}}; Layer inputLayer = {inputNodes, 2}; Layer currentLayer = {currentNodes, 2}; updateWeights( &inputLayer, ¤tLayer ); assert( fabs( 0.2676627 - currentLayer.nodes[0].weights[0] ) < 0.001 && "Weight 0, 0 is not as expected" ); assert( fabs( 0.4823373 - currentLayer.nodes[0].weights[1] ) < 0.001 && "Weight 0, 1 is not as expected" ); assert( fabs( 0.2676627 - currentLayer.nodes[0].weights[2] ) < 0.001 && "Weight 0, 2 is not as expected" ); assert( fabs( -0.741169 - currentLayer.nodes[1].weights[0] ) < 0.001 && "Weight 1, 0 is not as expected" ); assert( fabs( 0.2411686 - currentLayer.nodes[1].weights[1] ) < 0.001 && "Weight 1, 1 is not as expected" ); assert( fabs( -0.741169 - currentLayer.nodes[1].weights[2] ) < 0.001 && "Weight 1, 2 is not as expected" ); }
void CGradientUpdateFunction::updateGradient(CFeatureList *gradientFeatures, double factor) { if (gradientFeatures != this->localGradientFeatureBuffer) { DebugPrint('g', "1..."); this->localGradientFeatureBuffer->clear(); CFeatureList::iterator it1 = gradientFeatures->begin(); for (; it1 != gradientFeatures->end(); it1 ++) { this->localGradientFeatureBuffer->update((*it1)->featureIndex, factor * (*it1)->factor); DebugPrint('g', "%d : %f %f \n", (*it1)->featureIndex, (*it1)->factor, factor); } if (DebugIsEnabled('g')) { DebugPrint('g', "localGradientFeatures: "); localGradientFeatureBuffer->saveASCII(DebugGetFileHandle('g')); } } else { localGradientFeatureBuffer->multFactor(factor); DebugPrint('g', "2..."); } if (etaCalc) { etaCalc->getWeightUpdates(this->localGradientFeatureBuffer); DebugPrint('g', "3..."); } if (DebugIsEnabled('g')) { DebugPrint('g', "gradientFeatures: "); gradientFeatures->saveASCII(DebugGetFileHandle('g')); DebugPrint('g', "localGradientFeatures: "); localGradientFeatureBuffer->saveASCII(DebugGetFileHandle('g')); } updateWeights(this->localGradientFeatureBuffer); }
/** * First function to be executed * Updates the postsynaptic trace and calls the updateWeights function */ int STDP3Conn::updateState(double time, double dt) { update_timer->start(); int status=0; if (stdpFlag) { //const int axonId = 0; // assume only one for now for(int axonId = 0; axonId<numberOfAxonalArborLists(); axonId++) { status=updateWeights(axonId); } } update_timer->stop(); //const int axonId = 0; // assume only one for now //return updateWeights(axonId); return status; }
estimates_t EM(const estimates_t& initial, const dataPoints_t& X, unsigned int maxIterations, Progress *progress) { // This will be used for probabilites calculation at each step prob_matrix_t prob; // Number of classes const unsigned int classes = initial.size(); // Sum of probabilites of all classes std::vector<double> sums(classes, 0); for(unsigned int i = 0; i < classes + 1; ++i) { prob.push_back(std::vector<double>()); std::vector<double>& ps = prob.back(); ps.resize(X.size()); } // Estimates after each iteration estimates_t next = initial; for(unsigned int iteration = 1; iteration <= maxIterations; ++iteration) { if (progress != NULL) { progress->updateProgress("EM running on difference image", 100*iteration/maxIterations, NORMAL); } std::fill(sums.begin(), sums.end(), 0.0); computeProbabilities(prob, sums, X, next); estimates_t::iterator estimateItr = next.begin(); estimates_t::const_iterator prev_estimateItr = next.begin(); std::vector<double>::const_iterator sumItr = sums.begin(); prob_matrix_t::const_iterator probItr = prob.begin(); // M-step for(; estimateItr != next.end(); ++estimateItr, ++sumItr, ++probItr, ++prev_estimateItr) { updateStdDevs(*estimateItr, *sumItr, *probItr, X, *prev_estimateItr); updateMeans(*estimateItr, *sumItr, *probItr, X); updateWeights(*estimateItr, *sumItr, X.size()); } } estimates_t final = next; return final; }
void processNewData(const vector<Mat>& image_data, void* extra_data ) { if( particles_estm.empty() ) { initPFCore(); } // register the data with TrackingProblem tracking_problem->registerCurrentData( image_data, extra_data); // compute \hat{x}_k | x_{k-1}, possible depends on z_k (non-SIR case) tracking_problem->sampleNewParticles( particles_estm, particles_pred ); // compute p(z_k | \hat{x}_k ) tracking_problem->evaluateLikelihood( particles_pred, likelihood); // compute w_k \prop w_{k-1} * p(z_k | \hat{x}_k ) p( \hat{x}_k | x_{k-1} ) updateWeights(); // modifies weights // re-sample to get rid of negligible weight particles resampleParticles(); // particles_pred -> particles_estm // display callback on the TrackingProblem with current x_k tracking_problem->outputCallback( particles_estm, weights ); }
void RAE::training() { x = lbfgs_malloc(getRAEWeightSize()); Map<MatrixLBFGS>(x, getRAEWeightSize(), 1).setRandom(); lbfgs_parameter_t param; iterTimes = atoi(para->getPara("IterationTime").c_str()); loadTrainingData(); lbfgs_parameter_init(¶m); param.max_iterations = iterTimes; lbfgsfloatval_t fx = 0; int ret; ret = lbfgs(getRAEWeightSize(), x, &fx, RAELBFGS::evaluate, RAELBFGS::progress, this, ¶m); cout << "L-BFGS optimization terminated with status code = " << ret << endl; cout << " fx = " << fx << endl; updateWeights(x); logWeights(para); trainingData.clear(); lbfgs_free(x); }
// step overwrite for ICO void ICO::step(){ updateActivities(); updateOutputs(); updateWeights(); }
// Actual allocation is done by an instance of real allocator, // which is specified by the template parameter. TestAllocator() : real(createAllocator<T>()) { // We use 'ON_CALL' and 'WillByDefault' here to specify the // default actions (call in to the real allocator). This allows // the tests to leverage the 'DoDefault' action. // However, 'ON_CALL' results in a "Uninteresting mock function // call" warning unless each test puts expectations in place. // As a result, we also use 'EXPECT_CALL' and 'WillRepeatedly' // to get the best of both worlds: the ability to use 'DoDefault' // and no warnings when expectations are not explicit. ON_CALL(*this, initialize(_, _, _)) .WillByDefault(InvokeInitialize(this)); EXPECT_CALL(*this, initialize(_, _, _)) .WillRepeatedly(DoDefault()); ON_CALL(*this, recover(_, _)) .WillByDefault(InvokeRecover(this)); EXPECT_CALL(*this, recover(_, _)) .WillRepeatedly(DoDefault()); ON_CALL(*this, addFramework(_, _, _, _, _)) .WillByDefault(InvokeAddFramework(this)); EXPECT_CALL(*this, addFramework(_, _, _, _, _)) .WillRepeatedly(DoDefault()); ON_CALL(*this, removeFramework(_)) .WillByDefault(InvokeRemoveFramework(this)); EXPECT_CALL(*this, removeFramework(_)) .WillRepeatedly(DoDefault()); ON_CALL(*this, activateFramework(_)) .WillByDefault(InvokeActivateFramework(this)); EXPECT_CALL(*this, activateFramework(_)) .WillRepeatedly(DoDefault()); ON_CALL(*this, deactivateFramework(_)) .WillByDefault(InvokeDeactivateFramework(this)); EXPECT_CALL(*this, deactivateFramework(_)) .WillRepeatedly(DoDefault()); ON_CALL(*this, updateFramework(_, _, _)) .WillByDefault(InvokeUpdateFramework(this)); EXPECT_CALL(*this, updateFramework(_, _, _)) .WillRepeatedly(DoDefault()); ON_CALL(*this, addSlave(_, _, _, _, _, _)) .WillByDefault(InvokeAddSlave(this)); EXPECT_CALL(*this, addSlave(_, _, _, _, _, _)) .WillRepeatedly(DoDefault()); ON_CALL(*this, removeSlave(_)) .WillByDefault(InvokeRemoveSlave(this)); EXPECT_CALL(*this, removeSlave(_)) .WillRepeatedly(DoDefault()); ON_CALL(*this, updateSlave(_, _, _, _)) .WillByDefault(InvokeUpdateSlave(this)); EXPECT_CALL(*this, updateSlave(_, _, _, _)) .WillRepeatedly(DoDefault()); ON_CALL(*this, addResourceProvider(_, _, _)) .WillByDefault(InvokeAddResourceProvider(this)); EXPECT_CALL(*this, addResourceProvider(_, _, _)) .WillRepeatedly(DoDefault()); ON_CALL(*this, activateSlave(_)) .WillByDefault(InvokeActivateSlave(this)); EXPECT_CALL(*this, activateSlave(_)) .WillRepeatedly(DoDefault()); ON_CALL(*this, deactivateSlave(_)) .WillByDefault(InvokeDeactivateSlave(this)); EXPECT_CALL(*this, deactivateSlave(_)) .WillRepeatedly(DoDefault()); ON_CALL(*this, updateWhitelist(_)) .WillByDefault(InvokeUpdateWhitelist(this)); EXPECT_CALL(*this, updateWhitelist(_)) .WillRepeatedly(DoDefault()); ON_CALL(*this, requestResources(_, _)) .WillByDefault(InvokeRequestResources(this)); EXPECT_CALL(*this, requestResources(_, _)) .WillRepeatedly(DoDefault()); ON_CALL(*this, updateAllocation(_, _, _, _)) .WillByDefault(InvokeUpdateAllocation(this)); EXPECT_CALL(*this, updateAllocation(_, _, _, _)) .WillRepeatedly(DoDefault()); ON_CALL(*this, updateAvailable(_, _)) .WillByDefault(InvokeUpdateAvailable(this)); EXPECT_CALL(*this, updateAvailable(_, _)) .WillRepeatedly(DoDefault()); ON_CALL(*this, updateUnavailability(_, _)) .WillByDefault(InvokeUpdateUnavailability(this)); EXPECT_CALL(*this, updateUnavailability(_, _)) .WillRepeatedly(DoDefault()); ON_CALL(*this, updateInverseOffer(_, _, _, _, _)) .WillByDefault(InvokeUpdateInverseOffer(this)); EXPECT_CALL(*this, updateInverseOffer(_, _, _, _, _)) .WillRepeatedly(DoDefault()); ON_CALL(*this, getInverseOfferStatuses()) .WillByDefault(InvokeGetInverseOfferStatuses(this)); EXPECT_CALL(*this, getInverseOfferStatuses()) .WillRepeatedly(DoDefault()); ON_CALL(*this, recoverResources(_, _, _, _)) .WillByDefault(InvokeRecoverResources(this)); EXPECT_CALL(*this, recoverResources(_, _, _, _)) .WillRepeatedly(DoDefault()); ON_CALL(*this, suppressOffers(_, _)) .WillByDefault(InvokeSuppressOffers(this)); EXPECT_CALL(*this, suppressOffers(_, _)) .WillRepeatedly(DoDefault()); ON_CALL(*this, reviveOffers(_, _)) .WillByDefault(InvokeReviveOffers(this)); EXPECT_CALL(*this, reviveOffers(_, _)) .WillRepeatedly(DoDefault()); ON_CALL(*this, setQuota(_, _)) .WillByDefault(InvokeSetQuota(this)); EXPECT_CALL(*this, setQuota(_, _)) .WillRepeatedly(DoDefault()); ON_CALL(*this, removeQuota(_)) .WillByDefault(InvokeRemoveQuota(this)); EXPECT_CALL(*this, removeQuota(_)) .WillRepeatedly(DoDefault()); ON_CALL(*this, updateWeights(_)) .WillByDefault(InvokeUpdateWeights(this)); EXPECT_CALL(*this, updateWeights(_)) .WillRepeatedly(DoDefault()); ON_CALL(*this, pause()) .WillByDefault(InvokePause(this)); EXPECT_CALL(*this, pause()) .WillRepeatedly(DoDefault()); ON_CALL(*this, resume()) .WillByDefault(InvokeResume(this)); EXPECT_CALL(*this, resume()) .WillRepeatedly(DoDefault()); }
int main() { srand(time(NULL)); Neuron neuron; initWeights(&neuron); neuron.eta = 0.5; FILE* file; file = fopen("C:\\Users\\Michael\\Source\\Repos\\Computational_Intelligence\\exercise_2\\testInput10A.txt", "r"); if (file == NULL) return EXIT_FAILURE; //read training data ("x1,x2,t") char line[60]; double trainingData[1000][DIM]; double testData[1000][N]; int i = 0; int trainingDataSize = 0; int testDataSize = 0; int trainingParsed = 0; while (1) { if (trainingParsed != 1 && fgets(line, 60, file)) { //fgets returns NULL at EOF (EOF in VS cmd line: enter ctrl+z enter) if (strcmp(line, "0,0,0\n") == 0) { trainingParsed = 1; i = 0; } else { memcpy(trainingData[i], parseTrainingInputLine(&line), DIM*sizeof(double)); trainingDataSize++; i++; } } else if (fgets(line, 60, file) && trainingParsed == 1) { memcpy(testData[i], parseTestInputLine(&line), (DIM-1)*sizeof(double)); testDataSize++; i++; } else break; } int trainingCycles = 0; double MSE = 1; double eSum = 0; while (MSE > 0.0001) { for (int j = 0; j < trainingDataSize; j++) { eSum += pow(updateWeights(&neuron, trainingData[j]), 2); //squared error } MSE = eSum * (0.5 / (NUM_NEURONS*trainingDataSize)); //mean square error (see BILHR doc by Peer) printf("MSE: %f\n", MSE); //printNeuron(&neuron); eSum = 0; trainingCycles++; } //read test data ("x1,x2") //neuron.w[0] = 0.2; for (int i = 0; i <= testDataSize; i++) { double res = activate(&neuron, testData[i]); if(res == 1) printf("+%f\n", res); else printf("%f\n", res); } return EXIT_SUCCESS; }
void AdaBoostMHLearner::run(const nor_utils::Args& args) { // load the arguments this->getArgs(args); // get the registered weak learner (type from name) BaseLearner* pWeakHypothesisSource = BaseLearner::RegisteredLearners().getLearner(_baseLearnerName); // initialize learning options; normally it's done in the strong loop // also, here we do it for Product learners, so input data can be created pWeakHypothesisSource->initLearningOptions(args); BaseLearner* pConstantWeakHypothesisSource = BaseLearner::RegisteredLearners().getLearner("ConstantLearner"); // get the training input data, and load it InputData* pTrainingData = pWeakHypothesisSource->createInputData(); pTrainingData->initOptions(args); pTrainingData->load(_trainFileName, IT_TRAIN, _verbose); // get the testing input data, and load it InputData* pTestData = NULL; if ( !_testFileName.empty() ) { pTestData = pWeakHypothesisSource->createInputData(); pTestData->initOptions(args); pTestData->load(_testFileName, IT_TEST, _verbose); } // The output information object OutputInfo* pOutInfo = NULL; if ( !_outputInfoFile.empty() ) { // Baseline: constant classifier - goes into 0th iteration BaseLearner* pConstantWeakHypothesis = pConstantWeakHypothesisSource->create() ; pConstantWeakHypothesis->initLearningOptions(args); pConstantWeakHypothesis->setTrainingData(pTrainingData); AlphaReal constantEnergy = pConstantWeakHypothesis->run(); //pOutInfo = new OutputInfo(_outputInfoFile); pOutInfo = new OutputInfo(args); pOutInfo->initialize(pTrainingData); if (pTestData) pOutInfo->initialize(pTestData); pOutInfo->outputHeader(pTrainingData->getClassMap()); pOutInfo->outputIteration(-1); pOutInfo->outputCustom(pTrainingData, pConstantWeakHypothesis); if (pTestData != NULL) { pOutInfo->separator(); pOutInfo->outputCustom(pTestData, pConstantWeakHypothesis); } pOutInfo->outputCurrentTime(); pOutInfo->endLine(); pOutInfo->initialize(pTrainingData); if (pTestData) pOutInfo->initialize(pTestData); } //cout << "Before serialization" << endl; // reload the previously found weak learners if -resume is set. // otherwise just return 0 int startingIteration = resumeWeakLearners(pTrainingData); Serialization ss(_shypFileName, _isShypCompressed ); ss.writeHeader(_baseLearnerName); // this must go after resumeProcess has been called // perform the resuming if necessary. If not it will just return resumeProcess(ss, pTrainingData, pTestData, pOutInfo); if (_verbose == 1) cout << "Learning in progress..." << endl; //I put here the starting time, but it may take very long time to load the saved model time_t startTime, currentTime; time(&startTime); /////////////////////////////////////////////////////////////////////// // Starting the AdaBoost main loop /////////////////////////////////////////////////////////////////////// for (int t = startingIteration; t < _numIterations; ++t) { if (_verbose > 1) cout << "------- WORKING ON ITERATION " << (t+1) << " -------" << endl; BaseLearner* pWeakHypothesis = pWeakHypothesisSource->create(); pWeakHypothesis->initLearningOptions(args); //pTrainingData->clearIndexSet(); pWeakHypothesis->setTrainingData(pTrainingData); AlphaReal energy = pWeakHypothesis->run(); //float gamma = pWeakHypothesis->getEdge(); //cout << gamma << endl; if ( (_withConstantLearner) || ( energy != energy ) ) // check constant learner if user wants it (if energi is nan, then we chose constant learner { BaseLearner* pConstantWeakHypothesis = pConstantWeakHypothesisSource->create() ; pConstantWeakHypothesis->initLearningOptions(args); pConstantWeakHypothesis->setTrainingData(pTrainingData); AlphaReal constantEnergy = pConstantWeakHypothesis->run(); if ( (constantEnergy <= energy) || ( energy != energy ) ) { delete pWeakHypothesis; pWeakHypothesis = pConstantWeakHypothesis; } } if (_verbose > 1) cout << "Weak learner: " << pWeakHypothesis->getName()<< endl; // Output the step-by-step information printOutputInfo(pOutInfo, t, pTrainingData, pTestData, pWeakHypothesis); // Updates the weights and returns the edge AlphaReal gamma = updateWeights(pTrainingData, pWeakHypothesis); if (_verbose > 1) { cout << setprecision(5) << "--> Alpha = " << pWeakHypothesis->getAlpha() << endl << "--> Edge = " << gamma << endl << "--> Energy = " << energy << endl // << "--> ConstantEnergy = " << constantEnergy << endl // << "--> difference = " << (energy - constantEnergy) << endl ; } // If gamma <= theta the algorithm must stop. // If theta == 0 and gamma is 0, it means that the weak learner is no better than chance // and no further training is possible. if (gamma <= _theta) { if (_verbose > 0) { cout << "Can't train any further: edge = " << gamma << " (with and edge offset (theta)=" << _theta << ")" << endl; } // delete pWeakHypothesis; // break; } // append the current weak learner to strong hypothesis file, // that is, serialize it. ss.appendHypothesis(t, pWeakHypothesis); // Add it to the internal list of weak hypotheses _foundHypotheses.push_back(pWeakHypothesis); // check if the time limit has been reached if (_maxTime > 0) { time( ¤tTime ); float diff = difftime(currentTime, startTime); // difftime is in seconds diff /= 60; // = minutes if (diff > _maxTime) { if (_verbose > 0) cout << "Time limit of " << _maxTime << " minutes has been reached!" << endl; break; } } // check for maxtime delete pWeakHypothesis; } // loop on iterations ///////////////////////////////////////////////////////// // write the footer of the strong hypothesis file ss.writeFooter(); // write the weights of the instances if the name of weights file isn't empty printOutWeights( pTrainingData ); // Free the two input data objects if (pTrainingData) delete pTrainingData; if (pTestData) delete pTestData; if (pOutInfo) delete pOutInfo; if (_verbose > 0) cout << "Learning completed." << endl; }
//updateAll void GraphHandler::updateAll(vector<vector<unsigned int>> &clustering, vector<unsigned int> &medians){ updateWeights(clustering, medians); updateEdges(); };
void AdaBoostMHLearner::resumeProcess(Serialization& ss, InputData* pTrainingData, InputData* pTestData, OutputInfo* pOutInfo) { if (_resumeShypFileName.empty()) return; vector<BaseLearner*>::iterator it; int t; // rebuild the new strong hypothesis file for (it = _foundHypotheses.begin(), t = 0; it != _foundHypotheses.end(); ++it, ++t) { BaseLearner* pWeakHypothesis = *it; // append the current weak learner to strong hypothesis file, ss.appendHypothesis(t, pWeakHypothesis); } if ( _fastResumeProcess ) { // The AdaBost will recalculate of the last iteration based on the margins // Updates the weights if (_verbose > 0) cout << "Recalculating the weights of training data..."; updateWeights(pOutInfo, pTrainingData, _foundHypotheses); if (_verbose > 0) cout << "Done" << endl; if (pTestData) { if (_verbose > 0) cout << "Recalculating the weights of test data..."; updateWeights(pOutInfo, pTestData, _foundHypotheses); } if (_verbose > 0) cout << "Done" << endl; // Output the step-by-step information //printOutputInfo(pOutInfo, _foundHypotheses.size(), pTrainingData, pTestData, pWeakHypothesis); } else { //slow resume process, in this case the AdaBoost will recalculate the error rates of all iterations const int numIters = static_cast<int>(_foundHypotheses.size()); const int step = numIters < 5 ? 1 : numIters / 5; if (_verbose > 0) cout << "Resuming up to iteration " << _foundHypotheses.size() - 1 << ": 0%." << flush; // simulate the AdaBoost algorithm for the weak learners already found for (it = _foundHypotheses.begin(), t = 0; it != _foundHypotheses.end(); ++it, ++t) { BaseLearner* pWeakHypothesis = *it; // Output the step-by-step information printOutputInfo(pOutInfo, t, pTrainingData, pTestData, pWeakHypothesis); // Updates the weights and returns the edge AlphaReal gamma = updateWeights(pTrainingData, pWeakHypothesis); if (_verbose > 1 && (t + 1) % step == 0) { float progress = static_cast<float>(t) / static_cast<float>(numIters) * 100.0; cout << "." << setprecision(2) << progress << "%." << flush; } // If gamma <= theta there is something really wrong. if (gamma <= _theta) { cerr << "ERROR!" << setprecision(4) << endl << "At iteration <" << t << ">, edge smaller than the edge offset (theta). Something must be wrong!" << endl << "[Edge: " << gamma << " < Offset: " << _theta << "]" << endl << "Is the data file the same one used during the original training?" << endl; // exit(1); } } // loop on iterations } if (_verbose > 0) cout << "Done!" << endl; }
// ------------------------------------------------------------------------- void AdaBoostMHLearner::run( const nor_utils::Args& args, InputData* pTrainingData, const string baseLearnerName, const int numIterations, vector<BaseLearner*>& foundHypotheses ) { // get the registered weak learner (type from name) BaseLearner* pWeakHypothesisSource = BaseLearner::RegisteredLearners().getLearner(baseLearnerName); // initialize learning options; normally it's done in the strong loop // also, here we do it for Product learners, so input data can be created pWeakHypothesisSource->initLearningOptions(args); BaseLearner* pConstantWeakHypothesisSource = BaseLearner::RegisteredLearners().getLearner("ConstantLearner"); if (_verbose == 1) cout << "Learning in progress..." << endl; /////////////////////////////////////////////////////////////////////// // Starting the AdaBoost main loop /////////////////////////////////////////////////////////////////////// for (int t = 0; t < numIterations; ++t) { if ((_verbose > 0)&&((t%100)==0)) cout << "--------------[ Boosting iteration " << (t+1) << " ]--------------" << endl; BaseLearner* pWeakHypothesis = pWeakHypothesisSource->create(); pWeakHypothesis->initLearningOptions(args); //pTrainingData->clearIndexSet(); pWeakHypothesis->setTrainingData(pTrainingData); AlphaReal energy = pWeakHypothesis->run(); //float gamma = pWeakHypothesis->getEdge(); //cout << gamma << endl; if ( (_withConstantLearner) || ( energy != energy ) ) // check constant learner if user wants it (if energi is nan, then we chose constant learner { BaseLearner* pConstantWeakHypothesis = pConstantWeakHypothesisSource->create() ; pConstantWeakHypothesis->initLearningOptions(args); pConstantWeakHypothesis->setTrainingData(pTrainingData); AlphaReal constantEnergy = pConstantWeakHypothesis->run(); if ( (constantEnergy <= energy) || ( energy != energy ) ) { delete pWeakHypothesis; pWeakHypothesis = pConstantWeakHypothesis; } } if (_verbose > 1) cout << "Weak learner: " << pWeakHypothesis->getName()<< endl; // Updates the weights and returns the edge AlphaReal gamma = updateWeights(pTrainingData, pWeakHypothesis); if (_verbose > 1) { cout << setprecision(5) << "--> Alpha = " << pWeakHypothesis->getAlpha() << endl << "--> Edge = " << gamma << endl << "--> Energy = " << energy << endl // << "--> ConstantEnergy = " << constantEnergy << endl // << "--> difference = " << (energy - constantEnergy) << endl ; } // If gamma <= theta the algorithm must stop. // If theta == 0 and gamma is 0, it means that the weak learner is no better than chance // and no further training is possible. if (gamma <= _theta) { if (_verbose > 0) { cout << "Can't train any further: edge = " << gamma << " (with and edge offset (theta)=" << _theta << ")" << endl; } // delete pWeakHypothesis; // break; } // Add it to the internal list of weak hypotheses foundHypotheses.push_back(pWeakHypothesis); } // loop on iterations ///////////////////////////////////////////////////////// if (_verbose > 0) cout << "--------------[ AdaBoost Learning completed. ]--------------" << endl; }
double * step(Dataset * d,Perceptron * p,double alpha){ double * y=currentOutput(d,p); updateWeights(d,p,y,alpha); return y; }
void Layer::updateWeights(double **deltas) { updateWeights(deltas, 0); }
void TrueOnlineSarsaLearner::learnPolicy(ALEInterface& ale, Features *features){ struct timeval tvBegin, tvEnd, tvDiff; vector<double> reward; double elapsedTime; double norm_a; double q_old, delta_q; double cumReward = 0, prevCumReward = 0; unsigned int maxFeatVectorNorm = 1; sawFirstReward = 0; firstReward = 1.0; //Repeat (for each episode): for(int episode = 0; episode < numEpisodesLearn; episode++){ for(unsigned int a = 0; a < nonZeroElig.size(); a++){ for(unsigned int i = 0; i < nonZeroElig[a].size(); i++){ int idx = nonZeroElig[a][i]; e[a][idx] = 0.0; } nonZeroElig[a].clear(); } //We have to clean the traces every episode: for(unsigned int i = 0; i < e.size(); i++){ for(unsigned int j = 0; j < e[i].size(); j++){ e[i][j] = 0.0; } } F.clear(); features->getActiveFeaturesIndices(ale.getScreen(), ale.getRAM(), F); updateQValues(F, Q); currentAction = epsilonGreedy(Q); q_old = Q[currentAction]; //Repeat(for each step of episode) until game is over: gettimeofday(&tvBegin, NULL); frame = 0; while(frame < episodeLength && !ale.game_over()){ reward.clear(); reward.push_back(0.0); reward.push_back(0.0); updateQValues(F, Q); sanityCheck(); //Take action, observe reward and next state: act(ale, currentAction, reward); cumReward += reward[1]; if(!ale.game_over()){ //Obtain active features in the new state: Fnext.clear(); features->getActiveFeaturesIndices(ale.getScreen(), ale.getRAM(), Fnext); updateQValues(Fnext, Qnext); //Update Q-values for the new active features nextAction = epsilonGreedy(Qnext); } else{ nextAction = 0; for(unsigned int i = 0; i < Qnext.size(); i++){ Qnext[i] = 0; } } //To ensure the learning rate will never increase along //the time, Marc used such approach in his JAIR paper if (F.size() > maxFeatVectorNorm){ maxFeatVectorNorm = F.size(); } norm_a = alpha/maxFeatVectorNorm; delta_q = Q[currentAction] - q_old; q_old = Qnext[nextAction]; delta = reward[0] + gamma * Qnext[nextAction] - Q[currentAction]; //e <- e + [1 - alpha * e^T phi(S,A)] phi(S,A) updateTrace(currentAction, norm_a); //theta <- theta + alpha * delta * e + alpha * delta_q (e - phi(S,A)) updateWeights(currentAction, norm_a, delta_q); //e <- gamma * lambda * e decayTrace(); F = Fnext; currentAction = nextAction; } ale.reset_game(); gettimeofday(&tvEnd, NULL); timeval_subtract(&tvDiff, &tvEnd, &tvBegin); elapsedTime = double(tvDiff.tv_sec) + double(tvDiff.tv_usec)/1000000.0; double fps = double(frame)/elapsedTime; printf("episode: %d,\t%.0f points,\tavg. return: %.1f,\t%d frames,\t%.0f fps\n", episode + 1, (cumReward-prevCumReward), (double)cumReward/(episode + 1.0), frame, fps); prevCumReward = cumReward; } }
lbfgsfloatval_t RAE::_evaluate(const lbfgsfloatval_t* x, lbfgsfloatval_t* g, const int n, const lbfgsfloatval_t step) { lbfgsfloatval_t fx = 0; int RAEThreadNum = atoi(para->getPara("RAEThreadNum").c_str()); RAEThreadPara* threadpara = new RAEThreadPara[RAEThreadNum]; int batchsize = trainingData.size() / RAEThreadNum; updateWeights(x); for(int i = 0; i < RAEThreadNum; i++) { threadpara[i].cRAE = this->copy(); threadpara[i].g = lbfgs_malloc(getRAEWeightSize()); for(int j = 0; j < getRAEWeightSize(); j++) { threadpara[i].g[j] = 0; } if(i == RAEThreadNum-1) { map<string, int>::iterator s; s = trainingData.begin(); for(int d = 0; d < i*batchsize; d++) { s++; } threadpara[i].cRAE->trainingData.insert(s, trainingData.end()); threadpara[i].instance_num = trainingData.size()%batchsize; } else { map<string, int>::iterator s, e; s = trainingData.begin(); e = trainingData.begin(); for(int d = 0; d < i*batchsize; d++) { s++; } for(int d = 0; d < (i+1)*batchsize; d++) { e++; } threadpara[i].cRAE->trainingData.insert(s, e); threadpara[i].instance_num = batchsize; } } pthread_t* pt = new pthread_t[RAEThreadNum]; for (int a = 0; a < RAEThreadNum; a++) pthread_create(&pt[a], NULL, RAELBFGS::deepThread, (void *)(threadpara + a)); for (int a = 0; a < RAEThreadNum; a++) pthread_join(pt[a], NULL); for(int i = 0; i < RAEThreadNum; i++) { fx += threadpara[i].lossVal; for(int elem = 0; elem < getRAEWeightSize(); elem++) { g[elem] += threadpara[i].g[elem]; } } /* int internal_node_num = 0; for(map<string, int>::iterator it = trainingData.begin(); it != trainingData.end(); it++) { internal_node_num += getInternalNode(it->first); }*/ fx /= trainingData.size(); fx += ZETA * decay(); for(int elem = 0; elem < getRAEWeightSize(); elem++) { g[elem] /= trainingData.size(); } delWeight1 += ZETA * weights1; delWeight1_b.setZero(); delWeight2 += ZETA * weights2; delWeight2_b.setZero(); update(g); delete pt; pt = NULL; for(int i = 0; i < RAEThreadNum; i++) { lbfgs_free(threadpara[i].g); delete threadpara[i].cRAE; } delete threadpara; threadpara = NULL; return fx; }
void FilterBoostLearner::run(const nor_utils::Args& args) { // load the arguments this->getArgs(args); time_t startTime, currentTime; time(&startTime); // get the registered weak learner (type from name) BaseLearner* pWeakHypothesisSource = BaseLearner::RegisteredLearners().getLearner(_baseLearnerName); // initialize learning options; normally it's done in the strong loop // also, here we do it for Product learners, so input data can be created pWeakHypothesisSource->initLearningOptions(args); BaseLearner* pConstantWeakHypothesisSource = BaseLearner::RegisteredLearners().getLearner("ConstantLearner"); // get the training input data, and load it InputData* pTrainingData = pWeakHypothesisSource->createInputData(); pTrainingData->initOptions(args); pTrainingData->load(_trainFileName, IT_TRAIN, _verbose); const int numClasses = pTrainingData->getNumClasses(); const int numExamples = pTrainingData->getNumExamples(); //initialize the margins variable _margins.resize( numExamples ); for( int i=0; i<numExamples; i++ ) { _margins[i].resize( numClasses ); fill( _margins[i].begin(), _margins[i].end(), 0.0 ); } // get the testing input data, and load it InputData* pTestData = NULL; if ( !_testFileName.empty() ) { pTestData = pWeakHypothesisSource->createInputData(); pTestData->initOptions(args); pTestData->load(_testFileName, IT_TEST, _verbose); } // The output information object OutputInfo* pOutInfo = NULL; if ( !_outputInfoFile.empty() ) { // Baseline: constant classifier - goes into 0th iteration BaseLearner* pConstantWeakHypothesis = pConstantWeakHypothesisSource->create() ; pConstantWeakHypothesis->initLearningOptions(args); pConstantWeakHypothesis->setTrainingData(pTrainingData); AlphaReal constantEnergy = pConstantWeakHypothesis->run(); pOutInfo = new OutputInfo(_outputInfoFile); pOutInfo->initialize(pTrainingData); updateMargins( pTrainingData, pConstantWeakHypothesis ); if (pTestData) pOutInfo->initialize(pTestData); pOutInfo->outputHeader(pTrainingData->getClassMap() ); pOutInfo->outputIteration(-1); pOutInfo->outputCustom(pTrainingData, pConstantWeakHypothesis); if (pTestData) { pOutInfo->separator(); pOutInfo->outputCustom(pTestData, pConstantWeakHypothesis); } pOutInfo->outputCurrentTime(); pOutInfo->endLine(); pOutInfo->initialize(pTrainingData); if (pTestData) pOutInfo->initialize(pTestData); } // reload the previously found weak learners if -resume is set. // otherwise just return 0 int startingIteration = resumeWeakLearners(pTrainingData); Serialization ss(_shypFileName, _isShypCompressed ); ss.writeHeader(_baseLearnerName); // this must go after resumeProcess has been called // perform the resuming if necessary. If not it will just return resumeProcess(ss, pTrainingData, pTestData, pOutInfo); if (_verbose == 1) cout << "Learning in progress..." << endl; /////////////////////////////////////////////////////////////////////// // Starting the AdaBoost main loop /////////////////////////////////////////////////////////////////////// for (int t = startingIteration; t < _numIterations; ++t) { if (_verbose > 1) cout << "------- WORKING ON ITERATION " << (t+1) << " -------" << endl; filter( pTrainingData, (int)(_Cn * log(t+2.0)) ); if ( pTrainingData->getNumExamples() < 2 ) { filter( pTrainingData, (int)(_Cn * log(t+2.0)), false ); } if (_verbose > 1) { cout << "--> Size of training data = " << pTrainingData->getNumExamples() << endl; } BaseLearner* pWeakHypothesis = pWeakHypothesisSource->create(); pWeakHypothesis->initLearningOptions(args); //pTrainingData->clearIndexSet(); pWeakHypothesis->setTrainingData(pTrainingData); AlphaReal energy = pWeakHypothesis->run(); BaseLearner* pConstantWeakHypothesis; pConstantWeakHypothesis = pConstantWeakHypothesisSource->create() ; pConstantWeakHypothesis->initLearningOptions(args); pConstantWeakHypothesis->setTrainingData(pTrainingData); AlphaReal constantEnergy = pConstantWeakHypothesis->run(); //estimate edge filter( pTrainingData, (int)(_Cn * log(t+2.0)), false ); AlphaReal edge = pWeakHypothesis->getEdge() / 2.0; AlphaReal constantEdge = pConstantWeakHypothesis->getEdge() / 2.0; if ( constantEdge > edge ) { delete pWeakHypothesis; pWeakHypothesis = pConstantWeakHypothesis; edge = constantEdge; } else { delete pConstantWeakHypothesis; } // calculate alpha AlphaReal alpha = 0.0; alpha = 0.5 * log( ( 1 + edge ) / ( 1 - edge ) ); pWeakHypothesis->setAlpha( alpha ); if (_verbose > 1) cout << "Weak learner: " << pWeakHypothesis->getName()<< endl; // Output the step-by-step information pTrainingData->clearIndexSet(); printOutputInfo(pOutInfo, t, pTrainingData, pTestData, pWeakHypothesis); // Updates the weights and returns the edge AlphaReal gamma = updateWeights(pTrainingData, pWeakHypothesis); if (_verbose > 1) { cout << setprecision(5) << "--> Alpha = " << pWeakHypothesis->getAlpha() << endl << "--> Edge = " << gamma << endl << "--> Energy = " << energy << endl // << "--> ConstantEnergy = " << constantEnergy << endl // << "--> difference = " << (energy - constantEnergy) << endl ; } // update the margins updateMargins( pTrainingData, pWeakHypothesis ); // append the current weak learner to strong hypothesis file, // that is, serialize it. ss.appendHypothesis(t, pWeakHypothesis); // Add it to the internal list of weak hypotheses _foundHypotheses.push_back(pWeakHypothesis); // check if the time limit has been reached if (_maxTime > 0) { time( ¤tTime ); float diff = difftime(currentTime, startTime); // difftime is in seconds diff /= 60; // = minutes if (diff > _maxTime) { if (_verbose > 0) cout << "Time limit of " << _maxTime << " minutes has been reached!" << endl; break; } } // check for maxtime delete pWeakHypothesis; } // loop on iterations ///////////////////////////////////////////////////////// // write the footer of the strong hypothesis file ss.writeFooter(); // Free the two input data objects if (pTrainingData) delete pTrainingData; if (pTestData) delete pTestData; if (pOutInfo) delete pOutInfo; if (_verbose > 0) cout << "Learning completed." << endl; }