【論文閱讀】Learning to drive from a world on rails


引用與參考

代碼地址:https://github.com/dotchen/WorldOnRails

論文地址:https://arxiv.org/abs/2105.00636

論文部分

  • [x] 已看完 寫在ipad上了 正在進行中

摘要划重點:

  1. 視覺 只有視覺 → 所以關於加入激光點雲的想法還是可以繼續
  2. 行駛數據建立在model-based 使用車輛本身自行車模型 →
  3. world on rails的意思是:環境並不會隨agent的行為而改變(很符合... Carla里的仿真了,車輛不會和你交互 只會按照自己的行程走 特別是在leaderboard測試的)
    但是這一點在現實中,並不適用,現實中有車輛交互博弈學習等 → 這也正是用學習的原因

world on rails的假設后:簡化學習問題、得知這個世界的動態信息?、自己的車低維度動作、狀態空間

通過之前pre-recorded駕駛數據得出自己現在這步驟的影響

  1. 在已有的數據軌跡中學習世界的模型(learn world model)
  2. 對於所有pre-recorded軌跡預估action-value
  3. 訓練RV policy,獲得action-value function,從而獲取所有動作的影響

理論方法總括

首先我們要學習的是一個能由傳感器信息做出輸入,輸出動作的policy \(\pi(I)\)

在訓練時的軌跡序列是:\(\tau=\left\{\left(\hat{I}_{1}, \hat{L}_{1}, \hat{a}_{1}\right),\left(\hat{I}_{2}, \hat{L}_{2}, \hat{a}_{2}\right), \ldots\right\}\)

  • \(\hat{I}_{t}\) 傳感器信息
  • \(\hat{L}_{t}\) 駕駛數據,主要是自身車輛和其他參與者的位置、速度、朝向
  • \(\hat{a}_{t}\) 做出的動作

戴帽的是從行駛數據中來的,普通的則是free or random變量

我們要利用這些駕駛數據學習的是:關於世界的forward model \(\mathcal{T}\)action-value function \(Q\),整體過程就是 \(L_t\),\(a_t\) 通過 \(\mathcal{T}\) 預測得到\(L_{t+1}\),最后的agent對應的policy \(\pi(I_t)\)僅以傳感器信息作為輸入

整個算法流程 (公式請看下面定義)

3.1 Forward model分解

駕駛狀態 \(L_t\) 和 forward model分成兩個部分:

  1. 僅考慮自身車輛的控制:

    \[L_{t+1}^{e g o}=\mathcal{T}^{e g o}\left(L_{t}^{e g o}, L_{t}^{\text {world }}, a_{t}\right) \]

  2. 建模剩下的世界模型:

    \[L_{t+1}^{\text {world }}=\mathcal{T}^{\text {world }}\left(L_{t}^{\text {ego }}, L_{t}^{\text {world }}, a_{t}\right) \]

    又因為假設的原因,world僅和自身有關,所以:\(L_{t+1}^{\text {world }}=\mathcal{T}^{\text {world }}\left(L_{t}^{\text {world }}\right)\),那么從一開始world狀態就能知道整個world的模型

由以上,就只需建模對於自身車輛的forward model,這里使用L1進行回歸訓練 \(\mathcal{T}^{e g o}\)

\[E_{\hat{L}_{t: t+T}^{e g o}, \hat{a}_{t}}\left[\sum_{\Delta=1}^{T}\left|\mathcal{T}^{e g o \Delta}\left(\hat{L}_{t}^{e g o}, \hat{a}_{t+\Delta-1}\right)-\hat{L}_{t+\Delta}^{e g o}\right|\right] \tag{1} \]

注意這里的自身車輛狀態其實可以通過自行車模型來計算得來

實驗處理

在收集到的subset軌跡上,訓練自身車輛的forward model \(\mathcal{T}^{e g o}\),收集的數據保證在整個動作空間展開,例如:

  • 轉向從\([-1,1]\);油門從\([0,1]\);前兩者都是均勻采樣,剎車是只有\(\{0,1\}\)

