AI-LECTURER 速報課|2026-07-28|約 28 分鐘

毛孩子的毛也能被AI看懂?拆解開源去背模型FeyNoBg的設計思路

📍 真實場景
阿詩,接案兩年的寵物寫真攝影師

客戶陸續要收到毛孩的桌曆和掛卡樣品,阿詩得把上百張居家拍攝的貓狗照片換成乾淨的白底或漸層底

😖 卡住的地方:現有的免費去背工具處理短毛狗還算勉強能用,一遇到長毛貓的毛絮或逆光的毛邊,邊界不是被切成鋸齒狀,就是殘留一圈原本背景的雜色,得手動用筆刷修,一張照片修快十分鐘
💡 這堂課帶你拆開一個剛開源、在多項評測都拿下最佳成績的去背模型FeyNoBg,搞懂它為什麼能把「找到毛孩」和「描出毛邊」這兩件事同時做好,還能在自己電腦上真的跑一次去背

🧭 這到底是什麼(白話版)

對電腦來說,一張照片其實是一格一格排好的像素網格。去背(背景移除)讓照片背景消失、變透明,只留下你要的主角這件事,說穿了就是AI要幫「每一個像素」打一個分數:這格是主角就給它高不透明度(opacity)一個像素「有多不透明」的數值,最高代表完全看得見、最低代表完全透明,是背景就給它趨近於零,卡在邊界上的像素則給一個中間值,讓它呈現半透明。

要打好這個分數,AI其實得身兼兩種能力。第一種是把前景/背景前景是你要留下的主角,背景是準備被移除的部分分開——如果背景很單純,靠顏色差異就能猜個大概;但遇到雜亂背景、低對比、或主角顏色跟背景很像(保護色)的情況,就得靠形狀、材質、上下文才能認出誰是主角。第二種能力更難,是把主角的邊界描準——這件事有個專門名字叫影像摳圖(image matting)不是簡單判斷「是」或「不是」前景,而是精算邊界像素該有幾成不透明,讓毛髮、髮絲能呈現自然的半透明漸層,而不是死板的鋸齒邊。長毛、細線、殘影這些狀況下,邊界早就不是一條清楚的線了。

過去常見的做法,是把這兩種能力交給不同的訓練資料分開練——結果很容易顧此失彼:一批資料練出來的模型很會找主角形狀,卻描不好邊;另一批很會描邊,卻常常整塊主角漏掉。FeyNoBg的作者觀察到,這其實是同一個問題的兩面,得在同一個模型裡讓兩種能力互相搭配,而不是分開單練。

於是FeyNoBg挑了BiRefNetFeyNoBg採用的基礎架構名稱,本身就把「找主角」和「描邊界」設計成兩個分工模組當骨架:圖片先經過一個分四階段層層萃取的模組,把畫面整理成一份份特徵圖(feature map)AI看過照片之後在腦中整理出的「摘要筆記」,後面的模組看這份筆記做判斷,不用重新翻閱整張原始照片;接著定位模組專門負責回答「主角在哪裡」的那部分模型重建模組專門負責回答「主角的邊界確切在哪裡」的那部分模型,也是處理毛髮、細線這類難題的關鍵,共用同一批特徵圖分頭合作。FeyNoBg目前已經公開釋出,並在八項業界常用評測中的四項拿下最佳的S-measure業界常用來衡量去背/分割結果跟標準答案有多相似的一種評分方式,分數越高代表做得越像,其餘四項也跟第一名差距在2%以內。

🎯 為什麼值得你花時間

省下大量修圖時間像阿詩這種每天要處理大量毛髮邊緣照片的工作者,過去得逐張用筆刷修邊,現在如果本地模型能一次把毛邊處理乾淨,等於把最耗工的那一步交給AI去做。
解決了「偏科」的老問題過去很多去背工具不是找主角準但邊界糊,就是邊界細但整塊主角漏掉。FeyNoBg把兩種能力放進同一個模型裡互相搭配,是這類工具少見同時兩頭都顧好的設計。
模型和訓練工具一起開源FeyNoBg不只是釋出「能用的模型」,也把訓練用的NoBg函式庫開源把模型與程式碼一起公開釋出,任何人都能下載、使用、甚至修改後再訓練釋出,代表有特殊需求(比如專門處理特定材質)的人可以拿自己的照片再訓練一個客製版本。

⚙️ 它是怎麼運作的

