Esempio n. 1
0
int main(int argc, char **argv)
{
	InitializeFast();

	Backend backend;

	ANNEvaluator evaluator;

	ANNMoveEvaluator mevaluator(evaluator);

	// if eval.net exists, use the ANN evaluator
	// if both eval.net and meval.net exist, use the ANN move evaluator

	if (FileReadable(EvalNetFilename))
	{
		backend.SetEvaluator(&evaluator);

		std::cout << "# Using ANN evaluator" << std::endl;

		if (FileReadable(MoveEvalNetFilename))
		{
			std::cout << "# Using ANN move evaluator" << std::endl;
			backend.SetMoveEvaluator(&mevaluator);
		}
		else
		{
			std::cout << "# Using static move evaluator" << std::endl;
			backend.SetMoveEvaluator(&gStaticMoveEvaluator);
		}
	}
	else
	{
		std::cout << "# Using static evaluator" << std::endl;
		std::cout << "# Using static move evaluator" << std::endl;

		backend.SetEvaluator(&Eval::gStaticEvaluator);
		backend.SetMoveEvaluator(&gStaticMoveEvaluator);
	}

	// first we handle special operation modes
	if (argc >= 2 && std::string(argv[1]) == "tdl")
	{
		InitializeSlowBlocking(evaluator, mevaluator);

		if (argc < 3)
		{
			std::cout << "Usage: " << argv[0] << " tdl positions" << std::endl;
			return 0;
		}
        //try 
        //{
	    Learn::TDL(argv[2]);
        //}
        //catch(...){}
		return 0;
	}
	else if (argc >= 2 && std::string(argv[1]) == "conv")
	{
		InitializeSlowBlocking(evaluator, mevaluator);

		if (argc < 3)
		{
			std::cout << "Usage: " << argv[0] << " conv FEN" << std::endl;
			return 0;
		}

		std::stringstream ss;

		for (int i = 2; i < argc; ++i)
		{
			ss << argv[i] << ' ';
		}

		Board b(ss.str());

		std::vector<FeaturesConv::FeatureDescription> ret;
		FeaturesConv::ConvertBoardToNN(b, ret);

		return 0;
	}
    else if(argc >= 2 && std::string(argv[1]) == "train_eval")
    {
        // ./giraffe train_eval <list filename> <epd_data_path> <epd_label_path> <epochs> 

        InitializeSlowBlocking(evaluator, mevaluator);
        std::ifstream epd_file_list(argv[2]);
        std::string epd_data_path = argv[3];
        std::string epd_label_path = argv[4];
        std::string epd_filename;
        std::vector<std::string> filenames;
        while(std::getline(epd_file_list, epd_filename)){
            filenames.push_back(epd_filename);
        }
        int epochs = std::stoi(argv[5]);
        
        for(int i = 0; i < epochs*filenames.size(); i++){
            std::string epd_path_full = epd_data_path + "/" + filenames[i % filenames.size()];
            std::string label_path_full = epd_label_path + "/" + filenames[i % filenames.size()] + ".xie";
            std::cout << label_path_full << std::endl;
            std::ifstream epd_file(epd_path_full);
            std::ifstream label_file(label_path_full);
            std::string fen;
            std::vector<std::string> fens;
            //std::cout << "Reading FENS" << std::endl;
            while(std::getline(epd_file, fen))
            {
                fens.push_back(fen);
            } 
            //std::cout << "Reading labels" << std::endl;
            
            std::string label;
            NNMatrixRM mat_labels = NNMatrixRM(fens.size(), 1);
            //std::vector<int> labels; 
            int idx = 0;
            while(std::getline(label_file, label)){
                //labels.push_back(stoi(label));
                mat_labels(idx, 0) = std::stoi(label);
                idx++; 
            }
            //std::cout << "Getting feature descriptions" << std::endl;
            Board dummy;
            std::vector<FeaturesConv::FeatureDescription> ret;
            FeaturesConv::ConvertBoardToNN(dummy, ret);

            //std::cout << "Starting Training" << std::endl;
            
            std::ofstream outNet(argv[6]);
            //evaluator.Serialize(outNet);
            evaluator.TrainLoop(fens, mat_labels, 10, ret);
            evaluator.Serialize(outNet);
        }
/*
        std::ifstream epd_file(argv[2]);
        std::ifstream label_file(argv[3]);
        std::string fen;
        std::vector<std::string> fens;
        std::cout << "Reading FENS" << std::endl;
        while(std::getline(epd_file, fen))
        {
            fens.push_back(fen);
        } 
        std::cout << "Reading labels" << std::endl;
        
        std::string label;
        NNMatrixRM mat_labels = NNMatrixRM(fens.size(), 1);
        //std::vector<int> labels; 
        int idx = 0;
        while(std::getline(label_file, label)){
            //labels.push_back(stoi(label));
            mat_labels(idx, 0) = std::stoi(label);
            idx++; 
        }
        std::cout << "Getting feature descriptions" << std::endl;
        int epochs = std::stoi(argv[4]);
        Board dummy;
		std::vector<FeaturesConv::FeatureDescription> ret;
		FeaturesConv::ConvertBoardToNN(dummy, ret);

        std::cout << "Starting Training" << std::endl;
        
        std::ofstream outNet(argv[5]);
        evaluator.Serialize(outNet);
        evaluator.TrainLoop(fens, mat_labels, epochs, ret);
        evaluator.Serialize(outNet);
  */      
        return 0;
    }
    else if (argc >= 2 && std::string(argv[1]) == "conv_file")
    {
        InitializeSlowBlocking(evaluator, mevaluator);
        
        std::ifstream inFile(argv[2]);
        std::ofstream outFile(argv[3]);

        std::string fen;
        std::vector<std::string> fens;
        while(std::getline(inFile, fen))
        {
            fens.push_back(fen);
            std::cout << fen << std::endl;
            /*
            Board b(fen);
		    std::vector<FeaturesConv::FeatureDescription> ret;
		    FeaturesConv::ConvertBoardToNN(b, ret);
            std::stringstream ss;
            for (int i = 0; i < ret.size()-1; i++)
            {
                ss << ret[i].XieToString() << " ";

            }
            ss << ret[ret.size() - 1].XieToString();
            outFile << ss.str() << std::endl;
            std::cout << ss.str() << std::endl;
            std::cout << "****" << std::endl;
            */
        }

        std::vector<FeaturesConv::FeatureDescription> dummy(363);

        NNMatrixRM ret = evaluator.BoardsToFeatureRepresentation_(fens, dummy);
        for(int64_t row = 0; row < ret.rows(); ++row)
        {
            for(int64_t col = 0; col < ret.cols(); ++ col)
            {
                outFile << ret(row,col) << ' '; 
            }
            outFile << '\n';
        }


        inFile.close();
        outFile.close();

        return 0;

    }
	else if (argc >= 2 && std::string(argv[1]) == "mconv")
	{
		InitializeSlowBlocking(evaluator, mevaluator);

		if (argc < 3)
		{
			std::cout << "Usage: " << argv[0] << " mconv FEN" << std::endl;
			return 0;
		}

		std::stringstream ss;

		for (int i = 2; i < argc; ++i)
		{
			ss << argv[i] << ' ';
		}

		Board b(ss.str());

		MoveList moves;
		b.GenerateAllLegalMoves<Board::ALL>(moves);

		NNMatrixRM ret;

		FeaturesConv::ConvertMovesInfo convInfo;

		FeaturesConv::ConvertMovesToNN(b, convInfo, moves, ret);

		for (int64_t row = 0; row < ret.rows(); ++row)
		{
			for (int64_t col = 0; col < ret.cols(); ++col)
			{
				std::cout << ret(row, col) << ' ';
			}
			std::cout << std::endl;
		}

		return 0;
	}
	else if (argc >= 2 && std::string(argv[1]) == "bench")
	{
		InitializeSlowBlocking(evaluator, mevaluator);

		double startTime = CurrentTime();

		static const NodeBudget BenchNodeBudget = 64*1024*1024;

		Search::SyncSearchNodeLimited(Board("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1"), BenchNodeBudget, backend.GetEvaluator(), backend.GetMoveEvaluator());
		Search::SyncSearchNodeLimited(Board("2r2rk1/pp3pp1/b2Pp3/P1Q4p/RPqN2n1/8/2P2PPP/2B1R1K1 w - - 0 1"), BenchNodeBudget, backend.GetEvaluator(), backend.GetMoveEvaluator());
		Search::SyncSearchNodeLimited(Board("8/1nr3pk/p3p1r1/4p3/P3P1q1/4PR1N/3Q2PK/5R2 w - - 0 1"), BenchNodeBudget, backend.GetEvaluator(), backend.GetMoveEvaluator());
		Search::SyncSearchNodeLimited(Board("5R2/8/7r/7P/5RPK/1k6/4r3/8 w - - 0 1"), BenchNodeBudget, backend.GetEvaluator(), backend.GetMoveEvaluator());
		Search::SyncSearchNodeLimited(Board("r5k1/2p2pp1/1nppr2p/8/p2PPp2/PPP2P1P/3N2P1/R3RK2 w - - 0 1"), BenchNodeBudget, backend.GetEvaluator(), backend.GetMoveEvaluator());
		Search::SyncSearchNodeLimited(Board("8/R7/8/1k6/1p1Bq3/8/4NK2/8 w - - 0 1"), BenchNodeBudget, backend.GetEvaluator(), backend.GetMoveEvaluator());

		std::cout << "Time: " << (CurrentTime() - startTime) << "s" << std::endl;

		return 0;
	}
	else if (argc >= 2 && std::string(argv[1]) == "check_bounds")
	{
		InitializeSlowBlocking(evaluator, mevaluator);

		if (argc < 3)
		{
			std::cout << "Usage: " << argv[0] << " check_bounds <EPD/FEN file>" << std::endl;
			return 0;
		}

		std::ifstream infile(argv[2]);

		if (!infile)
		{
			std::cerr << "Failed to open " << argv[2] << " for reading" << std::endl;
			return 1;
		}

		uint64_t passes = 0;
		uint64_t total = 0;
		float windowSizeTotal = 0.0f;

		std::string fen;
		std::vector<std::string> fens;
		while (std::getline(infile, fen))
		{
			fens.push_back(fen);
		}

		#pragma omp parallel
		{
			auto evaluatorCopy = evaluator;

			#pragma omp for
			for (size_t i = 0; i < fens.size(); ++i)
			{
				Board b(fens[i]);
				float windowSize = 0.0f;
				bool res = evaluatorCopy.CheckBounds(b, windowSize);

				#pragma omp critical(boundCheckAccum)
				{
					if (res)
					{
						++passes;
					}

					++total;

					windowSizeTotal += windowSize;
				}
			}
		}

		std::cout << passes << "/" << total << std::endl;
		std::cout << "Average window size: " << (windowSizeTotal / total) << std::endl;

		return 0;
	}
	else if (argc >= 2 && std::string(argv[1]) == "train_bounds")
	{
		InitializeSlowBlocking(evaluator, mevaluator);

		if (argc < 4)
		{
			std::cout << "Usage: " << argv[0] << " train_bounds <EPD/FEN file> <output net file>" << std::endl;
			return 0;
		}

		std::ifstream infile(argv[2]);

		if (!infile)
		{
			std::cerr << "Failed to open " << argv[2] << " for reading" << std::endl;
			return 1;
		}

		std::vector<FeaturesConv::FeatureDescription> featureDescriptions;
		Board dummyBoard;
		FeaturesConv::ConvertBoardToNN(dummyBoard, featureDescriptions);

		std::string line;
		std::vector<std::string> fens;
		while (std::getline(infile, line))
		{
			fens.push_back(line);
		}

		const size_t BlockSize = 256;
		const size_t PrintInterval = BlockSize * 100;

		for (size_t i = 0; i < (fens.size() - BlockSize); i += BlockSize)
		{
			if (i % PrintInterval == 0)
			{
				std::cout << i << "/" << fens.size() << std::endl;
			}

			std::vector<std::string> positions;

			for (size_t j = 0; j < BlockSize; ++j)
			{
				positions.push_back(fens[i + j]);
			}

			evaluator.TrainBounds(positions, featureDescriptions, 1.0f);
		}

		std::ofstream outfile(argv[3]);

		if (!outfile)
		{
			std::cerr << "Failed to open " << argv[3] << " for writing" << std::endl;
			return 1;
		}

		evaluator.Serialize(outfile);

		return 0;
	}
	else if (argc >= 2 && std::string(argv[1]) == "sample_internal")
	{
		// MUST UNCOMMENT "#define SAMPLING" in static move evaluator

		InitializeSlowBlocking(evaluator, mevaluator);

		if (argc < 4)
		{
			std::cout << "Usage: " << argv[0] << " sample_internal <EPD/FEN file> <output file>" << std::endl;
			return 0;
		}

		std::ifstream infile(argv[2]);
		std::ofstream outfile(argv[3]);

		if (!infile)
		{
			std::cerr << "Failed to open " << argv[2] << " for reading" << std::endl;
			return 1;
		}

		std::string fen;
		std::vector<std::string> fens;
		static const uint64_t maxPositions = 5000000;
		uint64_t numPositions = 0;
		while (std::getline(infile, fen) && numPositions < maxPositions)
		{
			fens.push_back(fen);
			++numPositions;
		}

		#pragma omp parallel
		{
			auto evaluatorCopy = evaluator;

			#pragma omp for
			for (size_t i = 0; i < fens.size(); ++i)
			{
                std::cout << i << std::endl;
				Board b(fens[i]);

				Search::SyncSearchNodeLimited(b, 1000, &evaluatorCopy, &gStaticMoveEvaluator, nullptr, nullptr);
			}
		}

		for (const auto &pos : gStaticMoveEvaluator.samples)
		{
			outfile << pos << std::endl;
		}

		return 0;
	}
	else if (argc >= 2 && std::string(argv[1]) == "label_bm")
	{
		InitializeSlowBlocking(evaluator, mevaluator);

		if (argc < 4)
		{
			std::cout << "Usage: " << argv[0] << " label_bm <EPD/FEN file> <output file>" << std::endl;
			return 0;
		}

		std::ifstream infile(argv[2]);
		std::ofstream outfile(argv[3]);

		if (!infile)
		{
			std::cerr << "Failed to open " << argv[2] << " for reading" << std::endl;
			return 1;
		}

		std::string fen;
		std::vector<std::string> fens;
		static const uint64_t maxPositions = 5000000;
		uint64_t numPositions = 0;
		while (std::getline(infile, fen) && numPositions < maxPositions)
		{
			Board b(fen);

			if (b.GetGameStatus() != Board::ONGOING)
			{
				continue;
			}

			fens.push_back(fen);
			++numPositions;
		}

		std::vector<std::string> bm(fens.size());

		uint64_t numPositionsDone = 0;

		double lastPrintTime = CurrentTime();
		size_t lastDoneCount = 0;

		#pragma omp parallel
		{
			auto evaluatorCopy = evaluator;

			#pragma omp for schedule(dynamic)
			for (size_t i = 0; i < fens.size(); ++i)
			{
				Board b(fens[i]);

				Search::SearchResult result = Search::SyncSearchNodeLimited(b, 100000, &evaluatorCopy, &gStaticMoveEvaluator, nullptr, nullptr);

				bm[i] = b.MoveToAlg(result.pv[0]);

				#pragma omp critical(numPositionsAndOutputFileUpdate)
				{
					++numPositionsDone;

					outfile << fens[i] << '\n';
					outfile << bm[i] << '\n';

					if (omp_get_thread_num() == 0)
					{
						double currentTime = CurrentTime();
						double timeDiff = currentTime - lastPrintTime;
						if (timeDiff > 1.0)
						{
							std::cout << numPositionsDone << '/' << fens.size() << std::endl;
							std::cout << "Positions per second: " << static_cast<double>(numPositionsDone - lastDoneCount) / timeDiff << std::endl;

							lastPrintTime = currentTime;
							lastDoneCount = numPositionsDone;
						}
					}
				}
			}
		}

		return 0;
	}
	else if (argc >= 2 && std::string(argv[1]) == "train_move_eval")
	{
		InitializeSlowBlocking(evaluator, mevaluator);

		if (argc < 4)
		{
			std::cout << "Usage: " << argv[0] << " train_move_eval <EPD/FEN file> <output file>" << std::endl;
			return 0;
		}

		std::ifstream infile(argv[2]);

		if (!infile)
		{
			std::cerr << "Failed to open " << argv[2] << " for reading" << std::endl;
			return 1;
		}

		std::cout << "Reading positions from " << argv[2] << std::endl;

		std::string fen;
		std::string bestMove;
		std::vector<std::string> fens;
		std::vector<std::string> bestMoves;
		static const uint64_t MaxPositions = 5000000;
		uint64_t numPositions = 0;
		while (std::getline(infile, fen) && std::getline(infile, bestMove) && numPositions < MaxPositions)
		{
			Board b(fen);

			if (b.GetGameStatus() != Board::ONGOING)
			{
				continue;
			}

			fens.push_back(fen);
			bestMoves.push_back(bestMove);

			++numPositions;
		}

		assert(bestMoves.size() == fens.size());

		// now we split a part of it out into a withheld test set
		size_t numTrainExamples = fens.size() * 0.9f;
		std::vector<std::string> fensTest(fens.begin() + numTrainExamples, fens.end());
		std::vector<std::string> bestMovesTest(bestMoves.begin() + numTrainExamples, bestMoves.end());

		static const uint64_t MaxTestingPositions = 10000;

		if (fensTest.size() > MaxTestingPositions)
		{
			fensTest.resize(MaxTestingPositions);
			bestMovesTest.resize(MaxTestingPositions);
		}

		fens.resize(numTrainExamples);
		bestMoves.resize(numTrainExamples);

		std::cout << "Num training examples: " << numTrainExamples << std::endl;
		std::cout << "Num testing examples: " << fensTest.size() << std::endl;

		std::cout << "Starting training" << std::endl;

		ANNMoveEvaluator meval(evaluator);

		meval.Train(fens, bestMoves);

		meval.Test(fensTest, bestMovesTest);

		std::ofstream outfile(argv[3]);

		meval.Serialize(outfile);

		return 0;
	}

	// we need a mutex here because InitializeSlow needs to print, and it may decide to
	// print at the same time as the main command loop (if the command loop isn't waiting)
	std::mutex coutMtx;

	coutMtx.lock();

	// do all the heavy initialization in a thread so we can reply to "protover 2" in time
	std::thread initThread(InitializeSlow, std::ref(evaluator), std::ref(mevaluator), std::ref(coutMtx));

	auto waitForSlowInitFunc = [&initThread, &coutMtx]() { coutMtx.unlock(); initThread.join(); coutMtx.lock(); };

	while (true)
	{
		std::string lineStr;

		coutMtx.unlock();
		std::getline(std::cin, lineStr);
		coutMtx.lock();

		std::stringstream line(lineStr);

		// we set usermove=1, so all commands from xboard start with a unique word
		std::string cmd;
		line >> cmd;

		// this is the list of commands we can process before initialization finished
		if (
			cmd != "xboard" &&
			cmd != "protover" &&
			cmd != "hard" &&
			cmd != "easy" &&
			cmd != "cores" &&
			cmd != "memory" &&
			cmd != "accepted" &&
			cmd != "rejected" &&
			initThread.joinable())
		{
			// wait for initialization to be done
			waitForSlowInitFunc();
		}

		if (cmd == "xboard") {} // ignore since we only support xboard mode anyways
		else if (cmd == "protover")
		{
			int32_t ver;
			line >> ver;

			if (ver >= 2)
			{
				std::string name = "Giraffe";
				if (gVersion != "")
				{
					name += " ";
					name += gVersion;
				}

				std::cout << "feature ping=1 setboard=1 playother=0 san=0 usermove=1 time=1 draw=0 sigint=0 sigterm=0 "
							 "reuse=1 analyze=1 myname=\"" << name << "\" variants=normal colors=0 ics=0 name=0 pause=0 nps=0 "
							 "debug=1 memory=0 smp=0 done=0" << std::endl;

				std::cout << "feature option=\"GaviotaTbPath -path .\"" << std::endl;

				std::cout << "feature done=1" << std::endl;
			}
		}
		else if (cmd == "accepted") {}