強化學習之二:Q-Learning原理及表與神經網絡的實現(Q-Learning with Tables and Neural Networks)


本文是對Arthur Juliani在Medium平台發布的強化學習系列教程的個人中文翻譯。(This article is my personal translation for the tutorial written and posted by Arthur Juliani on Medium.com。)

原文地址(URL for original article):https://medium.com/emergent-future/simple-reinforcement-learning-with-tensorflow-part-0-q-learning-with-tables-and-neural-networks-d195264329d0


我們將學習如何解決OpenAI的冰湖(FrozenLake)問題。不過我們的冰湖版本和上圖呈現的圖片可不太一樣~

作為本強化學習教程系列的第一章,我們將一同探索強化學習算法的一個大家庭———Q-Learning算法—。它們和后面章節基於策略的算法(Policy-based algorithms)(1-3 part)有些不一樣。相對於用一個復雜而臃腫的深度神經網絡,我們將以實現一個簡單的查閱表(lookup-table)版本的算法為初始目標,然后再展示如何用Tensorflow框架來實現一個等價的神經網絡版本的算法。考慮到我們將回歸基礎知識,所以本教程可以視作系列教程的第0部分。希望本教程能夠幫助你理解Q-Learning的工作原理,基於此,我們將最終結合策略梯度(Policy Gradient)和Q-Learning來構造最先進的強化學習代理(Agents)。(如果你對策略網絡(Policy Networks)更感興趣,或者早就掌握了Q-Learning,你可以直接從這里開始。)

不像策略梯度方法那樣試圖學習到可以將一個觀察(Observation)與一個動作(action)直接映射的函數,Q-Learning會嘗試去學習給定一個狀態(State)下,采取某個具體動作的值。雖然這兩種方式最終都可以實現在給定情況下的智能行為決策,但是如何最終完成行為選擇的過程是非常不一樣的。你可能聽說過可以玩Atari游戲的深度Q網絡(Deep Q-Networs),而它其實本質上也就是更復雜的Q-Learning算法的實現。

表環境下的表方法(Tabular Approaches for Tabular Environments)

冰湖環境的規則:

在這個教程里,我們將試圖解決OpenAI的gym項目中包含的冰湖FrozenLake問題。對於不熟悉gym項目的人來說,OpenAI gym提供了一種能方便簡易地在一系列游戲中,對學習代理(learning agents)進行各類實驗或測試的方式。而其中之一的冰湖環境是一個4*4的網格。格子包含三種類型:起始格,目標格,安全的冰格和危險的冰洞。我們的目標是讓一個agent能夠自己從起點到終點,並且不會在中途掉入洞中。在任何時候,agent都可以選擇從上,下,左,右四個中選擇一個方向進行一步移動。而后會使問題變復雜的是,在冰湖環境中,還有會偶爾把agent吹得偏離到一個並非它移動目標的格子上。因此,在這種環境下agent就不太可能每次都能表現完美,但是學習如何去避免掉入洞中並達到目標格還是可以做到的。agent每走一步的回報(reward)都是0,除了在達到目標時為1。因此,我們需要一個算法可以學習到長期期望回報。這也就是Q-Learning發揮用處的地方。

在這個算法最簡單的實現中,Q-Learning會以一個表(table)的形式呈現。這個表的行代表不同的狀態(所在方格的坐標),列代表不同的可采取的行動(上、下、左、右移動一步)。在冰湖環境中,我們有16個狀態(每個方格算一個),以及四種動作,因此我們將得到一個16*4的Q值表,這個表的每一個具體值的含義是:該狀態下,采取該行為的長期期望回報。我們從初始化一個一致的Q值表(全部賦值為0)開始,再根據我們觀察得到的對各種行動的回報來更新Q值表的對應值。

我們對Q值表的更新准則是貝爾曼方程(Bellman Equation)。貝爾曼方程告訴我們:一個給定行動的期望長期回報等於【當前回報】加上【下一個狀態下,采取期望中所能帶來最優未來長期回報的行為對應的回報】。因此,我們可以在Q表上估計如何對未來行動的Q值進行更新。貝爾曼方程用數學公式表示如下:

