強化學習之猜猜我是誰--- Deep Q-Network ^_^
Deep Q-Network和Q-Learning怎麽長得這麽像,難道它們有關系?
沒錯,Deep Q-Network其實是Q-Learning融合了神經網絡的一種方法
這次我們以打飛機的一個例子來講解Deep Q-Network,什麽打飛機?嘻嘻,我們接著看
簡要
Deep Q-Network簡稱DQN
神經網絡有什麽作用呢,在Q-Learning中我們使用Q表來記錄經驗的,通過神經網絡我們就不需要Q表了,當我們把狀態和動作輸入到神經網絡中時,經過神經網絡的分析等到action,在環境復雜的下我們的機器可能無法承受不住如此龐大的Q表把,所有就需要神經網絡這個好幫手了
是不是發現了相似之處,它其實只是在Q-Learning的基礎的加了一些小東西,
- 記憶庫 (用於重復學習)
- 神經網絡計算 Q 值
- 暫時凍結
q_target
參數 (切斷相關性)
DQN的核心部分就是記憶庫,它會記錄下所有經歷過的步驟,然後反復的進行學習
遊戲開始
首先我們先搭建環境,在gym的環境下我們創建一個打飛機的遊戲
env=gym.make(‘BeamRider-ram-v0‘)
重磅出擊了,接下來是我們的核心部分,DQN的實現
首先我們初始化DQN的參數
def __init__(self): self.ALPHA=0.001 self.GAMMA=0.95 self.ESPLION=1.0 self.ESPLION_DECAY=0.99 self.ESPLION_MIN=0.0001 self.action_size=env.action_space.n self.state_size=env.observation_space.shape[0] self.model=self._build_model() self.memory=deque(maxlen=5000)
童鞋們是不是發現多了兩個參數,model和memory,model就是我們的神經網絡模型,而memroy沒錯就是我們的記憶庫
我們創建一個簡單的神經網絡模型,不過這個神經網絡模型是空的,用於我們的演示,在這裏我用的是kears
def _build_model(self): model=Sequential() model.add(Dense(24, input_dim=self.state_size, activation=‘relu‘)) model.add(Dense(24,activation=‘relu‘)) model.add(Dense(self.action_size,activation=‘linear‘)) model.compile(loss=‘mse‘,optimizer=Adam(lr=self.ALPHA)) return model
經過神經網絡我們得到我們下一步的動作
def choose_action(self,obervation): if np.random.uniform()<self.ESPLION: return env.action_space.sample()
#經過神經網絡得到action action=self.model.predict(obervation) return np.argmax(action[0])
開始向記憶庫中添加我們的經歷
def update_memory(self,obervation,action,reward,obervation_,done): self.memory.append((obervation,action,reward,obervation_,done))
這次的訓練有所不同,我們是在記憶庫中獲取一些經驗然後進行學習
def learn(self): if len(self.memory)<batch_size: return minibach=random.sample(self.memory,batch_size) for state,action,reward,next_state,done in minibach: target=reward if not done: target=reward+self.GAMMA*np.amax(self.model.predict(next_state)[0]) target_f=self.model.predict(state) target_f[0][action]=target self.model.fit(state,target_f,epochs=1,verbose=0) if self.ESPLION>self.ESPLION_MIN: self.ESPLION*=self.ESPLION_DECAY
為了有一個以後有一個良好的分數,我們不僅要看眼前還要有長遠的眼光,這裏和Q-learning,Sarsa一樣,我在上方用紅色標記出來了
我們發現多了兩個參數,ESPLION_MIN,ESPLION_DACAY,這個是做什麽用的呢,為了讓我們的程序不在一直探索我們設置了這兩個參數,ESPLION_DECAY用來減少我們的ESPLION值,ESPLION_MIN用來規定我們最少探測的次數,當低於這個後我們遍不再進行DECAY
我們運行這個程序
剛開始時我們的戰鬥機一直陣亡, 漸漸的它學會了擊落敵方飛機
經過一段時間的戰鬥後,戰鬥機也就越來越厲害了
Double DQN
DQN還有很多變種,其中一種是Double DQN
因為Q-learning中存在Qmax,正是因為Qmax的存在而導致overestimate(過估計),如果DQN發現經過神經網絡輸出後Q值特被的大,這就是overestimate
這是原本的DQN中的Q實現
這是Double DQN中的Q實現
這樣我們用Q估計來的動作放在Q實現中來預測出我們要選擇的動作這樣來防止overestimate
所有在初始化參數時,我們再添加一個具有相同結構的神經網絡模型
在使用DQN時我們發現並不是很穩定,使用DDQN時則相對穩定些
game over
以下是所有的代碼,小夥伴們可以試一下
#coding:utf-8 from keras.models import Sequential from keras.layers import Dense from keras.optimizers import Adam from keras.utils import plot_model import numpy as np import gym import random from collections import deque from keras.callbacks import Callback import matplotlib.pyplot as plt batch_size=32 losses=[] class LossHistory(Callback): def on_batch_end(self, batch, logs=None): losses.append(logs.get(‘loss‘)) class Agent(object): def __init__(self): self.ALPHA=0.001 self.GAMMA=0.95 self.ESPLION=1.0 self.ESPLION_DECAY=0.99 self.ESPLION_MIN=0.001 self.action_size=env.action_space.n self.state_size=env.observation_space.shape[0] self.memory=deque(maxlen=5000) self.model=self._build_model() def _build_model(self): model=Sequential() model.add(Dense(24, input_dim=self.state_size, activation=‘relu‘)) model.add(Dense(24,activation=‘relu‘)) model.add(Dense(self.action_size,activation=‘linear‘)) model.compile(loss=‘mse‘,optimizer=Adam(lr=self.ALPHA)) return model def choose_action(self,obervation): if np.random.uniform()<self.ESPLION: return env.action_space.sample() action=self.model.predict(obervation) return np.argmax(action[0]) def update_memory(self,obervation,action,reward,obervation_,done): self.memory.append((obervation,action,reward,obervation_,done)) def plot_model(self): plot_model(self.model, to_file=‘./save_graph/model.png‘) class DDQNAgent(Agent): def __init__(self): super(DDQNAgent,self).__init__() self.target_model=self._build_model() self.update_target_model() def update_target_model(self): self.target_model.set_weights(self.model.get_weights()) def learn(self): if len(self.memory)<batch_size: return minibach=random.sample(self.memory,batch_size) for state,action,reward,next_state,done in minibach: target=self.model.predict(state) if done: target[0][action]=reward else: old_model=self.model.predict(next_state)[0] new_model=self.target_model.predict(next_state)[0] target[0][action]=reward+self.GAMMA*new_model[np.argmax(old_model)] self.model.fit(state,target,epochs=1,verbose=0) if self.ESPLION>self.ESPLION_MIN: self.ESPLION*=self.ESPLION_DECAY class DQNAgent(Agent): def learn(self): if len(self.memory)<batch_size: return minibach=random.sample(self.memory,batch_size) for state,action,reward,next_state,done in minibach: target=reward if not done: target=reward+self.GAMMA*np.amax(self.model.predict(next_state)[0]) target_f=self.model.predict(state) target_f[0][action]=target self.model.fit(state,target_f,epochs=1,verbose=0) if self.ESPLION>self.ESPLION_MIN: self.ESPLION*=self.ESPLION_DECAY history_loss=LossHistory() env=gym.make(‘BeamRider-ram-v0‘) # agent=DQNAgent() agent=DDQNAgent() totcal=0 for e in range(50001): obervation=env.reset() obervation=np.reshape(obervation,[1,agent.state_size]) done=False index=0 while not done: # env.render() action=agent.choose_action(obervation) obervation_,reward,done,info=env.step(action) obervation_= np.reshape(obervation_, [1, agent.state_size]) reward=-10 if done else reward agent.update_memory(obervation,action,reward,obervation_,done) obervation=obervation_ index+=1 totcal+=reward if done: agent.update_target_model() # if len(losses)!=0: # plt.plot(range(len(losses)),losses) # plt.savefig(‘./save_graph/loss.png‘) if e%50==0: agent.model.save(‘./AirRaid_model.h5‘) agent.learn() agent.plot_model() print ‘esp {},reward {} espilon {}‘.format(e,totcal/index,agent.ESPLION)
本篇文章意在帶領小夥伴們進入強化學習的殿堂 ^_^
強化學習之猜猜我是誰--- Deep Q-Network ^_^