Exemple #1
0
 def sgf_properties(self,
                    save_comments_player=None,
                    save_comments_class=None,
                    eval_thresholds=None,
                    save_analysis=False):
     properties = copy.copy(super().sgf_properties())
     note = self.note.strip()
     if save_analysis and self.analysis_complete:
         try:
             properties["KT"] = analysis_dumps(self.analysis)
         except Exception as e:
             print(f"Error in saving analysis: {e}")
     if self.points_lost and save_comments_class is not None and eval_thresholds is not None:
         show_class = save_comments_class[evaluation_class(
             self.points_lost, eval_thresholds)]
     else:
         show_class = False
     comments = properties.get("C", [])
     if (self.parent and self.parent.analysis_exists
             and self.analysis_exists and
         (note or ((save_comments_player or {}).get(self.player, False)
                   and show_class))):
         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
         ]
         if best_sq and "SQ" not in properties:
             properties["SQ"] = best_sq
         if top_x and "MA" not in properties:
             properties["MA"] = [top_x]
         comments.append(
             self.comment(sgf=True, interactive=False) +
             SGF_INTERNAL_COMMENTS_MARKER)
     if self.is_root:
         comments = [
             i18n._("SGF start message") + SGF_INTERNAL_COMMENTS_MARKER +
             "\n",
             *comments,
             f"\nSGF generated by {PROGRAM_NAME} {VERSION}{SGF_INTERNAL_COMMENTS_MARKER}\n",
         ]
         properties["CA"] = ["UTF-8"]
         properties["AP"] = [f"{PROGRAM_NAME}:{VERSION}"]
     if self.shortcut_from:
         properties["KTSF"] = [id(self.shortcut_from)]
     elif "KTSF" in properties:
         del properties["KTSF"]
     if self.shortcuts_to:
         properties["KTSID"] = [id(self)]
     elif "KTSID" in properties:
         del properties["KTSID"]
     if note:
         comments.append(f"{self.note}")
     if comments:
         properties["C"] = [SGF_SEPARATOR_MARKER.join(comments)]
     elif "C" in properties:
         del properties["C"]
     return properties
Exemple #2
0
 def eval_color(
         self,
         points_lost,
         show_dots_for_class: List[bool] = None) -> Optional[List[float]]:
     i = evaluation_class(points_lost,
                          self.trainer_config["eval_thresholds"])
     if show_dots_for_class is None or show_dots_for_class[i]:
         return EVAL_COLORS[i]
Exemple #3
0
 def sgf_properties(self,
                    save_comments_player=None,
                    save_comments_class=None,
                    eval_thresholds=None):
     properties = copy.copy(super().sgf_properties())
     note = self.note.strip()
     if self.points_lost and save_comments_class is not None and eval_thresholds is not None:
         show_class = save_comments_class[evaluation_class(
             self.points_lost, eval_thresholds)]
     else:
         show_class = False
     if (self.parent and self.parent.analysis_ready and self.analysis_ready
             and (note or
                  ((save_comments_player or {}).get(self.player, False)
                   and show_class))):
         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
         ]
         if best_sq and "SQ" not in properties:
             properties["SQ"] = best_sq
         if top_x and "MA" not in properties:
             properties["MA"] = [top_x]
         comment = self.comment(sgf=True, interactive=False)
         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."
         ]
     if note:
         properties["C"] = [
             "\n".join(properties.get("C", "")) + f"\nNote: {self.note}"
         ]
     return properties
Exemple #4
0
def game_report(game, thresholds, depth_filter=None):
    cn = game.current_node
    nodes = cn.nodes_from_root
    while cn.children:  # main branch
        cn = cn.children[0]
        nodes.append(cn)

    x, y = game.board_size
    depth_filter = [
        math.ceil(board_frac * x * y)
        for board_frac in depth_filter or (0, 1e9)
    ]
    nodes = [
        n for n in nodes if n.move and not n.is_root
        and depth_filter[0] <= n.depth < depth_filter[1]
    ]
    histogram = [{"B": 0, "W": 0} for _ in thresholds]
    ai_top_move_count = {"B": 0, "W": 0}
    ai_approved_move_count = {"B": 0, "W": 0}
    player_ptloss = {"B": [], "W": []}
    weights = {"B": [], "W": []}

    for n in nodes:
        points_lost = n.points_lost
        if n.points_lost is None:
            continue
        else:
            points_lost = max(0, points_lost)
        bucket = len(thresholds) - 1 - evaluation_class(
            points_lost, thresholds)
        player_ptloss[n.player].append(points_lost)
        histogram[bucket][n.player] += 1
        cands = n.parent.candidate_moves
        filtered_cands = [
            d for d in cands
            if d["order"] < ADDITIONAL_MOVE_ORDER and "prior" in d
        ]
        weight = min(
            1.0,
            sum([max(d["pointsLost"], 0) * d["prior"]
                 for d in filtered_cands]) /
            (sum(d["prior"] for d in filtered_cands) or 1e-6),
        )  # complexity capped at 1
        # adj_weight between 0.05 - 1, dependent on difficulty and points lost
        adj_weight = max(0.05, min(1.0, max(weight, points_lost / 4)))
        weights[n.player].append((weight, adj_weight))
        if n.parent.analysis_complete:
            ai_top_move_count[n.player] += int(
                cands[0]["move"] == n.move.gtp())
            ai_approved_move_count[n.player] += int(n.move.gtp() in [
                d["move"] for d in filtered_cands if d["order"] == 0 or (
                    d["pointsLost"] < 0.5 and d["order"] < 5)
            ])

    wt_loss = {
        bw: sum(s * aw for s, (w, aw) in zip(player_ptloss[bw], weights[bw])) /
        (sum(aw for _, aw in weights[bw]) or 1e-6)
        for bw in "BW"
    }
    sum_stats = {
        bw: {
            "accuracy": 100 * 0.75**wt_loss[bw],
            "complexity": sum(w for w, aw in weights[bw]) /
            len(player_ptloss[bw]),
            "mean_ptloss": sum(player_ptloss[bw]) / len(player_ptloss[bw]),
            "weighted_ptloss": wt_loss[bw],
            "ai_top_move": ai_top_move_count[bw] / len(player_ptloss[bw]),
            "ai_top5_move": ai_approved_move_count[bw] /
            len(player_ptloss[bw]),
        } if len(player_ptloss[bw]) > 0 else {}
        for bw in "BW"
    }
    return sum_stats, histogram, player_ptloss