亚洲天堂网_国产中出_日韩激情网_97se.com_中国亚洲老少妇色视频

資源共享分類
通信信號 圖像語音 神經(jīng)網(wǎng)絡(luò) 智能優(yōu)化 控制器 數(shù)值仿真 數(shù)學(xué)建模 其他專業(yè)

微信:HuangL1121
Q Q:1224848052
團隊:嘉興麥特萊博軟件開發(fā)工作室
地址:嘉興港區(qū)
 
神經(jīng)網(wǎng)絡(luò)
MATLAB代做|python代做--深度增強學(xué)習(xí)PPO(Proximal Policy Optimization)算法
來源:本站    日期:2019/4/22    瀏覽量:830  

功能描述:

     OpenAI出品的baselines項目提供了一系列deep reinforcement learning(DRL,深度強化學(xué)習(xí)或深度增強學(xué)習(xí))算法的實現(xiàn)。現(xiàn)在已經(jīng)有包括DQN,DDPG,TRPO,A2C,ACER,PPO在內(nèi)的近十種經(jīng)典算法實現(xiàn),同時它也在不斷擴充中。它為對DRL算法的復(fù)現(xiàn)驗證和修改實驗提供了很大的便利。本文主要走讀其中的PPO(Proximal Policy Optimization)算法的源碼實現(xiàn)。PPO是2017年由OpenAI提出的一種DRL算法,它不僅有很好的performance(尤其是對于連續(xù)控制問題),同時相較于之前的TRPO方法更加易于實現(xiàn)。之前寫過一篇雜文《深度增強學(xué)習(xí)(DRL)漫談 - 信賴域(Trust Region)系方法》對其歷史、原理及相關(guān)方法做了簡單介紹,因此本文主要focus在代碼實現(xiàn)的學(xué)習(xí)了解上。
      OpenAI baselines項目中對于PPO算法有兩個實現(xiàn),分別位于ppo1和ppo2目錄下。其中ppo2是利用GPU加速的,官方號稱會快三倍左右,所以下面主要是看ppo2。對應(yīng)論文為《Proximal Policy Optimization Algorithms》,以下簡稱PPO論文。本文我們就以atari這個經(jīng)典的DRL實驗場景為例看一下大體流程。啟動訓(xùn)練的命令在readme中有:
def main():
# 實現(xiàn)位于common/cmd_util.py。它主要為parser添加幾個參數(shù):
#   1) env:代表要執(zhí)行atari中的哪個游戲環(huán)境。默認(rèn)為BreakoutNoFrameskip-v4,即“打磚塊”。
#   2) seed:隨機種子。默認(rèn)為0。
#   3) num-timesteps:訓(xùn)練的頻數(shù)。默認(rèn)為10M次。
     parser = atari_arg_parser()
# 通過參數(shù)選擇policy network的形式,實現(xiàn)在policies.py。默認(rèn)為CNN。這里有三種選擇:
#   1) CNN:相應(yīng)函數(shù)為CnnPolicy()。發(fā)表于《Nature》上的經(jīng)典DRL奠基論文《Human-level control through
#       deep reinforcement learning》中使用的神經(jīng)網(wǎng)絡(luò)結(jié)構(gòu):conv->relu->conv->relu->conv->relu->
#       fc->relu。注意它是雙頭網(wǎng)絡(luò),一頭輸出policy,一頭輸出value。
#   2) LSTM:相應(yīng)函數(shù)為LstmPolicy()。它將CNN的輸出之上再加上LSTM層,這樣就結(jié)合了時間域的信息。
#   3) LnLSTM:相應(yīng)函數(shù)為LnLstmPolicy()。其它的和上面一樣,只是在構(gòu)造LSTM層時添加了Layer normalization
#       (詳見論文《Layer Normalization》)
     parser.add_argument('--policy', help='Policy architecture', choices=['cnn', 'lstm', 'lnlstm'], default='cnn')
# 用剛才的構(gòu)建的parser解析命令行傳入的參數(shù)。
     args = parser.parse_args()
