TensorFlow 2.x 核心 API 與模型構建 TensorFlow 是一個強大的開源機器學習庫,尤其在深度學習領域應用廣泛。TensorFlow 2.x 在易用性和效率方面做了大量改進,引入了Keras作為其高級API,使得模型構建和訓練更加直觀和便捷。本文將介紹 TensorFlow 2.x 的核心 API 以及如何使用它們來構建和訓練一個深度學習模型。 一、 TensorFlow 2.x 的核心理念 TensorFlow 2.x 的核心理念是: 易用性 (Ease of Use): 通過Keras作為首選的高級API,簡化了模型的開發流程。 聲明式編程 (Declarative Programming): 允許開發者定義計算圖,但通過Eager Execution(即時執行)模式,使得構建和調試更加直觀,類似于Python的命令式編程。 端到端 (End-to-End): 支持從數據準備、模型訓練到模型部署的完整流程。 跨平臺 (Cross-Platform): 可以在CPU、GPU、TPU以及服務器、桌面、移動設備等多種平臺上運行。 二、 TensorFlow 2.x 的核心 API TensorFlow 2.x 的API龐大且功能全面,但以下幾個是構建和訓練模型最常用的核心部分: 2.1 tf.keras:高級 API tf.keras 是TensorFlow 2.x推薦并集成的首選高級API,它封裝了模型構建、層定義、損失函數、優化器、評估指標等常用功能,提供了一套面向對象且易于使用的接口。 模型 (tf.keras.Model 和 tf.keras.Sequential): tf.keras.Sequential: 用于構建線性的、堆疊的層模型。非常適合順序結構的網絡。 tf.keras.Model: 更靈活的API,可以構建復雜的、具有多輸入/輸出、共享層、多分支的網絡結構。通過子類化(subclassing)tf.keras.Model 來定義。 層 (tf.keras.layers.*): 提供了構建神經網絡的基本單元,如 Dense (全連接層), Conv2D (卷積層), MaxPooling2D (池化層), Flatten (展平層), Dropout (正則化層), BatchNormalization (批歸一化層) 等。 每一層都有其可訓練的權重(kernel 和 bias)。 損失函數 (tf.keras.losses.*): 定義了模型預測與真實標簽之間的差距,如 CategoricalCrossentropy, SparseCategoricalCrossentropy, MeanSquaredError。 優化器 (tf.keras.optimizers.*): 實現了各種梯度下降的變種,用于更新模型的權重,如 Adam, SGD, RMSprop。 指標 (tf.keras.metrics.*): 用于評估模型的性能,如 Accuracy, Precision, Recall, AUC。 2.2 tf.data:數據處理管道 tf.data API 提供了一種高效、靈活地構建輸入數據管道的方式,能夠處理大規模數據集,并與 tf.keras 無縫集成。 創建數據集: 可以從NumPy數組、TensorFlow張量、CSV文件、TFRecords等多種數據源創建 tf.data.Dataset 對象。 數據轉換: map(): 對數據集中的每個元素應用一個函數(如數據增強、特征工程)。 shuffle(): 隨機打亂數據集,通常在訓練開始前使用。 batch(): 將數據集中的元素分組打包成批。 prefetch(): 在模型訓練時,預先加載下一個批次的數據,避免CPU/GPU等待。 cache(): 將數據集內容緩存到內存或本地文件中,加快重復訪問的速度。 2.3 tf.Tensor:張量(Tensors) 張量是 TensorFlow 的核心數據結構,類似于 NumPy 的數組。它們是多維數組,可以存儲標量、向量、矩陣,乃至更高維度的數據。 創建張量: tf.constant(): 創建一個不可更改的張量。 tf.Variable(): 創建一個可更改的張量,通常用于存儲模型的可訓練權重。 張量操作: TensorFlow 提供了豐富的張量運算函數,如 tf.add, tf.multiply, tf.matmul, tf.reduce_sum, tf.reshape 等。 Eager Execution: 在 TensorFlow 2.x 中,張量操作會立即執行并返回結果,這使得調試和交互式開發非常方便。 2.4 自動微分 (tf.GradientTape) 自動微分是深度學習模型訓練的關鍵。TensorFlow 2.x 使用 tf.GradientTape API 來記錄計算過程,并計算損失函數關于模型變量的梯度。 三、 使用 tf.keras 構建模型 有兩種主要方式構建 tf.keras 模型: 3.1 順序模型 (tf.keras.Sequential) 適用于線性堆疊的層,非常簡單直觀。 步驟: 創建一個 tf.keras.Sequential 實例。 通過 add() 方法將層依次添加到模型中。 最后,編譯模型(指定優化器、損失函數、評估指標)。 使用 fit() 方法訓練模型。 示例:構建一個簡單的全連接網絡進行MNIST圖像分類 <PYTHON> import tensorflow as tf from tensorflow import keras from tensorflow.keras import layers # 1. 定義模型 model = keras.Sequential([ # 輸入層:展平28x28的圖像為784維的向量 layers.Flatten(input_shape=(28, 28), name='input_layer'), # 第一個隱藏層:全連接層,256個神經元,ReLU激活函數 layers.Dense(256, activation='relu', name='hidden_layer_1'), # Dropout層:防止過擬合,以0.2的比例丟棄神經元 layers.Dropout(0.2), # 輸出層:全連接層,10個神經元(對應0-9數字),softmax激活函數,輸出概率分布 layers.Dense(10, activation='softmax', name='output_layer') ]) # 2. 編譯模型 model.compile(optimizer=keras.optimizers.Adam(learning_rate=0.001), loss=keras.losses.SparseCategoricalCrossentropy(), # MNIST標簽是整數,使用SparseCategoricalCrossentropy metrics=['accuracy']) # (假設已加載并預處理好MNIST數據集: train_images, train_labels, test_images, test_labels) # 例如: (train_images, train_labels), (test_images, test_labels) = keras.datasets.mnist.load_data() # 需要將像素值歸一化到 [0, 1] train_images = train_images.astype('float32') / 255.0 test_images = test_images.astype('float32') / 255.0 # 3. 訓練模型 history = model.fit(train_images, train_labels, epochs=10, # 訓練輪數 batch_size=32, # 每個批次的大小 validation_split=0.2) # 從訓練數據中劃分20%作為驗證集 # 4. 評估模型 test_loss, test_acc = model.evaluate(test_images, test_labels, verbose=2) print(f'\nTest accuracy: {test_acc}') # (可選)進行預測 # predictions = model.predict(test_images[:5]) # print(f'\nPredictions for first 5 test images:\n {predictions}') 3.2 函數式 API (tf.keras.Model 子類化) 適用于構建更復雜的模型,如多輸入、多輸出、共享層、非線性連接的模型。 步驟: 創建一個類,繼承自 tf.keras.Model。 在 __init__ 方法中定義模型所需的層。 在 call() 方法中實現模型的前向傳播邏輯,定義數據如何通過這些層。 實例化該類,然后編譯和訓練。 示例:構建一個更復雜的模型(例如,帶殘差連接) <PYTHON> import tensorflow as tf from tensorflow import keras from tensorflow.keras import layers # 定義一個可以重用的殘差塊 def residual_block(x, filters, kernel_size=3): # 存儲輸入,以便進行殘差連接 shortcut = x # 第一個卷積層 x = layers.Conv2D(filters, kernel_size, padding='same')(x) x = layers.BatchNormalization()(x) x = layers.Activation('relu')(x) # 第二個卷積層 x = layers.Conv2D(filters, kernel_size, padding='same')(x) x = layers.BatchNormalization()(x) # 殘差連接:如果輸入和輸出的特征維度不匹配,需要通過1x1卷積進行轉換 if shortcut.shape[-1] != filters: shortcut = layers.Conv2D(filters, (1, 1), padding='same')(shortcut) shortcut = layers.BatchNormalization()(shortcut) # 激活函數 x = layers.add([x, shortcut]) x = layers.Activation('relu')(x) return x # 定義主模型 class ComplexModel(keras.Model): def __init__(self, num_classes=10): super(ComplexModel, self).__init__() # 輸入層 - 假設輸入尺寸為 (height, width, channels) self.conv1 = layers.Conv2D(32, 3, activation='relu', padding='same', input_shape=(32, 32, 3)) self.pool1 = layers.MaxPooling2D((2, 2)) # 第一個殘差塊 self.res1 = residual_block(32, 32) # 32通道 # 第二個殘差塊(特征通道加倍) self.res2 = residual_block(32, 64) # 64通道 self.pool2 = layers.MaxPooling2D((2, 2)) # 展平層 self.flatten = layers.Flatten() # 全連接層 self.dense1 = layers.Dense(128, activation='relu') # 輸出層 self.dropout = layers.Dropout(0.5) self.output_dense = layers.Dense(num_classes, activation='softmax') def call(self, inputs, training=False): # training參數用于控制Dropout等層的行為 x = self.conv1(inputs) x = self.pool1(x) x = self.res1(x) x = self.res2(x) x = self.pool2(x) x = self.flatten(x) x = self.dense1(x) if training: # 只在訓練時應用Dropout x = self.dropout(x) return self.output_dense(x) # 實例化模型 complex_model = ComplexModel(num_classes=10) # 編譯模型 complex_model.compile(optimizer=keras.optimizers.Adam(learning_rate=0.001), loss=keras.losses.SparseCategoricalCrossentropy(), metrics=['accuracy']) # (假設已加載并預處理好CIFAR-10數據集) # (train_images, train_labels), (test_images, test_labels) = keras.datasets.cifar10.load_data() # ... 數據預處理 ... # 訓練模型 # history = complex_model.fit(train_images, train_labels, epochs=20, batch_size=64, validation_split=0.2) # 評估模型 # test_loss, test_acc = complex_model.evaluate(test_images, test_labels, verbose=2) # print(f'\nTest accuracy: {test_acc}') 四、 數據處理管道 tf.data 使用 tf.data 可以高效地準備訓練數據。 示例:構建MNIST數據集的 tf.data 管道 <PYTHON> import tensorflow as tf from tensorflow import keras # 加載數據 (train_images, train_labels), (test_images, test_labels) = keras.datasets.mnist.load_data() # 數據歸一化和重塑 train_images = train_images.astype('float32') / 255.0 test_images = test_images.astype('float32') / 255.0 # 對于 Conv2D 層,輸入數據需要一個通道維度 (batch, height, width, channels) # MNIST 是灰度圖,所以通道是 1 train_images = train_images[..., tf.newaxis] test_images = test_images[..., tf.newaxis] # 定義超參數 BATCH_SIZE = 64 BUFFER_SIZE = tf.data.AUTOTUNE # AUTOTUNE 會自動選擇最佳的緩沖區大小 # 構建訓練數據集管道 train_dataset = tf.data.Dataset.from_tensor_slices((train_images, train_labels)) train_dataset = train_dataset.shuffle(BUFFER_SIZE) # 打亂數據 train_dataset = train_dataset.batch(BATCH_SIZE) # 分批 train_dataset = train_dataset.prefetch(buffer_size=BUFFER_SIZE) # 預取數據 # 構建測試數據集管道 (通常不需要shuffle,但需要batch和prefetch) test_dataset = tf.data.Dataset.from_tensor_slices((test_images, test_labels)) test_dataset = test_dataset.batch(BATCH_SIZE) test_dataset = test_dataset.prefetch(buffer_size=BUFFER_SIZE) # 現在可以直接將 train_dataset 和 test_dataset 傳遞給 model.fit() 和 model.evaluate() # 示例: # model = keras.Sequential([...]) # 假設模型已定義 # model.compile(...) # history = model.fit(train_dataset, epochs=10, validation_data=test_dataset) # 可以直接傳入dataset # test_loss, test_acc = model.evaluate(test_dataset) 五、 訓練、評估與預測 model.fit(): 這是模型訓練的核心方法。 接受訓練數據(X, y)或 tf.data.Dataset。 epochs: 訓練的總輪數。 batch_size: m?i批次樣本數。 validation_data 或 validation_split: 用于驗證模型的性能。 callbacks: 可以在訓練過程中執行特定動作,如保存模型、早停(Early Stopping)。 model.evaluate(): 用于評估模型在測試集或驗證集上的性能。 接受測試數據(X, y)或 tf.data.Dataset。 返回損失值和指定的評估指標。 model.predict(): 用于在新數據上進行預測。 接受輸入數據。 對于分類任務,通常返回預測屬于每個類別的概率;對于回歸任務,返回預測值。 六、 保存與加載模型 訓練好的模型可以保存下來,以便后續使用或部署。 保存整個模型: 包括模型結構、權重、優化器狀態。 <PYTHON> model.save('my_model.keras') # 新格式 # 或者 # model.save('my_model_h5', save_format='h5') # 舊格式 加載模型: <PYTHON> loaded_model = keras.models.load_model('my_model.keras') 僅保存權重: <PYTHON> model.save_weights('my_model_weights.weights.h5') # 會自動選擇合適的格式 加載權重: <PYTHON> # 需要先構建模型結構 # complex_model_for_weights = ComplexModel() # complex_model_for_weights.load_weights('my_model_weights.weights.h5') 七、 總結 TensorFlow 2.x 通過 Keras API 極大地簡化了深度學習模型的構建和訓練過程。掌握 tf.keras.Sequential 和 tf.keras.Model 的使用,結合 tf.data 構建高效的數據管道,并理解 tf.Tensor 和 tf.GradientTape 的概念,是成為一名TensorFlow開發者的基礎。 ![]() |