/// <summary> /// Constructor. /// </summary> /// <param name="id"></param> /// <param name="nnEvaluator"></param> /// <param name="searchParams"></param> /// <param name="childSelectParams"></param> /// <param name="gameLimitManager"></param> /// <param name="paramsSearchExecutionModifier"></param> public GameEngineCeresInProcess(string id, NNEvaluatorDef evaluatorDef, ParamsSearch searchParams = null, ParamsSelect childSelectParams = null, IManagerGameLimit gameLimitManager = null, ParamsSearchExecutionModifier paramsSearchExecutionModifier = null) : base(id) { if (evaluatorDef == null) { throw new ArgumentNullException(nameof(evaluatorDef)); } // Use default settings for search and select params if not specified. if (searchParams == null) { searchParams = new ParamsSearch(); } if (childSelectParams == null) { childSelectParams = new ParamsSelect(); } // Use default limit manager if not specified. if (gameLimitManager == null) { gameLimitManager = new ManagerGameLimitCeres(); } ParamsSearchExecutionModifier = paramsSearchExecutionModifier; EvaluatorDef = evaluatorDef; SearchParams = searchParams; GameLimitManager = gameLimitManager; ChildSelectParams = childSelectParams; }
static GameEngine GetEngine(GameEngineUCISpec engineSpec, string suffix, NNEvaluatorDef evaluatorDef, ParamsSearch paramsSearch, ParamsSelect paramsSelect, IManagerGameLimit timeManager) { bool resetMovesBetweenMoves = !paramsSearch.TreeReuseEnabled; bool enableTranpsositions = paramsSearch.Execution.TranspositionMode != TranspositionMode.None; // Create requested type of engine if (engineSpec == null) { return(new GameEngineCeresInProcess("Ceres_" + suffix, evaluatorDef, paramsSearch, paramsSelect, timeManager, null)); } else if (engineSpec.Name == "LC0") { if (evaluatorDef == null) { throw new Exception("EvaluatorDef must be specified when running LC0 engine"); } // TODO: do we really want to emulate always here? probably not // WARNING: above. bool forceDisableSmartPruning = false; return(new GameEngineLC0("LZ0_" + suffix, evaluatorDef.Nets[0].Net.NetworkID, forceDisableSmartPruning, false, paramsSearch, paramsSelect, evaluatorDef, null, CeresUserSettingsManager.GetLC0ExecutableFileName())); } else { return(engineSpec.CreateEngine()); } }
/// <summary> /// Constructor. /// </summary> /// <param name="id">descriptive identifier</param> /// <param name="paramsNN">specification of the neural network to be used</param> /// <param name="forceDisableSmartPruning"></param> /// <param name="emulateCeresSettings"></param> /// <param name="searchParams"></param> /// <param name="selectParams"></param> /// <param name="uciSetOptionCommands"></param> /// <param name="callback"></param> /// <param name="overrideEXE">optinally the full name of the executable file(otherwise looks for Ceres executable in working directory)</param> public GameEngineCeresUCI(string id, NNEvaluatorDef paramsNN, bool forceDisableSmartPruning = false, bool emulateCeresSettings = false, ParamsSearch searchParams = null, ParamsSelect selectParams = null, string[] uciSetOptionCommands = null, ProgressCallback callback = null, string overrideEXE = null) : base(id, GetExecutableFN(overrideEXE), null, null, null, uciSetOptionCommands, callback, false, ExtraArgsForEvaluator(paramsNN)) { // TODO: support some limited emulation of options if (searchParams != null || selectParams != null) { throw new NotSupportedException("Customized searchParams and selectParams not yet supported"); } if (paramsNN == null) { throw new ArgumentNullException(nameof(paramsNN)); } if (forceDisableSmartPruning) { throw new NotImplementedException(nameof(forceDisableSmartPruning)); } if (emulateCeresSettings) { throw new NotImplementedException(nameof(emulateCeresSettings)); } }
/// <summary> /// Runs a new search. /// </summary> /// <param name="nnEvaluators"></param> /// <param name="paramsSelect"></param> /// <param name="paramsSearch"></param> /// <param name="limitManager"></param> /// <param name="paramsSearchExecutionPostprocessor"></param> /// <param name="reuseOtherContextForEvaluatedNodes"></param> /// <param name="priorMoves"></param> /// <param name="searchLimit"></param> /// <param name="verbose"></param> /// <param name="startTime"></param> /// <param name="gameMoveHistory"></param> /// <param name="progressCallback"></param> /// <param name="possiblyUsePositionCache"></param> /// <param name="isFirstMoveOfGame"></param> public void Search(NNEvaluatorSet nnEvaluators, ParamsSelect paramsSelect, ParamsSearch paramsSearch, IManagerGameLimit limitManager, ParamsSearchExecutionModifier paramsSearchExecutionPostprocessor, MCTSIterator reuseOtherContextForEvaluatedNodes, PositionWithHistory priorMoves, SearchLimit searchLimit, bool verbose, DateTime startTime, List <GameMoveStat> gameMoveHistory, MCTSManager.MCTSProgressCallback progressCallback = null, bool possiblyUsePositionCache = false, bool isFirstMoveOfGame = false) { searchLimit = AdjustedSearchLimit(searchLimit, paramsSearch); int maxNodes; if (MCTSParamsFixed.STORAGE_USE_INCREMENTAL_ALLOC) { // In this mode, we are just reserving virtual address space // from a very large pool (e.g. 256TB for Windows). // Therefore it is safe to reserve a very large block. maxNodes = (int)(1.1f * MCTSNodeStore.MAX_NODES); } else { if (searchLimit.SearchCanBeExpanded) { throw new Exception("STORAGE_USE_INCREMENTAL_ALLOC must be true when SearchCanBeExpanded."); } if (searchLimit.Type != SearchLimitType.NodesPerMove) { maxNodes = (int)searchLimit.Value + 5_000; } else { throw new Exception("STORAGE_USE_INCREMENTAL_ALLOC must be true when using time search limits."); } } MCTSNodeStore store = new MCTSNodeStore(maxNodes, priorMoves); SearchLimit searchLimitToUse = ConvertedSearchLimit(priorMoves.FinalPosition, searchLimit, 0, 0, paramsSearch, limitManager, gameMoveHistory, isFirstMoveOfGame); Manager = new MCTSManager(store, reuseOtherContextForEvaluatedNodes, null, null, nnEvaluators, paramsSearch, paramsSelect, searchLimitToUse, paramsSearchExecutionPostprocessor, limitManager, startTime, null, gameMoveHistory, isFirstMoveOfGame); using (new SearchContextExecutionBlock(Manager.Context)) { (BestMove, TimingInfo) = MCTSManager.Search(Manager, verbose, progressCallback, possiblyUsePositionCache); } }
/// <summary> /// /// </summary> /// <param name="store"></param> /// <param name="reuseOtherContextForEvaluatedNodes"></param> /// <param name="reusePositionCache"></param> /// <param name="reuseTranspositionRoots"></param> /// <param name="nnEvaluators"></param> /// <param name="searchParams"></param> /// <param name="childSelectParams"></param> /// <param name="searchLimit"></param> /// <param name="paramsSearchExecutionPostprocessor"></param> /// <param name="limitManager"></param> /// <param name="startTime"></param> /// <param name="priorManager"></param> /// <param name="gameMoveHistory"></param> /// <param name="isFirstMoveOfGame"></param> public MCTSManager(MCTSNodeStore store, MCTSIterator reuseOtherContextForEvaluatedNodes, PositionEvalCache reusePositionCache, TranspositionRootsDict reuseTranspositionRoots, NNEvaluatorSet nnEvaluators, ParamsSearch searchParams, ParamsSelect childSelectParams, SearchLimit searchLimit, ParamsSearchExecutionModifier paramsSearchExecutionPostprocessor, IManagerGameLimit limitManager, DateTime startTime, MCTSManager priorManager, List <GameMoveStat> gameMoveHistory, bool isFirstMoveOfGame) { if (searchLimit.IsPerGameLimit) { throw new Exception("Per game search limits not supported"); } StartTimeThisSearch = startTime; RootNWhenSearchStarted = store.Nodes.nodes[store.RootIndex.Index].N; ParamsSearchExecutionPostprocessor = paramsSearchExecutionPostprocessor; IsFirstMoveOfGame = isFirstMoveOfGame; SearchLimit = searchLimit; // Make our own copy of move history. PriorMoveStats = new List <GameMoveStat>(); if (gameMoveHistory != null) { PriorMoveStats.AddRange(gameMoveHistory); } // Possibly autoselect new optimal parameters ParamsSearchExecutionChooser paramsChooser = new ParamsSearchExecutionChooser(nnEvaluators.EvaluatorDef, searchParams, childSelectParams, searchLimit); // TODO: technically this is overwriting the params belonging to the prior search, that's ugly (but won't actually cause a problem) paramsChooser.ChooseOptimal(searchLimit.EstNumNodes(50_000, false), paramsSearchExecutionPostprocessor); // TODO: make 50_000 smarter int estNumNodes = EstimatedNumSearchNodesForEvaluator(searchLimit, nnEvaluators); // Adjust the nodes estimate if we are continuing an existing search if (searchLimit.Type == SearchLimitType.NodesPerMove && RootNWhenSearchStarted > 0) { estNumNodes = Math.Max(0, estNumNodes - RootNWhenSearchStarted); } Context = new MCTSIterator(store, reuseOtherContextForEvaluatedNodes, reusePositionCache, reuseTranspositionRoots, nnEvaluators, searchParams, childSelectParams, searchLimit, estNumNodes); ThreadSearchContext = Context; TerminationManager = new MCTSFutilityPruning(this, searchLimit.SearchMoves); LimitManager = limitManager; CeresEnvironment.LogInfo("MCTS", "Init", $"SearchManager created for store {store}", InstanceID); }
/// <summary> /// Constructor. /// </summary> public GameEngineDefCeres(string id, NNEvaluatorDef evaluatorDef, ParamsSearch searchParams = null, ParamsSearchExecutionModifier paramsSearchExecutionPostprocessor = null, ParamsSelect selectParams = null, IManagerGameLimit overrideTimeManager = null) : base(id) { EvaluatorDef = evaluatorDef; SearchParams = searchParams ?? new ParamsSearch(); ParamsSearchExecutionPostprocessor = paramsSearchExecutionPostprocessor; SelectParams = selectParams ?? new ParamsSelect(); OverrideTimeManager = overrideTimeManager; }
/// <summary> /// Constructor. /// </summary> public GameEngineDefCeres(string id, NNEvaluatorDef evaluatorDef, ParamsSearch searchParams = null, ParamsSearchExecutionModifier paramsSearchExecutionPostprocessor = null, ParamsSelect selectParams = null, IManagerGameLimit overrideTimeManager = null) : base(id) { // Make a defensive clone of the EvaluatorDef so it will definitely not be shared. EvaluatorDef = ObjUtils.DeepClone(evaluatorDef); SearchParams = searchParams ?? new ParamsSearch(); ParamsSearchExecutionPostprocessor = paramsSearchExecutionPostprocessor; SelectParams = selectParams ?? new ParamsSelect(); OverrideTimeManager = overrideTimeManager; }
public Response <List <ScheduleListDto> > Search(ParamsSearch data, string token) { Response <List <ScheduleListDto> > obj = null; var hCliente = _global.rspClient("Schedule/Buscar", data, token); if (hCliente.IsSuccessStatusCode) { obj = new JavaScriptSerializer().Deserialize <Response <List <ScheduleListDto> > >(hCliente.Content.ReadAsStringAsync().Result); } return(obj); }
/// <summary> /// Construtor. /// </summary> /// <param name="evaluatorDef"></param> /// <param name="inStream"></param> /// <param name="outStream"></param> /// <param name="searchFinishedEvent"></param> public UCIManager(NNEvaluatorDef evaluatorDef, TextReader inStream = null, TextWriter outStream = null, Action <MCTSManager> searchFinishedEvent = null) { InStream = inStream ?? Console.In; OutStream = outStream ?? Console.Out; SearchFinishedEvent = searchFinishedEvent; EvaluatorDef = evaluatorDef; ParamsSearch = new ParamsSearch(); ParamsSelect = new ParamsSelect(); }
/// <summary> /// Returns an LC0Engine object configured according to specified settings. /// </summary> /// <param name="paramsSearch"></param> /// <param name="paramsSelect"></param> /// <param name="evaluatorDef"></param> /// <param name="network"></param> /// <param name="resetStateAndCachesBeforeMoves"></param> /// <param name="emulateCeresOptions"></param> /// <param name="verboseOutput"></param> /// <param name="overrideEXE"></param> /// <returns></returns> public static LC0Engine GetLC0Engine(ParamsSearch paramsSearch, ParamsSelect paramsSelect, NNEvaluatorDef evaluatorDef, INNWeightsFileInfo network, bool resetStateAndCachesBeforeMoves, bool emulateCeresOptions, bool verboseOutput, bool forceDisableSmartPruning, string overrideEXE = null, bool alwaysFillHistory = false) { (string EXE, string lzOptions) = GetLC0EngineOptions(paramsSearch, paramsSelect, evaluatorDef, network, emulateCeresOptions, verboseOutput, overrideEXE, forceDisableSmartPruning, alwaysFillHistory); return(new LC0Engine(EXE, lzOptions, resetStateAndCachesBeforeMoves)); }
SearchOnFEN(NNEvaluatorSet nnEvaluators, ParamsSelect paramsChildSelect, ParamsSearch paramsSearch, IManagerGameLimit timeManager, ParamsSearchExecutionModifier paramsSearchExecutionPostprocessor, MCTSIterator reuseOtherContextForEvaluatedNodes, string fen, string movesStr, SearchLimit searchLimit, bool verbose = false, MCTSManager.MCTSProgressCallback progressCallback = null, bool possiblyEnablePositionCache = false, List <GameMoveStat> gameMoveHistory = null) { PositionWithHistory priorMoves = PositionWithHistory.FromFENAndMovesUCI(fen, movesStr); return(Search(nnEvaluators, paramsChildSelect, paramsSearch, timeManager, paramsSearchExecutionPostprocessor, reuseOtherContextForEvaluatedNodes, priorMoves, searchLimit, verbose, DateTime.Now, gameMoveHistory, progressCallback, possiblyEnablePositionCache)); }
/// <summary> /// Constructor. /// </summary> /// <param name="id"></param> /// <param name="evaluatorDef"></param> /// <param name="forceDisableSmartPruning"></param> /// <param name="searchParamsEmulate"></param> /// <param name="selectParamsEmulate"></param> /// <param name="overrideEXE"></param> /// <param name="extraCommandLineArgs"></param> public GameEngineDefLC0(string id, NNEvaluatorDef evaluatorDef, bool forceDisableSmartPruning, ParamsSearch searchParamsEmulate = null, ParamsSelect selectParamsEmulate = null, string overrideEXE = null, string extraCommandLineArgs = null) : base(id) { if ((SearchParamsEmulate == null) != (SelectParamsEmulate == null)) { throw new ArgumentException("SearchParamsEmulate and SelectParamsEmulate must be both provided or not"); } // Verify compatability of evaluator for LC0 if (evaluatorDef == null) { throw new ArgumentNullException(nameof(evaluatorDef)); } if (evaluatorDef.Nets.Length != 1) { throw new Exception("Exactly one network must be specified for use with LC0."); } if (evaluatorDef.Nets[0].Net.Type != NNEvaluatorType.LC0Library) { throw new Exception("Network Type must be LC0Library"); } if (evaluatorDef.NetCombo != NNEvaluatorNetComboType.Single) { throw new Exception("Network Type must be Single"); } ID = id; // Make a defensive clone of the EvaluatorDef so it will definitely not be shared. EvaluatorDef = ObjUtils.DeepClone(evaluatorDef); ForceDisableSmartPruning = forceDisableSmartPruning; SearchParamsEmulate = searchParamsEmulate; SelectParamsEmulate = selectParamsEmulate; OverrideEXE = overrideEXE; ExtraCommandLineArgs = extraCommandLineArgs; }
/// <summary> /// Construtor. /// </summary> /// <param name="evaluatorDef"></param> /// <param name="inStream"></param> /// <param name="outStream"></param> /// <param name="searchFinishedEvent"></param> public UCIManager(NNEvaluatorDef evaluatorDef, TextReader inStream = null, TextWriter outStream = null, Action <MCTSManager> searchFinishedEvent = null, bool disablePruning = false) { InStream = inStream ?? Console.In; OutStream = outStream ?? Console.Out; SearchFinishedEvent = searchFinishedEvent; EvaluatorDef = evaluatorDef; ParamsSearch = new ParamsSearch(); ParamsSelect = new ParamsSelect(); if (disablePruning) { ParamsSearch.FutilityPruningStopSearchEnabled = false; } }
public JsonResult Search(ParamsSearch data) { #region TOKEN var sessione = (SessionModel)Session[Resources.Constante.SessionUsuario]; LoginDto oLoginDto = new LoginDto(); oLoginDto.v_UserName = sessione.UserName; oLoginDto.v_Password = sessione.Pass; var validated = _securityBL.ValidateAccess(oLoginDto); if (validated == null) { return(Json("", "application/json", Encoding.UTF8, JsonRequestBehavior.AllowGet)); } #endregion if (data.Value == null) { data.Value = ""; } var response = _receptionBL.Search(data, validated.Token); return(Json(response, "application/json", Encoding.UTF8, JsonRequestBehavior.AllowGet)); }
/// <summary> /// Constructor. /// </summary> /// <param name="id"></param> /// <param name="evaluatorDef"></param> /// <param name="searchParams"></param> /// <param name="childSelectParams"></param> /// <param name="gameLimitManager"></param> /// <param name="paramsSearchExecutionModifier"></param> /// <param name="logFileName"></param> public GameEngineCeresInProcess(string id, NNEvaluatorDef evaluatorDef, ParamsSearch searchParams = null, ParamsSelect childSelectParams = null, IManagerGameLimit gameLimitManager = null, ParamsSearchExecutionModifier paramsSearchExecutionModifier = null, string logFileName = null) : base(id) { if (evaluatorDef == null) { throw new ArgumentNullException(nameof(evaluatorDef)); } // Use default settings for search and select params if not specified. if (searchParams == null) { searchParams = new ParamsSearch(); } if (childSelectParams == null) { childSelectParams = new ParamsSelect(); } // Use default limit manager if not specified. if (gameLimitManager == null) { gameLimitManager = new ManagerGameLimitCeres(); } ParamsSearchExecutionModifier = paramsSearchExecutionModifier; EvaluatorDef = evaluatorDef; SearchParams = searchParams; GameLimitManager = gameLimitManager; ChildSelectParams = childSelectParams; SearchLogFileName = logFileName; VerboseMoveStats = CeresUserSettingsManager.Settings.VerboseMoveStats; if (!string.IsNullOrEmpty(CeresUserSettingsManager.Settings.SearchLogFile)) { SearchLogFileName = CeresUserSettingsManager.Settings.SearchLogFile; } }
/// <summary> /// Publicly exposed method that launches a round of root preloading /// based on search paratemrs and updates associated statistics. /// </summary> /// <param name="root"></param> /// <param name="selectorID"></param> /// <param name="maxNodes"></param> /// <param name="pThreshold"></param> /// <returns></returns> public List <MCTSNode> GetRootPreloadNodes(MCTSNode root, int selectorID, int maxNodes, float pThreshold = float.NaN) { ParamsSearch parmsSearch = root.Context.ParamsSearch; // Nothing to do if this feature is not active if (parmsSearch.Execution.RootPreloadDepth == 0) { return(null); } // Try to gather some nodes List <MCTSNode> nodes = GatherRootPreloadNodes(selectorID, root, maxNodes, parmsSearch.Execution.RootPreloadDepth, parmsSearch.Execution.RootPreloadWidth, pThreshold); int numNodesSelectedThisAttempt = nodes is null ? 0 : nodes.Count; TotalCumulativeRootPreloadNodes += numNodesSelectedThisAttempt; return(nodes); }
/// <summary> /// Constructor. /// </summary> /// <param name="id"></param> /// <param name="evaluatorDef"></param> /// <param name="forceDisableSmartPruning"></param> /// <param name="searchParamsEmulate"></param> /// <param name="selectParamsEmulate"></param> /// <param name="overrideEXE"></param> public GameEngineDefLC0(string id, NNEvaluatorDef evaluatorDef, bool forceDisableSmartPruning, ParamsSearch searchParamsEmulate = null, ParamsSelect selectParamsEmulate = null, string overrideEXE = null) : base(id) { if ((SearchParamsEmulate == null) != (SelectParamsEmulate == null)) { throw new ArgumentException("SearchParamsEmulate and SelectParamsEmulate must be both provided or not"); } // Verify compatability of evaluator for LC0 if (evaluatorDef == null) { throw new ArgumentNullException(nameof(evaluatorDef)); } if (evaluatorDef.Nets.Length != 1) { throw new Exception("Exactly one network must be specified for use with LC0."); } if (evaluatorDef.Nets[0].Net.Type != NNEvaluatorType.LC0Library) { throw new Exception("Network Type must be LC0Library"); } if (evaluatorDef.NetCombo != NNEvaluatorNetComboType.Single) { throw new Exception("Network Type must be Single"); } ID = id; EvaluatorDef = evaluatorDef ?? throw new ArgumentNullException(nameof(evaluatorDef)); ForceDisableSmartPruning = forceDisableSmartPruning; SearchParamsEmulate = searchParamsEmulate; SelectParamsEmulate = selectParamsEmulate; OverrideEXE = overrideEXE; }
/// <summary> /// Constructor /// </summary> /// <param name="searchParams"></param> /// <param name="selectParams"></param> /// <param name="paramsNN"></param> /// <param name="id"></param> /// <param name="networkID"></param> /// <param name="emulateCeresSettings"></param> /// <param name="setupAction"></param> /// <param name="overrideEXE"></param> public GameEngineLC0(string id, string networkID, bool forceDisableSmartPruning = false, bool emulateCeresSettings = false, ParamsSearch searchParams = null, ParamsSelect selectParams = null, NNEvaluatorDef paramsNN = null, Action setupAction = null, string overrideEXE = null, bool verbose = false, bool alwaysFillHistory = false) : base(id) { SetupAction = setupAction; if (SetupAction != null) { SetupAction(); } bool resetStateAndCachesBeforeMoves = searchParams != null && !searchParams.TreeReuseEnabled; LC0Engine = LC0EngineConfigured.GetLC0Engine(searchParams, selectParams, paramsNN, NNWeightsFiles.LookupNetworkFile(networkID), emulateCeresSettings, resetStateAndCachesBeforeMoves, verbose, forceDisableSmartPruning, overrideEXE, alwaysFillHistory); }
public static void Analyze(string fenAndMoves, SearchLimit searchLimit, NNEvaluatorDef evaluatorDef, bool forceDisablePruning, LC0Engine lc0Engine = null, GameEngine comparisonEngine = null, bool verbose = false) { Console.WriteLine("============================================================================="); Console.WriteLine("Analyzing FEN : " + fenAndMoves); Console.WriteLine("Search limit : " + searchLimit.ToString()); Console.WriteLine("Ceres evaluator : " + evaluatorDef.ToString()); if (comparisonEngine != null) { Console.WriteLine("Opponent : " + comparisonEngine.ToString()); } Console.WriteLine(); Console.WriteLine(); NNEvaluatorSet nnEvaluators = new NNEvaluatorSet(evaluatorDef); // Warmup (in parallel) lc0Engine?.DoSearchPrepare(); Parallel.Invoke( () => nnEvaluators.Warmup(true), () => comparisonEngine?.Warmup()); bool ceresDone = false; lastInfoUpdate = DateTime.Now; UCISearchInfo lastCeresInfo = null; // Launch Ceres MCTSearch ceresResults = null; Task searchCeres = Task.Run(() => { ParamsSearch searchParams = new ParamsSearch(); searchParams.FutilityPruningStopSearchEnabled = !forceDisablePruning; PositionWithHistory positionWithHistory = PositionWithHistory.FromFENAndMovesUCI(fenAndMoves); ceresResults = new MCTSearch(); ceresResults.Search(nnEvaluators, new ParamsSelect(), searchParams, null, null, null, positionWithHistory, searchLimit, verbose, DateTime.Now, null, manager => lastCeresInfo = new UCISearchInfo(UCIInfo.UCIInfoString(manager), null, null), false, true); }); // Possibly launch search for other engine Task searchComparison = null; if (lc0Engine != null || comparisonEngine != null) { searchComparison = Task.Run(() => { if (lc0Engine != null) { lc0Engine.DoSearchPrepare(); lc0Engine.AnalyzePositionFromFENAndMoves(fenAndMoves, searchLimit); } else { comparisonEngine.Search(PositionWithHistory.FromFENAndMovesUCI(fenAndMoves), searchLimit, verbose: true); } }); } ; while (!searchCeres.IsCompleted || (searchComparison != null && !searchComparison.IsCompleted)) { Thread.Sleep(1000); //Console.WriteLine(DateTime.Now + " --> " + lastCeresInfo?.PVString + " OTHER " + comparisonEngine?.UCIInfo?.RawString); int numCharactersSame = int.MaxValue; if (lastCeresInfo?.PVString != null || comparisonEngine?.UCIInfo?.RawString != null) { if (lastCeresInfo != null && comparisonEngine?.UCIInfo != null) { numCharactersSame = 0; string pv1 = lastCeresInfo.PVString; UCISearchInfo lastComparisonInfo = comparisonEngine.UCIInfo; string pv2 = lastComparisonInfo.PVString; while (pv1.Length > numCharactersSame && pv2.Length > numCharactersSame && pv1[numCharactersSame] == pv2[numCharactersSame]) { numCharactersSame++; } } } if (lastCeresInfo != null) { WriteUCI("Ceres", lastCeresInfo, numCharactersSame); } if (comparisonEngine != null) { WriteUCI(comparisonEngine.ID, comparisonEngine.UCIInfo, numCharactersSame); } Console.WriteLine(); } searchCeres.Wait(); searchComparison?.Wait(); string infoUpdate = UCIInfo.UCIInfoString(ceresResults.Manager); double q2 = ceresResults.SearchRootNode.Q; //SearchPrincipalVariation pv2 = new SearchPrincipalVariation(worker2.Root); MCTSPosTreeNodeDumper.DumpPV(ceresResults.SearchRootNode, true); }
/// <summary> /// Dump two sets of parameters, optionally showing only differences. /// </summary> public static void DumpParams(TextWriter writer, bool differentOnly, GameEngineUCISpec externalEngine1Spec, GameEngineUCISpec externalEngine2Spec, NNEvaluatorDef evaluatorDef1, NNEvaluatorDef evaluatorDef2, SearchLimit searchLimit1, SearchLimit searchLimit2, ParamsSelect selectParams1, ParamsSelect selectParams2, ParamsSearch searchParams1, ParamsSearch searchParams2, IManagerGameLimit timeManager1, IManagerGameLimit timeManager2, ParamsSearchExecution paramsSearchExecution1, ParamsSearchExecution paramsSearchExecution2) { writer.WriteLine("\r\n-----------------------------------------------------------------------"); writer.WriteLine("ENGINE 1 Options Modifications from Default"); if (evaluatorDef1 != null) { writer.WriteLine("Ceres Evaluator : " + evaluatorDef1.ToString()); } else { writer.Write("External UCI : " + externalEngine1Spec); } writer.Write(ObjUtils.FieldValuesDumpString <SearchLimit>(searchLimit1, SearchLimit.NodesPerMove(1), differentOnly)); // writer.Write(ObjUtils.FieldValuesDumpString<NNEvaluatorDef>(Def.NNEvaluators1.EvaluatorDef, new ParamsNN(), differentOnly)); writer.Write(ObjUtils.FieldValuesDumpString <ParamsSelect>(selectParams1, new ParamsSelect(), differentOnly)); writer.Write(ObjUtils.FieldValuesDumpString <ParamsSearch>(searchParams1, new ParamsSearch(), differentOnly)); DumpTimeManagerDifference(true, null, timeManager1); writer.Write(ObjUtils.FieldValuesDumpString <ParamsSearchExecution>(paramsSearchExecution1, new ParamsSearchExecution(), differentOnly)); writer.WriteLine("\r\n-----------------------------------------------------------------------"); writer.WriteLine("ENGINE 2 Options Modifications from Engine 1"); bool evaluatorsDifferent = false; bool eval2TypeDifferent = (evaluatorDef1 == null) != (evaluatorDef2 == null); if (eval2TypeDifferent) { evaluatorsDifferent = true; } else { if (evaluatorDef1 != null) { evaluatorsDifferent = evaluatorDef1.ToString() != evaluatorDef2.ToString(); } else { evaluatorsDifferent = externalEngine1Spec.ToString() != externalEngine2Spec.ToString(); } } if (!differentOnly || evaluatorsDifferent) { if (evaluatorDef1 != null && evaluatorDef2 != null) { writer.WriteLine("Ceres Evaluator : " + evaluatorDef2.ToString()); } else { writer.Write("External UCI : " + externalEngine2Spec); } } if (searchLimit2 != null) { writer.Write(ObjUtils.FieldValuesDumpString <SearchLimit>(searchLimit2, searchLimit1, differentOnly)); // writer.Write(ObjUtils.FieldValuesDumpString<NNEvaluatorDef>(Def.NNEvaluators1.EvaluatorDef, Def.NNEvaluators2.EvaluatorDef, differentOnly)); writer.Write(ObjUtils.FieldValuesDumpString <ParamsSelect>(selectParams2, selectParams1, differentOnly)); writer.Write(ObjUtils.FieldValuesDumpString <ParamsSearch>(searchParams2, searchParams1, differentOnly)); DumpTimeManagerDifference(differentOnly, timeManager1, timeManager2); writer.Write(ObjUtils.FieldValuesDumpString <ParamsSearchExecution>(paramsSearchExecution2, paramsSearchExecution1, differentOnly)); } }
/// <summary> /// Returns the executable location and program arguments appropriate /// for LC0 given specified Ceres parameters /// (optionally emulating them to the degree possible). /// </summary> /// <param name="paramsSearch"></param> /// <param name="paramsSelect"></param> /// <param name="evaluatorDef"></param> /// <param name="network"></param> /// <param name="emulateCeresOptions"></param> /// <param name="verboseOutput"></param> /// <param name="overrideEXE"></param> /// <param name="forceDisableSmartPruning"></param> /// <param name="alwaysFillHistory"></param> /// <returns></returns> public static (string, string) GetLC0EngineOptions(ParamsSearch paramsSearch, ParamsSelect paramsSelect, NNEvaluatorDef evaluatorDef, INNWeightsFileInfo network, bool emulateCeresOptions, bool verboseOutput, string overrideEXE = null, bool forceDisableSmartPruning = false, bool alwaysFillHistory = false) { if (paramsSearch == null) { paramsSearch = new ParamsSearch(); } if (paramsSelect == null) { paramsSelect = new ParamsSelect(); } //fail int8 string precisionStr = MCTSParams.PRECISION == WFEvalNetTensorRT.TRTPrecision.Int8 ? "trt-int8" : "cudnn-fp16"; // Must reverse values to conform to LZ0 convention float FPU_MULTIPLIER = paramsSelect.FPUMode == ParamsSelect.FPUType.Reduction ? -1.0f : 1.0f; // TODO: plug in both versions of Centiapwn to low level Leela code string fpuVals = $"--fpu-value={FPU_MULTIPLIER * paramsSelect.FPUValue} --fpu-value-at-root={FPU_MULTIPLIER * paramsSelect.FPUValueAtRoot} "; string strategyStr = paramsSelect.FPUMode == ParamsSelect.FPUType.Absolute ? "absolute " : "reduction "; string fpuStr = fpuVals + "--fpu-strategy=" + strategyStr; string strategyAtRootStr = paramsSelect.FPUModeAtRoot == ParamsSelect.FPUType.Absolute ? "absolute " : "reduction "; string fpuStrRoot = paramsSelect.FPUModeAtRoot == ParamsSelect.FPUType.Same ? "--fpu-strategy-at-root=same " : "--fpu-strategy-at-root=" + strategyAtRootStr; string netSourceFile = network.FileName; int minibatchSize = 256; // LC0 default // If GPUs have equal fractions then we use demux where only 2 threads needed, // otherwise we use roundrobin and best is 1 + number of GPUS // Note that with increasing threads Leela plays significantly non-deterministically and somewhat worse int NUM_THREADS = evaluatorDef.EqualFractions ? 2 : evaluatorDef.Devices.Length + 1; string lzOptions = "--nodes-as-playouts "; // essential to get same behavior as Ceres with go nodes command lzOptions += "--multi-gather "; // greatly improves search speed if (forceDisableSmartPruning || (emulateCeresOptions && !paramsSearch.FutilityPruningStopSearchEnabled)) { lzOptions += " --smart-pruning-factor=0 "; } // Default nncache is only 200_000 but big tournaments (TCEC 19) have used as high as 20_000_000. // To keep memory requires reasonable for typical systems we default to a value in between. // However note that for very small nets such as 128x10 it may be faster to uze zero nncache. const int LC0_CACHE_SIZE = 5_000_000; int MOVE_OVERHEAD = (int)(new ParamsSearch().MoveOverheadSeconds * 1000); lzOptions += $"--move-overhead={MOVE_OVERHEAD} "; if (USE_LC0_SMALL_SEARCH_SETTINGS) { // Works better for smaller searchs (such as 1000 nodes) lzOptions += " --max-collision-visits=32 "; } else { // Much faster for large searches with multigather enabled. lzOptions += " --max-out-of-order-evals-factor=2.4 --max-collision-events=500 --max-collision-visits=500 "; } if (alwaysFillHistory) { lzOptions += $" --history-fill=always "; } if (emulateCeresOptions) { bool useNNCache = evaluatorDef.CacheMode > PositionEvalCache.CacheMode.None || paramsSearch.Execution.TranspositionMode > TranspositionMode.None; int cacheSize = useNNCache ? LC0_CACHE_SIZE : 0; lzOptions += $@"-w {netSourceFile} -t {NUM_THREADS} --minibatch-size={minibatchSize} " + // " --policy-softmax-temp=2.2 --backend=cudnn-fp16 "; $" --policy-softmax-temp={paramsSelect.PolicySoftmax} --cache-history-length={evaluatorDef.NumCacheHashPositions - 1} " + // $" --score-type=win_percentage" + BackendArgumentsString(evaluatorDef) + //"--backend=multiplexing --backend-opts=(backend=cudnn-fp16,gpu=0),(backend=cudnn-fp16,gpu=1),(backend=cudnn-fp16,gpu=2),(backend=cudnn-fp16,gpu=3) " + // $"--backend={precisionStr} --backend-opts=gpu={SearchParamsNN.GPU_ID_LEELA_UCI} " + $"{fpuStr} {fpuStrRoot} " + $" --no-sticky-endgames "; // + --no-out-of-order-eval"; // *** NOTE: if we add this flag, LZ0 seems to play a little different and better. TODO: study this, should we adopt? lzOptions += $" --cpuct-factor={paramsSelect.CPUCTFactor} --cpuct-base={paramsSelect.CPUCTBase} --cpuct={paramsSelect.CPUCT} --nncache={cacheSize} "; // lzOptions += $" --max-collision-visits={paramsSearch.MAX_COLLISIONS + 1 }"; // Must increment by 1 to make comparable (also, LC0 hangs at value ot zero) } else { // Mostly we let Leela use default options, except to make it fair // we use a large nncache and number of threads appropriate for the number of GPUs in use // lzOptions = $@"-w {weightsDir}\{netSourceFile} --minibatch-size={minibatchSize} -t {paramsNN.NNEVAL_NUM_GPUS + 1} " + lzOptions += $@"-w {netSourceFile} -t {NUM_THREADS} " + // $"--score-type=win_percentage " + $"--nncache={LC0_CACHE_SIZE} " + // like TCEC 10, only 5% benefit $"--max-prefetch=160 --max-collision-events=917 " + BackendArgumentsString(evaluatorDef); } string tbPath = CeresUserSettingsManager.Settings.TablebaseDirectory; if (paramsSearch.EnableTablebases) { lzOptions += (@$ " --syzygy-paths=#{tbPath}# ").Replace("#", "\""); } if (verboseOutput) { lzOptions += " --verbose-move-stats "; } string EXE = CeresUserSettingsManager.GetLC0ExecutableFileName(); #if EXPERIMENTAL const bool LZ_USE_TRT = false; // NOTE: if true, the GPU is seemingly currently hardcoded to 3. The max batch size is 512 if (LZ_USE_TRT) { if (network.NetworkID == "59999") { EXE = @"C:\dev\lc0\19May\lc0\build\lc0_59999.exe"; } else if (network.NetworkID == "42767") { EXE = @"C:\dev\lc0\19May\lc0\build\lc0_42767.exe"; } else { throw new Exception("Unknown net for EXE " + network.NetworkID); } if (evaluatorDef.Nets[0].Net.Precision == NNEvaluatorPrecision.Int8) { lzOptions = lzOptions.Replace("cudnn-fp16", "trt-int8"); } else if (evaluatorDef.Nets[0].Net.Precision == NNEvaluatorPrecision.FP16) { lzOptions = lzOptions.Replace("cudnn-fp16", "trt-fp16"); } else { throw new NotImplementedException(); } } #endif if (overrideEXE != null) { EXE = overrideEXE; } return(EXE, lzOptions); }
/// <summary> /// Constructor. /// </summary> /// <param name="store"></param> /// <param name="nnParams"></param> /// <param name="searchParams"></param> /// <param name="childSelectParams"></param> /// <param name="priorMoves">if null, the prior moves are taken from the passed store</param> /// <param name="searchLimit"></param> public MCTSManager(MCTSNodeStore store, MCTSIterator reuseOtherContextForEvaluatedNodes, PositionEvalCache reusePositionCache, TranspositionRootsDict reuseTranspositionRoots, NNEvaluatorSet nnEvaluators, ParamsSearch searchParams, ParamsSelect childSelectParams, SearchLimit searchLimit, ParamsSearchExecutionModifier paramsSearchExecutionPostprocessor, IManagerGameLimit timeManager, DateTime startTime, MCTSManager priorManager, List <GameMoveStat> gameMoveHistory, bool isFirstMoveOfGame) { StartTimeThisSearch = startTime; RootNWhenSearchStarted = store.Nodes.nodes[store.RootIndex.Index].N; ParamsSearchExecutionPostprocessor = paramsSearchExecutionPostprocessor; IsFirstMoveOfGame = isFirstMoveOfGame; PriorMoveStats = new List <GameMoveStat>(); // Make our own copy of move history. if (gameMoveHistory != null) { PriorMoveStats.AddRange(gameMoveHistory); } // Possibly convert time limit per game into time for this move. if (searchLimit.IsPerGameLimit) { SearchLimitType type = searchLimit.Type == SearchLimitType.SecondsForAllMoves ? SearchLimitType.SecondsPerMove : SearchLimitType.NodesPerMove; float rootQ = priorManager == null ? float.NaN : (float)store.RootNode.Q; ManagerGameLimitInputs timeManagerInputs = new(store.Nodes.PriorMoves.FinalPosition, searchParams, PriorMoveStats, type, store.RootNode.N, rootQ, searchLimit.Value, searchLimit.ValueIncrement, float.NaN, float.NaN, maxMovesToGo : searchLimit.MaxMovesToGo, isFirstMoveOfGame : isFirstMoveOfGame); ManagerGameLimitOutputs timeManagerOutputs = timeManager.ComputeMoveAllocation(timeManagerInputs); SearchLimit = timeManagerOutputs.LimitTarget; } else { SearchLimit = searchLimit; } // Possibly autoselect new optimal parameters ParamsSearchExecutionChooser paramsChooser = new ParamsSearchExecutionChooser(nnEvaluators.EvaluatorDef, searchParams, childSelectParams, searchLimit); // TODO: technically this is overwriting the params belonging to the prior search, that's ugly (but won't actually cause a problem) paramsChooser.ChooseOptimal(searchLimit.EstNumNodes(50_000), paramsSearchExecutionPostprocessor); // TODO: make 50_000 smarter int estNumNodes = EstimatedNumSearchNodesForEvaluator(searchLimit, nnEvaluators); // Adjust the nodes estimate if we are continuing an existing search if (searchLimit.Type == SearchLimitType.NodesPerMove && RootNWhenSearchStarted > 0) { estNumNodes = Math.Max(0, estNumNodes - RootNWhenSearchStarted); } Context = new MCTSIterator(store, reuseOtherContextForEvaluatedNodes, reusePositionCache, reuseTranspositionRoots, nnEvaluators, searchParams, childSelectParams, searchLimit, estNumNodes); ThreadSearchContext = Context; TerminationManager = new MCTSFutilityPruning(this, Context); LimitManager = timeManager; CeresEnvironment.LogInfo("MCTS", "Init", $"SearchManager created for store {store}", InstanceID); }