iT邦幫忙

2026 iThome 鐵人賽

DAY 14
0
AI Engineering

從零訓練到瀏覽器部署:30 天打造 Atari Breakout 強化學習 AI系列 第 14

Day 14|先讓訓練值得跑久,再看 100K 的 DQN 到底學到什麼

  • 分享至 

  • xImage
  •  

DAY 13已經回答了一個很重要的問題:目前這套 DQN 訓練程式能不能正常工作?

答案是可以。用來保存過去互動資料的 Replay Buffer 會持續累積經驗,模型權重也確實會更新,訓練過程中的數值沒有立刻出現 NaN 或明顯失控。

但「程式能訓練」和「Agent 已經開始學會 Breakout」是兩件不同的事。

Day 13 只跑了 10,000 個環境步數,一共完成 48 局遊戲。這種規模很適合抓程式錯誤,卻很容易把幾局遊戲的隨機波動誤認成模型真的在進步。

所以 Day 14 的問題很單純:

如果 10K 還不足以判斷模型是否真的在學,那就把實驗拉到 100K;但在跑十倍更久之前,先確認目前的訓練流程沒有把時間浪費掉。

整天的流程可以濃縮成:

10K:確認訓練程式沒壞
        ↓
要觀察學習,需要更長的 100K
        ↓
長跑前先整理訓練流程
        ↓
固定系統設定
        ↓
只改學習率,跑 100K
        ↓
看每局分數、數值診斷與真實遊戲畫面
        ↓
把「看起來有進步」交給 Day 15 正式評估

10K 是健康檢查,100K 才開始看學習曲線

10K 很適合快速確認幾件事:Replay Buffer 有沒有資料、模型有沒有更新、探索比例有沒有照預定方式下降,以及損失值、Q-value、目標值與梯度是否維持正常。

但它不適合拿來排誰好誰壞。

Breakout 的獎勵不是每一步都有,而且每一局長度不同。假設某個設定在 10K 的平均每局回報是 1.15,另一組是 1.75,這個差距可能只是最後幾局剛好打得比較好,還不能說參數真的造成穩定差異。

因此 Day 14 把兩種用途分開:

  • 10K 短跑檢查:回答「這組設定能不能正常訓練?」
  • 100K 主要比較:回答「跑久之後,學習曲線是否開始出現可解釋的差異?」

這裡的「每局回報(Return)」就是一整局累積起來的獎勵,也可以把它理解成這局到底打得多好。

100K 也不是「一定能學會 Breakout」的門檻。它只是把觀察時間拉長,讓少數幾局的運氣比較不容易主導結論。

從 Day 13 的 10K 診斷、Day 14 的 10K 短跑檢查到 100K 主要比較

這張圖最重要的地方不是「100K 一定要選出勝者」,而是反過來:如果 100K 仍然沒有可靠差異,「目前無法分辨」本身就是合理的實驗結果。

跑 100K 之前,先看時間都花去哪裡

DQN 的卷積神經網路(CNN)確實在 RTX 4060 上計算,但完整的訓練流程不只有神經網路。

每一步大致還要經過:

遊戲環境產生新畫面
        ↓
模型選擇動作
        ↓
把這次互動寫進 Replay Buffer
        ↓
從 Replay Buffer 抽出一批資料
        ↓
模型計算預測、學習目標、誤差
        ↓
反向傳播並更新權重

其中遊戲環境和大量 Python 控制流程仍然在 CPU 上執行。

所以:有使用 CUDA,不代表 GPU 就會一直忙。

Day 14 先從最明顯的資料路徑開始檢查:Replay Buffer。

把 Replay Buffer 放進 GPU,為什麼完整訓練反而沒有更快?

原本的 Replay Buffer 把過去的互動資料存在 CPU 的 NumPy 陣列。模型需要學習時,才從裡面抽一批資料,再送進 GPU。

GPU-resident Replay 的做法則是:讓 Replay Buffer 直接常駐在 GPU 記憶體。

這樣訓練時可以直接在 GPU 內抽樣、取資料,再送進 DQN 更新,不需要每次都把整批訓練資料從 CPU 搬過去。

如果只測「資料已經在 GPU 後,模型更新能有多快」,結果很好:大約可以處理 39K~41K 筆訓練樣本/秒

但這只是局部測試,不是完整的 Breakout 訓練。

真正的訓練還包含:

  • 遊戲環境前進一步;
  • 模型決定下一個動作;
  • 記錄每局分數;
  • 每一步把新的互動資料寫進 Replay Buffer。

