stuff
This commit is contained in:
1 parent
8171a6d5fd
commit
39556ad690
9 files changed
+64
-50
No files matched your search
+2
-2
@@ -1,7 +1,7 @@
|
||||
# additions
|
||||
KataGoData
|
||||
KataGo/KataGoData
|
||||
old
|
||||
experiments
|
||||
.idea
|
||||
gtp.log
|
||||
*.zip
|
||||
@@ -14,7 +14,7 @@ my
|
||||
outdated_log.txt
|
||||
|
||||
# too big
|
||||
models/b20*.gz
|
||||
models/*.bin.gz
|
||||
|
||||
# standard python ignore
|
||||
# Byte-compiled / optimized / DLL files
|
||||
|
||||
@@ -1,14 +1,18 @@
|
||||
[x] Player button to black/white with AI style spinner
|
||||
[] Multi engine (detect all req. analysis in analysis[engine] fn)
|
||||
[] Non square boards
|
||||
[] Polish graph
|
||||
[x Non square boards
|
||||
[x] remove fast -> in settings?
|
||||
[x] Polish graph
|
||||
|
||||
[] Multi engine (detect all req. analysis in analysis[engine] fn)
|
||||
[] Graph is awkward when reviewing. Should we store nodes rather than values? & populate on new game.
|
||||
|
||||
[] Score instead of game end
|
||||
[] Self-play tournaments?
|
||||
[] List edit settings/object edit settings?
|
||||
[] README
|
||||
[] Release notes
|
||||
[] remove button disable code?
|
||||
|
||||
|
||||
|
||||
[] BoxLayout padding/spacing use instead of fiddling?
|
||||
|
||||
|
||||
+2
-1
@@ -15,7 +15,8 @@
|
||||
"init_size": 19,
|
||||
"komi_19": 6.5,
|
||||
"komi_13": 6.5,
|
||||
"komi_9": 6.5
|
||||
"komi_9": 6.5,
|
||||
"sweep_visits_frac": 0.2
|
||||
},
|
||||
"trainer": {
|
||||
"num_undo_prompts": [1,1,1,0.5,0],
|
||||
|
||||
@@ -78,18 +78,24 @@ class KataGoEngine:
|
||||
else:
|
||||
self.katrain.log(f"Query result {analysis['id']} discarded -- recent new game?", OUTPUT_DEBUG)
|
||||
|
||||
def request_analysis(self, analysis_node: GameNode, callback: Callable, visits: int = None, priority: int = 0, ownership: Optional[bool] = None, next_move=None):
|
||||
query_id = f"QUERY:{str(self.query_counter)}"
|
||||
def send_query(self, query, callback):
|
||||
self.query_counter += 1
|
||||
if "id" not in query:
|
||||
query["id"] = f"QUERY:{str(self.query_counter)}"
|
||||
self.queries[query["id"]] = (callback, time.time())
|
||||
if self.katago_process:
|
||||
self.katrain.log(f"Sending query {query['id']}: {str(query)}", OUTPUT_DEBUG)
|
||||
self.katago_process.stdin.write((json.dumps(query) + "\n").encode())
|
||||
self.katago_process.stdin.flush()
|
||||
|
||||
def request_analysis(self, analysis_node: GameNode, callback: Callable, visits: int = None, priority: int = 0, ownership: Optional[bool] = None, next_move=None):
|
||||
moves = [m for node in analysis_node.nodes_from_root for m in node.move_with_placements]
|
||||
if next_move:
|
||||
moves.append(next_move)
|
||||
|
||||
if ownership is None:
|
||||
ownership = self.config["enable_ownership"] and not next_move
|
||||
size_x, size_y = analysis_node.board_size
|
||||
query = {
|
||||
"id": query_id,
|
||||
"rules": self.get_rules(analysis_node),
|
||||
"priority": self.base_priority + priority,
|
||||
"analyzeTurns": [len(moves)],
|
||||
@@ -101,8 +107,4 @@ class KataGoEngine:
|
||||
"includePolicy": not next_move,
|
||||
"moves": [[m.player, m.gtp()] for m in moves],
|
||||
}
|
||||
self.queries[query_id] = (callback, time.time())
|
||||
if self.katago_process:
|
||||
self.katrain.log(f"Sending query {query_id}: {str(query)}", OUTPUT_DEBUG)
|
||||
self.katago_process.stdin.write((json.dumps(query) + "\n").encode())
|
||||
self.katago_process.stdin.flush()
|
||||
self.send_query(query, callback)
|
||||
@@ -281,13 +281,13 @@ class Game:
|
||||
elif mode == "sweep":
|
||||
board_size_x, board_size_y = self.board_size
|
||||
analyze_moves = [Move(coords=(x, y), player=cn.next_player) for x in range(board_size_x) for y in range(board_size_y) if (x, y) not in stones]
|
||||
visits = self.engine.config["visits_fast"]
|
||||
visits = self.engine.config["visits"] * self.config["sweep_visits_frac"]
|
||||
self.katrain.controls.set_status(f"Refining analysis of entire board to {visits} visits")
|
||||
priority = -1_000_000_000
|
||||
else: # mode=='refine':
|
||||
analyze_moves = [Move.from_gtp(gtp, player=cn.next_player) for gtp, _ in cn.analysis["moves"].items()]
|
||||
visits = max(d["visits"] for d in cn.analysis["moves"].values()) + self.engine.config["visits_fast"]
|
||||
self.katrain.controls.set_status(f"Refining analysis of candidate moves to {visits} visits")
|
||||
visits = max(d["visits"] for d in cn.analysis["moves"].values())
|
||||
self.katrain.controls.set_status(f"Equalizing analysis of candidate moves to {visits} visits")
|
||||
priority = -1_000
|
||||
for move in analyze_moves:
|
||||
cn.analyze(self.engine, priority, visits=visits, refine_move=move)
|
||||
+7
-2
@@ -75,12 +75,17 @@ class GameNode(SGFNode):
|
||||
if self.parent and self.parent.analysis_ready:
|
||||
previous_top_move = self.parent.candidate_moves[0]
|
||||
if sgf or hints and previous_top_move["move"] != single_move.gtp(): # TODO: when to include?
|
||||
text += f"Top move was {previous_top_move['move']} ({self.format_score(previous_top_move['scoreLead'])})\n"
|
||||
text += f"Predicted top move was {previous_top_move['move']} ({self.format_score(previous_top_move['scoreLead'])})\n"
|
||||
points_lost = self.points_lost
|
||||
if sgf and points_lost > 0.5:
|
||||
text += f"Estimated point loss: {points_lost:.1f}\n"
|
||||
if sgf or hints:
|
||||
text += f"Top policy move was {self.parent.policy_ranking[0][0].gtp()}\n"
|
||||
policy_ranking = self.parent.policy_ranking
|
||||
policy_ix = [ix+1 for (m,p),ix in zip(policy_ranking,range(len(policy_ranking))) if m==single_move]
|
||||
if not policy_ix or policy_ix[0]!=1:
|
||||
text += f"Top policy move was {policy_ranking[0][0].gtp()}\n"
|
||||
if policy_ix:
|
||||
text += f"Your move was #{policy_ix} according to NN policy\n"
|
||||
if self.auto_undo:
|
||||
text += "Move was automatically undone."
|
||||
else:
|
||||
|
||||
+1
-1
@@ -69,6 +69,6 @@ class Controls(BoxLayout):
|
||||
self.show_evaluation_stats(current_node)
|
||||
|
||||
if current_node.score:
|
||||
self.graph.update_value(current_node.depth, current_node.score)
|
||||
self.graph.update_value(current_node)
|
||||
|
||||
self.info.text = info
|
||||
+15
-19
@@ -19,17 +19,6 @@ from kivy.uix.spinner import Spinner
|
||||
from kivy.uix.textinput import TextInput
|
||||
|
||||
|
||||
class CheckBoxHint(BoxLayout):
|
||||
__events__ = ("on_active",)
|
||||
|
||||
@property
|
||||
def active(self):
|
||||
return self.checkbox.active
|
||||
|
||||
def on_active(self, *args):
|
||||
pass
|
||||
|
||||
|
||||
class DarkLabel(Label):
|
||||
pass
|
||||
|
||||
@@ -173,7 +162,7 @@ class CensorableLabel(BoxLayout):
|
||||
|
||||
|
||||
class ScoreGraph(Label):
|
||||
values = ListProperty([])
|
||||
nodes = ListProperty([])
|
||||
line_points = ListProperty([])
|
||||
dot_pos = ListProperty([0, 0])
|
||||
highlighted_index = NumericProperty(None)
|
||||
@@ -182,12 +171,18 @@ class ScoreGraph(Label):
|
||||
super().__init__(**kwargs)
|
||||
Clock.schedule_once(self.on_size, 0)
|
||||
|
||||
def clear(self):
|
||||
self.values = []
|
||||
def initialize_from_game(self, root):
|
||||
self.nodes = [root]
|
||||
node = root
|
||||
while node.children:
|
||||
node = node.children[0]
|
||||
self.nodes.append(node)
|
||||
self.highlighted_index = 0
|
||||
|
||||
def on_size(self, *args):
|
||||
values = self.values
|
||||
if values:
|
||||
nodes = self.nodes
|
||||
if nodes:
|
||||
values = [n.score if n and n.score else 0 for n in nodes]
|
||||
val_range = min(values or [0]), max(values or [0])
|
||||
scale = math.ceil(max(3, max(-val_range[0], val_range[1]) * 1.05))
|
||||
|
||||
@@ -202,9 +197,10 @@ class ScoreGraph(Label):
|
||||
self.highlighted_index = min(self.highlighted_index, len(values) - 1)
|
||||
self.dot_pos = [c - self.highlight_size / 2 for c in line_points[self.highlighted_index]]
|
||||
|
||||
def update_value(self, index, value):
|
||||
self.values.extend([0] * max(0, index - (len(self.values) - 1)))
|
||||
self.values[index] = value or 0
|
||||
def update_value(self, node):
|
||||
index = node.depth
|
||||
self.nodes.extend([None] * max(0, index - (len(self.nodes) - 1)))
|
||||
self.nodes[index] = node
|
||||
self.highlighted_index = index
|
||||
self.on_size()
|
||||
|
||||
|
||||
+14
-8
@@ -19,6 +19,7 @@ from engine import KataGoEngine
|
||||
from game import Game, IllegalMoveException, KaTrainSGF, Move
|
||||
from gui import *
|
||||
from gui.popups import ConfigPopup, NewGamePopup
|
||||
from sgf_parser import ParseError
|
||||
|
||||
|
||||
class KaTrainGui(BoxLayout):
|
||||
@@ -50,7 +51,7 @@ class KaTrainGui(BoxLayout):
|
||||
config_file = sys.argv[1] if len(sys.argv) > 1 else os.path.join(base_path, "config.json")
|
||||
try:
|
||||
self.log(f"Using config file {config_file}", OUTPUT_INFO)
|
||||
self._config_store = JsonStore(config_file)
|
||||
self._config_store = JsonStore(config_file,indent=4)
|
||||
self._config = dict(self._config_store)
|
||||
except Exception as e:
|
||||
self.log(f"Failed to load config {config_file}: {e}", OUTPUT_ERROR)
|
||||
@@ -125,7 +126,7 @@ class KaTrainGui(BoxLayout):
|
||||
def _do_new_game(self, move_tree=None):
|
||||
self.game = Game(self, self.engine, self.config("game"), move_tree=move_tree)
|
||||
self.controls.select_mode("analyze" if move_tree and len(move_tree.nodes_in_tree) > 1 else "play")
|
||||
self.controls.graph.clear()
|
||||
self.controls.graph.initialize_from_game(self.game.root)
|
||||
self.update_state(redraw_board=True) # TODO: just board here/redraw is in all anyway?
|
||||
|
||||
def _do_ai_move(self, node=None):
|
||||
@@ -163,7 +164,12 @@ class KaTrainGui(BoxLayout):
|
||||
|
||||
def readfile(files, _mouse):
|
||||
fileselect_popup.dismiss()
|
||||
self._do_new_game(self, move_tree=KaTrainSGF.parse_file(files[0]))
|
||||
try:
|
||||
move_tree = KaTrainSGF.parse_file(files[0])
|
||||
except ParseError as e:
|
||||
self.log(f"Failed to load SGF. Parse Error: {e}", OUTPUT_ERROR)
|
||||
return
|
||||
self._do_new_game(move_tree=move_tree)
|
||||
|
||||
popup_contents.filesel.on_submit = readfile
|
||||
fileselect_popup.open()
|
||||
@@ -184,7 +190,7 @@ class KaTrainGui(BoxLayout):
|
||||
for pl in Move.PLAYERS:
|
||||
if not self.game.root.get_first(f"P{pl}"):
|
||||
_, model_file = os.path.split(self.engine.config["model"])
|
||||
self.game.root.properties[f"P{pl}"] = [f"KaTrain (KataGo {model_file})" if self.controls.ai_auto.active(pl) else "Player"]
|
||||
self.game.root.properties[f"P{pl}"] = [f"KaTrain (KataGo {model_file})" if 'ai' in self.controls.player_mode(pl) else "Player"]
|
||||
msg = self.game.write_sgf(self.config("files/sgf_save"))
|
||||
self.log(msg, OUTPUT_INFO)
|
||||
self.controls.set_status(msg)
|
||||
@@ -194,10 +200,10 @@ class KaTrainGui(BoxLayout):
|
||||
return # if in new game or load, don't allow keyboard shortcuts
|
||||
|
||||
shortcuts = {
|
||||
"u": self.controls.eval.checkbox,
|
||||
"i": self.controls.hints.checkbox,
|
||||
"p": self.controls.policy.checkbox,
|
||||
"o": self.controls.ownership.checkbox,
|
||||
"u": self.controls.eval,
|
||||
"i": self.controls.hints,
|
||||
"p": self.controls.policy,
|
||||
"o": self.controls.ownership,
|
||||
"a": ("ai-move",),
|
||||
"right": ("switch-branch", 1),
|
||||
"left": ("switch-branch", -1),
|
||||
|
||||
Reference in new issue
Block a user