# 這個項目中實現(xiàn)了簡單的日志系統(tǒng)。其中日志所在目錄和格式可以用過OPENAI_LOGDIR和OPENAI_LOG_FORMAT兩個環(huán)境
# 變量控制。實現(xiàn)類Logger中主要有兩個字典:name2val和name2cnt。它們分別是名稱到值和計數(shù)的映射。
     logger.configure()
# 這里是開始正式訓(xùn)練了。
     train(args.env, num_timesteps=args.num_timesteps, seed=args.seed,
         policy=args.policy)
--------------------- 
def train(env_id, num_timesteps, seed, policy):
     # 首先是一坨和TensorFlow相關(guān)的環(huán)境設(shè)置,比如根據(jù)cpu核數(shù)設(shè)定并行線程數(shù)等。
     ...
     # 構(gòu)建運行環(huán)境。流程還比較長,下面會再詳細(xì)地理下。
     env = VecFrameStack(make_atari_env(env_id, 8, seed), 4)
     # 對應(yīng)前面說的三種策略網(wǎng)絡(luò)。用于根據(jù)參數(shù)選取相應(yīng)的實現(xiàn)函數(shù)。
     policy = {'cnn' : CnnPolicy, 'lstm' : LstmPolicy, 'lnlstm' : LnLstmPolicy}[policy]
     # 使用PPO算法進行學(xué)習(xí)。其中傳入的參數(shù)不少是模型的超參數(shù)。詳細(xì)可參見PPO論文中的Table 5。
     ppo2.learn(policy=policy, env=env, nsteps=128, nminibatches=4,
         lam=0.95, gamma=0.99, noptepochs=4, log_interval=1,
         ent_coef=.01,
         lr=lambda f : f * 2.5e-4,
         cliprange=lambda f : f * 0.1,
         total_timesteps=int(num_timesteps * 1.1))
--------------------- 
# make_atari_env()函數(shù)實現(xiàn)位于common/cmd_util.py。看函數(shù)名就知道主要就是創(chuàng)建atari環(huán)境。通過OpenAI gym
# 創(chuàng)建基本的atari環(huán)境后,還需要層層封裝。gym中提供了Wrapper接口,讓開發(fā)者通過decorator設(shè)計模式來改變環(huán)境中的設(shè)# 定。
def make_atari_env(env_id, num_env, ...):  # 這里的num_env為8,意味著會創(chuàng)建8個獨立的并行運行環(huán)境。
    def make_env(rank):
        def _thunk():
            # 創(chuàng)建由gym構(gòu)建的atari環(huán)境的封裝類。
            env = make_atari(env_id):       
                # 通過OpenAI的gym接口創(chuàng)建gym環(huán)境。
                env = gym.make(env_id)  
                # NoopResetEnv為gym.Wrapper的繼承類。每次環(huán)境重置(調(diào)用reset())時執(zhí)行指定步隨機動作。
                env = NoopResetEnv(env) 
                # MaxAndSkipEnd也是gym.Wrapper的繼承類。每隔4幀返回一次。返回中的reward為這4幀reward
                # 之和,observation為最近兩幀中最大值。
                env = MaxAndSkipEnd(env)    
                return env
            # 每個環(huán)境選取不同的隨機種子,避免不同環(huán)境跑得都一樣。
            env.seed(seed + rank)       
            # 實現(xiàn)在monitor.py中。Monitor為gym中Wrapper的繼承類,對環(huán)境Env進行封裝,主要添加了對
            # episode結(jié)束時信息的記錄。
            env = Monitor(env, ...)     
            return wrap_deepmind(env, ...):
                # 標(biāo)準(zhǔn)情況下,對于atari中的很多游戲(比如這兒的打磚塊),命掉光了(如該游戲有5條命)算episode
                # 結(jié)束,環(huán)境重置。這個Wrapper的作用是只要掉命就讓step()返回done,但保持環(huán)境重置的時機不變
                #(仍然是命掉完時)。原注釋中說這個trick在DeepMind的DQN中用來幫助value的估計。
                env = EpisodeicLifeEnv(env)     
                # 通過OpenCV將原始輸入轉(zhuǎn)成灰度圖,且轉(zhuǎn)成84 x 84的分辨率。
                env = WarpFrame(env)        
                # 將reward按正負(fù)值轉(zhuǎn)為+1, -1和0。
                env = ClipRewardEnv(env)    
                ...
                return env
        return _thunk   
    ...
    # 返回SubprocVecEnv對象。
    return SubprocVecEnv([make_env(i + start_index) for i in range(num_env)]) 
