# 十三、深度強化學習
強化學習是一種學習形式,其中軟件智能體觀察環境并采取行動以最大化其對環境的獎勵,如下圖所示:

這個比喻可以用來表示現實生活中的情況,如下所示:
* 股票交易智能體觀察交易信息,新聞,分析和其他形式信息,并采取行動買入或賣出交易,以便以短期利潤或長期利潤的形式最大化獎勵。
* 保險智能體觀察有關客戶的信息,然后采取行動確定保險費金額,以便最大化利潤并最大限度地降低風險。
* 類人機器人觀察環境然后采取行動,例如步行,跑步或拾取物體,以便在實現目標方面最大化獎勵。
強化學習已成功應用于許多應用,如廣告優化,股票市場交易,自動駕駛汽車,機器人和游戲,僅舉幾例。
強化學習與監督學習不同,因為預先沒有標簽來調整模型的參數。該模型從運行中獲得的獎勵中學習。雖然短期獎勵可以立即獲得,但只有經過幾個步驟才能獲得長期獎勵。這種現象也稱為**延遲反饋**。
強化學習也與無監督學習不同,因為在無監督學習中沒有可用的標簽,而在強化學習中,反饋可用于獎勵。
在本章中,我們將通過涵蓋以下主題來了解強化學習及其在 TensorFlow 和 Keras 中的實現:
* OpenAI Gym 101
* 將簡單的策略應用于 Cartpole 游戲
* 強化學習 101
* Q 函數
* 探索和利用
* V 函數
* RL 技術
* RL 的簡單神經網絡策略
* 實現 Q-Learning
* Q-Learning 的初始化和離散化
* 使用 Q-Table 進行 Q-Learning
* 深度 Q 網絡:使用 Q-Network 進行 Q-Learning
我們將在 OpenAI Gym 中演示我們的示例,讓我們首先了解一下 OpenAI Gym。
# OpenAI Gym 101
OpenAI Gym 是一個基于 Python 的工具包,用于研究和開發強化學習算法。 OpenAI Gym 在撰寫本文時提供了 700 多個開源貢獻環境。使用 OpenAI,您還可以創建自己的環境。最大的優勢是 OpenAI 提供了一個統一的接口來處理這些環境,并在您專注于強化學習算法的同時負責運行模擬。
[描述 OpenAI Gym 的研究論文可在此鏈接中找到](http://arxiv.org/abs/1606.01540)。
您可以使用以下命令安裝 OpenAI Gym:
```py
pip3 install gym
```
如果上述命令不起作用,[您可以在此鏈接中找到有關安裝的更多幫助](https://github.com/openai/gym#installation)。?
1. 讓我們在 OpenAI Gym 中打印可用環境的數量:
您可以按照本書代碼包中的 Jupyter 筆記本`ch-13a_Reinforcement_Learning_NN`中的代碼進行操作。
```py
all_env = list(gym.envs.registry.all())
print('Total Environments in Gym version {} : {}'
.format(gym.__version__,len(all_env)))
Total Environments in Gym version 0.9.4 : 777
```
1. 讓我們打印所有環境的列表:
```py
for e in list(all_env):
print(e)
```
輸出的部分列表如下:
```py
EnvSpec(Carnival-ramNoFrameskip-v0)
EnvSpec(EnduroDeterministic-v0)
EnvSpec(FrostbiteNoFrameskip-v4)
EnvSpec(Taxi-v2)
EnvSpec(Pooyan-ram-v0)
EnvSpec(Solaris-ram-v4)
EnvSpec(Breakout-ramDeterministic-v0)
EnvSpec(Kangaroo-ram-v4)
EnvSpec(StarGunner-ram-v4)
EnvSpec(Enduro-ramNoFrameskip-v4)
EnvSpec(DemonAttack-ramDeterministic-v0)
EnvSpec(TimePilot-ramNoFrameskip-v0)
EnvSpec(Amidar-v4)
```
由`env`對象表示的每個環境都有一個標準化的接口,例如:
* 通過傳遞 ID 字符串,可以使用`env.make(<game-id-string>)`函數創建`env`對象。
* 每個`env`對象包含以下主要函數:
* `step()`函數將操作對象作為參數并返回四個對象:
* 觀察:由環境實現的對象,代表對環境的觀察。
* 獎勵:一個帶符號的浮點值,表示前一個操作的增益(或損失)。
* `done`:表示方案是否完成的布爾值。
* `info`:表示診斷信息的 Python 字典對象。
* `render()`函數可創建環境的直觀表示。
* `reset()`函數將環境重置為原始狀態。
* 每個`env`對象都有明確定義的動作和觀察,由`action_space`和`observation_space`表示。
CartPole 是健身房里最受歡迎的學習強化學習游戲之一。在這個游戲中,連接到推車的桿必須平衡,以便它不會下降。如果桿子傾斜超過 15 度或者推車從中心移動超過 2.4 個單元,則游戲結束。 [OpenAI.com](http://openai.com) 的主頁用這些詞強調游戲:
這種環境的小尺寸和簡單性使得可以進行非常快速的實驗,這在學習基礎知識時是必不可少的。
游戲只有四個觀察和兩個動作。動作是通過施加 +1 或 -1 的力來移動購物車。觀察結果是推車的位置,推車的速度,桿的角度以及桿的旋轉速度。然而,學習觀察語義的知識不是學習最大化游戲獎勵所必需的。
現在讓我們加載一個流行的游戲環境 CartPole-v0,然后用隨機控件播放:
1. 使用標準`make`函數創建`env`對象:
```py
env = gym.make('CartPole-v0')
```
1. 劇集的數量是游戲的數量。我們現在將它設置為一個,表示我們只想玩一次游戲。由于每集都是隨機的,因此在實際的制作過程中,您將運行多集并計算獎勵的平均值。此外,我們可以初始化一個數組,以便在每個時間步都存儲環境的可視化:
```py
n_episodes = 1
env_vis = []
```
1. 運行兩個嵌套循環 - 一個用于劇集數量的外部循環和一個用于您要模擬的時間步數的內部循環。您可以繼續運行內部循環,直到方案完成或將步數設置為更高的值。
* 在每集開始時,使用`env.reset()`重置環境。
* 在每個時間步的開始,使用`env.render()`捕獲可視化。
```py
for i_episode in range(n_episodes):
observation = env.reset()
for t in range(100):
env_vis.append(env.render(mode = 'rgb_array'))
print(observation)
action = env.action_space.sample()
observation, reward, done, info = env.step(action)
if done:
print("Episode finished at t{}".format(t+1))
break
```
1. 使用輔助函數渲染環境:
```py
env_render(env_vis)
```
1. 輔助函數的代碼如下:
```py
def env_render(env_vis):
plt.figure()
plot = plt.imshow(env_vis[0])
plt.axis('off')
def animate(i):
plot.set_data(env_vis[i])
anim = anm.FuncAnimation(plt.gcf(),
animate,
frames=len(env_vis),
interval=20,
repeat=True,
repeat_delay=20)
display(display_animation(anim, default_mode='loop'))
```
運行此示例時,我們得到以下輸出:
```py
[-0.00666995 -0.03699492 -0.00972623 0.00287713]
[-0.00740985 0.15826516 -0.00966868 -0.29285861]
[-0.00424454 -0.03671761 -0.01552586 -0.00324067]
[-0.0049789 -0.2316135 -0.01559067 0.28450351]
[-0.00961117 -0.42650966 -0.0099006 0.57222875]
[-0.01814136 -0.23125029 0.00154398 0.27644332]
[-0.02276636 -0.0361504 0.00707284 -0.01575223]
[-0.02348937 0.1588694 0.0067578 -0.30619523]
[-0.02031198 -0.03634819 0.00063389 -0.01138875]
[-0.02103895 0.15876466 0.00040612 -0.3038716 ]
[-0.01786366 0.35388083 -0.00567131 -0.59642642]
[-0.01078604 0.54908168 -0.01759984 -0.89089036]
[ 1.95594914e-04 7.44437934e-01 -3.54176495e-02 -1.18905344e+00]
[ 0.01508435 0.54979251 -0.05919872 -0.90767902]
[ 0.0260802 0.35551978 -0.0773523 -0.63417465]
[ 0.0331906 0.55163065 -0.09003579 -0.95018025]
[ 0.04422321 0.74784161 -0.1090394 -1.26973934]
[ 0.05918004 0.55426764 -0.13443418 -1.01309691]
[ 0.0702654 0.36117014 -0.15469612 -0.76546874]
[ 0.0774888 0.16847818 -0.1700055 -0.52518186]
[ 0.08085836 0.3655333 -0.18050913 -0.86624457]
[ 0.08816903 0.56259197 -0.19783403 -1.20981195]
Episode finished at t22
```
桿子需要 22 個時間步長才能變得不平衡。在每次運行中,我們得到不同的時間步長值,因為我們通過使用`env.action_space.sample()`在學術上選擇了動作。
由于游戲如此迅速地導致失敗,隨機選擇一個動作并應用它可能不是最好的策略。有許多算法可以找到解決方案,使桿子保持筆直,可以使用更長的時間步長,例如爬山,隨機搜索和策略梯度。
解決 Cartpole 游戲的一些算法可通過此鏈接獲得:
<https://openai.com/requests-for-research/#cartpole>
<http://kvfrans.com/simple-algoritms-for-solving-cartpole/>
<https://github.com/kvfrans/openai-cartpole>
# 將簡單的策略應用于 Cartpole 游戲
到目前為止,我們已經隨機選擇了一個動作并應用它。現在讓我們應用一些邏輯來挑選行動而不是隨機機會。第三個觀察指的是角度。如果角度大于零,則意味著桿向右傾斜,因此我們將推車向右移動(1)。否則,我們將購物車向左移動(0)。我們來看一個例子:
1. 我們定義了兩個策略函數如下:
```py
def policy_logic(env,obs):
return 1 if obs[2] > 0 else 0
def policy_random(env,obs):
return env.action_space.sample()
```
1. 接下來,我們定義一個將針對特定數量的劇集運行的實驗函數;每一集一直持續到游戲損失,即`done`為`True`。我們使用`rewards_max`來指示何時突破循環,因為我們不希望永遠運行實驗:
```py
def experiment(policy, n_episodes, rewards_max):
rewards=np.empty(shape=(n_episodes))
env = gym.make('CartPole-v0')
for i in range(n_episodes):
obs = env.reset()
done = False
episode_reward = 0
while not done:
action = policy(env,obs)
obs, reward, done, info = env.step(action)
episode_reward += reward
if episode_reward > rewards_max:
break
rewards[i]=episode_reward
print('Policy:{}, Min reward:{}, Max reward:{}'
.format(policy.__name__,
min(rewards),
max(rewards)))
```
1. 我們運行實驗 100 次,或直到獎勵小于或等于`rewards_max`,即設置為 10,000:
```py
n_episodes = 100
rewards_max = 10000
experiment(policy_random, n_episodes, rewards_max)
experiment(policy_logic, n_episodes, rewards_max)
```
我們可以看到邏輯選擇的動作比隨機選擇的動作更好,但不是更好:
```py
Policy:policy_random, Min reward:9.0, Max reward:63.0, Average reward:20.26
Policy:policy_logic, Min reward:24.0, Max reward:66.0, Average reward:42.81
```
現在讓我們進一步修改選擇動作的過程 - 基于參數。參數將乘以觀察值,并且將基于乘法結果是零還是一來選擇動作。讓我們修改隨機搜索方法,我們隨機初始化參數。代碼如下:
```py
def policy_logic(theta,obs):
# just ignore theta
return 1 if obs[2] > 0 else 0
def policy_random(theta,obs):
return 0 if np.matmul(theta,obs) < 0 else 1
def episode(env, policy, rewards_max):
obs = env.reset()
done = False
episode_reward = 0
if policy.__name__ in ['policy_random']:
theta = np.random.rand(4) * 2 - 1
else:
theta = None
while not done:
action = policy(theta,obs)
obs, reward, done, info = env.step(action)
episode_reward += reward
if episode_reward > rewards_max:
break
return episode_reward
def experiment(policy, n_episodes, rewards_max):
rewards=np.empty(shape=(n_episodes))
env = gym.make('CartPole-v0')
for i in range(n_episodes):
rewards[i]=episode(env,policy,rewards_max)
#print("Episode finished at t{}".format(reward))
print('Policy:{}, Min reward:{}, Max reward:{}, Average reward:{}'
.format(policy.__name__,
np.min(rewards),
np.max(rewards),
np.mean(rewards)))
n_episodes = 100
rewards_max = 10000
experiment(policy_random, n_episodes, rewards_max)
experiment(policy_logic, n_episodes, rewards_max)
```
我們可以看到隨機搜索確實改善了結果:
```py
Policy:policy_random, Min reward:8.0, Max reward:200.0, Average reward:40.04
Policy:policy_logic, Min reward:25.0, Max reward:62.0, Average reward:43.03
```
通過隨機搜索,我們改進了結果以獲得 200 的最大獎勵。平均而言,隨機搜索的獎勵較低,因為隨機搜索會嘗試各種不良參數,從而降低整體結果。但是,我們可以從所有運行中選擇最佳參數,然后在生產中使用最佳參數。讓我們修改代碼以首先訓練參數:
```py
def policy_logic(theta,obs):
# just ignore theta
return 1 if obs[2] > 0 else 0
def policy_random(theta,obs):
return 0 if np.matmul(theta,obs) < 0 else 1
def episode(env,policy, rewards_max,theta):
obs = env.reset()
done = False
episode_reward = 0
while not done:
action = policy(theta,obs)
obs, reward, done, info = env.step(action)
episode_reward += reward
if episode_reward > rewards_max:
break
return episode_reward
def train(policy, n_episodes, rewards_max):
env = gym.make('CartPole-v0')
theta_best = np.empty(shape=[4])
reward_best = 0
for i in range(n_episodes):
if policy.__name__ in ['policy_random']: theta = np.random.rand(4) * 2 - 1
else:
theta = None
reward_episode=episode(env,policy,rewards_max, theta)
if reward_episode > reward_best:
reward_best = reward_episode
theta_best = theta.copy()
return reward_best,theta_best
def experiment(policy, n_episodes, rewards_max, theta=None):
rewards=np.empty(shape=[n_episodes])
env = gym.make('CartPole-v0')
for i in range(n_episodes):
rewards[i]=episode(env,policy,rewards_max,theta)
#print("Episode finished at t{}".format(reward))
print('Policy:{}, Min reward:{}, Max reward:{}, Average reward:{}'
.format(policy.__name__,
np.min(rewards),
np.max(rewards),
np.mean(rewards)))
n_episodes = 100
rewards_max = 10000
reward,theta = train(policy_random, n_episodes, rewards_max)
print('trained theta: {}, rewards: {}'.format(theta,reward))
experiment(policy_random, n_episodes, rewards_max, theta)
experiment(policy_logic, n_episodes, rewards_max)
```
我們訓練了 100 集,然后使用最佳參數為隨機搜索策略運行實驗:
```py
n_episodes = 100
rewards_max = 10000
reward,theta = train(policy_random, n_episodes, rewards_max)
print('trained theta: {}, rewards: {}'.format(theta,reward))
experiment(policy_random, n_episodes, rewards_max, theta)
experiment(policy_logic, n_episodes, rewards_max)
```
我們發現訓練參數給出了 200 的最佳結果:
```py
trained theta: [-0.14779543 0.93269603 0.70896423 0.84632461], rewards: 200.0
Policy:policy_random, Min reward:200.0, Max reward:200.0, Average reward:200.0
Policy:policy_logic, Min reward:24.0, Max reward:63.0, Average reward:41.94
```
我們可以優化訓練代碼以繼續訓練,直到我們獲得最大獎勵。筆記本`ch-13a_Reinforcement_Learning_NN`中提供了此優化的代碼。
現在我們已經學習了 OpenAI Gym 的基礎知識,讓我們學習強化學習。
# 強化學習 101
強化學習由智能體從前一個時間步驟輸入觀察和獎勵并以動作產生輸出來描述,目標是最大化累積獎勵。
智能體具有策略,值函數和模型:
* 智能體用于選擇下一個動作的算法稱為**策略**。在上一節中,我們編寫了一個策略,它將采用一組參數`θ`,并根據觀察和參數之間的乘法返回下一個動作。該策略由以下等式表示:

`S`是一組狀態,`A`是一組動作。
策略是確定性的或隨機性的。
* 確定性策略在每次運行中為相同狀態返回相同的操作:

* 隨機策略為每次運行中的相同狀態返回相同操作的不同概率:

* **值函數**根據當前狀態中的所選動作預測長期獎勵的數量。因此,值函數特定于智能體使用的策略。獎勵表示行動的直接收益,而值函數表示行動的累積或長期未來收益。獎勵由環境返回,值函數由智能體在每個時間步驟估計。
* **模型**表示智能體在內部保存的環境。該模型可能是環境的不完美表示。智能體使用該模型來估計所選動作的獎勵和下一個狀態。
智能體的目標還可以是為馬爾可夫決策過程(MDP)找到最優策略。 MDP 是從一個州到另一個州的觀察,行動,獎勵和過渡的數學表示。為簡潔起見,我們將省略對 MDP 的討論,并建議好奇的讀者在互聯網上搜索更深入 MDP 的資源。
# Q 函數(在模型不可用時學習優化)
如果模型不可用,則智能體通過反復試驗來學習模型和最優策略。當模型不可用時,智能體使用 Q 函數,其定義如下:

如果狀態`s`處的智能體選擇動作`a`,則 Q 函數基本上將狀態和動作對映射到表示預期總獎勵的實數。
# RL 算法的探索與利用
在沒有模型的情況下,智能體在每一步都要探索或利用。 **探索**意味著智能體選擇一個未知動作來找出獎勵和模型。 **利用**意味著智能體選擇最知名的行動來獲得最大獎勵。如果智能體總是決定利用它,那么它可能會陷入局部最優值。因此,有時智能體會繞過學到的策略來探索未知的行為。同樣,如果智能體總是決定探索,那么它可能無法找到最優策略。因此,在探索和利用之間取得平衡非常重要。在我們的代碼中,我們通過使用概率`p`來選擇隨機動作和概率`1-p`來選擇最優動作來實現這一點。
# V 函數(模型可用時學習優化)
如果事先知道模型,則智能體可以執行**策略搜索**以找到最大化值函數的最優策略。當模型可用時,智能體使用值函數,該函數可以樸素地定義為未來狀態的獎勵總和:

因此,使用策略`p`選擇操作的時間步`t`的值將是:

`V`是值,`R`是獎勵,值函數估計在未來最多`n`個時間步長。
當智能體使用這種方法估計獎勵時,它會平等地將所有行為視為獎勵。在極點推車示例中,如果民意調查在步驟 50 處進行,則它將把直到第 50 步的所有步驟視為對跌倒的同等責任。因此,不是添加未來獎勵,而是估計未來獎勵的加權總和。通常,權重是提高到時間步長的折扣率。如果貼現率為零,則值函數變為上面討論的幼稚函數,并且如果貼現率的值接近 1,例如 0.9 或 0.92,則與當前獎勵相比,未來獎勵的影響較小。
因此,現在行動`a`的時間步`t`的值將是:

`V`是值,`R`是獎勵,`r`是折扣率。
**V 函數和 Q 函數之間的關系**:
`V*(s)`是狀態`s`下的最優值函數,其給出最大獎勵,并且`Q*(s,a)`是狀態`s`下的最佳 Q 函數,其通過選擇動作`a`給出最大期望獎勵。 因此,`V*(s)`是所有可能動作中所有最優 Q 函數`Q*(s,a)`的最大值:

# 強化學習技巧
可以根據模型的可用性對強化學習技術進行如下分類:
* **模型可用**:如果模型可用,則智能體可以通過迭代策略或值函數來離線計劃,以找到提供最大獎勵的最優策略。
* **值迭代學習**:在值迭代學習方法中,智能體通過將`V(s)`初始化為隨機值開始,然后重復更新`V(s)`直到找到最大獎勵。
* **策略迭代學習** : 在策略迭代學習方法中,智能體通過初始化隨機策略`p`開始,然后重復更新策略,直到找到最大獎勵。
* **模型不可用**:如果模型不可用,則智能體只能通過觀察其動作的結果來學習。因此,從觀察,行動和獎勵的歷史來看,智能體會嘗試估計模型或嘗試直接推導出最優策略:
* **基于模型的學習**:在基于模型的學習中,智能體首先從歷史中估計模型,然后使用策略或基于值的方法來找到最優策略。
* **無模型學習**:在無模型學習中,智能體不會估計模型,而是直接從歷史中估計最優策略。 Q-Learning 是無模型學習的一個例子。
作為示例,值迭代學習的算法如下:
```py
initialize V(s) to random values for all states
Repeat
for s in states
for a in actions
compute Q[s,a]
V(s) = max(Q[s]) # maximum of Q for all actions for that state
Until optimal value of V(s) is found for all states
```
策略迭代學習的算法如下:
```py
initialize a policy P_new to random sequence of actions for all states
Repeat
P = P_new
for s in states
compute V(s) with P[s]
P_new[s] = policy of optimal V(s)
Until P == P_new
```
# 強化學習的樸素神經網絡策略
我們按照以下策略進行:
1. 讓我們實現一個樸素的基于神經網絡的策略。為定義一個新策略使用基于神經網絡的預測來返回動作:
```py
def policy_naive_nn(nn,obs):
return np.argmax(nn.predict(np.array([obs])))
```
1. 將`nn`定義為一個簡單的單層 MLP 網絡,它將具有四個維度的觀測值作為輸入,并產生兩個動作的概率:
```py
from keras.models import Sequential
from keras.layers import Dense
model = Sequential()
model.add(Dense(8,input_dim=4, activation='relu'))
model.add(Dense(2, activation='softmax'))
model.compile(loss='categorical_crossentropy',optimizer='adam')
model.summary()
```
這就是模型的樣子:
```py
Layer (type) Output Shape Param #
=================================================================
dense_16 (Dense) (None, 8) 40
_________________________________________________________________
dense_17 (Dense) (None, 2) 18
=================================================================
Total params: 58
Trainable params: 58
Non-trainable params: 0
```
1. 這個模型需要訓練。運行 100 集的模擬并僅收集分數大于 100 的那些劇集的訓練數據。如果分數小于 100,那么這些狀態和動作不值得記錄,因為它們不是好戲的例子:
```py
# create training data
env = gym.make('CartPole-v0')
n_obs = 4
n_actions = 2
theta = np.random.rand(4) * 2 - 1
n_episodes = 100
r_max = 0
t_max = 0
x_train, y_train = experiment(env,
policy_random,
n_episodes,
theta,r_max,t_max,
return_hist_reward=100 )
y_train = np.eye(n_actions)[y_train]
print(x_train.shape,y_train.shape)
```
我們能夠收集 5732 個樣本進行訓練:
```py
(5732, 4) (5732, 2)
```
1. 接下來,訓練模型:
```py
model.fit(x_train, y_train, epochs=50, batch_size=10)
```
1. 訓練的模型可用于玩游戲。但是,在我們合并更新訓練數據的循環之前,模型不會從游戲的進一步游戲中學習:
```py
n_episodes = 200
r_max = 0
t_max = 0
_ = experiment(env,
policy_naive_nn,
n_episodes,
theta=model,
r_max=r_max,
t_max=t_max,
return_hist_reward=0 )
_ = experiment(env,
policy_random,
n_episodes,
theta,r_max,t_max,
return_hist_reward=0 )
```
我們可以看到,這種樸素的策略幾乎以同樣的方式執行,雖然比隨機策略好一點:
```py
Policy:policy_naive_nn, Min reward:37.0, Max reward:200.0, Average reward:71.05
Policy:policy_random, Min reward:36.0, Max reward:200.0, Average reward:68.755
```
我們可以通過網絡調整和超參數調整,或通過學習更多游戲玩法來進一步改進結果。 但是,有更好的算法,例如 Q-Learning。
在本章的其余部分,我們將重點關注 Q-Learning 算法,因為大多數現實生活中的問題涉及無模型學習。
# 實現 Q-Learning
Q-Learning 是一種無模型的方法,可以找到可以最大化智能體獎勵的最優策略。在最初的游戲過程中,智能體會為每對(狀態,動作)學習 Q 值,也稱為探索策略,如前面部分所述。一旦學習了 Q 值,那么最優策略將是在每個狀態中選擇具有最大 Q 值的動作,也稱為利用策略。學習算法可以以局部最優解決方案結束,因此我們通過設置`exploration_rate`參數來繼續使用探索策略。
Q-Learning 算法如下:
```py
initialize Q(shape=[#s,#a]) to random values or zeroes
Repeat (for each episode)
observe current state s
Repeat
select an action a (apply explore or exploit strategy)
observe state s_next as a result of action a
update the Q-Table using bellman's equation
set current state s = s_next
until the episode ends or a max reward / max steps condition is reached
Until a number of episodes or a condition is reached
(such as max consecutive wins)
```
上述算法中的`Q(s, )`表示我們在前面部分中描述的 Q 函數。此函數的值用于選擇操作而不是獎勵,因此此函數表示獎勵或折扣獎勵。使用未來狀態中 Q 函數的值更新 Q 函數的值。眾所周知的貝爾曼方程捕獲了這一更新:

這基本上意味著在時間步驟`t`,在狀態`s`中,對于動作`a`,最大未來獎勵(Q)等于來自當前狀態的獎勵加上來自下一狀態的最大未來獎勵。
`Q(s, a)`可以實現為 Q 表或稱為 Q 網絡的神經網絡。在這兩種情況下,Q 表或 Q 網絡的任務是基于給定輸入的 Q 值提供最佳可能的動作。隨著 Q 表變大,基于 Q 表的方法通常變得棘手,因此使神經網絡成為通過 Q 網絡逼近 Q 函數的最佳候選者。讓我們看看這兩種方法的實際應用。
您可以按照本書代碼包中的 Jupyter 筆記本`ch-13b_Reinforcement_Learning_DQN`中的代碼進行操作。
# Q-Learning 的初始化和離散化
極地車環境返回的觀測涉及環境狀況。極點車的狀態由我們需要離散的連續值表示。
如果我們將這些值離散化為小的狀態空間,那么智能體會得到更快的訓練,但需要注意的是會有收斂到最優策略的風險。
我們使用以下輔助函數來離散極推車環境的狀態空間:
```py
# discretize the value to a state space
def discretize(val,bounds,n_states):
discrete_val = 0
if val <= bounds[0]:
discrete_val = 0
elif val >= bounds[1]:
discrete_val = n_states-1
else:
discrete_val = int(round( (n_states-1) *
((val-bounds[0])/
(bounds[1]-bounds[0]))
))
return discrete_val
def discretize_state(vals,s_bounds,n_s):
discrete_vals = []
for i in range(len(n_s)):
discrete_vals.append(discretize(vals[i],s_bounds[i],n_s[i]))
return np.array(discrete_vals,dtype=np.int)
```
我們將每個觀察尺寸的空間離散為 10 個單元。您可能想嘗試不同的離散空間。在離散化之后,我們找到觀察的上限和下限,并將速度和角速度的界限改變在 -1 和 +1 之間,而不是`-Inf`和`+Inf`。代碼如下:
```py
env = gym.make('CartPole-v0')
n_a = env.action_space.n
# number of discrete states for each observation dimension
n_s = np.array([10,10,10,10]) # position, velocity, angle, angular velocity
s_bounds = np.array(list(zip(env.observation_space.low, env.observation_space.high)))
# the velocity and angular velocity bounds are
# too high so we bound between -1, +1
s_bounds[1] = (-1.0,1.0)
s_bounds[3] = (-1.0,1.0)
```
# 使用 Q-Table 的 Q-Learning
您可以在`ch-13b.ipynb`中按照本節的代碼進行操作。 由于我們的離散空間的尺寸為`[10,10,10,10]`,因此我們的 Q 表的尺寸為`[10,10,10,10,2]`:
```py
# create a Q-Table of shape (10,10,10,10, 2) representing S X A -> R
q_table = np.zeros(shape = np.append(n_s,n_a))
```
我們根據`exploration_rate`定義了一個利用或探索的 Q-Table 策略:
```py
def policy_q_table(state, env):
# Exploration strategy - Select a random action
if np.random.random() < explore_rate:
action = env.action_space.sample()
# Exploitation strategy - Select the action with the highest q
else:
action = np.argmax(q_table[tuple(state)])
return action
```
定義運行單個劇集的`episode()`函數,如下所示:
1. 首先初始化變量和第一個狀態:
```py
obs = env.reset()
state_prev = discretize_state(obs,s_bounds,n_s)
episode_reward = 0
done = False
t = 0
```
1. 選擇操作并觀察下一個狀態:
```py
action = policy(state_prev, env)
obs, reward, done, info = env.step(action)
state_new = discretize_state(obs,s_bounds,n_s)
```
1. 更新 Q 表:
```py
best_q = np.amax(q_table[tuple(state_new)])
bellman_q = reward + discount_rate * best_q
indices = tuple(np.append(state_prev,action))
q_table[indices] += learning_rate*( bellman_q - q_table[indices])
```
1. 將下一個狀態設置為上一個狀態,并將獎勵添加到劇集的獎勵中:
```py
state_prev = state_new
episode_reward += reward
```
`experiment()`函數調用劇集函數并累積報告獎勵。您可能希望修改該函數以檢查連續獲勝以及特定于您的游戲或游戲的其他邏輯:
```py
# collect observations and rewards for each episode
def experiment(env, policy, n_episodes,r_max=0, t_max=0):
rewards=np.empty(shape=[n_episodes])
for i in range(n_episodes):
val = episode(env, policy, r_max, t_max)
rewards[i]=val
print('Policy:{}, Min reward:{}, Max reward:{}, Average reward:{}'
.format(policy.__name__,
np.min(rewards),
np.max(rewards),
np.mean(rewards)))
```
現在,我們要做的就是定義參數,例如`learning_rate`,`discount_rate`和`explore_rate`,并運行`experiment()`函數,如下所示:
```py
learning_rate = 0.8
discount_rate = 0.9
explore_rate = 0.2
n_episodes = 1000
experiment(env, policy_q_table, n_episodes)
```
對于 1000 集,基于我們的簡單實現,基于 Q-Table 的策略的最大獎勵為 180:
```py
Policy:policy_q_table, Min reward:8.0, Max reward:180.0, Average reward:17.592
```
我們對算法的實現很容易解釋。但是,您可以對代碼進行修改以將探索率設置為最初,然后隨著時間步長的過去而衰減。同樣,您還可以實現學習和折扣率的衰減邏輯。讓我們看看,由于我們的 Q 函數學得更快,我們是否可以用更少的劇集獲得更高的獎勵。
# 使用 Q-Network 或深度 Q 網絡(DQN)的 Q-Learning
在 DQN 中,我們將 Q-Table 替換為神經網絡(Q-Network),當我們使用探索狀態及其 Q 值連續訓練時,它將學會用最佳動作進行響應。因此,為了訓練網絡,我們需要一個存儲游戲內存的地方:
1. 使用大小為 1000 的雙端隊列實現游戲內存:
```py
memory = deque(maxlen=1000)
```
1. 接下來,構建一個簡單的隱藏層神經網絡模型,`q_nn`:
```py
from keras.models import Sequential
from keras.layers import Dense
model = Sequential()
model.add(Dense(8,input_dim=4, activation='relu'))
model.add(Dense(2, activation='linear'))
model.compile(loss='mse',optimizer='adam')
model.summary()
q_nn = model
```
Q-Network 看起來像這樣:
```py
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
dense_1 (Dense) (None, 8) 40
_________________________________________________________________
dense_2 (Dense) (None, 2) 18
=================================================================
Total params: 58
Trainable params: 58
Non-trainable params: 0
_________________________________________________________________
```
執行游戲的一集的`episode()`函數包含基于 Q-Network 的算法的以下更改:
1. 生成下一個狀態后,將狀態,操作和獎勵添加到游戲內存中:
```py
action = policy(state_prev, env)
obs, reward, done, info = env.step(action)
state_next = discretize_state(obs,s_bounds,n_s)
# add the state_prev, action, reward, state_new, done to memory
memory.append([state_prev,action,reward,state_next,done])
```
1. 使用 bellman 函數生成并更新`q_values`以獲得最大的未來獎勵:
```py
states = np.array([x[0] for x in memory])
states_next = np.array([np.zeros(4) if x[4] else x[3] for x in memory])
q_values = q_nn.predict(states)
q_values_next = q_nn.predict(states_next)
for i in range(len(memory)):
state_prev,action,reward,state_next,done = memory[i]
if done:
q_values[i,action] = reward
else:
best_q = np.amax(q_values_next[i])
bellman_q = reward + discount_rate * best_q
q_values[i,action] = bellman_q
```
1. 訓練`q_nn`的狀態和我們從記憶中收到的`q_values`:
```py
q_nn.fit(states,q_values,epochs=1,batch_size=50,verbose=0)
```
將游戲玩法保存在內存中并使用它來訓練模型的過程在深度強化學習文獻中也稱為**記憶重放**。讓我們按照以下方式運行基于 DQN 的游戲:
```py
learning_rate = 0.8
discount_rate = 0.9
explore_rate = 0.2
n_episodes = 100
experiment(env, policy_q_nn, n_episodes)
```
我們獲得 150 的最大獎勵,您可以通過超參數調整,網絡調整以及使用折扣率和探索率的速率衰減來改進:
```py
Policy:policy_q_nn, Min reward:8.0, Max reward:150.0, Average reward:41.27
```
我們在每一步計算和訓練模型;您可能希望在劇集之后探索將其更改為訓練。此外,您可以更改代碼以丟棄內存重放,并為返回較小獎勵的劇集再訓練模型。但是,請謹慎實現此選項,因為它可能會減慢您的學習速度,因為初始游戲會更頻繁地產生較小的獎勵。
# 總結
在本章中,我們學習了如何在 Keras 中實現強化學習算法。為了保持示例的簡單,我們使用了 Keras;您也可以使用 TensorFlow 實現相同的網絡和模型。我們只使用了單層 MLP,因為我們的示例游戲非常簡單,但對于復雜的示例,您最終可能會使用復雜的 CNN,RNN 或序列到序列模型。
我們還了解了 OpenAI Gym,這是一個框架,提供了一個模擬許多流行游戲的環境,以實現和實踐強化學習算法。我們談到了深層強化學習概念,我們鼓勵您探索專門寫有關強化學習的書籍,以深入學習理論和概念。
強化學習是一種先進的技術,你會發現它常用于解決復雜的問題。在下一章中,我們將學習另一系列先進的深度學習技術:生成對抗網絡。
- TensorFlow 1.x 深度學習秘籍
- 零、前言
- 一、TensorFlow 簡介
- 二、回歸
- 三、神經網絡:感知器
- 四、卷積神經網絡
- 五、高級卷積神經網絡
- 六、循環神經網絡
- 七、無監督學習
- 八、自編碼器
- 九、強化學習
- 十、移動計算
- 十一、生成模型和 CapsNet
- 十二、分布式 TensorFlow 和云深度學習
- 十三、AutoML 和學習如何學習(元學習)
- 十四、TensorFlow 處理單元
- 使用 TensorFlow 構建機器學習項目中文版
- 一、探索和轉換數據
- 二、聚類
- 三、線性回歸
- 四、邏輯回歸
- 五、簡單的前饋神經網絡
- 六、卷積神經網絡
- 七、循環神經網絡和 LSTM
- 八、深度神經網絡
- 九、大規模運行模型 -- GPU 和服務
- 十、庫安裝和其他提示
- TensorFlow 深度學習中文第二版
- 一、人工神經網絡
- 二、TensorFlow v1.6 的新功能是什么?
- 三、實現前饋神經網絡
- 四、CNN 實戰
- 五、使用 TensorFlow 實現自編碼器
- 六、RNN 和梯度消失或爆炸問題
- 七、TensorFlow GPU 配置
- 八、TFLearn
- 九、使用協同過濾的電影推薦
- 十、OpenAI Gym
- TensorFlow 深度學習實戰指南中文版
- 一、入門
- 二、深度神經網絡
- 三、卷積神經網絡
- 四、循環神經網絡介紹
- 五、總結
- 精通 TensorFlow 1.x
- 一、TensorFlow 101
- 二、TensorFlow 的高級庫
- 三、Keras 101
- 四、TensorFlow 中的經典機器學習
- 五、TensorFlow 和 Keras 中的神經網絡和 MLP
- 六、TensorFlow 和 Keras 中的 RNN
- 七、TensorFlow 和 Keras 中的用于時間序列數據的 RNN
- 八、TensorFlow 和 Keras 中的用于文本數據的 RNN
- 九、TensorFlow 和 Keras 中的 CNN
- 十、TensorFlow 和 Keras 中的自編碼器
- 十一、TF 服務:生產中的 TensorFlow 模型
- 十二、遷移學習和預訓練模型
- 十三、深度強化學習
- 十四、生成對抗網絡
- 十五、TensorFlow 集群的分布式模型
- 十六、移動和嵌入式平臺上的 TensorFlow 模型
- 十七、R 中的 TensorFlow 和 Keras
- 十八、調試 TensorFlow 模型
- 十九、張量處理單元
- TensorFlow 機器學習秘籍中文第二版
- 一、TensorFlow 入門
- 二、TensorFlow 的方式
- 三、線性回歸
- 四、支持向量機
- 五、最近鄰方法
- 六、神經網絡
- 七、自然語言處理
- 八、卷積神經網絡
- 九、循環神經網絡
- 十、將 TensorFlow 投入生產
- 十一、更多 TensorFlow
- 與 TensorFlow 的初次接觸
- 前言
- 1.?TensorFlow 基礎知識
- 2. TensorFlow 中的線性回歸
- 3. TensorFlow 中的聚類
- 4. TensorFlow 中的單層神經網絡
- 5. TensorFlow 中的多層神經網絡
- 6. 并行
- 后記
- TensorFlow 學習指南
- 一、基礎
- 二、線性模型
- 三、學習
- 四、分布式
- TensorFlow Rager 教程
- 一、如何使用 TensorFlow Eager 構建簡單的神經網絡
- 二、在 Eager 模式中使用指標
- 三、如何保存和恢復訓練模型
- 四、文本序列到 TFRecords
- 五、如何將原始圖片數據轉換為 TFRecords
- 六、如何使用 TensorFlow Eager 從 TFRecords 批量讀取數據
- 七、使用 TensorFlow Eager 構建用于情感識別的卷積神經網絡(CNN)
- 八、用于 TensorFlow Eager 序列分類的動態循壞神經網絡
- 九、用于 TensorFlow Eager 時間序列回歸的遞歸神經網絡
- TensorFlow 高效編程
- 圖嵌入綜述:問題,技術與應用
- 一、引言
- 三、圖嵌入的問題設定
- 四、圖嵌入技術
- 基于邊重構的優化問題
- 應用
- 基于深度學習的推薦系統:綜述和新視角
- 引言
- 基于深度學習的推薦:最先進的技術
- 基于卷積神經網絡的推薦
- 關于卷積神經網絡我們理解了什么
- 第1章概論
- 第2章多層網絡
- 2.1.4生成對抗網絡
- 2.2.1最近ConvNets演變中的關鍵架構
- 2.2.2走向ConvNet不變性
- 2.3時空卷積網絡
- 第3章了解ConvNets構建塊
- 3.2整改
- 3.3規范化
- 3.4匯集
- 第四章現狀
- 4.2打開問題
- 參考
- 機器學習超級復習筆記
- Python 遷移學習實用指南
- 零、前言
- 一、機器學習基礎
- 二、深度學習基礎
- 三、了解深度學習架構
- 四、遷移學習基礎
- 五、釋放遷移學習的力量
- 六、圖像識別與分類
- 七、文本文件分類
- 八、音頻事件識別與分類
- 九、DeepDream
- 十、自動圖像字幕生成器
- 十一、圖像著色
- 面向計算機視覺的深度學習
- 零、前言
- 一、入門
- 二、圖像分類
- 三、圖像檢索
- 四、對象檢測
- 五、語義分割
- 六、相似性學習
- 七、圖像字幕
- 八、生成模型
- 九、視頻分類
- 十、部署
- 深度學習快速參考
- 零、前言
- 一、深度學習的基礎
- 二、使用深度學習解決回歸問題
- 三、使用 TensorBoard 監控網絡訓練
- 四、使用深度學習解決二分類問題
- 五、使用 Keras 解決多分類問題
- 六、超參數優化
- 七、從頭開始訓練 CNN
- 八、將預訓練的 CNN 用于遷移學習
- 九、從頭開始訓練 RNN
- 十、使用詞嵌入從頭開始訓練 LSTM
- 十一、訓練 Seq2Seq 模型
- 十二、深度強化學習
- 十三、生成對抗網絡
- TensorFlow 2.0 快速入門指南
- 零、前言
- 第 1 部分:TensorFlow 2.00 Alpha 簡介
- 一、TensorFlow 2 簡介
- 二、Keras:TensorFlow 2 的高級 API
- 三、TensorFlow 2 和 ANN 技術
- 第 2 部分:TensorFlow 2.00 Alpha 中的監督和無監督學習
- 四、TensorFlow 2 和監督機器學習
- 五、TensorFlow 2 和無監督學習
- 第 3 部分:TensorFlow 2.00 Alpha 的神經網絡應用
- 六、使用 TensorFlow 2 識別圖像
- 七、TensorFlow 2 和神經風格遷移
- 八、TensorFlow 2 和循環神經網絡
- 九、TensorFlow 估計器和 TensorFlow HUB
- 十、從 tf1.12 轉換為 tf2
- TensorFlow 入門
- 零、前言
- 一、TensorFlow 基本概念
- 二、TensorFlow 數學運算
- 三、機器學習入門
- 四、神經網絡簡介
- 五、深度學習
- 六、TensorFlow GPU 編程和服務
- TensorFlow 卷積神經網絡實用指南
- 零、前言
- 一、TensorFlow 的設置和介紹
- 二、深度學習和卷積神經網絡
- 三、TensorFlow 中的圖像分類
- 四、目標檢測與分割
- 五、VGG,Inception,ResNet 和 MobileNets
- 六、自編碼器,變分自編碼器和生成對抗網絡
- 七、遷移學習
- 八、機器學習最佳實踐和故障排除
- 九、大規模訓練
- 十、參考文獻