Q(s,a)=r+γ(max(Q(s,a))

這個公式的描述了一個給定狀態s下,采取行動a的Q值等於當即獲得的回報r加上一個折現因子y乘以能夠最大化的在下一狀態s’采取時能獲得的最大長期回報的動作a’對應的長期回報。折現因子y允許我們決定相對於當前就可以獲得的回報,未來的可能回報的相對重要性。通過這種方式,Q表會慢慢開始獲得更准確的任一給定狀態下,采取任意動作所對應的期望未來回報值。以下是Python版的對於Q表版本的冰湖環境解決方案的完整實現:

import gym
import numpy as np


env = gym.make('FrozenLake-v0')

# Implement Q-Table learning algorithm
# 實現Q表學習算法
# Initialize table with all zeros
# 初始化Q表為全0值
Q = np.zeros([env.observation_space.n,env.action_space.n])
# Set learning parameters
# 設置學習參數
lr = .8
y = .95
num_episodes = 2000
# create lists to contain total rewards and steps per episode
# 創建列表以包含每個episode的總回報與總步數
#jList = []
rList = []
for i in range(num_episodes):
    # Reset environment and get first new observation
    # 初始化環境並獲得第一個觀察
    s = env.reset()
    rAll = 0
    d = False
    j = 0
    # The Q-Table learning algorithm
    # Q表學習算法
    while j < 99:
        j+=1
        # Choose an action by greedily (with noise) picking from Q table
        # 基於Q表貪婪地選擇一個最優行動(有噪音干擾)
        a = np.argmax(Q[s,:] + np.random.randn(1,env.action_space.n)*(1./(i+1)))
        # Get new state and reward from environment
        # 從環境中獲得回報和新的狀態信息
        s1,r,d,_ = env.step(a)

        #Update Q-Table with new knowledge
        # 用新的知識更新Q表
        Q[s,a] = Q[s,a] + lr*(r + y*np.max(Q[s1,:]) - Q[s,a])
        rAll += r
        s = s1
        if d == True:
            break
    #jList.append(j)
    rList.append(rAll)

print("Score over time: " +  str(sum(rList)/num_episodes))

print("Final Q-Table Values")
print(Q)

Github源代碼

(感謝Praneet D找到了該實現方法對應的最優的超參數)

基於神經網絡的Q-Learning(Q-Learning with Neural Networks)

現在你可能認為:表格方法挺好的,但是它不能規模化(scale),不是嗎?因為對一個簡單的網格世界建立一個16*4的表是很容易的,但是在任何一個現在的游戲或真實世界環境中都有無數可能的狀態。對於大多數有趣的問題,表格都無法發揮出作用。因此,我們需要一些代替性的方案來描述我們的狀態,並生成對應動作的Q值:這也就是神經網絡(Neural Network,簡稱NN)可以大展身手的地方。NN可以作為一個動作估計器(function approximator),我們能夠輸入任意多的可能狀態,因為所有狀態都可以被編碼成一個個向量,並把它們和各自對應的Q值進行對應(map)。

在冰湖例子中,我們將使用一個一層的NN,它接受以one-hot形式編碼的狀態向量(1*16),並輸出一個含有4個Q值的向量,每個分量對應一個動作的長期期望回報。這樣一個簡單的NN就像一個強化版的Q表,而網絡的權重就發揮着曾經的Q表中的各個單元格的作用。關鍵的不同時我們可以方便簡易地擴充Tensorflow網絡,包括加新的層,激活函數以及不同的輸出類型,而這些都是一個一般的表格無法做到的。於是,更新的方法也發生了一點變化。相比於之前直接更新表格,我們現在將使用逆傳播(backpropagation)和損失函數(loss function)**來完成更新。我們的損失函數采取平方和損失的形式,即加總當前預測的Q值與目標值間的差值的平方,並以梯度形式在網絡中傳播。這種情況下,所選行動的目標Q值依然采用上面提到的貝爾曼方程中的計算方法。

Loss=Σ(QtargetQ)2

以下是用Tensorflow實現簡單Q網絡的完整代碼:

# Q-Network Learning
# Q網絡學習

import gym
import numpy as np
import random
import tensorflow as tf
import matplotlib.pyplot as plt
%matplotlib inline

# Load the environment
# 加載環境

env = gym.make('FrozenLake-v0')


# The Q-Network Approach
# Q網絡方法
# Implementing the network itself
# 實現網絡

tf.reset_default_graph()

# These lines establish the feed-forward part of the network used to choose actions
# 下面的幾行代碼建立了網絡的前饋部分,它將用於選擇行動
inputs1 = tf.placeholder(shape=[1,16],dtype=tf.float32)
W = tf.Variable(tf.random_uniform([16,4],0,0.01))
Qout = tf.matmul(inputs1,W)
predict = tf.argmax(Qout,1)

# Below we obtain the loss by taking the sum of squares difference between the target and prediction Q values.
# 下面的幾行代碼可以獲得預測Q值與目標Q值間差值的平方和加總的損失。
nextQ = tf.placeholder(shape=[1,4],dtype=tf.float32)
loss = tf.reduce_sum(tf.square(nextQ - Qout))
trainer = tf.train.GradientDescentOptimizer(learning_rate=0.1)
updateModel = trainer.minimize(loss)

# Training the network
# 訓練網絡
init = tf.initialize_all_variables()

# Set learning parameters
# 設置學習參數
y = .99
e = 0.1
num_episodes = 2000
#create lists to contain total rewards and steps per episode
# 創建列表以包含每個episode對應的總回報與總步數。
jList = []
rList = []
with tf.Session() as sess:
    sess.run(init)
    for i in range(num_episodes):
        # Reset environment and get first new observation
        # 初始化環境並獲得第一個觀察
        s = env.reset()
        rAll = 0
        d = False
        j = 0
        # The Q-Network
        # Q網絡
        while j < 99:
            j+=1
            #Choose an action by greedily (with e chance of random action) from the Q-network
            # 基於Q網絡的輸出結果,貪婪地選擇一個行動(有一定的概率選擇隨機行動)
            a,allQ = sess.run([predict,Qout],feed_dict={inputs1:np.identity(16)[s:s+1]})
            if np.random.rand(1) < e:
                a[0] = env.action_space.sample()
            # Get new state and reward from environment
            # 從環境中獲得回報以及新的狀態信息
            s1,r,d,_ = env.step(a[0])
            # Obtain the Q' values by feeding the new state through our network
            # 通過將新的狀態向量輸入到網絡中獲得Q值。
            Q1 = sess.run(Qout,feed_dict={inputs1:np.identity(16)[s1:s1+1]})
            # Obtain maxQ' and set our target value for chosen action.
            # 獲得最大的Q值,並為所選行為設定目標值
            maxQ1 = np.max(Q1)
            targetQ = allQ
            targetQ[0,a[0]] = r + y*maxQ1
            # Train our network using target and predicted Q values
            # 用目標和預測的Q值訓練網絡
            _,W1 = sess.run([updateModel,W],feed_dict={inputs1:np.identity(16)[s:s+1],nextQ:targetQ})
            rAll += r
            s = s1
            if d == True:
                # Reduce chance of random action as we train the model.
                # 隨着訓練的進行,主鍵減少選擇隨機行為的概率
                e = 1./((i/50) + 10)
                break
        jList.append(j)
        rList.append(rAll)
print("Percent of succesful episodes: " + str(sum(rList)/num_episodes) + "%")

# Percent of succesful episodes: 0.352%
# 成功的episode比例:0.352%
# Some statistics on network performance
# 一些網絡性能的統計量
# We can see that the network beings to consistently reach the goal around the 750 episode mark.
# 我們可以看到,當網絡訓練了750個episode左右的時候,agent就可以比較穩定地到達目標了。


plt.plot(rList)

# It also begins to progress through the environment for longer than chance aroudn the 750 mark as well.
# 在750個episode之后,agent也一般需要更長的步數以到達目標。

plt.plot(jList)

雖然網絡學會了解決冰湖問題,但是結果表明它似乎比如Q表方法那么高效。即雖然神經網絡在Q-Learning問題上提供了更高的靈活性,但它也犧牲了一定的穩定性。還有很多可能的對我們的簡單Q網絡進行擴展的辦法,這些擴展可以讓NN獲得更好的性能並實現更穩定的學習過程。兩種需要提到的特別技巧分別是經驗重放(Experience Replay)冰凍目標網絡(Freezing Target Networks)。這些改進方式或者其它的一些技巧都是讓DQN可以玩Atari游戲的關鍵所在,並且我們也將在后面探索這些相關知識。對於有關Q-Learning的更多理論,可以看Tambet Matiisen的這篇博文,希望本教程可以幫助對實現簡單Q-Learning算法的人們一些幫助!


如果這篇博文對你有幫助,你可以考慮捐贈以支持未來更多的相關的教程、文章和實現。對任意的幫助與貢獻都表示非常感激!

如果你想跟進我在深度學習、人工智能、感知科學方面的工作,可以在Medium上follow我 @Arthur Juliani,或者推特@awjliani。

用Tensorflow實現簡單強化學習的系列教程:

  1. Part 0 — Q-Learning Agents
  2. Part 1 — Two-Armed Bandit
  3. Part 1.5 — Contextual Bandits
  4. Part 2 — Policy-Based Agents
  5. Part 3 — Model-Based RL
  6. Part 4 — Deep Q-Networks and Beyond
  7. Part 5 — Visualizing an Agent’s Thoughts and Actions
  8. Part 6 — Partial Observability and Deep Recurrent Q-Networks
  9. Part 7 — Action-Selection Strategies for Exploration
  10. Part 8 — Asynchronous Actor-Critic Agents (A3C)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM