【深入浅出强化学习-编程实战】1 多臂赌博机

多臂赌博机:
假设玩家共有N次摇动摇臂的机会,每次怎么选择可以使得最后得到的金币最多?

  • ϵ \epsilon ϵ-greedy
  • 玻尔兹曼策略
  • UCB策略
# 多臂赌博机
import numpy as np
import matplotlib.pyplot as plt

class KB_Game:
    def __init__(self,*args,**kwargs):
        # 属性
        # q 每个臂的平均回报,假设臂的数目是3,初始值都为0.0
        self.q = np.array([0.0,0.0,0.0])
        # action_counts 摇动每个臂的次数,初始值为0
        self.action_counts = np.array([0,0,0])
        # current_cumulative_rewards 当前累积回报总和,初始值为0.0
        self.current_cumulate_rewards=0.0
        # action 动作空间
        self.actions = [1,2,3]
        # counts 玩家玩游戏的次数
        self.counts = 0
        # counts_history 玩家玩游戏的次数记录
        self.counts_history = []
        # cumulative_rewards_history 累积回报的记录
        self.cumulative_rewards_history = []
        # a 玩家当前动作,初始值可以设为任意一个动作
        self.a = 1
        # reward 当前回报 初始为0
        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

    # 三种选择动作的策略方法
    # 输入为策略policy, 有3个policy: e_greedy,ucb,boltzmann
    # 参数字典**kwargs用于传递相应策略所对的超参数,e_greedy——epsilon,ucb——c_ratio,boltzmann——temerature
    def choose_action(self,policy,**kwargs):
        action = 0

        if policy == 'e_greedy':
            if np.random.random()<kwargs['epsilon']:
                action = np.random.randint(1,4)#1,2,3任意选
            else:
                action = np.argmax(self.q)+1

        # UCB中,N(a)在分母,因此第一次是依次摇动每个臂,程序判断每个动作的次数,如果有为0的则选择该动作
        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())# 用p的规则在[1,2,3]中抽样

        return action

    # 交互学习训练
    # 输入为play_total 要训练的总次数;policy 训练的策略;**kwargs 超参数字典
    # 智能体通过要学习的策略选择动作,再将动作传给step(),从多臂赌博机中获得回报r,智能体根据立即回报更新每个动作的平均回报q,计算当前的累积回报并保存
    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
            print(self.a)
            # 与环境交互一次
            self.r = self.step(self.a)
            self.counts += 1
            # 更新值函数
            self.q[self.a-1] = (self.q[self.a-1]*self.action_counts[self.a-1]+self.r)/(self.action_counts[self.a-1] +1)
            self.action_counts += 1
            reward_1.append([self.q[0]])
            reward_2.append([self.q[1]])
            reward_3.append([self.q[2]])
            self.current_cumulate_rewards += self.r
            self.cumulative_rewards_history.append(self.current_cumulate_rewards)
            self.counts_history.append(i)

    # 每次训练新policy时,需要将成员变量进行重置
    def reset(self):
        self.q = np.array([0.0,0.0,0.0])
        self.action_counts = np.array([0,0,0])
        self.current_cumulate_rewards = 0.0
        self.counts = 0
        self.counts_history = []
        self.cumulative_rewards_history = []
        self.a = 1
        self.reward = 0

    # 画图 更直观比较不同策略的性能
    # 参数为colors 曲线的颜色,policy
    def plot(self,colors,policy,style):
        plt.figure(1)
        plt.plot(self.counts_history,self.cumulative_rewards_history,colors,label=policy)
        plt.legend()# 加上图例
        plt.xlabel('n',fontsize=18)
        plt.ylabel('total rewards',fontsize=18)

# KB_Game类完成了
# 写主程序
if __name__ == '__main__':
    # step1:设置随机种子,以免我们每次结果都一样
    np.random.seed(0)
    # step2:将类KB_Game进行实例化
    k_gamble = KB_Game()
    # step3: 设置总的训练次数total,设置每个策略的超参数,调用类的训练方法进行学习
    total = 200
    k_gamble.train(play_total=total,policy='e_greedy',epsilon=0.05)
    # step4: 学习完后调用画图方法
    k_gamble.plot(colors='b',policy='e_greedy',style='--')
    # step5: 进行初始化,训练另一个策略
    k_gamble.reset()
    k_gamble.train(play_total=total, policy='ucb', c_ratio=0.5)
    k_gamble.plot(colors='r', policy='ucb', style='-.')
    k_gamble.reset()
    k_gamble.train(play_total=total, policy='boltzmann', temperature=1)
    k_gamble.plot(colors='g', policy='boltzmann', style='-')
    k_gamble.reset()
    # step6: 画图,显示3种策略的学习和训练过程
    plt.show()

结果
在这里插入图片描述
很明显,UCB比其他两个策略要好。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值