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
|
# additions
|
||||||
KataGoData
|
KataGoData
|
||||||
KataGo/KataGoData
|
KataGo/KataGoData
|
||||||
old
|
experiments
|
||||||
.idea
|
.idea
|
||||||
gtp.log
|
gtp.log
|
||||||
*.zip
|
*.zip
|
||||||
@@ -14,7 +14,7 @@ my
|
|||||||
outdated_log.txt
|
outdated_log.txt
|
||||||
|
|
||||||
# too big
|
# too big
|
||||||
models/b20*.gz
|
models/*.bin.gz
|
||||||
|
|
||||||
# standard python ignore
|
# standard python ignore
|
||||||
# Byte-compiled / optimized / DLL files
|
# Byte-compiled / optimized / DLL files
|
||||||
|
|||||||
@@ -1,14 +1,18 @@
|
|||||||
[x] Player button to black/white with AI style spinner
|
[x] Player button to black/white with AI style spinner
|
||||||
[] Multi engine (detect all req. analysis in analysis[engine] fn)
|
[x Non square boards
|
||||||
[] Non square boards
|
|
||||||
[] Polish graph
|
|
||||||
[x] remove fast -> in settings?
|
[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?
|
[] List edit settings/object edit settings?
|
||||||
[] README
|
[] README
|
||||||
[] Release notes
|
[] Release notes
|
||||||
[] remove button disable code?
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[] BoxLayout padding/spacing use instead of fiddling?
|
||||||
|
|
||||||
|
|
||||||
+2
-1
@@ -15,7 +15,8 @@
|
|||||||
"init_size": 19,
|
"init_size": 19,
|
||||||
"komi_19": 6.5,
|
"komi_19": 6.5,
|
||||||
"komi_13": 6.5,
|
"komi_13": 6.5,
|
||||||
"komi_9": 6.5
|
"komi_9": 6.5,
|
||||||
|
"sweep_visits_frac": 0.2
|
||||||
},
|
},
|
||||||
"trainer": {
|
"trainer": {
|
||||||
"num_undo_prompts": [1,1,1,0.5,0],
|
"num_undo_prompts": [1,1,1,0.5,0],
|
||||||
|
|||||||
@@ -78,18 +78,24 @@ class KataGoEngine:
|
|||||||
else:
|
else:
|
||||||
self.katrain.log(f"Query result {analysis['id']} discarded -- recent new game?", OUTPUT_DEBUG)
|
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):
|
def send_query(self, query, callback):
|
||||||
query_id = f"QUERY:{str(self.query_counter)}"
|
|
||||||
self.query_counter += 1
|
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]
|
moves = [m for node in analysis_node.nodes_from_root for m in node.move_with_placements]
|
||||||
if next_move:
|
if next_move:
|
||||||
moves.append(next_move)
|
moves.append(next_move)
|
||||||
|
|
||||||
if ownership is None:
|
if ownership is None:
|
||||||
ownership = self.config["enable_ownership"] and not next_move
|
ownership = self.config["enable_ownership"] and not next_move
|
||||||
size_x, size_y = analysis_node.board_size
|
size_x, size_y = analysis_node.board_size
|
||||||
query = {
|
query = {
|
||||||
"id": query_id,
|
|
||||||
"rules": self.get_rules(analysis_node),
|
"rules": self.get_rules(analysis_node),
|
||||||
"priority": self.base_priority + priority,
|
"priority": self.base_priority + priority,
|
||||||
"analyzeTurns": [len(moves)],
|
"analyzeTurns": [len(moves)],
|
||||||
@@ -101,8 +107,4 @@ class KataGoEngine:
|
|||||||
"includePolicy": not next_move,
|
"includePolicy": not next_move,
|
||||||
"moves": [[m.player, m.gtp()] for m in moves],
|
"moves": [[m.player, m.gtp()] for m in moves],
|
||||||
}
|
}
|
||||||
self.queries[query_id] = (callback, time.time())
|
self.send_query(query, callback)
|
||||||
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()
|
|
||||||
@@ -281,13 +281,13 @@ class Game:
|
|||||||
elif mode == "sweep":
|
elif mode == "sweep":
|
||||||
board_size_x, board_size_y = self.board_size
|
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]
|
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")
|
self.katrain.controls.set_status(f"Refining analysis of entire board to {visits} visits")
|
||||||
priority = -1_000_000_000
|
priority = -1_000_000_000
|
||||||
else: # mode=='refine':
|
else: # mode=='refine':
|
||||||
analyze_moves = [Move.from_gtp(gtp, player=cn.next_player) for gtp, _ in cn.analysis["moves"].items()]
|
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"]
|
visits = max(d["visits"] for d in cn.analysis["moves"].values())
|
||||||
self.katrain.controls.set_status(f"Refining analysis of candidate moves to {visits} visits")
|
self.katrain.controls.set_status(f"Equalizing analysis of candidate moves to {visits} visits")
|
||||||
priority = -1_000
|
priority = -1_000
|
||||||
for move in analyze_moves:
|
for move in analyze_moves:
|
||||||
cn.analyze(self.engine, priority, visits=visits, refine_move=move)
|
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:
|
if self.parent and self.parent.analysis_ready:
|
||||||
previous_top_move = self.parent.candidate_moves[0]
|
previous_top_move = self.parent.candidate_moves[0]
|
||||||
if sgf or hints and previous_top_move["move"] != single_move.gtp(): # TODO: when to include?
|
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
|
points_lost = self.points_lost
|
||||||
if sgf and points_lost > 0.5:
|
if sgf and points_lost > 0.5:
|
||||||
text += f"Estimated point loss: {points_lost:.1f}\n"
|
text += f"Estimated point loss: {points_lost:.1f}\n"
|
||||||
if sgf or hints:
|
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:
|
if self.auto_undo:
|
||||||
text += "Move was automatically undone."
|
text += "Move was automatically undone."
|
||||||
else:
|
else:
|
||||||
|
|||||||
+1
-1
@@ -69,6 +69,6 @@ class Controls(BoxLayout):
|
|||||||
self.show_evaluation_stats(current_node)
|
self.show_evaluation_stats(current_node)
|
||||||
|
|
||||||
if current_node.score:
|
if current_node.score:
|
||||||
self.graph.update_value(current_node.depth, current_node.score)
|
self.graph.update_value(current_node)
|
||||||
|
|
||||||
self.info.text = info
|
self.info.text = info
|
||||||
+15
-19
@@ -19,17 +19,6 @@ from kivy.uix.spinner import Spinner
|
|||||||
from kivy.uix.textinput import TextInput
|
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):
|
class DarkLabel(Label):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@@ -173,7 +162,7 @@ class CensorableLabel(BoxLayout):
|
|||||||
|
|
||||||
|
|
||||||
class ScoreGraph(Label):
|
class ScoreGraph(Label):
|
||||||
values = ListProperty([])
|
nodes = ListProperty([])
|
||||||
line_points = ListProperty([])
|
line_points = ListProperty([])
|
||||||
dot_pos = ListProperty([0, 0])
|
dot_pos = ListProperty([0, 0])
|
||||||
highlighted_index = NumericProperty(None)
|
highlighted_index = NumericProperty(None)
|
||||||
@@ -182,12 +171,18 @@ class ScoreGraph(Label):
|
|||||||
super().__init__(**kwargs)
|
super().__init__(**kwargs)
|
||||||
Clock.schedule_once(self.on_size, 0)
|
Clock.schedule_once(self.on_size, 0)
|
||||||
|
|
||||||
def clear(self):
|
def initialize_from_game(self, root):
|
||||||
self.values = []
|
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):
|
def on_size(self, *args):
|
||||||
values = self.values
|
nodes = self.nodes
|
||||||
if values:
|
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])
|
val_range = min(values or [0]), max(values or [0])
|
||||||
scale = math.ceil(max(3, max(-val_range[0], val_range[1]) * 1.05))
|
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.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]]
|
self.dot_pos = [c - self.highlight_size / 2 for c in line_points[self.highlighted_index]]
|
||||||
|
|
||||||
def update_value(self, index, value):
|
def update_value(self, node):
|
||||||
self.values.extend([0] * max(0, index - (len(self.values) - 1)))
|
index = node.depth
|
||||||
self.values[index] = value or 0
|
self.nodes.extend([None] * max(0, index - (len(self.nodes) - 1)))
|
||||||
|
self.nodes[index] = node
|
||||||
self.highlighted_index = index
|
self.highlighted_index = index
|
||||||
self.on_size()
|
self.on_size()
|
||||||
|
|
||||||
|
|||||||
+14
-8
@@ -19,6 +19,7 @@ from engine import KataGoEngine
|
|||||||
from game import Game, IllegalMoveException, KaTrainSGF, Move
|
from game import Game, IllegalMoveException, KaTrainSGF, Move
|
||||||
from gui import *
|
from gui import *
|
||||||
from gui.popups import ConfigPopup, NewGamePopup
|
from gui.popups import ConfigPopup, NewGamePopup
|
||||||
|
from sgf_parser import ParseError
|
||||||
|
|
||||||
|
|
||||||
class KaTrainGui(BoxLayout):
|
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")
|
config_file = sys.argv[1] if len(sys.argv) > 1 else os.path.join(base_path, "config.json")
|
||||||
try:
|
try:
|
||||||
self.log(f"Using config file {config_file}", OUTPUT_INFO)
|
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)
|
self._config = dict(self._config_store)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.log(f"Failed to load config {config_file}: {e}", OUTPUT_ERROR)
|
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):
|
def _do_new_game(self, move_tree=None):
|
||||||
self.game = Game(self, self.engine, self.config("game"), move_tree=move_tree)
|
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.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?
|
self.update_state(redraw_board=True) # TODO: just board here/redraw is in all anyway?
|
||||||
|
|
||||||
def _do_ai_move(self, node=None):
|
def _do_ai_move(self, node=None):
|
||||||
@@ -163,7 +164,12 @@ class KaTrainGui(BoxLayout):
|
|||||||
|
|
||||||
def readfile(files, _mouse):
|
def readfile(files, _mouse):
|
||||||
fileselect_popup.dismiss()
|
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
|
popup_contents.filesel.on_submit = readfile
|
||||||
fileselect_popup.open()
|
fileselect_popup.open()
|
||||||
@@ -184,7 +190,7 @@ class KaTrainGui(BoxLayout):
|
|||||||
for pl in Move.PLAYERS:
|
for pl in Move.PLAYERS:
|
||||||
if not self.game.root.get_first(f"P{pl}"):
|
if not self.game.root.get_first(f"P{pl}"):
|
||||||
_, model_file = os.path.split(self.engine.config["model"])
|
_, 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"))
|
msg = self.game.write_sgf(self.config("files/sgf_save"))
|
||||||
self.log(msg, OUTPUT_INFO)
|
self.log(msg, OUTPUT_INFO)
|
||||||
self.controls.set_status(msg)
|
self.controls.set_status(msg)
|
||||||
@@ -194,10 +200,10 @@ class KaTrainGui(BoxLayout):
|
|||||||
return # if in new game or load, don't allow keyboard shortcuts
|
return # if in new game or load, don't allow keyboard shortcuts
|
||||||
|
|
||||||
shortcuts = {
|
shortcuts = {
|
||||||
"u": self.controls.eval.checkbox,
|
"u": self.controls.eval,
|
||||||
"i": self.controls.hints.checkbox,
|
"i": self.controls.hints,
|
||||||
"p": self.controls.policy.checkbox,
|
"p": self.controls.policy,
|
||||||
"o": self.controls.ownership.checkbox,
|
"o": self.controls.ownership,
|
||||||
"a": ("ai-move",),
|
"a": ("ai-move",),
|
||||||
"right": ("switch-branch", 1),
|
"right": ("switch-branch", 1),
|
||||||
"left": ("switch-branch", -1),
|
"left": ("switch-branch", -1),
|
||||||
|
|||||||
Reference in new issue
Block a user