强化学习实例:多臂赌博机

本文围绕多臂赌博机问题展开,探讨如何在拉动N次杆的情况下使获得的金币最多。介绍了强化学习中的三种随机策略,包括ϵ−greedy策略、玻尔兹曼分布和UCB策略,并给出了Python代码实现。通过运行代码,发现UCB策略效果最佳。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、游戏背景

多臂赌博机是一种游戏机,在本文中是一种具有三个拉杆的游戏机,每拉动一个杆,就会有一些金币从机器里出来,每只杆拉动出现的金币都是不一样的,同一只杆拉动多次出现的金币数量也是不全相同的,因此考虑拉动N次杆,怎么能让出现的金币的个数最多?

二、采取策略

一个很显然的思路是,先试探性的每个杆都拉动几次,看看哪个杆出现的金币比较多,那么之后就拉动那一只杆,这种思路是一种解决方法,但是如果因为巧合导致选择的那一只杆不是出金币最多的,那么就会导致很大的损失,所以考虑有没有方法可以在选择当前出金币最多的杆的同时,依旧有一定概率去拉动其他杆?这就是强化学习中的随机策略,主要说三种策略:

1、ϵ−greedy策略

                \pi(a|s) \leftarrow \begin{cases} 1-\epsilon+\frac{\epsilon}{|A(s)|} if a=argmax_a Q(s,a)\\ \frac{\epsilon}{|A(s)|} if a \neq argmax_a Q(s,a)\\ \end{cases}

就是每次选择当前金币最多的杆拉,但是还有ϵ(一个很小的数)去随机拉动任意杆,和上边的思路是吻合的。

2、玻尔兹曼分布

              p(a_{i})=\frac{exp(Q(a_{i})/\tau)}{\sum_j exp(Q(a_{j})/\tau)}

相比贪婪策略,对每一项做出了软处理

3、UCB策略

一个较为复杂的公式,使用置信区间来表示搜索,一般是三种中效果最好的

三、代码实现

首先建立一个游戏的类,先定义一些基本量:

def __init__(self, *args, **kwargs):
    #动作
    self.actions = [1, 2, 3]
    #平均回报
    self.q = np.array([0.0, 0.0, 0.0])
    #每个杆被选中的次数
    self.action_counts = np.array([0, 0, 0])
    #玩游戏的次数
    self.counts = 0
    #当前回报总和
    self.current_cumulative_rewards = 0.0
    #次数记录
    self.counts_history = []
    #奖励历史
    self.cumulative_rewards_history = []
    #当前动作
    self.a = 1
    #当前回报
    self.reward = 0

接下来是动作返回的金币个数:

# 模拟多臂赌博机
def step(self, a):
    r = 0
    #三个动作会反馈不同分布的金币个数
    if a == 1:
        r = np.random.normal(1, 1)
    if a == 2:
        r = np.random.normal(2, 1)
    if a == 3:
        r = np.random.normal(1.5, 1)
    return r

接下来根据不同的策略选择摇杆:

def choose_action(self, policy, **kwargs):
    action = 0
    if policy == 'e_greedy':
        if np.random.random() < kwargs['epsilon']:
            action = np.random.randint(1, 4)
        else:
            action = np.argmax(self.q) + 1
    if policy == 'ucb':
        c_ratio = kwargs['c_ratio']
        if 0 in self.action_counts:
            action = np.where(self.action_counts == 0)[0][0] + 1
        else:
            value = self.q + c_ratio * np.sqrt(np.log(self.counts) / self.action_counts)
            action = np.argmax(value) + 1
    if policy == 'boltzmann':
        tau = kwargs['temperature']
        p = np.exp(self.q / tau) / (np.sum(np.exp(self.q / tau)))
        action = np.random.choice([1, 2, 3], p=p.ravel())
    return action

下边是交互过程,后边三个是不同策略的超参数,就像贪婪的ϵ和玻尔兹曼的\tau

# 实际的交互过程
def train(self, play_total, policy, **kwargs):
    reward_1 = []
    reward_2 = []
    reward_3 = []
    for i in range(play_total):
        action = 0
        if policy == 'e_greedy':
            action = self.choose_action(policy, epsilon=kwargs['epsilon'])
        if policy == 'ucb':
            action = self.choose_action(policy, c_ratio=kwargs['c_ratio'])
        if policy == 'boltzmann':
            action = self.choose_action(policy, temperature=kwargs['temperature'])
        self.a = action
        self.reward = self.step(self.a)
        self.counts += 1
        self.q[self.a - 1] = (self.q[self.a - 1] * self.action_counts[self.a - 1] + self.reward) / (
                    self.action_counts[self.a - 1] + 1)
        self.action_counts[self.a - 1] += 1
        reward_1.append(self.q[0])
        reward_2.append(self.q[1])
        reward_3.append(self.q[2])
        self.current_cumulative_rewards += self.reward
        self.counts_history.append(i)
        self.cumulative_rewards_history.append(self.current_cumulative_rewards)

主体部分已经完成,后边还有画图和重置的函数,这里就不再列举了,运行代码看看训练结果:

if __name__ == '__main__':
    np.random.seed(0)
    k_gamble = KB_Game()
    total = 2000
    k_gamble.train(play_total=total, policy='e_greedy', epsilon=0.05)
    k_gamble.plot(colors='r', policy='e_greedy', linestyle='-')
    k_gamble.reset()
    k_gamble.train(play_total=total, policy='boltzmann', temperature=1)
    k_gamble.plot(colors='g', policy='boltzmann', linestyle='--')
    k_gamble.reset()
    k_gamble.train(play_total=total, policy='ucb', c_ratio=0.5)
    k_gamble.plot(colors='b', policy='ucb', linestyle='-.')
    plt.show()

从这张图中可以看出UCB的策略得到了最好的结果

源代码可以参考链接:https://github.com/hustCYQ/RL/blob/main/KBgame.py

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

负壹

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值