simple ai testing
This commit is contained in:
1 parent
dbe4011ab6
commit
e74d7c7166
4 files changed
+79
-17
No files matched your search
@@ -80,7 +80,7 @@ maxVisits = 500
|
||||
# But there's no substitute for experimenting and seeing what's best for your hardware and your usage case.
|
||||
# Keep in mind that the number of threads you want doesn't necessarily have much to do with how many cores you
|
||||
# have on your system, and could easily exceed the number of cores. GPU batching is (usually) the dominant consideration.
|
||||
numSearchThreads = 8
|
||||
numSearchThreads = 1
|
||||
|
||||
# nnMaxBatchSize is the max number of positions to send to a single GPU at once. Generally, it should be the case that:
|
||||
# (number of GPUs you will use * nnMaxBatchSize) >= (numSearchThreads * num-analysis-threads)
|
||||
@@ -109,6 +109,7 @@ nnMaxBatchSize = 96
|
||||
|
||||
# Other General GPU Settings-------------------------------------------------------------------------------
|
||||
|
||||
|
||||
# Cache up to 2 ** this many neural net evaluations in case of transpositions in the tree.
|
||||
nnCacheSizePowerOfTwo = 20
|
||||
# Size of mutex pool for nnCache is 2 ** this
|
||||
@@ -116,7 +117,6 @@ nnMutexPoolSizePowerOfTwo = 16
|
||||
# Randomize board orientation when running neural net evals?
|
||||
nnRandomize = true
|
||||
|
||||
|
||||
# TO USE MULTIPLE GPUS:
|
||||
# Set this to the number of GPUs you have and/or would like to use...
|
||||
# AND if it is more than 1, uncomment the appropriate CUDA or OpenCL section below.
|
||||
|
||||
+5
-1
@@ -17,7 +17,7 @@
|
||||
"anim_pv_time": 0.5,
|
||||
"debug_level": 0,
|
||||
"lang": "en",
|
||||
"version": "1.5.0"
|
||||
"version": "1.5.1"
|
||||
},
|
||||
"timer": {
|
||||
"byo_length": 30,
|
||||
@@ -88,6 +88,10 @@
|
||||
"ai:policy": {
|
||||
"opening_moves": 22.0
|
||||
},
|
||||
"ai:simple": {
|
||||
"max_points_lost": 2.0,
|
||||
"settled_weight": 1.0
|
||||
},
|
||||
"ai:p:weighted": {
|
||||
"weaken_fac": 1.25,
|
||||
"pick_override": 1.0,
|
||||
|
||||
+63
-11
@@ -8,29 +8,31 @@ from katrain.core.constants import (
|
||||
AI_DEFAULT,
|
||||
AI_HANDICAP,
|
||||
AI_INFLUENCE,
|
||||
AI_INFLUENCE_ELO_GRID,
|
||||
AI_JIGO,
|
||||
AI_LOCAL,
|
||||
AI_LOCAL_ELO_GRID,
|
||||
AI_PICK,
|
||||
AI_PICK_ELO_GRID,
|
||||
AI_POLICY,
|
||||
AI_RANK,
|
||||
AI_SCORELOSS,
|
||||
AI_SCORELOSS_ELO,
|
||||
AI_SIMPLE,
|
||||
AI_SIMPLE_OWNERSHIP,
|
||||
AI_STRATEGIES_PICK,
|
||||
AI_STRATEGIES_POLICY,
|
||||
AI_STRENGTH,
|
||||
AI_TENUKI,
|
||||
AI_TENUKI_ELO_GRID,
|
||||
AI_TERRITORY,
|
||||
AI_TERRITORY_ELO_GRID,
|
||||
AI_WEIGHTED,
|
||||
AI_WEIGHTED_ELO,
|
||||
CALIBRATED_RANK_ELO,
|
||||
OUTPUT_DEBUG,
|
||||
OUTPUT_ERROR,
|
||||
OUTPUT_INFO,
|
||||
AI_WEIGHTED_ELO,
|
||||
AI_SCORELOSS_ELO,
|
||||
CALIBRATED_RANK_ELO,
|
||||
AI_LOCAL_ELO_GRID,
|
||||
AI_TENUKI_ELO_GRID,
|
||||
AI_TERRITORY_ELO_GRID,
|
||||
AI_INFLUENCE_ELO_GRID,
|
||||
AI_PICK_ELO_GRID,
|
||||
)
|
||||
from katrain.core.game import Game, GameNode, Move
|
||||
from katrain.core.utils import var_to_grid
|
||||
@@ -168,7 +170,7 @@ def request_ai_analysis(game: Game, cn: GameNode, extra_settings: Dict) -> Optio
|
||||
|
||||
def set_error(a):
|
||||
nonlocal error
|
||||
game.katrain.log("Error in PDA-based analysis", a)
|
||||
game.katrain.log(f"Error in additional analysis query: {a}")
|
||||
error = True
|
||||
|
||||
engine = game.engines[cn.player]
|
||||
@@ -203,6 +205,13 @@ def generate_ai_move(game: Game, ai_mode: str, ai_settings: Dict) -> Tuple[Move,
|
||||
game.katrain.log(f"Error getting handicap-based move", OUTPUT_ERROR)
|
||||
ai_mode = AI_DEFAULT
|
||||
|
||||
if ai_mode == AI_SIMPLE:
|
||||
simple_moves = ai_settings["simple_moves"]
|
||||
simple_analysis = request_ai_analysis(game, cn, {"simpleMovesBias": simple_moves, "wideRootNoise": 0.10})
|
||||
if not simple_analysis:
|
||||
game.katrain.log(f"Error getting simple-biased move", OUTPUT_ERROR)
|
||||
ai_mode = AI_DEFAULT
|
||||
|
||||
while not cn.analysis_ready:
|
||||
time.sleep(0.01)
|
||||
game.engines[cn.next_player].check_alive(exception_if_dead=True)
|
||||
@@ -326,9 +335,25 @@ def generate_ai_move(game: Game, ai_mode: str, ai_settings: Dict) -> Tuple[Move,
|
||||
candidate_ai_moves = cn.candidate_moves
|
||||
if ai_mode == AI_HANDICAP:
|
||||
candidate_ai_moves = handicap_analysis["moveInfos"]
|
||||
if ai_mode == AI_SIMPLE:
|
||||
candidate_ai_moves = simple_analysis["moveInfos"]
|
||||
for data in candidate_ai_moves:
|
||||
print(
|
||||
"{order} {move}: visits {visits} utility {util} utilityLcb {lcb}".format(
|
||||
visits=data["visits"],
|
||||
order=data["order"],
|
||||
move=data["move"],
|
||||
util=data["utility"],
|
||||
lcb=data["utilityLcb"],
|
||||
)
|
||||
)
|
||||
|
||||
top_cand = Move.from_gtp(candidate_ai_moves[0]["move"], player=cn.next_player)
|
||||
if top_cand.is_pass and ai_mode not in [AI_DEFAULT, AI_HANDICAP]: # don't play suicidal to balance score
|
||||
if top_cand.is_pass and ai_mode not in [
|
||||
AI_DEFAULT,
|
||||
AI_HANDICAP,
|
||||
AI_SIMPLE,
|
||||
]: # don't play suicidal to balance score
|
||||
aimove = top_cand
|
||||
ai_thoughts += f"Top move is pass, so passing regardless of strategy. "
|
||||
else:
|
||||
@@ -352,13 +377,40 @@ def generate_ai_move(game: Game, ai_mode: str, ai_settings: Dict) -> Tuple[Move,
|
||||
topmove = weighted_selection_without_replacement(moves, 1)[0]
|
||||
aimove = topmove[2]
|
||||
ai_thoughts += f"ScoreLoss strategy found {len(candidate_ai_moves)} candidate moves (best {top_cand.gtp()}) and chose {aimove.gtp()} (weight {topmove[1]:.3f}, point loss {topmove[0]:.1f}) based on score weights."
|
||||
elif ai_mode == AI_SIMPLE_OWNERSHIP:
|
||||
|
||||
def settledness(d):
|
||||
return sum([abs(o) for o in d["ownership"]])
|
||||
|
||||
moves_with_settledness = sorted(
|
||||
[
|
||||
(Move.from_gtp(d["move"], player=cn.next_player), settledness(d), d)
|
||||
for d in candidate_ai_moves
|
||||
if d["pointsLost"] < ai_settings["max_points_lost"] and "ownership" in d
|
||||
],
|
||||
key=lambda t: t[2]["pointsLost"] - ai_settings["settled_weight"] * t[1],
|
||||
)
|
||||
if moves_with_settledness:
|
||||
cands = [
|
||||
f"{move.gtp()} ({d['pointsLost']:.1f} pt lost, {settled:.1f} settledness)"
|
||||
for move, settled, d in moves_with_settledness
|
||||
]
|
||||
ai_thoughts += f"Simple ownership strategy. Candidates {', '.join(cands)} "
|
||||
aimove = moves_with_settledness[0][0]
|
||||
else:
|
||||
if ai_mode not in [AI_DEFAULT, AI_HANDICAP]:
|
||||
game.katrain.log(
|
||||
"No moves found - are you using an older KataGo with no per-move ownership info?", OUTPUT_ERROR
|
||||
)
|
||||
aimove = top_cand
|
||||
else:
|
||||
if ai_mode not in [AI_DEFAULT, AI_HANDICAP, AI_SIMPLE]:
|
||||
game.katrain.log(f"Unknown AI mode {ai_mode} or policy missing, using default.", OUTPUT_INFO)
|
||||
ai_thoughts += f"Strategy {ai_mode} not found or unexpected fallback."
|
||||
aimove = top_cand
|
||||
if ai_mode == AI_HANDICAP:
|
||||
ai_thoughts += f"Handicap strategy found {len(candidate_ai_moves)} moves returned from the engine and chose {aimove.gtp()} as top move. PDA based score {cn.format_score(handicap_analysis['rootInfo']['scoreLead'])} and win rate {cn.format_winrate(handicap_analysis['rootInfo']['winrate'])}"
|
||||
elif ai_mode == AI_SIMPLE:
|
||||
ai_thoughts += f"Simple moves strategy found {len(candidate_ai_moves)} moves returned from the engine and chose {aimove.gtp()} as top move. "
|
||||
else:
|
||||
ai_thoughts += f"Default strategy found {len(candidate_ai_moves)} moves returned from the engine and chose {aimove.gtp()} as top move"
|
||||
game.katrain.log(f"AI thoughts: {ai_thoughts}", OUTPUT_DEBUG)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
VERSION = "1.5.0"
|
||||
VERSION = "1.5.1"
|
||||
HOMEPAGE = "https://github.com/sanderland/katrain"
|
||||
CONFIG_MIN_VERSION = "1.4.0" # keep config files from this version
|
||||
CONFIG_MIN_VERSION = "1.5.1" # keep config files from this version
|
||||
|
||||
OUTPUT_ERROR = -1
|
||||
OUTPUT_KATAGO_STDERR = -0.5
|
||||
@@ -33,16 +33,19 @@ AI_TENUKI = "ai:p:tenuki"
|
||||
AI_INFLUENCE = "ai:p:influence"
|
||||
AI_TERRITORY = "ai:p:territory"
|
||||
AI_RANK = "ai:p:rank"
|
||||
AI_SIMPLE = "ai:disabled"
|
||||
AI_SIMPLE_OWNERSHIP = "ai:simple"
|
||||
|
||||
AI_CONFIG_DEFAULT = AI_RANK
|
||||
|
||||
AI_STRATEGIES_ENGINE = [AI_DEFAULT, AI_HANDICAP, AI_SCORELOSS, AI_JIGO]
|
||||
AI_STRATEGIES_ENGINE = [AI_DEFAULT, AI_HANDICAP, AI_SIMPLE, AI_SCORELOSS, AI_JIGO]
|
||||
AI_STRATEGIES_PICK = [AI_PICK, AI_LOCAL, AI_TENUKI, AI_INFLUENCE, AI_TERRITORY, AI_RANK]
|
||||
AI_STRATEGIES_POLICY = [AI_WEIGHTED, AI_POLICY] + AI_STRATEGIES_PICK
|
||||
AI_STRATEGIES = AI_STRATEGIES_ENGINE + AI_STRATEGIES_POLICY
|
||||
AI_STRATEGIES_RECOMMENDED_ORDER = [
|
||||
AI_DEFAULT,
|
||||
AI_RANK,
|
||||
AI_SIMPLE_OWNERSHIP,
|
||||
AI_HANDICAP,
|
||||
AI_SCORELOSS,
|
||||
AI_POLICY,
|
||||
@@ -67,6 +70,7 @@ AI_STRENGTH = { # dan ranks, backup if model is missing. TODO: remove some?
|
||||
AI_INFLUENCE: -7,
|
||||
AI_TERRITORY: -7,
|
||||
AI_RANK: float("nan"),
|
||||
AI_SIMPLE_OWNERSHIP: 9,
|
||||
}
|
||||
|
||||
AI_OPTION_VALUES = {
|
||||
@@ -85,6 +89,8 @@ AI_OPTION_VALUES = {
|
||||
"threshold": [2, 2.5, 3, 3.5, 4, 4.5],
|
||||
"automatic": "bool",
|
||||
"pda": [(x / 10, f"{'W' if x<0 else 'B'}+{abs(x/10):.1f}") for x in range(-30, 31)],
|
||||
"max_points_lost": [x/10 for x in range(51)],
|
||||
"settled_weight": [x/10 for x in range(-100,101)],
|
||||
}
|
||||
AI_KEY_PROPERTIES = {"kyu_rank", "strength", "weaken_fac", "pick_frac", "pick_n", "automatic"}
|
||||
|
||||
|
||||
Reference in new issue
Block a user