深度學習中的轉移學習技術,藉由使用預訓練模型,能有效縮短模型訓練時間並提升效能。本文將以 PyTorch 和 Keras 兩種深度學習框架為例,示範如何使用 ResNet 和 MobileNet 等預訓練模型,快速建構影像分類別模型。我們會逐步講解如何載入預訓練模型,凍結部分權重以保留已學習的特徵,以及如何增加客製化層以適應新的影像分類別任務。文章中將使用 CIFAR-10 資料集作為訓練和評估的範例,並提供完整的程式碼實作。此外,我們也會探討特徵提取和微調等進階技巧,以及如何應用於物件偵測任務,例如使用 YOLO 架構。
轉移學習的基本步驟
- 載入預訓練模型:首先,載入一個預先訓練好的模型,這個模型通常是在大型資料集上訓練的,例如ImageNet。
- 凍結部分權重:根據需要,凍結模型中某些層的權重,以保留其學到的特徵提取能力。
- 增加新層:在預訓練模型的基礎上增加新層,以適應新任務的需求。
- 訓練新模型:使用新任務的資料集對新增加的層進行訓練。
PyTorch中的轉移學習例項
import torch
import torch.nn as nn
import torch.optim as optim
# 載入預訓練模型
model = torchvision.models.resnet50(pretrained=True)
# 凍結部分權重
for param in model.parameters():
param.requires_grad = False
# 增加新層
model.fc = nn.Linear(model.fc.in_features, 10)
# 設定損失函式和最佳化器
criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(model.fc.parameters(), lr=0.001)
# 訓練新模型
for epoch in range(5):
# 訓練模型
model.train()
for inputs, labels in train_loader:
inputs, labels = inputs.to(device), labels.to(device)
optimizer.zero_grad()
outputs = model(inputs)
loss = criterion(outputs, labels)
loss.backward()
optimizer.step()
# 測試模型
model.eval()
test_loss = 0
correct = 0
with torch.no_grad():
for inputs, labels in test_loader:
inputs, labels = inputs.to(device), labels.to(device)
outputs = model(inputs)
loss = criterion(outputs, labels)
test_loss += loss.item()
_, predicted = torch.max(outputs, 1)
correct += (predicted == labels).sum().item()
accuracy = correct / len(test_loader.dataset)
print(f'Epoch {epoch+1}, Test Accuracy: {accuracy:.2f}%')
Keras中的轉移學習例項
from tensorflow import keras
from tensorflow.keras import layers
# 載入預訓練模型
base_model = keras.applications.MobileNetV2(weights='imagenet', include_top=False, input_shape=(224, 224, 3))
# 凍結部分權重
base_model.trainable = False
# 增加新層
x = base_model.output
x = layers.GlobalAveragePooling2D()(x)
x = layers.Dense(128, activation='relu')(x)
predictions = layers.Dense(10, activation='softmax')(x)
# 建立新模型
model = keras.Model(inputs=base_model.input, outputs=predictions)
# 編譯模型
model.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy'])
# 訓練新模型
model.fit(train_data, train_labels, epochs=5, validation_data=(test_data, test_labels))
使用 Keras 進行轉移學習
在本文中,我們將使用 Keras 和 TensorFlow 來實作兩種轉移學習(Transfer Learning, TL)場景。這樣,我們可以比較這兩個函式庫。在這個例子中,我們將使用 MobileNetV3Small 架構。讓我們開始:
步驟 1:定義迷你批次和輸入影像大小
首先,我們需要定義迷你批次和輸入影像大小。影像大小由玄貓決定。
IMG_SIZE = 224
BATCH_SIZE = 50
步驟 2:載入 CIFAR-10 資料集
接下來,我們使用 TensorFlow datasets 載入 CIFAR-10 資料集。repeat()
方法允許我們重複使用資料集進行多個 epoch。
import tensorflow as tf
import tensorflow_datasets as tfds
data, metadata = tfds.load('cifar10', with_info=True, as_supervised=True)
raw_train, raw_test = data['train'].repeat(), data['test'].repeat()
步驟 3:定義資料轉換函式
現在,我們需要定義兩個函式:train_format_sample
和 test_format_sample
。這些函式將原始影像轉換為適合 CNN 輸入的格式。輸入影像將經過以下轉換:
- 尺寸重設為 224x224
- 標準化到 (-1, 1) 區間
- 標籤轉換為 one-hot 編碼
- 隨機水平和垂直翻轉訓練影像
以下是實際的實作:
def train_format_sample(image, label):
"""轉換訓練資料"""
image = tf.cast(image, tf.float32)
image = tf.image.resize(image, (IMG_SIZE, IMG_SIZE))
image = tf.image.random_flip_left_right(image)
image = tf.image.random_flip_up_down(image)
label = tf.one_hot(label, 10)
return image, label
內容解密:
在上述程式碼中,我們使用 tf.cast
將影像轉換為 float32
型別,然後使用 tf.image.resize
尺寸重設為 224x224。接下來,我們使用 tf.image.random_flip_left_right
和 tf.image.random_flip_up_down
對影像進行隨機水平和垂直翻轉。最後,我們使用 tf.one_hot
將標籤轉換為 one-hot 編碼。
圖表翻譯:
flowchart TD A[原始影像] --> B[尺寸重設] B --> C[標準化] C --> D[隨機翻轉] D --> E[one-hot 編碼] E --> F[輸出]
此圖表展示了影像轉換的過程,從原始影像到最終的輸出。
使用預訓練模型進行特徵提取
在深度學習中,預訓練模型可以大大加速我們的開發過程。這裡,我們將使用 MobileNetV3Small 這個預訓練模型作為特徵提取器。首先,我們需要載入這個預訓練模型,並且排除掉最後的全連線層(FC層)。
base_model = tf.keras.applications.MobileNetV3Small(
weights='imagenet', include_top=False, input_shape=(IMG_SIZE, IMG_SIZE, 3))
接下來,我們需要凍結預訓練模型的權重,以避免在訓練過程中修改它們。這是因為預訓練模型已經學習到了很多有用的特徵,我們不希望在訓練過程中破壞它們。
base_model.trainable = False
然後,我們需要在預訓練模型的輸出上增加一些額外的層,以便能夠輸出我們需要的特徵。這裡,我們增加了一個 GlobalAveragePooling2D
層,來對預訓練模型的輸出進行全域性平均池化。
x = base_model.output
x = tf.keras.layers.GlobalAveragePooling2D()(x)
最後,我們可以定義我們的特徵提取模型了。
fe_model = tf.keras.Model(inputs=base_model.input, outputs=x)
這個特徵提取模型可以用來從輸入影像中提取出有用的特徵。
完整程式碼
def build_fe_model():
"""Create feature extraction model from the pre-trained model MobileNetV3Small"""
base_model = tf.keras.applications.MobileNetV3Small(
weights='imagenet', include_top=False, input_shape=(IMG_SIZE, IMG_SIZE, 3))
base_model.trainable = False
x = base_model.output
x = tf.keras.layers.GlobalAveragePooling2D()(x)
fe_model = tf.keras.Model(inputs=base_model.input, outputs=x)
return fe_model
內容解密:
在這個程式碼中,我們首先載入了 MobileNetV3Small 這個預訓練模型,並且排除掉了最後的全連線層。然後,我們凍結了預訓練模型的權重,以避免在訓練過程中修改它們。接下來,我們增加了一個 GlobalAveragePooling2D
層,來對預訓練模型的輸出進行全域性平均池化。最後,我們定義了我們的特徵提取模型,並且傳回它。
圖表翻譯:
graph LR A[輸入影像] --> B[預訓練模型] B --> C[GlobalAveragePooling2D] C --> D[特徵提取模型] D --> E[輸出特徵]
這個圖表展示了我們的特徵提取模型的架構。輸入影像首先被輸入到預訓練模型中,然後預訓練模型的輸出被輸入到 GlobalAveragePooling2D
層中。最後,GlobalAveragePooling2D
層的輸出被輸入到特徵提取模型中,然後輸出特徵。
進階電腦視覺應用
在深度學習中,預先訓練好的模型可以作為特徵提取器,幫助我們快速開發新的電腦視覺應用。下面,我們將介紹如何使用預先訓練好的 MobileNetV3Small 模型進行特徵提取和微調。
特徵提取模型
首先,我們需要定義一個特徵提取模型。這個模型使用預先訓練好的 MobileNetV3Small 作為基礎,然後在頂部增加了一個全連線層。以下是實作:
def build_fe_model():
"""建立特徵提取模型"""
base_model = tf.keras.applications.MobileNetV3Small(
input_shape=(IMG_SIZE, IMG_SIZE, 3),
include_top=False,
weights='imagenet',
include_preprocessing=True
)
base_model.trainable = False #凍結所有層
model = tf.keras.Sequential([
base_model,
tf.keras.layers.GlobalAveragePooling2D(),
tf.keras.layers.Dense(
metadata.features['label'].num_classes,
activation='softmax'
)
])
return model
在這個模型中,我們首先載入預先訓練好的 MobileNetV3Small 模型,然後凍結所有層,以防止在訓練過程中更新權重。接著,我們在頂部增加了一個全連線層,使用 softmax 啟用函式進行多分類別任務。
微調模型
微調模型與特徵提取模型的主要區別在於,我們只凍結底層的預先訓練網路層,而不是所有層。以下是實作:
def build_ft_model():
"""建立微調模型"""
base_model = tf.keras.applications.MobileNetV3Small(
input_shape=(IMG_SIZE, IMG_SIZE, 3),
include_top=False,
weights='imagenet',
include_preprocessing=True
)
fine_tune_at = 100 # 從這層開始微調
# 凍結所有層,除了從 fine_tune_at 層開始的層
for layer in base_model.layers[:fine_tune_at]:
layer.trainable = False
model = tf.keras.Sequential([
base_model,
tf.keras.layers.GlobalAveragePooling2D(),
tf.keras.layers.Dense(
metadata.features['label'].num_classes,
activation='softmax'
)
])
return model
在這個模型中,我們首先載入預先訓練好的 MobileNetV3Small 模型,然後凍結所有層,除了從 fine_tune_at
層開始的層。這樣,我們就可以在微調過程中更新這些層的權重,以適應新的任務。
內容解密:
在上面的程式碼中,我們使用 tf.keras.applications.MobileNetV3Small
載入預先訓練好的 MobileNetV3Small 模型。然後,我們使用 include_top=False
引數排除頂部的全連線層,因為我們要在頂部增加自己的全連線層。接著,我們使用 weights='imagenet'
引數載入預先訓練好的權重,並使用 include_preprocessing=True
引數啟用預處理。
在微調模型中,我們使用 fine_tune_at
變數控制從哪層開始微調。然後,我們使用 layer.trainable = False
凍結所有層,除了從 fine_tune_at
層開始的層。
圖表翻譯:
flowchart TD A[載入預先訓練好的模型] --> B[凍結所有層] B --> C[增加全連線層] C --> D[定義微調模型] D --> E[凍結部分層] E --> F[增加全連線層] F --> G[定義微調模型]
在這個流程圖中,我們展示瞭如何建立特徵提取模型和微調模型。首先,我們載入預先訓練好的模型,然後凍結所有層。接著,我們增加全連線層以進行多分類別任務。在微調模型中,我們凍結部分層,然後增加全連線層。
實作深度學習模型的訓練和評估
在深度學習中,模型的訓練和評估是非常重要的步驟。以下是實作模型訓練和評估的步驟。
訓練模型
def train_model(model, epochs=5):
"""
訓練模型。
這個函式是共用的,適用於特徵提取(FE)和微調(FT)模式。
Args:
model: 要訓練的模型。
epochs: 訓練的 epochs 數量,預設為 5。
"""
# 組態模型為訓練模式
model.compile(
optimizer=tf.keras.optimizers.Adam(learning_rate=0.0001),
loss='categorical_crossentropy',
metrics=['accuracy']
)
# 訓練模型
history = model.fit(
train_batches,
epochs=epochs,
steps_per_epoch=metadata.splits['train'].num_examples / BATCH_SIZE,
validation_data=test_batches,
validation_steps=metadata.splits['test'].num_examples / BATCH_SIZE
)
return history
評估模型
def evaluate_model(model):
"""
評估模型。
Args:
model: 要評估的模型。
Returns:
評估結果。
"""
# 評估模型
loss, accuracy = model.evaluate(test_batches)
return loss, accuracy
繪製準確率
def plot_accuracy(history):
"""
繪製準確率。
Args:
history: 訓練歷史。
"""
# 繪製準確率
plt.plot(history.history['accuracy'], label='訓練準確率')
plt.plot(history.history['val_accuracy'], label='驗證準確率')
plt.xlabel('Epochs')
plt.ylabel('準確率')
plt.legend()
plt.show()
物體偵測
def object_detection(model, image):
"""
物體偵測。
Args:
model: 要使用的模型。
image: 要偵測的影像。
Returns:
偵測結果。
"""
# 預測
predictions = model.predict(image)
# 處理預測結果
results = []
for prediction in predictions:
# 處理單個預測結果
result = {
'class': prediction['class'],
'confidence': prediction['confidence'],
'bbox': prediction['bbox']
}
results.append(result)
return results
範例使用
# 建立模型
model = create_model()
# 訓練模型
history = train_model(model)
# 評估模型
loss, accuracy = evaluate_model(model)
# 繪製準確率
plot_accuracy(history)
# 物體偵測
image = ...
results = object_detection(model, image)
物體偵測技術概述
物體偵測是一種電腦視覺任務,旨在找到影像或影片中特定類別的物體例項,例如人、車輛和樹木。與影像分類別不同,物體偵測不僅能夠辨識物體的類別,還能夠定位物體在影像中的位置。
物體偵測演算法的輸出通常包括以下訊息:
- 物體的類別(例如人、車輛、樹木等)
- 物體存在的機率(或物體得分),範圍為[0, 1],表示演算法對物體存在的信心程度
- 物體所在的矩形區域(稱為邊界盒)
物體偵測方法
目前,物體偵測方法主要分為三類別:
- 經典滑動視窗法:此方法使用一個普通的分類別網路(分類別器)對影像中的每個位置進行分類別,以判斷是否存在物體。這種方法可以使用任何型別的分類別演算法,但相對較慢且容易出錯。
- 建立影像金字塔:將同一影像以不同尺寸進行表示,以便能夠檢測到不同大小的物體。
- 將分類別器滑動於整個影像中:使用影像中的每個位置作為分類別器的輸入,判斷該位置是否存在物體。
- 合併多個重疊的邊界盒:使用一些啟發式方法將多個邊界盒合併為單一預測。
- 兩階段檢測方法:這種方法非常準確,但相對較慢。如其名稱所示,兩階段檢測方法包括兩個步驟:
- 區域提案網路(RPN):掃描影像並提出可能包含物體的邊界盒(或稱為區域興趣),但不進行物體類別的判斷。
- 物體類別判斷:將提出的區域送入第二階段進行物體類別的判斷。
- 單階段(或單次)檢測方法:這種方法使用單一的卷積神經網路(CNN)同時預測物體類別和邊界盒。單階段方法通常比兩階段方法更快,但準確度稍低。
YOLO(You Only Look Once)物體偵測演算法
YOLO是一種流行的單階段物體偵測演算法,其名稱反映了其單階段的特性。自最初釋出以來,YOLO已經經歷了多個版本的更新,包括YOLOv1、YOLOv2、YOLOv3、YOLOv4、YOLOv5、YOLOv7等。每個版本都在前一個版本的基礎上進行了改進和最佳化。
YOLO的優點在於其高效和實時的物體偵測能力,使其在各種應用領域中得到廣泛使用。然而,YOLO的準確度可能不如兩階段檢測方法,但其速度和效率使其成為了一種非常有競爭力的物體偵測演算法。
YOLO的演進
- YOLOv1:最初的YOLO版本,由Joseph Redmon、Santosh Divvala、Ross Girshick和Ali Farhadi提出。
- YOLOv2:由Joseph Redmon和Ali Farhadi提出。
- YOLOv3:由Joseph Redmon和Ali Farhadi提出。
- YOLOv4:由Alexey Bochkovskiy、Chien-Yao Wang和Hong-Yuan Mark Liao提出。
- YOLOv5:由Glenn Jocher提出。
- YOLOv7:由玄貓、Alexey Bochkovskiy和Hong-Yuan Mark Liao提出,達到了當時的最先進水平。
YOLOv7的提出標誌著YOLO系列演算法又一次取得了重大突破,進一步提高了物體偵測的準確度和效率。
YOLO的應用
YOLO在各種領域中得到廣泛應用,包括:
- 安全監控:使用YOLO進行實時物體偵測,可以快速回應安全事件。
- 人工智慧交通:YOLO可以用於車輛、行人和其他交通參與者的偵測,提高交通安全性。
- 工業檢測:YOLO可以用於產品的品品檢測,自動化生產流程。
- 醫學影像分析:YOLO可以用於醫學影像中的物體偵測,例如腫瘤的檢測。
YOLO的高效和準確使其成為了一種非常有用的工具,在各種領域中得到廣泛應用和研究。
物件偵測技術:YOLO架構
YOLO(You Only Look Once)是一種實時物件偵測系統,能夠快速地偵測影像中的物件。YOLO的架構主要分為三個部分:Backbone、Neck和Head。
Backbone
Backbone是YOLO架構中的第一部分,負責從輸入影像中提取特徵。通常,Backbone是一個預先訓練好的卷積神經網路(CNN),例如DarkNet-53。這個部分的輸出將被傳遞給Neck進行進一步的處理。
綜觀電腦視覺領域的發展趨勢,轉移學習已成為加速模型訓練、提升效能的關鍵技術。本文從PyTorch和Keras框架的程式碼範例出發,深入剖析了轉移學習的實作步驟,並以MobileNetV3Small模型在CIFAR-10資料集上的應用為例,闡明瞭特徵提取和微調策略的實際操作。此外,本文還探討了YOLO物件偵測技術的演進歷程及其核心架構,展現了其在物件偵測領域的優勢。然而,轉移學習並非萬靈丹,模型選擇、超引數調整以及資料集特性等因素都會影響最終效能。對於追求極致效能的應用場景,仍需針對特定任務進行模型最佳化和客製化調整。展望未來,隨著模型架構的持續創新和訓練資料的指數級增長,預期轉移學習將在更多電腦視覺任務中扮演更重要的角色,並朝向更自動化、更精準的方向發展。玄貓認為,深入理解轉移學習的原理和實務技巧,將有助於開發者構建更強大、更有效率的電腦視覺應用。