--------------------- 
創(chuàng)建num_env個元素(這里為8)的數(shù)組,每一個元素為一個函數(shù)閉包_thunk()。VecEnv實現(xiàn)在baselines/common/vec_env/__init__.py,它是一個抽象類,代表異步向量化環(huán)境。其中包括幾個重要的抽象函數(shù): 
reset()用于重置所有環(huán)境,step_async()用于通知所有環(huán)境開始根據(jù)給定動作執(zhí)行一步,step_wait()得到執(zhí)行完的結(jié)果。step_wait()等待step_async()的結(jié)果。step()就是step_async() 加上step_wait()。而VecEnvWrapper也為VecEnv的繼承類,和gym中提供的Wrapper功能類似,如果要對VecEnv實現(xiàn)的默認(rèn)行為做修改的話就可以利用它。

上面函數(shù)最后返回的SubprocVecEnv類為VecEnv的繼承類,它主要將上面創(chuàng)建好的函數(shù)放到各個子進程中去執(zhí)行。在SubprocVecEnv實現(xiàn)類中,構(gòu)造時傳入在子進程中執(zhí)行的函數(shù)。通過Process創(chuàng)建子進程,并通過Pipe進行進程間通信。make_atari_env()中創(chuàng)建SubprocVecEnv后,又立馬被VecFrameStack封裝了一把。VecFrameStack為VecEnvWrapper的實現(xiàn)類,實現(xiàn)在vec_frame_stack.py。在VecFrameStack的構(gòu)造函數(shù)中,wos為gym環(huán)境中的原始狀態(tài)空間,維度為[84,84,1]。low和high分別為這些維度的最低和最高值。stackedobs就是把幾個環(huán)境的狀態(tài)空間疊加起來,即維度變?yōu)?8, 84, 84, 4)。8為環(huán)境個數(shù),(84,84)為單幀狀態(tài)維度,也就是游戲的屏幕輸出,4代表最近4幀(因為會用最近4的幀的游戲畫面來作為網(wǎng)絡(luò)模型的輸入)。

可以看到,除了正常的封裝外,還需要做一些比較tricky,比較靠經(jīng)驗的處理。理論上我們希望這部分越少越好,因為越少算法就越通用。然而現(xiàn)狀是這一塊tuning對結(jié)果的好壞可能產(chǎn)生比較大的影響。。。