正如前面提到的forward model \(\mathcal{T}^{e g o}\) 是由現在的\((x_t,y_t,\theta_t,v_t)\) 來預測下一個時刻車輛的狀態:\((x_{t+1},y_{t+1},\theta_{t+1},v_{t+1})\)

在這里可以使用已知的自行車模型作為 \(\mathcal{T}^{e g o}\) 的結構先驗:我們僅學習車輛的\(f_b,r_b\);從轉向\(s\)到輪轉向\(\phi\)的映射;油門和剎車到加速度的映射

  • [x] 這一條具體怎么做還需要看代碼的實現方式,\(f_b,r_b\)這兩者是車輛的基本參數吧?

    詳情見 代碼閱讀,是學習學到的這兩個參數


3.2 Action-value function

這里我們想要的是一個給出行駛狀態和動作,返回一個動作價值函數 [所以從這里可以知道對比lbc的方法 他是把鳥瞰圖,或者說激活RGB圖像的方式換成了RL里面對於動作價值的概念]

這里的公式就是Bellman基本公式,強化學習書里的,關於value function和q function的區別見:https://www.zhihu.com/question/59122948/answer/1899310296

\[\begin{aligned}V\left(L_{t}^{e g o}, \hat{L}_{t}^{\text {world }}\right)=& \max _{a} Q\left(L_{t}^{e g o}, \hat{L}_{t}^{\text {world }}, a\right) \\Q\left(L_{t}^{\text {ego }}, \hat{L}_{t}^{\text {world }}, a_{t}\right)= & r\left(L_{t}^{\text {ego }}, \hat{L}_{t}^{\text {world }}, a_{t}\right)+ \gamma V\left(\mathcal{T}^{\text {ego }}\left(L_{t}^{\text {ego }}, \hat{L}_{t}^{\text {world }}, a\right), \hat{L}_{t+1}^{\text {world }}\right)\end{aligned} \]

其中,\(\hat{L}_{t}^{\text {world }}\)是直接記錄下來的周圍環境(世界)的,不會對\(Q\)造成影響(是假設),所以這整個式子可以簡化一下:

\[V_{t}\left(L_{t}^{e g o}\right)=\max _{a} Q_{t}\left(L_{t}^{e g o}, a\right) \tag{2} \]

其中的\(Q\)值計算由此可得:

\[Q_{t}\left(L_{t}^{e g o}, a_{t}\right)= r\left(L_{t}^{e g o}, \hat{L}_{t}^{\text {world }}, a_{t}\right)+ \gamma V_{t+1}\left(\mathcal{T}^{e g o}\left(L_{t}^{e g o}, a\right)\right) \]

  • 自身車輛的狀態 \(L_{t}^{e g o}\) 由 (位置、朝向、速度) 組成;這樣對每一個 \(V_{t}\left(L_{t}^{e g o}\right)\) 狀態的價值我們都進行計算,在最后的eval過程中,線性擬合其值如果value falls between bins

實驗處理

對於每個時間\(t\) 我們把vaule function弄成一個4D的tensor:\(N_H \times N_W\)是關於位置的;\(N_v\)是關於速度的;\(N_\theta\)是關於朝向的

實驗中\(N_H=N_W=96, N_v=4, N_\theta=5\),每個點代表了物理的\(\frac{1}{3} \times \frac{1}{3} m^{2}\)區域,\(2m/s\)的速度范圍和\(38°\)的朝向范圍

\(\hat{L}_{t}^{e g o}=\left(x_{t}, y_{t}, v, \theta\right)\) 自身車輛的狀態是處於整個離散化空間的中間的;對於value fall outside就直接為0

這里同樣我們也離散化了我們的轉向和油門 \(M_s \times M_t\),然后在轉向或踩油門的時候,我們不進行剎車,那么當\(M_s=9,M_t=3\)。整個動作空間就是\(9\times3+1=28\)

reward的設計如下:

