上一节我们完成了围棋机器人,也就是Agent,它所面临的环境就是当前棋盘状况。Agent有自己的“脑子”,也就是它自己附带着一个经过人类棋手所产生棋盘数据训练后的网络,由于网络采用人类业余高段位的棋手产生的棋盘数据训练,因此它也具备相当水平,现在问题是如何让它像AlphaGo那样具备超过人类能力的落子水平。
我们现在要使用的办法是生成两个Agent,然后让他们相互对弈,我们把对弈过程的每次落子和最终结果结合起来作为数据,然后反向去训练Agent,如此能让电脑在自动化情况下实现棋艺自我提升。相应代码如下:
def simulate_game(black_player, white_player):
moves = []
game = GameState.new_game(19)
agents = {
Player.black: black_player,
Player.white: white_player
}
while not game.is_over(): #让两个机器人对弈
next_move = agents[game.next_player].select_move(game)
moves.append(next_move) #记录每一步落子
game = game.apply_move(next_move)
game_result = compute_game_result(game) #计算最终输赢,前面章节实现过这个函数
return game_result.winner
增强式学习的本质实际上是通过自动化的方式产生大量数据,然后使用神经网络分析数据,掌握数据中隐含的统计规律,从而让计算机找到处理问题的自动化方法。上面代码我们使用两个机器人产生了大量数据,这些数据中就包含了围棋走法规律,这里跟我们以前使用两个随机落子机器人不同之处在于,机器人落子模拟了人类棋手落子规律,应为Agent中使用的网络时经过人类棋手数据训练过。
有了大量数据之后,我们可以通过棋盘数据对应的胜负情况来分析在给定棋盘形式下,每一步落子的好坏。而且这种自我对弈的优点在于系统可以一次从输赢两方面同时获得经验,上面模拟对弈产生输赢后,网络可以从赢家的落子方式抽取出好的落子方式,从输家的落子方式中抽取坏的落子方式,于是网络就能通过一次虚拟对弈获得双重经验。
接下来我们启动两个机器人的对弈过程,同时用上一节构造的ExperienceCollector来收集他们的落子步骤:
def experience_simulation(num_games, agent1, agent2): #让两个机器人模拟对弈
collector1 = ExperienceCollector()
collector2 = ExperienceCollector()
color1 = Player.black
for i in range(num_games): #收集两个机器人的落子步骤
collector1.begin_episode()
agent1.set_collector(collector1)
collector2.begin_episode()
agent2.set_collector(collector2)
if color1 == Player.black:
black_player, white_player = agent1, agent2
else:
white_player, black_player = agent2, agent1
game_recotd = simulate_game(black_player, white_player)
if game_record.winner == color1: #胜利者每一步落子得到的回报是1,输家每一步落子回报是-1
collector1.complete_episode(reward = 1)
collector2.complete_episode(reward = -1)
else:
collector2.complete_episode(reward = 1)
collector1.complete_episode(reward = -1)
color1 = color1.other
f1 = open('AlphaGoEncoder', 'rb')
encoder1 = pickle.load(f1)
f2 = open('AlphaGoEncoder', 'rb')
alpha_network1 = load_model('alphago_networks.h5')
alpha_network2 = load_model('alphago_networks.h5')
agent1 = PolicyAgent(alpha_network1, encoder1)
agent2 = PolicyAgent(alpha_network2, encoder2)
num_games = 1000
experience = experience_simulation(num_games, agent1, agent2) #启动自我对弈
agent1.train(experience) #使用对弈产生的数据训练自己
在上面代码能够正常运行之前,我们还需要完善一下上一节给出的代码,对PolicyAgent添加如下代码:
class PolicyAgent():
def __init__(self, model, encoder):
self.model = model #该变量对应上面训练的网络
self.encoder = encoder #对应48层棋盘编码
self.collector = None
def select_move(self, game_state):#根据棋盘情况选择落子
board_tensor = self.encoder.encode(game_state)
X = np.array([board_tensor])
move_probs = self.model.predict(X)[0] #利用网络预测下一步落子,返回每一步落子概率
move_probs = clip_probs(move_probs) #过滤掉那些概率过高或过低的步骤
num_moves = self.encoder.board_width * self.encoder.board_height
candidates = np.arange(num_moves)
ranked_moves = np.random.choice(candidates, num_moves, replace = False, p = move_probs) #对所有落子步骤根据其概率进行抽样
for point_idx in ranked_moves:
point = self.encoder.decode_point_index(point_idx)
move = Move.play(point)
#判断当前落子是否合理
is_valid = game_state.is_valid_move(move)
is_an_eye = is_point_an_eye(game_state.board, point, game_state.next_player)
if is_valid and (not is_an_eye): #记录落子步骤
if self.collector is not None:
self.collector.record_decision(state = board_tensor,
action = point_idx)
return Move.play(point)
return Move.pass_turn()
def set_collector(self, collector):
self.collector = collector
def train(self, experience, lr = 0.0000001, clipnorm = 1.0, batch_size = 512):
#应用对弈产生的数据训练网络
opt = SGD(lr = lr, clipnorm = clipnorm)
self.model.compile(loss = 'categorical_crossentropy', optimizer = opt)
n = experience.states.shape[0]
num_moves = self.encoder.board_width * self.encoder.board_height
y = np.zeros((n, num_moves))
for i in range(n):
action = experience.actions[i]
reward = experience.rewards[i]
y[i][action] = reward
self.model.fit(experiences.states, y, batch_size = batch_size, epochs = 1)
在上面Agent实现找那个,我们增加了collector记录落子步骤的代码,同时增加了train函数,它接收对弈产生的落子数据,然后将这些数据用于训练网络,完成上面代码,整个增强式学习的系统就可以顺利运行起来。当然在没有GPU算力支持下,普通CPU是不可能在短时间内跑出结果的,我会把训练好的Agent对象序列化成数据文件附带到课程的附件里。
新书上架,请诸位朋友多多支持: WechatIMG1.jpeg
网友评论