好了,接下去就可以看看PPO算法主體了。入口為ppo2.py的learn()函數(shù)。
--------------------- 
class Model(object):
    def __init__(self, *, policy, ob_space, ac_space, nbatch_act, nbatch_train,
                 nsteps, ent_coef, vf_coef, max_grad_norm):
        # 用前面指定的網(wǎng)絡(luò)類型構(gòu)造兩個策略網(wǎng)絡(luò)。act_model用于執(zhí)行策略網(wǎng)絡(luò)根據(jù)當(dāng)前observation返回
        # action和value等,即只做inference。train_model顧名思義主要用于參數(shù)的更新(模型的學(xué)習(xí))。
        # 注意這兩個網(wǎng)絡(luò)的參數(shù)是共享的,因此train_model更新的參數(shù)可以體現(xiàn)在act_model上。假設(shè)使用默
        # 認(rèn)的CnnPolicy,其中的step()函數(shù)計算action, value function和action提供的信息量;
        # value()函數(shù)計算value。

        # nbatch_act = 8,就等于環(huán)境個數(shù)nenvs。因為每一次都分別對8個環(huán)境執(zhí)行,得到每個環(huán)境中actor的動作。
        # 1為nsteps。其實在CNN中沒啥用,在LSTM才會用到(因為LSTM會考慮前nsteps步作為輸入)。
        act_model = policy(sess, ob_space, ac_space, nbatch_act, 1, reuse=False)    
            h = nature_cnn(X)       # 如前面所說,《Nature》上的網(wǎng)絡(luò)結(jié)構(gòu)打底。然后輸出policy和value。
            pi = fc(h, 'pi', ...)   # for policy
            vf = fc(h, 'v')         # for value function
            # 根據(jù)action space創(chuàng)建相應(yīng)的參數(shù)化分布。如這里action space是Discrete(4),那分布
            # 就是CategoricalPdType()。然后根據(jù)該分布類型,結(jié)合網(wǎng)絡(luò)輸出(pi),得到動作概率分
            # 布CategoricalPd,最后在該分布上采樣,得到動作a0。neglogp0即為該動作的自信息量。
            pdtype = make_pdtype() 
            pd = self.pdtype.pdfromflat(pi) 
            a0 = self.pd.sample()
            neglogp0 = self.pd.neglogp(a0)
        # 和構(gòu)建action model類似,構(gòu)建用于訓(xùn)練的網(wǎng)絡(luò)train_model。nbatch_train為256,因為是用于模型的學(xué)習(xí),
        # 因此和act_model不同,這兒網(wǎng)絡(luò)輸入的batch size為256。
        train_model = policy(sess, ob_space, ac_space, nbatch_train, nsteps, reuse=True)    
        # 創(chuàng)建一坨placeholder,這些是后面要傳入的。
        A = train_model.pdtype.sample_placeholder([None])  # action
        ADV = tf.placeholder(tf.float32, [None])           # advantage
        R = tf.placeholder(tf.float32, [None])             # return
        OLDNEGLOGPAC = tf.placeholder(tf.float32, [None])  # old -log(action)
        OLDVPRED = tf.placeholder(tf.float32, [None])      # old value prediction
        LR = tf.placeholder(tf.float32, [])                # learning rate
        CLIPRANGE = tf.placeholder(tf.float32, [])         # clip range,就是論文中的epsilon。

        neglogpac = train_model.pd.neglogp(A)              # -log(action)
        entropy = tf.reduce_mean(train_model.pd.entropy())

        # 訓(xùn)練模型提供的value預(yù)測。
        vpred = train_model.vf  
        # 和vpred類似,只是與上次的vpred相比變動被clip在由CLIPRANGE指定的區(qū)間中。
        vpredclipped = OLDVPRED + tf.clip_by_value(train_model.vf - OLDVPRED, - CLIPRANGE, CLIPRANGE)    
        vf_losses1 = tf.square(vpred - R)
        vf_losses2 = tf.square(vpredclipped - R)
        # V loss為兩部分取大值:第一部分是網(wǎng)絡(luò)預(yù)測value值和R的差平方;第二部分是被clip過的預(yù)測value值
        # 和return的差平方。這部分和論文中似乎不太一樣。主要目的應(yīng)該是懲罰value值的過大更新。
        vf_loss = .5 * tf.reduce_mean(tf.maximum(vf_losses1, vf_losses2))
        # 論文中的probability ratio。把這里的exp和log展開就是論文中的形式。
        ratio = tf.exp(OLDNEGLOGPAC - neglogpac)    
        pg_losses = -ADV * ratio
        pg_losses2 = -ADV * tf.clip_by_value(ratio, 1.0 - CLIPRANGE, 1.0 + CLIPRANGE)
        # 論文公式(7),由于前面都有負(fù)號,這里是取maximum.
        pg_loss = tf.reduce_mean(tf.maximum(pg_losses, pg_losses2)) 
        approxkl = .5 * tf.reduce_mean(tf.square(neglogpac - OLDNEGLOGPAC))
        clipfrac = tf.reduce_mean(tf.to_float(tf.greater(tf.abs(ratio - 1.0), CLIPRANGE)))
        # 論文公式(9),ent_coef, vf_coef分別為PPO論文中的c1, c2,這里分別設(shè)為0.01和0.5。entropy為文中的S;pg_loss為文中的L^{CLIP}
        loss = pg_loss - entropy * ent_coef + vf_loss * vf_coef     

        # 構(gòu)建trainer,用于參數(shù)優(yōu)化。
        grads = tf.gradients(loss, params)
        trainer = tf.train.AdamOptimizer(learning_rate=LR, max_grad_norm)
        _train = trainer.apply_gradients()
