訓練資料讀太慢?TFRecords、tf.data 與 prefetch 加速

訓練資料讀太慢,多半是 GPU 在等資料:把小檔打包成 TFRecords,再用 tf.data 的 prefetch 邊讀邊訓練。

前面 12 篇都在講「資料怎麼整理」:切資料集、處理遺失值、做特徵、遮個資。這篇講的是最後一步:資料怎麼餵進模型。餵得慢,前面做得再好,模型也只能乾等。

一樣用有 2,000 間分店的連鎖飲料店當例子(教學假設)。這次要訓練的是「封膜檢查」模型:每杯飲料封膜後拍一張照片,讓模型判斷封膜有沒有歪、有沒有漏。總共 200 萬張照片,每張裁切後約 50 KB,全部放在 Google 的雲端儲存空間 Cloud Storage,加起來約 100 GB。

訓練資料讀太慢的真相:GPU 在等資料。傻做法一步 1.3 秒,加 prefetch 變 0.9 秒,四招全開變 0.4 秒,GPU 使用率從 31% 拉到 100%

為什麼你需要知道

  • GPU 按小時計費:訓練用的 GPU、TPU 都是租的,它在等資料的每一秒都在燒錢。GPU 使用率只有 30%,等於你付了 100% 的錢只用到三成
  • 最常見的誤會:訓練太慢就換更貴的 GPU,結果一點都沒變快。因為瓶頸不在「算」,在「讀」。這篇教你先判斷是哪一種慢
  • 筆記裡的三個關鍵字,舊題庫很常考:「大型 CSV 要分割檔案+平行 interleave」「TensorFlow 圖片用 TFRecords+tf.data」「TPU 輸入瓶頸用 prefetch」。這篇把三個全部講清楚
  • 證照必考:PMLE 考試指南第 3.2 節要你會「在 Cloud Storage 和 BigQuery 上組織訓練資料」「把資料送進訓練管線」「排除訓練失敗的問題」,第 3.3 節要你會選 CPU、GPU、TPU

先搞懂:訓練的時候,電腦到底在做什麼?

白話是什麼

模型訓練是一步一步做的,每一步叫一個訓練步驟(training step)。TensorFlow 官方的效能指南把一個步驟拆成三件事:

  1. 開檔:找到檔案、打開它
  2. 讀資料:把資料從硬碟或網路讀進記憶體,通常還要做前處理(解壓縮、縮放、裁切)
  3. 訓練:把這一批資料送進 GPU 算

幾個會一直出現的 IT 名詞先講一下:

  • CPU(中央處理器):電腦的大腦,什麼都會做,但同一時間只能做幾件事
  • GPU(圖形處理器):原本是畫遊戲畫面的晶片,擅長「同時做幾千個簡單算術」。訓練神經網路剛好就是大量的乘法和加法,所以 GPU 比 CPU 快很多倍
  • TPU(張量處理器):Google 自己設計、專門為機器學習打造的晶片,比 GPU 更專、更快
  • I/O(輸入輸出):讀硬碟、走網路、開檔案,這些「搬資料」的動作統稱 I/O

比喻:一個廚師、一個倉庫

把訓練想成餐廳出菜:

  • GPU 是廚師,炒菜超快
  • 資料是食材,放在遠處的中央倉庫(Cloud Storage)
  • CPU 是助手,負責跑腿和切菜(前處理)

傻做法是這樣:廚師每炒一盤菜,都先自己走去倉庫拿食材,拿回來自己切,切完才下鍋。走路 36 秒、切菜 18 秒、炒菜 24 秒。你算算,廚師真正在炒菜的時間只有三成,其他時間都在走路和切菜。

這就是「GPU 在等資料」。

來龍去脈:為什麼現在特別嚴重

這幾年 GPU、TPU 的運算速度翻了好幾倍,但硬碟和網路沒有跟著等比例變快。廚師越來越快,倉庫卻還是那麼遠,瓶頸自然從「算」移到「讀」。

資料放在雲端時更明顯。TensorFlow 官方文件點出遠端儲存(例如 Cloud Storage)和本機硬碟的兩個差別:

本機硬碟遠端儲存(Cloud Storage)
開檔到讀到第一個位元組的時間(time-to-first-byte)很短可能長上好幾個數量級
讀取頻寬一個檔就能用滿總頻寬很大,但單一檔案只用得到一小部分

用倉庫的比喻:雲端倉庫很大、門很多,但每次開門都要等保全確認(開檔慢),而且一個人一次只能走一道門(單檔頻寬小)。所以同時派很多人走不同的門,才用得滿。

兩種慢:輸入受限 vs 運算受限

輸入受限(input-bound)運算受限(compute-bound)
白話GPU 在等資料資料早就準備好,GPU 算不過來
比喻廚師在等食材食材堆滿檯面,廚師炒不完
怎麼看出來GPU 使用率低、忽高忽低GPU 使用率接近 100%
解法這篇講的全部:prefetch、平行讀取、TFRecords、快取換更快的 GPU/TPU、加大批次、多台機器一起算(第 16 篇)

