基于tensorflow的最簡單的強化學習入門-part1.5: 基于上下文老虎機問題(Contextual Bandits)

封面

本文翻譯自 Simple Reinforcement Learning with Tensorflow Part 1.5: Contextual Bandits, 作者是 Arthur Juliani, 原文鏈接

介紹

在這個系列的前一部分文章中,我們介紹了增強學習的一些概念,并且演示了如何通過建立一個agent來解決多臂老虎機問題(Multi-arm bandits)。多臂老虎機可以當作一種特殊的增強學習問題,沒有狀態(state),只需要采取行動(action)并獲取最大的獎勵(reward)即可。由于沒有給定的狀態,那么任意時刻的最佳動作始終都是最佳的動作。而在第二部分的文章展示了完整的強化學習問題,其中包括環境狀態延遲獎勵

事實上,在無狀態問題和完整的強化學習問題上還存在著一些不同,我想提供一個這樣的例子來展示如何解決它。我希望對強化學習不太了解的朋友們可以通過在逐步的學習中有所收獲。這這篇文章中,作為第一篇文章和第二篇文章的過渡,我將展示如何解決有狀態的問題,但是我們不會考慮延遲獎勵,所有這些都將出現在第二部分的文章中。這種簡化的強化學習問題稱為上下文老虎機問題。

多臂老虎機問題(只有行動和回報),上下文老虎機問題(有狀態,行動和回報):完全RL問題(獎勵有可能在時間上延遲)

上下文老虎機問題

在第一部分討論多臂老虎機問題中,我們可以認為只有一個老虎機。agent可能的動作就是拉動老虎機中一個機臂,通過這種方式以不同的頻率得到+1或者-1的獎勵。在這個問題中,agent會永遠選擇同一個機械臂,該臂帶來的回報最多。因此,我們設計的agent完全忽略環境狀態,環境狀態不會影響我們采取的動作和回報,所以對于所有的動作來說只有一種給定的狀態

上下文老虎機問題中帶來了狀態的概念。狀態包含agent能夠利用的一系列環境的描述和信息。在這個例子中,有多個老虎機而不是一個老虎機,狀態可以看做我們正在操作哪個老虎機。我們的目標不僅僅是學習單一老虎機的操作方法,而是很多老虎機。在每一個老虎機中,轉動每一個機臂帶來的回報都會不一樣,我們的agent需要學習到在不同狀態下(老虎機)執行動作所帶來的回報。為了實現這個功能,我們會基于tensorflow構造一個簡單的神經網絡,輸入狀態并且得到動作的權重。通過策略梯度更新方法,我們的agent就可以學習到不同狀態下如何獲得最大的回報。下面是實現上述過程的python的代碼:

定義上下文老虎機

這里我們定義上下文老虎機,在這個例子中,我們使用三個多臂老虎機,不同的老虎機有不同的概率分布,因此需要執行不同的動作獲取最佳結果。getbandit函數隨機生成一個數字,數字越低就越可能產生正的回報。我們希望agent可以一直選擇能夠產生最大收益的老虎機臂

import tensorflow as tf
import tensorflow.contrib.slim as slim
import numpy as np


class contextual_bandit():
    def __init__(self):
        self.state = 0
        #List out our bandits. Currently arms 4, 2, and 1 (respectively) are the most optimal.
        self.bandits = np.array([[0.2,0,-0.0,-5],[0.1,-5,1,0.25],[-5,5,5,5]])
        self.num_bandits = self.bandits.shape[0]
        self.num_actions = self.bandits.shape[1]
        
    def getBandit(self):
        self.state = np.random.randint(0,len(self.bandits)) #Returns a random state for each episode.
        return self.state
        
    def pullArm(self,action):
        #Get a random number.
        bandit = self.bandits[self.state,action]
        result = np.random.randn(1)
        if result > bandit:
            #return a positive reward.
            return 1
        else:
            #return a negative reward.
            return -1

策略梯度的agent

這段代碼建立了一個簡單的基于神經網絡的agent,其中輸入為當前的狀態,輸出為執行的動作。這使得agent可以根據當前的狀態執行不同的動作。agent使用一組權重,每一個作為在給定狀態下執行特定動作的回報的估計。

class agent():
    def __init__(self, lr, s_size,a_size):
        #These lines established the feed-forward part of the network. The agent takes a state and produces an action.
        self.state_in= tf.placeholder(shape=[1],dtype=tf.int32)
        state_in_OH = slim.one_hot_encoding(self.state_in,s_size)
        output = slim.fully_connected(state_in_OH,a_size,\
            biases_initializer=None,activation_fn=tf.nn.sigmoid,weights_initializer=tf.ones_initializer())
        self.output = tf.reshape(output,[-1])
        self.chosen_action = tf.argmax(self.output,0)

        #The next six lines establish the training proceedure. We feed the reward and chosen action into the network
        #to compute the loss, and use it to update the network.
        self.reward_holder = tf.placeholder(shape=[1],dtype=tf.float32)
        self.action_holder = tf.placeholder(shape=[1],dtype=tf.int32)
        self.responsible_weight = tf.slice(self.output,self.action_holder,[1])
        self.loss = -(tf.log(self.responsible_weight)*self.reward_holder)
        optimizer = tf.train.GradientDescentOptimizer(learning_rate=lr)
        self.update = optimizer.minimize(self.loss)
    
tf.reset_default_graph() #Clear the Tensorflow graph.

訓練

cBandit = contextual_bandit() #Load the bandits.
myAgent = agent(lr=0.001,s_size=cBandit.num_bandits,a_size=cBandit.num_actions) #Load the agent.
weights = tf.trainable_variables()[0] #The weights we will evaluate to look into the network.

total_episodes = 10000 #Set total number of episodes to train agent on.
total_reward = np.zeros([cBandit.num_bandits,cBandit.num_actions]) #Set scoreboard for bandits to 0.
e = 0.1 #Set the chance of taking a random action.

init = tf.initialize_all_variables()

# Launch the tensorflow graph
with tf.Session() as sess:
    sess.run(init)
    i = 0
    while i < total_episodes:
        s = cBandit.getBandit() #Get a state from the environment.
        
        #Choose either a random action or one from our network.
        if np.random.rand(1) < e:
            action = np.random.randint(cBandit.num_actions)
        else:
            action = sess.run(myAgent.chosen_action,feed_dict={myAgent.state_in:[s]})
        
        reward = cBandit.pullArm(action) #Get our reward for taking an action given a bandit.
        
        #Update the network.
        feed_dict={myAgent.reward_holder:[reward],myAgent.action_holder:[action],myAgent.state_in:[s]}
        _,ww = sess.run([myAgent.update,weights], feed_dict=feed_dict)
        
        #Update our running tally of scores.
        total_reward[s,action] += reward
        if i % 500 == 0:
            print "Mean reward for each of the " + str(cBandit.num_bandits) + " bandits: " + str(np.mean(total_reward,axis=1))
        i+=1
for a in range(cBandit.num_bandits):
    print "The agent thinks action " + str(np.argmax(ww[a])+1) + " for bandit " + str(a+1) + " is the most promising...."
    if np.argmax(ww[a]) == np.argmin(cBandit.bandits[a]):
        print "...and it was right!"
    else:
        print "...and it was wrong!"

希望本教程能夠有助于你直觀的理解強化學習如何解決不同的問題。如果你已經掌握了這個方法,并且已經準備好探索完整的深度強化問題,你可以直接看第二部分或者以后的文章。

如果你覺得這篇文章對你有幫助,可以關注原作者。

如果你想要繼續看到我的文章,也可以專注專欄。第一次翻譯,希望能和大家一起交流。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容