所以我又做了一次真正的完整流程比較。固定批次大小 32、每 4 個環境步數更新一次、開始學習的步數、模型與隨機種子都相同,只改 Replay Buffer 放在 CPU 還是 GPU:

Replay 方式 每秒環境步數 每秒模型更新次數 每秒訓練樣本 總耗時 GPU 平均使用率
CPU + 預先配置傳輸緩衝區 361.61 71.92 2,302 27.65 s 23.87%
GPU-resident Replay 338.13 67.25 2,152 29.57 s 24.63%

結果很明確:在目前單一 Breakout 環境、批次大小 32 的情況下,GPU Replay 沒有讓完整訓練更快。

原因不是 GPU 裡面抽資料很慢,而是新的互動資料仍然是由 CPU 上的遊戲環境產生。

也就是說,GPU Replay 雖然省掉了「訓練時整批資料從 CPU 搬到 GPU」的成本,卻多了另一件事:每一個環境步數,都要把一小筆新的互動資料寫進 GPU。

這些資料量本身不大,但次數很多。對 GPU 來說,很多次很小的搬運,不一定比少數幾次較大的搬運划算。

因此前面的 39K~41K 並沒有錯,只是它回答的是另一個問題:

局部測試
→ 資料已經在 GPU 時,模型更新可以多快?

完整訓練
→ 真正玩遊戲、收資料、寫 Replay、更新模型時可以多快?

目前的結果告訴我們:GPU 內部的模型更新很快,但整條訓練流程還沒有辦法把這個優勢完全發揮出來。

這也留下了 Day 16 的方向:如果之後要讓 GPU Replay 真正展現優勢,就不能只繼續優化 Replay 本身,而要處理「一次只跑一個遊戲環境、一次只替一個畫面選動作、每次只寫入一筆資料」這些問題。

真正先省下時間的,是減少每一步不必要的工作

Replay 的比較沒有直接帶來加速,但測量過程讓另一件事變得很清楚:訓練程式裡有一些工作根本不需要每一步都做。

原本每一步都會頻繁計算診斷資料、立刻把 CSV 寫入磁碟,CPU 執行緒數也沿用比較大的預設值。這些事情不會讓 Agent 多學一筆經驗,卻會讓 CPU、GPU 和 Python 更常互相等待。

在相同訓練設定、相同 10K 隨機種子下,把這些高頻工作減少後:

10K 測試 調整前 調整後
每秒環境步數 145.94 218.99
每秒模型更新次數 32.85 49.29
總耗時 68.52 s 45.66 s
CPU 執行緒數 12 1
診斷 / CSV 寫入間隔 1 / 1 100 / 100

兩邊都完成 2,251 次模型更新,目標網路的同步次數也一致,主要訓練數值仍然正常。

每秒環境步數從 145.94 提高到 218.99,大約是 1.50 倍

這種加速比較乾淨:沒有少做模型更新,也沒有偷偷降低訓練量,只是把不需要每一步做的工作降低頻率。

GPU 使用率比較高,不代表整體訓練比較快

接著我又測了一個很直覺的想法:既然 GPU 使用率不高,把每次訓練使用的資料量放大,是不是就會更快?

這裡的「批次大小(batch size)」就是模型每次更新時,從 Replay Buffer 拿多少筆資料一起學。

我固定其他主要條件,只比較批次大小 32 / 64 / 128

批次大小 每秒環境步數 每秒訓練樣本 GPU 平均使用率 GPU 記憶體峰值
32 235.74 1,698 30.13% 1.76 GiB
64 203.32 2,929 32.22% 1.89 GiB
128 177.36 5,110 34.88% 1.97 GiB

這組批次大小測試是另一輪固定條件的 10K 實驗,所以不要把它的絕對數字直接和上一張 Replay A/B 表橫向比較;這裡只比較同一張表內不同批次大小的相對結果。

結果很有意思:批次 128 的 GPU 使用率最高,每秒也處理最多訓練樣本,但整個遊戲訓練反而最慢

原因是把批次放大,只是讓「每一次模型更新」做更多工作,卻沒有解決前面真正的等待:目前仍然只有一個遊戲環境,而且模型大部分時間一次只替一個畫面決定動作。

更重要的是,批次大小本身也會改變模型怎麼學,所以不能只因為 GPU 看起來比較忙,就把較大的批次當成更好的 DQN 設定。

批次大小 32、64、128 的完整訓練速度、GPU 使用率與記憶體比較

這裡真正得到的結論只有一句:

在目前單一遊戲環境的訓練方式下,批次 32 的完整訓練速度最高;批次變大雖然能讓 GPU 一次處理更多資料,卻沒有讓整個 Breakout 訓練更快。