怎麼知道自己是哪一種? 最簡單是看 GPU 使用率(NVIDIA 顯卡用 nvidia-smi 指令就看得到)。要看得更細,TensorFlow 有 Profiler 工具,會直接告訴你每一步有幾成時間在等輸入。Cloud TPU 的效能指南也說,排除 TPU 效能問題的第一步就是先做 profile。

為什麼要學

不先分清楚是哪一種慢,就會做白工:輸入受限時換 GPU 沒用,運算受限時改讀檔也沒用。考試更是直接考這個判斷:題目說「GPU 使用率很低」,答案絕對不是「換更大的 GPU」。


1. tf.data:把「餵資料」變成一條生產線

白話是什麼

tf.data 是 TensorFlow 內建的一組工具,專門用來建輸入管線(input pipeline)。

管線這個詞在 IT 界很常見,意思是「一連串接好的處理步驟」,資料像水一樣從頭流到尾,每一站做一件事。tf.data 的管線就是:讀檔 → 解析 → 前處理 → 打亂 → 分批 → 送進模型。

比喻:便當工廠的輸送帶

傻做法是一個人從頭做到尾:拿米、裝飯、放菜、蓋盒、裝箱。輸送帶的做法是每一站站一個人,各做一件事,便當一個接一個往下傳。

重點不是「步驟變少」,而是每一站可以同時做事:裝飯的人在裝第 10 個便當時,放菜的人正在放第 9 個,裝箱的在裝第 8 個。

來龍去脈

早期用 TensorFlow 讀資料,很多人是自己寫 Python 迴圈,一筆一筆讀進來再丟給模型。這樣做又慢又難平行,而且每個人寫法都不一樣。TensorFlow 後來把這件事標準化成 tf.data:你描述「資料從哪來、要怎麼處理」,它負責排程、開多執行緒、管理緩衝區。

執行緒(thread)是程式裡可以同時跑的工作線,多開幾條就能同時做幾件事;緩衝區(buffer)是一塊暫存空間,先做好的東西放在這裡等人拿。

一條管線長什麼樣

以封膜照片為例,一條標準的 tf.data 管線大概是這樣(看不懂程式沒關係,下面一行一行翻譯):

