Gym中MountainCar-v0小車上山的DDQN算法學習

此程序使用的是DDQN算法和DuelingDQN模型凡恍,在小車上山環(huán)境中的實現(xiàn)。

DQN算法族適用于動作空間有限的離散非連續(xù)狀態(tài)環(huán)境伍伤,但因為狀態(tài)無限多所以難以通過有限的回合對Q(s,a)進行估值和訓練收斂抛杨。DQN算法族將Q-learning和神經(jīng)網(wǎng)絡結合,通過神經(jīng)網(wǎng)絡來構造函數(shù)鄙币,實現(xiàn)對Q(s,a)的估值肃叶,此時Q(s,a)不再是通過查表計算,而是通過把狀態(tài)參量代入函數(shù)計算十嘿,所以解決了無限多狀態(tài)無法訓練的問題因惭。

程序缺點:暫未實現(xiàn)可視化。

初始化

import torch
from torch import nn
import numpy as np
import pandas as pd
import gym
import collections
#使用cuda加速訓練
device = 'cuda' if torch.cuda.is_available() else 'cpu'

經(jīng)驗回放

標準Q-learning訓練時沒有打破序列相關性详幽,可能會導致估值存在偏頗,影響收斂。DQN算法族使用經(jīng)驗回放來解決這個問題唇聘。

class DQNReplayer:
    def __init__(self, capacity):
        self.memory = pd.DataFrame(index=range(capacity),
                columns=['observation', 'action', 'reward',
                'next_observation', 'done'])
        self.i = 0
        self.count = 0
        self.capacity = capacity
    
    def store(self, *args):
        self.memory.loc[self.i] = args
        self.i = (self.i + 1) % self.capacity
        self.count = min(self.count + 1, self.capacity)
        
    def sample(self, size):
        indices = np.random.choice(self.count, size=size)
        return (np.stack(self.memory.loc[indices, field]) for field in
                self.memory.columns)

Dueling Net模型

與普通網(wǎng)絡模型在訓練過程中無異版姑,不必深究

class DuelingNet(nn.Module):
    def __init__(self, layers, num_actions):
        super(DuelingNet, self).__init__()
        self.layers = layers
        self.num_actions=num_actions
        self.features = nn.Sequential(
            nn.Linear(self.layers, 64, bias=True),
            nn.ReLU(),
        )
        self.adv = nn.Linear(64, self.num_actions, bias=True)
        self.val = nn.Linear(64, 1, bias=True)

    def forward(self, x):
        x = self.features(x)
        adv = self.adv(x)
        val = self.val(x).expand(adv.size()) #擴展某個size為1的維度,值一樣  (1迟郎,6)
        x = val + adv -adv.mean().expand(adv.size())
        return x

訓練agent

class agent():
    #設置超參數(shù)
    def __init__(self,env=gym.make('MountainCar-v0'),layers=2,capacity=500,LR=0.001,gamma=0.9,epsilon=0.05):
        self.env=env
        self.layers=layers
        self.min=env.unwrapped.min_position
        self.max=env.unwrapped.max_position
        self.action_num=env.action_space.n
        self.net1=DuelingNet(self.layers,self.action_num).to(device)
        self.net2=DuelingNet(self.layers,self.action_num).to(device)
        self.optimizer1 = torch.optim.Adam(self.net1.parameters(), lr=LR)
        self.loss_func = nn.MSELoss()
        self.replayer=DQNReplayer(capacity)
        self.lr=LR
        self.gamma=gamma
        self.epsilon=epsilon

    #選擇動作   
    def action(self,state,israndom):
        state_=torch.Tensor(state).to(device)
        if israndom and np.random.random() < self.epsilon:
            return np.random.randint(0, self.action_num)
        return torch.max(torch.from_numpy(self.net1.forward(state_).cpu().detach().numpy()).to(device), 0)[1].item()

    #訓練網(wǎng)絡
    def learn(self,state,action,reward,next_state,done):
        if done:
            self.replayer.store(state,action,reward,next_state,0)
        else:
            self.replayer.store(state,action,reward,next_state,1)
        if self.replayer.count<self.replayer.capacity:
            return None
        
        batch = list(self.replayer.sample(10))
        state = torch.FloatTensor(batch[0]).to(device)
        action = torch.LongTensor(batch[1]).unsqueeze(1).to(device)
        reward = torch.FloatTensor(batch[2]).unsqueeze(1).to(device)
        next_state = torch.FloatTensor(batch[3]).to(device)
        done = torch.FloatTensor(batch[4]).unsqueeze(1).to(device)

        a = self.net1.forward(next_state).max(dim=1)[1].view(-1,1)
        u = reward + self.gamma * self.net2.forward(next_state).gather(1,a) * done
        loss = self.loss_func(self.net1.forward(state).gather(1,action),u)
        self.optimizer1.zero_grad()
        loss.backward()
        self.optimizer1.step()

    #儲存模型參數(shù)
    def save_models(self,episode):
        torch.save(self.net1.state_dict(), './net/double_dqn.pkl')
        torch.save(self.net2.state_dict(), './net/double_dqn_target.pkl')
        print('=====================')
        print('%d episode model has been save...' %(episode))