最後,我又固定批次大小 32,測試 1 / 2 / 4 個 PyTorch CPU 執行緒,每秒環境步數分別是 290.08 / 306.79 / 304.15,因此後續採用 2 個執行緒

到這裡就停止改系統設定。

因為接下來如果一邊改學習率,一邊又換 Replay、批次大小、CPU 執行緒數,最後曲線有差異時,就不知道到底是哪一項造成的。

系統設定固定後,才正式比較 100K 的學習率

現在才回到真正的強化學習問題。

學習率(learning rate)控制的是:每次模型根據誤差調整權重時,要走多大一步。

太小可能學得很慢;太大則可能讓模型的價值估計變得不穩定。

這次一次只改學習率:

設定 學習率 其他主要條件
基準 1e-4 GPU Replay、批次32、隨機種子42、探索規則、目標網路同步、獎勵裁切、FP32 固定
較低 5e-5 同上
較高 2e-4 同上

這裡三組都固定使用 GPU Replay,不是因為它已經證明比 CPU Replay 更快,而是因為這一輪要固定同一條資料路徑,才能把「學習率」留成主要變因。

三組先跑 10K 做健康檢查,全部正常後才進 100K。

100K 期間也不只保存最後結果,而是保留中途模型與紀錄,讓 25K、50K、75K、100K 都可以回頭查看。

統計方式也先固定:

  • 最近 20 個完整回合的平均與中位數;
  • 每 20 個回合的移動平均;
  • 最近 20 局中,後 10 局平均減去前 10 局平均,觀察近期是否還在進步。

跑到 100K,三組結果終於開始拉開

三組都完整跑到 100,000 個環境步數:

設定 完成回合數 最近 20 局平均 中位數 最佳 20 局移動平均 近期變化 每秒環境步數 總耗時
基準 1e-4 364 5.15 5.50 5.15 -0.30 358.47 278.96 s
較低 5e-5 389 1.80 2.00 2.90 -0.20 387.92 257.78 s
較高 2e-4 308 9.15 8.00 9.15 -0.10 390.60 256.02 s

在這一次隨機種子 42 的實驗裡,2e-4 的後段表現明顯高於另外兩組。

這比 10K 時的結果有資訊得多,因為現在看到的是較長一段學習過程,而不是少數幾局的短期平均。

但仍然只能得到這個結論:

在目前這組條件下,2e-4 是值得下一階段繼續驗證的候選設定。

它還不能被叫作「最佳學習率」,因為現在只有一個訓練隨機種子。

100K 期間三種學習率的每局回報與 20 回合移動平均

圖中的淡色點是每一局實際得到的回報,粗線則是 20 回合移動平均。

這張圖最重要的不是「2e-4 贏了」,而是:跑到 100K 之後,三條學習曲線終於開始出現值得追蹤的差異。

分數變高的同時,模型內部有沒有開始失控?

只看每局分數還不夠。

DQN 內部還有幾個重要數值:

  • Q-value:模型估計某個動作長期有多值得做;
  • 目標值:模型這次更新時想追近的參考值;
  • TD 誤差:目前預測和學習目標差多少;
  • 梯度大小:這次更新想把模型參數推動多大。

如果學習真的開始數值失控,常見情況會是:價值估計越來越誇張、誤差越拉越大、損失值與梯度也一起持續升高,最後甚至出現無效數值。

這次 100K 沒有看到這條完整的失控鏈。

三組的 Q-value 與目標值確實都上升:

設定 Q 平均:25K → 100K 目標值平均:25K → 100K
基準 1e-4 0.751 → 1.364 0.731 → 1.373
較低 5e-5 0.555 → 1.155 0.553 → 1.193
較高 2e-4 0.513 → 1.722 0.499 → 1.755

較高學習率那組的價值估計上升得最快,但「Q-value 變大」本身不能直接當成錯誤,也不能直接當成學得比較好。

到 100K 附近,三組平均絕對 TD 誤差約為:

  • 基準:0.054
  • 較低:0.033
  • 較高:0.044

較高學習率那組全程最大的絕對 TD 誤差約為 1.18,主要數值都仍然是正常有限值。

因此目前比較合理的判讀是:2e-4 讓價值估計變化得更快,值得繼續監看,但現在還沒有足夠證據說它已經數值不穩定。

100K 期間的損失值、Q-value、目標值、梯度、探索比例與訓練速度