files = tf.data.Dataset.list_files("gs://drink-ml/sealing/*.tfrecord")
ds = files.interleave(tf.data.TFRecordDataset, num_parallel_calls=tf.data.AUTOTUNE)
ds = ds.map(parse_and_resize, num_parallel_calls=tf.data.AUTOTUNE)
ds = ds.shuffle(10_000).batch(64).prefetch(tf.data.AUTOTUNE)
這一行白話
list_files(...)列出 Cloud Storage 上所有封膜照片的打包檔(gs:// 開頭就是 Cloud Storage 的路徑)
interleave(TFRecordDataset, ...)同時打開好幾個檔案,交錯著讀
map(parse_and_resize, ...)每一張照片解析、縮放,而且好幾張同時做
shuffle(10_000)先拿 10,000 張放進袋子打亂,讓模型不會照固定順序學
batch(64)每 64 張包成一批
prefetch(AUTOTUNE)先把下一批準備好,GPU 一要就有

tf.data.AUTOTUNE 的意思是「要開幾條線你自己決定」,TensorFlow 會在執行時動態調整。官方文件建議大多數情況直接用它。


2. 四招加速:各治一種慢

TensorFlow 效能指南整理的做法,用廚房比喻一次看懂。

tf.data 四招加速對照:prefetch 預先抓取像助手先備好下一盤食材、interleave 像多人同時去倉庫、map 平行像多個助手同時切菜、cache 快取像切好的菜放冰箱第二輪直接拿

第 1 招:prefetch(預先抓取)

白話:GPU 在算這一批的時候,背景同時把下一批讀好、放在緩衝區。

比喻:助手在廚師炒這盤菜時,就先把下一盤的食材拿到檯面旁邊。廚師炒完回頭,食材已經在了。

原理:官方文件寫得很清楚,prefetch 讓「資料準備」和「模型運算」重疊,一步的時間從「準備時間+訓練時間」變成「兩者取大的那個」。

怎麼用:管線最後加 .prefetch(tf.data.AUTOTUNE)。要預先抓幾批?官方說至少等於一個訓練步驟會吃掉的批次數,用 AUTOTUNE 讓它自己調最省事。

第 2 招:interleave(交錯平行讀檔)

白話:同時打開好幾個檔案,輪流從每個檔各拿一點。

比喻:一個人去倉庫搬,一次只能走一道門;派四個人同時去,四道門一起走。雲端倉庫「開門慢、單門窄」的問題就靠這招解。

兩個參數:

  • cycle_length:同時開幾個檔案輪著讀
  • num_parallel_calls:真正平行開幾條線去讀。沒設這個,interleave 只是「輪流」不是「同時」,官方文件實測:只輪流沒有加速,加了平行才有

對應筆記那條「大型 CSV 要分割檔案」:一個 50 GB 的 CSV 只有一個檔,再多人也只能排隊走同一道門。先切成 100 個 500 MB 的檔,interleave 才有東西可以平行。第 3 節會再講。

第 3 招:map 平行化(多人同時切菜)

白話:解碼圖片、縮放、資料增強這些前處理,一次做很多張,不要一張做完才做下一張。

比喻:切菜只有一個助手,就算廚師再快也要等;開四個助手同時切,速度直接變四倍。

怎麼用:.map(fn, num_parallel_calls=tf.data.AUTOTUNE)。官方給的簡單原則是「開到 CPU 核心數」,用 AUTOTUNE 讓它自己抓。

進階:先 batch 再 map。每叫一次前處理函數都有固定的排程開銷。官方的做法是把函數改成「一次處理一整批」(向量化),然後 batch 放在 map 前面,開銷只付一次。官方實測從 0.24 秒降到 0.05 秒,差了近 5 倍。

第 4 招:cache(快取)

白話:第一輪訓練讀過、處理過的資料,存在記憶體或本機硬碟;第二輪起直接拿,不用再去倉庫。

比喻:切好的菜放冰箱,明天不用再切一次。

快取(cache)在 IT 界到處都是,意思都一樣:把算過、拿過的東西先存一份在比較近的地方,下次直接用。

兩個規則:

  • 放得下就放在 map 之後:連前處理都省掉
  • 放不下就放在 map 之前,或乾脆事先處理好:如果 map 會讓資料變大(例如把壓縮的 JPEG 解成原始像素,一張會大十幾倍),200 萬張解開放不進記憶體,就只快取讀檔那段,解碼每輪重做。或者在訓練前先用別的工具(第 23 篇會講的 Dataflow)把資料處理好存成檔案

另外一個小提醒:資料增強不要放在 cache 前面。第 11 篇講過,資料增強的重點是每一輪看到的照片都有一點不一樣,快取起來就每輪都一樣了。

四招一張表

招式治什麼慢比喻關鍵參數
prefetchGPU 等資料的空檔先備好下一盤食材prefetch(AUTOTUNE)
interleave遠端開檔慢、單檔頻寬小多人同時走不同的門num_parallel_calls=AUTOTUNE
map 平行前處理只用到一顆 CPU 核心多個助手同時切菜num_parallel_calls=AUTOTUNE,先 batch 再 map
cache每一輪都重讀、重處理切好的菜放冰箱cache() 放 map 之後(放得下)或之前

3. 算一次給你看:一個步驟到底花多久

繼續用封膜照片的例子,數字是教學假設:

  • 每批 64 張照片
  • 開檔+讀資料:0.6 秒(照片在 Cloud Storage)
  • 前處理(解碼、縮放):0.3 秒
  • GPU 訓練這一批:0.4 秒
  • 總共跑 1,000 步

傻做法:三件事排隊做

一步的時間 = 讀資料 + 前處理 + 訓練
          = 0.6 + 0.3 + 0.4
          = 1.3 秒

1,000 步 = 1,300 秒 ≈ 21 分 40 秒。

GPU 使用率 = 訓練時間 ÷ 一步的時間 = 0.4 ÷ 1.3 ≈ 31%。你付了 100% 的 GPU 錢,它只工作三成。

加 prefetch:讀資料和訓練重疊

一步的時間 = max(讀資料 + 前處理, 訓練)
          = max(0.6 + 0.3, 0.4)
          = max(0.9, 0.4)
          = 0.9 秒

max 是「取大的那個」。因為兩邊同時進行,誰慢就等誰。

1,000 步 = 900 秒 = 15 分。GPU 使用率 = 0.4 ÷ 0.9 ≈ 44%。

有進步,但 GPU 還是在等,因為「準備資料」那邊 0.9 秒比「訓練」0.4 秒慢。瓶頸還在資料端。

再加 interleave 和平行 map:把資料端壓下來

  • 4 個檔同時讀,讀資料 0.6 秒 → 約 0.15 秒
  • 4 顆 CPU 核心同時做前處理,0.3 秒 → 約 0.075 秒
一步的時間 = max(0.15 + 0.075, 0.4)
          = max(0.225, 0.4)
          = 0.4 秒

1,000 步 = 400 秒 ≈ 6 分 40 秒。GPU 使用率 = 0.4 ÷ 0.4 = 100%。

三種做法比一比

做法一步時間1,000 步GPU 使用率比傻做法快
傻做法1.3 秒21 分 40 秒31%1 倍
加 prefetch0.9 秒15 分44%1.4 倍
四招全開0.4 秒6 分 40 秒100%3.25 倍

程式沒改模型一行,光改讀資料的方式,就快了 3 倍多,GPU 的錢也只付三分之一。

數字怎麼看

  • 資料端時間 > 訓練時間:輸入受限,繼續在資料端下功夫(更多平行、打包 TFRecords、加快取)
  • 資料端時間 < 訓練時間:變成運算受限,再加速資料也不會更快。例子裡資料端已經壓到 0.225 秒,再壓到 0.1 秒,一步還是 0.4 秒。這時要換更快的 GPU、加大批次,或多台機器一起算
  • 換了更快的 GPU 之後要重算:假設 GPU 升級後訓練時間從 0.4 秒變 0.2 秒,資料端的 0.225 秒馬上又變成瓶頸。所以硬體升級後,輸入管線通常要再調一次
  • 0.6 秒的讀資料裡,開檔佔了多少? 檔案又小又多,開檔開銷會吃掉大半。這就是下一節 TFRecords 要解的問題

4. TFRecords:把 200 萬個小檔打包成幾百個大箱

先看問題:小檔案為什麼慢

Cloud Storage 每打開一個檔案都有固定的開銷(前面講的 time-to-first-byte)。假設每次開檔要 20 毫秒(0.02 秒,教學假設):

200 萬張照片,每張一個檔
開檔總時間 = 2,000,000 × 0.02 秒 = 40,000 秒 ≈ 11 小時

光是「開檔」就要 11 個小時,還沒開始讀內容。

如果把 200 萬張照片打包成 500 個大檔(每個 200 MB):

開檔總時間 = 500 × 0.02 秒 = 10 秒

從 11 小時變 10 秒。這就是打包的威力。

白話是什麼

TFRecord 是 TensorFlow 的檔案格式,把很多筆資料一筆接一筆存成二進位紀錄。TensorFlow 官方教學的定義就一句話:「一種儲存一連串二進位紀錄的簡單格式」。

二進位(binary)是電腦原生的 0 和 1,不是給人看的文字。好處是電腦讀的時候不用再「翻譯」(像 CSV 要把文字 “0.57” 轉成數字),直接用。

比喻:散裝水果 vs 整箱

200 萬顆水果一顆一顆裝袋,倉庫出貨要開 200 萬次門。改成 500 箱,每箱 4,000 顆,開 500 次門就搬完。

箱子裡每顆水果還是分開的(每筆資料獨立),只是運送單位變大了。

來龍去脈:Protocol Buffers 和 tf.train.Example

TFRecord 裡面每一筆紀錄,通常是一個叫 tf.train.Example 的東西,它是用 Protocol Buffers(簡稱 protobuf)寫的。

Protocol Buffers 是 Google 自家發明、用來把結構化資料序列化的格式。序列化(serialization)就是把程式裡的物件壓成一串位元組,方便存檔或傳輸,像把組合家具拆成平板裝箱,到了再組回來。

tf.train.Example 本質上是一張「欄位名稱 → 值」的對照表,官方寫法是 {"string": tf.train.Feature}。而值的型態只有三種:

型態裝什麼封膜照片的例子
BytesList文字、原始位元組image:JPEG 檔的原始內容;store_id:分店編號 “TP-0231”
FloatList小數fill_level:裝杯高度 0.93
Int64List整數、布林值label:封膜正常 0、有問題 1;shot_hour:拍攝時段 14

比喻:一個標準便當盒只有三種格子(主菜格、配菜格、湯格),不管裝什麼菜都只能放進這三種格子。好處是任何人拿到便當盒都知道怎麼打開。

為什麼叫 Example:機器學習裡一筆訓練資料習慣叫一個「樣本」(example),這個格式就是「一個樣本長什麼樣」的標準容器。

重要:不是一定要轉成 TFRecord

官方教學特別加了一段提醒:這些結構是選用的。除非你用 tf.data,而且「讀資料」確認是訓練的瓶頸,否則沒有必要把現有程式改成 TFRecord。

這是考試的陷阱之一:看到「訓練很慢」不要反射性選「轉 TFRecord」。先確認是不是輸入受限(前面「先搞懂」那一節講的),而且是不是「小檔太多」造成的。

檔案要切多大、切幾個:算一次

TensorFlow 官方教學給了兩個經驗法則:

  1. 檔案數至少是「同時讀資料的主機數」的 10 倍,才有足夠的平行度
  2. 每個檔至少 10 MB,最好 100 MB 以上,prefetch 才有效果

套在封膜照片上:

資料量 100 GB,打算用 4 台機器一起訓練
檔案數至少 = 4 × 10 = 40 個
每檔大小 = 100 GB ÷ 40 = 2.5 GB

2.5 GB 遠超過 100 MB,可以切更細。切成 500 個檔,每檔 200 MB:500 ≥ 40,200 MB ≥ 100 MB,兩個規則都滿足。

數字怎麼看:

  • 檔太少(例如只有 4 個):4 台機器各讀一個,平行度不夠,而且有一台讀完了其他還在讀
  • 檔太小(例如每檔 1 MB):又回到開檔開銷太大的問題,prefetch 一次抓不到多少東西
  • 官方說如果算出來每檔小於 10 MB,就要減少檔案數,在「平行度」和「單檔效率」之間取捨
TFRecords 打包:200 萬個 50 KB 小檔開檔要 11 小時,打包成 500 個 200 MB 大檔只要 10 秒;tf.train.Example 只有 BytesList、FloatList、Int64List 三種格子;每檔至少 100 MB、檔數至少主機數的 10 倍

怎麼寫、怎麼讀

寫:用 tf.io.TFRecordWriter,把每張照片包成 tf.train.Example、序列化、寫進去。200 萬張要轉,通常不會在一台機器上跑,而是用 Dataflow 這類批次處理服務平行轉(第 23 篇會比較 Dataflow 和 Dataproc)。

讀:tf.data.TFRecordDataset(檔案清單, num_parallel_reads=...)。num_parallel_reads 就是同時讀幾個檔,Cloud TPU 的效能指南直接點名這個參數是解決「TPU 在等資料」的方法。

為什麼要學

這是舊題庫最常見的情境之一:「大量圖片放在 Cloud Storage,用 TensorFlow 訓練,I/O 是瓶頸」,標準答案就是「轉成 TFRecord,用 tf.data 讀」。但新版考試更強調判斷:你要能說出為什麼小檔慢、檔要切多大、什麼情況不用轉。


5. 大型 CSV 也一樣:先切檔,再 interleave

筆記裡「大型 CSV:分割檔案+Parallel Interleave」這條,道理跟 TFRecord 完全一樣,只是方向相反:TFRecord 是「太多小檔要合併」,大 CSV 是「一個巨檔要拆開」。

CSV 是最常見的表格文字檔,每行一筆資料、欄位用逗號分開,Excel 可以直接開。

假設飲料店 5 年的銷售紀錄是一個 50 GB 的 CSV:

  • 一個檔:只能從頭讀到尾,一條線,interleave 沒有東西可以平行
  • 切成 100 個 500 MB 的檔:interleave 同時開 8 個、16 個檔讀,速度直接乘上去

tf.data 讀 CSV 有兩個工具,官方指南都有:

  • tf.data.experimental.make_csv_dataset:高階、方便,會自己猜欄位型態,支援一次給多個檔案、自動分批和打亂
  • tf.data.experimental.CsvDataset:低階、要自己指定每欄型態,但控制更細

另外一個思路:表格資料量真的很大,很多時候直接放進 BigQuery 比切 CSV 更省事,用 SQL 處理完再接訓練。BigQuery ML 第 15 篇會講,資料服務怎麼選第 23 篇會比。


6. TPU 特別要注意的事

TPU 算得比 GPU 更快,所以更容易輸入受限。Cloud TPU 效能指南把「輸入受限的模型」列為第一個效能問題,解法就是確保資料源源不絕地送進去:用 TFRecordDataset 的 num_parallel_reads 平行讀檔,加上 prefetch。

另外有一個 TPU 專屬的細節:批次大小。

  • 一顆 TPU 裝置(例如 v2-8、v3-8)有 8 個核心,TPU 會把一批資料平均切給 8 個核心。你設批次 128,每個核心拿到 128 ÷ 8 = 16 筆
  • 每個核心內部用的是 8 × 128 的向量暫存器在做矩陣乘法,所以官方建議批次大小要能被 8 或 128 整除
  • 記憶體放得下的話,用越大的批次越好

核心(core)可以想成「一顆晶片裡面有幾個獨立的工作單位」,8 核心就是 8 個人同時算。

套回例子:批次 64 可以被 8 整除,沒問題;如果設 100,100 ÷ 8 = 12.5,切不平均,效率會打折。


在 GCP 上怎麼做

1. 資料放哪裡:Cloud Storage 還是 BigQuery

Google 的訓練文件建議,以下情況把訓練資料放 Cloud Storage:

  • 非結構化資料:圖片、文字、影片
  • 已經是 TFRecord 這類格式的結構化資料
  • 很大的檔案,例如原始影片
  • 要做分散式訓練(多台機器一起)

Cloud Storage 是 Google 的雲端檔案儲存服務,存東西的單位叫 bucket(中文版文件叫「值區」),可以想成一個超大的雲端資料夾。

表格資料則通常放 BigQuery(Google 的資料倉儲,用 SQL 查詢),站上有一篇BigQuery 跟資料庫差在哪可以先看。

同一個區域:訓練程式碼需求文件明寫,要讀 Cloud Storage 讀得快,bucket 要放在跟訓練同一個區域(region,就是 Google 機房所在的地理位置,例如台灣 asia-east1)。資料在美國、訓練在台灣,等於廚房在台北、倉庫在洛杉磯。

2. 訓練程式怎麼讀 Cloud Storage:掛成資料夾

在 Agent Platform(原 Vertex AI,後面會講改名)跑無伺服器訓練時,Google 會用 Cloud Storage FUSE 把你的 bucket 掛載成訓練機器上的資料夾,路徑是 /gcs/你的bucket名稱/。

掛載(mount)就是把一個遠端的儲存空間接上來,讓程式用「開本機檔案」的方式讀它。對程式來說,/gcs/drink-ml/sealing/part-0001.tfrecord 跟硬碟上的檔案沒兩樣。

with open('/gcs/drink-ml/labels.csv', 'r') as f:
    lines = f.readlines()

好處(官方列的):

  • 資料是串流進訓練工作,不是先整包下載,啟動更快
  • 大檔案連續讀取的吞吐量高,分散式訓練也適合

官方的效能建議:

  • 檔案要大而少,減少查找和開檔的延遲(跟 TFRecord 的道理一樣)
  • 用分散式訓練把頻寬用滿
  • 常用的檔案開快取
  • 檢查點(checkpoint)和日誌寫本機硬碟,不要直接寫 Cloud Storage。檢查點是訓練中途存的模型進度,像遊戲存檔
  • 不要重新命名資料夾(這個操作在 Cloud Storage FUSE 不是一次完成的,中斷會留一半);不要沒事就 close() 或 flush(),每次都會真的傳一次檔案、產生費用

不想用掛載,也可以用 TensorFlow 的 tf.io.gfile.GFile 直接讀 gs:// 路徑,或 Cloud Storage 的 Python 客戶端。這些都支援 ADC(應用程式預設憑證),意思是程式自動拿到訓練工作的身分,不用在程式裡寫任何密碼或金鑰。

3. 資料太大放不進記憶體

官方文件〈載入大型資料集〉那段說得很直接:訓練機器的記憶體可能裝不下整份資料,這時要串流或分批讀。TensorFlow 的 tf.data.Dataset 可以直接從 Cloud Storage 串流 TFRecord 或文字資料,這就是這篇從頭講到現在的東西。

另一條路是多台機器做資料平行(每台只讀一部分),第 16 篇講分散式訓練時會展開。

4. 前處理太重、CPU 跟不上

四招全開之後 GPU 還是在等,問題可能變成 CPU 不夠:解碼 200 萬張 JPEG 本身就很花 CPU。兩個方向:

  • 訓練前先處理好:用 Dataflow 這類批次服務,把解碼、縮放做完存成 TFRecord,訓練時只剩「讀」
  • tf.data service:TensorFlow 的進階功能,把整條 tf.data 管線搬到另一群機器上跑,訓練機器只負責算。概念像把備餐廚房獨立出來,主廚房只負責炒

5. Vertex AI 改名了

Vertex AI 在 2026 年 4 月改名為 Gemini Enterprise Agent Platform(簡稱 Agent Platform),訓練相關的服務跟著改,官方對照表:

舊名稱新名稱
Vertex AI PlatformGemini Enterprise Agent Platform
Vertex AI TrainingGemini Enterprise Agent Platform Managed Training
Vertex AI Serverless TrainingGemini Enterprise Agent Platform Serverless Training
Vertex AI Training ClustersManaged Training Clusters on Gemini Enterprise Agent Platform

舊題庫寫「Vertex AI Training」「Vertex AI custom training」,現在叫 Agent Platform Managed Training 或 Serverless Training,做的事一樣:你給程式和資料,它幫你開機器、跑訓練、收模型。第 16 篇會專門講。


考試會怎麼考

Google Cloud Professional Machine Learning Engineer(PMLE,專業機器學習工程師) 證照,2026 年 6 月 1 日起的官方考試指南裡,這篇的內容對應到:

考試區塊跟這篇有關的項目
第 2 區:跨團隊管理資料與模型(約 16%)2.1 組織不同類型的資料(表格、文字、圖片),讓實驗、訓練、服務都有效率
第 3 區:把原型放大成 ML 模型(約 21%)3.2 在 Google Cloud 上組織訓練資料(Cloud Storage、BigQuery);把結構化、非結構化資料送進訓練管線;排除訓練失敗的問題。3.3 評估 CPU、GPU、TPU 等運算選項;GPU 和 TPU 上的分散式訓練

新版指南沒有直接寫出 TFRecord、prefetch 這些字,但「送進訓練管線」「排除訓練問題」「選加速器」這些項目,考題一定會用「訓練太慢」「GPU 使用率低」的情境來問。

PMLE 考試關鍵字:GPU 或 TPU 使用率低想到輸入管線瓶頸、幾百萬張小圖在 Cloud Storage 想到 TFRecords、一個超大 CSV 想到切檔加 interleave、TPU 在等資料想到 prefetch 和 num_parallel_reads、每輪重讀同樣資料想到 cache、資料和訓練不同區域想到搬到同一區

看到這些字,就想到這個

題目出現的關鍵字想到
「GPU/TPU 使用率低」「加速器閒置」「換更大的 GPU 沒變快」輸入管線瓶頸:prefetch、interleave、平行 map
「Profiler 顯示 input-bound」「在等資料」同上,先從 prefetch 開始
「幾百萬張小圖片放在 Cloud Storage」「I/O 是瓶頸」打包成 TFRecords+tf.data
「一個很大的 CSV 檔」「單一檔案」切成多個檔+parallel interleave
「TPU 在等資料」「TPU 輸入瓶頸」prefetch、TFRecordDataset 的 num_parallel_reads
「每一輪都重讀同樣的資料」「資料放得進記憶體」cache
「資料放不進記憶體」串流讀取,不要 cache;或多台機器資料平行
「前處理很重」「CPU 滿載」訓練前先用 Dataflow 處理好;或 tf.data service
「訓練機器和資料在不同區域」bucket 搬到同一個區域
「TPU 批次大小怎麼設」8 或 128 的倍數,記憶體放得下的最大值
「訓練很慢」但沒說 GPU 使用率先判斷是輸入受限還是運算受限,不要直接選 TFRecord

六個常見陷阱

  1. GPU 使用率低就換更大的 GPU:那是運算受限的解法,輸入受限換了也沒用,還更貴
  2. 看到「慢」就轉 TFRecord:官方明說不是必要,先確認瓶頸在讀資料、而且是小檔太多
  3. interleave 沒加 num_parallel_calls:只是輪流讀,不是同時讀,官方實測沒有加速
  4. cache 放在資料增強後面:每一輪看到的都是同一批增強結果,資料增強白做
  5. cache 放不進記憶體還硬放:記憶體爆掉訓練直接失敗。放不下就只快取讀檔那段,或事先處理好
  6. TFRecord 檔切太小或太少:太小回到開檔開銷問題,太少平行度不夠。記住「每檔 100 MB 以上、檔數是主機數 10 倍以上」

練習情境(自己出的練習,不是真實考題)

飲料店的封膜檢查模型用一張 GPU 訓練,200 萬張照片每張一個檔放在 Cloud Storage。工程師發現 GPU 使用率只有 25%,於是換成更高階的 GPU,使用率掉到 12%,總訓練時間幾乎沒變。應該怎麼做?

判斷過程:

  • 「GPU 使用率低、換 GPU 沒變快」→ 輸入受限,不是運算受限
  • 「200 萬個小檔在 Cloud Storage」→ 開檔開銷太大,打包成 TFRecords(每檔 100 MB 以上)
  • 用 tf.data 讀:interleave 平行開檔、map 平行前處理、最後 prefetch
  • 換回原本的 GPU 就夠了,省錢

同一家店要用 5 年的銷售紀錄(一個 50 GB 的 CSV)訓練需求預測模型,在 Agent Platform 上跑。讀資料非常慢,但 CPU 和 GPU 使用率都很低。應該怎麼做?

判斷過程:

  • 「一個 50 GB 的 CSV」→ 單一檔案只能一條線讀,切成多個檔(例如 100 個 500 MB)
  • 切完用 interleave 加 num_parallel_calls 平行讀
  • 確認 bucket 和訓練工作在同一個區域
  • 另一個合理選項:資料放進 BigQuery,用 SQL 處理後再訓練(第 15 篇)

團隊改用 TPU 訓練影像模型,資料已經是 TFRecord。TPU 的 profile 顯示大部分時間在等輸入。批次大小設 100。應該調什麼?

判斷過程:

  • 「TPU 在等輸入」→ TFRecordDataset 加 num_parallel_reads,管線尾端加 prefetch(AUTOTUNE)
  • 「批次 100」→ 100 不能被 8 整除,8 核心分不平均,改成 128 或 256(記憶體放得下的最大值)
  • 若前處理很重,考慮先用 Dataflow 處理好,或開 tf.data service

常見問答

訓練資料讀太慢怎麼辦?

先看 GPU 使用率。使用率低、忽高忽低,代表 GPU 在等資料,叫輸入受限,解法是改輸入管線:用 tf.data 的 prefetch 讓讀資料和訓練同時進行、interleave 平行開檔、map 加 num_parallel_calls 平行前處理、cache 快取第一輪讀過的資料。如果檔案又小又多,先打包成 TFRecords。使用率接近 100% 則是運算受限,要換更快的硬體或多台機器。

TFRecord 是什麼?

TFRecord 是 TensorFlow 的檔案格式,把很多筆資料一筆接一筆存成二進位紀錄,一個檔裡可以裝幾千、幾萬筆。每筆通常是一個 tf.train.Example,本質是「欄位名稱對應到值」的表,值只有 BytesList、FloatList、Int64List 三種型態。主要好處是把大量小檔合併成少量大檔,大幅減少開檔開銷,而且是二進位格式,讀的時候不用再轉換。

一定要把資料轉成 TFRecord 嗎?

不一定。TensorFlow 官方教學明說這些結構是選用的,除非你用 tf.data 而且確認「讀資料」是訓練瓶頸,否則不需要把現有程式改成 TFRecord。它解決的是「小檔太多、開檔開銷太大」這個特定問題;如果你的資料本來就是幾個大檔,或瓶頸在運算,轉了也不會變快。

tf.data 是什麼?跟直接用 Python 讀檔差在哪?

tf.data 是 TensorFlow 內建的輸入管線工具,你描述資料從哪來、要怎麼處理,它負責排程、開多執行緒、管理緩衝區。自己用 Python 迴圈讀檔是一筆做完才做下一筆,讀資料和訓練會互相等;tf.data 可以讓讀檔、前處理、訓練三件事同時進行,而且 prefetch、interleave、map 都可以設平行度,或用 AUTOTUNE 讓它自己調。

prefetch 是什麼?要設多少?

prefetch 是在 GPU 算這一批的時候,背景先把下一批讀好放在緩衝區。效果是一步的時間從「準備時間加訓練時間」變成「兩者取大的」。官方建議預先抓取的數量至少等於一個訓練步驟會消耗的批次數,實務上直接寫 prefetch(tf.data.AUTOTUNE) 讓 TensorFlow 在執行時動態調整就好。

interleave 和 map 的 num_parallel_calls 差在哪?

兩個都是「同時開幾條線」,但管的階段不同。interleave 的 num_parallel_calls 管「同時打開幾個檔案讀」,解決遠端儲存開檔慢、單檔頻寬小的問題;map 的 num_parallel_calls 管「同時對幾筆資料做前處理」,解決解碼、縮放只用到一顆 CPU 核心的問題。兩個都可以設 tf.data.AUTOTUNE。

cache 什麼時候不能用?

兩種情況。第一,資料處理後放不進記憶體或本機硬碟,例如 200 萬張 JPEG 解碼後變原始像素會大十幾倍,這時只能快取讀檔那段,或事先把資料處理好存檔。第二,cache 不能放在資料增強後面,因為資料增強的目的是每一輪看到的照片都略有不同,快取之後每輪都一樣,增強就白做了。

TFRecord 檔案要切多大、切幾個?

TensorFlow 官方的經驗法則:檔案數至少是同時讀資料的主機數的 10 倍,每個檔至少 10 MB,最好 100 MB 以上。例如 100 GB 資料用 4 台機器訓練,至少要 40 個檔;切成 500 個 200 MB 的檔兩個條件都滿足。檔太少平行度不夠,檔太小又回到開檔開銷太大的問題;如果算出來每檔不到 10 MB,就要減少檔案數。

大型 CSV 讀太慢怎麼辦?

一個巨大的 CSV 只有一個檔,不管開幾條線都只能排隊從頭讀。做法是先切成多個檔(例如 50 GB 切成 100 個 500 MB),再用 tf.data 的 interleave 加 num_parallel_calls 平行讀。tf.data 的 make_csv_dataset 可以一次接多個檔案。資料量真的很大時,另一個常見做法是直接放進 BigQuery 用 SQL 處理。

TPU 的批次大小為什麼要是 8 或 128 的倍數?

一顆 TPU 裝置有 8 個核心,會把一批資料平均切給 8 個核心,批次 128 每核心拿 16 筆;每個核心內部用 8 乘 128 的向量暫存器做矩陣乘法。所以 Cloud TPU 效能指南建議批次大小要能被 8 或 128 整除,而且在記憶體放得下的前提下用最大的批次。設 100 這種數字會切不平均,效率打折。

訓練資料放 Cloud Storage 怎麼讀最快?

四件事:bucket 和訓練工作放同一個區域;檔案大而少(打包成 TFRecord);用 tf.data 平行讀取加 prefetch;用分散式訓練把頻寬用滿。在 Agent Platform 上跑無伺服器訓練時,bucket 會用 Cloud Storage FUSE 掛載在 /gcs/ 底下,程式像讀本機檔案一樣讀。檢查點和日誌建議寫本機硬碟,不要直接寫 Cloud Storage。

Vertex AI Training 改名了嗎?

是。Vertex AI 在 2026 年 4 月改名為 Gemini Enterprise Agent Platform,Vertex AI Training 改叫 Gemini Enterprise Agent Platform Managed Training,Vertex AI Serverless Training 改叫 Gemini Enterprise Agent Platform Serverless Training。舊題庫看到 Vertex AI Training 或 custom training,就是現在的 Agent Platform Managed Training,功能一樣。


重點整理

  • 先分清楚兩種慢:GPU 使用率低是輸入受限(在等資料),接近 100% 是運算受限。輸入受限換 GPU 沒用
  • tf.data 四招:prefetch 讓讀資料和訓練重疊(一步時間從相加變取大)、interleave 加 num_parallel_calls 平行開檔、map 加 num_parallel_calls 平行前處理、cache 快取第一輪讀過的資料。全部可以用 AUTOTUNE
  • 算一次:傻做法 0.6+0.3+0.4=1.3 秒;prefetch 後 max(0.9, 0.4)=0.9 秒;四招全開 max(0.225, 0.4)=0.4 秒,快 3.25 倍、GPU 使用率 31% → 100%
  • TFRecords:把大量小檔打包成少量大檔,省掉開檔開銷;每檔 100 MB 以上、檔數是主機數的 10 倍以上;官方明說不是必要,先確認瓶頸
  • 大 CSV 反過來:一個巨檔要先切成多檔,interleave 才有東西可以平行
  • TPU:更容易輸入受限,用 num_parallel_reads+prefetch;批次大小是 8 或 128 的倍數
  • GCP 上:資料放 Cloud Storage,bucket 跟訓練同一區域;Agent Platform 用 Cloud Storage FUSE 掛在 /gcs/;Vertex AI Training 現在叫 Agent Platform Managed Training

延伸閱讀

本系列

站上相關文章


資料整理好,也要餵得快,GPU 的錢才花得值。如果你想有系統地從雲端基礎一路學到在 GCP 上動手做機器學習,可以看看東東的 GCP 課程,或加 LINE 聊聊你現在的狀況,一起找出最適合你的學習順序。

Table of Contents
返回頂端