規定zero-speed area:比如遇到紅燈、接近其他車輛/行人等

  • +1:保持在目標車道
  • 0:如果偏離了車道,但是+1到0直接的變化不是二值,而是線性擬合smoothly penalized
  • +5:如果在zero-speed area里停下了
    但是這里zero-speed只會給一次,不會累加了,以免出現車輛直接一直停下不走了
    因為有了zero-speed區域,所以關於碰撞的懲罰也就不需要有了
  • \(r_{stop}=0.01\) 以避免agent為了躲避而偏離車道 → 這一點我感覺只要不壓實線,虛線變道應該是可以的吧 → 可能是對於leaderboard場景的trick設置

最后是通過high-level commands[左轉、右轉、直走、跟隨路徑、change right、 change left]來計算的整個動作價值函數


3.3 Policy Distillation

然后再使用 \(Q_{t}\left(\hat{L}_{t}^{e g o}, \cdot\right)\) 去監督學習VP(visuomotor policy) \(\pi(\hat I_t )\) ,所以呢 \(Q_{t}\left(\hat{L}_{t}^{e g o}, \cdot\right)\) 代表了車輛在那個狀態下做出哪個動作是最優的,然后優化迭代我們直接通過期望:

\[E_{\hat{L}_{t}^{e g o}, \hat{I}_{t}}\left[\sum_{a} \pi\left(a \mid \hat{I}_{t}\right) Q_{t}\left(\hat{L}_{t}^{e g o}, a\right)+\alpha H\left(\pi\left(\cdot \mid \hat{I}_{t}\right)\right)\right] \tag{3} \]

其中\(H\) 是entropy regularizer,\(\alpha\) 是溫度超參數,這樣的處理是為了拿到diverse output policy

實驗處理

對於policy network的設計使用的是以RGB作為輸入,ResNet34作為網絡框架

  1. flatten ResNet features
  2. concatenating speed
  3. 喂到網絡里去
  4. 輸出動作空間的分布:categorical distribution over discretized action spaces
  • [x] 從圖中應該比較明顯可知:這個value map是限制在地圖里的,也就是說如果換一個環境是需要重新再來的,從這一點上可能就沒有lbc好?所以每個地圖環境都是需要一個value map去對應的

    看了代碼知道了 不算是限制在地圖里,而是因為讀取了地圖中的waypoint 來進行reward判斷,就是需要沿着車道線行駛不能出界或者偏移 詳情見reward的操作

  • [ ] 關於加入value map其實有改進,針對lbc 的方法強化了正確動作的概率,類似於value map再做一層限制同樣也是第二個agent的先驗


4 實驗部分處理

  1. 通過carla內的行為規划器 [5] Carla之全局規划follow 來收集數據 \(\pi_b\)

    並沒有使用行為規划器來進行,而是直接生成min-max的一系列動作,根據reward 選出最好的進行 做出動作

  2. 使用autopilot來添加轉向的噪音

    • [ ] 這一點還需細看是怎么加進去的
  3. 使用上面的數據去學習forward model,而不是直接去使用autopilot去做監督學習

對應每個我都直接放在上面的細節中了

  • [x] 所以還是行為規划器,Q action-value只是用來幫助激活RGB的某個部分,更或者是說保存整個地圖信息在這個情況下怎樣做是最好的;但是並沒有去改善行為規划器的東西?而是從中學習得到value值

代碼運行部分

Carla版本0.9.10.1,python版本3.7,已經在Planning主機上設置好了,

①打開termnial ②輸入zsh ③輸入carla_wor

運行結構主要由三個大過程組成,第一過程可以直接使用文件夾內的ego_model.th來

Rails系列代碼閱讀,后續傳上來后再一個個貼吧

Stage 0: ego model

