强化学习中的multiarmed-Bandit以及经典解法epsilon-greedy算法,附加python实现

最近在看Management Science上的文章《A Dynamic Clustering Approach to Data-Driven Assortment Personalization》,其中提到了一个Multiarmed-Bandit模型,想要深入学习一下,但是查遍各种网站,都没有中文的关于这个问题的介绍,因此去油管上学习,然后翻译成中文在这里跟大家分享。

Exploration and esploitation tradeoff

在强化学习中有一个经典问题,即Exploration and esploitation tradeoff,在该问题中有一个两难境地:到底我们应该花精力去探索从而对收益有更精确的估计,还是应该按照目前拥有的信息,选择最大收益期望的行动?
由此引申出Multiarmed-Bandit模型

Multiarmed-Bandit Model

假设现在有n台老虎机,每台老虎机的收益不同,但我们事先并不知道每台老虎机的期望收益。
我们在这里假设:每台老虎机的收益服从方差为1的正态分布,均值事先并不知道。我们需要探索每台老虎机的收益分布,并最终让行动选择拥有最有的期望收益的老虎机。

传统的解决方案 A/B test

A/B test的思路是,给每台老虎机分配数量相同的测试数目,然后根据所有老虎机的测试结果,选择表现最优的老虎机进行剩下的所有操作。
这种方法的最大劣势就是将探索与开发割裂开来。在探索过程中只考虑探索,只收集信息,而在开发的阶段就不再考虑探索,也就失去了学习的机会,有可能陷入了局部最优,没有找到最优的老虎机。

epsilon-greedy 算法

epsilon-greedy算法也是一种贪婪算法,不过在每次选择的过程中,会以一个较小的改了选择不是最优行动的其他行动,从而能够不断进行探索。由于epsilon较少,并且最终算法会找到最优的行动,因此最终选择最优的行动的概率会趋近于1-epsilon。
下面展示python代码:

import numpy as np
import matplotlib.pyplot as plt


class EpsilonGreedy:
    def __init__(self):
        self.epsilon = 0.1  # 设定epsilon值
        self.num_arm = 10  # 设置arm的数量
        self.arms = np.random.uniform(0, 1, self.num_arm)  # 设置每一个arm的均值,为0-1之间的随机数
        self.best = np.argmax(self.arms)  # 找到最优arm的index
        self.T = 50000  # 设置进行行动的次数
        self.hit = np.zeros(self.T)  # 用来记录每次行动是否找到最优arm
        self.reward = np.zeros(self.num_arm)  # 用来记录每次行动后各个arm的平均收益
        self.num = np.zeros(self.num_arm)  # 用来记录每次行动后各个arm被拉动的总次数

    def get_reward(self, i):  # i为arm的index
        return self.arms[i] + np.random.normal(0, 1)  # 生成的收益为arm的均值加上一个波动

    def update(self, i):
        self.num[i] += 1
        self.reward[i] = (self.reward[i]*(self.num[i]-1)+self.get_reward(i))/self.num[i]

    def calculate(self):
        for i in range(self.T):
            if np.random.random() > self.epsilon:
                index = np.argmax(self.reward)
            else:
                a = np.argmax(self.reward)
                index = a
                while index == a:
                    index = np.random.randint(0, self.num_arm)
            if index == self.best:
                self.hit[i] = 1  # 如果拿到的arm是最优的arm,则将其记为1
            self.update(index)

    def plot(self):  # 画图查看收敛性
        x = np.array(range(self.T))
        y1 = np.zeros(self.T)
        t = 0
        for i in range(self.T):
            t += self.hit[i]
            y1[i] = t/(i+1)
        y2 = np.ones(self.T)*(1-self.epsilon)
        plt.plot(x, y1)
        plt.plot(x, y2)
        plt.show()


E = EpsilonGreedy()
E.calculate()
E.plot()

最终的结果如下图所示:
在这里插入图片描述
随着行动的不断进行,累计准确率(选到最优arm的频率)在不断上升,并且逼近了我们所设置的上线 1 ϵ 1-\epsilon ,证明了 ϵ \epsilon -greedy算法的有效性!

发布了15 篇原创文章 · 获赞 9 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/qq_39320588/article/details/104315111