diff --git a/README.md b/README.md index fdfa94a19..3028b148d 100644 --- a/README.md +++ b/README.md @@ -54,6 +54,46 @@ and then execute: ``python train.py`` (To use GPU in PyTorch, set ``use_gpu=Tru The models (best_policy.model and current_policy.model) will be saved every a few updates (default 50). + +With Tensorflow and ResNet30, uncomment the line +``` +# from policy_value_net_res_tensorflow import PolicyValueNetRes30 # Tensorflow +``` +Then execute: +``` +python train.py -h + -h, --help show this help message and exit + --ModelName {baseline,res30}, -m {baseline,res30} + --LossFunction {lv,lp,l+,lx}, -l {lv,lp,l+,lx} + --EnableForbiddenHands, -fh Enable forbidden hands +``` +baseline_l+: +``` +python train.py --ModelName baseline --LossFunction l+ --EnableForbiddenHands True +``` + +baseline_lp: +``` +python train.py --ModelName baseline --LossFunction lp --EnableForbiddenHands True +``` + +res30_l+: +``` +python train.py --ModelName res30 --LossFunction l+ --EnableForbiddenHands True +``` + +res30_lp: +``` +python train.py --ModelName res30 --LossFunction lp --EnableForbiddenHands True +``` + +Human play with AI + +``` +pip install tensorflow==1.14.0 +python gobang_res30.py +``` + **Note:** the 4 provided models were trained using Theano/Lasagne, to use them with PyTorch, please refer to [issue 5](https://github.com/junxiaosong/AlphaZero_Gomoku/issues/5). **Tips for training:** @@ -61,4 +101,4 @@ The models (best_policy.model and current_policy.model) will be saved every a fe 2. For the case of 8 * 8 board and 5 in a row, it may need 2000~3000 self-play games to get a good model, and it may take about 2 days on a single PC. ### Further reading -My article describing some details about the implementation in Chinese: [https://zhuanlan.zhihu.com/p/32089487](https://zhuanlan.zhihu.com/p/32089487) +My article describing some details about the implementation in Chinese: [https://zhuanlan.zhihu.com/p/32089487](https://zhuanlan.zhihu.com/p/32089487) diff --git a/evaluate.py b/evaluate.py new file mode 100644 index 000000000..bab7017a5 --- /dev/null +++ b/evaluate.py @@ -0,0 +1,91 @@ +# -*- coding: utf-8 -*- +""" +An implementation of the evaluation pipeline of AlphaZero for Gomoku + +@author: Chunlei Wang +""" + +import random +import numpy as np +from collections import defaultdict, deque +from game import Board, Game +from mcts_alphaZero import MCTSPlayer +#from policy_value_net import PolicyValueNet # Theano and Lasagne +#from policy_value_net_pytorch import PolicyValueNet # Pytorch +from policy_value_net_tensorflow import PolicyValueNet # Tensorflow +#from policy_value_net_keras import PolicyValueNet # Keras +from policy_value_net_res_tensorflow import PolicyValueNetRes30 # Tensorflow +from datetime import datetime +import utils +import os + +OUTPUT_DIR = "evaluation/" + datetime.utcnow().strftime("%Y%m%d%H%M%S") +os.makedirs(OUTPUT_DIR, exist_ok=True) +EVALUATION_OUTPUT = OUTPUT_DIR + "/evaluation.txt" + +class EvaluationPipeline(): + def __init__(self, current_model, baseline_model): + # params of the board and the game + self.board_width = 9 + self.board_height = 9 + self.n_in_row = 5 + self.board = Board(width=self.board_width, + height=self.board_height, + n_in_row=self.n_in_row, + forbidden_hands=True) + self.game = Game(self.board) + self.n_playout = 400 # num of simulations for each move + self.c_puct = 5 + + self.baseline_policy_value_net = PolicyValueNet(self.board_width, + self.board_height, + 'l+', + model_file=baseline_model) + + self.current_policy_value_net = PolicyValueNetRes30(self.board_width, + self.board_height, + 'l+', + model_file=current_model) + + def policy_evaluate(self, n_games=100): + """ + Evaluate the trained policy by playing against the baseline MCTS player + """ + current_mcts_player = MCTSPlayer(self.current_policy_value_net.policy_value_fn, + c_puct=self.c_puct, + n_playout=self.n_playout) + + baseline_mcts_player = MCTSPlayer(self.baseline_policy_value_net.policy_value_fn, + c_puct=self.c_puct, + n_playout=self.n_playout) + + win_cnt = defaultdict(int) + for i in range(n_games): + winner = self.game.start_play(current_mcts_player, + baseline_mcts_player, + start_player=i % 2, + is_shown=1) + win_cnt[winner] += 1 + win_ratio = 1.0*(win_cnt[1] + 0.5*win_cnt[-1]) / n_games + + output = "Evaluation games: {}, num_playouts: {}, win: {}, lose: {}, tie: {}, win ratio: {}".format( + n_games, + self.n_playout, + win_cnt[1], win_cnt[2], win_cnt[-1], win_ratio) + + utils.log(output, EVALUATION_OUTPUT) + + return win_ratio + + def run(self): + """run the evaluation pipeline""" + try: + win_ratio = self.policy_evaluate() + return win_ratio + except KeyboardInterrupt: + print('\n\rquit') + + +if __name__ == '__main__': + evaluation_pipeline = EvaluationPipeline(current_model='output/current_policy.model', baseline_model='output/baseline_policy.model') + evaluation_pipeline.run() diff --git a/game.py b/game.py index 7b58ca238..ceb434ac1 100644 --- a/game.py +++ b/game.py @@ -6,10 +6,36 @@ from __future__ import print_function import numpy as np +INPUT_STATE_CHANNEL_SIZE = 19 class Board(object): """board for the game""" + """ + 0: blank + 1: black + 2: white + """ + forbidden_hands_of_three_patterns = [ + [0, 1, 1, 1, 0], + [0, 1, 0, 1, 1, 0], + [0, 1, 1, 0, 1, 0], + ] + + forbidden_hands_of_four_patterns = [ + [0, 1, 1, 1, 1, 0], + [0, 1, 1, 1, 0, 1], + [0, 1, 0, 1, 1, 1], + [1, 1, 1, 0, 1, 0], + [1, 0, 1, 1, 1, 0], + [2, 1, 1, 1, 1, 0], + [2, 1, 1, 1, 0, 1], + [2, 1, 0, 1, 1, 1], + [0, 1, 1, 1, 1, 2], + [1, 1, 1, 0, 1, 2], + [1, 0, 1, 1, 1, 2], + ] + def __init__(self, **kwargs): self.width = int(kwargs.get('width', 8)) self.height = int(kwargs.get('height', 8)) @@ -19,17 +45,20 @@ def __init__(self, **kwargs): self.states = {} # need how many pieces in a row to win self.n_in_row = int(kwargs.get('n_in_row', 5)) + self.forbidden_hands = bool(kwargs.get('forbidden_hands', False)) self.players = [1, 2] # player1 and player2 def init_board(self, start_player=0): if self.width < self.n_in_row or self.height < self.n_in_row: raise Exception('board width and height can not be ' 'less than {}'.format(self.n_in_row)) + self.start_player = start_player self.current_player = self.players[start_player] # start player # keep available moves in a list self.availables = list(range(self.width * self.height)) self.states = {} self.last_move = -1 + self.last_16_move = [0]*(INPUT_STATE_CHANNEL_SIZE-3) def move_to_location(self, move): """ @@ -48,13 +77,41 @@ def location_to_move(self, location): return -1 h = location[0] w = location[1] + if h < 0 or h >= self.height: + return -1 + if w < 0 or w >= self.width: + return -1 + move = h * self.width + w if move not in range(self.width * self.height): return -1 return move + def current_last16move_state(self): + """return the board state from the perspective of the current res30 player. + state shape: INPUT_STATE_CHANNEL_SIZE*width*height + """ + + square_state = np.zeros((INPUT_STATE_CHANNEL_SIZE, self.width, self.height)) + if self.states: + moves, players = np.array(list(zip(*self.states.items()))) + move_curr = moves[players == self.current_player] + move_oppo = moves[players != self.current_player] + + square_state[0][move_curr // self.width, + move_curr % self.height] = 1.0 + square_state[1][move_oppo // self.width, + move_oppo % self.height] = 1.0 + # indicate the last 16 move location + for i in range(INPUT_STATE_CHANNEL_SIZE-3): + square_state[2+i][np.array(self.last_16_move[i::2]) // self.width, + np.array(self.last_16_move[i::2]) % self.height] = 1.0 + if len(self.states) % 2 == 0: + square_state[INPUT_STATE_CHANNEL_SIZE-1][:, :] = 1.0 # indicate the colour to play + return square_state[:, ::-1, :] + def current_state(self): - """return the board state from the perspective of the current player. + """return the board state from the perspective of the current baseline player. state shape: 4*width*height """ @@ -82,6 +139,8 @@ def do_move(self, move): else self.players[1] ) self.last_move = move + self.last_16_move.pop(0) + self.last_16_move.append(move) def has_a_winner(self): width = self.width @@ -89,6 +148,9 @@ def has_a_winner(self): states = self.states n = self.n_in_row + if self.forbidden_hands and self.states and self.states[self.last_move] == self.players[self.start_player] and self.check_forbidden_hands(): + return True, self.players[(self.start_player + 1) % 2] + moved = list(set(range(width * height)) - set(self.availables)) if len(moved) < self.n_in_row *2-1: return False, -1 @@ -116,6 +178,71 @@ def has_a_winner(self): return False, -1 + def check_forbidden_hands(self): + directions = [ + [1, 0], + [1, 1], + [0, 1], + [-1, 1], + ] + + patterns_of_three_matches = [ + 1 if self.check_forbidden_pattern(p, d) else 0 + for d in directions + for p in self.forbidden_hands_of_three_patterns + ] + + patterns_of_four_matches = [ + 1 if self.check_forbidden_pattern(p, d) else 0 + for d in directions + for p in self.forbidden_hands_of_four_patterns + ] + + if sum(patterns_of_three_matches) > 1 or sum(patterns_of_four_matches) > 1: + return True + + def check_forbidden_pattern(self, pattern, direction): + for (i, x) in enumerate(pattern): + if x == 1: + pieces = self.collect_pieces(self.last_move, direction, i, len(pattern)) + if pieces != [] and Board.list_equal(pieces, pattern): + return True + + return False + + def list_equal(list1, list2): + if len(list1) != len(list2): + return False + + for (a, b) in zip(list1, list2): + if a != b: + return False + + return True + + def collect_pieces(self, move, direction, look_back, length): + cur_location = self.move_to_location(move) + start_location = [ + cur_location[0] - direction[0] * look_back, + cur_location[1] - direction[1] * look_back, + ] + + pieces = [] + for i in range(length): + location = [ + start_location[0] + i * direction[0], + start_location[1] + i * direction[1], + ] + move = self.location_to_move(location) + if move == -1: + return [] + else: + if move in self.states: + pieces.append(1 if self.states[move] == self.players[self.start_player] else 2) + else: + pieces.append(0) + return pieces + def game_end(self): """Check whether the game is ended or not""" win, winner = self.has_a_winner() @@ -180,14 +307,13 @@ def start_play(self, player1, player2, start_player=0, is_shown=1): self.graphic(self.board, player1.player, player2.player) end, winner = self.board.game_end() if end: - if is_shown: - if winner != -1: + if winner != -1: print("Game end. Winner is", players[winner]) - else: - print("Game end. Tie") + else: + print("Game end. Tie") return winner - def start_self_play(self, player, is_shown=0, temp=1e-3): + def start_self_play(self, player, model_name, is_shown=0, temp=1e-3): """ start a self-play game using a MCTS player, reuse the search tree, and store the self-play data: (state, mcts_probs, z) for training """ @@ -199,7 +325,7 @@ def start_self_play(self, player, is_shown=0, temp=1e-3): temp=temp, return_prob=1) # store the data - states.append(self.board.current_state()) + states.append(self.board.current_state() if model_name == 'baseline' else self.board.current_last16move_state()) mcts_probs.append(move_probs) current_players.append(self.board.current_player) # perform a move @@ -220,4 +346,4 @@ def start_self_play(self, player, is_shown=0, temp=1e-3): print("Game end. Winner is player:", winner) else: print("Game end. Tie") - return winner, zip(states, mcts_probs, winners_z) + return winner, zip(states, mcts_probs, winners_z) \ No newline at end of file diff --git a/gobang.py b/gobang.py new file mode 100644 index 000000000..2de364450 --- /dev/null +++ b/gobang.py @@ -0,0 +1,208 @@ +from tkinter import * +import math + +#定义棋盘类 +class chessBoard() : + def __init__(self) : + self.window = Tk() + self.window.title("五子棋游戏") + self.window.geometry("660x500") + self.window.resizable(0,0) + self.canvas=Canvas(self.window , bg="#EEE8AC" , width=500, height=500) + self.paint_board() + self.canvas.grid(row=0, column=0) + + def paint_board(self) : + for row in range(0, 10): + if row == 0 or row == 9: + self.canvas.create_line(25, 25+row*50, 25+9*50, 25+row*50, width=2) + else : + self.canvas.create_line(25, 25+row*50, 25+9*50, 25+row*50, width=1) + + for column in range(0, 10): + if column == 0 or column == 9: + self.canvas.create_line(25+column*50, 25, 25+column*50, 25+9*50, width=2) + else : + self.canvas.create_line(25+column*50, 25, 25+column*50, 25+9*50, width=1) + + self.canvas.create_oval(122, 122, 128, 128, fill="black") + self.canvas.create_oval(372, 122, 378, 128, fill="black") + self.canvas.create_oval(122, 372, 128, 378, fill="black") + self.canvas.create_oval(372, 372, 378, 378, fill="black") + + +#定义五子棋游戏类 +#0为黑子 , 1为白子 , 2为空位 +class Gobang() : + #初始化 + def __init__(self) : + self.board = chessBoard() + self.game_print = StringVar() + self.game_print.set("") + #16*16的二维列表,保证不会out of index + self.db = [([2] * 9) for i in range(9)] + #悔棋用的顺序列表 + self.order = [] + #棋子颜色 + self.color_count = 0 + self.color = 'black' + #清空与赢的初始化,已赢为1,已清空为1 + self.flag_win = 1 + self.flag_empty = 1 + self.options() + + + #黑白互换 + def change_color(self) : + self.color_count = (self.color_count + 1 ) % 2 + if self.color_count == 0 : + self.color = "black" + elif self.color_count ==1 : + self.color = "white" + + + #落子 + def chess_moving(self ,event) : + #不点击“开始”与“清空”无法再次开始落子 + if self.flag_win ==1 or self.flag_empty ==0: + return + #坐标转化为下标 + x,y = event.x-25 , event.y-25 + x = round(x/50) + y = round(y/50) + #点击位置没用落子,且没有在棋盘线外,可以落子 + while self.db[y][x] == 2 and self.limit_boarder(y,x): + self.db[y][x] = self.color_count + self.order.append(x+15*y) + self.board.canvas.create_oval(25+50*x-15 , 25+50*y-15 , 25+50*x+15 , 25+50*y+15 , fill = self.color,tags = "chessman") + if self.game_win(y,x,self.color_count) : + print(self.color,"获胜") + self.game_print.set(self.color+"获胜") + else : + self.change_color() + self.game_print.set("请"+self.color+"落子") + + + #保证棋子落在棋盘上 + def limit_boarder(self , y , x) : + if x<0 or x>8 or y<0 or y>8 : + return False + else : + return True + + + #计算连子的数目,并返回最大连子数目 + def chessman_count(self , y , x , color_count ) : + count1,count2,count3,count4 = 1,1,1,1 + #横计算 + for i in range(-1 , -5 , -1) : + if self.db[y][x+i] == color_count : + count1 += 1 + else: + break + for i in range(1 , 5 ,1 ) : + if self.db[y][x+i] == color_count : + count1 += 1 + else: + break + #竖计算 + for i in range(-1 , -5 , -1) : + if self.db[y+i][x] == color_count : + count2 += 1 + else: + break + for i in range(1 , 5 ,1 ) : + if self.db[y+i][x] == color_count : + count2 += 1 + else: + break + #/计算 + for i in range(-1 , -5 , -1) : + if self.db[y+i][x+i] == color_count : + count3 += 1 + else: + break + for i in range(1 , 5 ,1 ) : + if self.db[y+i][x+i] == color_count : + count3 += 1 + else: + break + #\计算 + for i in range(-1 , -5 , -1) : + if self.db[y+i][x-i] == color_count : + count4 += 1 + else: + break + for i in range(1 , 5 ,1 ) : + if self.db[y+i][x-i] == color_count : + count4 += 1 + else: + break + + return max(count1 , count2 , count3 , count4) + + + #判断输赢 + def game_win(self , y , x , color_count ) : + if self.chessman_count(y,x,color_count) >= 5 : + self.flag_win = 1 + self.flag_empty = 0 + return True + else : + return False + + + #悔棋,清空棋盘,再画剩下的n-1个棋子 + def withdraw(self ) : + if len(self.order)==0 or self.flag_win == 1: + return + self.board.canvas.delete("chessman") + z = self.order.pop() + x = z%15 + y = z//15 + self.db[y][x] = 2 + self.color_count = 1 + for i in self.order : + ix = i%15 + iy = i//15 + self.change_color() + self.board.canvas.create_oval(25+50*ix-15 , 25+50*iy-15 , 25+50*ix+15 , 25+50*iy+15 , fill = self.color,tags = "chessman") + self.change_color() + self.game_print.set("请"+self.color+"落子") + + + #清空 + def empty_all(self) : + self.board.canvas.delete("chessman") + #还原初始化 + self.db = [([2] * 16) for i in range(16)] + self.order = [] + self.color_count = 0 + self.color = 'black' + self.flag_win = 1 + self.flag_empty = 1 + self.game_print.set("") + + + + #将self.flag_win置0才能在棋盘上落子 + def game_start(self) : + #没有清空棋子不能置0开始 + if self.flag_empty == 0: + return + self.flag_win = 0 + self.game_print.set("请"+self.color+"落子") + + + def options(self) : + self.board.canvas.bind("",self.chess_moving) + Label(self.board.window , textvariable = self.game_print , font = ("Arial", 20) ).place(relx = 0, rely = 0 ,x = 505 , y = 200) + Button(self.board.window , text= "开始游戏" ,command = self.game_start,width = 13, font = ("Verdana", 12)).place(relx=0, rely=0, x=505, y=15) + Button(self.board.window , text= "我要悔棋" ,command = self.withdraw,width = 13, font = ("Verdana", 12)).place(relx=0, rely=0, x=505, y=60) + Button(self.board.window , text= "清空棋局" ,command = self.empty_all,width = 13, font = ("Verdana", 12)).place(relx=0, rely=0, x=505, y=105) + Button(self.board.window , text= "结束游戏" ,command = self.board.window.destroy,width = 13, font = ("Verdana", 12)).place(relx=0, rely=0, x=505, y=420) + self.board.window.mainloop() + + +if __name__ == "__main__": + game = Gobang() \ No newline at end of file diff --git a/gobang_res30.py b/gobang_res30.py new file mode 100644 index 000000000..f43983037 --- /dev/null +++ b/gobang_res30.py @@ -0,0 +1,316 @@ +from tkinter import * +import math +import pickle +from game import Board, Game +from mcts_alphaZero import MCTSPlayer +from policy_value_net_tensorflow import PolicyValueNet # Tensorflow +from policy_value_net_res_tensorflow import PolicyValueNetRes30 # Tensorflow +from human_play import Human + +#定义棋盘类 +class chessBoard() : + def __init__(self, **kwargs) : + self.width = int(kwargs.get('width', 9)) + self.height = int(kwargs.get('height', 9)) + # need how many pieces in a row to win + self.n_in_row = int(kwargs.get('n_in_row', 5)) + self.row = self.height - 1 + self.column = self.width - 1 + + self.window = Tk() + self.window.title("五子棋游戏") + self.window.geometry("660x450") + self.window.resizable(0,0) + self.canvas=Canvas(self.window , bg="#EEE8AC" , width=self.column*50+50, height=self.row*50+50) + self.paint_board() + self.canvas.grid(row=0, column=0) + + def paint_board(self) : + for row in range(0, self.height): + if row == 0 or row == self.row: + self.canvas.create_line(25, 25+row*50, 25+self.row*50, 25+row*50, width=2) + else : + self.canvas.create_line(25, 25+row*50, 25+self.row*50, 25+row*50, width=1) + + for column in range(0, self.width): + if column == 0 or column == self.column: + self.canvas.create_line(25+column*50, 25, 25+column*50, 25+self.column*50, width=2) + else : + self.canvas.create_line(25+column*50, 25, 25+column*50, 25+self.column*50, width=1) + column = self.column // 4 + row = self.row // 4 + x = 25+column*50 + y = 25+row*50 + self.canvas.create_oval(x-3, y-3, x+3, y+3, fill="black") + x = 25+(self.column-column)*50 + self.canvas.create_oval(x-3, y-3, x+3, y+3, fill="black") + y = 25+(self.row-row)*50 + self.canvas.create_oval(x-3, y-3, x+3, y+3, fill="black") + x = 25+column*50 + self.canvas.create_oval(x-3, y-3, x+3, y+3, fill="black") + x = 25+(self.column//2)*50 + y = 25+(self.row//2)*50 + self.canvas.create_oval(x-3, y-3, x+3, y+3, fill="black") + + +#定义五子棋游戏类 +#0为黑子 , 1为白子 , 2为空位 +class Gobang() : + #初始化 + def __init__(self) : + self.board = chessBoard() + self.game_print = StringVar() + self.game_print.set("") + #16*16的二维列表,保证不会out of index + self.db = [([2] * 9) for i in range(9)] + #悔棋用的顺序列表 + self.order = [] + #棋子颜色 + self.color_count = 0 + self.color = 'black' + #清空与赢的初始化,已赢为1,已清空为1 + self.flag_win = 1 + self.flag_empty = 1 + + self.start_player = 0 + width, height, n_in_row = 9, 9, 5 + model_file = 'output/best_policy.model' + baseline_file = 'output/baseline_policy.model' + board = Board(width=width, height=height, n_in_row=n_in_row, forbidden_hands=False) + self.game = Game(board) + self.game.board.init_board(self.start_player) + self.best_policy = PolicyValueNetRes30(width, height, 'l+', model_file=model_file) + self.baseline_policy = PolicyValueNet(width, height, 'l+', model_file=baseline_file) + self.mcts_player = MCTSPlayer(self.best_policy.policy_value_fn, + c_puct=5, + n_playout=500) # set larger n_playout for better performance + self.mcts_baseline_player = MCTSPlayer(self.baseline_policy.policy_value_fn, + c_puct=5, + n_playout=500) # set larger n_playout for better performance + self.human_player = Human() + self.human_player.set_player_ind(1) + #self.mcts_baseline_player.set_player_ind(1) + self.mcts_player.set_player_ind(2) + self.players = {1:self.human_player, 2:self.mcts_player} + #self.players = {1:self.mcts_baseline_player, 2:self.mcts_player} + + self.options() + + + #黑白互换 + def change_color(self) : + self.color_count = (self.color_count + 1 ) % 2 + if self.color_count == 0 : + self.color = "black" + elif self.color_count ==1 : + self.color = "white" + + + #落子 + def chess_moving(self ,event) : + #不点击“开始”与“清空”无法再次开始落子 + if self.flag_win ==1 or self.flag_empty ==0: + return + #坐标转化为下标 + x,y = event.x-25 , event.y-25 + x = round(x/50) + y = round(y/50) + #点击位置没用落子,且没有在棋盘线外,可以落子 + while self.db[y][x] == 2 and self.limit_boarder(y,x): + if len(self.order) > 0: + last_move = self.order[-1] + last_y = last_move//9 + last_x = last_move%9 + self.change_color() + self.board.canvas.delete("chessman_new") + self.board.canvas.create_oval(25+50*last_x-15 , 25+50*last_y-15 , 25+50*last_x+15 , 25+50*last_y+15 , fill = self.color,tags = "chessman") + self.change_color() + + self.db[y][x] = self.color_count + current_move = x+9*y + self.order.append(current_move) + self.board.canvas.create_oval(25+50*x-18 , 25+50*y-18 , 25+50*x+18 , 25+50*y+18 , fill = self.color,tags = "chessman_new") + player_in_turn = self.get_current_player() + print(self.color, player_in_turn, f"{x}, {y}") + self.game.board.do_move(current_move) + end, winner = self.game.board.game_end() + if end: + self.flag_win = 1 + self.flag_empty = 0 + print(self.color, player_in_turn, "win!!!") + self.game_print.set(self.color+"-"+str(player_in_turn)+"获胜") + else: + self.change_color() + player_in_turn = self.get_current_player() + self.game_print.set("请"+self.color+"-"+str(player_in_turn)+"落子") + if player_in_turn is self.human_player: + return + self.board.window.update() + move = player_in_turn.get_action(self.game.board) + x = move%9 + y = move//9 + + + #保证棋子落在棋盘上 + def limit_boarder(self , y , x) : + if x<0 or x>8 or y<0 or y>8 : + return False + else : + return True + + + #计算连子的数目,并返回最大连子数目 + def chessman_count(self , y , x , color_count ) : + count1,count2,count3,count4 = 1,1,1,1 + #横计算 + for i in range(-1 , -5 , -1) : + if self.db[y][x+i] == color_count : + count1 += 1 + else: + break + for i in range(1 , 5 ,1 ) : + if self.db[y][x+i] == color_count : + count1 += 1 + else: + break + #竖计算 + for i in range(-1 , -5 , -1) : + if self.db[y+i][x] == color_count : + count2 += 1 + else: + break + for i in range(1 , 5 ,1 ) : + if self.db[y+i][x] == color_count : + count2 += 1 + else: + break + #/计算 + for i in range(-1 , -5 , -1) : + if self.db[y+i][x+i] == color_count : + count3 += 1 + else: + break + for i in range(1 , 5 ,1 ) : + if self.db[y+i][x+i] == color_count : + count3 += 1 + else: + break + #\计算 + for i in range(-1 , -5 , -1) : + if self.db[y+i][x-i] == color_count : + count4 += 1 + else: + break + for i in range(1 , 5 ,1 ) : + if self.db[y+i][x-i] == color_count : + count4 += 1 + else: + break + + return max(count1 , count2 , count3 , count4) + + + #判断输赢 + def game_win(self , y , x , color_count ) : + if self.chessman_count(y,x,color_count) >= 5 : + self.flag_win = 1 + self.flag_empty = 0 + return True + else : + return False + + + #悔棋,清空棋盘,再画剩下的n-1个棋子 + def withdraw(self ) : + if len(self.order)==0 or self.flag_win == 1: + return + self.board.canvas.delete("chessman") + z = self.order.pop() + x = z%9 + y = z//9 + self.db[y][x] = 2 + self.color_count = 1 + for i in self.order : + ix = i%9 + iy = i//9 + self.change_color() + self.board.canvas.create_oval(25+50*ix-15 , 25+50*iy-15 , 25+50*ix+15 , 25+50*iy+15 , fill = self.color,tags = "chessman") + self.change_color() + self.game_print.set("请"+self.color+"落子") + + + #清空 + def empty_all(self) : + self.board.canvas.delete("chessman_new") + self.board.canvas.delete("chessman") + print(" Empty all!!!") + #还原初始化 + self.db = [([2] * 9) for i in range(9)] + self.order = [] + self.color_count = 0 + self.color = 'black' + self.flag_win = 1 + self.flag_empty = 1 + self.game_print.set("") + self.start_player = (self.start_player+1)%2 + self.game.board.init_board(self.start_player) + + def get_current_player(self): + current_player = self.game.board.get_current_player() + player_in_turn = self.players[current_player] + return player_in_turn + + #将self.flag_win置0才能在棋盘上落子 + def game_start(self) : + #没有清空棋子不能置0开始 + if self.flag_empty == 0: + return + self.flag_win = 0 + print(" New game start...") + + while True: + player_in_turn = self.get_current_player() + self.game_print.set("请"+self.color+"-"+str(player_in_turn)+"落子") + self.board.window.update() + if player_in_turn is self.human_player: + return + + if len(self.order) > 0: + last_move = self.order[-1] + last_y = last_move//9 + last_x = last_move%9 + self.change_color() + self.board.canvas.delete("chessman_new") + self.board.canvas.create_oval(25+50*last_x-15 , 25+50*last_y-15 , 25+50*last_x+15 , 25+50*last_y+15 , fill = self.color,tags = "chessman") + self.change_color() + + move = player_in_turn.get_action(self.game.board) + x = move%9 + y = move//9 + self.db[y][x] = self.color_count + self.order.append(move) + self.board.canvas.create_oval(25+50*x-18 , 25+50*y-18 , 25+50*x+18 , 25+50*y+18 , fill = self.color,tags = "chessman_new") + print(self.color, player_in_turn, f"{x}, {y}") + self.game.board.do_move(move) + end, winner = self.game.board.game_end() + if end: + self.flag_win = 1 + self.flag_empty = 0 + print(self.color, player_in_turn, "win!!!") + self.game_print.set(self.color+"-"+str(player_in_turn)+"获胜") + return + else: + self.change_color() + + def options(self) : + self.board.canvas.bind("",self.chess_moving) + Label(self.board.window , textvariable = self.game_print , font = ("Arial", 12) ).place(relx = 0, rely = 0 ,x = 475 , y = 200) + Button(self.board.window , text= "开始游戏" ,command = self.game_start,width = 13, font = ("Verdana", 12)).place(relx=0, rely=0, x=475, y=15) + #Button(self.board.window , text= "我要悔棋" ,command = self.withdraw,width = 13, font = ("Verdana", 12)).place(relx=0, rely=0, x=475, y=60) + Button(self.board.window , text= "清空棋局" ,command = self.empty_all,width = 13, font = ("Verdana", 12)).place(relx=0, rely=0, x=475, y=105) + Button(self.board.window , text= "结束游戏" ,command = self.board.window.destroy,width = 13, font = ("Verdana", 12)).place(relx=0, rely=0, x=475, y=400) + self.board.window.mainloop() + + +if __name__ == "__main__": + game = Gobang() \ No newline at end of file diff --git a/human_play.py b/human_play.py index 9e80c6701..393ad8b28 100644 --- a/human_play.py +++ b/human_play.py @@ -11,10 +11,10 @@ from game import Board, Game from mcts_pure import MCTSPlayer as MCTS_Pure from mcts_alphaZero import MCTSPlayer -from policy_value_net_numpy import PolicyValueNetNumpy +# from policy_value_net_numpy import PolicyValueNetNumpy # from policy_value_net import PolicyValueNet # Theano and Lasagne # from policy_value_net_pytorch import PolicyValueNet # Pytorch -# from policy_value_net_tensorflow import PolicyValueNet # Tensorflow +from policy_value_net_res_tensorflow import PolicyValueNetRes30 # Tensorflow # from policy_value_net_keras import PolicyValueNet # Keras @@ -48,10 +48,10 @@ def __str__(self): def run(): n = 5 - width, height = 8, 8 - model_file = 'best_policy_8_8_5.model' + width, height = 9, 9 + model_file = 'output/best_policy.model' try: - board = Board(width=width, height=height, n_in_row=n) + board = Board(width=width, height=height, n_in_row=n, forbidden_hands=True) game = Game(board) # ############### human VS AI ################### @@ -61,12 +61,7 @@ def run(): # mcts_player = MCTSPlayer(best_policy.policy_value_fn, c_puct=5, n_playout=400) # load the provided model (trained in Theano/Lasagne) into a MCTS player written in pure numpy - try: - policy_param = pickle.load(open(model_file, 'rb')) - except: - policy_param = pickle.load(open(model_file, 'rb'), - encoding='bytes') # To support python3 - best_policy = PolicyValueNetNumpy(width, height, policy_param) + best_policy = PolicyValueNetRes30(width, height, 'l+', model_file=model_file) mcts_player = MCTSPlayer(best_policy.policy_value_fn, c_puct=5, n_playout=400) # set larger n_playout for better performance diff --git a/intermediate_preprocess.ipynb b/intermediate_preprocess.ipynb new file mode 100644 index 000000000..efe0cedf6 --- /dev/null +++ b/intermediate_preprocess.ipynb @@ -0,0 +1,81 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 9, + "metadata": { + "scrolled": false + }, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "2999\n" + ] + } + ], + "source": [ + "import matplotlib.pyplot as plt\n", + "import numpy as np\n", + "import pandas as pd\n", + "\n", + "def preprocess(intermediate_result_file, new_file):\n", + " new_lines = []\n", + " with open(intermediate_result_file,'r') as f:\n", + " for line in f:\n", + " if \"episode_len\" not in line and \"lr_multiplier\" not in line:\n", + " continue\n", + " \n", + " if \"episode_len\" in line:\n", + " new_line = line.strip()\n", + " elif new_line:\n", + " new_line += ', '\n", + " new_line += line\n", + " new_lines.append(new_line)\n", + " new_line = ''\n", + " print(len(new_lines))\n", + " with open(new_file,'w') as f:\n", + " f.writelines(new_lines)\n", + " \n", + "\n", + "preprocess('output/res30_l+_console.txt', \"output/res30_l+_intermediate_result_tmp.txt\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "interpreter": { + "hash": "57baa5815c940fdaff4d14510622de9616cae602444507ba5d0b6727c008cbd6" + }, + "kernelspec": { + "name": "python3", + "display_name": "Python 3.7.5 64-bit" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.7.5" + }, + "metadata": { + "interpreter": { + "hash": "57baa5815c940fdaff4d14510622de9616cae602444507ba5d0b6727c008cbd6" + } + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} \ No newline at end of file diff --git a/loss_plot.ipynb b/loss_plot.ipynb new file mode 100644 index 000000000..b2f86224e --- /dev/null +++ b/loss_plot.ipynb @@ -0,0 +1,228 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "scrolled": false + }, + "outputs": [ + { + "output_type": "display_data", + "data": { + "text/plain": "
", + "image/svg+xml": "\r\n\r\n\r\n\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n\r\n", + "image/png": "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\n" + }, + "metadata": { + "needs_background": "light" + } + }, + { + "output_type": "display_data", + "data": { + "text/plain": "
", + "image/svg+xml": "\r\n\r\n\r\n\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n\r\n", + "image/png": "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\n" + }, + "metadata": { + "needs_background": "light" + } + }, + { + "output_type": "display_data", + "data": { + "text/plain": "
", + "image/svg+xml": "\r\n\r\n\r\n\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n\r\n", + "image/png": "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\n" + }, + "metadata": { + "needs_background": "light" + } + }, + { + "output_type": "display_data", + "data": { + "text/plain": "
", + "image/svg+xml": "\r\n\r\n\r\n\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n\r\n", + "image/png": "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\n" + }, + "metadata": { + "needs_background": "light" + } + } + ], + "source": [ + "import matplotlib.pyplot as plt\n", + "import numpy as np\n", + "import pandas as pd\n", + "\n", + "def loss_plot(intermediate_result_file, model_name):\n", + " batch = []\n", + " loss = []\n", + " value_loss = []\n", + " policy_loss = []\n", + " entropy = []\n", + " with open(intermediate_result_file,'r') as f:\n", + " for line in f:\n", + " line = line.strip().split(',')\n", + " batch.append(line[0].split(':')[-1])\n", + " loss.append(line[4].split(':')[-1])\n", + " value_loss.append(line[5].split(':')[-1])\n", + " policy_loss.append(line[6].split(':')[-1])\n", + " entropy.append(line[7].split(':')[-1])\n", + "\n", + " batch = np.array(batch).astype(int)\n", + " loss = np.array(loss).astype(float)\n", + " value_loss = np.array(value_loss).astype(float)\n", + " policy_loss = np.array(policy_loss).astype(float)\n", + " entropy = np.array(entropy).astype(float)\n", + "\n", + " plt.plot(batch, loss, label='loss')\n", + " plt.plot(batch, value_loss, label='value loss')\n", + " plt.plot(batch, policy_loss, label='policy loss')\n", + " plt.legend()\n", + " plt.title(model_name + ' loss')\n", + " plt.xlabel('batch num')\n", + " plt.ylabel('loss')\n", + " plt.grid(axis='y')\n", + " plt.show()\n", + " return pd.DataFrame(data=[batch, loss]).T\n", + "\n", + "def win_ratio_plot(scores_result_file_1, model_name_1, scores_result_file_2, model_name_2):\n", + " batch_50_1 = []\n", + " win_ratio_1 = []\n", + " with open(scores_result_file_1,'r') as f:\n", + " for line in f:\n", + " line = line.strip().split(',')\n", + " batch_50_1.append(line[0].split(':')[-1])\n", + " win_ratio_1.append(line[-1].split(':')[-1])\n", + "\n", + " batch_50_1 = np.array(batch_50_1).astype(int)\n", + " win_ratio_1 = np.array(win_ratio_1).astype(float)\n", + "\n", + " batch_50_2 = []\n", + " win_ratio_2 = []\n", + " with open(scores_result_file_2,'r') as f:\n", + " for line in f:\n", + " line = line.strip().split(',')\n", + " batch_50_2.append(line[0].split(':')[-1])\n", + " win_ratio_2.append(line[-1].split(':')[-1])\n", + "\n", + " batch_50_2 = np.array(batch_50_2).astype(int)\n", + " win_ratio_2 = np.array(win_ratio_2).astype(float)\n", + "\n", + " plt.plot(batch_50_1, win_ratio_1, label=model_name_1 + ' win ratio')\n", + " plt.plot(batch_50_2, win_ratio_2, label=model_name_2 + ' win ratio')\n", + " plt.legend()\n", + " plt.title('win ratio')\n", + " plt.xlabel('batch num')\n", + " plt.ylabel('win ratio')\n", + " plt.grid(axis='y')\n", + " plt.show()\n", + "\n", + "win_ratio_plot('output/scores.txt', 'baseline', 'output/res30_l+_scores.txt', 'res30')\n", + "\n", + "df_baseline = loss_plot('output/intermediate_result.txt', 'baseline')\n", + "df_baseline.columns = ['batch_num', 'loss_baseline']\n", + "df_res30 = loss_plot('output/res30_l+_intermediate_result.txt', 'res30')\n", + "df_res30.columns = ['batch_num', 'loss_res30']\n", + "df_merged = pd.merge(df_baseline, df_res30, how='left', on='batch_num')\n", + "plt.plot(df_merged['batch_num'], df_merged['loss_baseline'], label='loss baseline')\n", + "plt.plot(df_merged['batch_num'], df_merged['loss_res30'], label='loss res30')\n", + "plt.legend()\n", + "plt.title('Loss Comparison')\n", + "plt.xlabel('batch num')\n", + "plt.ylabel('loss')\n", + "plt.grid(axis='y')\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [], + "source": [ + "def rescue_code(function):\n", + " import inspect\n", + " get_ipython().set_next_input(\"\".join(inspect.getsourcelines(function)[0]))\n", + "\n", + "rescue_code(loss_plot)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def loss_plot(intermediate_result_file):\n", + " batch = []\n", + " loss = []\n", + " value_loss = []\n", + " policy_loss = []\n", + " entropy = []\n", + " with open(intermediate_result_file,'r') as f:\n", + " for line in f:\n", + " line = line.strip().split(',')\n", + " batch.append(line[0].split(':')[-1])\n", + " loss.append(line[4].split(':')[-1])\n", + " value_loss.append(line[5].split(':')[-1])\n", + " policy_loss.append(line[6].split(':')[-1])\n", + " entropy.append(line[7].split(':')[-1])\n", + "\n", + " batch = np.array(batch).astype(float)\n", + " loss = np.array(loss).astype(float)\n", + " value_loss = np.array(value_loss).astype(float)\n", + " policy_loss = np.array(policy_loss).astype(float)\n", + " entropy = np.array(entropy).astype(float)\n", + "\n", + " plt.plot(batch, loss, label='loss')\n", + " plt.plot(batch, value_loss, label='value loss')\n", + " plt.plot(batch, policy_loss, label='policy loss')\n", + " plt.legend()\n", + " plt.title('loss')\n", + " plt.xlabel('batch num')\n", + " plt.ylabel('loss')\n", + " plt.grid(axis='y')\n", + " plt.show()\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "interpreter": { + "hash": "57baa5815c940fdaff4d14510622de9616cae602444507ba5d0b6727c008cbd6" + }, + "kernelspec": { + "name": "python3", + "display_name": "Python 3.7.5 64-bit" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.7.5" + }, + "metadata": { + "interpreter": { + "hash": "57baa5815c940fdaff4d14510622de9616cae602444507ba5d0b6727c008cbd6" + } + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} \ No newline at end of file diff --git a/mcts_alphaZero.py b/mcts_alphaZero.py index 214e0ed9b..096ef7ce1 100644 --- a/mcts_alphaZero.py +++ b/mcts_alphaZero.py @@ -215,4 +215,4 @@ def get_action(self, board, temp=1e-3, return_prob=0): print("WARNING: the board is full") def __str__(self): - return "MCTS {}".format(self.player) + return "AI {}".format(self.player) diff --git a/mcts_pure.py b/mcts_pure.py index 92a67484c..734eed757 100644 --- a/mcts_pure.py +++ b/mcts_pure.py @@ -133,6 +133,7 @@ def _playout(self, state): # Evaluate the leaf node by random rollout leaf_value = self._evaluate_rollout(state) # Update value and visit count of nodes in this traversal. + # This leaf value is used for parent, so if evaluation value is 1, then current player win, and this node's value should be -1. node.update_recursive(-leaf_value) def _evaluate_rollout(self, state, limit=1000): diff --git a/output/baseline_policy.model.data-00000-of-00001 b/output/baseline_policy.model.data-00000-of-00001 new file mode 100644 index 000000000..ce068a20a Binary files /dev/null and b/output/baseline_policy.model.data-00000-of-00001 differ diff --git a/output/baseline_policy.model.index b/output/baseline_policy.model.index new file mode 100644 index 000000000..48afa340a Binary files /dev/null and b/output/baseline_policy.model.index differ diff --git a/output/best_policy.model.data-00000-of-00001 b/output/best_policy.model.data-00000-of-00001 new file mode 100644 index 000000000..1b82e2f29 Binary files /dev/null and b/output/best_policy.model.data-00000-of-00001 differ diff --git a/output/best_policy.model.index b/output/best_policy.model.index new file mode 100644 index 000000000..3a7014476 Binary files /dev/null and b/output/best_policy.model.index differ diff --git a/policy_value_net_res_tensorflow.py b/policy_value_net_res_tensorflow.py new file mode 100644 index 000000000..b4b75989b --- /dev/null +++ b/policy_value_net_res_tensorflow.py @@ -0,0 +1,191 @@ +# -*- coding: utf-8 -*- +""" +An implementation of the policyValueNet in Tensorflow +Tested in Tensorflow 1.4 and 1.5 + +@author: Chunlei Wang +""" + +import numpy as np +import tensorflow as tf +from tensorflow.contrib.layers.python.layers import batch_norm as batch_norm +from game import INPUT_STATE_CHANNEL_SIZE + +class PolicyValueNetRes30(): + def __init__(self, board_width, board_height, loss_function, model_file=None): + self.board_width = board_width + self.board_height = board_height + + self.graph = tf.Graph() # create graph for each instance individuly + with self.graph.as_default(): + self.is_training = tf.placeholder(tf.bool) + # Define the tensorflow neural network + # 1. Input: + self.input_states = tf.placeholder( + tf.float32, shape=[None, INPUT_STATE_CHANNEL_SIZE, board_height, board_width]) + self.input_state = tf.transpose(self.input_states, [0, 2, 3, 1]) + + # 2. Common Networks Layers + self.block1 = self._block(self.input_state, 32, 3, is_training=self.is_training, scope="block1") + self.block2 = self._block(self.block1, 64, 3, is_training=self.is_training, scope="block2") + self.block3 = self._block(self.block2, 128, 3, is_training=self.is_training, scope="block3") + + # 3-1 Action Networks + self.action_conv = tf.layers.conv2d(inputs=self.block3, filters=4, + kernel_size=[1, 1], padding="same", + data_format="channels_last", + activation=tf.nn.relu) + # Flatten the tensor + self.action_conv_flat = tf.reshape( + self.action_conv, [-1, 4 * board_height * board_width]) + # 3-2 Full connected layer, the output is the log probability of moves + # on each slot on the board + self.action_fc = tf.layers.dense(inputs=self.action_conv_flat, + units=board_height * board_width, + activation=tf.nn.log_softmax) + # 4 Evaluation Networks + self.evaluation_conv = tf.layers.conv2d(inputs=self.block3, filters=2, + kernel_size=[1, 1], + padding="same", + data_format="channels_last", + activation=tf.nn.relu) + self.evaluation_conv_flat = tf.reshape( + self.evaluation_conv, [-1, 2 * board_height * board_width]) + self.evaluation_fc1 = tf.layers.dense(inputs=self.evaluation_conv_flat, + units=64, activation=tf.nn.relu) + # output the score of evaluation on current state + self.evaluation_fc2 = tf.layers.dense(inputs=self.evaluation_fc1, + units=1, activation=tf.nn.tanh) + + # Define the Loss function + # 1. Label: the array containing if the game wins or not for each state + self.labels = tf.placeholder(tf.float32, shape=[None, 1]) + # 2. Predictions: the array containing the evaluation score of each state + # which is self.evaluation_fc2 + # 3-1. Value Loss function + self.value_loss = tf.losses.mean_squared_error(self.labels, + self.evaluation_fc2) + # 3-2. Policy Loss function + self.mcts_probs = tf.placeholder( + tf.float32, shape=[None, board_height * board_width]) + self.policy_loss = tf.negative(tf.reduce_mean( + tf.reduce_sum(tf.multiply(self.mcts_probs, self.action_fc), 1))) + # 3-3. L2 penalty (regularization) + l2_penalty_beta = 1e-4 + vars = tf.trainable_variables() + l2_penalty = l2_penalty_beta * tf.add_n( + [tf.nn.l2_loss(v) for v in vars if 'bias' not in v.name.lower()]) + # 3-4 Add up to be the Loss function + if loss_function == 'lv': + self.loss = self.value_loss + l2_penalty + elif loss_function == 'lp': + self.loss = self.policy_loss + l2_penalty + elif loss_function == 'l+': + self.loss = self.value_loss + self.policy_loss + l2_penalty + elif loss_function == 'lx': + self.loss = self.value_loss * self.policy_loss + l2_penalty + + # Define the optimizer we use for training + self.learning_rate = tf.placeholder(tf.float32) + + self.adam_optimizer = tf.train.AdamOptimizer( + learning_rate=self.learning_rate).minimize(self.loss) + + # Make a session + self.session = tf.Session(graph=self.graph) + + # calc policy entropy, for monitoring only + self.entropy = tf.negative(tf.reduce_mean( + tf.reduce_sum(tf.exp(self.action_fc) * self.action_fc, 1))) + + # Initialize variables + init = tf.global_variables_initializer() + self.session.run(init) + + # For saving and restoring + self.saver = tf.train.Saver() + if model_file is not None: + self.restore_model(model_file) + + ''' + self.mom_optimizer = tf.train.MomentumOptimizer( + learning_rate=self.learning_rate,momentum=0.9).minimize(self.loss) + var_list = [var for var in tf.global_variables() if 'Momentum' in var.name] + self.session.run(tf.variables_initializer(var_list)) + ''' + def _batch_norm(self, x, is_training, scope="bn"): + z = tf.cond(is_training, lambda: batch_norm(x, decay=0.9, center=True, scale=True, updates_collections=None,is_training=True, reuse=None, trainable=True, scope=scope), + lambda: batch_norm(x, decay=0.9, center=True, scale=True, updates_collections=None,is_training=False, reuse=True, trainable=False, scope=scope)) + return z + + def _block(self, x, n_out, n, is_training, scope="block"): + with tf.variable_scope(scope): + out = self._bottleneck(x, n_out, is_training, scope="bottleneck1") + for i in range(1, n): + out = self._bottleneck(out, n_out, is_training, scope=("bottleneck%s" % (i + 1))) + return out + + def _bottleneck(self, x, n_out, is_training, scope="bottleneck"): + """ A residual bottleneck unit""" + n_in = x.get_shape()[-1] + + with tf.variable_scope(scope): + h = tf.layers.conv2d(inputs=x, filters=n_out, kernel_size=[3, 3], padding="same", data_format="channels_last", activation=None) + h = self._batch_norm(h, is_training, scope="bn_1") + h = tf.nn.relu(h) + h = tf.layers.conv2d(inputs=h, filters=n_out, kernel_size=[3, 3], padding="same", data_format="channels_last", activation=None) + h = self._batch_norm(h, is_training, scope="bn_2") + h = tf.nn.relu(h) + h = tf.layers.conv2d(inputs=h, filters=n_out, kernel_size=[3, 3], padding="same", data_format="channels_last", activation=None) + h = self._batch_norm(h, is_training, scope="bn_3") + + if n_in != n_out: + shortcut = tf.layers.conv2d(inputs=x, filters=n_out, kernel_size=[1, 1], padding="same", data_format="channels_last", activation=None) + shortcut = self._batch_norm(shortcut, is_training, scope="bn_4") + else: + shortcut = self._batch_norm(x, is_training, scope="bn_4") + return tf.nn.relu(self._batch_norm(shortcut + h, is_training, scope="bn_5")) + + def policy_value(self, state_batch): + """ + input: a batch of states + output: a batch of action probabilities and state values + """ + log_act_probs, value = self.session.run( + [self.action_fc, self.evaluation_fc2], + feed_dict={self.input_states: state_batch, + self.is_training: False} + ) + act_probs = np.exp(log_act_probs) + return act_probs, value + + def policy_value_fn(self, board): + """ + input: board + output: a list of (action, probability) tuples for each available + action and the score of the board state + """ + legal_positions = board.availables + current_state = np.ascontiguousarray(board.current_last16move_state().reshape( + -1, INPUT_STATE_CHANNEL_SIZE, self.board_width, self.board_height)) + act_probs, value = self.policy_value(current_state) + act_probs = zip(legal_positions, act_probs[0][legal_positions]) + return act_probs, value + + def train_step(self, state_batch, mcts_probs, winner_batch, lr): + """perform a training step""" + winner_batch = np.reshape(winner_batch, (-1, 1)) + loss, value_loss, policy_loss, entropy, _ = self.session.run( + [self.loss, self.value_loss, self.policy_loss, self.entropy, self.adam_optimizer], + feed_dict={self.input_states: state_batch, + self.mcts_probs: mcts_probs, + self.labels: winner_batch, + self.learning_rate: lr, + self.is_training: True}) + return loss, value_loss, policy_loss, entropy + + def save_model(self, model_path): + self.saver.save(self.session, model_path) + + def restore_model(self, model_path): + self.saver.restore(self.session, model_path) diff --git a/policy_value_net_tensorflow.py b/policy_value_net_tensorflow.py index 589110708..e5b1b0d7f 100644 --- a/policy_value_net_tensorflow.py +++ b/policy_value_net_tensorflow.py @@ -11,96 +11,105 @@ class PolicyValueNet(): - def __init__(self, board_width, board_height, model_file=None): + def __init__(self, board_width, board_height, loss_function, model_file=None): self.board_width = board_width self.board_height = board_height - # Define the tensorflow neural network - # 1. Input: - self.input_states = tf.placeholder( - tf.float32, shape=[None, 4, board_height, board_width]) - self.input_state = tf.transpose(self.input_states, [0, 2, 3, 1]) - # 2. Common Networks Layers - self.conv1 = tf.layers.conv2d(inputs=self.input_state, - filters=32, kernel_size=[3, 3], - padding="same", data_format="channels_last", - activation=tf.nn.relu) - self.conv2 = tf.layers.conv2d(inputs=self.conv1, filters=64, - kernel_size=[3, 3], padding="same", - data_format="channels_last", - activation=tf.nn.relu) - self.conv3 = tf.layers.conv2d(inputs=self.conv2, filters=128, - kernel_size=[3, 3], padding="same", - data_format="channels_last", - activation=tf.nn.relu) - # 3-1 Action Networks - self.action_conv = tf.layers.conv2d(inputs=self.conv3, filters=4, + self.graph = tf.Graph() # create graph for each instance individuly + with self.graph.as_default(): + # Define the tensorflow neural network + # 1. Input: + self.input_states = tf.placeholder( + tf.float32, shape=[None, 4, board_height, board_width]) + self.input_state = tf.transpose(self.input_states, [0, 2, 3, 1]) + # 2. Common Networks Layers + self.conv1 = tf.layers.conv2d(inputs=self.input_state, + filters=32, kernel_size=[3, 3], + padding="same", data_format="channels_last", + activation=tf.nn.relu) + self.conv2 = tf.layers.conv2d(inputs=self.conv1, filters=64, + kernel_size=[3, 3], padding="same", + data_format="channels_last", + activation=tf.nn.relu) + self.conv3 = tf.layers.conv2d(inputs=self.conv2, filters=128, + kernel_size=[3, 3], padding="same", + data_format="channels_last", + activation=tf.nn.relu) + # 3-1 Action Networks + self.action_conv = tf.layers.conv2d(inputs=self.conv3, filters=4, kernel_size=[1, 1], padding="same", data_format="channels_last", activation=tf.nn.relu) - # Flatten the tensor - self.action_conv_flat = tf.reshape( - self.action_conv, [-1, 4 * board_height * board_width]) - # 3-2 Full connected layer, the output is the log probability of moves - # on each slot on the board - self.action_fc = tf.layers.dense(inputs=self.action_conv_flat, - units=board_height * board_width, - activation=tf.nn.log_softmax) - # 4 Evaluation Networks - self.evaluation_conv = tf.layers.conv2d(inputs=self.conv3, filters=2, - kernel_size=[1, 1], - padding="same", - data_format="channels_last", - activation=tf.nn.relu) - self.evaluation_conv_flat = tf.reshape( - self.evaluation_conv, [-1, 2 * board_height * board_width]) - self.evaluation_fc1 = tf.layers.dense(inputs=self.evaluation_conv_flat, - units=64, activation=tf.nn.relu) - # output the score of evaluation on current state - self.evaluation_fc2 = tf.layers.dense(inputs=self.evaluation_fc1, - units=1, activation=tf.nn.tanh) - - # Define the Loss function - # 1. Label: the array containing if the game wins or not for each state - self.labels = tf.placeholder(tf.float32, shape=[None, 1]) - # 2. Predictions: the array containing the evaluation score of each state - # which is self.evaluation_fc2 - # 3-1. Value Loss function - self.value_loss = tf.losses.mean_squared_error(self.labels, - self.evaluation_fc2) - # 3-2. Policy Loss function - self.mcts_probs = tf.placeholder( - tf.float32, shape=[None, board_height * board_width]) - self.policy_loss = tf.negative(tf.reduce_mean( - tf.reduce_sum(tf.multiply(self.mcts_probs, self.action_fc), 1))) - # 3-3. L2 penalty (regularization) - l2_penalty_beta = 1e-4 - vars = tf.trainable_variables() - l2_penalty = l2_penalty_beta * tf.add_n( + # Flatten the tensor + self.action_conv_flat = tf.reshape( + self.action_conv, [-1, 4 * board_height * board_width]) + # 3-2 Full connected layer, the output is the log probability of moves + # on each slot on the board + self.action_fc = tf.layers.dense(inputs=self.action_conv_flat, + units=board_height * board_width, + activation=tf.nn.log_softmax) + # 4 Evaluation Networks + self.evaluation_conv = tf.layers.conv2d(inputs=self.conv3, filters=2, + kernel_size=[1, 1], + padding="same", + data_format="channels_last", + activation=tf.nn.relu) + self.evaluation_conv_flat = tf.reshape( + self.evaluation_conv, [-1, 2 * board_height * board_width]) + self.evaluation_fc1 = tf.layers.dense(inputs=self.evaluation_conv_flat, + units=64, activation=tf.nn.relu) + # output the score of evaluation on current state + self.evaluation_fc2 = tf.layers.dense(inputs=self.evaluation_fc1, + units=1, activation=tf.nn.tanh) + + # Define the Loss function + # 1. Label: the array containing if the game wins or not for each state + self.labels = tf.placeholder(tf.float32, shape=[None, 1]) + # 2. Predictions: the array containing the evaluation score of each state + # which is self.evaluation_fc2 + # 3-1. Value Loss function + self.value_loss = tf.losses.mean_squared_error(self.labels, + self.evaluation_fc2) + # 3-2. Policy Loss function + self.mcts_probs = tf.placeholder( + tf.float32, shape=[None, board_height * board_width]) + self.policy_loss = tf.negative(tf.reduce_mean( + tf.reduce_sum(tf.multiply(self.mcts_probs, self.action_fc), 1))) + # 3-3. L2 penalty (regularization) + l2_penalty_beta = 1e-4 + vars = tf.trainable_variables() + l2_penalty = l2_penalty_beta * tf.add_n( [tf.nn.l2_loss(v) for v in vars if 'bias' not in v.name.lower()]) - # 3-4 Add up to be the Loss function - self.loss = self.value_loss + self.policy_loss + l2_penalty - - # Define the optimizer we use for training - self.learning_rate = tf.placeholder(tf.float32) - self.optimizer = tf.train.AdamOptimizer( - learning_rate=self.learning_rate).minimize(self.loss) - - # Make a session - self.session = tf.Session() - - # calc policy entropy, for monitoring only - self.entropy = tf.negative(tf.reduce_mean( - tf.reduce_sum(tf.exp(self.action_fc) * self.action_fc, 1))) - - # Initialize variables - init = tf.global_variables_initializer() - self.session.run(init) - - # For saving and restoring - self.saver = tf.train.Saver() - if model_file is not None: - self.restore_model(model_file) + # 3-4 Add up to be the Loss function + if loss_function == 'lv': + self.loss = self.value_loss + l2_penalty + elif loss_function == 'lp': + self.loss = self.policy_loss + l2_penalty + elif loss_function == 'l+': + self.loss = self.value_loss + self.policy_loss + l2_penalty + elif loss_function == 'lx': + self.loss = self.value_loss * self.policy_loss + l2_penalty + + # Define the optimizer we use for training + self.learning_rate = tf.placeholder(tf.float32) + self.optimizer = tf.train.AdamOptimizer( + learning_rate=self.learning_rate).minimize(self.loss) + + # calc policy entropy, for monitoring only + self.entropy = tf.negative(tf.reduce_mean( + tf.reduce_sum(tf.exp(self.action_fc) * self.action_fc, 1))) + + # Make a session + self.session = tf.Session(graph=self.graph) + + # Initialize variables + init = tf.global_variables_initializer() + self.session.run(init) + + # For saving and restoring + self.saver = tf.train.Saver() + if model_file is not None: + self.restore_model(model_file) def policy_value(self, state_batch): """ @@ -130,13 +139,13 @@ def policy_value_fn(self, board): def train_step(self, state_batch, mcts_probs, winner_batch, lr): """perform a training step""" winner_batch = np.reshape(winner_batch, (-1, 1)) - loss, entropy, _ = self.session.run( - [self.loss, self.entropy, self.optimizer], + loss, value_loss, policy_loss, entropy, _ = self.session.run( + [self.loss, self.value_loss, self.policy_loss, self.entropy, self.optimizer], feed_dict={self.input_states: state_batch, self.mcts_probs: mcts_probs, self.labels: winner_batch, self.learning_rate: lr}) - return loss, entropy + return loss, value_loss, policy_loss, entropy def save_model(self, model_path): self.saver.save(self.session, model_path) diff --git a/train.py b/train.py index d33a20879..d461f9248 100644 --- a/train.py +++ b/train.py @@ -12,27 +12,32 @@ from game import Board, Game from mcts_pure import MCTSPlayer as MCTS_Pure from mcts_alphaZero import MCTSPlayer -from policy_value_net import PolicyValueNet # Theano and Lasagne -# from policy_value_net_pytorch import PolicyValueNet # Pytorch -# from policy_value_net_tensorflow import PolicyValueNet # Tensorflow -# from policy_value_net_keras import PolicyValueNet # Keras - +#from policy_value_net import PolicyValueNet # Theano and Lasagne +#from policy_value_net_pytorch import PolicyValueNet # Pytorch +from policy_value_net_tensorflow import PolicyValueNet # Tensorflow +#from policy_value_net_keras import PolicyValueNet # Keras +from policy_value_net_res_tensorflow import PolicyValueNetRes30 # Tensorflow +from datetime import datetime +import utils +import os +import argparse class TrainPipeline(): - def __init__(self, init_model=None): + def __init__(self, model_name, loss_function, forbidden_hands, init_model=None): # params of the board and the game - self.board_width = 6 - self.board_height = 6 - self.n_in_row = 4 + self.board_width = 9 + self.board_height = 9 + self.n_in_row = 5 self.board = Board(width=self.board_width, height=self.board_height, - n_in_row=self.n_in_row) + n_in_row=self.n_in_row, + forbidden_hands=forbidden_hands) self.game = Game(self.board) # training params self.learn_rate = 2e-3 self.lr_multiplier = 1.0 # adaptively adjust the learning rate based on KL self.temp = 1.0 # the temperature param - self.n_playout = 400 # num of simulations for each move + self.n_playout = 1000 # num of simulations for each move self.c_puct = 5 self.buffer_size = 10000 self.batch_size = 512 # mini-batch size for training @@ -41,20 +46,35 @@ def __init__(self, init_model=None): self.epochs = 5 # num of train_steps for each update self.kl_targ = 0.02 self.check_freq = 50 - self.game_batch_num = 1500 + self.game_batch_num = 3000 self.best_win_ratio = 0.0 # num of simulations used for the pure mcts, which is used as # the opponent to evaluate the trained policy self.pure_mcts_playout_num = 1000 + self.model_name = model_name if init_model: # start training from an initial policy-value net - self.policy_value_net = PolicyValueNet(self.board_width, - self.board_height, - model_file=init_model) + if self.model_name == 'baseline': + self.policy_value_net = PolicyValueNet(self.board_width, + self.board_height, + loss_function, + model_file=init_model) + else: + self.policy_value_net = PolicyValueNetRes30(self.board_width, + self.board_height, + loss_function, + model_file=init_model) else: # start training from a new policy-value net - self.policy_value_net = PolicyValueNet(self.board_width, - self.board_height) + if self.model_name == 'baseline': + self.policy_value_net = PolicyValueNet(self.board_width, + self.board_height, + loss_function) + else: + self.policy_value_net = PolicyValueNetRes30(self.board_width, + self.board_height, + loss_function) + self.mcts_player = MCTSPlayer(self.policy_value_net.policy_value_fn, c_puct=self.c_puct, n_playout=self.n_playout, @@ -86,14 +106,15 @@ def collect_selfplay_data(self, n_games=1): """collect self-play data for training""" for i in range(n_games): winner, play_data = self.game.start_self_play(self.mcts_player, - temp=self.temp) + self.model_name, + temp=self.temp) play_data = list(play_data)[:] self.episode_len = len(play_data) # augment the data play_data = self.get_equi_data(play_data) self.data_buffer.extend(play_data) - def policy_update(self): + def policy_update(self, batch_num, episode_len): """update the policy-value net""" mini_batch = random.sample(self.data_buffer, self.batch_size) state_batch = [data[0] for data in mini_batch] @@ -101,7 +122,7 @@ def policy_update(self): winner_batch = [data[2] for data in mini_batch] old_probs, old_v = self.policy_value_net.policy_value(state_batch) for i in range(self.epochs): - loss, entropy = self.policy_value_net.train_step( + loss, value_loss, policy_loss, entropy = self.policy_value_net.train_step( state_batch, mcts_probs_batch, winner_batch, @@ -125,21 +146,30 @@ def policy_update(self): explained_var_new = (1 - np.var(np.array(winner_batch) - new_v.flatten()) / np.var(np.array(winner_batch))) - print(("kl:{:.5f}," - "lr_multiplier:{:.3f}," - "loss:{}," - "entropy:{}," - "explained_var_old:{:.3f}," - "explained_var_new:{:.3f}" - ).format(kl, + + utils.log(("batch:{}," + "episode_len:{}," + "kl:{:.5f}," + "lr_multiplier:{:.3f}," + "loss:{}," + "value_loss:{}," + "policy_loss:{}," + "entropy:{}," + "explained_var_old:{:.3f}," + "explained_var_new:{:.3f}" + ).format(batch_num, + episode_len, + kl, self.lr_multiplier, loss, + value_loss, + policy_loss, entropy, explained_var_old, - explained_var_new)) + explained_var_new), INTERMEDIATE_RESULT) return loss, entropy - def policy_evaluate(self, n_games=10): + def policy_evaluate(self, current_batch, n_games=10): """ Evaluate the trained policy by playing against the pure MCTS player Note: this is only for monitoring the progress of training @@ -157,9 +187,14 @@ def policy_evaluate(self, n_games=10): is_shown=0) win_cnt[winner] += 1 win_ratio = 1.0*(win_cnt[1] + 0.5*win_cnt[-1]) / n_games - print("num_playouts:{}, win: {}, lose: {}, tie:{}".format( + + output = "current_batch:{},num_playouts:{},win:{},lose:{},tie:{},win_ratio:{}".format( + current_batch, self.pure_mcts_playout_num, - win_cnt[1], win_cnt[2], win_cnt[-1])) + win_cnt[1], win_cnt[2], win_cnt[-1], win_ratio) + + utils.log(output, SCORE_OUTPUT) + return win_ratio def run(self): @@ -167,21 +202,19 @@ def run(self): try: for i in range(self.game_batch_num): self.collect_selfplay_data(self.play_batch_size) - print("batch i:{}, episode_len:{}".format( - i+1, self.episode_len)) if len(self.data_buffer) > self.batch_size: - loss, entropy = self.policy_update() + loss, entropy = self.policy_update(i+1, self.episode_len) # check the performance of the current model, # and save the model params if (i+1) % self.check_freq == 0: - print("current self-play batch: {}".format(i+1)) - win_ratio = self.policy_evaluate() - self.policy_value_net.save_model('./current_policy.model') - if win_ratio > self.best_win_ratio: - print("New best policy!!!!!!!!") + utils.log("current self-play batch: {}".format(i+1), CONSOLE_OUTPUT) + win_ratio = self.policy_evaluate(current_batch=i+1) + self.policy_value_net.save_model(OUTPUT_DIR+'/current_policy.model') + if win_ratio >= self.best_win_ratio: + utils.log("New best policy!!!!!!!!", CONSOLE_OUTPUT) self.best_win_ratio = win_ratio # update the best_policy - self.policy_value_net.save_model('./best_policy.model') + self.policy_value_net.save_model(OUTPUT_DIR+'/best_policy.model') if (self.best_win_ratio == 1.0 and self.pure_mcts_playout_num < 5000): self.pure_mcts_playout_num += 1000 @@ -191,5 +224,37 @@ def run(self): if __name__ == '__main__': - training_pipeline = TrainPipeline() + parser = argparse.ArgumentParser(prog='train.py') + parser.add_argument('--ModelName', '-m', dest='ModelName', required=True, choices=['baseline', 'res30']) + parser.add_argument('--LossFunction', '-l', dest='LossFunction', required=True, choices=['lv', 'lp', 'l+', 'lx']) + parser.add_argument('--EnableForbiddenHands', '-fh', dest='EnableForbiddenHands', action='store_false', help=r'Enable forbidden hands') + + args = parser.parse_args() + model_name = args.ModelName + loss_function = args.LossFunction + forbidden_hands = args.EnableForbiddenHands + + OUTPUT_DIR = "output/" + OUTPUT_DIR += model_name + OUTPUT_DIR += "_" + loss_function + OUTPUT_DIR += "_forbiddenhands/" if forbidden_hands else "/" + init_model = OUTPUT_DIR + "current_policy.model" + if not os.path.exists(init_model): + init_model = None + OUTPUT_DIR += datetime.utcnow().strftime("%Y%m%d%H%M%S") + os.makedirs(OUTPUT_DIR, exist_ok=True) + INTERMEDIATE_RESULT = OUTPUT_DIR + "/intermediate_result.txt" + SCORE_OUTPUT = OUTPUT_DIR + "/scores.txt" + CONSOLE_OUTPUT = OUTPUT_DIR + "/console.txt" + + print("**************************************************************") + print("Start new training process...") + print(f"ModelName: {model_name}, LossFunction: {loss_function}, EnableForbiddenHands: {forbidden_hands}") + print(f"init model : {init_model}") + print(f"intermediate result : {INTERMEDIATE_RESULT}") + print(f"score output : {SCORE_OUTPUT}") + print(f"console output : {CONSOLE_OUTPUT}") + print("**************************************************************") + + training_pipeline = TrainPipeline(model_name, loss_function, forbidden_hands, init_model) training_pipeline.run() diff --git a/utils.py b/utils.py new file mode 100644 index 000000000..43a19ed71 --- /dev/null +++ b/utils.py @@ -0,0 +1,10 @@ +from datetime import datetime +import os + +def log(message, logpath): + timestamp = datetime.utcnow().strftime("%Y-%m-%d %H:%M:%S ") + message = timestamp + message + print(message) + os.makedirs(os.path.dirname(logpath), exist_ok=True) + with open(logpath,'a+') as fs: + fs.write(message+'\n')