這一過程... 我暫時不知道是干啥的 因為按道理說第一過程才是開始收集train_scenario 的才對

  • [x] 待查明,這一過程ego的作用 → 訓練得知車輛運動模型 train car dynamics
  1. 首先到config.yaml文件,修改ego_data和ego_model的儲存位置

    ego_data_dir: collection/phase0
    ego_model_dir: collection/phase0
    main_data_dir: collection
    main_model_dir: collection
    
  2. 啟動Carla,這里是寫的sh文件來啟動多個Carla窗口,注意一個carla本身就需要2G顯存,正常6G顯存電腦建議只啟動2個即可

    ./scripts/launch_carla.sh 2 2000
    # ./scripts/launch_carla.sh [NUM RUNNERS] [WORLD PORT]
    
  3. 啟動收集data的腳本

    • [x] 咦?在這里就有收集數據的嘛??? → train dynamics
    python -m rails.data_phase0 --num-runners=2 --port=2000
    

    首先把 在這里我就沒有運行下去了,主要是出現了pygame 然后它就自己也沒報什么錯誤,也沒保存什么文件就.. 就.. 就停止了

    未知錯誤示意

    大概探索了一下,從leaderboard_evaluator.py里出來的,但是因為沒辦法print所以不知道更具體為什么,猜測原因是ray.remote,為什么沒辦法print啊!!!真是的!!!

    crash_message = "Agent couldn't be set up"
    
    • [x] 奇奇怪怪 為什么issue里沒有人和我遇到一樣的問題

    被自己氣死了!.... emmm 果然猜測是對的,改一下ray.init部分就可以顯示了

    ray.init(logging_level=40, local_mode=True, log_to_driver=False)
    
    • [x] 然后就顯示wandb的,查一下

      太絕了啊!這都是什么好東西!

    • [x] 有空查一下ray的東西

      查完感覺!超棒!太爽了吧!

    關於rails代碼詳細介紹請跳轉吧,寫在一起太長了,不過上面的步驟已經能讓整個運行起來了:

    data_phase0.py

    • [ ] 但是運行過程中,前20個左右的frame可能是OK的,后面總是提示說,保存不了圖片?但是為啥這個是和frame有關的呢?奇怪

      • 錯誤示意:

        Traceback (most recent call last):
          File "/home/udi/KinZhang/WorldOnRails/leaderboard/leaderboard/scenarios/scenario_manager.py", line 152, in _tick_scenario
            ego_action = self._agent()
          File "/home/udi/KinZhang/WorldOnRails/leaderboard/leaderboard/autoagents/agent_wrapper.py", line 88, in __call__
            return self._agent()
          File "/home/udi/KinZhang/WorldOnRails/leaderboard/leaderboard/autoagents/autonomous_agent.py", line 115, in __call__
            control = self.run_step(input_data, timestamp)
          File "autoagents/collector_agents/random_collector.py", line 124, in run_step
            self.flush_data()
          File "autoagents/collector_agents/random_collector.py", line 67, in flush_data
            'vid': wandb.Video(np.stack(self.rgbs).transpose((0,3,1,2)), fps=20, format='mp4')
          File "<__array_function__ internals>", line 6, in stack
          File "/home/udi/anaconda3/envs/carla_py37/lib/python3.7/site-packages/numpy/core/shape_base.py", line 423, in stack
            raise ValueError('need at least one array to stack')
        ValueError: need at least one array to stack
        
        During handling of the above exception, another exception occurred:
        
        Traceback (most recent call last):
          File "/home/udi/KinZhang/WorldOnRails/leaderboard/leaderboard/leaderboard_evaluator.py", line 365, in _load_and_run_scenario
            self.manager.run_scenario()
          File "/home/udi/KinZhang/WorldOnRails/leaderboard/leaderboard/scenarios/scenario_manager.py", line 136, in run_scenario
            self._tick_scenario(timestamp)
          File "/home/udi/KinZhang/WorldOnRails/leaderboard/leaderboard/scenarios/scenario_manager.py", line 159, in _tick_scenario
            raise AgentError(e)
        leaderboard.autoagents.agent_wrapper.AgentError: need at least one array to stack
        ======[Agent] Wallclock_time = 2021-07-08 14:50:50.458292 / 6.338849 / Sim_time = 4.550000067800283 / 0.717682718910227x
        
        Stopping the route, the agent has crashed:
        > need at least one array to stack
        
  4. 這里運行收集的數據是由隨機動作得到的數據集,主要作用是用來訓練車輛動力學

  5. 收集完后進行訓練此收集數據

    python -m rails.train_phase0 --data-dir=[EGO data DIR]
    # 注意這里的[EGO data DIR] 需要和上面config里的ego_model_dir一致
    