--------------------- 
# Runnder是整個訓(xùn)練過程的協(xié)調(diào)者。
runner = Runner(env=env, model=model, nsteps=nsteps,...)
# total_timesteps = 11000000, nbatch = 1024,因此模型參數(shù)更新nupdates = 10742次。
nupdates = total_timesteps // nbatch
for update in range(1, nupdates+1) # 對應(yīng)論文中Algorithm的外循環(huán)。
    obs, returns, masks, actions, values, ... = runner.run()
        # 模型(上面的act_model)執(zhí)行nsteps步。有8個環(huán)境,即共1024步。該循環(huán)對應(yīng)論文中Algorithm的第2,3行。
        for _ in range(self.nsteps): 
            # 執(zhí)行模型,通過策略網(wǎng)絡(luò)返回動作。
            actions, values, self.states, ... = self.model.step(self.obs, self.status, ...)
            # 通過之前創(chuàng)建的環(huán)境執(zhí)行動作,得到observation和reward等信息。
            self.obs[:], rewards, self.dones, infos = self.env.step(actions)
        # 上面環(huán)境執(zhí)行返回的observation, action, values等信息都加入mb_xxx中存起來,后面要拿來學(xué)習(xí)參數(shù)用。
        mb_obs = np.asarray(mb_obs, dtype=self.obs.dtype) 
        mb_rewards = np.asarray(mb_rewards, dtype=np.float32) 
        mb_actions = np.asarray(mb_actions) 
        ...
        # 估計Advantage。對應(yīng)化文中Algorithm的第4行。
        for t in reversed(range(self.nsteps)):
            # 論文中公式(12)。
            delta = mb_rewards[t] + self.gamma * nextvalues * nextnonterminal - mb_values[t]  
            # 論文中公式(11)。
            mb_advs[t] = lastgaelam = delta + self.gamma * self.lam * nextnonterminal * lastgaelam 
        mb_returns = mb_advs + mb_values # Return = Advantage + Value
        return (*map(sf01, (mb_obs, mb_returns, mb_dones, mb_actions, mb_values, mb_neglogpacs)), mb_states, epinfos)
    epinfobuf.extend(epinfos) # Gym中返回的info。
    # 論文中Algorithm 1第6行。
    if states is None: # nonrecurrent version
        inds = np.arange(nbatch)   
        for _ in range(noptepochs): # epoch為4
            np.random.shuffle(inds)
            # 8個actor,每個運行128步,因此單個batch為1024步。1024步又分為4個minibatch,
            # 因此單次訓(xùn)練的batch size為256(nbatch_train)。
            for start in range(0, nbatch, nbatch_train): # [0, 256, 512, 768]
                end = start + nbatch_train
                mbinds = inds[start:end]
                slices = (arr[mbinds] for arr in (obs, ...))
                # 將前面得到的batch訓(xùn)練數(shù)據(jù)作為參數(shù),調(diào)用模型的train()函數(shù)進行參數(shù)學(xué)習(xí)。
                mblossvals.append(model.train(lrnow, cliprangenow, *slices)) 
                    # Advantage = Return - Value
                    advs = returns - values 
                    # Normalization
                    advs = (advs - advs.mean()) / (advs.std() + 1e-8) 
                    # cliprange是隨著更新的步數(shù)遞減的。因為一般來說訓(xùn)練越到后面越收斂,每一步的差異也會越來越小。 
                    # neglogpacs和values都是nbatch_train維向量,即shape為(256, )。
                    td_map = {train_mode.X:obs, A:actions, ADV:advs, R:returns, LR:lr, 
                        CLIPRANGE:cliprange, OLDNEGLOGPAC:neglogpacs, OLDVPRED:values}
                    return sess.run([pg_loss, vf_loss, entropy, approxkl, clipfrac, _train], td_map)
    else:
        ...
    # 每過指定間隔打印以下參數(shù)。
    if update % log_interval == 0 or update == 1:
        ev = explained_variance(values, returns)
        logger.logkv("serial_timesteps", update*nsteps)
        logger.logkv("nupdates", update)
        ...
    # 滿足條件時保存模型。
    if save_interval and (update % save_interval == 0 or update == 1) and logger.get_dir():
        ...
        model.save(savepath)
