基于tensorflow的最簡單的強化學習入門-part1:多臂老虎機問題

題圖

本文翻譯自 Simple Reinforcement Learning in Tensorflow: Part 1 - Two-armed Bandit, 作者是 Arthur Juliani, 原文鏈接

介紹

強化學習不僅提供了指導人工智能agent如何行動的能力,還允許它通過和環境的相互作用自主學習。同時結合神經網絡強大的表達能力和目標驅動學習方式,深度強化學習成為了強大的人工智能基本方法。深度強化學習已經完成了一些驚人的壯舉,例如在Atari游戲中戰勝了人類,在在圍棋項目上擊敗了世界冠軍,最近又在德州撲克中大放異彩。

構建這些人工智能程序和構建可監督學習程序有所不同。可監督學習只是簡單的學習模型對某個輸入的反饋,而強化學習算法使agent能夠通過觀察(observation)、獎勵(reward)和動作(action)來學習對于輸入的正確的反饋。在特定情況下,強化學習和有監督學習是不同的,agent并不知道何謂正確的行動,這使事情變得很棘手。在這篇文章和后續的文章中,我將介紹如何構造和訓練強化學習agent。為了使大家概念清晰,處理的任務和agent的設計都會從簡單到復雜。

雙臂老虎機問題(Two-Armed bandit)

最簡單的強化學習問題就是多臂老虎機問題了。多臂老虎機問題本質上可以看做一個擁有n個槽的老虎機,轉動每個槽都有固定回報概率。我們的目標就是找到回報概率最高的的槽并且不斷的選擇它來獲取最高的回報。為了簡化這個問題,假設這個機器只有兩個槽,我們要做的就是從這兩個槽中找到回報更高的那一個。事實上,這個問題非常簡單,但是可以看作真正RL問題的一個原型。一般的RL問題需要符合如下條件

  • 不同的動作導致不同的回報。舉個例子,在迷宮中尋找寶藏,如果往左就能獲得寶藏,往右就什么都得不到。
  • 回報在時間上有延遲。沿用上述的例子,在迷宮中往左時,我們并不是立即知道我們走的就是正確的方向。
  • 某個動作下的回報跟當時的環境有關。繼續剛才的例子,往左邊是當前情況下的最佳選擇,在其他情況下就不一定了。

多臂老虎機是學習強化學習良好的開端,我們不需要去擔心#2和#3的問題。我們只需要關注哪個動作可以帶來怎樣的回報,并且確保我們能夠選擇理想的動作。用RL的術語來說,這就叫做Policy。我們將要用一種叫做策略梯度(policy gradients)的方法,該方法中我們的簡單的神經網絡通過和環境的的不斷交互同時結合BP算法就可以學習到如何執行該動作的策略(policy)。在強化學習中,還有另一種方法叫做價值函數(value functions),在這個方法中,agent并不是學習某種狀態下特定的動作,而是學習如何預測當前的狀態和動作的好壞(價值)。兩種方法都可以使得agent可以學習良好的策略,不過策略梯度方法更直接一些。

策略梯度算法

簡單來說,策略梯度網絡可以直接產生輸出。在我們這個簡單的例子中,我們不需要根據當前的狀態來調節輸出。因此,我們的網絡只包括一組的權重,每個對應著老虎拉動機臂可能的動作,輸出代表對應的動作的好壞。如果我們將這些權重初始化為1,那么agent可能會對每個分支的潛在回報過于樂觀。

為了更新網絡參數,我們將采用一種稱為e-greedy的策略(后續章節會詳細介紹這個方法)。應用這個策略意味著在大多數情況下,我們的agent會選擇帶來最大預期好處的動作,但是偶爾的以e的概率,它將隨機選擇。這樣agent就可以嘗試每一個可能的狀態,一旦我們的agent采取行動,它就會收到1或者-1的獎勵。有了這個獎勵,我們可以使用損失函數更新我們的網絡參數:

譯者注:在Andrej Karpathy文中也有對這個方法的介紹。

Loss = log(\Pi) * A
  • A稱為優勢(advantage), 是所有強化學習方法中一個重要的概念。直觀的看,它對應于某個動作跟某些baseline相比的好壞。在未來的算法中,我們會開發更復雜的baseline和我們的回報對比,當在當前的問題中,我們假設baseline為0,而A可以簡單的認為是每個行動的回報。
  • \pi 稱為策略,在這個例子中它代表選擇這個動作的權重。

顯而易見,這樣的損失函數允許我們增加產生積極獎勵動作時的權重,并且減少產生負獎勵時的權重。通過這樣方式,agent或多或少的能夠在未來學習如何采取動作,獲得獎勵,并且更新我們的網絡。我們會很快收斂到(學習到)一個agent,該agent可以解決我們的多臂老虎機問題。如果不相信我說的,那你可以自己試試看。

基于tensorflow強化學習代碼:

Bandits

在這個例子中我們采用一個四個臂的老虎機。pullBandit函數隨機從正態分布函數采樣一個值,如果該值越小,那么就會更有可能產生一個正的回報。我想要我們的agent能夠學習到產生回報最高的那個老虎機臂。bandits是一個數組,bandit 4(index#3)被設置為產生最高回報。

import tensorflow as tf
import numpy as np

bandits = [0.2,0,-0.2,-5]
num_bandits = len(bandits)
def pullBandit(bandit):
    #Get a random number.
    result = np.random.randn(1)
    if result > bandit:
        #return a positive reward.
        return 1
    else:
        #return a negative reward.
        return -1

Agent

下述代碼實現了一個簡單的基于神經網絡的agent。該agent主要包括每一個bandit對應的權重,每一個權重就是選擇該bandit預期的回報。通過不斷的選擇老虎臂并且獲得回報,我們將采用策略梯度方法來更新權重,


tf.reset_default_graph()

#These two lines established the feed-forward part of the network. This does the actual choosing.
weights = tf.Variable(tf.ones([num_bandits]))
chosen_action = tf.argmax(weights,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.
reward_holder = tf.placeholder(shape=[1],dtype=tf.float32)
action_holder = tf.placeholder(shape=[1],dtype=tf.int32)
responsible_weight = tf.slice(weights,action_holder,[1])
loss = -(tf.log(responsible_weight)*reward_holder)
optimizer = tf.train.GradientDescentOptimizer(learning_rate=0.001)
update = optimizer.minimize(loss)

Training the Agent

通過不斷的選擇動作并且獲得回報,利用reward和action,我們能夠合適的更新神經網絡中的權重。最終該網絡會傾向于選擇帶來回報更多的bandit。


total_episodes = 1000 #Set total number of episodes to train agent on.
total_reward = np.zeros(num_bandits) #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:
        
        #Choose either a random action or one from our network.
        if np.random.rand(1) < e:
            action = np.random.randint(num_bandits)
        else:
            action = sess.run(chosen_action)
        
        reward = pullBandit(bandits[action]) #Get our reward from picking one of the bandits.
        
        #Update the network.
        _,resp,ww = sess.run([update,responsible_weight,weights], feed_dict={reward_holder:[reward],action_holder:[action]})
        
        #Update our running tally of scores.
        total_reward[action] += reward
        if i % 50 == 0:
            print "Running reward for the " + str(num_bandits) + " bandits: " + str(total_reward)
        i+=1
print "The agent thinks bandit " + str(np.argmax(ww)+1) + " is the most promising...."
if np.argmax(ww) == np.argmax(-np.array(bandits)):
    print "...and it was right!"
else:
    print "...and it was wrong!"

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

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

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

推薦閱讀更多精彩內容