深度學習模型的效能與準確度高度仰賴輸入資料的品質。影像預處理步驟,包含形狀轉換、資料品質提升和模型品質最佳化,是確保模型能有效學習的關鍵。影像形狀的調整,例如將影像縮放至模型輸入層所需的尺寸,是模型訓練的第一步。同時,資料品質的提升,例如處理影像中的光照差異或異常畫素值,能有效提升模型的魯棒性。此外,為了提升模型訓練效率,通常會將畫素值縮放到特定範圍,例如 0 到 1 或 -1 到 1,以利於最佳化器運作。這些預處理步驟環環相扣,共同決定了模型的最終效能。
影像預處理的重要性與方法
在將原始影像輸入到影像模型之前,通常需要進行預處理。預處理有多個重疊的目標,包括形狀轉換、資料品質改進和模型品質提升。
形狀轉換
輸入的影像通常需要轉換成一致的大小。例如,考慮一個簡單的深度神經網路(DNN)模型:
model = tf.keras.Sequential([
tf.keras.layers.Flatten(input_shape=(512, 256, 3)),
tf.keras.layers.Dense(128, activation=tf.keras.activations.relu),
tf.keras.layers.Dense(len(CLASS_NAMES), activation='softmax')
])
這個模型要求輸入的影像是具有推斷批次大小、512列、256行和3個通道的4D張量。如果原始影像資料的大小不是這樣,那麼就無法將每個輸入值對映到網路的節點。因此,不符合要求的影像需要轉換成具有精確形狀的張量。
內容解密:
tf.keras.Sequential用於建立序列模型,層按順序堆積疊。tf.keras.layers.Flatten將輸入展平,用於將多維輸入轉換為一維。input_shape=(512, 256, 3)指定輸入形狀為512x256畫素的RGB影像。tf.keras.layers.Dense是全連線層,用於分類別任務。- 模型的輸入和輸出層需要根據具體任務進行調整。
資料品質轉換
另一個進行預處理的原因是強制執行資料品質。例如,許多衛星影像由於太陽光照或地球曲率而具有終止線(terminator line)。太陽光照可能導致影像不同部分的光照水平不同。由於終止線的位置可以從時間戳中精確得知,因此可以根據對應地球點接收到的太陽輻照度對每個畫素值進行歸一化處理。
為什麼需要資料品質轉換?
- 太陽光照和地球曲率可能導致影像品質問題。
- 神經網路期望看到有限的浮點數值,因此需要處理特殊畫素值(如無窮大或未感測到的畫素)。
提升模型品質
預處理的第三個目標是進行有助於提高模型精確度的轉換。例如,機器學習最佳化器在資料值為小數時表現最佳。因此,在預處理階段,將畫素值縮放到[0, 1]或[-1, 1]範圍內是有幫助的。
如何提升模型品質?
- 縮放畫素值以改善最佳化器的效能。
- 透過增加翻轉影像或新增隨機擾動來擴充資料集,從而提高模型的魯棒性。
大小和解析度
正如前一節所討論的,預處理影像的一個關鍵原因是確保影像張量具有機器學習模型輸入層所期望的形狀。為此,我們通常需要更改讀取影像的大小和/或解析度。
使用Keras預處理層
當輸入影像大小不同時,我們需要將它們預處理成機器學習模型輸入層所期望的形狀。在第2章中,我們使用TensorFlow函式在讀取影像時指定所需的高度和寬度:
img = tf.image.resize(img, [IMG_HEIGHT, IMG_WIDTH])
內容解密:
tf.image.resize用於調整影像大小。[IMG_HEIGHT, IMG_WIDTH]指定了目標大小。- 調整大小是預處理的重要步驟,以確保所有影像具有相同的尺寸。
影像大小調整與預處理技術
在深度學習影像處理任務中,調整影像大小和進行適當的預處理是至關重要的步驟。本章節將探討如何使用Keras和TensorFlow進行影像大小調整和預處理。
使用Keras進行影像大小調整
Keras提供了一個名為Resizing的預處理層,可以用來調整影像大小。我們可以將多個預處理操作組合成一個Sequential模型:
preproc_layers = tf.keras.Sequential([
tf.keras.layers.experimental.preprocessing.Resizing(
height=IMG_HEIGHT, width=IMG_WIDTH,
input_shape=(None, None, 3))
])
然而,直接將此預處理層應用於資料集會遇到問題,因為資料集提供的是3D張量(高度、寬度、通道),而Keras的Sequential模型需要4D張量(批次大小、高度、寬度、通道)。為瞭解決這個問題,我們可以定義一個函式來新增和移除批次維度:
def apply_preproc(img, label):
# 新增批次維度,呼叫預處理層,移除批次維度
x = tf.expand_dims(img, 0)
x = preproc_layers(x)
x = tf.squeeze(x, 0)
return x, label
內容解密:
tf.expand_dims(img, 0):在影像張量的第一個維度新增一個新的維度,使其變成4D張量,以便能夠被Keras的Sequential模型處理。preproc_layers(x):將增加了批次維度的影像輸入到預處理層中進行大小調整。tf.squeeze(x, 0):移除處理後的影像張量的第一個維度,使其還原成3D張量。
透過這種方式,我們可以將預處理層應用於資料集:
train_dataset.map(apply_preproc)
使用TensorFlow的影像模組
TensorFlow的tf.image模組提供了豐富的影像處理功能,包括大小調整、裁剪、填充等。我們可以使用resize_with_pad函式來在調整大小的同時保持影像的長寬比:
img = tf.image.resize_with_pad(img, [IMG_HEIGHT, IMG_WIDTH])
或者透過填充零值來達到期望的大小:
def apply_preproc(img, label):
return (tf.image.resize_with_pad(img, 2*IMG_HEIGHT, 2*IMG_WIDTH),
label)
train_dataset.map(apply_preproc)
內容解密:
tf.image.resize_with_pad(img, 2*IMG_HEIGHT, 2*IMG_WIDTH):將影像調整到兩倍於目標大小,然後透過填充零值來保持長寬比。train_dataset.map(apply_preproc):將定義的預處理函式應用於資料集中的每個影像。
結合Keras和TensorFlow進行預處理
為了實作更複雜的預處理流程,我們可以結合使用Keras和TensorFlow的功能。例如,使用TensorFlow的resize_with_pad和Keras的CenterCrop層來進行中心裁剪:
preproc_layers = tf.keras.Sequential([
tf.keras.layers.Lambda(lambda img:
tf.image.resize_with_pad(
img, 2*IMG_HEIGHT, 2*IMG_WIDTH),
input_shape=(None, None, 3)),
tf.keras.layers.experimental.preprocessing.CenterCrop(
height=IMG_HEIGHT, width=IMG_WIDTH)
])
內容解密:
tf.keras.layers.Lambda(lambda img: tf.image.resize_with_pad(img, 2*IMG_HEIGHT, 2*IMG_WIDTH)):使用Lambda層包裝TensorFlow的resize_with_pad函式,以實作影像大小的調整和填充。tf.keras.layers.experimental.preprocessing.CenterCrop(height=IMG_HEIGHT, width=IMG_WIDTH):使用Keras的CenterCrop層對填充後的影像進行中心裁剪,以獲得最終的目標大小。
這種結合使用的方法允許我們靈活地構建複雜的預處理流程,同時利用Keras和TensorFlow各自的優勢。
影像預處理與模型訓練
在深度學習模型的訓練過程中,影像預處理是一個非常重要的步驟。適當的預處理可以提高模型的效能和準確度。在本章中,我們將探討不同的影像預處理方法,並比較它們對模型訓練的影響。
影像預處理方法
在前面的章節中,我們已經介紹了幾種不同的影像預處理方法,包括在Keras中作為預處理層、在TensorFlow中作為tf.data管線的一部分、以及在Keras中作為模型本身的一部分。這些方法的選擇取決於效率和靈活性之間的權衡。
在本章中,我們將使用tf.data管線來進行影像預處理。首先,我們定義了一個parse_tfr函式來解析TFRecord檔案中的影像資料。然後,我們使用apply_preproc函式來對影像進行預處理,包括調整大小和中心裁剪。
train_dataset = tf.data.TFRecordDataset(
[filename for filename in tf.io.gfile.glob('gs://practical-ml-vision-book/flowers_tfr/train-*')]
).map(parse_tfr).map(apply_preproc).batch(batch_size)
內容解密:
tf.data.TFRecordDataset用於讀取TFRecord檔案中的資料。map(parse_tfr)將parse_tfr函式應用於每個資料樣本,解析TFRecord檔案中的影像資料。map(apply_preproc)將apply_preproc函式應用於每個資料樣本,對影像進行預處理。batch(batch_size)將資料樣本分成批次,以提高訓練效率。
模型訓練
我們的模型使用MobileNet遷移學習模型,該模型在第三章中已經介紹過。模型的架構如下:
layers = [
hub.KerasLayer(
"https://tfhub.dev/.../mobilenet_v2/...",
input_shape=(IMG_HEIGHT, IMG_WIDTH, IMG_CHANNELS),
trainable=False,
name='mobilenet_embedding'),
tf.keras.layers.Dense(num_hidden,
activation=tf.keras.activations.relu,
name='dense_hidden'),
tf.keras.layers.Dense(len(CLASS_NAMES),
activation='softmax',
name='flower_prob')
]
model = tf.keras.Sequential(layers, name='flower_classification')
model.compile(optimizer=tf.keras.optimizers.Adam(learning_rate=lrate),
loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=False),
metrics=['accuracy'])
history = model.fit(train_dataset, validation_data=eval_dataset, epochs=10)
內容解密:
hub.KerasLayer用於載入預訓練的MobileNet模型。tf.keras.layers.Dense用於新增全連線層,以進行分類別任務。model.compile用於編譯模型,指定最佳化器、損失函式和評估指標。model.fit用於訓練模型,傳入訓練資料集、驗證資料集和訓練輪數。
訓練結果
模型的訓練結果如圖6-7所示。從圖中可以看出,模型的驗證準確率在0.85左右波動。
比較不同的預處理方法
在本章中,我們比較了不同的影像預處理方法對模型訓練的影響。結果表明,使用填充和中心裁剪的預處理方法比簡單的調整大小方法效果稍差。這可能是因為不同的預處理方法對模型的泛化能力有不同的影響。
避免訓練-服務偏差
在模型佈署時,需要確保訓練和服務管道的一致性,以避免訓練-服務偏差。這可以透過重用相同的預處理程式碼來實作。
總之,影像預處理是深度學習模型訓練中的一個重要步驟。選擇合適的預處理方法可以提高模型的效能和準確度。同時,需要確保訓練和服務管道的一致性,以避免訓練-服務偏差。
避免訓練與預測間的差異:重用預處理程式碼
在機器學習專案中,訓練和預測(或稱推理)階段的資料處理流程必須保持一致,以避免因資料處理不同而導致模型在實際應用中表現不佳。為了達成這目標,我們需要確保預處理步驟在訓練和預測階段都能正確重用。
將預處理步驟放入可重用的函式中
首先,我們可以將預處理步驟封裝在獨立的函式或類別中,以便在訓練和預測流程中重複使用。以下是一個名為 _Preprocessor 的類別範例:
class _Preprocessor:
def __init__(self):
self.preproc_layers = tf.keras.Sequential([
tf.keras.layers.experimental.preprocessing.CenterCrop(
height=IMG_HEIGHT, width=IMG_WIDTH),
input_shape=(2*IMG_HEIGHT, 2*IMG_WIDTH, 3)
])
def read_from_tfr(self, proto):
# 解析 TFRecord 檔案
feature_description = ... # 定義資料結構描述
rec = tf.io.parse_single_example(proto, feature_description)
shape = tf.sparse.to_dense(rec['shape'])
img = tf.reshape(tf.sparse.to_dense(rec['image']), shape)
label_int = rec['label_int']
return img, label_int
def preprocess(self, img):
# 對影像進行預處理
x = tf.image.resize_with_pad(img, 2*IMG_HEIGHT, 2*IMG_WIDTH)
x = tf.expand_dims(x, 0)
x = self.preproc_layers(x)
x = tf.squeeze(x, 0)
return x
def read_from_jpegfile(self, filename):
# 從 JPEG 檔案讀取影像
img = tf.io.read_file(filename)
img = tf.image.decode_jpeg(img, channels=IMG_CHANNELS)
img = tf.image.convert_image_dtype(img, tf.float32)
return img
內容解密:
_Preprocessor類別:這個類別封裝了所有必要的預處理步驟,包括從 TFRecord 或 JPEG 檔案讀取資料、對影像進行縮放和裁剪等。read_from_tfr方法:負責從 TFRecord 檔案中讀取資料並解析成影像和標籤。preprocess方法:對讀取的影像進行預處理,包括縮放、裁剪等操作。read_from_jpegfile方法:從單個 JPEG 檔案讀取影像並進行必要的轉換,以便進行預測。
在模型中整合預處理步驟
另一種方法是將預處理步驟直接整合到 Keras 模型中。這樣做的好處是模型在訓練和預測階段都能自動套用相同的預處理步驟。
layers = [
tf.keras.layers.experimental.preprocessing.CenterCrop(
height=IMG_HEIGHT, width=IMG_WIDTH,
input_shape=(2*IMG_HEIGHT, 2*IMG_WIDTH, IMG_CHANNELS),
),
hub.KerasLayer(...),
tf.keras.layers.Dense(...),
tf.keras.layers.Dense(...)
]
內容解密:
- 模型中的預處理層:將
CenterCrop層直接加入到模型的第一層,確保輸入的影像會先經過裁剪處理。 - 自動套用預處理:這樣設計的好處是,在進行預測時,模型會自動對輸入的影像進行相同的預處理,從而避免因預處理不同而導致的誤差。
使用 tf.transform 建立可重用的預處理構件
tf.transform 是 TensorFlow 的一個函式庫,用於建立可在訓練和預測階段重用的預處理流程。這種方法可以確保無論是在訓練還是預測階段,資料都經過相同的轉換,從而減少因資料處理不一致而導致的問題。