天天看點

【深入淺出強化學習-程式設計實戰】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()
           

結果

【深入淺出強化學習-程式設計實戰】1 多臂賭博機

很明顯,UCB比其他兩個政策要好。