另外,這組設定的 epsilon 在前 10K 就下降到 0.05,後面 90K 大多維持低探索比例。這不是這次比較的變因;如果之後要研究探索速度,應該另外做只改 epsilon 下降速度的實驗。

曲線之外,直接看看 Agent 在遊戲裡做了什麼

曲線和診斷數據都是數字,但它們看不到擋板到底有沒有開始對球做出比較合理的反應。

所以 Day 14 另外保存不同訓練階段的模型,使用同一套方式重新跑 Breakout,再把畫面錄成 GIF。

為了讓 1K、10K、50K、100K 之間可以比較,錄影時固定:

  • 同一個遊戲環境;
  • 同一個評估隨機種子;
  • 相同畫面前處理;
  • epsilon = 0,也就是完全不加入隨機探索,只使用模型當下認為最好的動作。

結果是:

  • 1K:回報 0
  • 10K:回報 0
  • 50K:回報 4
  • 100K:回報 7

這些都只是同一個隨機種子、單一回合的結果,所以不能拿來取代 Day 15 的正式評估。

但它們可以回答另一件事:不同訓練階段的模型,實際在畫面上做出了什麼行為?

1K steps

1K 模型實際執行 Breakout

10K steps

10K 模型實際執行 Breakout

50K steps

50K 模型實際執行 Breakout

100K steps

100K 模型實際執行 Breakout

1K 與 10K 還看不到穩定得分;50K 已經可以看到磚塊出現缺口;100K 則清掉更多磚塊,並在 363 個評估步數後結束。

這些 GIF 是「行為證據」,不是正式成績。

看起來比較會玩,不代表它在不同隨機種子、不同回合下都比較強。

100K 分數還不高,不代表模型一定太小

看到 100K 的分數還不算高,很容易直接猜:是不是 CNN 或中間的隱藏層不夠大?

目前還不能這樣判斷。

如果 50K 到 100K 的分數仍然往上走,第一個合理動作通常是繼續觀察更長的訓練,而不是立刻把模型放大。

只有當:

訓練跑得更久
        ↓
分數長時間停在差不多的位置
        ↓
訓練數值又都正常
        ↓
不同合理參數設定也都卡在相近低分

才比較有理由懷疑模型容量不足。

如果未來真的要測模型大小,也應該一次只改一個地方,例如把隱藏層大小比較成 256 / 512 / 1024,而不是一次把整個 CNN 和全連接層全部放大。

Day 14 現在看到的是:100K 比 10K 更明顯地出現了學習跡象,而不是模型容量已經撞牆。

Day 14 最後只留下兩個答案

走到這裡,前面的系統測試、100K 學習曲線、數值診斷與 GIF,其實可以收斂成兩個答案。

第一個答案:DQN 已經出現值得正式驗證的學習跡象

10K 只能證明訓練程式沒壞;拉到 100K 後,三種學習率才開始拉開。

在這一次隨機種子 42 下,2e-4 的後段分數較高,而且 Q-value、TD 誤差與梯度沒有形成明顯的數值失控鏈。

所以它可以成為下一階段的候選設定,但還不能被叫作最佳設定。

Day 15 會把模型固定下來,用固定的評估隨機種子、完全不探索的策略與 Atari 原始分數,正式比較 Random Policy(隨機策略)和 DQN

第二個答案:現在真正限制 GPU 的,不是 Replay Buffer 抽樣本身

GPU Replay 在「資料已經位於 GPU」的局部測試裡很快,但完整訓練沒有因此變快;把批次放大也只是讓 GPU 更忙,沒有提高整個遊戲訓練的速度。

真正值得處理的方向已經變得很具體:

一次只跑一個遊戲環境
+ 一次只替一個畫面選動作
+ 每次只寫入一筆 GPU Replay

所以 GPU Replay 不會因為這次完整比較沒有贏就被丟掉。

Day 16 會進一步改成:

多個遊戲環境並行
        ↓
一次替多個畫面決定動作
        ↓
一次寫入多筆 GPU Replay

也就是多環境並行(Vectorized Environments)搭配批次化的 GPU 訓練流程。

Day 14 最後真正學到的不是「哪個 GPU 設定最快」,也不是「哪個學習率一定最好」,而是先把兩個問題分開:

系統跑得快,不代表模型學得好;模型看起來在進步,也不能只靠一次實驗就宣布成功。


上一篇
Day 13|DQN 不學時怎麼查:先證明程式沒壞,再談超參數
下一篇
Day 15|DQN 真的變強了嗎?一次評估反而抓出了動作選擇問題
系列文
從零訓練到瀏覽器部署:30 天打造 Atari Breakout 強化學習 AI17
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言