開始訓練

agent = agent()
best_reward = 0
mean_test = collections.deque(maxlen=10)
for i_episode in range(2000):
    state = agent.env.reset()
    total_reward = 0
    treward = 0
    step_num=0

    #每十個回合統(tǒng)一兩個網(wǎng)絡的參數(shù)
    if i_episode%10==0:
        agent.net2.load_state_dict(agent.net1.state_dict())

    while True:
#        agent.env.render()
        action = agent.action(state, True)
        next_state, reward, done, info = agent.env.step(action)
        reward_real = reward#環(huán)境真實獎勵

    #獎勵函數(shù)(非常重要剥险,影響收斂結果和收斂速度)
        if next_state[0]>-0.4 and next_state[0]<0.5:
            reward=10*(next_state[0]+0.4)**3
        elif next_state[0]>=0.5:
            reward=100
        elif next_state[0]<=-0.4:
            reward=-0.1

        treward+=reward#獎勵函數(shù)獎勵
        agent.learn(state, action, reward, next_state, done)
        state=next_state
        total_reward += reward_real
        step_num += 1
        if done or step_num>=200:
            break
    print('episode: {} , total_reward: {} , treward: {}'.format(i_episode, round(total_reward, 3), round(treward, 3)))

    # TEST
    if i_episode % 10 == 0:
        state = agent.env.reset()
        test_reward = 0
        while True:
#            agent.env.render()
            action = agent.action(state, israndom=False)
            next_state, reward, done, info = agent.env.step(action)
            test_reward += reward
            state = next_state
            if done:
                agent.env.close()
                break
        print('episode: {} , test_reward: {}'.format(i_episode, round(test_reward, 3)))
        mean_test.append(test_reward)
        if np.mean(mean_test)>best_reward:
            best_reward = np.mean(mean_test)
            agent.save_models(i_episode)
最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市宪肖,隨后出現(xiàn)的幾起案子表制,更是在濱河造成了極大的恐慌,老刑警劉巖控乾,帶你破解...
    沈念sama閱讀 217,734評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件么介,死亡現(xiàn)場離奇詭異,居然都是意外死亡蜕衡,警方通過查閱死者的電腦和手機壤短,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,931評論 3 394
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來慨仿,“玉大人久脯,你說我怎么就攤上這事×海” “怎么了帘撰?”我有些...
    開封第一講書人閱讀 164,133評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長万皿。 經(jīng)常有香客問我摧找,道長,這世上最難降的妖魔是什么相寇? 我笑而不...
    開封第一講書人閱讀 58,532評論 1 293
  • 正文 為了忘掉前任慰于,我火速辦了婚禮,結果婚禮上唤衫,老公的妹妹穿的比我還像新娘婆赠。我一直安慰自己,他們只是感情好佳励,可當我...
    茶點故事閱讀 67,585評論 6 392
  • 文/花漫 我一把揭開白布休里。 她就那樣靜靜地躺著,像睡著了一般赃承。 火紅的嫁衣襯著肌膚如雪妙黍。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,462評論 1 302
  • 那天瞧剖,我揣著相機與錄音拭嫁,去河邊找鬼可免。 笑死,一個胖子當著我的面吹牛做粤,可吹牛的內(nèi)容都是我干的浇借。 我是一名探鬼主播,決...
    沈念sama閱讀 40,262評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼怕品,長吁一口氣:“原來是場噩夢啊……” “哼妇垢!你這毒婦竟也來了?” 一聲冷哼從身側響起肉康,我...
    開封第一講書人閱讀 39,153評論 0 276
  • 序言:老撾萬榮一對情侶失蹤闯估,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后吼和,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體涨薪,經(jīng)...
    沈念sama閱讀 45,587評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,792評論 3 336
  • 正文 我和宋清朗相戀三年纹安,在試婚紗的時候發(fā)現(xiàn)自己被綠了尤辱。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,919評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡厢岂,死狀恐怖光督,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情塔粒,我是刑警寧澤结借,帶...
    沈念sama閱讀 35,635評論 5 345
  • 正文 年R本政府宣布,位于F島的核電站卒茬,受9級特大地震影響船老,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜圃酵,卻給世界環(huán)境...
    茶點故事閱讀 41,237評論 3 329
  • 文/蒙蒙 一柳畔、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧郭赐,春花似錦薪韩、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,855評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至观谦,卻和暖如春拉盾,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背豁状。 一陣腳步聲響...
    開封第一講書人閱讀 32,983評論 1 269
  • 我被黑心中介騙來泰國打工捉偏, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留倒得,地道東北人。 一個月前我還...
    沈念sama閱讀 48,048評論 3 370
  • 正文 我出身青樓夭禽,卻偏偏與公主長得像屎暇,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子驻粟,可洞房花燭夜當晚...
    茶點故事閱讀 44,864評論 2 354

推薦閱讀更多精彩內(nèi)容