readme update

This commit is contained in:
Sander Land committed 2020-04-29 20:52:39 +02:00
1 parent 0de3335cd1
commit 26a37724dd
10 files changed
+85 -62

No files matched your search

+56 -34
View File
@@ -10,7 +10,19 @@ but has since grown to include a wide range of features, including:
* Play against a wide range of weakened versions of AI with various styles.
* Play against a stronger player and use the retry option instead of handicap stones.
![screenshot](https://imgur.com/t3Im6Xu.png)
## Screenshots
| Analyze games | Play against an AI Teacher |
| ------------- | ------------- |
| ![screenshot](img/screenshot_analyze.png) | ![screenshot](img/screenshot_play.png) |
## Quickstart
* Right-click any button you don't understand for help.
* To analyze a game, load it using the button in the top right, or press `ctrl-L`
* To play against AI, pick an AI from the drop down a color and either 'human' or 'teach' for yourself and start playing.
* For different board sizes, use the button with the little goban in the bottom right for a new game.
## Installation
@@ -35,70 +47,80 @@ but has since grown to include a wide range of features, including:
* Executables for Mac are not available, so compiling from source code is required there.
* Start the app by running `python katrain.py`. Note that the program can be slow to initialize the first time, due to KataGo's GPU tuning.
## Quickstart
* To analyze a game, load it using the button in the top right, or press `ctrl-L`
* To play against AI, pick an AI from the drop down a color and either 'human' or 'teach' for yourself and start playing.
* For different board sizes, use the button with the little goban in the bottom right for a new game.
## Manual
[Screenshot]
### Play
Under the 'play' tab you can select who is playing black and white.
* Human is simple play with potential feedback, but without auto-undo.
* Teach will give you instant feedback, and auto-undo bad moves to give you a second chance.
* Settings for this mode can be found under 'Configure teacher'
* Settings for this mode can be found under 'Configure Teacher'
* AI will activate the AI in the dropdown next to the buttons.
* Settings for the selected AI(s) can be found under 'Configure AI'
* Settings for the selected AI(s) can be found under 'Configure AIs'
If you do not want to see 'Points lost' or other feedback for your moves,
set 'show last n dots' to 0 under 'Configure Teacher', and click on the words 'Points lost' to hide its value.
#### AIs
Available AIs, with strength indicating an estimate for the default settings, are:
* **9p**: **Default** is full KataGo, above professional level.
* **[9p+]** **Default** is full KataGo, above professional level.
* **Balance** is KataGo occasionally making weaker moves, attempting to win by ~2 points.
* **Jigo** is KataGo aggressively making weaker moves, attempting to win by 0.5 points.
* **~4d**: **Policy** is the top move from the policy network (it's 'shape sense' without reading), should be around high dan level depending on the model used.
* **~1d**: **P:Weighted** will pick a random move weighted by the policy, as long as it's above `lower_bound`. `weaken_fac` uses policy^(1/weaken_fac), increasing the chance for weaker moves.
* **~5k**: **P:Pick** will pick a `pick_n + pick_frac * <number of legal moves>` moves at random, and play the best move among them.
* **[~4d]** **Policy** uses the top move from the policy network (it's 'shape sense' without reading), should be around high dan level depending on the model used.
* **[~3k]**: **P:Weighted** picks a random move weighted by the policy, as long as it's above `lower_bound`. `weaken_fac` uses `policy^(1/weaken_fac)`, increasing the chance for weaker moves.
* **[~5k]**: **P:Pick** picks `pick_n + pick_frac * <number of legal moves>` moves at random, and play the best move among them.
The setting `pick_override` determines the minimum value at which this process is bypassed to play the best move instead, preventing obvious blunders.
This is probably the best choice for kyu players who want a chance of winning. Variants of this strategy include:
* **~3k**: **P:Local** will pick such moves biased towards the last move with probability related to `local_stddev`.
* **~10k**: **~P:Tenuki** is biased in the opposite way as P:Local, using the same setting.
* **~7k**: P:Influence is biased towards 4th+ line moves, with every line below that dividing both the chance of considering the move and the policy value by `influence_weight`. Consider setting `pick_frac=1.0` to only affect the policy weight.
* **~7k**: P:Territory is biased in the opposite way, towards 1-3rd line moves, using the same setting.
* * **~7k**: P:Noise mixes the policy with `noise_strength` Dirichlet noise. At `noise_strength=0.9` play is near-random, while `noise_strength=0.7` is still quite strong. Regardless, mistakes are typically strange can include senseless first-line moves.
* `<Pause>` pauses AI moves, in case you want to do analysis without triggering moves, or simply hide the evaluation dots for this player.
This, along with 'Weighted' are probably the best choice for kyu players who want a chance of winning without playing the sillier bots below. Variants of this strategy include:
* **[~3k]**: **P:Local** will pick such moves biased towards the last move with probability related to `local_stddev`.
* **[~7k]**: **~P:Tenuki** is biased in the opposite way as P:Local, using the same setting.
* **[~7k]**: **P:Influence** is biased towards 4th+ line moves, with every line below that dividing both the chance of considering the move and the policy value by `influence_weight`. Consider setting `pick_frac=1.0` to only affect the policy weight.
* **[~7k]**: **P:Territory** is biased in the opposite way, towards 1-3rd line moves, using the same setting.
* * **[~7k]**: **P:Noise** mixes the policy with `noise_strength` Dirichlet noise. At `noise_strength=0.9` play is near-random, while `noise_strength=0.7` is still quite strong. A threshold setting is included to avoid senseless first-line moves.
* **<Pause>**: pauses AI moves, in case you want to do analysis without triggering moves, or simply hide the evaluation dots for this player.
Selecting the AI as either white or black opens up the option to configure it under 'Configure AI'.
### Analysis
* The checkboxes have the following keyboard shortscuts, and they configure:
* The checkboxes have the following keyboard shortcuts, and they configure:
* **[q]**: Child moves are shown. On by default, can turn it off to avoid obscuring other information or when wanting to guess the next move.
* **[w]**: All dots: Show all evaluation dots instead of the last few. You can configure how many are shown with thsi setting off under 'Configure Teacher'.
* **[e]**:
* **[w]**: All dots: Show all evaluation dots instead of the last few.
* You can configure how many are shown with this setting off, and whether they are shown for AIs under 'Play/Configure Teacher'.
* **[e]**: Top moves: Show the next moves KataGo considered, colored by their expected point loss. Small dots indicate high uncertainty. Hover over any of them to see the principal variation.
* **[r]**: Show owner: Show expected ownership of each square.
* **[t]**: NN Policy: Show KataGo's policy network evaluation, i.e. where it thinks the best next move is purely from the position, and in the absence of any 'reading'.
* The analysis buttons have the following keyboard shortcuts, and they do:
* **[a]**: Extra: Re-evaluate the position using more visits, usually resulting in a more accurate evaluation.
* **[s]**: Equalize: Re-evaluate all currently shown next moves with the same visits as the current top move. Useful to increase confidence in the suggestions with high uncertainty.
* **[d]**: Sweep: Evaluate all possible next moves. This can take a bit of time, but the result is nothing if not colourful.
### Keyboard shortcuts
In addition to shortcuts mentioned above, there are:
In addition to these, there are:
* Tab to switch between analysis and play modes. (NB. keyboard shortcuts function regardless)
* ~ or ` or p : Hide side panel UI and only show the board.
* Ctrl-v : Load SGF from clipboard
* Ctrl-c : Save SGF to clipboard
* Ctrl-l : Load SGF from file
* Ctrl-s : Load SGF to file
* Ctrl-n : Load SGF from clipboard
* **[Tab]**: to switch between analysis and play modes. (NB. keyboard shortcuts function regardless)
* **[~]** or **[`]** or **[p]**: Hide side panel UI and only show the board.
* **[enter]**: AI Move
* **[arrow up]** or **[z]**: Undo move. Hold shift for 10 moves at a time, or ctrl to skip to thte start.
* **[arrow down]** or **[x]**: Redo move. Hold shift for 10 moves at a time, or ctrl to skip to thte start.
* **[scroll up]**: Undo move. Only works with the mouse pointer on the board.
* **[scroll down]**: Redo move.
* **[Ctrl-v]**: Load SGF from clipboard
* **[Ctrl-c]**: Save SGF to clipboard
* **[Ctrl-l]**: Load SGF from file
* **[Ctrl-s]**: Load SGF to file
* **[Ctrl-n]**: Load SGF from clipboard
* **[space]**: Pass
### Configuration
Configuration is stored in `config.json`. Most settings are now available to edit in the program, but
some cosmetic options are now.
some cosmetic options are not.
You can use `python katrain.py your_config_file.json` to use another config file instead.
If you ever need to reset to the original settings, simply re-download the `config.json` file in this repository.
@@ -108,7 +130,7 @@ If you ever need to reset to the original settings, simply re-download the `conf
* The program is slow to start!
* The first startup of KataGo can be slow, after that it should be much faster.
* The program is running too slowly!
* Lower the visits count in the `max_visits` block of `config.json` by half or so and try again.
* Adjust the number of visits or maximum time allowed in the settings.
## Contributing
-5
View File
@@ -124,11 +124,6 @@
"line_weight": 5,
"_help_right": "Samples `pick_n + pick_frac * <number of legal moves>` and plays the best one, biased to below the `threshold` line.",
"_help_left": "Increase `line_weight` to penalize moves closer to the center more."
},
"<Pause>": {
"_help_right": "--Edward Lasker",
"_help_left": "The rules of go are so elegant, organic, and rigorously logical that if intelligent life forms exist elsewhere in the universe, they almost certainly play go."
}
},
"board_ui": {
+10 -6
View File
@@ -19,13 +19,13 @@ class GameNode(SGFNode):
self.move_number = 0
self.undo_threshold = random.random() # for fractional undos, store the random threshold in the move itself for consistency
def sgf_properties(self, save_comments_player, save_comments_class, eval_thresholds):
def sgf_properties(self, save_comments_player=None, save_comments_class=None, eval_thresholds=None):
properties = copy.copy(super().sgf_properties())
if self.points_lost:
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 save_comments_player.get(self.player, False) and show_class and self.analysis_ready:
if (save_comments_player or {}).get(self.player, False) and show_class and self.analysis_ready:
candidate_moves = self.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]
@@ -39,7 +39,7 @@ class GameNode(SGFNode):
if self.is_root:
properties["C"] = [
"Moves marked 'X' indicate the top move according to KataGo, those with a square are all moves which lose at most 0.5 points.\n"
+ properties.get("C", "")
+ "\n".join(properties.get("C", ""))
+ "\nSGF with review generated by KaTrain."
]
return properties
@@ -97,12 +97,16 @@ class GameNode(SGFNode):
previous_top_move = self.parent.candidate_moves[0]
if sgf or hints:
if previous_top_move["move"] != single_move.gtp():
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"
text += f"Predicted top move was {previous_top_move['move']} ({self.format_score(previous_top_move['scoreLead'])}).\n"
else:
text += f"Move was predicted best move.\n"
if sgf:
if previous_top_move.get("pv") and (sgf or hints):
text += f"PV: {' '.join(previous_top_move['pv'])}"
if sgf or hints or teach:
policy_ranking = self.parent.policy_ranking
policy_ix = [ix + 1 for (p, m), ix in zip(policy_ranking, range(len(policy_ranking))) if m == single_move]
@@ -112,7 +116,7 @@ class GameNode(SGFNode):
text += f"Top policy move was {policy_ranking[0][1].gtp()} ({policy_ranking[0][0]:.1%}).\n"
if self.auto_undo and sgf:
text += "Move was automatically undone in teaching mode."
if self.ai_thoughts:
if self.ai_thoughts and (sgf or hints):
text += f"\nAI thought process: {self.ai_thoughts}"
else:
text = "No analysis available" if sgf else "Analyzing move..."
-1
View File
@@ -199,7 +199,6 @@ class BadukPanWidget(Widget):
evalsize = 0
else:
evalsize = min(1, max(0, realized_points_lost / points_lost))
print(node.single_move, realized_points_lost, points_lost, evalsize)
for m in node.move_with_placements:
if has_stone.get(m.coords) and not drawn_stone.get(m.coords): # skip captures, last only for
move_eval_on = show_dots_for.get(m.player) and (i < show_n_eval or full_eval_on)
+6
View File
@@ -65,9 +65,15 @@ class Controls(BoxLayout):
points_lost = current_node.points_lost
self.score_change.label = f"Points lost" if points_lost and points_lost > 0 else f"Points gained"
self.score_change.text = f"{move.player}: {abs(points_lost):.1f}" if points_lost else "..."
print(current_player_is_ai_playing_human, move, next_player_is_human_or_both_robots)
elif not current_player_is_ai_playing_human:
print(current_player_is_ai_playing_human, move, next_player_is_human_or_both_robots)
self.score_change.label = f"Points lost"
self.score_change.text = ""
elif current_player_is_ai_playing_human and current_node.parent and current_node.parent.single_move:
points_lost = current_node.parent.points_lost
self.score_change.label = f"Points lost" if points_lost and points_lost > 0 else f"Points gained"
self.score_change.text = f"{current_node.parent.single_move.player}: {abs(points_lost):.1f}" if points_lost else "..."
elif both_players_are_robots and current_node.parent and current_node.parent.analysis_ready:
self.score.text = current_node.parent.format_score()
self.win_rate.text = current_node.parent.format_win_rate()
-1
View File
@@ -237,7 +237,6 @@ class ConfigTeacherPopup(QuickConfigGui):
def __init__(self, katrain, popup, **kwargs):
self.settings = katrain.config("trainer")
self.sgf_settings = katrain.config("sgf")
print(self.sgf_settings, katrain.config("sgf"))
self.ui_settings = katrain.config("board_ui")
super().__init__(katrain, popup, self.settings, **kwargs)
Clock.schedule_once(self._build, 0)
Binary file not shown.

After

Width:  |  Height:  |  Size: 161 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 125 KiB

+6 -2
View File
@@ -366,6 +366,7 @@
scroll_type: ['bars']
bar_width: 5
bar_color: BUTTON_COLOR
label: label
canvas.before:
Color:
rgba: root.border_color
@@ -378,6 +379,7 @@
rectangle: [self.pos[0]+1,self.pos[1]+2,self.width-3,self.height-3]
width:1
Label:
id: label
padding: 5, 5
font_size: dp(18)
color: BLACK
@@ -588,10 +590,12 @@
border_color: 0.5,0.1,0.1,1
opacity: 1 if self.text else 0
text: ''
size_hint_y: 0.00001 if not self.text else 0.66
size_hint_y: None
height: 0.00001 if not self.text else min(0.66*self.parent.height,self.label.texture_size[1])
ScrollableLabel:
id: info
size_hint: 1, 1 - status_label.size_hint_y
size_hint: 1, None
height: self.parent.height - status_label.height - 1
BoxLayout:
orientation: 'horizontal'
size_hint: 1, None
+7 -13
View File
@@ -91,14 +91,7 @@ class KaTrainGui(BoxLayout):
auto_undo = cn.player and "undo" in self.controls.player_mode(cn.player)
if auto_undo and cn.analysis_ready and cn.parent and cn.parent.analysis_ready:
self.game.analyze_undo(cn, self.config("trainer")) # not via message loop
if (
cn.analysis_ready
and "ai" in self.controls.player_mode(cn.next_player).lower()
and "pause" not in self.controls.ai_mode(cn.next_player).lower()
and not cn.children
and not self.game.ended
and not (auto_undo and cn.auto_undo is None)
):
if cn.analysis_ready and "ai" in self.controls.player_mode(cn.next_player).lower() and not cn.children and not self.game.ended and not (auto_undo and cn.auto_undo is None):
self._do_ai_move(cn) # cn mismatch stops this if undo fired. avoid message loop here or fires repeatedly.
# Handle prisoners and next player display
@@ -195,7 +188,7 @@ class KaTrainGui(BoxLayout):
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, analyze_fast=fileselect_popup.fast.active)
self._do_new_game(move_tree=move_tree, analyze_fast=popup_contents.fast.active)
popup_contents.filesel.on_submit = readfile
fileselect_popup.open()
@@ -229,10 +222,11 @@ class KaTrainGui(BoxLayout):
self.controls.set_status(msg)
def on_touch_up(self, touch):
if touch.button == "scrollup":
self("redo")
elif touch.button == "scrolldown":
self("undo")
if self.board_gui.collide_point(*touch.pos) or self.board_controls.collide_point(*touch.pos):
if touch.button == "scrollup":
self("redo")
elif touch.button == "scrolldown":
self("undo")
return super().on_touch_up(touch)
def _on_keyboard_down(self, keyboard, keycode, text, modifiers):