1
圖片進四階段特徵萃取器照片先被送進一個分四個階段的處理流程,前面階段負責抓局部小細節(比如一根一根的毛),後面階段則把這些細節組合成整體樣貌,也就是特徵圖。
2
第三階段身兼兩頭第三階段的任務最吃重:它要有足夠廣的視野去判斷「這是不是一整隻貓」,同時還得保留足夠的空間細節,讓後面還原得出毛邊的形狀,是整個流程裡最關鍵的中繼站。
3
定位模組找主角定位模組拿著同一份特徵圖,回答「主角在畫面的哪個範圍」,這一步比較像是抓大方向,不用管毛邊夠不夠精細。
4
重建模組描邊界重建模組同時使用這份特徵圖,專心處理邊界問題:哪裡是清楚的邊、哪裡是毛髮或細線混在一起的模糊帶,把每個邊界像素該有的不透明度算出來。
5
合成最終的透明圖把定位模組抓到的主角範圍,跟重建模組算出的邊界不透明度值合在一起,就得到每個像素最終的不透明度,也就是去背後的成品。

🔍 程式碼漫遊(點有 ● 的行看白話講解)

這段是簡化過的「把照片丟進FeyNoBg、拿到去背結果」核心流程,對應下面下載專案裡的remove_bg.py

model = AutoModelForImageSegmentation.from_pretrained(MODEL_ID, trust_remote_code=True)
💬 從Hugging Face把FeyNoBg的模型結構和權重都下載下來,trust_remote_code代表允許載入模型作者自訂的程式碼,因為BiRefNet不是transformers內建的標準架構
preprocess = transforms.Compose([transforms.Resize(size), transforms.ToTensor(), transforms.Normalize(...)])
💬 把照片轉成模型看得懂的格式:改成固定大小、轉成數字矩陣、再做正規化,這一步每個去背模型幾乎都要做
prediction = model(input_tensor)[-1].sigmoid()
💬 把照片丟進模型算一次,取最後一層輸出,用sigmoid把數字壓成0到1之間,這就是每個像素的不透明度分數
opacity_map = transforms.ToPILImage()(prediction.squeeze().cpu())
💬 把剛剛算出來的一堆不透明度數字,轉回一張圖片的格式,方便等一下貼回原圖
result.putalpha(opacity_map)
💬 這一步是真正「去背」發生的地方:把算出來的不透明度貼到原圖的透明通道上,背景就會依照分數變透明

🛠️ 動手做:在自己電腦上跑一次FeyNoBg,幫毛孩照片去背

這是一個真實小專案:下載(或複製)檔案,照步驟在你電腦上跑起來。

📄 requirements.txt ⬇ 下載
torch
torchvision
transformers
pillow
📄 remove_bg.py ⬇ 下載
from pathlib import Path

import torch
from PIL import Image
from torchvision import transforms
from transformers import AutoModelForImageSegmentation

MODEL_ID = "usefeyn/FeyNoBg"  # 依 Hugging Face 上 FeyNoBg 頁面公布的模型代號為準
INPUT_PATH = Path("cat_photo.jpg")
OUTPUT_PATH = Path("cat_photo_transparent.png")


def load_model():
    model = AutoModelForImageSegmentation.from_pretrained(
        MODEL_ID, trust_remote_code=True
    )
    model.eval()
    return model


def make_opacity_map(model, image):
    size = (1024, 1024)
    preprocess = transforms.Compose([
        transforms.Resize(size),
        transforms.ToTensor(),
        transforms.Normalize([0.5, 0.5, 0.5], [1.0, 1.0, 1.0]),
    ])
    input_tensor = preprocess(image).unsqueeze(0)

    with torch.no_grad():
        prediction = model(input_tensor)[-1].sigmoid()

    opacity = transforms.ToPILImage()(prediction.squeeze().cpu())
    return opacity.resize(image.size)


def cut_out(image_path, output_path):
    model = load_model()
    original = Image.open(image_path).convert("RGB")

    opacity_map = make_opacity_map(model, original)

    result = original.copy()
    result.putalpha(opacity_map)
    result.save(output_path)
    print(f"已輸出去背圖片:{output_path}")