Stage 1: Q-computation

Tips 前提知曉

  1. 這個階段!真的很耗時!兩塊TiTan XP(和1080Ti差不多)訓練10個epochs需要用4天
  2. 但是這個階段更耗存儲空間(如果要收集到作者有的數據集需要3.4TB in the lmdb format,詳情見此issue:https://github.com/dotchen/WorldOnRails/issues/17#issuecomment-858148921
  3. 收集數據如果因為空間不夠,一定要記得刪掉未完成的那一個part不然frame無法正確讀取,計算q value的腳本會報錯
  4. 記得提前對 config_nocrash.yaml 文件進行修改config 和 數據路徑不然... 會報錯的,詳情見倒數第二部分可能出現的問題
  5. 此次使用會出現CUDA報錯問題,詳情見倒數第二部分可能出現的問題

收集數據

完成上面的車輛參數學習后,我們就可以把我們的動作(油門、方向盤、剎車)轉成速度輸出了,也就是上面理論部分提到的:

\(\hat{L}_{t}^{e g o}=\left(x_{t}, y_{t}, v, \theta\right)\) 自身車輛的狀態是處於整個離散化空間的中間的;對於value fall outside就直接為0

這里主要是收集數據

# Open Carla
./scripts/launch_carla.sh [NUM RUNNERS] [WORLD PORT]

# 這一層設置你想要收集的數據
python -m rails.data_phase1 --scenario={train_scenario, nocrash_train_scenario} --num-runners=[NUM RUNNERS] --port=[WORLD PORT]
  1. 打開Carla

  2. 收集數據,scenario 是指在哪個環境下,比如前者就是通過leaderboard來收集數據,后者可指定route在Town01下的4個不同的訓練天氣

    所以這個部分總結來看:在一個位置,根據已知的min, max的動作閾值,生成一張動作表,然后通過地圖(其實也算是上帝視角)來給各個動作塊附上reward,然后選取最大的。reward的標准呢在這里,不得不說一句這個作者代碼是真的牛掰... 硬生生看來我好久才理解了

計算Q Value

等待上面數據收集完成后,就可以關閉Carla,運行Q value label的腳本

# Q-labeling
python -m rails.data_phase2 --num-runners=[NUM RUNNERS]

代碼閱讀:/

運行后可以從wandb上看到一些記錄的細節:

大概可以看到即使只有1W(原作者數據集的1/1000都不到 也是花了1小時才做好的Q value label的過程)

  • [x] 為什么需要forward model呢,直接拿action來訓練不行嗎?比如 油門、方向盤、剎車去對應出value map,而且實際輸出圖片也看出來是這樣的 (但是估計是通過forward反映射了?)

    因為需要從油門、方向盤、剎車 → 速度 → 預測位置,最后一個預測位置也就是我們需要的state in the world

  • [x] 但是為什么不直接從定位GPS中讀取呢?因為加了噪音,有誤差嘛?

    我忘記這個問題為什么問出來了,但是大概是這樣的,首先做出的動作,並沒有實際做出,而是根據地圖的上帝因素進行判斷,判斷的前提是拿ego_model知曉了 這個動作做出后 位置大概在哪里,然后和地圖waypoint偏移什么的來進行比較

  • [x] 但是實際上在 data_phase1的時候就有計算哪個動作的reward更高,通過論文中說到的標准來確定,所以這么看來動作是離散的 問題有點大 frame是20內

    首先提出這個問題的時候,我還沒意識到又是一次上帝視角去判斷所有reward;第二動作確實是離散的,收集的頻率為4Hz,也就是說動作為保持250ms直到下一次更新?

Stage 2: Image model training

python -m rails.train_phase2

可能會遇到的運行問題

  1. ModuleNotFoundError: No module named 'leaderboard.leaderboard_evaluator'

    原因:這是因為我下載了leaderboard后,結構是這樣的leaderboard/leaderboard/code,

    解決方案:

    1. 把leaderboard復制出來就好了
    2. 或者是在原主leaderboard下加一個空的__init__.py文件即可
  2. > cuda runtime error (38) : no CUDA-capable device is detected at /opt/conda/conda-bld/pytorch_1579040055865/work/aten/src/THC/THCGeneral.cpp:50

    運行第二階段的數據收集時,也就是這行

    python -m rails.data_phase1 --scenario={train_scenario, nocrash_train_scenario} --num-runners=[NUM RUNNERS] --port=[WORLD PORT]
    

    原因:主要錯誤也指明了,是找不到cuda

    解決方案:定位到在q_collector.py文件中device是沒有指定哪一個的

    參考:https://github.com/pytorch/pytorch/issues/5046

    for key, value in config.items():
          setattr(self, key, value)
    os.environ["CUDA_VISIBLE_DEVICES"] = '0'
    device = torch.device('cuda')
    
    ego_model = EgoModel(1./FPS*(self.num_repeat+1)).to(device)
    
    
  3. 感覺第二階段的bug挺多的啊... 整個config中路徑都沒有被讀入哎 emmm

    我知道了,是我沒有看清楚config.yaml,這個data_phase1讀取的config是!!!! config_nocrash.yaml真是絕了,應該在readme里面說一聲的

Debug小技巧

對於python來說,debug感覺上應該比C/C++輕松不少的,首先是我一開始設置了很久的launch因為這個不是直接運行一個py文件而是 -m腳本方式運行,所以launch中應該要加入其下的Python env但是我加了很久,怎么着都不行,所以就另辟蹊徑走到了,直接開一個口進行監聽的方式

具體參考:https://blog.csdn.net/m0_37991005/article/details/113342656

步驟:

  1. 配置launch.json文件

    其中launch文件是這樣的:注意第一個Debug是我當時設置了很久的環境 也沒設對,所以第二個啟動時注意選擇好VScode界面

    {
        // Use IntelliSense to learn about possible attributes.
        // Hover to view descriptions of existing attributes.
        // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
        "version": "0.2.0",
        "configurations": [
            {
                "name": "Debug",
                "type": "python",
                // PYTHONPATH = ${CARLA_ROOT}/PythonAPI/carla/":"${SCENARIO_RUNNER_ROOT}":"${LEADERBOARD_ROOT}
                //~/KinZhang/WorldOnRails/PythonAPI/carla/:~/KinZhang/WorldOnRails/leaderboard:~/KinZhang/WorldOnRails/scenario_runner
                // "python.pythonPath": "~/KinZhang/WorldOnRails/PythonAPI/carla/",
                "request": "launch",
                "program": "${file}",
                "console": "integratedTerminal",
                "cwd": "${fileDirname}"
                
            },
            {
                "name": "Attach Debug",
                "type": "python",
                "request": "attach",
                "connect": {
                "host": "localhost",
                "port": 5678
                }
            }
        ]
    }
    
  2. 配置后,首先運行python文件(注意看中間寫的debugpy --listen 5678 --wait-for-client

    python -m debugpy --listen 5678 --wait-for-client -m rails.data_phase1 --num-runners=1 --port=2000
    
  3. 然后是進入監聽狀態,再去VSCode里點擊:首先選擇好對應的那個Python文件,然后再選擇好哪一個debug設置,最后點小綠就能debug上了

  4. 調試示意圖:

    同時可以到下面的debug terminal進行實時的調試測試(python可以 編譯后的C/C++類型只能顯示顯示而已)


免責聲明!

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



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