ai selfplay, black 120

This commit is contained in:
Sander Land committed 2020-05-30 23:33:10 +02:00
1 parent 06cc316326
commit 9c6d521a88
16 files changed
+566 -134

No files matched your search

+90 -18
View File
@@ -21,7 +21,9 @@ class GameNode(SGFNode):
self.move_number = 0
self.time_used = 0
self.analysis_visits_requested = 0
self.undo_threshold = random.random() # for fractional undos, store the random threshold in the move itself for consistency
self.undo_threshold = (
random.random()
) # for fractional undos, store the random threshold in the move itself for consistency
self._favourite_child = None
def sgf_properties(self, save_comments_player=None, save_comments_class=None, eval_thresholds=None):
@@ -30,10 +32,18 @@ class GameNode(SGFNode):
show_class = save_comments_class[evaluation_class(self.points_lost, eval_thresholds)]
else:
show_class = False
if (save_comments_player or {}).get(self.player, False) and show_class and self.analysis_ready and self.parent and self.parent.analysis_ready:
if (
(save_comments_player or {}).get(self.player, False)
and show_class
and self.analysis_ready
and self.parent
and self.parent.analysis_ready
):
candidate_moves = self.parent.candidate_moves
top_x = Move.from_gtp(candidate_moves[0]["move"]).sgf(self.board_size)
best_sq = [Move.from_gtp(d["move"]).sgf(self.board_size) for d in candidate_moves[1:] if d["pointsLost"] <= 0.5]
best_sq = [
Move.from_gtp(d["move"]).sgf(self.board_size) for d in candidate_moves[1:] if d["pointsLost"] <= 0.5
]
if best_sq and "SQ" not in properties:
properties["SQ"] = best_sq
if top_x and "MA" not in properties:
@@ -42,14 +52,21 @@ class GameNode(SGFNode):
if comment:
properties["C"] = ["\n".join(properties.get("C", "")) + comment]
if self.is_root:
properties["C"] = [i18n._("SGF start message") + "\n" + "\n".join(properties.get("C", "")) + "\nSGF with review generated by KaTrain."]
properties["C"] = [
i18n._("SGF start message")
+ "\n"
+ "\n".join(properties.get("C", ""))
+ "\nSGF with review generated by KaTrain."
]
if self.note.strip():
properties["C"] = ["\n".join(properties.get("C", "")) + f"\nNote: {self.note}"]
return properties
@staticmethod
def order_children(children):
return sorted(children, key=lambda c: 0.5 if c.auto_undo is None else int(c.auto_undo)) # analyzed/not undone main, non-teach second, undone last
return sorted(
children, key=lambda c: 0.5 if c.auto_undo is None else int(c.auto_undo)
) # analyzed/not undone main, non-teach second, undone last
def set_favourite_child(self, c):
self._favourite_child = c
@@ -66,20 +83,32 @@ class GameNode(SGFNode):
if visits and not refine_move:
self.analysis_visits_requested = max(self.analysis_visits_requested, engine.config["max_visits"])
engine.request_analysis(
self, lambda result: self.set_analysis(result, refine_move), priority=priority, visits=visits, analyze_fast=analyze_fast, time_limit=time_limit, next_move=refine_move
self,
lambda result: self.set_analysis(result, refine_move),
priority=priority,
visits=visits,
analyze_fast=analyze_fast,
time_limit=time_limit,
next_move=refine_move,
)
def update_move_analysis(self, move_analysis, move_gtp):
cur = self.analysis["moves"].get(move_gtp)
if cur is None:
self.analysis["moves"][move_gtp] = {"move": move_gtp, "order": 999, **move_analysis} # some default values for keys missing in rootInfo
self.analysis["moves"][move_gtp] = {
"move": move_gtp,
"order": 999,
**move_analysis,
} # some default values for keys missing in rootInfo
elif cur["visits"] < move_analysis["visits"]:
cur.update(move_analysis)
def set_analysis(self, analysis_json, refine_move):
if refine_move:
pvtail = analysis_json["moveInfos"][0]["pv"] if analysis_json["moveInfos"] else []
self.update_move_analysis({"pv": [refine_move.gtp()] + pvtail, **analysis_json["rootInfo"]}, refine_move.gtp())
self.update_move_analysis(
{"pv": [refine_move.gtp()] + pvtail, **analysis_json["rootInfo"]}, refine_move.gtp()
)
else:
for move_analysis in analysis_json["moveInfos"]:
self.update_move_analysis(move_analysis, move_analysis["move"])
@@ -87,8 +116,12 @@ class GameNode(SGFNode):
self.policy = analysis_json.get("policy")
self.analysis["root"] = analysis_json["rootInfo"]
if self.parent and self.move:
analysis_json["rootInfo"]["pv"] = [self.move.gtp()] + (analysis_json["moveInfos"][0]["pv"] if analysis_json["moveInfos"] else [])
self.parent.update_move_analysis(analysis_json["rootInfo"], self.move.gtp()) # update analysis in parent for consistency
analysis_json["rootInfo"]["pv"] = [self.move.gtp()] + (
analysis_json["moveInfos"][0]["pv"] if analysis_json["moveInfos"] else []
)
self.parent.update_move_analysis(
analysis_json["rootInfo"], self.move.gtp()
) # update analysis in parent for consistency
@property
def analysis_ready(self):
@@ -138,19 +171,44 @@ class GameNode(SGFNode):
points_lost = self.points_lost
if sgf and points_lost > 0.5:
text += i18n._("Info:point loss").format(points_lost=points_lost) + "\n"
text += i18n._("Info:top move").format(top_move=previous_top_move["move"], score=self.format_score(previous_top_move["scoreLead"])) + "\n"
text += (
i18n._("Info:top move").format(
top_move=previous_top_move["move"],
score=self.format_score(previous_top_move["scoreLead"]),
)
+ "\n"
)
else:
text += i18n._("Info:best move") + "\n"
if previous_top_move.get("pv") and (sgf or hints):
text += i18n._("Info:PV").format(pv=self.make_pv(single_move.player, previous_top_move["pv"], interactive)) + "\n"
text += (
i18n._("Info:PV").format(
pv=self.make_pv(single_move.player, previous_top_move["pv"], interactive)
)
+ "\n"
)
if sgf or hints or teach:
policy_ranking = self.parent.policy_ranking
currmove_policy_with_ix = [(ix + 1, p) for (p, m), ix in zip(policy_ranking, range(len(policy_ranking))) if m == single_move]
currmove_policy_with_ix = [
(ix + 1, p)
for (p, m), ix in zip(policy_ranking, range(len(policy_ranking)))
if m == single_move
]
if currmove_policy_with_ix:
text += i18n._("Info:policy rank").format(rank=currmove_policy_with_ix[0][0], probability=currmove_policy_with_ix[0][1]) + "\n"
text += (
i18n._("Info:policy rank").format(
rank=currmove_policy_with_ix[0][0], probability=currmove_policy_with_ix[0][1]
)
+ "\n"
)
if not currmove_policy_with_ix or currmove_policy_with_ix[0] != 1 and (sgf or hints):
text += i18n._("Info:policy best").format(move=policy_ranking[0][1].gtp(), probability=policy_ranking[0][0]) + "\n"
text += (
i18n._("Info:policy best").format(
move=policy_ranking[0][1].gtp(), probability=policy_ranking[0][0]
)
+ "\n"
)
if self.auto_undo and sgf:
text += i18n._("Info:teaching undo") + "\n"
top_pv = self.analysis_ready and self.candidate_moves[0].get("pv")
@@ -173,7 +231,13 @@ class GameNode(SGFNode):
@property
def parent_realized_points_lost(self) -> Optional[float]:
single_move = self.move
if single_move and self.parent and self.parent.parent and self.analysis_ready and self.parent.parent.analysis_ready:
if (
single_move
and self.parent
and self.parent.parent
and self.analysis_ready
and self.parent.parent.analysis_ready
):
parent_parent_score = self.parent.parent.score
score = self.score
return self.player_sign(single_move.player) * (score - parent_parent_score)
@@ -189,11 +253,19 @@ class GameNode(SGFNode):
if not self.analysis["moves"]:
polmoves = self.policy_ranking
top_polmove = polmoves[0][1] if polmoves else Move(None) # if no info at all, pass
return [{**self.analysis["root"], "pointsLost": 0, "order": 0, "move": top_polmove.gtp()}] # single visit -> go by policy/root
return [
{**self.analysis["root"], "pointsLost": 0, "order": 0, "move": top_polmove.gtp()}
] # single visit -> go by policy/root
root_score = self.analysis["root"]["scoreLead"]
move_dicts = list(self.analysis["moves"].values()) # prevent incoming analysis from causing crash
return sorted([{"pointsLost": self.player_sign(self.next_player) * (root_score - d["scoreLead"]), **d} for d in move_dicts], key=lambda d: (d["order"], d["pointsLost"]))
return sorted(
[
{"pointsLost": self.player_sign(self.next_player) * (root_score - d["scoreLead"]), **d}
for d in move_dicts
],
key=lambda d: (d["order"], d["pointsLost"]),
)
@property
def policy_ranking(self) -> Optional[List[Tuple[float, Move]]]: # return moves from highest policy value to lowest