2026年8月23日 星期日

PyTorch vs Keras 核心架構對照表

 一、 兩大框架之核心設計哲學與物理映射表

「動態計算圖(PyTorch)」與「靜態/宣告式 API(Keras/TensorFlow)」。

【 深度學習框架設計哲學對立面 】

物理維度 PyTorch (Imperative / Dynamic) Keras (Declarative / Functional)
物理本質 動態計算圖 (Eager Execution) 宣告式封裝 (Engine Abstraction)
控制核心 明確參數導向 (Tensor-level) 層級抽象導向 (Layer-level)
執行流程 手動控制 Loop, 自由度高 高階 fit() 封裝, 速度與易用平衡

二、 核心對照變數物理映射表 (Scientific Alignment Map)

下表為 PyTorch Keras 在模型建構、參數控制與訓練上的 1-to-1 科學對照:

比較維度 PyTorch (物件/參數導向) Keras / TensorFlow (層級/宣告導向)
線性映射層 nn.Linear(in_features, out_features) layers.Dense(units)
卷積層 nn.Conv2d(in_channels, out_channels, ...) layers.Conv2D(filters, kernel_size, ...)
池化層 nn.MaxPool2d(kernel_size) layers.MaxPooling2D(pool_size)
結構容器 nn.Sequential 或繼承 nn.Module Sequential 或 Functional API (Model)
凍結核心屬性 參數張量屬性 parameter.requires_grad = False 層級/模型屬性 layer.trainable = False
訓練循環 手動撰寫 loss.backward()opt.step() 宣告式 model.compile() + model.fit()
權重獲取 model.state_dict()model.parameters() model.get_weights()

三、 深入對位解構 (Deep Architectural Alignment)

1. 模型結構與線性層物理映射 (nn.Linear    vs    layers.Dense)

線性層的數學本質為矩陣相乘與偏置相加: Y = X x W + B

🔬 PyTorch 介面實作:

  • 物理特性:權重矩陣 W 的形狀是 (out_features, in_features),在內部進行矩陣乘法時,PyTorch 會自動將輸入 X 與 W 的轉置相乘: X x W.T + B
  • 類別導向定義: (Neural Network建築模型材料庫)
import torch
import torch.nn as nn

# 宣告線性層:輸入維度 50,輸出維度 10
py_linear = nn.Linear(in_features=50, out_features=10)

# 直接存取權重參數張量
print(py_linear.weight.shape)  # 輸出: torch.Size([10, 50])
print(py_linear.bias.shape)    # 輸出: torch.Size([10])

🔬 Keras 介面實作:

  • 物理特性:權重矩陣 W 的形狀是 (in_features, out_features)。Keras 直接執行 X x W + B。它不需要在初始化時顯式指定 in_features,而是會在第一次前向傳播(傳入數據)時自動推導輸入維度。
  • 類別導向定義
from tensorflow import keras
from tensorflow.keras import layers

# 宣告 Dense 層:僅需指定輸出單元數 10
keras_dense = layers.Dense(units=10)

# 注意:在未建立/未傳入數據前,Keras 的權重並未初始化 (避免維度硬編碼)
# 傳入虛擬數據進行建置
keras_dense.build(input_shape=(None, 50))
print(keras_dense.weights[0].shape)  # 輸出: (50, 10) -> 權重矩陣
print(keras_dense.weights[1].shape)  # 輸出: (10,)    -> 偏置向量

2. 凍結語句與參數控制 ( requires_grad vs trainable )

這就是造成 AttributeError 的核心根源。

【 凍結機制之物理路徑對比 】

◆ PyTorch (從 Tensor 屬性阻斷)
model.features (nn.Sequential)parameters() 生成器[Parameter Tensor (Weight)]requires_grad = False (Autograd 引擎跳過梯度計算)

Keras (從 Layer 容器狀態標記)
model.layers (Layer List)layer.trainable = False[Layer Object]在 compile() 時,將該層所有權重移出可訓練變數列表 (trainable_weights)

❌ 混淆陷阱除錯 (Error Diagnostics)

當我們嘗試在 PyTorchConv2d 物件上直接寫 layer.trainable = False 時:

  • PyTorch 執行期反饋
    AttributeError: 'Conv2d' object has no attribute 'trainable'
  • 根因分析:PyTorch 的 nn.Module(Conv2d 的父類別)只維護一個 _parameters 字典和一個 _modules 字典,它沒有設計 trainable 這個屬性來管理狀態。
  • PyTorch 正確凍結語法
for param in model.features.parameters():
    param.requires_grad = False

❌ 反向混淆陷阱 (Keras 側)

若在 Keras 的 Layer 上嘗試修改屬性 layer.requires_grad = False

  • 運行回饋:Keras 的 Layer 對象並不會報錯,但完全不起作用。因為 Keras 的底層引擎在呼叫 model.compile() 時,只會去檢查各層的 .trainable 屬性。

3. 訓練核心與優化器控制 (Autograd vs Compile)

🔬 PyTorch 的「顯式物理控制」:

PyTorch 將前向傳播、損失計算、反向傳播與參數更新完全暴露給開發者。優化器只負責更新傳入給它的那組參數。

# 1. 篩選出未被凍結的參數,送入優化器
optimizer = torch.optim.SGD(
    filter(lambda p: p.requires_grad, model.parameters()),
    lr=0.01
)

# 2. 訓練迴圈手動控制
optimizer.zero_grad()        # 1. 清空舊梯度
outputs = model(inputs)      # 2. 前向傳播
loss = criterion(outputs, y) # 3. 計算損失
loss.backward()              # 4. 反向傳播 (僅對 requires_grad=True 的參數計算梯度)
optimizer.step()             # 5. 更新權重

🔬 Keras 的「宣告式引擎控制」:

Keras 將底層細節隱藏在 C++ 引擎中。開發者只需宣告優化器與損失函數,並由 fit() 執行高階優化。

# 1. 凍結特定層
model.get_layer("block1_conv1").trainable = False

# 2. 編譯模型 (此步驟會鎖定哪些權重可以被更新)
model.compile(
    optimizer=keras.optimizers.SGD(learning_rate=0.01),
    loss='sparse_categorical_crossentropy'
)

# 3. 啟動訓練,引擎內部自動處理梯度與更新
model.fit(x_train, y_train, epochs=5)

四、 總結:Feynman 專家級記憶口訣

  • PyTorch 是「泥水匠」:你得親自走到每個「水泥磚(Tensor)」面前,把「要不要抹水泥(requires_grad)」的開關關掉。你對磚頭(參數)直接發言。
  • Keras 是「設計師」:你只需對「房間(Layer)」掛上「請勿施工(trainable = False)」的牌子,施工隊(compile)在進場時看到牌子,就會自動繞過整個房間。你對房間(層)發言。