if __name__ == "__main__":
    cut_out(INPUT_PATH, OUTPUT_PATH)
  1. 開啟PowerShell,切到你想放這個小專案的資料夾,例如:cd D:\practice\feynobg-demo
  2. 建立虛擬環境:py -3.12 -m venv .venv
  3. 啟用虛擬環境:.\.venv\Scripts\Activate.ps1(如果出現「因為在這個系統上已停用指令碼執行」的錯誤,先以系統管理員身分開啟PowerShell執行 Set-ExecutionPolicy RemoteSigned,再重新啟用一次)
  4. 安裝套件:pip install -r requirements.txt(第一次安裝torch可能要花幾分鐘,請耐心等待)
  5. 把要去背的照片放進同一個資料夾,改名成 cat_photo.jpg
  6. 執行:python remove_bg.py
  7. 程式跑完後,資料夾裡會多一張cat_photo_transparent.png,用小畫家或瀏覽器打開,檢查毛髮邊緣是不是比之前用過的工具更乾淨

🧠 工程思維透鏡(資深工程師看到的是什麼)

🔭 材料裡提到過去常犯的錯,是把「找主角」和「描邊界」兩種能力交給不同資料分開練——為什麼FeyNoBg選擇讓兩個模組共用同一份特徵圖,而不是乾脆做兩個獨立模型再把結果拼起來?
分開訓練的問題不是「做不到」,而是資料一旦分流,兩邊各自最佳化的方向會慢慢偏掉,變成「改善這邊、犧牲那邊」的蹺蹺板。讓定位模組和重建模組共用同一份特徵圖,等於逼它們用同一套對這張圖的理解做事,兩邊的判斷天生就是一致的,這是工程上用共用表示換掉各自為政的典型取捨——付出的代價是兩個模組沒辦法完全獨立調整,換到的好處是不會出現互相矛盾的結果。
🔭 為什麼特徵萃取器的第三階段被形容成「工作最重」的一關?
這其實是電腦視覺裡常見的看得廣跟看得細的拔河:太早期的階段視野小,只看得到局部(一根毛、一小塊顏色),沒辦法判斷這是不是一整隻貓;太後期的階段視野雖廣,但為了整理出全局樣貌,往往會犧牲掉細部的空間位置資訊,也就是毛邊在哪一個精確的像素。第三階段被放在流程中段,就是刻意讓它同時保留兩者的折衷位置,這種在網路的哪一層做取捨的決定,正是設計這類模型時最花心思的地方。
🔭 FeyNoBg跟NoBg同時開源、而不是只放出模型檔案讓人下載就好,這個決定在工程上代表什麼?
只給模型,使用者只能用,沒辦法針對自己的資料調整;只給訓練函式庫,沒有現成模型,門檻又太高,多數人根本用不起來。同時釋出兩者,讓一般使用者可以直接下載FeyNoBg來用,同時也把想訓練專門處理某種材質的去背模型這條路留給進階使用者,是開源專案常見的產品/工具雙軌策略:先用現成模型降低採用門檻,再用開放的訓練工具保留客製化空間。

📝 隨堂考(點選答案,立即回饋)

Q1. 根據這篇材料,去背這件事其實需要AI具備哪兩種能力?
✅ 材料明確指出去背需要兩種技能:分辨前景背景,以及處理邊界的image matting,缺一不可。
Q2. 為什麼把「找主角」和「描邊界」分開訓練容易出問題?
✅ 材料提到不平衡的訓練組合會讓一項技能的進步是靠犧牲另一項換來的,這正是分開練資料的風險。
Q3. FeyNoBg是以哪個既有的模型架構為基礎打造的?
✅ 材料寫明FeyNoBg選擇BiRefNet作為基礎架構,因為它本身就把定位跟邊界重建設計成兩個分工模組。
Q4. FeyNoBg跟NoBg分別是什麼?
✅ 材料指出FeyNoBg是模型本身,NoBg則是用來訓練這個模型、也開放給別人訓練自己模型的函式庫。

🃏 翻牌記憶卡(先想答案,再點開對答)

影像摳圖(image matting)點我翻面
不是判斷是不是前景的二選一問題,而是精算邊界像素該有幾成不透明,讓毛髮、髮絲能有自然的半透明過渡
特徵圖(feature map)點我翻面
AI看過照片後整理出的摘要筆記,後面的模組依據這份筆記做判斷
定位模組 vs 重建模組點我翻面
定位模組負責找出主角在畫面的哪裡;重建模組負責描出主角邊界的精確形狀,兩者共用同一份特徵圖
BiRefNet點我翻面
FeyNoBg採用的基礎架構,本身就把找主角與描邊界拆成兩個互相搭配的模組
S-measure點我翻面
用來衡量去背/分割結果跟標準答案相似程度的一種評分方式,分數越高代表結果越貼近正確答案

✅ 離開前自測(全勾=這課真的學會了)

0%