env.close()
--------------------- 
import gym
from gym import spaces
import multiprocessing
import joblib
import sys
import os
import numpy as np
import tensorflow as tf

from baselines.ppo2 import ppo2
from baselines.common.cmd_util import make_atari_env, atari_arg_parser
from baselines.common.atari_wrappers import make_atari, wrap_deepmind
from baselines.ppo2.policies import CnnPolicy
from baselines.common.vec_env.vec_frame_stack import VecFrameStack

def main(argv):
    ncpu = multiprocessing.cpu_count()
    config = tf.ConfigProto(allow_soft_placement=True,
                            intra_op_parallelism_threads=ncpu,
                            inter_op_parallelism_threads=ncpu)
    config.gpu_options.allow_growth = True
    sess = tf.Session(config=config)

    env_id = "BreakoutNoFrameskip-v4"
    seed = 0
    nenvs = 1
    nstack = 4

    env = wrap_deepmind(make_atari(env_id))
    ob_space = env.observation_space
    ac_space = env.action_space

    wos = env.observation_space
    low = np.repeat(wos.low, nstack, axis=-1)
    high = np.repeat(wos.high, nstack, axis=-1)
    stackedobs = np.zeros((nenvs,)+low.shape, low.dtype)
    observation_space = spaces.Box(low=low, high=high, dtype=env.observation_space.dtype)
    vec_ob_space = observation_space

    act_model = CnnPolicy(sess, vec_ob_space, ac_space, nenvs, 1, reuse=False)

    with tf.variable_scope('model'):
        params = tf.trainable_variables()

    #load_path = '/tmp/openai-2018-05-27-15-06-16-102537/checkpoints/00030'
    load_path = argv[0]
    loaded_params = joblib.load(load_path)
    restores = []
    for p, loaded_p in zip(params, loaded_params):
        restores.append(p.assign(loaded_p))
    sess.run(restores)
    print("model " + load_path + " loaded")

    obs = env.reset()
    done = False
    for _ in range(1000):
        env.render()
        obs = np.expand_dims(obs, axis=0)

        stackedobs = np.roll(stackedobs, shift=-1, axis=-1)
        stackedobs[..., -obs.shape[-1]:] = obs

        actions, values, states, neglogpacs = act_model.step(stackedobs)
        print("%d, action=%d" % (_, actions[0]))
        obs, reward, done, info = env.step(actions[0])
        if done:
            print("done")
            obs = env.reset()
            stackedobs.fill(0)

    sess.close()

if __name__ == '__main__':
    if (len(sys.argv)) != 2:
        sys.exit("Usage: %s ckpt_path" % sys.argv[0])
    if not os.path.exists(sys.argv[1]):
        sys.exit("ckpt file %s not found" % sys.argv[1])
    main(sys.argv[1:])
--------------------- 

聯(lián)系:highspeedlogic

QQ :1224848052

微信:HuangL1121

郵箱:1224848052@qq.com

網(wǎng)站:http://www.mat7lab.com/

網(wǎng)站:http://www.hslogic.com/

微信掃一掃:






   上一篇: MATLAB代做|FPGA代做|R-CNN論文解讀    下一篇:    
   相關(guān)閱讀
· MATLAB代做|FPGA代做|simulink代做—— 2020/7/14
· MATLAB代做|FPGA代做|simulink代做—— 2020/5/30
· MATLAB代做|FPGA代做|simulink代做—— 2020/5/30
· MATLAB代做|FPGA代做|simulink代做—— 2020/2/1
· MATLAB代做|FPGA代做|simulink代做—— 2019/12/11
· MATLAB代做|FPGA代做|simulink代做—— 2019/12/11
· MATLAB代做|FPGA代做|simulink代做—— 2019/12/11
· Alexnet網(wǎng)絡(luò)結(jié)構(gòu) 2019/11/20
· MATLAB代做|FPGA代做|simulink代做—— 2019/9/15
· MATLAB代做|FPGA代做|simulink代做—— 2019/8/29
Copyright 2017-2025 © 嘉興麥特萊博軟件開發(fā)工作室
  • 網(wǎng)站備案號:浙ICP備18008591號-1