# 如何用 SAHI 偵測小物件:推論與微調 # How to Detect Small Objects with SAHI: Inference & Fine-Tuning > 原文來源:https://visionbrick.com/how-to-detect-small-objects-with-sahi-inference-fine-tuning/ --- 像 Ultralytics 這類函式庫對深度學習,特別是物件偵測,有很大影響。即使一個人對電腦視覺一無所知,他們也能透過結合幾個元素來訓練並部署物體偵測模型。首先,從 Kaggle 找到資料集,建立筆記本,啟用 GPU,然後用 Ultralytics 來訓練。只要寫近 **50 行程式碼**,花 **4 到 5 小時**,**任何人都能訓練 YOLO 模型並部署**。是的,這對一般物體偵測是有效的。如果資料集夠乾淨且夠大,就會有一個模型能在大多數情況下使用。你大多時候可以準確偵測常見物體,比如汽車、人。但這是每個任務都一樣嗎? ![Small Object Detection with SAHI](https://hackmd.io/_uploads/H1vO69yQ-e.png) **Small Object Detection with SAHI [VisDrone19-Detection dataset]** 使用 SAHI 進行小型物體偵測 [VisDrone19-Detection 資料集] 當然不,我們來想想小物件。物體太小,甚至用肉眼無法準確辨識。因此,這種簡單的方法行不通,針對**小型物體的偵測有不同的解決方案**,本文將介紹 **SAHI**。SAHI 的主要理念是將影像切片成較小的區域,並在這些小區域進行推論與訓練,並進一步處理。 --- ## 為什麼小物件偵測較難?SAHI 如何成功? 想像影像中的小物體,如飛機、昆蟲和遠方的人。即使在原始圖片中,也很難辨認。現在想想模型訓練部分,因為記憶體限制和訓練時間,大多數情況下**影像會被調整到像 640×640、640×480 這樣的解析度**。 即使在預設情況下,Ultralytics 也會將原始圖片調整為 640×640。影像大小會顯著影響訓練時間,有時在低 GPU VRAM(4GB、6GB、8GB)時,**CUDA 記憶體不足**錯誤很常見。你可以透過減少批次大小或影像解析度來解決這個問題。 ![How SAHI Slicing Aided Inference works](https://visionbrick.com/wp-content/uploads/2025/11/sahichart-3-1024x647.png.webp) **How SAHI Slicing Aided Inference works?** SAHI 切片輔助推論是如何運作的? 物件即使在原始解析度下也很小,想想在訓練前調整大小後會發生什麼事?它們變得**非常小**,有時甚至消失。這時 SAHI 登場了。這個想法簡單卻有效:如果我們**將影像切成較小的片段**,逐個處理,就不必將整張影像調整到較低解析度。將影像切片成多個片段後,每個片段的尺寸調整到較高解析度,同時保持比例,使**較小的區域變大**(同時物體變大),此方法對小物件偵測有顯著效果。 ![Detecting Small Objects with SAHI](https://visionbrick.com/wp-content/uploads/2025/11/image-31.png.webp) **Detecting Small Objects with SAHI [VisDrone19-Detection dataset]** 使用 SAHI 偵測小型物體 [VisDrone19-Detection 資料集] 如果你有時間,我強烈建議你閱讀 SAHI 的論文。內容不長(4 頁),而且他們解釋得很完美。你可以從[這裡](https://arxiv.org/abs/2202.06934)閱讀。 --- ## SAHI (Slicing Aided Hyper Inference) SAHI(切割輔助超推論) 你可以在任何物件偵測模型上使用 SAHI,因為**它不會改變模型架構**。其理念是將影像切片成較小的區域;因此,模型架構保持不變。你可以搭配 **YOLO**、**Faster R-CNN**、**SSD**、**DETR** 等任何你想到的物體偵測模型。 如我之前所說,影像會被切成較小的區域,每個區域都分別處理。但有一個問題:**如果一個物件夾在兩個補丁之間呢?** 解決這個問題,每個補丁與相鄰補丁重疊 **25%**。最後,為了消除從相鄰補丁偵測到的重複物件,會應用 **NMS(非最大抑制)**。順帶一提,25% 是預設參數;你可以改變它。 ![Object falls between two patches](https://visionbrick.com/wp-content/uploads/2025/11/overlap-1024x746.png.webp) **Object falls between two patches** 物體落在兩個區域之間 [[img](https://www.pexels.com/photo/person-hiking-in-mountains-13416295/)] 論文中提出了兩種不同的方法: ### 1. Slicing Aided Inference(切割輔助推論) 到目前為止,我已經告訴你第一個方法的主要概念,但還有更多。好,我們有一張圖片,然後把它切成更小的區域。重要的是把這些較小的補丁**調整到更高解析度**。透過這樣做,我們的小塊會變大,裡面的物體也會變大。接著,物件偵測模型會運行在這些新產生的高解析度補丁上。對於小型物體,這種方法特別合理,尤其是**高解析度影像中的小物體**。 ![Slicing Aided Inference](https://visionbrick.com/wp-content/uploads/2025/11/image-12.png.webp) **Slicing Aided Inference**. Source: [[paper link](https://arxiv.org/abs/2202.06934)] 切割輔助推論 ### 2. Slicing Aided Fine-tuning(切割輔助微調) 那「切割輔助微調」方法呢?顧名思義,這是關於訓練。訓練前,將影像切片成較小的片段,將這些片段調整至較大解析度,然後**在這些新建立的高解析度片段及整張影像上訓練物件偵測模型**。你可以直覺地處理這件事,因為這很有道理。你有一個超小的物體,存在於高解析度影像中。首先,你將這張圖片分割成較小的區域,然後將這些小區域調整到更高解析度。這樣一來,你的超小物體會變大,接著你用這些補丁訓練物體偵測模型,讓**小物體偵測的準確度提升**。 ![Slicing Aided Fine-tuning](https://visionbrick.com/wp-content/uploads/2025/11/image-11.png.webp) **Slicing Aided Fine-tuning**. Source: [[paper link](https://arxiv.org/abs/2202.06934)] 切割輔助微調 現在,我將展示論文中建議的兩種方法的示範。首先,我會示範如何**將 YOLO 模型與 SAHI 結合**,以提升小物件偵測的推論能力。接下來,我將示範如何在你的資料集上進行**切片輔助微調**,以訓練更穩健的小型物件偵測模型。 --- ## 安裝 Installation 安裝並不複雜;你需要幾個函式庫。你應該建立一個支援 GPU 的 PyTorch 環境來訓練並加快推論速度。 ```bash pip install sahi ``` ![GitHub repository of SAHI](https://visionbrick.com/wp-content/uploads/2025/11/image-32-1024x575.png.webp) **GitHub repository of SAHI** ([link](https://github.com/obss/sahi)) SAHI 的 GitHub 倉庫 --- ## 1. Slicing Aided Inference with YOLO + SAHI 以 YOLO + SAHI 切割輔助推論 好,讓我們從切片輔助推論開始。我談了很多事情,比如調整圖片大小到低解析度或高解析度、重疊區域。**我們不需要處理這些問題,因為 SAHI 和 Ultralytics 一樣使用者友善**。 ![Slicing Aided Inference with YOLO + SAHI](https://visionbrick.com/wp-content/uploads/2025/11/image-13.png.webp) **Slicing Aided Inference with YOLO + SAHI** 與 YOLO + SAHI 的輔助推斷切割 首先,建立一個 `UltralyticsDetectionModel` 類別實例來**載入你的 YOLO 模型**,然後用 `get_sliced_prediction` 函式來**推論**。我用的是預訓練的 YOLO 模型(`yolov8n.pt`)。如果你想用自訂模型或其他預訓練模型來使用 SAHI,情況不會改變。 `UltralyticsDetectionModel`(models/ultralytics.py)繼承自 `DetectionModel`(models/base.py)類別。我強烈建議你查閱原始碼以更好理解。 ![models structure](https://visionbrick.com/wp-content/uploads/2025/11/image-14.png.webp) **models/ultralytics.py, models/base.py** 你可以在 `predict.py` 檔案中找到 `get_sliced_prediction` 函式所需的所有資訊。 ![get_sliced_prediction function](https://visionbrick.com/wp-content/uploads/2025/11/image-15.png.webp) **`get_sliced_prediction` function inside `predict.py` file** 現在讓我們來推論 SAHI。你可以更改 `model_path`、`device`,以及測試影像的路徑。 參數說明: - **slice_height**:補丁高度 - **slice_width**:補丁的寬度 - **overlap_ratio**:相鄰補丁的重疊百分比 ```python from sahi.models.ultralytics import UltralyticsDetectionModel from sahi.predict import get_sliced_prediction detection_model = UltralyticsDetectionModel( model_path="yolov8n.pt", confidence_threshold=0.3, device="cuda" ) result = get_sliced_prediction( r"images/cars.jpg", detection_model, slice_height=256, slice_width=256, overlap_height_ratio=0.2, overlap_width_ratio=0.2 ) ``` ![Detection of small objects with SAHI](https://visionbrick.com/wp-content/uploads/2025/11/vertical_comparison-734x1024.jpg.webp) **Detection of small objects with SAHI** [[img](https://www.pexels.com/photo/road-between-green-leafed-trees-59512/)] 用 SAHI 偵測小物體 ### 視覺化結果 為了視覺化結果,你可以循環 `result` 變數,取得包圍框座標、標籤資訊和置信度值,然後畫出包圍框並在物件上寫入標籤資訊。或者,你也可以直接使用 `export_visuals` 函數;它會將輸出影像儲存到 `export_dir` 路徑。 ```python for pred in result.object_prediction_list: bbox = pred.bbox.to_xyxy() x1, y1, x2, y2 = map(int, bbox) label = pred.category.name score = pred.score.value ``` ```python result.export_visuals(export_dir="runs/predictions/") ``` ### slice_image 函式 還有另一個很酷的函數叫 `slice_image`。你可以利用這個功能**儲存所有切片**,以更好地視覺化和理解 SAHI。讓我給你看一個簡短的示範。 ```python from sahi.slicing import slice_image slice_image_result = slice_image( image="test_image.jpg", output_file_name="slice", output_dir="runs/sliced_images/", slice_height=256, slice_width=256, overlap_height_ratio=0.2, overlap_width_ratio=0.2, ) print(f"Original Image Size: {slice_image_result.original_image_height}x{slice_image_result.original_image_width} (HxW)") print(f"Slice Size: {slice_width}x{slice_height} pixels") print(f"Total Slices Created: {len(slice_image_result.images)}") print(f"Slices Saved To: {slice_image_result.image_dir}") ``` 輸出結果: - Original Image Size: **853×1280 (HxW)** - Slice Size: **256×256 pixels** - Total Slices Created: **24 Slices** - Saved To: **runs/sliced_images/** ![Sliced images output](https://visionbrick.com/wp-content/uploads/2025/11/image-16-1024x443.png.webp) **Output: Sliced images in the `output_dir` directory** 輸出:`output_dir` 目錄中的切片影像 --- ## 2. Slicing Aided Fine-tuning 切割輔助微調 現在是第二部分的時間。這個想法和第一個很接近;**主要差別在於此步驟是在訓練階段之前完成,而非推論時**。假設我們有一個包含 **1,000** 張高解析度影像的資料集。首先,像第一種方法一樣將影像切成片段,然後再放大。用這些放大後的補丁來訓練物件偵測模型。根據切片參數和影像大小,你會有大約 **10,000** 到 **50,000** 張訓練影像。 **當你擁有高解析度資料集時,這種方法會有效**。假設你的資料集包含低解析度影像,例如 640×640。所以,切割就沒有意義;影像解析度本來就很低。所以,如果你的影像解析度很高,比如 **1920×1080**、**2160×1440** 等,最好進行微調。 ### VisDrone19-Detection Dataset 我會用 **VisDrone19-Detection Dataset** 做微調,因為論文中的基準測試都是在這個資料集上進行的。該資料集包含由無人機拍攝的高解析度影像。 ![Benchmark results](https://visionbrick.com/wp-content/uploads/2025/11/image-17.png.webp) **Benchmark results on VisDrone19-Detection dataset**. Source: [[paper link](https://arxiv.org/abs/2202.06934)] VisDrone19-Detection 資料集上的基準測試結果 資料集包含不同解析度,如 **1400×1050**、**1920×1080** 及 **2000×1500** 高解析度影像。我決定只用 **2000×1500** 張圖片,因為切片會大幅增加圖片數量,而且我的 GTX 1660 Ti Max-Q GPU 訓練兩天後可能會燒毀 :/ ![Visdrone19-Detection dataset](https://visionbrick.com/wp-content/uploads/2025/11/visdrone-example-images-1024x783.png.webp) **Visdrone19-Detection dataset** Visdrone19-Detection 資料集 您可以在下方圖表中看到該 VisDrone19-Detection 資料集的影像解析度分布。 ![Image resolution distribution](https://visionbrick.com/wp-content/uploads/2025/11/visdrone_size_distribution-1024x434.png.webp) **Image resolution distribution of the VisDrone19-Detection dataset** VisDrone19-Detection 資料集的影像解析度分布 ### 資料集格式轉換 VisDrone19-Detection 資料集格式並非 COCO 格式。如果你不想花時間把資料集轉換成 COCO 格式,我建議你**直接選擇已經是 COCO 格式的資料集**。我處理了 VisDrone19-Detection 資料集並匯出成 COCO 格式。 ![Converting to YOLO format](https://visionbrick.com/wp-content/uploads/2025/11/image-24.png.webp) **Converting VisDrone19-Detection dataset to YOLO format** 將 VisDrone19-Detection 資料集轉換為 YOLO 格式 ### slice_coco 函式 在 SAHI 中,有一個稱為 `slice_coco` 的函數。這個函式會將 COCO 格式的資料集切片,然後建立 COCO 格式的資料集。 你可以改變 `coco_annotation_path`、`image_dir`、`output_dir` 變數。 ```python from sahi.slicing import slice_coco coco_dict, coco_path = slice_coco( coco_annotation_file_path=coco_annotation_path, image_dir=IMAGE_DIR, output_coco_annotation_file_name="visdrone_train_sliced.json", output_dir=SLICED_OUTPUT_DIR, ignore_negative_samples=False, slice_height=640, slice_width=640, overlap_height_ratio=0.2, overlap_width_ratio=0.2, min_area_ratio=0.1, verbose=True ) ``` 輸出是一個包含所有圖片的資料夾,以及一個 JSON 格式的註解檔案。你可以在 `output_coco_annotation_file_name` 目錄裡看到註解檔,以及 `output_dir` 目錄下的切片圖片。 當你擁有 COCO 格式的資料集後,一切都變得相當簡單。COCO 格式就像深度學習中的 `print("hello world")`。你可以用各種工具匯出不同的資料集格式,但我覺得沒必要。你可以直接建立一條簡單的管線,從 COCO 格式匯出到任何其他格式。 我要訓練一個 YOLO 模型;因此,我將資料集轉換成 YOLO 格式。 > VisDrone19-Detection dataset → COCO format → YOLO format ![Example YOLO format](https://visionbrick.com/wp-content/uploads/2025/11/image-25.png.webp) **Example YOLO format** YOLO 格式範例 你可以將資料集拆分成訓練集和驗證集,比例隨你所想。你可以從 `slice_coco` 函式建立的切片資料集中看到幾個範例。 ![Visdrone19-Detection dataset with annotations](https://visionbrick.com/wp-content/uploads/2025/11/visdrone_sample_images-1024x711.png.webp) **Visdrone19-Detection dataset with annotations** 帶註解的 Visdrone19-Detection 資料集 ### 建立 YAML 檔案 在開始訓練之前,還有幾個額外的步驟。因為我要訓練一個 YOLO 模型,我會建立一個包含資料集資訊的 YAML 檔案。 ![YAML file for dataset](https://visionbrick.com/wp-content/uploads/2025/11/image-21.png.webp) **YAML file for dataset** 資料集的 YAML 檔案 ### 開始訓練 好,現在我們可以開始用切片資料集訓練了。我會把 `yolo11n.pt` 當作預訓練模型使用,但你也可以自由使用其他模型。 ```python from ultralytics import YOLO model = YOLO('yolo11n.pt') results = model.train( data="dataset.yaml", epochs=50, imgsz=640, batch=16, name='yolo11_visdrone_sliced', project='runs/train', device='cuda', patience=10, save=True, plots=True, verbose=True ) ``` 訓練開始了。即使我只用了 VisDrone19-Detection 資料集裡 2000×1500 解析度的影像,一個 epoch 大約花了 8 分鐘。2000×1500 解析度下有 772 張影像,切片後則有 9300 張。訓練 8 小時後結束。 ![Model training with sliced images](https://visionbrick.com/wp-content/uploads/2025/11/image-27-1024x291.png.webp) **Model training with sliced images** 使用切片影像進行模型訓練 ### 測試新模型 現在,是時候測試新模型了。同樣地,我會用 `get_sliced_prediction` 函式搭配新訓練的模型。 ```python from sahi import AutoDetectionModel from sahi.predict import get_sliced_prediction best_model_path = "runs/train/yolo11_visdrone_sliced/weights/best.pt" test_image = "../test_image.jpg" detection_model = AutoDetectionModel.from_pretrained( model_type='ultralytics', model_path=best_model_path, confidence_threshold=0.3, device="cuda", ) result = get_sliced_prediction( test_image, detection_model, slice_height=640, slice_width=640, overlap_height_ratio=0.2, overlap_width_ratio=0.2 ) result.export_visuals(export_dir="runs/predictions/") ``` ![Small Object Detection with SAHI](https://visionbrick.com/wp-content/uploads/2025/11/image-30.png.webp) **Small Object Detection with SAHI** 使用 SAHI 偵測小型物體 --- ## 結語 好了,我就到這裡。希望你喜歡,如果有任何問題,歡迎隨時問我(siromermer@gmail.com) --- ## 參考資料 - SAHI Paper: https://arxiv.org/abs/2202.06934 - SAHI GitHub: https://github.com/obss/sahi - Ultralytics: https://github.com/ultralytics/ultralytics