增强式学习核心算法:基于策略的梯度下降法

作者: 望月从良 | 来源:发表于2019-06-06 18:18 被阅读58次

    上一节我们介绍了什么叫增强式学习,它的模型值得我们印刻在脑海里:


    屏幕快照 2019-05-17 下午5.36.15.png

    我们要打造一个Agent,也就是智能机器人,它运作在一个给定环境中。它每次与环境互动时都有给定种选择,同时它可以获得当前环境的状态,Agent如果在有限种选择中选择了“正确”的选择,那么环境就会给它一个正回馈,如果做出了错误选择 ,环境就会给它负反馈。

    问题在于Agent如何根据当前环境状况让自己做出的选择以最大概率获得正回馈呢?这就是增强式学习的核心所在,我们必须给Agent一套原则或算法,让它懂得如何根据当前环境的变化做选择,而且这套算法要能够不断进化,随着算法运行得越多,算法能根据环境的回馈不断调整自己,然后算法能抽取出从当前环境状况找到最佳选择的规律。

    我们注意到增强式学习与以往神经网络不同之处。以前的神经网络要想提升准确率,一个前提就是不断增加输入数据量。而增强式学习不同,它不需要输入更多数据,它只要增加与环境互动的次数,从互动结果中直接学习,不需要额外数据是增强式学习强大之处。

    本节我们研究一种叫基于策略的学习法。假设在一个模拟环境中,Agent有5种选择,如果它没有学习能力,那么无论环境如何变化,它都只会在5种选择中随意选择一种。假设一次episode需要agent作出100次选择,那么我们预计每种选择大概有20次。当然20只是预测值,在具体一次episode中,某种选择肯定不是恰好20次。我们用下面代码模拟一下类似情况:

    import  numpy as np
    counts = {1: 0, 2: 0, 3: 0, 4: 0, 5: 0}
    for i in range(100):
        choice = np.random.choice([1, 2, 3, 4, 5])
        counts[choice] += 1
    print(counts)
    

    运行代码会发现,每一种选择都不可能正好是20次,当如果把上面代码运行多次,那么每种选择的次数评价起来会是20次左右。接下来我们进行一种简单的环境模拟,我们模拟两个agent从1到5中选择,每人选择100次然后加总,最后结果大的获胜:

    def  simulate_game(policy):
        player_1_choices = {1: 0, 2: 0, 3: 0, 4: 0, 5: 0}
        player_1_total = 0
        player_2_choices = {1: 0, 2: 0, 3: 0, 4: 0, 5: 0}
        player_2_total = 0
        for i in range(100):
            player_1_choice = np.random.choice([1,2,3,4,5], p = policy)
            player_1_choices[player_1_choice] += 1
            player_1_total += player_1_choice
            player_2_choice = np.random.choice([1,2,3,4,5], p = policy)
            player_2_choices[player_2_choice] += 1
            player_2_total += player_2_choice
        if player_1_total > player_2_total:
            winner_choices = player_1_choices
            loser_choices = player_2_choices
        else:
            winner_choices = player_2_choices
            loser_choices = player_1_choices
        return (winner_choices, loser_choices)
    
    policy = [0.2, 0.2, 0.2, 0.2, 0.2]
    print(simulate_game(policy))
    

    多运行几次上面代码就会看到,winner就是能多次挑选到大数值的player,例如我运行后结果如下:
    ({1: 21, 2: 14, 3: 19, 4: 26, 5: 20}, {1: 20, 2: 25, 3: 21, 4: 18, 5: 16})
    不难理解在这样的环境里,选1是坏选择,选5才是好选择。如果代码中的Player拥有学习能力的话,它就能从反馈中发现每种选择的好坏,例如它会发现自己选择1多的时候负反馈也多,选5多的时候正反馈也多,于是它就会主动增加选择5的几率。

    代码中的player可以基于如下政策调整比率。首先随机选择,然后根据结果调整。如果一次模拟下来发现自己的选择得到了胜利,那么它下次就就增加本次选择中选取次数最多的那个数值,如果失败了,它下次就减少选取次数最多的那个数值,如此反复足够多后,player就会不自觉的多选择5少选择1,这就是基于政策的学习算法核心所在。

    上面展示的学习算法还不足以应用到围棋这么复杂的情景。首先上面模拟中player并没有根据环境的当前状态去做选择,同时如何对“环境”进行分析是一个非常棘手的问题。在围棋中所谓“环境”就是棋盘上棋子的分布,如何把棋盘布局与落子方式关联起来就需要使用神经网络进行计算。

    我们已经知道,在神经网络中,我们通过修改连接链路的权重来改进网络的输出结果,链路的修改方法就是梯度下降法。以前我们总是修改权重,使得网络的输出与给定结果尽可能的接近,现在不一样,我们要在给定策略条件下,通过分析当前棋盘情况去修改链路权重,这种做法就叫基于政策的梯度下降法。

    接下来我们将通过代码的方式,逐步实现整个AlphaGo系统,在模块实现时我们会突出相应的学习算法,很多抽象或难理解的概念无法用语言来表述清楚,但是落实到代码上时反而能变得具体和生动,从而更好理解,因此对计算机技术而言,实践永远是最好的学习方法!

    首先,我们定义AlphaGo网络的基本结构:

    from keras.models import Sequential
    from keras.layers.core import Dense, Flatten
    from keras.layers.convolutional import Conv2D
    
    def  alphago_model(input_shape, is_policy_net = False,
                      num_filters = 192, first_kernel_size = 5, other_kernel_size = 3):
        model = Sequential()
        #第1到12层都是是卷积层,第一层将棋盘分解成5*5小块进行解析,其余层将棋盘分解成3*3小块解析
        model.add(Conv2D(num_filters, first_kernel_size, input_shape = input_shape, padding = 'same',
                        data_format = 'channels_first', activation = 'relu'))
        for i in range(2, 12):
            model.add(Conv2D(num_filters, other_kernel_size, padding = 'same',
                            data_format = 'channels_first', activation = 'relu'))
        if is_policy_net:
            #进入这里表明构建的网络将执行基于策略的梯度下降法,具体算法内容后面会在实现时具体分析
            model.add(Conv2D(filters = 1, kernel_size = 1, padding = 'same',
                            data_format = 'channels_first', activation = 'softmax'))
            model.add(Flatten())
            return model
        else:
            #增强式学习处理基于策略的梯度下降法外还有基于数值的下降法,后面实现时我们再深入分析
            model.add(Conv2D(num_filters, other_kernel_size, padding = 'same',
                            data_format = 'channels_first', activation = 'relu'))
            model.add(Conv2D(filters = 1, kernel_size = 1, padding = 'same',
                            data_format = 'channels_first', activation = 'relu'))
            model.add(Flatten())
            model.add(Dense(256, activation = 'relu'))
            model.add(Dense(1, activation = 'tanh'))
            return model
    
    model = alphago_model(input_shape = (19, 19, 19) )
    model.summary()
    

    上面代码运行后输出如下:

    Layer (type)                 Output Shape              Param #   
    =================================================================
    conv2d_59 (Conv2D)           (None, 192, 19, 19)       91392     
    _________________________________________________________________
    conv2d_60 (Conv2D)           (None, 192, 19, 19)       331968    
    _________________________________________________________________
    conv2d_61 (Conv2D)           (None, 192, 19, 19)       331968    
    _________________________________________________________________
    conv2d_62 (Conv2D)           (None, 192, 19, 19)       331968    
    _________________________________________________________________
    conv2d_63 (Conv2D)           (None, 192, 19, 19)       331968    
    _________________________________________________________________
    conv2d_64 (Conv2D)           (None, 192, 19, 19)       331968    
    _________________________________________________________________
    conv2d_65 (Conv2D)           (None, 192, 19, 19)       331968    
    _________________________________________________________________
    conv2d_66 (Conv2D)           (None, 192, 19, 19)       331968    
    _________________________________________________________________
    conv2d_67 (Conv2D)           (None, 192, 19, 19)       331968    
    _________________________________________________________________
    conv2d_68 (Conv2D)           (None, 192, 19, 19)       331968    
    _________________________________________________________________
    conv2d_69 (Conv2D)           (None, 192, 19, 19)       331968    
    _________________________________________________________________
    conv2d_70 (Conv2D)           (None, 192, 19, 19)       331968    
    _________________________________________________________________
    conv2d_71 (Conv2D)           (None, 1, 19, 19)         193       
    _________________________________________________________________
    flatten_5 (Flatten)          (None, 361)               0         
    _________________________________________________________________
    dense_7 (Dense)              (None, 256)               92672     
    _________________________________________________________________
    dense_8 (Dense)              (None, 1)                 257       
    =================================================================
    Total params: 3,836,162
    Trainable params: 3,836,162
    Non-trainable params: 0
    

    我们看到整个网络有三百多万参数,训练这个网络将需要非常庞大的算力支持才行。接下来我们看看适用于AlphaGo得棋盘编码,它跟我们前面提到的编码很相像,主不过它更复杂一些,它将拥有48层,每一层记录当前棋盘的特定信息。这种编码之所以有那么多层,是因为我们希望能从棋盘上判断某种特定策略是否可行,例如一种策略叫”梯形围捕“,例如下面这种情况:

    屏幕快照 2019-06-06 下午5.21.22.png

    最左边的棋盘中白子只剩下右边一个自由点,如果被黑棋堵上就会被吃掉。当如果它直接堵住右边只有点的话,黑棋可以继续围堵,使得白棋始终只有一个自由点,如此下去最后白棋走到边缘处无路可走,最后被黑棋全部吃掉,这种情况就是”梯级围堵“。但如果白棋已经有一个棋子在梯形路径右上角,那么梯形围捕就会失败,如下图:

    屏幕快照 2019-06-06 下午5.25.36.png

    所以棋盘编码就需要记录当前是否具备梯形围捕的条件,如果有的话,AlphaGo就可以对对方进行梯形围捕。在前面编码中,我们使用三层来记录拥有1,2,或3个以上自由点的棋子,在48层编码中,我们使用8层来记录拥有1到8个以上自由点的棋子,我们总结一下48层编码中的不同层作用:2层分别记录不同颜色棋子在棋盘中的分布:

    作用 层数 说明
    记录棋子颜色 3 其中2层分布记录不同颜色棋子分布,1层记录空白位置
    填充1 1 这一层全部用1来填满
    填充0 1 这一层全部用0填满
    有效性 1 这一层记录所有能有效落子的位置
    落子记录 8 这8层记录若干步前的棋盘状况
    自由点 8 记录这次落子衔接起来的棋子中对应的自由点
    经过当前步后的自由点数 8 当前落子后所有棋子自由点的变化
    对方被吃掉的棋子数 8 当前落子后对方有多少棋子被吃掉
    叫吃 8 落子后,本方有多少棋子可能会被对方下一步吃掉
    梯形围捕 1 当前落子或被梯形围捕吗
    梯形逃逸 1 当前落子能否破坏梯形围捕
    当前落子方棋子颜色 1 如果当前落子方是白棋用1填充,如果是黑棋 用0填充

    为了方便起见,我们不用亲自实现上面编码,到时候我们之间加载相应类,这样我们可以把精力集中到算法的设计上。下一节我们将深入研究具体的学习算法实现。

    请关注公众号,让我们共同学习进步


    qrcode_for_gh_00f6e6bb0b6c_258.jpg 新书上架,请诸位朋友多多支持: WechatIMG1.jpeg

    相关文章

      网友评论

        本文标题:增强式学习核心算法:基于策略的梯度下降法

        本文链接:https://www.haomeiwen.com/subject/redlxctx.html