AlphaGo实战一

一、MCTS算法

树结构:树结构定义了一个可行解的解空间,每一个叶子节点到根节点的路径都对应了一个解(solution)

蒙特卡洛方法:MSTC不需要事先给定打标样本,随机统计方法充当了驱动力的作用,通过随机统计实验获取观测结果

损失评估函数:提供一个可量化的确定性反馈,用于评估解的优劣 => MCTS是通过随机模拟寻找损失函数代表的背后“真实函数”

反向传播线性优化:每次获得一条路径的损失结果后,采用反向传播(Backup)对整条路径上的所有节点进行整体优化

启发式搜索策略:算法遵循损失最小化的原则在整个搜索空间上进行启发式搜索,直到找到一组最优解或者提前终止

 

代码实现:

# MCTS树节点,每个节点都记录了自己的Q值,先验概率P和 UCT值第二项,即调整后的访问次数u(用于exploration)

class TreeNode(object):
    # 节点初始化
    def __init__(self, parent, prior_p):
        self._parent = parent
        self._children = {}  # Action到TreeNode的映射map
        self._n_visits = 0   # 访问次数
        self._Q = 0         # 行动价值
        self._u = 0   # UCB值第二项,即调整后的访问次数(exploration)
        self._P = prior_p    # 先验概率

    # Expand,展开叶子节点(新的孩子节点)
    def expand(self, action_priors):
        for action, prob in action_priors:
            # 如果不是该节点的子节点,那么就expand 添加为子节点
            if action not in self._children:
                # 父亲节点为当前节点self,先验概率为prob
                self._children[action] = TreeNode(self, prob)

# Select步骤,在孩子节点中,选择具有最大行动价值UCT,通过get_value(c_puct)函数得到
def select(self, c_puct):
    # 每次选择最大UCB值的节点,返回(action, next_node)
    return max(self._children.items(),
           key=lambda act_node: act_node[1].get_value(c_puct))

# 从叶子评估中,更新节点Q值和访问次数
def update(self, leaf_value):
    # 节点访问次数+1
    self._n_visits += 1
    # 更新Q值,变化的Q对于所有访问次数进行平均
    self._Q += 1.0*(leaf_value - self._Q) / self._n_visits

# 递归的更新所有祖先,调用self.update
def update_recursive(self, leaf_value):
    # 如果不是根节点,就需要先调用父亲节点的更新
    if self._parent:
        self._parent.update_recursive(-leaf_value)
    self.update(leaf_value)

# 计算节点价值 UCT值 = Q值 + 调整后的访问次数(exploitation + exploration)
def get_value(self, c_puct):
    # 计算调整后的访问次数
    self._u = (c_puct * self._P * np.sqrt(self._parent._n_visits) / (1 + self._n_visits))
    return self._Q + self._u

# 判断是否为叶子节点
def is_leaf(self):
    return self._children == {}

# 判断是否为根节点
def is_root(self):
    return self._parent is None

# MCTS:Monte Carlo Tree Search 实现了蒙特卡洛树的搜索 
class MCTS(object):
    # policy_value_fn 考虑了棋盘状态,输出一组(action, probability)和分数[-1,1]之间(预计结束时的比分期望)
    # c_puct exploitation和exploration之间的折中系数
    def __init__(self, policy_value_fn, c_puct=5, n_playout=10000):
        self._root = TreeNode(None, 1.0) # 根节点
        self._policy = policy_value_fn   # 策略状态,考虑了棋盘状态,输出一组(action, probability)和分数[-1,1]之间
        self._c_puct = c_puct # exploitation和exploration之间的折中系数
        self._n_playout = n_playout

# 从根节点到叶节点运行每一个playout,获取叶节点的值(胜负平结果1,-1,0),并通过其父节点将其传播回来
# 状态是就地修改的,所以需要保存副本
def _playout(self, state):
    # 设置当前节点
    node = self._root
    # 必须要走到叶子节点
    while(1):
        if node.is_leaf():
            break
        # 基于贪心算法 选择下一步
        action, node = node.select(self._c_puct)
        state.do_move(action)

# 对于current player,根据state 得到一组(action, probability) 和分数v [-1,1]之间(比赛结束时的预期结果)
action_probs, leaf_value = self._policy(state)
# 检查游戏是否结束
end, winner = state.game_end()
if not end:
    node.expand(action_probs)
else:
    # 游戏结束,计算leaf_value
    if winner == -1:  # 平均
        leaf_value = 0.0
    else:
        leaf_value = (1.0 if winner == state.get_current_player() else -1.0)

# 将子节点的评估值反向传播更新父节点(所有)
node.update_recursive(-leaf_value)

def get_move_probs(self, state, temp=1e-3):
    # 运行_n_playout次 _playout
    for n in range(self._n_playout):
        # 在进行_playout之前需要保存当前状态的副本,因为状态是就地修改的
        state_copy = copy.deepcopy(state)
        self._playout(state_copy)

    # 基于节点的访问次数,计算move probabilities
    act_visits = [(act, node._n_visits) for act, node in self._root._children.items()]
    acts, visits = zip(*act_visits)
    # 基于节点的访问次数,通过softmax计算概率
    act_probs = softmax(1.0/temp * np.log(np.array(visits) + 1e-10))
    return acts, act_probs

# 在树中前进一步
def update_with_move(self, last_move):
    if last_move in self._root._children:
        self._root = self._root._children[last_move]
        self._root._parent = None
    else:
        self._root = TreeNode(None, 1.0)

顺序执行_n_playout次的playouts,返回可能的actions和相应的可能性

state为当前棋盘状态,temp 温度参数,控制了探索的程度 (0,1]范围

当MCTS搜索完成时,返回局面state下的落子概率π,与N^(1 /temp)成正比,其中N是从根状态每次移动的访问计数,temp是控制温度的参数

 

二、SolfMax

1、solfMax概念

机器学习中重要的计算工具,可以兼容logistics算法、可以独立作为机器学习的模型进行建模训练、还可以作为深度学习的激励函数

简单的说,就是计算一组数值中每个值的占比 假设一共有n个用数值表示的分类                ,n表示分类的个数,

softmax计算公式为: i表示k中的某个分类,gi表示该分类的值

假设有三个数值A=5,B=1,C=-1,那么他们的softmax占比为 计算结果为:P(A)=0.9817, P(B)=0.0180, P(C)=0.0003

2、SoftMax特性:

归一化:最后的合计为1,即P(A)+P(B)+P(C)=1

放大效果:单纯从数值来看,5和1的差距并不大,但是通过指数运算有明显的放大效果,5的占比能到98%以上

散列性质,每一个比率虽然最后都会进行归一,但是他们放大之前的数值是可以相互不干扰的

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值