
電腦視覺 - 影像分割 - U-Net
除了知道圖片裡「有什麼」,我們還想知道它「在哪裡」與「是什麼形狀」。本篇將帶你了解影像分割的經典模型 U-Net,並透過 Python 與 PyTorch 實作,從零訓練一個模型來抓出圖片中的物件輪廓。
WRITTEN BY

- Name
- Harry Chang
在之前的文章中,我們學習了 CNN (用來判斷整張圖片是什麼) 以及 YOLO (用來框出物件在哪裡)。但如果我們遇到的是醫學影像(例如找出腫瘤的精確邊界)或是自動駕駛(辨識哪裡是道路、哪裡是行人),只用一個「方框」是不夠的。
我們需要的是影像分割 (Image Segmentation),也就是為圖片中的「每一個像素 (Pixel)」進行分類。而在這領域中,最經典且強大的模型就是 U-Net。
- 一、 影像分割的演進與模型發展史
- 二、 資料集來源:合成雜訊形狀資料集 (Synthetic Noisy Shapes)
- 三、 原理:為什麼叫 U-Net?
- 四、 實戰:PyTorch 程式碼實作
- 五、 模型評估:U-Net 實測結果
- 六、 總結
一、 影像分割的演進與模型發展史
要了解 U-Net 為什麼偉大,我們必須先回顧「影像分割」這個領域是如何演進的:
- FCN (全卷積神經網路, 2014):開山鼻祖。科學家首次把 CNN 最後的「全連接層 (Dense Layer)」拔掉,全部換成卷積層。這讓模型能輸出跟原圖一樣大小的「熱力圖 (Heatmap)」,而不只是一個分類標籤。缺點是輸出的邊界非常模糊。
- U-Net (2015):醫學影像的救星。為了解決 FCN 邊界模糊的問題,提出了「U 字型架構」與「跳躍連接 (Skip Connections)」,完美結合了深層語意與淺層細節,成為影像分割領域的黃金標準。
- Mask R-CNN (2017):實例分割 (Instance Segmentation) 的王者。U-Net 只能分出「哪些像素是人」,但 Mask R-CNN 不僅能分割,還能告訴你「這是路人 A,那是路人 B」。它將 YOLO 那樣的物件偵測與影像分割完美結合。
- SAM (Segment Anything Model, 2023):分割界的 ChatGPT。由 Meta 發表,這是一個基於 Transformer 的超大型基礎模型 (Foundation Model)。你只要點擊圖片上的任何物體,或是輸入文字,它就能「Zero-shot (零樣本)」直接完美分割出該物件。
了解了這段發展史,我們就來好好拆解這座影像分割領域的重要里程碑:U-Net。
二、 資料集來源:合成雜訊形狀資料集 (Synthetic Noisy Shapes)
為了解釋 U-Net 的威力,我們這次不使用龐大的真實資料集,而是自己用 Python 寫一個生成器,創造出一個「充滿雜訊的形狀資料集」。
資料集特色與欄位介紹:
這是一個 二元影像分割問題 (Binary Image Segmentation)。
- 目標 (Ground Truth Mask):一張黑白的遮罩圖片,白色的部分 (1) 代表物件,黑色的部分 (0) 代表背景。
- 輸入特徵 (Input Image):我們在原圖上加入大量的隨機高斯雜訊 (Gaussian Noise),讓物件變得模糊難辨,用來測試模型是否能「看透」雜訊抓出真正的形狀。
三、 原理:為什麼叫 U-Net?
U-Net 發表於 2015 年,最初是為了解決醫學影像分割問題而誕生的。它的網路架構畫出來就像一個英文字母 "U",因此得名。
我們可以透過以下的 Mermaid 圖表,直觀地看看這個「U 字型」長什麼樣子:
U-Net 核心由兩個部分組成:
- 編碼器 (Encoder / Downsampling):U 的左半邊。它像一般的 CNN 一樣,不斷地縮小圖片尺寸並萃取特徵(尋找「這是什麼」的語意資訊)。
- 解碼器 (Decoder / Upsampling):U 的右半邊。它將縮小後的特徵圖逐步放大,恢復到原本的圖片尺寸(重建「在哪裡」的空間資訊)。
跳躍連接 (Skip Connections):U-Net 的靈魂
許多初學者在這裡會不太好理解,為什麼我們需要「跳躍連接」?
讓我們用一個「畫地圖」的例子來想像這個 U 字型架構:
- U 型的左半邊 (縮小/編碼):為了看懂地圖的「整體大局(例如:這裡有一座山、一條河)」,網路會把圖片不斷縮小。這時模型懂了「這是什麼」,但因為圖片變小了,河流確切的邊界細節已經糊掉、遺失了。
- U 型的右半邊 (放大/解碼):現在我們要把這張縮小、充滿大局觀的特徵圖,重新放大回原本的尺寸,並精準標出河流的位置。如果只憑剛剛模糊的印象來放大,畫出來的邊界一定很不精準。
- 跳躍連接的作用:它就像是個作弊橋樑!在你(右半邊)準備放大的每一個階段,它會把「左半邊還沒縮小前、邊界依然清晰的局部草圖」直接拷貝一份,透過一條捷徑貼到右半邊給模型當參考。
如此一來,右半邊的網路在預測時,同時擁有了:
- 從 U 型底部深層網路傳上來的 「宏觀理解」(我知道這整塊區域是一條河)。
- 從左側跳躍連接傳過來的 「微觀細節」(我看著清晰的草圖,知道河流的邊緣確切在哪裡)。
兩者完美拼接在一起,這就是 U-Net 能夠畫出極度精準輪廓的真正秘密!
四、 實戰:PyTorch 程式碼實作
我們用 PyTorch 實作了一個迷你的 U-Net。你可以看到 forward 函數中,是如何完美體現「跳躍連接」的:
# 關鍵程式碼:U-Net 的網路架構與跳躍連接
import torch
import torch.nn as nn
class TinyUNet(nn.Module):
# ... (初始化省略)
def forward(self, x):
# 1. Encoder (左半邊:向下萃取)
conv1 = self.dconv_down1(x) # 產生草稿
x = self.maxpool(conv1) # 縮小
conv2 = self.dconv_down2(x)
# 2. Decoder (右半邊:向上還原)
x = self.up(conv2) # 放大
# 3. Skip Connection (跳躍連接:將左邊的草稿貼過來!)
x = torch.cat([x, conv1], dim=1)
x = self.dconv_up1(x)
# 輸出預測的遮罩 (Mask)
out = torch.sigmoid(self.conv_last(x))
return out
五、 模型評估:U-Net 實測結果
我們將這個迷你的 U-Net 訓練了 10 個 Epoch(因為模型很小,在 CPU 上只需幾秒鐘),並觀察 Loss 的變化:
- Epoch 1: Loss: 0.5436
- Epoch 10: Loss: 0.0169 (成功收斂!)
視覺化解析:模型看到了什麼?
我們隨機抽取一張沒見過的測試圖片讓模型預測,結果如下:

圖片結果與說明:
- 左圖 (Input Image):這是模型看到的畫面,充滿了雪花般的雜訊,人類肉眼雖然能看出有個圓形,但邊界非常模糊。
- 中圖 (True Mask):這是我們期望模型輸出的標準答案(乾淨的圓形遮罩)。
- 右圖 (Predicted Mask):這是 U-Net 預測出的結果!
- 結果驚人:儘管輸入圖片充滿雜訊,U-Net 依然完美地過濾了背景干擾,精準地還原了圓形的平滑邊界。這就是「跳躍連接」保留空間細節的威力。
六、 總結
- 像素級的預測:影像分割 (Segmentation) 比物件偵測更進一步,它能告訴我們每一個像素屬於什麼分類。
- U 字型架構:左半邊負責理解「這是什麼」,右半邊負責還原「它在哪裡」。
- 跳躍連接 (Skip Connection):U-Net 的靈魂,完美融合了深層的語意資訊與淺層的邊界細節。
在醫學影像、衛星空拍圖分析、甚至現在最紅的 AI 繪圖 (Diffusion Model 內部也使用了 U-Net 架構!) 中,U-Net 都是不可或缺的核心基石。