LSTM 是吃「序列」的模型,輸入永遠是三維:(批次大小, 時間步數, 特徵數)——一次餵幾筆、每筆看幾個時刻、每個時刻量幾個值。本頁用 TensorFlow 實跑:答案 A 的 (32, 24, 5) 直接 predict 出 32 個預測;更把 B、C、D 三個錯 shape 真的餵進去——C、D 當場報錯,B 竟然不報錯,默默給你 24 個預測而不是 32 個。「沒報錯」不等於「餵對了」,這是本頁最重要的一課。
以最近 24 個時間步、每步 5 個特徵建立 LSTM,並一次送入 32 筆序列。送入 model 的 X_batch 正確 shape 為何?
import numpy as np # 拿出陣列工具,取小名 np from tensorflow.keras import Sequential # 「一層接一層」的模型容器 from tensorflow.keras.layers import Dense, Input, LSTM # 三種積木層 X_batch = np.zeros((32, 24, 5), dtype=np.float32) # 32 筆 × 24 步 × 5 特徵的資料 model = Sequential([ # 開始疊模型(中括號=清單) Input(shape=(24, 5)), # 宣告每一筆長什麼樣(沒有 32!) LSTM(16), # 循序讀 24 步,吐 16 維摘要 Dense(1) # 摘要 → 1 個預測值 ]) # 疊完收工
想像一家醫院的加護病房:32 位病人,每位手上有一份「最近 24 小時」的紀錄表,表上每小時量 5 個生命徵象(心跳、血壓、呼吸、血氧、體溫)。把這疊表格原封不動變成一個陣列,就是 X_batch:
最外層數「幾筆」(32 份病歷)→ 中層數「幾步」(24 個時刻)→ 最內層數「幾個值」(5 個徵象)。寫成 shape 就是 (32, 24, 5)——從外往內、由大到小地念。LSTM 拿到後,會替每一筆病歷沿著 24 個時刻依序讀,一步一步更新記憶,最後給出預測。
點擊後出現漸進式說明:白話說明 → 說清楚一點 → 常見錯誤與考點。
點擊後出現漸進式說明。
九行,一行一行走完。右上角的「看位置」可以把這一行放回完整程式裡看。
import numpy as np # 整箱搬進來,取小名 np
numpy 是 Python 的陣列工具箱,as np 幫它取慣用小名。本題用它做一件事:造出那箱 (32, 24, 5) 的資料——深度學習的資料容器幾乎都從 numpy 陣列出發。
from tensorflow.keras import Sequential # 模型容器:一層接一層 from tensorflow.keras.layers import Dense, Input, LSTM # 三種積木層一次拿齊
Sequential 是「積木直直疊」的模型容器:資料從第一層流到最後一層。layers 抽屜裡拿三塊積木:Input(宣告入口的形狀)、LSTM(會沿時間讀的循環層)、Dense(全連接層,收尾用)。
一次 import 多件用逗號隔開——跟前幾頁 sklearn 的寫法一樣,只是這次的工具箱換成 TensorFlow 的 Keras。
X_batch = np.zeros((32, 24, 5), dtype=np.float32) # 全 0 的 32 筆 × 24 步 × 5 特徵
np.zeros(shape) 造出一箱全是 0 的陣列,shape 用元組 (32, 24, 5) 指定——這行就是答案 A 本人:最外層 32 筆序列、每筆 24 個時間步、每步 5 個特徵。dtype=np.float32 指定單精度浮點數——深度學習的慣用精度(省一半記憶體、GPU 友善)。
為什麼是全 0?考題只關心「形狀對不對」,內容是什麼無所謂——像搬家先確認紙箱尺寸,裡面先塞報紙也行。
model = Sequential([ # 開始疊:中括號裡放「層的清單」(括號先不關)
呼叫 Sequential([...]),把成品貼上 model 的名牌。注意是小括號包中括號:小括號是呼叫、中括號是「層的清單」——清單的順序就是資料流動的順序。括號沒關,第 5 到 9 行是同一句話。
Input(shape=(24, 5)), # 每一筆長 (24, 5)——批次維不寫
Input(shape=(24, 5)) 宣告的是「每一筆」長什麼樣:24 步 × 5 特徵。批次大小 32 不寫進模型——batch 維永遠留白(summary 裡顯示 None),因為「一次餵幾筆」是餵資料的人臨時決定的:實跑同一個模型,餵 1 筆得 (1, 1)、餵 7 筆得 (7, 1)、餵 500 筆得 (500, 1),全都通。
LSTM(16), # 循序讀 24 個時間步,最後吐一條 16 維摘要
LSTM 對每一筆序列從第 1 步讀到第 24 步,一路更新自己的記憶;16 是單元數(units)——記憶與輸出的維度。預設只回最後一步的輸出,所以 32 筆進去、出來是 (32, 16):每筆一條 16 維摘要(時間軸被讀掉了)。
return_sequences=True,24 步的輸出全保留,變 (32, 24, 16)——疊第二層 LSTM 時就要開這個。Dense(1) # 16 維摘要 → 1 個預測值 ]) # 中括號、小括號依序關上,模型疊完
Dense(1) 把 16 維摘要加權成 1 個數字(例如「下一小時的用電量」)——參數 16 個權重+1 個偏置=17 個。整條旅程:(32, 24, 5) → LSTM(16) → (32, 16) → Dense(1) → (32, 1),實跑 model.predict(X_batch) 得到的正是 (32, 1):32 筆各一個預測。
整個模型的參數共 1,408 + 17 = 1,425 個——model.summary() 印出來的 Total params 就是這個數字。
三維陣列就是「箱子裡有盒子、盒子裡有格子」。點下面的三顆按鈕,看每個數字管到哪一層:
reshape 成 (24, 32, 5) 是硬把格線重畫(實跑:原本第 3 筆第 10 步的值 31002,reshape 後跑到別人家變 131102)——資料全亂了但程式不報錯。真要交換軸,用的是 transpose(實跑:transpose(1, 0, 2) 後同一個值原封不動搬到新位置)。但本題根本不該換——照 (幾筆, 幾步, 幾個特徵) 的約定放好,才是唯一正解。考題只問哪個對;本站把四個 shape 全部實跑 model.predict(),下場分三種——其中最值得記的,是那個不報錯的錯:
InvalidArgumentError:最後一軸的 24 個「特徵」撞上 [5, 64] 的權重矩陣(5 個特徵 × 4 個閘門 × 16 單元=64——錯誤訊息裡直接看得到模型的解剖構造)。D → 當場 ValueError:LSTM 要三維,(32, 120) 只有二維。B → 不報錯:時間步維是動態的,模型把 24 當「筆數」、32 當「步數」,默默回傳 (24, 1)——你要 32 個預測,它給 24 個,而且每一個都是用錯的切法算的。assert X_batch.shape == (32, 24, 5);② 餵之後檢查輸出筆數等於你送進去的筆數。這也是為什麼考題愛考 shape——它是深度學習裡最常見、又最不會自己喊痛的 bug。題目說「最近 24 個時間步」——實務上你手上是一條長長的感測紀錄(例如 100 個小時 × 5 個欄位),要自己切成一筆一筆的 24 步視窗:從第 1 小時開始框 24 小時、往右滑 1 步再框一次⋯⋯
(32, 24, 5) 只是起點。資料在模型裡每過一層,shape 就變一次——考題也愛考中途站:
(None, 16)、Dense 層輸出 (None, 1)——那個 None 就是留白的批次維(第 6 行的伏筆)。Total params: 1,425(LSTM 1,408 + Dense 17)。參數公式 4 × (units×features + units² + units):units 8→448、16→1,408、32→4,864、64→17,920——全部與實跑相符,一個不差。選項 D 不是亂編的——24 × 5 = 120,它是「把一筆的時間表攤平成一排」的結果。攤平之後的世界屬於 MLP(多層感知機):
mlp = Sequential([Input(shape=(120,)), Dense(1)]) # MLP:一筆就是一排 120 個數字 mlp.predict(np.zeros((32, 120))) # (32, 120) 在這裡完全合法 → 輸出 (32, 1)
本站實跑:這個 MLP 吃 (32, 120) 完全沒問題;在 LSTM 模型前面加一層 Flatten(),也能把 (32, 24, 5) 攤成 120 維再接 Dense(該 Dense 的參數是 120 + 1 = 121,實跑相符)。所以 D 錯的點不是「120 算錯」,是「餵錯了對象」:本題的模型第一層是 LSTM——它沿著時間軸一步一步讀,攤平等於把 24 個時刻的先後順序拆掉,LSTM 就沒有「時間」可讀了。
(幾筆, 幾步, 幾個特徵)=(batch, timesteps, features)——32 筆序列、每筆 24 個時間步、每步 5 個特徵,跟 Input(shape=(24, 5)) 的宣告嚴絲合縫(batch 維由餵的人決定)。實跑 model.predict(X_batch) 輸出 (32, 1):32 筆各一個預測。程式第 4 行 np.zeros((32, 24, 5)) 就是答案本人。
批次與時間步對調。實跑竟然不報錯——時間步維是動態的,模型把 24 當筆數、32 當步數,默默回傳 (24, 1):你要 32 個預測它給 24 個,每個都用錯的切法算。這種錯不會自己喊痛,得靠 assert X.shape == (32, 24, 5) 和「輸出筆數對不對」自己抓。
時間步與特徵對調——變成「5 個時間步、每步 24 個特徵」。實跑當場 InvalidArgumentError:Matrix size-incompatible: In[0]: [32,24], In[1]: [5,64]——24 個「特徵」撞上為 5 個特徵打造的權重矩陣(5 × 64,64 = 4 閘門 × 16 單元)。特徵數是模型蓋好時就焊死的,對不上就炸。
24 × 5 = 120,把每筆的時間表攤成一排——那是 MLP 的吃法(實跑 Input(shape=(120,)) 的模型吃它完全合法)。但 LSTM 要三維:實跑當場 ValueError: Invalid input shape ... incompatible shape (32, 120)。攤平把 24 個時刻的先後順序拆掉,LSTM 就無時間可讀——選了 D,等於否定了用 LSTM 的理由。
再看一次同一段程式。這次你知道三個數字各管哪一層了。
以最近 24 個時間步、每步 5 個特徵建立 LSTM,並一次送入 32 筆序列。送入 model 的 X_batch 正確 shape 為何?
X_batch = np.zeros((32, 24, 5), dtype=np.float32) # (幾筆, 幾步, 幾個特徵) model = Sequential([ # 疊模型 Input(shape=(24, 5)), # 每一筆的形狀(batch 不寫) LSTM(16), # (32,24,5) → (32,16) Dense(1) # (32,16) → (32,1) ]) # 收工
八題,全部都是本題的延伸。答錯會直接告訴你錯在哪。
assert X.shape == (32, 24, 5)+檢查輸出筆數。return_sequences=True 保留每一步 → (32, 24, 16)(疊第二層 LSTM 必開);後面接 Dense(1) 分別得 (32, 1) 與 (32, 24, 1)——全為實跑。「LSTM 輸入 shape」是中級科目三深度學習的高頻考點,而且問法變化不大。最常見的六種:① 給情境問 X 的 shape(本題這種——按「幾筆、幾步、幾個特徵」排就對);② 問 Input(shape=...) 該填什麼(不含批次維,本題 (24, 5));③ 問 LSTM 層的輸出 shape(預設 (batch, units);return_sequences=True 時 (batch, timesteps, units));④ 問參數量(4 × (units×features + units² + units));⑤ 問長度 T 的序列能切幾個 W 步視窗(T − W + 1);⑥ 問哪些模型吃三維輸入(RNN 家族;MLP 吃二維、CNN 影像吃四維)。一句口訣:(幾筆, 幾步, 幾個特徵)——批次不進模型、時間不能攤平、特徵焊在模型裡。
由外往內數:最外層是「幾筆」(一次送幾份資料)、中層是「幾步」(每份資料有幾個時刻)、最內層是「幾個特徵」(每個時刻量幾個值)。生活版:32 份病歷 × 每份 24 小時 × 每小時 5 個生命徵象。技術名:(batch_size, timesteps, features)——Keras 的 RNN 家族(SimpleRNN/LSTM/GRU)都吃這個順序。反著驗算也行:題目給「24 個時間步、5 個特徵」→ Input(shape=(24, 5));前面補上批次 32 → (32, 24, 5)。注意順序錯了不一定報錯(見下面第三題),所以要用「約定」記,不能用「跑跑看」試。
因為「一次餵幾筆」不是模型的性質,是餵資料的人臨時的決定。模型蓋好時只需要知道「每一筆長什麼樣」(24 步 × 5 特徵),批次維永遠留白——model.summary() 裡顯示 (None, 16)、(None, 1),那個 None 就是留白的位置。本站實跑同一個模型:餵 (1, 24, 5) 得 (1, 1)、餵 (7, 24, 5) 得 (7, 1)、餵 (500, 24, 5) 得 (500, 1)——全部成功。這也是考題的雙生題:問 X_batch 答 (32, 24, 5)、問 Input 的 shape 參數答 (24, 5),差別就在含不含批次。
不一定——這是本頁最重要的實跑發現。C (32, 5, 24):特徵數對不上(24 撞上為 5 個特徵打造的 [5, 64] 權重矩陣)→ 當場 InvalidArgumentError。D (32, 120):維度數不對(LSTM 要 3 維)→ 當場 ValueError。但 B (24, 32, 5):特徵數 5 對得上、時間步維又是動態的(模型不檢查你送幾步)→ 完全不報錯,默默回傳 (24, 1)——把 24 當筆數、32 當步數,每個預測都用錯的切法算。結論:報錯的 shape 錯是小事,不報錯的 shape 錯才是大事。防身術:餵之前 assert shape、餵之後對輸出筆數。
用滑動視窗:手上是一條長 T 的連續紀錄(例如 100 小時 × 5 欄),從頭框住 24 步做第 1 筆、往右滑 1 步再框做第 2 筆⋯⋯能切出 T − W + 1 筆(實跑:T=100、W=24 → 77 筆,疊成 (77, 24, 5))。每筆視窗通常配一個標籤(例如「第 25 小時的值」)做監督式訓練。訓練時不會 77 筆全下,而是每輪抽一把(例如 32 筆)——這一把叫一個 batch,(32, 24, 5) 的 32 就是這樣來的。切完視窗後的訓練/測試切分還有時間順序的講究(不能隨機洗),見站內「時間序列切分」頁。
16 是 units(單元數)——LSTM 記憶向量與輸出向量的維度,可以想成「摘要的欄位數」。它不是時間步數、也不是特徵數,純粹是你決定的模型容量。參數公式:LSTM 有 4 組閘門(遺忘、輸入、候選、輸出),每組都有「吃輸入的權重 units×features、吃自己上一步輸出的權重 units×units、偏置 units」——合計 4 × (16×5 + 16×16 + 16) = 4 × 352 = 1,408。本站實跑 units=8/16/32/64 → 448/1,408/4,864/17,920,全部與公式相符。注意 units² 那一項:units 翻倍、參數約四倍——容量是平方成長的。
預設(False)LSTM 只回最後一步的輸出:(32, 24, 5) → (32, 16)——適合「整段看完給一個結論」的任務(預測下一小時、分類整段序列)。開 True 則每一步的輸出都保留:→ (32, 24, 16)——兩個場合必開:① 疊第二層 LSTM(下一層也要吃 3 維序列);② 每一步都要一個預測(序列標註)。本站實跑:rs=True 後面接 Dense(1),輸出變 (32, 24, 1)——Dense 對每一步各算一次。考題愛問「兩層 LSTM 疊在一起,第一層要設什麼」——答案就是 return_sequences=True。
看資料的天生結構:MLP 吃 2 維 (batch, features)——每筆就是一排數字,沒有空間或時間結構(本站實跑 Input(shape=(120,)) 的 MLP 吃 (32, 120) 完全合法,這正是選項 D 的世界)。RNN/LSTM/GRU 吃 3 維 (batch, timesteps, features)——多出來的中間軸是「時間」,模型沿著它一步步讀。CNN(影像)吃 4 維 (batch, 高, 寬, 通道)——多出來的是空間兩軸加色彩通道。把 (32, 24, 5) 攤平成 (32, 120) 餵 MLP 不會報錯、有時也能得到堪用的模型,但等於宣告「順序不重要」——會用 LSTM,就是因為你相信時間順序有訊息。