51c視覺~YOLO~合集8

我自己的原文哦~???https://blog.51cto.com/whaosoft/12897680

1、Yolo9

1.1、YOLOv9+SAM實現動態目標檢測和分割

主要介紹基于YOLOv9+SAM實現動態目標檢測和分割

背景介紹

????在本文中,我們使用YOLOv9+SAM在RF100 Construction-Safety-2 數據集上實現自定義對象檢測模型。

????這種集成不僅提高了在不同圖像中檢測和分割對象的準確性和粒度,而且還擴大了應用范圍——從增強自動駕駛系統到改進醫學成像中的診斷過程。

????通過利用 YOLOv9 的高效檢測功能和 SAM 以零樣本方式分割對象的能力,這種強大的組合最大限度地減少了對大量再訓練或數據注釋的需求,使其成為一種多功能且可擴展的解決方案。

YOLOv9簡介

? ??YOLOv9簡介(You Only Look Once)

YOLOv9性能圖示

YOLOv9模型圖

??? YOLOv9 在實時目標檢測方面取得了重大進步,結合了可編程梯度信息 (PGI) 和通用高效層聚合網絡 (GELAN),以提高效率、準確性和適應性,其在 MS COCO 數據集上的性能證明了這一點。

????利用開源社區的協作工作并在 Ultralytics YOLOv5 的基礎上構建,YOLOv9 通過信息瓶頸原理和可逆函數解決深度學習中信息丟失的挑戰,跨層保留基本數據。

????這些創新策略提高了模型的結構效率,并確保精確的檢測能力,而不會影響細節,即使在輕量級模型中也是如此。

??? YOLOv9 的架構減少了不必要的參數和計算需求,使其能夠在各種模型大小(從緊湊的 YOLOv9-S 到更廣泛的 YOLOv9-E)上實現最佳性能,展示了速度和檢測精度之間的和諧平衡。

????作為計算機視覺領域的里程碑,YOLOv9不僅建立了新的基準,而且拓寬了人工智能在目標檢測和分割方面的應用視野,凸顯了該領域戰略創新和協作努力的影響。?

SAM簡介

? ??SAM簡介(Segment-Anything-Model)

SAM模型圖

? ? 分割一切模型 (SAM) 通過簡化圖像分割來推動計算機視覺向前發展,這對于從科學研究到創造性工作的一系列用途至關重要。

??? SAM 利用迄今為止最大的 Segment Anything 1-Billion (SA-1B) 掩模數據集,通過減少對專業知識、強大的計算能力和廣泛的數據集標注的依賴來實現分割的民主化。

????在 Apache 2.0 許可證下,SAM 引入了一個基礎模型框架,允許通過簡單的提示輕松調整任務,反映自然語言處理中的進步。

????通過對超過 10 億個不同掩模的訓練,SAM 理解了物體的廣義概念,促進了跨陌生領域的零鏡頭傳輸,并增強了其在 AR/VR、創意藝術和科學研究等各個領域的實用性。

????該模型的提示驅動靈活性和廣泛的任務適應性標志著分割技術的重大飛躍,將 SAM 定位為研究社區和應用程序開發人員的多功能且易于訪問的工具。

關于數據集

?該項目利用Roboflow 的RF100施工數據集,特別是Construction-Safety-2子集,來演示集成模型的功能。

https://blog.roboflow.com/roboflow-100/

??? RF100 是由英特爾發起的一項計劃,旨在建立對象檢測模型的開源基準。它側重于 Roboflow Universe 上可用數據集的通用性,提高可訪問性并加快人工智能和深度學習的開發過程。

??? RF100 構建數據集與 Roboflow 中的其他項目一樣,是開源的,可以免費使用。?

實現步驟

????實現步驟如下:

  • 環境設置
  • 下載 YOLOv9 和 SAM 的預訓練模型權重
  • 圖像推理
  • 可視化和分析
  • 獲取檢測結果
  • 使用 SAM 進行分割

????環境設置

????需要有 Google 帳戶才能訪問 Google Colab,這是一項免費云服務,為深度學習任務提供必要的計算資源,包括訪問高達 16 GB 的 GPU 和 TPU。

????GPU狀態檢查

????首先,我們確保 GPU 的可用性和就緒性,用于處理和運行 YOLOv9+SAM 模型。

????安裝 Google 云盤

????接下來,如果您已經下載了數據集,我們需要導航到存儲數據集的文件夾,否則我們可以直接使用 Roboflow 加載數據集。

from google.colab import drive
drive.mount('/content/drive')or%cd {HOME}/
!pip install -q roboflowfrom roboflow import Roboflow
rf = Roboflow(api_key="YOUR API KEY")
project = rf.workspace("roboflow-100").project("construction-safety-gsnvb")
dataset = project.version(2).download("yolov7")

????配置?YOLOv9

????數據集準備好后,克隆 YOLOv9 存儲庫,然后切換到 YOLOv9 目錄并安裝所需的依賴項,為對象檢測和分割任務做好準備。

!git clone https://github.com/SkalskiP/yolov9.git
%cd yolov9
!pip3 install -r requirements.txt -q

????顯示當前目錄

????將當前工作目錄的路徑存儲在HOME變量中以供參考。

import os
HOME = os.getcwd()
print(HOME)

????下載權重模型

????讓我們為模型權重創建一個目錄,并從 GitHub 上的發布頁面下載特定的 YOLOv9 和 GELAN 模型權重,這對于使用預訓練參數初始化模型至關重要。

!mkdir -p {HOME}/weights
!wget -P {HOME}/weights -q https://github.com/WongKinYiu/yolov9/releases/download/v0.1/yolov9-c.pt
!wget -P {HOME}/weights -q https://github.com/WongKinYiu/yolov9/releases/download/v0.1/yolov9-e.pt
!wget -P {HOME}/weights -q https://github.com/WongKinYiu/yolov9/releases/download/v0.1/gelan-c.pt
!wget -P {HOME}/weights -q https://github.com/WongKinYiu/yolov9/releases/download/v0.1/gelan-e.pt

????下載圖像進行推理

????為了使用 YOLOv9 權重進行推理,我們必須設置一個數據目錄并下載一個示例圖像進行處理,并在變量中設置該圖像的路徑SOURCE_IMAGE_PATH。

!mkdir -p {HOME}/data
!wget -P {HOME}/data -q /content/drive/MyDrive/data/image9.jpeg
SOURCE_IMAGE_PATH = f"{HOME}/image9.jpeg"

????使用自定義數據運行檢測

????之后,執行detect.py指定參數對圖像進行目標檢測,設置置信度閾值并保存檢測結果。這將創建一個包含 class_ids、邊界框坐標和置信度分數的文本文件,我們稍后將使用它。

!python detect.py --weights {HOME}/weights/gelan-c.pt --conf 0.1 --source /content/drive/MyDrive/data/image9.jpeg --device 0 --save-txt --save-conf

????顯示檢測結果

????然后,我們利用 IPython 的顯示和圖像功能來展示指定路徑圖像中檢測到的對象,并進行調整以獲得最佳觀看效果。

????安裝 Ultralytics

????安裝 Ultralytics 包以訪問 YOLO 對象檢測模型實現和實用程序,不要忘記導入 YOLO 類以執行對象檢測任務。

!pip install ultralytics 
from ultralytics import YOLO

????安裝Segment-Anything模型

????現在讓我們安裝 Segment-Anything 庫并下載 SAM 模型的權重文件,為高質量圖像分割任務做好準備。

!pip install 'git+https://github.com/facebookresearch/segment-anything.git'!wget https://dl.fbaipublicfiles.com/segment_anything/sam_vit_h_4b8939.pth

????提取檢測結果和置信度分數

????我們需要將 YOLOv9 檢測結果保存在上面的文本文件中來提取類 ID、置信度分數和邊界框坐標。這里的坐標已經標準化,所以我們先將它們轉換為圖像比例,然后打印它們進行驗證。

import cv2# Specify the path to your image
image_path = '/content/drive/MyDrive/data/image9.jpeg'# Read the image to get its dimensions
image = cv2.imread(image_path)
image_height, image_width, _ = image.shapedetections_path = '/content/yolov9/runs/detect/exp/labels/image9.txt'bboxes = []
class_ids = []
conf_scores = []with open(detections_path, 'r') as file:for line in file:components = line.split()class_id = int(components[0])confidence = float(components[5])cx, cy, w, h = [float(x) for x in components[1:5]]# Convert from normalized [0, 1] to image scalecx *= image_widthcy *= image_heightw *= image_widthh *= image_height# Convert the center x, y, width, and height to xmin, ymin, xmax, ymaxxmin = cx - w / 2ymin = cy - h / 2xmax = cx + w / 2ymax = cy + h / 2class_ids.append(class_id)bboxes.append((xmin, ymin, xmax, ymax))conf_scores.append(confidence)# Display the results
for class_id, bbox, conf in zip(class_ids, bboxes, conf_scores):print(f'Class ID: {class_id}, Confidence: {conf:.2f}, BBox coordinates: {bbox}')

????初始化 SAM 以進行圖像分割

????使用指定的預訓練權重初始化 SAM 后,我們繼續從 SAM 模型注冊表中選擇模型類型以生成分段掩碼。

from segment_anything import sam_model_registry, SamAutomaticMaskGenerator, SamPredictor
sam_checkpoint = "/content/yolov9/sam_vit_h_4b8939.pth"
model_type = "vit_h"
sam = sam_model_registry[model_type](checkpoint=sam_checkpoint)
predictor = SamPredictor(sam)

????加載圖像進行分割

????通過 OpenCV 庫,我們加載圖像以使用 SAM 進行處理,為分割做好準備。

import cv2
image = cv2.cvtColor(cv2.imread('/content/drive/MyDrive/data/image9.jpeg'), cv2.COLOR_BGR2RGB)
predictor.set_image(image)

????結果可視化

????為了可視化檢測和分割結果,我們必須使用 SAM 將邊界框轉換為分割掩模。我們隨機為類 ID 分配唯一的顏色,然后定義用于顯示掩碼、置信度分數和邊界框的輔助函數。coco.yaml 文件用于將 class_ids 映射到類名。

import matplotlib.patches as patches
from matplotlib import pyplot as plt
import numpy as np
import yamlwith open('/content/yolov9/data/coco.yaml', 'r') as file:coco_data = yaml.safe_load(file)class_names = coco_data['names']for class_id, bbox, conf in zip(class_ids, bboxes, conf_scores):class_name = class_names[class_id]# print(f'Class ID: {class_id}, Class Name: {class_name}, BBox coordinates: {bbox}')color_map = {}
for class_id in class_ids:color_map[class_id] = np.concatenate([np.random.random(3), np.array([0.6])], axis=0)def show_mask(mask, ax, color):h, w = mask.shape[-2:]mask_image = mask.reshape(h, w, 1) * np.array(color).reshape(1, 1, -1)ax.imshow(mask_image)def show_box(box, label, conf_score, color, ax):x0, y0 = box[0], box[1]w, h = box[2] - box[0], box[3] - box[1]rect = plt.Rectangle((x0, y0), w, h, edgecolor=color, facecolor='none', lw=2)ax.add_patch(rect)label_offset = 10# Construct the label with the class name and confidence scorelabel_text = f'{label} {conf_score:.2f}'ax.text(x0, y0 - label_offset, label_text, color='black', fnotallow=10, va='top', ha='left',bbox=dict(facecolor=color, alpha=0.7, edgecolor='none', boxstyle='square,pad=0.4'))plt.figure(figsize=(10, 10))
ax = plt.gca()
plt.imshow(image)# Display and process each bounding box with the corresponding mask
for class_id, bbox in zip(class_ids, bboxes):class_name = class_names[class_id]# print(f'Class ID: {class_id}, Class Name: {class_name}, BBox coordinates: {bbox}')color = color_map[class_id]input_box = np.array(bbox)# Generate the mask for the current bounding boxmasks, _, _ = predictor.predict(point_coords=None,point_labels=None,box=input_box,multimask_output=False,)show_mask(masks[0], ax, color=color)show_box(bbox, class_name, conf, color, ax)# Show the final plot
plt.axis('off')
plt.show()

????提取掩碼

????最后,我們生成一個合成圖像,在白色背景下突出顯示檢測到的對象,從分割蒙版創建聚合蒙版,并將其應用到將原始圖像與白色背景混合以增強可視化。

aggregate_mask = np.zeros(image.shape[:2], dtype=np.uint8)# Generate and accumulate masks for all bounding boxes
for bbox in bboxes:input_box = np.array(bbox).reshape(1, 4)masks, _, _ = predictor.predict(point_coords=None,point_labels=None,box=input_box,multimask_output=False,)aggregate_mask = np.where(masks[0] > 0.5, 1, aggregate_mask)# Convert the aggregate segmentation mask to a binary mask
binary_mask = np.where(aggregate_mask == 1, 1, 0)# Create a white background with the same size as the image
white_background = np.ones_like(image) * 255# Apply the binary mask to the original image
# Where the binary mask is 0 (background), use white_background; otherwise, use the original image
new_image = white_background * (1 - binary_mask[..., np.newaxis]) + image * binary_mask[..., np.newaxis]# Display the new image with the detections and white background
plt.figure(figsize=(10, 10))
plt.imshow(new_image.astype(np.uint8))
plt.axis('off')
plt.show()

1.2、YOLOv9~

太快 太卷了?在目標檢測領域,YOLOv9 實現了一代更比一代強,利用新架構和方法讓傳統卷積在參數利用率方面勝過了深度卷積。目標檢測新SOTA:YOLOv9問世,新架構讓傳統卷積重煥生機

繼 2023 年 1 月?YOLOv8?正式發布一年多以后,YOLOv9 終于來了!

我們知道,YOLO 是一種基于圖像全局信息進行預測的目標檢測系統。自 2015 年 Joseph Redmon、Ali Farhadi 等人提出初代模型以來,領域內的研究者們已經對 YOLO 進行了多次更新迭代,模型性能越來越強大。

此次,YOLOv9 由中國臺灣 Academia Sinica、臺北科技大學等機構聯合開發,相關的論文《Learning What You Want to Learn Using Programmable Gradient Information 》已經放出。

論文地址:https://arxiv.org/pdf/2402.13616.pdf

GitHub 地址:https://github.com/WongKinYiu/yolov9

如今的深度學習方法重點關注如何設計最合適的目標函數,從而使得模型的預測結果能夠最接近真實情況。同時,必須設計一個適當的架構,可以幫助獲取足夠的信息進行預測。然而,現有方法忽略了一個事實,即當輸入數據經過逐層特征提取和空間變換時,大量信息將會丟失。?

因此,YOLOv9 深入研究了數據通過深度網絡傳輸時數據丟失的重要問題,即信息瓶頸和可逆函數。

研究者提出了可編程梯度信息(programmable gradient information,PGI)的概念,來應對深度網絡實現多個目標所需要的各種變化。PGI 可以為目標任務計算目標函數提供完整的輸入信息,從而獲得可靠的梯度信息來更新網絡權值。

此外,研究者基于梯度路徑規劃設計了一種新的輕量級網絡架構,即通用高效層聚合網絡(Generalized Efficient Layer Aggregation Network,GELAN)。該架構證實了 PGI 可以在輕量級模型上取得優異的結果。

研究者在基于 MS COCO 數據集的目標檢測任務上驗證所提出的 GELAN 和 PGI。結果表明,與基于深度卷積開發的 SOTA 方法相比,GELAN 僅使用傳統卷積算子即可實現更好的參數利用率。

對于 PGI 而言,它的適用性很強,可用于從輕型到大型的各種模型。我們可以用它來獲取完整的信息,從而使從頭開始訓練的模型能夠比使用大型數據集預訓練的 SOTA 模型獲得更好的結果。下圖 1 展示了一些比較結果。

對于新發布的 YOLOv9,曾參與開發了 YOLOv7、YOLOv4、Scaled-YOLOv4 和 DPT 的 Alexey Bochkovskiy 給予了高度評價,表示 YOLOv9 優于任何基于卷積或 transformer 的目標檢測器。

還有網友表示,YOLOv9 看起來就是新的 SOTA 實時目標檢測器,他自己的自定義訓練教程也在路上了。

更有「勤勞」的網友已經為 YOLOv9 模型添加了 pip 支持。

接下來看 YOLOv9 的詳細信息。

問題陳述

通常,人們將深度神經網絡收斂困難問題歸因于梯度消失或梯度飽和等因素,這些現象確實存在于傳統的深度神經網絡中。然而,現代深度神經網絡通過設計各種歸一化和激活函數,已經從根本上解決了上述問題。不過即便如此,深度神經網絡中仍然存在著收斂速度慢或收斂效果差的問題。那么這個問題的本質到底是什么?

研究者通過對信息瓶頸的深入分析,推斷出了該問題的根本原因:梯度最初從非常深層的網絡傳遞出來后不久,就丟失了許多達成目標所需的信息。為了驗證這一推斷,研究者們對具有初始權重的不同架構的深度網絡進行前饋處理。圖 2 對此進行了可視化說明。顯然,PlainNet 在深層丟失了很多進行對象檢測所需的重要信息。至于 ResNet、CSPNet 和 GELAN 能夠保留的重要信息比例,確實與訓練后能夠獲得的準確性正相關。研究者進一步設計了基于可逆網絡的方法來解決上述問題的原因。

方法介紹

可編程梯度信息(PGI)

該研究提出了一種新的輔助監督框架:可編程梯度信息(Programmable Gradient Information,PGI),如圖 3(d)所示。?

PGI 主要包括三個部分,即(1)主分支,(2)輔助可逆分支,(3)多級輔助信息。

  • PGI 的推理過程僅使用了主分支,因此不需要額外的推理成本;
  • 輔助可逆分支是為了處理神經網絡加深帶來的問題, 網絡加深會造成信息瓶頸,導致損失函數無法生成可靠的梯度;
  • 多級輔助信息旨在處理深度監督帶來的誤差累積問題,特別是多個預測分支的架構和輕量級模型。?

GELAN 網絡

此外,該研究還提出了一個新的網絡架構 GELAN(如下圖所示),具體而言,研究者把 CSPNet、 ELAN 這兩種神經網絡架構結合起來,從而設計出兼顧輕量級、推理速度和準確性的通用高效層聚合網絡(generalized efficient layer aggregation network ,GELAN)。研究者將最初僅使用卷積層堆疊的 ELAN 的功能泛化到可以使用任何計算塊的新架構。

實驗結果

為了評估 YOLOv9 的性能,該研究首先將 YOLOv9 與其他從頭開始訓練的實時目標檢測器進行了全面的比較,結果如下表 1 所示。

該研究還將 ImageNet 預訓練模型納入比較中,結果如下圖 5 所示。值得注意的是,使用傳統卷積的 YOLOv9 在參數利用率上甚至比使用深度卷積的 YOLO MS 還要好。

消融實驗

為了探究 YOLOv9 中各個組件的作用,該研究進行了一系列消融實驗。

該研究首先對 GELAN 的計算塊進行消融實驗。如下表 2 所示,該研究發現用不同的計算塊替換 ELAN 中的卷積層后,系統可以保持良好的性能。

然后該研究又在不同尺寸的 GELAN 上針對 ELAN 塊深度和 CSP 塊深度進行了消融實驗,結果如下表 3 所示。

在 PGI 方面,研究者分別在主干網絡和 neck 上對輔助可逆分支和多級輔助信息進行了消融研究。表 4 列出了所有實驗的結果。從表 4 中可以看出,PFH 只對深度模型有效,而本文提出的 PGI 在不同組合下都能提高精度。

研究者進一步在不同大小的模型上實現了 PGI 和深度監控,并對結果進行了比較,結果如表 5 所示。

圖 6 顯示了從基準 YOLOv7 到 YOLOv9- E 逐步增加組件的結果。

可視化

研究者探討了信息瓶頸問題,并將其進行了可視化處理,圖 6 顯示了在不同架構下使用隨機初始權重作為前饋獲得的特征圖的可視化結果。

圖 7 說明了 PGI 能否在訓練過程中提供更可靠的梯度,從而使用于更新的參數能夠有效捕捉輸入數據與目標之間的關系。

#做訓練

如何安裝YOLOv9

YOLOv9被打包為一系列腳本,您可以使用這些腳本進行工作。在撰寫本指南時,沒有官方的Python包或包裝器可供您與模型進行交互。

要使用YOLOv9,您需要下載項目存儲庫。然后,您可以運行訓練作業或從現有的COCO檢查點進行推理。

本教程假定您正在使用Google Colab。如果您在筆記本環境之外的本地機器上工作,請根據需要調整命令。

YOLOv9中存在一個錯誤,阻止您對圖像進行推理,但Roboflow團隊正在維護一個非官方的分支,其中包含一個補丁,直到修復發布。要從我們的補丁分支安裝YOLOv9,請運行以下命令:

git clone https://github.com/SkalskiP/yolov9.gitcd yolov9pip3 install -r requirements.txt -q

讓我們設置一個HOME目錄來工作:

import osHOME = os.getcwd()print(HOME)

接下來,需要下載模型權重。目前只有v9 - C和v9 - E權重可用。可以使用以下命令進行下載:

!mkdir -p {HOME}/weights!wget -P {HOME}/weights -q https://github.com/WongKinYiu/yolov9/releases/download/v0.1/yolov9-c.pt!wget -P {HOME}/weights -q https://github.com/WongKinYiu/yolov9/releases/download/v0.1/yolov9-e.pt!wget -P {HOME}/weights -q https://github.com/WongKinYiu/yolov9/releases/download/v0.1/gelan-c.pt!wget -P {HOME}/weights -q https://github.com/WongKinYiu/yolov9/releases/download/v0.1/gelan-e.pt

現在可以使用項目庫中的腳本在YOLOv9模型上運行推理和訓練。

在YOLOv9模型上推理

在示例圖像上使用v9 - C COCO檢查點進行推理。創建一個新的數據目錄,并將示例圖像下載到您的筆記本中。你可以用我們的狗圖片作為例子,也可以用你想要的任何其他圖片。

!mkdir -p {HOME}/data!wget -P {HOME}/data -q https://media.roboflow.com/notebooks/examples/dog.jpegSOURCE_IMAGE_PATH = f"{HOME}/dog.jpeg"

我們現在可以在我們的圖像上進行推理:

!python detect.py --weights {HOME}/weights/gelan-c.pt --conf 0.1 --source {HOME}/data/dog.jpeg --device 0Image(filename=f"{HOME}/yolov9/runs/detect/exp/dog.jpeg", width=600)

?我們的模型能夠成功地識別出圖像中的人、狗和汽車。有鑒于此,該模型錯誤地將背帶識別為手提包,并且未能檢測到背包。

讓我們試試參數最多的v9 - E模型:

!python detect.py --weights {HOME}/weights/yolov9-e.pt --conf 0.1 --source {HOME}/data/dog.jpeg --device 0Image(filename=f"{HOME}/yolov9/runs/detect/exp2/dog.jpeg", width=600)

該模型能夠成功識別人、狗、汽車和背包。

如何訓練YOLOv9模型

您可以使用YOLOv9項目目錄中的train.py文件來訓練YOLOv9模型。

第1步:下載數據集

要開始訓練模型,您將需要一個數據集。對于本指南,我們將使用一個關于足球運動員的數據集。生成的模型將能夠在場地上識別足球運動員。

如果您沒有數據集,請查看Roboflow Universe,這是一個共享了超過200,000個計算機視覺數據集的社區。您可以找到涵蓋從書脊到足球運動員再到太陽能電池板的數據集。

運行以下代碼來下載我們在本指南中使用的數據集:

%cd {HOME}/yolov9roboflow.login()rf = roboflow.Roboflow()project = rf.workspace("roboflow-jvuqo").project("football-players-detection-3zvbc")dataset = project.version(1).download("yolov7")

當您運行此代碼時,將會要求您通過Roboflow進行身份驗證。請跟隨在您的終端中出現的鏈接進行驗證。如果您沒有賬戶,將被帶到一個頁面,您可以在該頁面創建一個賬戶。然后,再次點擊鏈接以使用Python包進行身份驗證。

此代碼以YOLOv7格式下載數據集,該格式與YOLOv9模型兼容。

您可以使用任何按照YOLOv7格式格式化的數據集來進行此操作。

第2步:使用YOLOv9 Python腳本訓練模型

讓我們為我們的數據集訓練一個模型,訓練20個epochs。我們將使用GELAN-C架構進行此操作,該架構是YOLOv9 GitHub倉庫發布的兩種架構之一。GELAN-C的訓練速度快。GELAN-C的推理時間也很快。

您可以使用以下代碼進行此操作:

%cd {HOME}/yolov9!python train.py \--batch 16 --epochs 20 --img 640 --device 0 --min-items 0 --close-mosaic 15 \--data {dataset.location}/data.yaml \--weights {HOME}/weights/gelan-c.pt \--cfg models/detect/gelan-c.yaml \--hyp hyp.scratch-high.yaml

你的模型將開始訓練。模型訓練時,將看到每個epoch的訓練指標。一旦模型完成訓練,就可以使用YOLOv9生成的圖來評估訓練結果。

運行下面的代碼來查看你的訓練圖:

Image(filename=f"{HOME}/yolov9/runs/train/exp/results.png", width=1000)

運行下面的代碼來查看你的混淆矩陣:

運行以下代碼,查看您的模型在驗證集中的一批圖像上的結果:

Image(filename=f"{HOME}/yolov9/runs/train/exp/val_batch0_pred.jpg",width=1000)

第3步:在自定義模型上運行推理

既然我們有了一個訓練好的模型,我們就可以進行推理。為此,我們可以使用YOLOv9庫中的detection . py文件。

運行以下代碼對驗證集中的所有圖像進行推理:

!python detect.py \--img 1280 --conf 0.1 --device 0 \--weights {HOME}/yolov9/runs/train/exp/weights/best.pt \--source {dataset.location}/valid/imagesimport globfrom IPython.display import Image, displayfor image_path in glob.glob(f'{HOME}/yolov9/runs/detect/exp4/*.jpg')[:3]:display(Image(filename=image_path, width=600))print("\n")

我們在大小為640的圖像上訓練了我們的模型,這使得我們可以用較少的計算資源來訓練模型。在推理過程中,我們將圖像尺寸增加到1280,使得我們可以從我們的模型中得到更準確的結果。

下面是我們模型結果的三個例子:

?我們的模型成功地識別了球員、裁判員和守門員。

結論

YOLOv9是由Chien-Yao Wang, I-Hau Yeh, and Hong-Yuan Mark Liao發布的一種新的計算機視覺模型架構。可以使用YOLOv9架構訓練目標檢測模型。

在本指南中,我們演示了如何在自定義數據集上運行推理和訓練YOLOv9模型。我們克隆了YOLOv9項目代碼,下載了模型權重,然后使用默認的COCO權重進行推理。然后,我們使用足球運動員檢測數據集訓練了一個微調的模型。我們回顧了訓練圖和混淆矩陣,然后在來自驗證集的圖像上測試了模型。

# 使用YOLOv9分割圖像中的對象

為什么 YOLOv9 可以改變細分游戲規則

????基于YOLOv8 在分割方面的成功,YOLOv9 提供了幾個潛在的優勢,可以使其成為您下一個項目的首選:

  • 推測速度提升:YOLO 模型以其實時功能而聞名。由于 YOLOv9 預計比 YOLOv8 更快,因此它可能非常適合需要瞬間分割的應用,例如自動駕駛車輛或機器人對象操縱。
  • 潛在的準確性提升:YOLO 開發人員不斷努力提高檢測和分類的準確性。如果 YOLOv9 效仿,它可以轉化為更精確的分割掩模,從而在醫學成像或場景理解等任務中獲得更好的性能。
  • 效率增強:YOLOv9 中的新架構改進可能會提高處理圖像進行分割的效率。這可能有利于計算資源有限的用戶或處理大量圖像處理任務的用戶。
  • 新分割技術的潛力:YOLOv9 核心架構的進步可能為全新的分割技術打開大門。我們可能會看到處理復雜對象形狀、遮擋的創新,甚至探索超越像素標記的新分割形式。

如何使用 YOLOv9 處理圖像

第 1 步:安裝必要的庫

pip install opencv-python ultralytics numpy

第 2 步:導入庫

from ultralytics import YOLO
import random
import cv2
import numpy as np

第 3 步:選擇模型

model = YOLO("yolov9e-seg.pt")

????在下面網站中,您可以比較不同的模型并權衡各自的優缺點。在本例中,我們選擇了 yolov9e-seg.pt。

https://docs.ultralytics.com/models/yolov9/

第 4 步:使用 YOLOv9 分割圖像中的對象

img = cv2.imread("YourImagePath")# if you want all classes
yolo_classes = list(model.names.values())
classes_ids = [yolo_classes.index(clas) for clas in yolo_classes]conf = 0.2results = model.predict(img, conf=conf)
colors = [random.choices(range(256), k=3) for _ in classes_ids]
print(results)
for result in results:for mask, box in zip(result.masks.xy, result.boxes):points = np.int32([mask])# cv2.polylines(img, points, True, (255, 0, 0), 1)color_number = classes_ids.index(int(box.cls[0]))cv2.fillPoly(img, points, colors[color_number])

1. 加載圖片:

  • img = cv2.imread("YourImagePath")使用OpenCV的函數從指定路徑讀取圖像cv2.imread()。

??? 2. 預測準備:

  • yolo_classes = list(model.names.values())創建 YOLOv9 模型識別的類名列表。
  • classes_ids = [yolo_classes.index(clas) for clas in yolo_classes]創建與這些名稱相對應的類 ID 列表。
  • conf = 0.2設置對象檢測的置信度閾值。僅考慮置信度分數高于此閾值的預測。

??? 3. 運行模型預測:

  • results = model.predict(img, conf=conf)調用predict()YOLOv9模型的方法對加載的圖像進行預測。結果包括檢測到的對象、其邊界框、掩模(多邊形輪廓)、置信度分數和類別預測。
  • colors = [random.choices(range(256), k=3) for _ in classes_ids]生成一個隨機顏色列表,每個類別一個,用于視覺表示。

??? 4. 處理結果和可視化掩模:

????該for循環迭代結果中每個檢測到的對象:

  • mask, box = zip(result.masks.xy, result.boxes)解包對象的掩模坐標和邊界框信息。
  • points = np.int32([mask])將掩模坐標(可能采用浮點格式)轉換為整數,以便使用 OpenCV 在圖像上繪圖。
  • color_number = classes_ids.index(int(box.cls[0]))根據對象的預測類別確定視覺表示的顏色索引。
  • cv2.fillPoly(img, points, colors[color_number])用原始圖像上相應的顏色填充掩模坐標定義的多邊形,有效地創建對象的視覺分割。

????筆記:

  • 如果未注釋,注釋掉的線# cv2.polylines(img, points, True, (255, 0, 0), 1)將在蒙版周圍繪制輪廓,而不是填充它們。

第 5 步:保存并繪制結果圖像

cv2.imshow("Image", img)
cv2.waitKey(0)cv2.imwrite("YourSavePath", img)

完整代碼:

from ultralytics import YOLO
import random
import cv2
import numpy as npmodel = YOLO("yolov9e-seg.pt")img = cv2.imread("YourImagePath")# if you want all classes
yolo_classes = list(model.names.values())
classes_ids = [yolo_classes.index(clas) for clas in yolo_classes]conf = 0.2results = model.predict(img, conf=conf)
colors = [random.choices(range(256), k=3) for _ in classes_ids]
print(results)
for result in results:for mask, box in zip(result.masks.xy, result.boxes):points = np.int32([mask])# cv2.polylines(img, points, True, (255, 0, 0), 1)color_number = classes_ids.index(int(box.cls[0]))cv2.fillPoly(img, points, colors[color_number])cv2.imshow("Image", img)
cv2.waitKey(0)cv2.imwrite("YourSavePath", img)

參考

YOLOv9論文:

https://arxiv.org/abs/2402.13616

YOLOv9 Github地址:

https://github.com/WongKinYiu/yolov9

2、Yolo11

2.1、區域內目標跟蹤

?計算機視覺領域正在迅速發展,尤其是隨著生成式人工智能的出現,它正在推動該領域的進一步發展。當我們考慮檢測物體時,通常首先想到的是物體檢測。但為了獲得更好的結果,應該考慮使用物體跟蹤。這種方法不僅可以檢測物體,還可以隨著時間的推移跟蹤它們,為每個物體分配唯一的 ID,以獲得更準確、更全面的結果。

什么是 TrackZone?

????顧名思義,區域內跟蹤對象是一種 Ultralytics解決方案,旨在關注幀內的特定區域,以優化跟蹤過程。

????這種方法僅處理幀的一部分而不是分析整個幀,從而顯著提高了跟蹤速度。

圖片

????💡您可以將Ultralytics支持的任何模型與 TrackZone 一起使用。

TrackZone 的應用

??? TrackZone 可在各個行業中廣泛應用,實現高效的對象跟蹤:

  • 智能交通管理:它可以跟蹤車輛并預測停車位或公交車站等特定區域內的交通擁堵情況,而不是監控整條道路。
  • 零售和庫存管理:它可以監控特定區域(例如零售貨架),以有效跟蹤商品。由于零售商場攝像頭通常不是專門為貨架監控而安裝的,因此您可以只關注所需區域,而不是分析整個畫面。
  • 生產線監控:在生產線場景中,它可用于僅監控活躍的生產區域而不是整個框架,確保在最需要的地方進行精確的跟蹤。

代碼演示

????讓我們深入研究代碼!Ultralytics 在 Python 中提供 TrackZone 功能,您也可以通過 CLI 使用單行命令輕松執行它。

????對于每個解決方案,您都需要配置視頻路徑,并且(可選)還要配置模型文件。這同樣適用于 TrackZone:只需指定視頻路徑,如果需要,您還可以包含模型文件路徑。但是,這是可選的,因為yolo11n.pt將使用默認模型進行處理。

import cv2from ultralytics import solutionscap = cv2.VideoCapture("path/to/video/file.mp4")
assert cap.isOpened(), "Error reading video file"
w, h, fps = (int(cap.get(x)) for x in (cv2.CAP_PROP_FRAME_WIDTH,cv2.CAP_PROP_FRAME_HEIGHT,cv2.CAP_PROP_FPS))# Define region points
region_points = [(150, 150), (1130, 150), (1130, 570), (150, 570)]
# Video writer
video_writer = cv2.VideoWriter("object_counting_output.avi",cv2.VideoWriter_fourcc(*"mp4v"), fps, (w, h))# Init TrackZone (Object Tracking in Zones, not complete frame)
trackzone = solutions.TrackZone(show=True,  # Display the outputreginotallow=region_points,  # Pass region pointsmodel="yolo11n.pt",  # i.e. YOLOv8, YOLOv9, YOLOv10, YOLO11# line_width=2,  # line width for bounding boxes and text display# classes=[0, 2],  # count specific classes i.e. person and car.
)# Process video
while cap.isOpened():success, im0 = cap.read()if not success:breakim0 = trackzone.trackzone(im0)video_writer.write(im0)cap.release()
video_writer.release()
cv2.destroyAllWindows()

????CLI(命令行界面)與 Python 類似,您可以使用 、 等參數配置 TrackZone 解決方案region。可以在參數source部分找到可用參數的完整列表。

# Run a trackzone example
yolo solutions trackzone show=True# Pass a source video
yolo solutions trackzone show=True source="path/to/video/file.mp4"# Pass region coordinates
yolo solutions trackzone show=True \
reginotallow=[(150, 150), (1130, 150), (1130, 570), (150, 570)]

TrackZone 的優勢?

????與傳統的對象跟蹤模塊相比,TrackZone 具有多種優勢,其中最重要的優勢如下所述。

  • 速度:通過僅處理幀的特定部分,與需要跟蹤整個幀內對象的傳統對象跟蹤相比,它可以提供更快的速度。
  • 準確度:TrackZone 通過聚焦畫面的裁剪和放大區域來提高準確度。這使模型能夠更有效地檢測和跟蹤指定區域內的物體。
  • 邊緣設備兼容性:TrackZone 可以在NVIDIA Jetson等低功耗邊緣設備上表現良好,這使其非常適合物聯網系統。

2.2、自定義數據集撲克牌識別

GPU環境配置

????安裝CUDA和cudnn,配置環境變量。檢查是否安裝成功:

!nvidia-smi

YOLOv11訓練

?1. 安裝必要依賴項并檢查。

pip install ultralytics
import ultralytics
ultralytics.checks()

圖片

????2. 下載數據集。

????數據集下載地址:

https://www.google.com/url?q=https%3A%2F%2Funiverse.roboflow.com%2F

????安裝roboflow:

pip install roboflow

????下載數據集:

from roboflow import Roboflow
rf = Roboflow(api_key="UynPSQgEXONS23dKJYtP")
project = rf.workspace("roboflow-jvuqo").project("poker-cards-fmjio")
version = project.version(4)
dataset = version.download("yolov8")

?3. 模型訓練。

yolo task=detect mode=train model=yolo11s.pt data={dataset.location}/data.yaml epochs=10 imgsz=640 plots=True
Downloading https://github.com/ultralytics/assets/releases/download/v8.3.0/yolo11s.pt to 'yolo11s.pt'...
100% 18.4M/18.4M [00:00<00:00, 147MB/s] 
WARNING ?? yolo11s.pt appears to require 'dill', which is not in Ultralytics requirements.
AutoInstall will run now for 'dill' but this feature will be removed in the future.
Recommend fixes are to train a new model using the latest 'ultralytics' package or to run a command with an official Ultralytics model, i.e. 'yolo predict model=yolov8n.pt'
requirements: Ultralytics requirement ['dill'] not found, attempting AutoUpdate...
Collecting dillDownloading dill-0.3.9-py3-none-any.whl.metadata (10 kB)
Downloading dill-0.3.9-py3-none-any.whl (119 kB)━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 119.4/119.4 kB 4.0 MB/s eta 0:00:00
Installing collected packages: dill
Successfully installed dill-0.3.9requirements: AutoUpdate success ? 2.4s, installed 1 package: ['dill']
requirements: ?? Restart runtime or rerun command for updates to take effectUltralytics 8.3.1 🚀 Python-3.10.12 torch-2.4.1+cu121 CUDA:0 (Tesla T4, 15102MiB)
engine/trainer: task=detect, mode=train, model=yolo11s.pt, data=/content/datasets/poker-cards-4/data.yaml, epochs=10, time=None, patience=100, batch=16, imgsz=640, save=True, save_period=-1, cache=False, device=None, workers=8, project=None, name=train, exist_ok=False, pretrained=True, optimizer=auto, verbose=True, seed=0, deterministic=True, single_cls=False, rect=False, cos_lr=False, close_mosaic=10, resume=False, amp=True, fractinotallow=1.0, profile=False, freeze=None, multi_scale=False, overlap_mask=True, mask_ratio=4, dropout=0.0, val=True, split=val, save_jsnotallow=False, save_hybrid=False, cnotallow=None, iou=0.7, max_det=300, half=False, dnn=False, plots=True, source=None, vid_stride=1, stream_buffer=False, visualize=False, augment=False, agnostic_nms=False, classes=None, retina_masks=False, embed=None, show=False, save_frames=False, save_txt=False, save_cnotallow=False, save_crop=False, show_labels=True, show_cnotallow=True, show_boxes=True, line_width=None, format=torchscript, keras=False, optimize=False, int8=False, dynamic=False, simplify=True, opset=None, workspace=4, nms=False, lr0=0.01, lrf=0.01, momentum=0.937, weight_decay=0.0005, warmup_epochs=3.0, warmup_momentum=0.8, warmup_bias_lr=0.1, box=7.5, cls=0.5, dfl=1.5, pose=12.0, kobj=1.0, label_smoothing=0.0, nbs=64, hsv_h=0.015, hsv_s=0.7, hsv_v=0.4, degrees=0.0, translate=0.1, scale=0.5, shear=0.0, perspective=0.0, flipud=0.0, fliplr=0.5, bgr=0.0, mosaic=1.0, mixup=0.0, copy_paste=0.0, copy_paste_mode=flip, auto_augment=randaugment, erasing=0.4, crop_fractinotallow=1.0, cfg=None, tracker=botsort.yaml, save_dir=runs/detect/train
Downloading https://ultralytics.com/assets/Arial.ttf to '/root/.config/Ultralytics/Arial.ttf'...
100% 755k/755k [00:00<00:00, 13.6MB/s]
Overriding model.yaml nc=80 with nc=52from  n    params  module                                       arguments                     0                  -1  1       928  ultralytics.nn.modules.conv.Conv             [3, 32, 3, 2]                 1                  -1  1     18560  ultralytics.nn.modules.conv.Conv             [32, 64, 3, 2]                2                  -1  1     26080  ultralytics.nn.modules.block.C3k2            [64, 128, 1, False, 0.25]     3                  -1  1    147712  ultralytics.nn.modules.conv.Conv             [128, 128, 3, 2]              4                  -1  1    103360  ultralytics.nn.modules.block.C3k2            [128, 256, 1, False, 0.25]    5                  -1  1    590336  ultralytics.nn.modules.conv.Conv             [256, 256, 3, 2]              6                  -1  1    346112  ultralytics.nn.modules.block.C3k2            [256, 256, 1, True]           7                  -1  1   1180672  ultralytics.nn.modules.conv.Conv             [256, 512, 3, 2]              8                  -1  1   1380352  ultralytics.nn.modules.block.C3k2            [512, 512, 1, True]           9                  -1  1    656896  ultralytics.nn.modules.block.SPPF            [512, 512, 5]                 10                  -1  1    990976  ultralytics.nn.modules.block.C2PSA           [512, 512, 1]                 11                  -1  1         0  torch.nn.modules.upsampling.Upsample         [None, 2, 'nearest']          12             [-1, 6]  1         0  ultralytics.nn.modules.conv.Concat           [1]                           13                  -1  1    443776  ultralytics.nn.modules.block.C3k2            [768, 256, 1, False]          14                  -1  1         0  torch.nn.modules.upsampling.Upsample         [None, 2, 'nearest']          15             [-1, 4]  1         0  ultralytics.nn.modules.conv.Concat           [1]                           16                  -1  1    127680  ultralytics.nn.modules.block.C3k2            [512, 128, 1, False]          17                  -1  1    147712  ultralytics.nn.modules.conv.Conv             [128, 128, 3, 2]              18            [-1, 13]  1         0  ultralytics.nn.modules.conv.Concat           [1]                           19                  -1  1    345472  ultralytics.nn.modules.block.C3k2            [384, 256, 1, False]          20                  -1  1    590336  ultralytics.nn.modules.conv.Conv             [256, 256, 3, 2]              21            [-1, 10]  1         0  ultralytics.nn.modules.conv.Concat           [1]                           22                  -1  1   1511424  ultralytics.nn.modules.block.C3k2            [768, 512, 1, True]           23        [16, 19, 22]  1    839532  ultralytics.nn.modules.head.Detect           [52, [128, 256, 512]]         
YOLO11s summary: 319 layers, 9,447,916 parameters, 9,447,900 gradients, 21.7 GFLOPsTransferred 493/499 items from pretrained weights
TensorBoard: Start with 'tensorboard --logdir runs/detect/train', view at http://localhost:6006/
Freezing layer 'model.23.dfl.conv.weight'
AMP: running Automatic Mixed Precision (AMP) checks with YOLO11n...
Downloading https://github.com/ultralytics/assets/releases/download/v8.3.0/yolo11n.pt to 'yolo11n.pt'...
100% 5.36M/5.36M [00:00<00:00, 66.1MB/s]
AMP: checks failed ?. Anomalies were detected with AMP on your system that may lead to NaN losses or zero-mAP results, so AMP will be disabled during training.
train: Scanning /content/datasets/poker-cards-4/train/labels... 811 images, 0 backgrounds, 0 corrupt: 100% 811/811 [00:00<00:00, 2011.74it/s]
train: New cache created: /content/datasets/poker-cards-4/train/labels.cache
/usr/local/lib/python3.10/dist-packages/albumentations/__init__.py:13: UserWarning: A new version of Albumentations is available: 1.4.16 (you have 1.4.15). Upgrade using: pip install -U albumentations. To disable automatic update checks, set the environment variable NO_ALBUMENTATIONS_UPDATE to 1.check_for_updates()
albumentations: Blur(p=0.01, blur_limit=(3, 7)), MedianBlur(p=0.01, blur_limit=(3, 7)), ToGray(p=0.01, num_output_channels=3, method='weighted_average'), CLAHE(p=0.01, clip_limit=(1, 4.0), tile_grid_size=(8, 8))
val: Scanning /content/datasets/poker-cards-4/valid/labels... 44 images, 0 backgrounds, 0 corrupt: 100% 44/44 [00:00<00:00, 1103.19it/s]
val: New cache created: /content/datasets/poker-cards-4/valid/labels.cache
Plotting labels to runs/detect/train/labels.jpg... 
optimizer: 'optimizer=auto' found, ignoring 'lr0=0.01' and 'momentum=0.937' and determining best 'optimizer', 'lr0' and 'momentum' automatically... 
optimizer: AdamW(lr=0.000179, momentum=0.9) with parameter groups 81 weight(decay=0.0), 88 weight(decay=0.0005), 87 bias(decay=0.0)
TensorBoard: model graph visualization added ?
Image sizes 640 train, 640 val
Using 2 dataloader workers
Logging results to runs/detect/train
Starting training for 10 epochs...
Closing dataloader mosaic
albumentations: Blur(p=0.01, blur_limit=(3, 7)), MedianBlur(p=0.01, blur_limit=(3, 7)), ToGray(p=0.01, num_output_channels=3, method='weighted_average'), CLAHE(p=0.01, clip_limit=(1, 4.0), tile_grid_size=(8, 8))Epoch    GPU_mem   box_loss   cls_loss   dfl_loss  Instances       Size1/10      8.43G     0.7088      4.804      1.116         47        640: 100% 51/51 [00:32<00:00,  1.57it/s]Class     Images  Instances      Box(P          R      mAP50  mAP50-95): 100% 2/2 [00:02<00:00,  1.47s/it]all         44        197      0.354       0.32      0.137       0.12Epoch    GPU_mem   box_loss   cls_loss   dfl_loss  Instances       Size2/10      8.23G     0.5137      2.753      0.967         53        640: 100% 51/51 [00:30<00:00,  1.69it/s]Class     Images  Instances      Box(P          R      mAP50  mAP50-95): 100% 2/2 [00:00<00:00,  2.02it/s]all         44        197      0.567      0.504      0.539      0.474Epoch    GPU_mem   box_loss   cls_loss   dfl_loss  Instances       Size3/10      8.22G     0.4965      1.702     0.9366         49        640: 100% 51/51 [00:30<00:00,  1.67it/s]Class     Images  Instances      Box(P          R      mAP50  mAP50-95): 100% 2/2 [00:00<00:00,  2.46it/s]all         44        197        0.7      0.734      0.792       0.71Epoch    GPU_mem   box_loss   cls_loss   dfl_loss  Instances       Size4/10      8.22G     0.4684      1.183     0.9193         52        640: 100% 51/51 [00:31<00:00,  1.64it/s]Class     Images  Instances      Box(P          R      mAP50  mAP50-95): 100% 2/2 [00:00<00:00,  2.56it/s]all         44        197      0.738      0.875      0.895       0.81Epoch    GPU_mem   box_loss   cls_loss   dfl_loss  Instances       Size5/10      8.23G     0.4554     0.8986     0.9102         48        640: 100% 51/51 [00:30<00:00,  1.67it/s]Class     Images  Instances      Box(P          R      mAP50  mAP50-95): 100% 2/2 [00:00<00:00,  2.46it/s]all         44        197      0.851      0.858      0.935      0.845Epoch    GPU_mem   box_loss   cls_loss   dfl_loss  Instances       Size6/10      8.21G     0.4378     0.6888     0.8992         50        640: 100% 51/51 [00:30<00:00,  1.66it/s]Class     Images  Instances      Box(P          R      mAP50  mAP50-95): 100% 2/2 [00:00<00:00,  2.59it/s]all         44        197      0.909      0.894      0.969      0.879Epoch    GPU_mem   box_loss   cls_loss   dfl_loss  Instances       Size7/10      8.22G     0.4268     0.5645     0.8986         47        640: 100% 51/51 [00:30<00:00,  1.65it/s]Class     Images  Instances      Box(P          R      mAP50  mAP50-95): 100% 2/2 [00:00<00:00,  2.70it/s]all         44        197      0.928      0.941      0.979      0.889Epoch    GPU_mem   box_loss   cls_loss   dfl_loss  Instances       Size8/10      8.22G     0.4144     0.4976     0.8868         50        640: 100% 51/51 [00:31<00:00,  1.64it/s]Class     Images  Instances      Box(P          R      mAP50  mAP50-95): 100% 2/2 [00:00<00:00,  3.05it/s]all         44        197      0.951      0.941      0.985      0.893Epoch    GPU_mem   box_loss   cls_loss   dfl_loss  Instances       Size9/10      8.23G     0.4086      0.455     0.8818         48        640: 100% 51/51 [00:31<00:00,  1.64it/s]Class     Images  Instances      Box(P          R      mAP50  mAP50-95): 100% 2/2 [00:00<00:00,  3.19it/s]all         44        197      0.958      0.942      0.984      0.894Epoch    GPU_mem   box_loss   cls_loss   dfl_loss  Instances       Size10/10      8.21G     0.3975     0.4244     0.8819         52        640: 100% 51/51 [00:30<00:00,  1.65it/s]Class     Images  Instances      Box(P          R      mAP50  mAP50-95): 100% 2/2 [00:00<00:00,  3.12it/s]all         44        197      0.955      0.947      0.985      0.89910 epochs completed in 0.094 hours.
Optimizer stripped from runs/detect/train/weights/last.pt, 19.2MB
Optimizer stripped from runs/detect/train/weights/best.pt, 19.2MBValidating runs/detect/train/weights/best.pt...
Ultralytics 8.3.1 🚀 Python-3.10.12 torch-2.4.1+cu121 CUDA:0 (Tesla T4, 15102MiB)
YOLO11s summary (fused): 238 layers, 9,432,924 parameters, 0 gradients, 21.4 GFLOPsClass     Images  Instances      Box(P          R      mAP50  mAP50-95): 100% 2/2 [00:01<00:00,  1.95it/s]all         44        197      0.955      0.946      0.985      0.89810 of clubs          3          3      0.963          1      0.995       0.9410 of diamonds          7          7      0.981          1      0.995      0.95910 of hearts          7          7      0.996          1      0.995      0.87710 of spades          4          4       0.99          1      0.995      0.6922 of clubs          2          2      0.936          1      0.995      0.9952 of diamonds          2          2      0.951          1      0.995      0.9952 of hearts          1          1      0.914          1      0.995      0.8952 of spades          4          4          1       0.69      0.995      0.9083 of clubs          2          2      0.818          1      0.995      0.9953 of diamonds          2          2      0.928          1      0.995      0.8953 of hearts          1          1      0.917          1      0.995      0.8953 of spades          4          4       0.97       0.75      0.758      0.6334 of clubs          2          2      0.935          1      0.995      0.9954 of diamonds          2          2      0.969          1      0.995      0.9954 of hearts          1          1      0.925          1      0.995      0.8954 of spades          4          4          1       0.79      0.995      0.7655 of clubs          8          8          1       0.74      0.879      0.8235 of diamonds          3          3          1      0.446      0.995      0.9415 of hearts          3          3      0.969          1      0.995      0.8635 of spades          1          1      0.968          1      0.995      0.9956 of clubs          7          7      0.977          1      0.995      0.9776 of diamonds          3          3      0.624          1      0.995      0.9296 of hearts          3          3      0.965          1      0.995      0.8956 of spades          1          1      0.926          1      0.995      0.8957 of clubs          7          7      0.984          1      0.995      0.9337 of diamonds          3          3      0.982          1      0.995      0.9957 of hearts          3          3      0.974          1      0.995      0.8097 of spades          1          1      0.916          1      0.995      0.7968 of clubs          7          7          1      0.871      0.995      0.9958 of diamonds          3          3      0.898      0.333       0.83      0.7978 of hearts          3          3      0.972          1      0.995      0.9298 of spades          1          1      0.917          1      0.995      0.9959 of clubs          3          3      0.965          1      0.995      0.9519 of diamonds          7          7      0.981          1      0.995      0.9529 of hearts          7          7      0.982          1      0.995      0.8639 of spades          4          4      0.999          1      0.995      0.822ace of clubs          2          2      0.941          1      0.995      0.995ace of diamonds          2          2      0.964          1      0.995      0.796ace of hearts          1          1      0.922          1      0.995      0.895ace of spades          4          4          1      0.787      0.995      0.863jack  of clubs          3          3      0.956          1      0.995      0.995jack of diamonds          7          7          1      0.988      0.995      0.995jack of hearts          6          6      0.846          1      0.972      0.827jack of spades          4          4      0.973          1      0.995      0.487king of clubs          3          3      0.968          1      0.995      0.995king of diamonds          7          7      0.986          1      0.995      0.982king of hearts          7          7      0.985          1      0.995      0.906king of spades          4          4      0.975          1      0.995      0.846queen of clubs          3          3          1      0.819      0.995      0.963queen of diamonds          7          7       0.98          1      0.995      0.995queen of hearts          7          7      0.986          1      0.995       0.92queen of spades          4          4      0.978          1      0.995      0.773
Speed: 0.2ms preprocess, 9.6ms inference, 0.0ms loss, 1.9ms postprocess per image
Results saved to runs/detect/train
💡 Learn more at https://docs.ultralytics.com/modes/train

from IPython.display import Image as IPyImageIPyImage(filename=f'{HOME}/runs/detect/train/confusion_matrix.png', width=600)

from IPython.display import Image as IPyImageIPyImage(filename=f'{HOME}/runs/detect/train/results.png', width=600)

from IPython.display import Image as IPyImageIPyImage(filename=f'{HOME}/runs/detect/train/val_batch0_pred.jpg', width=600)

????4.?模型驗證微調

yolo task=detect mode=val model={HOME}/runs/detect/train/weights/best.pt data={dataset.location}/data.yaml
Ultralytics 8.3.1 🚀 Python-3.10.12 torch-2.4.1+cu121 CUDA:0 (Tesla T4, 15102MiB)
YOLO11s summary (fused): 238 layers, 9,432,924 parameters, 0 gradients, 21.4 GFLOPs
val: Scanning /content/datasets/poker-cards-4/valid/labels.cache... 44 images, 0 backgrounds, 0 corrupt: 100% 44/44 [00:00<?, ?it/s]Class     Images  Instances      Box(P          R      mAP50  mAP50-95): 100% 3/3 [00:03<00:00,  1.13s/it]all         44        197      0.955      0.946      0.985      0.89810 of clubs          3          3      0.963          1      0.995       0.9410 of diamonds          7          7      0.981          1      0.995      0.95910 of hearts          7          7      0.996          1      0.995      0.87710 of spades          4          4       0.99          1      0.995      0.6922 of clubs          2          2      0.936          1      0.995      0.9952 of diamonds          2          2      0.951          1      0.995      0.9952 of hearts          1          1      0.914          1      0.995      0.8952 of spades          4          4          1       0.69      0.995      0.9083 of clubs          2          2      0.818          1      0.995      0.9953 of diamonds          2          2      0.928          1      0.995      0.8953 of hearts          1          1      0.917          1      0.995      0.8953 of spades          4          4       0.97       0.75      0.758      0.6334 of clubs          2          2      0.935          1      0.995      0.9954 of diamonds          2          2      0.969          1      0.995      0.9954 of hearts          1          1      0.925          1      0.995      0.8954 of spades          4          4          1       0.79      0.995      0.7655 of clubs          8          8          1       0.74      0.879      0.8235 of diamonds          3          3          1      0.446      0.995      0.9415 of hearts          3          3      0.969          1      0.995      0.8635 of spades          1          1      0.968          1      0.995      0.9956 of clubs          7          7      0.977          1      0.995      0.9776 of diamonds          3          3      0.624          1      0.995      0.9296 of hearts          3          3      0.965          1      0.995      0.8956 of spades          1          1      0.926          1      0.995      0.8957 of clubs          7          7      0.984          1      0.995      0.9337 of diamonds          3          3      0.982          1      0.995      0.9957 of hearts          3          3      0.974          1      0.995      0.8097 of spades          1          1      0.916          1      0.995      0.7968 of clubs          7          7          1      0.871      0.995      0.9958 of diamonds          3          3      0.898      0.333       0.83      0.7978 of hearts          3          3      0.972          1      0.995      0.9298 of spades          1          1      0.917          1      0.995      0.9959 of clubs          3          3      0.965          1      0.995      0.9519 of diamonds          7          7      0.981          1      0.995      0.9529 of hearts          7          7      0.982          1      0.995      0.8639 of spades          4          4      0.999          1      0.995      0.822ace of clubs          2          2      0.941          1      0.995      0.995ace of diamonds          2          2      0.964          1      0.995      0.796ace of hearts          1          1      0.922          1      0.995      0.895ace of spades          4          4          1      0.787      0.995      0.863jack  of clubs          3          3      0.956          1      0.995      0.995jack of diamonds          7          7          1      0.988      0.995      0.995jack of hearts          6          6      0.846          1      0.972      0.827jack of spades          4          4      0.973          1      0.995      0.487king of clubs          3          3      0.968          1      0.995      0.995king of diamonds          7          7      0.986          1      0.995      0.982king of hearts          7          7      0.985          1      0.995      0.906king of spades          4          4      0.975          1      0.995      0.846queen of clubs          3          3          1      0.819      0.995      0.963queen of diamonds          7          7       0.98          1      0.995      0.995queen of hearts          7          7      0.986          1      0.995       0.92queen of spades          4          4      0.978          1      0.995      0.773
Speed: 7.9ms preprocess, 16.0ms inference, 0.0ms loss, 27.2ms postprocess per image
Results saved to runs/detect/val
💡 Learn more at https://docs.ultralytics.com/modes/val

????5. 模型推理。

yolo task=detect mode=predict model={HOME}/runs/detect/train/weights/best.pt cnotallow=0.25 source={dataset.location}/test/images save=True
Ultralytics 8.3.1 🚀 Python-3.10.12 torch-2.4.1+cu121 CUDA:0 (Tesla T4, 15102MiB)
YOLO11s summary (fused): 238 layers, 9,432,924 parameters, 0 gradients, 21.4 GFLOPsimage 1/44 /content/datasets/poker-cards-4/test/images/IMG_20220316_134701_jpg.rf.27aa29de9d6012ae05c64b156f7c07b8.jpg: 640x640 1 2 of spades, 1 3 of spades, 1 4 of spades, 1 ace of spades, 15.8ms
image 2/44 /content/datasets/poker-cards-4/test/images/IMG_20220316_135012_jpg.rf.ee7179374d33235528db011cb5418226.jpg: 640x640 1 2 of spades, 1 3 of spades, 1 4 of spades, 1 ace of spades, 15.8ms
image 3/44 /content/datasets/poker-cards-4/test/images/IMG_20220316_135021_jpg.rf.d038afdef1a927103dae268ff392888f.jpg: 640x640 1 2 of spades, 1 3 of spades, 1 4 of spades, 1 ace of spades, 15.8ms
image 4/44 /content/datasets/poker-cards-4/test/images/IMG_20220316_140241_jpg.rf.c44522806b5455bfb03a638aa3ffa896.jpg: 640x640 2 5 of spadess, 1 6 of spades, 2 7 of spadess, 1 8 of spades, 15.7ms
image 5/44 /content/datasets/poker-cards-4/test/images/IMG_20220316_140255_jpg.rf.0d10768652a0f20bea317e96632d3448.jpg: 640x640 1 5 of spades, 1 6 of spades, 1 7 of spades, 2 8 of spadess, 15.7ms
image 6/44 /content/datasets/poker-cards-4/test/images/IMG_20220316_140335_jpg.rf.c3310d8f13f66189440daf8419b1ad9c.jpg: 640x640 1 5 of spades, 1 6 of spades, 1 7 of spades, 1 8 of spades, 15.7ms
image 7/44 /content/datasets/poker-cards-4/test/images/IMG_20220316_140400_jpg.rf.3f21e54bd916b05218202fbf109d8a5f.jpg: 640x640 1 5 of spades, 1 6 of spades, 1 7 of spades, 1 8 of spades, 15.5ms
image 8/44 /content/datasets/poker-cards-4/test/images/IMG_20220316_140723_jpg.rf.826bc2b212c4001c11115ef28f58d142.jpg: 640x640 1 5 of spades, 1 6 of spades, 1 7 of spades, 2 8 of spadess, 13.7ms
image 9/44 /content/datasets/poker-cards-4/test/images/IMG_20220316_141442_jpg.rf.41913768e5d56c57566ee3b45391470d.jpg: 640x640 1 10 of spades, 1 9 of spades, 1 jack of spades, 1 king of spades, 1 queen of spades, 13.8ms
image 10/44 /content/datasets/poker-cards-4/test/images/IMG_20220316_141917_jpg.rf.b3075e4161fe5fa2285d75bb2da3bc7a.jpg: 640x640 1 10 of spades, 1 9 of spades, 1 jack of spades, 1 king of spades, 1 queen of spades, 13.7ms
image 11/44 /content/datasets/poker-cards-4/test/images/IMG_20220316_141940_jpg.rf.e0ca71cfc8dc86a6624c3f90fe6c5e9e.jpg: 640x640 1 10 of spades, 1 9 of spades, 1 jack of spades, 1 king of spades, 1 queen of spades, 13.7ms
image 12/44 /content/datasets/poker-cards-4/test/images/IMG_20220316_142643_jpg.rf.13b0a2a65a9d4b17580b39ed19de5bba.jpg: 640x640 1 2 of hearts, 1 3 of hearts, 1 4 of hearts, 1 ace of hearts, 13.7ms
image 13/44 /content/datasets/poker-cards-4/test/images/IMG_20220316_144500_jpg.rf.14c3cb5eadd6c3d449916f52d9f9381e.jpg: 640x640 1 5 of hearts, 1 6 of hearts, 1 7 of hearts, 1 8 of hearts, 13.7ms
image 14/44 /content/datasets/poker-cards-4/test/images/IMG_20220316_144507_jpg.rf.ab9b95792bbdbe7694910967641fba38.jpg: 640x640 1 5 of hearts, 1 6 of hearts, 1 7 of hearts, 1 8 of hearts, 14.3ms
image 15/44 /content/datasets/poker-cards-4/test/images/IMG_20220316_144511_jpg.rf.40ee049c8f854c558e2ca20f90be3787.jpg: 640x640 1 5 of hearts, 1 6 of hearts, 1 7 of hearts, 1 8 of hearts, 13.7ms
image 16/44 /content/datasets/poker-cards-4/test/images/IMG_20220316_144650_jpg.rf.34b246c8ee646cbb5979a35d68c58901.jpg: 640x640 1 5 of hearts, 1 6 of hearts, 1 7 of hearts, 1 8 of hearts, 11.6ms
image 17/44 /content/datasets/poker-cards-4/test/images/IMG_20220316_144652_jpg.rf.316d0dad84d3d696fa8fa3caf53fb700.jpg: 640x640 1 5 of hearts, 1 6 of hearts, 1 7 of hearts, 1 8 of hearts, 10.0ms
image 18/44 /content/datasets/poker-cards-4/test/images/IMG_20220316_144657_jpg.rf.0b7bb9ab4b594b83097af9c4c1ea46c3.jpg: 640x640 1 5 of hearts, 1 6 of hearts, 1 7 of hearts, 1 8 of hearts, 10.0ms
image 19/44 /content/datasets/poker-cards-4/test/images/IMG_20220316_144711_jpg.rf.19a6cc13f83f27b45e10a6056bb25721.jpg: 640x640 1 5 of hearts, 1 6 of hearts, 1 7 of hearts, 1 8 of hearts, 10.0ms
image 20/44 /content/datasets/poker-cards-4/test/images/IMG_20220316_161217_jpg.rf.1755e5fefb14ca6df49690604289bb46.jpg: 640x640 1 10 of hearts, 1 9 of hearts, 1 jack of hearts, 1 king of hearts, 1 queen of hearts, 10.0ms
image 21/44 /content/datasets/poker-cards-4/test/images/IMG_20220316_161313_jpg.rf.12498ecbc8985a8ff65bd2033d8f622a.jpg: 640x640 1 10 of hearts, 1 9 of hearts, 1 jack of hearts, 1 king of hearts, 1 queen of hearts, 10.0ms
image 22/44 /content/datasets/poker-cards-4/test/images/IMG_20220316_161455_jpg.rf.635ccd0ee9f7dd762009f539d6b998e9.jpg: 640x640 1 10 of hearts, 1 9 of hearts, 1 jack of hearts, 1 king of hearts, 1 queen of hearts, 9.8ms
image 23/44 /content/datasets/poker-cards-4/test/images/IMG_20220316_161515_jpg.rf.b22dd5d2b8037f009a9e65052d2d3b5c.jpg: 640x640 1 10 of hearts, 1 9 of hearts, 1 jack of hearts, 1 king of hearts, 1 queen of hearts, 9.9ms
image 24/44 /content/datasets/poker-cards-4/test/images/IMG_20220316_161525_jpg.rf.f7962cdc50e0a3cd03e4c081a1d2a67a.jpg: 640x640 1 10 of hearts, 1 9 of hearts, 1 jack of hearts, 1 king of hearts, 1 queen of hearts, 9.8ms
image 25/44 /content/datasets/poker-cards-4/test/images/IMG_20220316_162828_jpg.rf.db7557485f5c3e5ce01b2e1ab3d4621e.jpg: 640x640 1 2 of diamonds, 1 3 of diamonds, 1 4 of diamonds, 1 ace of diamonds, 9.9ms
image 26/44 /content/datasets/poker-cards-4/test/images/IMG_20220316_163749_jpg.rf.3c41ec25d2a8390c760eb7fcf2d2466b.jpg: 640x640 1 5 of diamonds, 1 6 of diamonds, 1 7 of diamonds, 1 8 of diamonds, 9.9ms
image 27/44 /content/datasets/poker-cards-4/test/images/IMG_20220316_163800_jpg.rf.e1ad0b7b78e379d5f9f0bec787a9050b.jpg: 640x640 1 5 of diamonds, 1 6 of diamonds, 1 7 of diamonds, 1 8 of diamonds, 8.9ms
image 28/44 /content/datasets/poker-cards-4/test/images/IMG_20220316_164227_jpg.rf.e42455b79bae041d959f90597b7065bc.jpg: 640x640 1 5 of diamonds, 1 6 of diamonds, 1 7 of diamonds, 1 8 of diamonds, 8.5ms
image 29/44 /content/datasets/poker-cards-4/test/images/IMG_20220316_164257_jpg.rf.0c3abfccf0f7f147946c89251b87f598.jpg: 640x640 1 5 of diamonds, 1 6 of diamonds, 1 7 of diamonds, 1 8 of diamonds, 8.4ms
image 30/44 /content/datasets/poker-cards-4/test/images/IMG_20220316_165206_jpg.rf.1e20afbea0b132989e944ffbd800f348.jpg: 640x640 1 10 of diamonds, 1 9 of diamonds, 1 jack of diamonds, 1 king of diamonds, 1 queen of diamonds, 9.5ms
image 31/44 /content/datasets/poker-cards-4/test/images/IMG_20220316_165221_jpg.rf.a5188caf60a7bd5e8c6dcf92d68f9505.jpg: 640x640 1 10 of diamonds, 1 9 of diamonds, 1 jack of diamonds, 1 king of diamonds, 1 queen of diamonds, 8.1ms
image 32/44 /content/datasets/poker-cards-4/test/images/IMG_20220316_165711_jpg.rf.c64b84b61322947a5a8c7545e214278c.jpg: 640x640 1 10 of diamonds, 1 9 of diamonds, 1 jack of diamonds, 1 king of diamonds, 1 queen of diamonds, 9.0ms
image 33/44 /content/datasets/poker-cards-4/test/images/IMG_20220316_165737_jpg.rf.11f2e19b001c300ee820e093b135409a.jpg: 640x640 1 10 of diamonds, 1 9 of diamonds, 1 jack of diamonds, 1 king of diamonds, 1 queen of diamonds, 8.4ms
image 34/44 /content/datasets/poker-cards-4/test/images/IMG_20220316_170523_jpg.rf.a106d534bf3279ec40e771452a142c1e.jpg: 640x640 1 2 of clubs, 1 3 of clubs, 1 4 of clubs, 1 ace of clubs, 8.9ms
image 35/44 /content/datasets/poker-cards-4/test/images/IMG_20220316_170755_jpg.rf.71804c21e1c7681d5b656427449e0a2a.jpg: 640x640 1 2 of clubs, 1 3 of clubs, 1 4 of clubs, 1 ace of clubs, 8.1ms
image 36/44 /content/datasets/poker-cards-4/test/images/IMG_20220316_171557_jpg.rf.9c6f913ba56e578ef4c31cc3faffcf7d.jpg: 640x640 1 5 of clubs, 1 6 of clubs, 1 7 of clubs, 1 8 of clubs, 8.1ms
image 37/44 /content/datasets/poker-cards-4/test/images/IMG_20220316_171653_jpg.rf.637e380597f1d844654a33f4a3555471.jpg: 640x640 1 5 of clubs, 1 6 of clubs, 1 7 of clubs, 1 8 of clubs, 9.2ms
image 38/44 /content/datasets/poker-cards-4/test/images/IMG_20220316_171810_jpg.rf.be96dac3cbdda6973a920a0a787b33f2.jpg: 640x640 1 5 of clubs, 1 6 of clubs, 2 7 of clubss, 10.4ms
image 39/44 /content/datasets/poker-cards-4/test/images/IMG_20220316_171916_jpg.rf.7c8b85f64455e815acc30b5111422bf2.jpg: 640x640 1 5 of clubs, 1 6 of clubs, 1 7 of clubs, 1 8 of clubs, 7.9ms
image 40/44 /content/datasets/poker-cards-4/test/images/IMG_20220316_171936_jpg.rf.b6e31b1cc6b5e14dc66462becfa4a63d.jpg: 640x640 1 5 of clubs, 1 6 of clubs, 1 7 of clubs, 1 8 of clubs, 7.7ms
image 41/44 /content/datasets/poker-cards-4/test/images/IMG_20220316_172435_jpg.rf.854fe0c471b03fe3a3894a3d2cbe00d0.jpg: 640x640 1 10 of clubs, 1 9 of clubs, 1 jack  of clubs, 1 king of clubs, 1 queen of clubs, 8.0ms
image 42/44 /content/datasets/poker-cards-4/test/images/IMG_20220316_172537_jpg.rf.8fe076e115c111f04732f8e7f778e51d.jpg: 640x640 1 10 of clubs, 1 9 of clubs, 1 jack  of clubs, 1 king of clubs, 1 queen of clubs, 7.8ms
image 43/44 /content/datasets/poker-cards-4/test/images/IMG_20220316_172800_jpg.rf.e63a3bae897cbf27dccbf969f543bb6f.jpg: 640x640 1 10 of clubs, 1 9 of clubs, 1 jack  of clubs, 1 king of clubs, 1 queen of clubs, 8.0ms
image 44/44 /content/datasets/poker-cards-4/test/images/IMG_20220316_173229_jpg.rf.1b93cc9a66ca2d0a28820a7dae74222a.jpg: 640x640 3 10 of clubss, 1 9 of clubs, 1 jack  of clubs, 1 king of clubs, 1 queen of clubs, 8.5ms
Speed: 1.5ms preprocess, 11.0ms inference, 14.9ms postprocess per image at shape (1, 3, 640, 640)
Results saved to runs/detect/predict
💡 Learn more at https://docs.ultralytics.com/modes/predict

????查看部分結果:

import glob
import os
from IPython.display import Image as IPyImage, displaylatest_folder = max(glob.glob('/content/runs/detect/predict*/'), key=os.path.getmtime)
for img in glob.glob(f'{latest_folder}/*.jpg')[:3]:display(IPyImage(filename=img, width=600))print("\n")

3、Yolo3

3.1、YOLO3~DIou

現在都yolo7了? 還老生常談~~ 基于DIou改進的YOLOv3目標檢測

DIoU要比GIou更加符合目標框回歸的機制,將目標與anchor之間的距離,重疊率以及尺度都考慮進去,使得目標框回歸變得更加穩定,不會像IoU和GIoU一樣出現訓練過程中發散等問題,并且方法能夠簡單地遷移到現有的算法中帶來性能的提升,實驗在YOLOv3上提升了5.91mAP。

IoU loss顧名思義就是直接通過IoU計算梯度進行回歸,論文提到IoU loss的無法避免的缺點:當兩個box無交集時,IoU=0,很近的無交集框和很遠的無交集框的輸出一樣,這樣就失去了梯度方向,無法優化。IoU loss的實現形式有很多種,除公式2外,還有UnitBox的交叉熵形式和IoUNet的Smooth-L1形式。?

上圖可以很好的來說明GIoU不穩定以及收斂很慢的原因。上圖中第一行三張圖展示的是GIoU的回歸過程,其中綠色框為目標框,黑色框為anchor,藍色框為不同次數的迭代后,anchor的偏移結果。第二行三張圖展示的是DIoU的回歸過程,其中綠色框為目標框,黑色框為anchor,紅色框為不同次數的迭代后,anchor的偏移結果。從圖中我們可以看到,GIoU在回歸的過程中,從損失函數的形式我們發現,當IoU為0時,GIoU會先盡可能讓anchor能夠和目標框產生重疊,之后GIoU會漸漸退化成IoU回歸策略,因此整個過程會非常緩慢而且存在發散的風險。而DIoU考慮到anchor和目標之間的中心點距離,可以更快更有效更穩定的進行回歸。??

如上圖中的包含情況,GIoU會退化成IoU(三個位置預測框和gt框所包圍的最小面積相同,懲罰項c保持一致,梯度發散)。由于很大程度依賴IoU項,GIoU需要更多的迭代次數來收斂,特別是水平和垂直的bbox(后面會分析)。一般地,GIoU loss不能很好地收斂SOTA算法,反而造成不好的結果。

綜合上面的分析,論文提出Distance-IoU(DIoU) loss,簡單地在IoU loss基礎上添加一個懲罰項,該懲罰項用于最小化兩個bbox的中心點距離。如圖1所示,DIoU收斂速度和效果都很好,而且DIoU能夠用于NMS的計算中,不僅考慮了重疊區域,還考慮了中心點距離。另外,論文考慮bbox的三要素,重疊區域,中心點距離和長寬比,進一步提出了Complete IoU(CIoU) loss,收斂更快,效果更好。

IoU and GIoU Losses

為了全面地分析IoU loss和GIoU的性能,論文進行了模擬實驗,模擬不同的距離、尺寸和長寬比的bbox的回歸情況,如下圖所示:

  • 綠色框代表仿真實驗需要回歸的七個不同尺度的目標框,七個目標框的中心點坐標都是(10 * 10);
  • 藍色的點代表了所有anchor的中心點,中心點的分布如上圖所示,各個方向都有,各種距離都有,當然每個anchor的一個中心點都包含有七個不同面積的anchor框。而且每個面積的anchor框又有七種不同的比例尺寸。因此一共有5000個藍色點,對應5000*7*7個anchor框,并且每個anchor框都需要回歸到七個gt目標框上,因此一共有5000*7*7*7個回歸案例。

最終的實驗結果如下:圖中展示的訓練同樣的步數后(200步),IoU,GIoU以及本文提出的DIoU、CIoU作為loss的情況下,每個anchor的誤差分布。

  • IoU:從IoU誤差的曲線我們可以發現,anchor越靠近邊緣,誤差越大,那些與目標框沒有重疊的anchor基本無法回歸;
  • GIoU:從GIoU誤差的曲線我們可以發現,對于一些沒有重疊的anchor,GIoU的表現要比IoU更好。但是由于GIoU仍然嚴重的依賴IoU,因此在兩個垂直方向,誤差很大,基本很難收斂,這就是GIoU不穩定的原因;
  • DIoU:從DIoU誤差的曲線我們可以發現,對于不同距離,方向,面積和比例的anchor,DIoU都能做到較好的回歸。

具體偽算法步驟如下:

論文將5000個中心點上的bbox在最后階段的total error進行了可視化。IoU loss只對與target box有交集的bbox有效,因為無交集的bbox的梯度為0。而GIoU由于增加了懲罰函數,中間大部分區域錯誤率明顯減少,但是垂直和水平的區域依然保持著高的error,這是由于GIoU的懲罰項經常很小甚至為0,導致訓練需要更多的迭代來收斂。?

3.2、YOLOv3~ COCO

?YOLOv3 模型使用COCO 數據集, 雖然yolo3也不用就全當學習哦

在 Kaggle 平臺使用 GPU 跑通 YOLOv3 訓練代碼.

  • COCO 2014 數據集地址(原始):https://cocodataset.org/
  • COCO 2014 數據集地址(Kaggle):https://www.kaggle.com/datasets/jeffaudi/coco-2014-dataset-for-yolov3
  • YOLOv3 原文項目地址:https://pjreddie.com/darknet/yolo/
  • 本次使用的 YOLOv3 項目地址(PyTorch):https://github.com/eriklindernoren/PyTorch-YOLOv3

跑通 YOLOv3 訓練過程,讀者會熟悉 YOLOv3 項目的文件及 Linux 文件操作,整個過程分為以下幾步。

  • 下載項目代碼
  • 下載和配置數據集中的圖像列表
  • 修改 coco.data 配置文件
  • 下載預訓練模型權重
  • 訓練模型

輸出目錄 第一行體現了 PyTorch-YOLOv3 項目在 Kaggle 平臺的地址為???/kaggle/working/PyTorch-YOLOv3??,每個文件夾的作用展示在下圖中。?

下載和配置數據集中的圖像列表添加平臺上存在的數據集

在 Kaggle 上點擊【Add Data】輸入數據集的名稱或者地址,即可導入數據集,數據集比較大,需要十幾分鐘的時間。

?接著進入???/kaggle???地址下查看里面有哪些內容,圖片太多了,便不顯示全部文件了,只顯示到了文件夾。?

點擊數據集里文件夾的右側,可以直接復制地址。?

由此獲得:

  • Input 文件夾下存放數據集,地址為:??/kaggle/input/coco-2014-dataset-for-yolov3??
  • 圖片的地址:??/kaggle/input/coco-2014-dataset-for-yolov3/coco2014/images??
  • 標簽的地址:??/kaggle/input/coco-2014-dataset-for-yolov3/coco2014/labels??

下載 coco 工具包及配置數據集中的圖像列表

項目文件中數據集的下載指令:

cd PyTorch-YOLOv3/  
./data/get_coco_dataset.sh

可以知道項目期望的數據集地址為???PyTorch-YOLOv3/data/coco/images??

查看??get_coco_dataset.sh??,內容如下:

#!/bin/bash  # CREDIT: https://github.com/pjreddie/darknet/tree/master/scripts/get_coco_dataset.sh  # Clone COCO API,需要操作  
git clone https://github.com/pdollar/coco  
cd coco  mkdir images  
cd images  # Download Images 已經存在,無需操作  
wget -c https://pjreddie.com/media/files/train2014.zip  
wget -c https://pjreddie.com/media/files/val2014.zip  # Unzip  
unzip -q train2014.zip  
unzip -q val2014.zip  cd ..  # Download COCO Metadata,此處只用下載 5k.part 和 trainvalno5k.part  
wget -c https://pjreddie.com/media/files/instances_train-val2014.zip  
wget -c https://pjreddie.com/media/files/coco/5k.part  
wget -c https://pjreddie.com/media/files/coco/trainvalno5k.part  
wget -c https://pjreddie.com/media/files/coco/labels.tgz  
tar xzf labels.tgz  
unzip -q instances_train-val2014.zip  # Set Up Image Lists,關鍵操作  
paste <(awk "{print \"$PWD\"}" <5k.part) 5k.part | tr -d '\t' > 5k.txt  
paste <(awk "{print \"$PWD\"}" <trainvalno5k.part) trainvalno5k.part | tr -d '\t' > trainvalno5k.txt

因為在 Kaggle 中直接引用了數據集,里面的??5k.part????和???trainvalno5k.part????沒有處理成???5k.txt????和???trainvalno5k.txt???,并且 Input 文件夾下沒有操作的權限,便在???PyTorch-YOLOv3/data/coco/images???項目下處理。

圖片在 Kaggle 里的地址:??/kaggle/input/coco-2014-dataset-for-yolov3/coco2014/images/train2014/COCO_train2014_000000000009.jpg??

修改 Set Up Image Lists 的代碼并且執行

$PWD 替換為???/kaggle/input/coco-2014-dataset-for-yolov3/coco2014??,保證圖像的列表地址是可以對應上的,代碼如下。

!wget -c https://pjreddie.com/media/files/coco/5k.part  
!paste <(awk "{print \"/kaggle/input/coco-2014-dataset-for-yolov3/coco2014\"}" <5k.part) 5k.part | tr -d '\t' > 5k.txt  !wget -c https://pjreddie.com/media/files/coco/trainvalno5k.part  
!paste <(awk "{print \"/kaggle/input/coco-2014-dataset-for-yolov3/coco2014\"}" <trainvalno5k.part) trainvalno5k.part | tr -d '\t' > trainvalno5k.txt  
%ls

修改 coco.data 配置文件

原來項目的配置文件 coco.data 的內容如下:

classes= 80  
train=data/coco/trainvalno5k.txt  
valid=data/coco/5k.txt  
names=data/coco.names  
backup=backup/  
eval=coco

修改成 Kaggle 平臺所在的地址:

classes= 80  
train=/kaggle/working/PyTorch-YOLOv3/data/coco/trainvalno5k.txt  
valid=/kaggle/working/PyTorch-YOLOv3/data/coco/5k.txt  
names=/kaggle/working/PyTorch-YOLOv3/data/coco.names  
backup=backup/  
eval=coco

使用 readlines 讀取 coco.data 文件的內容到列表里,接下來修改 train\valid\names 的地址(字符串)。

將 coco.data 更名為 coco_original.data,新建 coco.data 文件,把列表 file_list 的每一行寫入 coco.data 文件里。

下載預訓練權重

預訓練權重包括:

  • YOLOv3 權重(標準版)
  • Tiny-YOLOv3 權重(輕量版)
  • darknet53 權重(骨干網絡)

先到 weights 文件夾下???%cd /kaggle/working/PyTorch-YOLOv3/weights/???,執行命令??!./download_weights.sh??。

訓練模型 ? ?

進入???/kaggle/working/PyTorch-YOLOv3???路徑下,使用預訓練模型 darknet53.conv.74 訓練模型。

把???/kaggle/working/PyTorch-YOLOv3/pytorchyolo/train.py????下的 train.py 代碼移動到???/kaggle/working/PyTorch-YOLOv3/???。

!python train.py --data config/coco.data  --pretrained_weights weights/darknet53.conv.74

train文件命令行參數說明

  • --epochs: 訓練大循環數量。類型為‘整形’,默認參數為100;
  • --batch_size: 批大小。類型為‘整形’,默認參數為8;
  • --gradient_accumulations: 累積多少個梯度再進行更新。類型為‘整形’,默認參數為2;
  • --model_def: 模型定義文件路徑。類型為‘字符串’,默認參數為"config/yolov3.cfg";
  • --data config: 數據配置文件路徑。類型為‘字符串’,默認參數為"config/coco.data";
  • --pretrained_weights: 如果從指定從檢查點模型開始訓練就填寫檢查點路徑。類型為‘字符串’,無默認參數;
  • --n_cpu: 批量生成時使用的cpu線程數。類型為‘整形’,默認參數為8;
  • --img_size: 圖片大小。類型為‘整形’,默認參數為416;
  • --checkpoint_interval: 保存模型權重的時間間隔。類型為‘整形’,默認參數為1;
  • --evaluation_interval: 使用驗證集驗證的時間間隔。類型為‘整形’,默認參數為1;
  • --compute_map: 如果是True則每10個batch計算一次mAP。類型為‘布爾值’,默認參數為False;
  • --multiscale_training: 是否允許進行多尺度訓練。類型為‘布爾值’,默認參數為True。

在 Kaggle 平臺上安裝不上 poetry,沒有使用官網推薦的訓練方式,如下。

poetry run yolo-train --data config/coco.data  --pretrained_weights weights/darknet53.conv.74

在【Settings】選擇 GPU 進行訓練,GPU 的配置應該放在啟動代碼環境時設置。

安裝需要的包 ?terminaltables 和 torchsummary,執行代碼開始訓練。

數據集太大了,選擇 GPU P100 訓練了 7 小時,才 4 個 Epoch,本次練習側重讓大家熟悉 YOLOv3 項目的文件。?

4、Yolo7

4.1、Yolo7~農業方向

這里使用了一種單階段目標檢測算法,并將基于CNN的人群計數思想轉移并應用到鴨計數問題中,提出了一種基于注意力機制改進的YOLOv7算法CBAM-YOLOv7。

論文鏈接:https://www.mdpi.com/2077-0472/12/10/1659/pdf

飼養密度是影響畜禽大規模生產和動物福利的關鍵因素。然而,麻鴨養殖業目前使用的人工計數方法效率低、人工成本高、精度低,而且容易重復計數和遺漏。

在這方面,本文使用深度學習算法來實現對密集麻鴨群數量的實時監測,并促進智能農業產業的發展。本文構建了一個新的大規模大麻鴨目標檢測圖像數據集,其中包含1500個大麻鴨目標的檢測全身幀標記和僅頭部幀標記。

此外,本文提出了一種基于注意力機制改進的YOLOv7算法CBAM-YOLOv7,在YOLOv7的主干網絡中添加了3個CBAM模塊,以提高網絡提取特征的能力,并引入SE-YOLOv7和ECA-YOLOv7進行比較實驗。實驗結果表明,CBAM-YOLOv7具有較高的精度,mAP@0.5和mAP@0.5:0.95略有改善。CBAM-YOLOv7的評價指標值比SE-YOLOw7和ECA-YOLOv 7的提高更大。此外,還對兩種標記方法進行了比較測試,發現僅頭部標記方法導致了大量特征信息的丟失,而全身框架標記方法顯示了更好的檢測效果。

算法性能評估結果表明,本文提出的智能麻鴨計數方法是可行的,可以促進智能可靠的自動計數方法的發展。

隨著技術的發展,監控設備在農業中發揮著巨大的作用。有多種方法可以監測個體動物的行為,例如插入芯片記錄生理數據、使用可穿戴傳感器和(熱)成像技術。一些方法使用附著在鳥類腳上的可穿戴傳感器來測量它們的活動,但這可能會對受監測的動物產生額外影響。特別是,在商業環境中,技術限制和高成本導致這種方法的可行性低。

因此,基于光流的視頻評估將是監測家禽行為和生理的理想方法。最初,許多監控視頻都是人工觀察的,效率低下,依賴于工作人員的經驗判斷,沒有標準。然而,近年來,由于大數據時代的到來和計算機圖形卡的快速發展,計算機的計算能力不斷增強,加速了人工智能的發展。與人工智能相關的研究正在增加,計算機視覺在動物檢測中的應用越來越廣泛。

例如,2014年Girshick等人提出的R-CNN首次引入了兩階段檢測方法。該方法使用深度卷積網絡來獲得優異的目標檢測精度,但其許多冗余操作大大增加了空間和時間成本,并且難以在實際的養鴨場中部署。Law等人提出了一種單階段的目標檢測方法CornerNet和一種新的池化方法:角點池化。

然而,基于關鍵點的方法經常遇到大量不正確的目標邊界框,這限制了其性能,無法滿足鴨子飼養模型的高性能要求。Duan等人在CornerNet的基礎上構建了CenterNet框架,以提高準確性和召回率,并設計了兩個對特征級噪聲具有更強魯棒性的自定義模塊,但Anchor-Free方法是一個具有前兩個關鍵點組合的過程,并且由于網絡結構簡單、處理耗時、速率低和測量結果不穩定,它不能滿足麻鴨工業化養殖所需的高性能和高準確率的要求。

本文的工作使用了一種單階段目標檢測算法,它只需要提取特征一次,就可以實現目標檢測,其性能高于多階段算法。目前,主流的單階段目標檢測算法主要包括YOLO系列、SSD、RetinaNet等。本文將基于CNN的人群計數思想轉移并應用到鴨計數問題中。隨著檢測結果的輸出,作者嵌入了一個目標計數模塊來響應工業化的需求。目標計數也是計算機視覺領域的一項常見任務。目標計數可分為多類別目標計數和單類別目標計數;本工作采用了一群大麻鴨的單類別計數。

本文希望實現的目標是:

  1. 建立了一個新的大規模的德雷克圖像數據集,并將其命名為“大麻鴨數據集”。大麻鴨數據集包含1500個標簽,用于全身框架和頭部框架,用于鴨的目標檢測。該團隊首次發布了大麻鴨數據集
  2. 本研究構建了大鴨識別、大鴨目標檢測、大鴨圖像計數等全面的工作基線,實現了麻鴨的智能養殖
  3. 該項目模型引入了CBAM模塊來構建CBAM-YOLOv7算法

材料的獲取

麻鴨是我國數量最豐富、分布最廣泛、種類最多樣的家鴨之一,具有體型小、省食、產蛋效率高等特點,具有重要的研究價值。使用DJI Pocket 2,一個適應性極強和靈活的微型萬向架相機,來捕捉本研究中使用的圖像和視頻數據集。數據收集自中國四川省雅安市的原水禽養殖場,由四川農業大學著名水禽飼養員王林泉教授創建。

在準備數據集的過程中,首先通過多次改變圖像拍攝的角度和距離,從10個不同的麻鴨屋采集數據。然后,手工篩選并丟棄了一些高重復的數據和一些由于麻鴨屋阻塞而未捕獲的冗余數據。最后,數據集總共包含了1500張圖像,其中包括訓練集中的1300張圖像和測試集中的200張圖像。圖1顯示了非最大抑制對麻鴨的檢測、識別和計數任務所帶來的挑戰的分析。圖2顯示了一個數據集標記工作的示例。

在目標檢測工作的預測階段,網絡輸出多個候選Anchor,但其中許多Anchor在同一對象附近重疊,如圖1b所示。非最大抑制能夠保留這組候選Anchor中最好的一個,如圖1c所示。將鴨A和鴨B命名為。當鴨A和鴨B太近時,由于篩選非最大入侵,可以消除鴨A的預測箱。因此,準確估計所包含的密集大麻鴨數據集的數量是一個挑戰。

由于對整個麻鴨體進行標記導致了許多重疊的標記箱,影響了麻鴨個體計數的準確性,選擇了只標記麻鴨頭的方法,并對兩者進行了比較實驗。

數據預處理

混合數據增強

Mixup是一種基于簡單的數據依賴數據增強原理的非常規數據增強方法,利用線性插值構建新的訓練樣本和標記。對數據標簽的處理公式如下:

圖3為不同融合比例Mixup數據增強過程后的數據結果。

Mosaic Data Augmentation

YOLOv4網絡使用Mosaic數據增強,其思想是隨機切割4幅圖像,并將它們組合成一幅圖像作為新生成的訓練數據,極大地豐富了檢測數據集,使網絡更加魯棒,并減少了GPU視頻內存占用。圖4顯示了Mosaic數據擴充操作的工作流程。

訓練參數

實驗中所使用的訓練過程的訓練參數如表1所示。

評價指標

為了評價該算法的性能,本研究中使用的評價指標分別為精度(P)、查全率(R)、mAP、F1 Score和FPS。精度表示陽性樣本占具有陽性預測結果的樣本的比例。

其計算公式如下:

mAP是每個類別的平均精度的平均值和平均AP值。其計算公式如下:

其中,S為所有類別的個數,分母為所有類別的ap之和。本研究的目標檢測目標僅為一種麻鴨,因此為AP = mAP。

Related Network

本節首先介紹了YOLOv7算法,然后詳細介紹了本文提出的在YOLOv7中添加注意力機制的改進方法。

YOLOv7

本文提出了一種基于計算機視覺的基于家鴨目標檢測和種群統計的識別和檢測算法。利用該算法,育種者可以實時獲取野鴨的數量和行為動態,實現養殖場的快速管理和戰略制定,優化野鴨的繁殖率和生長速度,有助于實現經濟效益的最大化。

鑒于鴨種群中個體密度小,且種群統計的實時要求,選擇了最新的Yolov7模型。“你只看一次(Yolov7)是一種單階段目標檢測算法。圖5為Yolov7的網絡結構圖。將Yolov7模型預處理方法與Yolov5集成,使用鑲嵌數據增強適用于小目標檢測。在體系結構方面,提出了基于ELAN的擴展ELAN(E-ELAN)。利用擴展、shuffle和合并基數,在不破壞原始梯度路徑的情況下,不斷提高網絡的學習能力。在計算塊的體系結構中,利用群卷積來擴展計算塊的通道和基數。不同的計算塊組被引導去學習更多樣化的特征。

然后,它重點關注一些優化模塊和方法,稱為可訓練的“bag-of-freebies”,包括以下內容:

  1. 采用無Identity的RepConv設計了規劃的重參化卷積體系結構,為不同的特征圖提供了更多的梯度多樣性。
  2. 介紹了輔助檢測頭,并利用優化過程生成的軟標簽用于Lead Head和輔助頭的學習。因此,由此生成的軟標簽應該能更好地表示源數據與目標之間的分布和相關性,從而獲得更準確的結果。
  • 批次歸一化層直接連接到卷積層,使得批次的歸一化平均值和方差在推斷階段被集成到卷積層的偏差和權重中。
  • 利用YOLOR中隱式知識的加法和乘法方法,結合卷積特征映射,可以在推理階段通過預先計算將其簡化為向量,從而結合之前或后續卷積層的偏差和權重。
  • EMA模型純粹被用作最終的推理模型。最后,實時目標檢測可以在不增加推理成本的情況下大大提高檢測精度,使5-160FPS范圍內的速度和精度超過所有已知的目標檢測器,可以實現目標檢測的快速響應和準確預測。

改進注意力機制的YOLOv7

注意力機制是一種常見的數據處理方法,廣泛應用于各個領域的機器學習任務。計算機視覺注意力機制的核心思想是找到原始數據之間的相關性,然后突出重要的特征,如通道注意力、像素注意力、多階注意力等。

CBAM主要包括通道注意力模塊和空間注意力模塊。模塊結構如圖6所示。

CBAM是一個輕量級的注意力模塊,可以在通道和空間維度上執行注意力操作。它由通道注意力模塊(CAM)和空間注意力模塊(SAM)組成。CAM可以使網絡更加關注圖像的前景和有意義的區域,而SAM可以使網絡更關注富含整個畫面上下文信息的位置。

YOLOv7 Introduces the CBAM Attention Mechanism

CBAM注意力機制被添加到YOLOV7網絡結構中,網絡結構如圖7所示。該模塊的功能是進一步提高特征提取網絡的特征提取能力。一旦將注意力機制添加到骨干網絡中,注意力機制模塊就會降低骨干網絡的一些原始權重。這導致網絡的預測結果出現錯誤。在這方面選擇將注意力機制添加到增強特征網絡提取的部分,而不破壞網絡提取的原始特征。

CBAM注意機制的工作原理如下:

在通道注意力模塊中,對H×W×C的輸入特征圖進行全局最大池化(GMP)和全局平均池化(GAP),得到2個大小為1×1×C的特征圖。這2個特征圖被發送到一個兩層的多層感知器。MLP第一層的神經元數量為C/r(r為還原率),激活函數為ReLU。第二層神經元的數量為C,這兩層神經網絡的權值被共享。然后,基于元素級計算添加輸出特征,并通過sigmoid生成最終的通道附著特征。最后,將通道注意力特征乘以原始輸入特征圖,得到空間注意力模塊的輸入特征。

在空間注意模塊中,使用上一步中的特征圖作為輸入。

經過GMP和GAP后,得到了2個大小為H×W×1的特征圖。然后執行Concat操作。將特征圖降維后,通過sigmoid生成空間注意力特征。最后,將空間注意力特征乘以輸入的特征圖,得到最終的特征圖。

實驗結果

?目標檢測網絡比較實驗結果

?引入注意機制的對比實驗結果

不同數據標注方法的實驗結果比較?

消融實驗結果?

4.2、YOLOv7~ELAN

雖然還沒升到7,先來學學吧

設計高效、高質量的表達性網絡架構一直是深度學習領域最重要的研究課題。當今主流的網絡設計策略大多基于前饋路徑,即基于數據路徑設計網絡架構。在本文中希望通過提高網絡學習能力來增強訓練模型的表達能力。由于驅動網絡參數學習的機制是反向傳播算法,本文設計了基于反向傳播路徑的網絡設計策略。提出了layer-level、stage-level和network-level的梯度路徑設計策略,并通過理論分析證明了設計策略的優越性和可行性和實驗。

深度神經網絡(DNN)現在廣泛用于各種設備,以解決不同類型的任務。數百萬科學家、工程師和研究人員參與了深度學習相關的工作。他們都期待著設計出能夠滿足他們需求的高效、準確、低成本的解決方案。因此,如何設計適合其產品的網絡架構變得尤為重要。

自2014年以來,許多DNN在各種任務上取得了接近人類或優于人類的性能。例如,谷歌的GoogLeNet和微軟的PReLUNet在圖像分類方面,Facebook的Deepface在人臉識別方面,DeepMind的AlphaGo在圍棋棋盤上等等。基于上述領域的開始,一些研究人員繼續開發更先進的新架構或算法以擊敗上述方法;

其他研究人員關注如何使DNN相關技術在人類日常生活中實用。Iandola等人提出的SqueezeNet是一個典型的例子,因為它將AlexNet的參數數量減少了50倍,但可以保持相當的精度。MobileNet和ShuffleNet也是很好的例子。前者將實際硬件操作延遲直接添加到架構設計的考慮中,而后者將硬件特性的分析用作設計神經網絡架構的參考。

就在ResNet、ResNeXt和DenseNet架構解決了深層網絡訓練中遇到的收斂問題之后,近年來CNN架構的設計集中在以下幾點:

1. 特征融合

2. 感受野增強

3. 注意機制

4. 分支選擇機制

換句話說,大多數研究遵循深度網絡的共同認知,即從淺層提取low-level特征,從深層提取high-level特征。根據上述原則,可以使用它們來設計神經網絡架構,以有效地組合數據路徑(前饋路徑)中的不同level的特征。

然而,這樣的設計策略是否一定正確?從圖1中發現,通過調整目標和損失層的配置,可以控制每個層(淺層或深層)學習的特征。也就是說,權重學習什么樣的特征主要取決于使用什么樣的信息來教它,而不是輸入來自哪些層的組合。基于這一發現,作者重新定義了網絡設計策略。

由于提出網絡結構可以用目標函數可以指導神經網絡學習信息的概念來設計,因此必須首先了解目標函數如何影響網絡權重的更新。

目前,主要的權重更新方法是反向傳播算法,它使用偏微分生成梯度,然后通過梯度下降來更新權重。該算法以鏈式規則的方式將梯度信息傳播到淺層,并重復這些步驟,直到更新所有層的權重。換句話說,目標函數教導的信息以梯度的形式在層之間傳播。

在本文中提出通過分析通過目標函數的引導生成的梯度,可以在執行反向傳播過程時通過梯度路徑來設計網絡結構。作者分別為3個不同級別的策略設計網絡架構,如layer-level、stage-level和network-level,如下所述:

1、Layer-level設計

在這個層次上設計了梯度分流策略,并使用它們來確認假設的有效性。調整層數并計算殘差連接的通道比率,然后設計Partial Residual Network(PRN)。

2、Stage-level設計

添加硬件特征以加快網絡推理。最大化梯度組合,同時最小化硬件計算成本,因此設計了Cross Stage Partial Network(CSPNet)。

3、Network-level設計

增加了梯度傳播效率的考慮,以平衡網絡的學習能力。當設計網絡架構時,還考慮了整個網絡的梯度傳播路徑長度,因此設計了Efficient Layer Aggregation Network(ELAN)。

本文方法

網絡設計策略??

如圖2所示,在本文中將網絡設計策略分為兩種:

1. 數據路徑設計策略

2. 梯度路徑設計策略

數據路徑設計策略主要側重于設計特征提取、特征選擇和特征融合操作,以提取具有特定屬性的特征。這些特征可以幫助后續層使用這些特征進一步獲得更好的屬性,以便進行更高級的分析。

應用梯度路徑設計策略的目的是分析梯度的來源和組成,以及如何通過驅動參數更新梯度。然后,可以使用上述分析的結果來設計網絡架構。設計理念是希望最終的參數利用率更高,從而達到最佳的學習效果。

接下來將分別討論數據路徑設計策略和梯度路徑設計策略的優點和缺點。

數據路徑設計策略有3個優點:

1. 可以提取具有特定物理意義的特征。例如,使用非對稱計算單元來提取具有不同感受野的特征;

2. 可以為不同的輸入自動選擇具有參數化模型的合適的操作單元。例如,使用kernel選擇來處理輸入具有不同的性質;

3. 可以直接重用所學習的特征。例如,特征金字塔網絡可以直接利用從不同層提取的特征進行更準確的預測。

數據路徑設計策略有2個缺點:

1. 在訓練過程中,有時會導致效果的不可預測的降級,此時需要設計更復雜的架構來解決問題。例如,non-local網絡的成對關系很容易退化為一元信息;

2. 各種專門設計的運算單元容易導致性能優化的困難。例如,在專用于AI的ASIC設計中,如果設計者想要添加算術單元,則需要額外的一組電路。

對于梯度路徑設計策略,總共有3個優點:

1. 可以有效地使用網絡參數,在這一部分中提出通過調整梯度傳播路徑,不同計算單元的權重可以學習各種信息,從而實現更高的參數利用效率;

2. 具有穩定的模型學習能力,由于梯度路徑設計策略直接確定并傳播信息以更新權重到每個計算單元,因此所設計的架構可以避免訓練期間的退化;

3. 具有高效的推理速度,梯度路徑設計策略使得參數利用非常有效,因此網絡可以在不增加額外復雜架構的情況下實現更高的精度。

由于上述原因,所設計的網絡在架構上可以更輕、更簡單。

梯度路徑設計策略有1個缺點:

1. 當梯度更新路徑不是網絡的簡單反向前饋路徑時,編程的難度將大大增加。

Partial Residual Networks??

Partial Residual Networks(PRN)其設計理念屬于layer-level設計策略。在PRN的設計中,主要概念是最大化用于更新每層的權重的梯度組合。影響梯度組合的主要因素有2個:

1. 第一個是梯度的源層。源層由連接到梯度路徑的不相交邊緣的節點組成;

2. 第二個因素是梯度流通過鏈式法則的操作從損失層到達特定層所需的時間。

需要注意的一點是,當梯度在鏈規則更新過程中發生變化時,其覆蓋的丟失信息量將隨著鏈的增長而逐漸減少。作者將上述持續時間定義為梯度流從損失層行進到特定層所需的層數。在PRN中提出了以下2種結構來改進ResNet:

Masked residual layer

在ResNet的設計中,將每個計算塊的輸出與identity連接一起添加,這樣的結構稱為殘差層。在PRN中,將identity連接乘以二進制Mask,并且只允許將某些通道的特征映射添加到計算塊的輸出中。將此結構稱為Masked residual layer,其架構如圖3所示。使用Masked residual layer的機制允許將特征圖分為兩部分,其中與被Mask的通道相對應的權重和與具有identity連接的通道相對的權重將由于上述identity效應而顯著增加梯度組合的數量。此外,梯度源的差異將同時影響整個梯度時間戳(沿時間軸的時間節點),從而使梯度組合更加豐富。

Asymmetric residual layer

在ResNet架構下,只能添加相同大小的特征圖,這就是為什么它是一個非常受限的架構。通常,當執行優化的架構的計算量和推理速度時,常常受到這種架構的限制,無法設計出符合要求的架構。在PRN架構下,提出的Masked residual layer可以將通道數量的不一致性視為某些通道被阻塞,從而允許具有不同通道數量的特征圖執行Masked residual操作。

將以上述方式操作的層稱為Asymmetric residual layer。Asymmetric residual layer以這樣的方式設計,即網絡架構更靈活,并且更能夠保持基于梯度路徑的模型的屬性。例如,當進行特征集成時,一般方法需要額外的過渡層來將不同的特征映射投影到同一維度,然后執行添加操作。然而,上述操作將增加大量參數和計算量,并且還將使梯度路徑更長,從而影響網絡的收斂。引入Asymmetric residual layer可以完美地解決類似問題。

Cross Stage Partial Networks??

CSPNet于2019年提出,它是一個基于Stage-level梯度路徑的網絡。與PRN一樣,CSPNet基于最大化梯度組合的概念。CSPNet和PRN的區別在于,后者側重于從理論角度確認梯度組合對網絡學習能力的改善,而前者則是為了進一步優化硬件推理速度而額外設計的。因此,在設計CSPNet時,將架構從Layer-level擴展到Stage-level,并優化整體架構。

CSPNet主要有以下2種結構:

Cross stage partial operation

從最大化梯度源的角度來看可以很容易地發現,當每個通道具有不同的梯度路徑時,梯度源可以最大化。此外,從最大化梯度時間戳的角度來看,當每個通道具有不同深度的計算塊時,可以最大化梯度時戳的數量。

根據上述概念可以導出一種設計用于最大化梯度源和梯度時間戳的架構。這種架構將是類似fractal-like的架構和具有深度卷積的類似分形的架構。雖然上述設計可以有效地提高參數利用率,但會大大降低并行化能力。此外,這將導致模型顯著降低GPU和TPU等推理引擎上的推理速度。

從前面的分析知道劃分通道可以增加梯度源的數量,并且使不同通道連接的子網絡具有不同的層可以增加梯度時間戳的數量。本文設計的Cross stage部分操作可以最大化梯度的組合,并在不破壞架構的情況下提高推理速度,并且可以并行化。

該體系結構如圖4所示。在圖4中,將stage的輸入特征圖分成兩部分,并使用這種方式增加梯度源的數量。

具體步驟如下:首先將輸入特征圖分成兩部分,其中一部分通過計算塊,該計算塊可以是任何計算塊,如Res Block、ResX Block或Dense Block。至于另一部分,它直接跨越整個Stage,然后與經過計算塊的部分集成。由于只有部分特征圖進入計算區進行操作,這種設計可以有效地減少參數量、操作、內存流量和內存峰值,從而使系統實現更快的推理速度。

Gradient flow truncate operation

為了使設計的網絡架構更強大進一步分析了用于更新CSPNet的梯度流。由于計算塊中經常使用shortcut連接,提供2條路徑的梯度源必然會重疊很多。當特征圖通過kernel函數時,它相當于空間投影。通常可以在兩條路徑的末端插入過渡層,以截斷復制的梯度流。通過以上步驟可以使從2條路徑和相鄰Stage學習到的信息具有更明顯的多樣性。

作者設計了3種不同的重復梯度流截斷操作組合,如圖5所示。這些操作可以與不同的架構相匹配,例如計算塊和下采樣塊,以獲得更好的結果。

高效的層聚合網絡

高效層聚合網絡(ELAN)的代碼于2022年7月發布。在網絡層面,它屬于梯度路徑設計網絡的范疇。設計ELAN的主要目的是解決在執行模型縮放時深度模型的收斂性會逐漸惡化的問題。

作者分析了通過整個網絡中每個層的最短梯度路徑和最長梯度路徑,從而設計了具有有效梯度傳播路徑的層聚合架構。ELAN主要由VoVNet和CSPNet組成,并利用計算塊中的堆棧結構優化了整個網絡的梯度長度。在接下來的內容中將詳細說明計算塊中的堆棧是如何工作的。

堆棧在計算塊中。當在做模型縮放時會出現一種現象,即當網絡達到一定深度時,如果繼續堆疊計算塊,精度增益將越來越小。更糟糕的是,當網絡達到某個臨界深度時,其收斂性開始惡化,導致總體精度比淺層網絡差。

最好的例子之一是Scaled-YOLOv4,看到它的P7模型使用了昂貴的參數和操作,但只有少量的精度增益,而且在許多流行網絡中也會出現同樣的現象。例如,ResNet-152的計算強度大約是ResNet-50的3倍,但在ImageNet上的精度提高不到1%。當ResNet堆疊到200層時,其精度甚至比ResNet-152更差。此外,當VoVNet堆疊到99層時,其精度甚至遠低于VoVNet-39。

從梯度路徑設計策略的角度來看,作者推測VoVNet的精度退化比ResNet快得多的原因是因為VoVNet堆疊基于OSA模塊。每個OSA模塊都包含一個過渡層,因此每次堆疊OSA模塊時,網絡中所有層的最短梯度路徑都會增加一個。

至于ResNet,它是由殘余塊堆疊的,殘余層的堆疊只會增加最長的梯度路徑,而不會增加最短的梯度路徑。為了驗證模型縮放的可能影響,作者基于YOLOR-CSP進行了一些實驗。從實驗結果中發現,當堆疊層達到80+層時,CSP fusion first的精度開始優于正常的CSPNet。此時,每個Stage的計算塊的最短梯度路徑將減少1。隨著網絡的不斷擴大和加深,CSP fusion last將獲得最高的精度,但此時所有層的最短梯度路徑將減少1。

上述實驗結果證實了先前的假設。在上述實驗的支持下,如圖6所示,在ELAN中設計了“計算塊中的堆棧”策略。設計的目的是避免使用過多過渡層的問題,并使整個網絡的最短梯度路徑快速變長。當網絡堆疊得更深時,上述設計策略能夠成功地訓練ELAN。

分析

在本節中,將分析基于經典網絡架構提出的梯度路徑設計策略。

首先,將使用梯度組合的概念分析現有的網絡架構和所提出的PRN,該示例表明表現良好的網絡架構確實具有更豐富的梯度組合。

然后,將分析所提出的CSPNet如何帶來更豐富的梯度組合和其他好處。

?最后,通過stop 梯度分析了梯度路徑長度的重要性,從而證實了所提出的ELAN具有設計概念上的優勢。

梯度組合分析??

一般研究人員通常使用最短梯度路徑和集成特征的數量來衡量網絡架構的學習效率和能力。然而,從SparseNet中可以發現,如表1所示,這些度量與準確性和參數使用并不完全相關。作者觀察了梯度傳播的過程,發現用于更新不同層權重的梯度組合與網絡的學習能力非常匹配,在本節中將分析梯度組合。

梯度組合由2種類型的組件組成,即Gradient Timestamp和Gradient Source。

Gradient Timestamp

圖7顯示了ResNet、PRN、DenseNet和SparseNet的架構。其中,作者展開了cascaded residual connection和concatenation connection以便于觀察梯度傳播過程。此外,圖7還顯示了每個架構上的gradient flow delivery timestamps。gradient sequence相當于廣度優先搜索過程,每個sequence將訪問上一輪遍歷所到達的所有outdegree nodes。

從圖7中可以看到PRN使用通道分割策略來豐富由對應于不同通道的權重接收的Gradient Timestamp。至于SparseNet,它使用稀疏連接來使與不同層相對應的權重連接所接收的Timestamp更加可變。

上述兩種方法都可以學習具有不同權重的更多樣的信息,這使得提出的架構更強大。

Gradient Source

圖8顯示了第1個梯度時間戳處ResNet、PRN和DenseNet的Gradient Source。從圖8可以看出,connection-based的架構,如DenseNet和SparseNet,屬于必須特別處理的網絡。這是因為在梯度傳播過程中,如果它是由同一層在某個Gradient Timestamp傳播的梯度信息,因為梯度流已經被預先分割,所以它不能像普通網絡那樣被處理。

對于基于殘差連接的架構,如ResNet和PRN,完全相同的梯度信息被傳播到所有的outdegree層。由于PRN的outdegree僅連接到其他層的某些通道,因此它可以具有比ResNet整體更豐富的梯度組合。

此外,還有使用其他split-transform merge策略的網絡架構,例如基于group convolution-based 的ResNeXt和基于depth-wise convolution的MobileNet等,這也可以增加Gradient Source的數量。

總結

總之,通過對梯度反向傳播過程中產生的Gradient Timestamp和Gradient Source的分析,可以清楚地解釋現有的流行網絡架構以及提出的PRN所學習的信息和參數的利用效率。在ResNet中,不同的層共享相同Timestamp和相同Gradient Source的許多梯度,DenseNet將相同Timestamp但不同Source的梯度信息傳遞給相應的層。這部分清楚地解釋了為什么基于串聯連接的DenseNet可以避免像基于殘差連接的ResNet那樣容易地學習大量無用信息的問題。本文提出的PRN使用簡單的masked residual layer來增加沿時間軸的梯度組合的數量,同時保持ResNet網絡拓撲,并轉移Gradient Source,從而增加Gradient Source的可變性。

跨階段部分策略分析??

CSPNet旨在增強在線學習能力,同時加快推理速度,因此將分別從這兩個方面討論CSPNet策略的優勢。在第3.1節中進行的分析中觀察到,即使Gradient Source生成的組合數量相同,當不同組合之間接收到的公共分量減少時,這使得梯度分量更豐富,也使網絡學習更好。這種現象實際上發生在為單層權重學習大量參數的過程中。

例如,dropout使用隨機伯努利Mask神經元來防止參數學習協同適應信息。從數學模型的角度來看,dropout是通過使用不同輸入產生的梯度來更新不同部分的權重,這相當于隨機集成結構。至于CSPNet,它通過梯度路徑上梯度的時間差和空間變換,直接增加了梯度組合的豐富性。接下來將介紹CSPNet使用什么策略來解決重復梯度信息的問題,以及它如何提高資源利用率。

Duplicated Gradient Information

在第3.1節中分析了梯度組合的數量以及多樣性對網絡學習能力的影響。在CSPNet中進一步分析了不同層接收的梯度信息內容,并設計了架構以提高參數使用效率。從PRN和SparseNet的梯度組合可以發現,它們在增加梯度組合豐富度的過程中具有共同性,即通過殘差連接或密集連接接收大量重復梯度信息的情況顯著減少。作者推測,這些重復的梯度是大量權重容易學習共適應信息的主要原因。

對于PRN,它利用梯度定時差來更新部分通道的權重。隨著鏈式規則的更新過程,上述時間差將擴散到整個網絡,然后實現更豐富的梯度組合。

此外,CSPNet直接使用cross stage使整個stage的兩條路徑具有很大的時間差,并使用不同的融合結構來減少stage與stage之間或計算塊路徑與cross stage connection路徑之間的重復梯度信息。

Resource Usage Efficiency

以Darknet-53為例,假設cross stage部分操作根據通道的方向將特征圖分成兩個相等的部分。此時,殘差塊的輸入通道數和輸出通道數減半,而中間的通道數保持不變。

根據上述結構,計算塊的總體計算和參數量將減少到原始的一半,而內存峰值是輸入特征圖和輸出特征圖的大小之和,因此將減少到原來的2/3。此外,由于整個計算塊中卷積層的輸入通道和輸出通道相等,因此此時的存儲器訪問成本將最小。

總結

總之,CSPNet成功地將梯度組合的概念與硬件利用效率相結合,使得所設計的網絡架構同時提高了學習能力和推理速度。CSPNet僅使用簡單的channel split、 cross stage connection并在不改變原有網絡計算單元的情況下成功完成預設目標。

CSPNet的另一個優點是它可以應用于許多流行的網絡架構,并在各個方面提高整體網絡效率。在表2中展示了應用于幾種流行網絡架構的CSPNet的優異性能。最后,由于CSPNet對許多硬件資源的要求較低,因此它適用于具有更嚴格硬件約束的設備上的高速推理。

坡度路徑長度分析?

如第3.1節所述,整個網絡的梯度路徑越短并不意味著學習能力越強。此外,即使整個梯度組合路徑的長度是固定的,作者發現ResNet的學習能力仍然下降當堆疊非常深時。然而,作者發現上述問題可以用于在訓練階段使用隨機深度將ResNet分解為較淺的隨機子網絡進行訓練,這可以使超深ResNet收斂到更好的結果。

上述現象告訴我們,在分析梯度路徑時,不僅可以查看整個網絡的最短梯度路徑和最長梯度路徑,還需要更詳細的梯度路徑分析。在下文中,將通過在訓練期間調整梯度流來控制梯度路徑長度,然后根據結果討論在設計網絡架構時的梯度長度策略。

Stop gradient

首先基于ResNet探討最短梯度長度的重要性。與PlainNet相比,ResNet中的每個殘差塊除了通過計算塊的梯度之外,還通過identity連接在計算塊上具有一部分梯度。這里,如圖9所示,分別對計算塊和identity連接執行Stop梯度操作。

當在identity連接上執行Stop梯度時,整個網絡的梯度路徑將類似于PlainNet。也就是說,最長的梯度路徑與最短的梯度路徑長度相同,網絡深度也相同。當在計算塊上執行Stop梯度時,最短的梯度路徑將直接穿過所有殘差連接并直接到達起始層,此時最短梯度路徑長度為1。由于每個計算塊有兩層,因此其最長梯度路徑為2。可以使用這兩組設置來觀察殘差學習本身的好處和梯度路徑的減少。?

使用Microsoft COCO數據集中的目標檢測和實例分割作為基線模型,對YOLOR CSP進行消融研究,結果如表3所示。實驗結果表明,在ResNet中執行縮短的梯度路徑確實是深度網絡更好收斂的重要因素。

Gradient path planning

根據以上分析和在YOLOR-CSP中使用CSP融合進行的模型縮放實驗,重新規劃了VoVNet的過渡層并進行了實驗。首先移除深度VoVNet的每個OSA模塊的過渡層,只留下每個階段中最后一個OSA模塊中的過渡層。以與上述相同的方式組織網絡的最長梯度路徑和通過每個層的最短梯度路徑。同時,還將CSPNet結構應用于上述網絡,以進一步觀察CSPNet的多功能性,相關實驗結果如表4所示。可以清楚地看到,深度VoVNet已經從無法收斂變為能夠很好地收斂并獲得非常好的精度。

總結

簡而言之,從上述實驗和分析中推斷,在規劃整個網絡的梯度路徑時,不僅應該考慮最短的梯度路徑,而且應該確保每個層的最短梯度路徑都可以有效地訓練。至于整個網絡的最長梯度路徑的長度,它將大于或等于任何層的最長的梯度路徑。因此,在實施網絡級梯度路徑設計策略時,需要考慮網絡中所有層的最長最短梯度路徑長度,以及整個網絡的最長梯度路徑。

實驗

Layer-level梯度路徑設計策略

在PRN實驗中將被masked residual layer mask的通道數設置為原始通道數的一半,實驗結果如表5所示。由于PRN的設計維護了整個網絡的所有參數和拓撲結構,所以只有殘差連接中的加法操作減少了一半,所以總體計算量幾乎沒有變化。

然而,YOLOR-PRN在精度上得到了顯著的提高,因為每層都使用了用來更新權重的梯度組合。與YOLOR-v3相比,PRN在目標檢測上提高了0.5%的AP,也可以觀察到高質量和顯著的改進。在實例分割上,將AP提高了0.1%,AP75提高了0.3%。

Stage-level梯度路徑設計策略

在CSPNet實驗中遵循優化推理速度的原則,將梯度分割比設置為50%-50%,實驗結果如表6所示。由于只有一半的通道特征圖將進入計算塊可以清楚地看到,與YOLOR-v3相比,YOLOR-CSP顯著減少了22%的計算量。然而,通過豐富的梯度組合,YOLOR-CSP在目標檢測上顯著提高了1.5%。與YOLOR-v3相比,YOLOR和CSPNet(YOLOR-CSP)的組合增加了更多高質量的結果。

作者進一步比較了梯度流截斷操作來減少重復梯度信息,清楚地看到YOLOR-CSP策略比CSP fusion first和CSP fusion last學習得更好。值得一提的是,無論采用何種融合策略,基于csp的體系結構的計算負荷都比YOLOR-v3低得多,精度也遠高于YOLOR-v3。

Network-level梯度路徑設計策略

在ELAN實驗中分別測試了計算塊在Backbone和Neck的疊加時間,結果如表7所示。從這個表中可以清楚地看出,ELAN在比YOLOR-v3少35%的計算量下,仍然可以提高0.7%的目標檢測性能。

在ELAN中可以靈活地設置堆棧的數量,從而在精度和計算量之間進行權衡。從表7中列出的實驗結果可以看到,在堆棧設置2,1s,YOLOR-ELAN可以在降低26%計算量的情況下,顯著提高目標檢測和實例分割的性能分別1.9%和0.6%。

比較??

最后,綜合比較了Layer-level 設計策略設計的YOLOR-PRN、Stage-level 設計策略設計的YOLOR-CSP和Network-level 設計策略設計的YOLOR-ELAN,以及基線YOLOR-v3和YOLOv5(r6.2),結果如表8所示。

從表中可以看出,基于梯度路徑設計策略設計的模型在各個方面都優于基于基線的方法。此外,無論計算量如何。由Network-level 設計策略設計的YOLOR-ELAN在參數數量和精度方面可以全面獲得最突出的性能。

研究結果表明,基于梯度路徑分析能夠設計出更好的網絡架構設計策略。如果與一般的基于數據路徑的策略相比,由數據路徑策略設計的體系結構通常需要額外的參數或計算成本來獲得更好的精度。相比之下,這三種基于梯度路徑設計策略的體系結構可以顯著提高整體性能。

5、Yolo5

5.1、YOLO5~火焰煙霧檢測

這里提出了一種基于YOLOv5的火焰煙霧檢測算法。基于改進的YOLOv5模型,建立了一種具有泛化性能的火焰煙霧檢測算法。改進后的YOLOv5模型精度可達99.5%,對火焰煙霧的檢測效果更加準確。

本次介紹的文章是廣東石油化工學院發表的一篇火焰煙霧檢測的文章,題目為《Flame smoke detection algorithm based on YOLOv5 in petrochemical plant》。

石油化工裝置火災煙霧檢測,可以預防火災,保證生產安全和生命安全。文章旨在解決復雜工廠背景下火焰煙霧檢測中的漏檢和誤檢問題。

文章提出了一種基于YOLOv5的火焰煙霧檢測算法。目標回歸損失函數(CIoU)用于改善目標檢測中的漏檢和誤檢,提高模型的檢測性能。改進后的激活函數避免了梯度消失,保持了算法較高的實時性。數據增強技術用于增強網絡提取特征的能力,提高小目標檢測模型的準確性。根據火焰煙霧的實際情況,改進了YOLOv5模型的損失函數和激活函數。基于改進的YOLOv5模型,建立了一種具有泛化性能的火焰煙霧檢測算法。將改進后的模型與SSD和YOLOv4-tiny進行了比較。改進后的YOLOv5模型精度可達99.5%,對火焰煙霧的檢測效果更加準確。改進后的網絡模型在運行時間和精度上均優于現有方法。

針對火焰煙霧檢測的實際特殊性,建立了一種改進的基于YOLOv5的火焰煙霧檢測網絡模型。通過改進損失函數來達到優化模型的目的,并結合非線性能力較強的激活函數來避免網絡的過擬合。該方法有助于改善火焰煙霧檢測中的漏檢和誤檢問題,可進一步推廣到行人目標檢測和車輛行駛識別中。

工廠的安全生產一直是一個不容忽視的問題。以石化工廠為例,由于生產車間密集,存在大量易燃易爆危險品,一旦發生火災,極易誘發災難性后果,造成環境污染,嚴重威脅生產安全和人員生命財產安全。因此,及時發現和預警控制早期火災是安全生產的現實需求。廠區內火焰煙霧檢測報警技術已受到國際、國內的重視。

火災早期探測主要通過煙霧傳感器和溫度傳感器來實現。例如,煙霧傳感器通過檢測煙霧濃度來完成防火。這種方法在室內或一些小場所有很好的表現。但在復雜環境中,由于氣流環境、熱障效應等因素的影響,再加上傳感器檢測距離較近、穩定性較低,依靠傳感器檢測溫度、濃度等指標,很難準確獲取現場實時信號數據信息。

雖然現有的目標檢測研究已經取得了重大突破,但在實際的目標檢測中,需要對整個圖像進行卷積,需要更大的視場來滿足算法的簡潔快速。YOLO是一種目標檢測器,它使用深度卷積神經網絡學習的特征來檢測目標。近年來,大量研究將其用于不同類型圖像的智能檢測,然而,模型結構復雜,火焰檢測精度不夠。

針對YOLOv5算法模型體積小、檢測速度快的優異性能,以及處理廠區火焰煙霧檢測問題的復雜性,文章在專門改進的YOLOv5的基礎上建立了一種植物火焰煙霧檢測算法,用于解決火焰煙霧漏檢和誤檢問題。該算法將原有的GIoU _ Loss替換為CIoU _ Loss作為邊界盒的損失函數,并利用SiLU激活函數來避免網絡的過擬合。最后,通過與SSD、YOLOv4-tiny和YOLOv7算法的比較,驗證了所提算法的有效性和可達性。

模型

A. YOLOv5網絡模型及算法改進

損失函數的改進

損失函數是評估回歸和分類問題的重要指標。在深度學習網絡中,反向傳播時間對誤差估計至關重要。因此,本節通過引入更好的理論CIoU _ Loss 損失函數,改進了GIoU _ Loss 。

在目標檢測中,需要對檢測盒與真實盒的檢測效果進行比較。通用網絡中使用的GIoU _ Loss解決了在IoU的基礎上,由于不同目標盒重疊而導致的比值無法優化的問題。GIoU的計算過程如下式第一個算式所示。

上式第二個算式中,A為預測箱,B為實箱,IoU為傳統的交點-并集比,即預測箱與實箱的交點面積與并集面積之比;Ac為預測框與實框最小包圍矩形的面積。U為預測框和實框的面積。第三個算式中,LGIOU為GIoU的損失。

當預測框包含在目標框內時,GIoU _ Loss退化為IoU _ Loss,相對位置關系無法區分。為了更好地優化目標盒和預測盒,本文提出用CIoU _ Loss代替原來的GIoU _ Loss作為包圍盒損失函數。CIoU的計算過程如下邊第一個算式所示。

上述第二個算式中,ωA, hA為實際幀寬,ωB, hB為預測幀寬,α是權重,υ度量長寬比的相似度。C為兩個矩形的最小對角線限定比例尺;ρ是A和B的中心點的歐氏距離;上述第三個算式中,LCIoU為CIoU的損失。

激活函數的改進

激活函數的目的是提高神經網絡的非線性擬合能力。在YOLOv5網絡結構中,骨干網中的LeakyReLU激活函數替換為SiLU(Sigmoid-Weighted Linear Units)激活函數。SiLU激活函數借鑒了ReLU函數族的思想,但更流暢。由于SiLU激活函數具有較強的非線性能力,可以解決LeakyReLU梯度爆炸的問題。如下圖所示,改進后的CBS模塊表示卷積層、批處理歸一層和SiLU激活函數的串聯模式。

SiLU激活函數表達式如下:?

如上式第一個算式中,Sigmoid是常用的激活單元,SiLU函數表示Sigmoid的加權組合。由于SiLU激活函數本身具有自穩定特性,如上述第二個算式所示,它可以有效抑制大量權重的學習,從而避免網絡過擬合,降低網絡泛化性能。

實驗結果與分析

A. 獲取數據集

所獲得的數據包含圖像和視頻兩種格式類型。將得到的視頻轉換為視頻圖像序列,去除部分相似度高的圖片。經過處理的樣本圖片被打亂,生成一個新的數據集用于訓練。為了更好地評價工廠中火焰煙霧的目標識別性能,實驗選擇火焰和煙霧兩種類型作為目標識別對象如下圖,可以更好地反映YOLO模型在真實環境中的效果。

為了從有限的工廠火焰煙霧數據集中充分獲取目標特征信息,通過隨機變換剔除模型中部分相似度較高的樣本圖像,防止過擬合導致特征學習停止,有利于模型的泛化。隨機變換包括翻轉、旋轉、尺度變換、隨機摳圖、高斯噪聲、隨機模糊、顏色抖動等,以達到擴展數據集的目的。文章采用馬賽克數據增強技術,通過隨機縮放、隨機裁剪和隨機發射,將4張隨機圖像拼接成1張圖像,豐富了數據集,提高了小目標的檢測精度,增強了網絡特征提取能力。下圖顯示了Mosaic數據增強結果。

B. 自適應圖像縮放

在一般的檢測任務中,數據集圖像的長度和寬度是不同的。由于小目標分布不均勻,嚴重影響了網絡運行效率。

常見的處理方法是在訓練和測試時將樣本圖像縮放到固定大小,然后將其發送到網絡進行學習。如果在輸入端僅以馬賽克增強作為小樣本圖像處理的主要手段,則提高了小目標的檢測精度,而減少了大目標的數據集,導致算法的平均精度下降。因此,傳統的數據處理方法效果并不理想。

文章采用自適應縮放技術對數據輸入端的數據進行處理。通過將原始圖像縮放到標準尺寸,解決了原始數據集樣本大小不同的問題。通過計算縮放后的尺度大小,得到黑邊的填充值,在圖像周圍自適應添加最小黑邊,減少計算量,從而加快檢測速度。向這個示例添加黑邊的效果如下圖所示。

C. 數據標注

本文使用圖像標注軟件labellmg對樣本圖像的真實值進行手動標注,選擇對應目標區域的標注矩形框,自定義目標類別,標注信息將以.xml格式保存。雙擊打開“saved.xml”文件,文件中包含箱子所屬類別、圖像文件名、路徑信息、目標類型和數量、箱子大小和中心點坐標。使用LabImage標注工具完成標注,最終獲得2585張樣本圖像,包括火和煙2類,按照8:2的比例分為訓練集和測試集,其中訓練集圖像2068張,測試集圖像517張。?

D.?模型訓練

用于模型訓練的硬件環境:Intel (R) Core (TM) i9-10900K CPU, 32.0 GB內存,NVIDIAGeForceRTX3090。軟件環境:Windows10操作系統,Python3.10開發語言,PyTorch深度學習框架。在超參數設置中,batch-size設置為16,最大迭代次數的epoch設置為300,num-workers設置為2。Adam優化器可以在訓練過程中達到參數優化的目的,同時保證網絡檢測精度,減小網絡規模和參數數量,增強網絡的檢測和識別能力。隨著訓練輪數的增加,總損失值呈下降趨勢。當訓練輪數為300輪時,模型的精度趨于穩定,總損失值基本穩定在0.03,滿足模型收斂的基本要求。可以確定300為模型的最佳訓練輪,模型達到了較好的擬合效果。

E. 基于YOLOv5的工廠火焰煙霧檢測及結果分析

為了更直觀地感受三種算法的測試結果,選取了一組復雜背景和小目標樣本圖像進行檢測。將選取的樣本組發送到三種算法的網絡模型中進行測試。YOLOv5l、SSD和YOLOv4-tiny算法的檢測結果分別如下三圖所示。

YOLOv5l檢測四張樣本圖像的時間分別為0.196s、0.075s、0.082s和0.07s。從上述的檢測結果可以得出,在保證目標盒位置準確的前提下,檢測小目標的可靠性達到80%以上,檢測大目標的可靠性達到90%以上,滿足廠區火焰煙霧檢測要求,具有良好的檢測性能。使用SSD算法對樣本組進行測試,從圖中可以看出,部分目標未被檢測到,被檢測目標的可靠性為60%-70%。可以看出,使用SSD算法檢測樣本組存在目標漏檢、置信度低等問題。出現這種現象的原因可能是樣本中的背景比較復雜,目標比較小。該模型在訓練和學習過程中無法充分提取目標特征。因此SSD算法不能較好地滿足廠區火焰煙霧目標檢測的指標要求。使用YOLOv4-tiny算法檢測樣本組的結果如上圖所示。yolov -tiny算法對樣本組的檢測時間分別為0.81 s、0.94 s、0.75 s和0.60 s,是改進YOLOv5算法的8-9倍。

從以上性能指標分析可以看出,基于我們提出的改進YOLOv5算法的火焰煙霧檢測結果AP值高于99%,提高了目標檢測精度,總損失率下降到0.03,顯著低于一般目標檢測算法的損失值。與SSD、YOLOv4-tiny和YOLOv7算法相比,基于改進YOLOv5算法的石化工廠火焰煙霧檢測具有速度快、體積小的優點,較好地滿足了石化工廠火焰煙霧檢測的基本要求。

結論

文章提出了一種基于改進YOLOv5的工廠背景下火焰煙霧實時檢測算法。目的是解決復雜背景、小目標和多目標火焰煙霧檢測中的漏檢和誤檢問題。

該模型采用速度快、精度高、尺寸自適應的YOLOv5l作為基本模型。文章的主要貢獻如下:

(1)為了更好地優化目標盒和預測盒,采用CIoU _ Loss代替原有的GIoU _ Loss作為包圍盒損失函數,加快了模型的收斂速度,提高了模型的檢測性能;

(2)為避免網絡過擬合,將卷積模塊的LeakyReLU激活函數替換為SiLU激活函數,解決LeakyReLU梯度消失和梯度爆炸的問題,防止其泛化性能降低;

(3)針對數據集中目標小、背景復雜的問題,采用馬賽克數據增強技術,提高小目標的檢測精度,增強網絡特征提取能力。自適應圖像調整技術可以自適應地在圖像周圍添加最少的黑邊,減少參數計算量,從而更好地平衡網絡模型的精度和速度。

(4)對預訓練的YOLOv5進行火焰煙霧測試和評估,并與其他算法進行比較。

實驗結果表明,該算法能夠很好地檢測出火焰煙霧樣本圖像中的多目標和小目標,對于數據集中的復雜背景、漏檢、誤檢等問題有較好的改善。該方法在火焰煙霧檢測的實際場景中具有一定的優勢。但是需要考慮的是,當檢測背景與煙霧的相似度過高時,算法在檢測視頻樣本時會出現較低的幀率。原因是數據集本身存在很多小目標,使用馬賽克數據增強會導致模型泛化能力較差。

5.2、YOLOv5~手勢識別

YOLO系列算法以其強悍的性能在圖像領域大放異彩。本文利用YOLOV5實現了一個有趣的功能,對手勢進行訓練識別,并識別顯示出對應的emoji。本文給出了詳細教程和完整實踐代碼,感興趣的同學可以跟著動起手來復現。

本文利用YOLOV5對手勢進行訓練識別,并識別顯示出對應的emoji,如同下圖:

本文整體思路如下。提示:本文含完整實踐代碼,代碼較長,建議先看文字部分的實踐思路,代碼先馬后看

一 、YOLOV5訓練數據集

1. 安裝環境依賴

本教程所用環境:YOLOV5版本是V3.1。

通過git clone 將源碼下載到本地,通過pip install -r requirements.txt 安裝依賴包 ?(其中官方要求python>=3.8 and torch>=1.6)。

我的環境是:系統環境Ubuntu16.04;cuda版本10.2;cudnn版本7.6.5;torch版本1.6.0;python版本3.8

2. 準備手勢識別數據集

其中手勢數據集已上傳至開源數據平臺Graviti,包含了完整代碼。

手勢數據集地址:https://gas.graviti.cn/dataset/datawhale/HandPose?utm_medium=0831datawhale

注:代碼在數據地址的討論區

2.1 數據集的采集以及標注

手勢數據采集的代碼:

import cv2def main():total_pics = 1000cap = cv2.VideoCapture(0)pic_no = 0flag_start_capturing = Falseframes = 0while True:ret,frame = cap.read()frame = cv2.flip(frame,1)cv2.imwrite("hand_images/" +str(pic_no) +".jpg",frame)cv2.imshow("Capturing gesture",frame)cv2.waitKey(10)pic_no += 1if pic_no == total_pics:breakmain()

在yolov5目錄下創建VOC2012文件夾(名字自己定義的),目錄結構就是VOC數據集的,對應如下:

VOC2012
../Annotations   #這個是存放數據集圖片對應的xml文件
../images  #這個存放圖片的
../ImageSets/Main  #這個主要是存放train.txt,test.txt,val.txt和trainval.txt四個文件。里面的內容是訓練集、測試集、驗證集以及訓練驗證集的名字(不帶擴展后綴名)。

示例:

VOC2012文件夾下內容:

Annotations文件中是xml文件(labelimg標注的):?

images為VOC數據集格式中的JPRGImages:?

ImageSets文件中Main子文件夾主要存放訓練,測試驗證集的劃分txt。這個劃分通過以下腳本代碼生成:

# coding:utf-8import os
import random
import argparseparser = argparse.ArgumentParser()
#xml文件的地址,根據自己的數據進行修改 xml一般存放在Annotations下
parser.add_argument('--xml_path', default='C:\\Users\\Lenovo\\Desktop\\hand_datasets\\VOC2012\\Annotations\\', type=str, help='input xml label path')
#數據集的劃分,地址選擇自己數據下的ImageSets/Main
parser.add_argument('--txt_path', default='C:\\Users\\Lenovo\\Desktop\\hand_datasets\\VOC2012\\ImageSets\\Main\\', type=str, help='output txt label path')
opt = parser.parse_args()trainval_percent = 1.0
train_percent = 0.99
xmlfilepath = opt.xml_path
txtsavepath = opt.txt_path
total_xml = os.listdir(xmlfilepath)
if not os.path.exists(txtsavepath):os.makedirs(txtsavepath)num = len(total_xml)
list_index = range(num)
tv = int(num * trainval_percent)
tr = int(tv * train_percent)
trainval = random.sample(list_index, tv)
train = random.sample(trainval, tr)file_trainval = open(txtsavepath + 'trainval.txt', 'w')
file_test = open(txtsavepath + 'test.txt', 'w')
file_train = open(txtsavepath + 'train.txt', 'w')
file_val = open(txtsavepath + 'val.txt', 'w')for i in list_index:name = total_xml[i][:-4] + '\n'if i in trainval:file_trainval.write(name)if i in train:file_train.write(name)else:file_val.write(name)else:file_test.write(name)file_trainval.close()
file_train.close()
file_val.close()
file_test.close()

運行代碼在Main文件下生成txt文檔如下:

2.2 生成yolo訓練格式labels

把xml標注信息轉換成yolo的txt格式。其中yolo的txt標簽格式信息:每個圖像對應一個txt文件,文件每一行為一個目標信息,包括classx_center, y_center, width, height 格式。如下圖所示:

創建voc_label.py文件,將訓練集,驗證集以及測試集生成txt標簽,代碼如下:

# -*- coding: utf-8 -*-
import xml.etree.ElementTree as ET
import os
from os import getcwdsets = ['train', 'val', 'test']
classes = ["four_fingers","hand_with_fingers_splayed","index_pointing_up","little_finger","ok_hand","raised_fist","raised_hand","sign_of_the_horns","three","thumbup","victory_hand"] 
# 11 classes  # 改成自己的類別
abs_path = os.getcwd()
print(abs_path)def convert(size, box):dw = 1. / (size[0])dh = 1. / (size[1])x = (box[0] + box[1]) / 2.0 - 1y = (box[2] + box[3]) / 2.0 - 1w = box[1] - box[0]h = box[3] - box[2]x = x * dww = w * dwy = y * dhh = h * dhreturn x, y, w, hdef convert_annotation(image_id):in_file = open('/home/yanyq/Ryan/yolov5/VOC2012/Annotations/%s.xml' % (image_id), encoding='UTF-8')out_file = open('/home/yanyq/Ryan/yolov5/VOC2012/labels/%s.txt' % (image_id), 'w')tree = ET.parse(in_file)root = tree.getroot()size = root.find('size')w = int(size.find('width').text)h = int(size.find('height').text)for obj in root.iter('object'):# difficult = obj.find('difficult').textdifficult = obj.find('difficult').textcls = obj.find('name').textif cls not in classes or int(difficult) == 1:continuecls_id = classes.index(cls)xmlbox = obj.find('bndbox')b = (float(xmlbox.find('xmin').text), float(xmlbox.find('xmax').text), float(xmlbox.find('ymin').text),float(xmlbox.find('ymax').text))b1, b2, b3, b4 = b# 標注越界修正if b2 > w:b2 = wif b4 > h:b4 = hb = (b1, b2, b3, b4)bb = convert((w, h), b)out_file.write(str(cls_id) + " " + " ".join([str(a) for a in bb]) + '\n')wd = getcwd()
for image_set in sets:if not os.path.exists('/home/yanyq/Ryan/yolov5/VOC2012/labels/'):os.makedirs('/home/yanyq/Ryan/yolov5/VOC2012/labels/')image_ids = open('/home/yanyq/Ryan/yolov5/VOC2012/ImageSets/Main/%s.txt' % (image_set)).read().strip().split()list_file = open('%s.txt' % (image_set), 'w')for image_id in image_ids:list_file.write(abs_path + '/images/%s.jpg\n' % (image_id))convert_annotation(image_id)list_file.close()

運行上述腳本后會生成labels文件夾和三個包含數據集的txt文件,其中labels中為圖像的yolo格式標注文件,train.txt,test.txt, val.txt文件為劃分后圖像所在位置的絕對路徑。

三個txt文件內容:

2.3 配置文件

1)數據集的配置

在yolov5目錄的data文件夾新建一個Emoji.yaml文件(自己定義)。用來存放訓練集驗證集的劃分文件train.txt和val.txt(其中這兩個文件是voc_label.py生成的)。具體內容如下:

2)模型的配置文件

一般訓練yolo模型的時候,是可以聚類自己標注的框作為先驗框(這樣可以保證標注樣本最大化的利用)。我們這里就直接采用默認值了。

選擇一個需要的模型,YOLOV5有提供s、m、l、x版本,其是逐漸增大的架構,也就是訓練時間和推理時間都對應增加,我們這里選擇s版本。在yolov5文件夾下的models文件夾中打開yolov5s.yaml文件,修改內容如下圖(我們選擇默認anchor,所以不做修改,只需要更改nc中的類別數,由于我們是11類,所以改成11就可以了):

到這里我們的自定義數據集以及配置文件創建完畢,下面就是訓練模型了。

3.模型訓練

3.1、下載預訓練模型

在源碼yolov5目錄下的weights文件夾下提供了下載smlx模型的腳本--download_weights.sh,執行這個腳本就可以下載這四個模型的預訓練模型了。

3.2、訓練模型

以上參數解釋如下:epochs:指的就是訓練過程中整個數據集將被迭代多少次,顯卡不行你就調小點。batch-size:一次看完多少張圖片才進行權重更新,梯度下降的mini-batch,顯卡不行你就調小點。cfg:存儲模型結構的配置文件。data:存儲訓練、測試數據的文件。img-size:輸入圖片寬高,顯卡不行你就……。rect:進行矩形訓練。resume:恢復最近保存的模型開始訓練。nosave:僅保存最終checkpoint。notest:僅測試最后的epoch。evolve:進化超參數。bucket:gsutil bucket。**?cache-images:緩存圖像以加快訓練速度。?weights:權重文件路徑。name:重命名results.txt to results_name.txt。device:cuda device, i.e. 0 or 0,1,2,3 or cpu。adam:使用adam優化。multi-scale:多尺度訓練,img-size +/- 50%。single-cls:**單類別的訓練集

訓練只需要運行訓練命令就可以了,如下:

$ python train.py  --data Emoji.yaml --cfg yolov5s.yaml --weights weights/yolov5s.pt --batch-size 64 --device "0,1,2,3" --epochs 200 --img-size 640

其中device batch-size 等需要根據自己機器進行設置。

4.模型測試

評估模型好壞就是在有標注的測試集或驗證集上進行模型效果的評估,在目標檢測中最常使用的評估指標為mAP。yolov5文件下的test.py文件中指定了數據集的配置文件和訓練結果模型如下:

通過以下命令進行模型測試:

python test.py --data data/Emoji.yaml --weights runs/train/exp2/weights/best.pt --augment

模型測試效果:

測試結果圖:

二、YOLOV5模型轉換

1.安裝依賴庫

pip install onnx coremltools onnx-simplifier

2.導出ONNX模型

python models/export.py --weights runs/train/exp2/weights/best.pt --img 640 --batch 1

此時在best.pt同級目錄下生成了best.mlmodel best.onnx best.torchscript.pt三個文件,我們只需best.onnx,這個文件可以直接用netron打開查看模型結構。

3.用onnx-simplifer簡化模型

為什么要簡化?

在訓練完深度學習的pytorch或者tensorflow模型后,有時候需要把模型轉成 onnx,但是很多時候,很多節點比如cast節點,Identity 這些節點可能都不需要,我們需要進行簡化,這樣會方便我們把模型轉成ncnn或者mnn等這些端側部署的模型格式或者通過tensorRT進行部署。

python -m onnxsim best.onnx yolov5-best-sim.onnx

完成后就生成了簡化版本的模型yolov5-best-sim.onnx。

三、YOLOV5轉換成ncnn模型

1、onnx轉.param .bin

由上述生成了yolov5-best-sim.onnx這個模型,我們利用ncnn自帶的工具onnx2ncnn.exe(這個工具是自己編譯生成的,我這里是在windows下編譯生成的,可以用linux下的可執行文件)生成yolov5s.param ?yolov5s.bin兩個文件。

在windows平臺下ctrl+r ? cmd命令行窗口輸入:

onnx2ncnn.exe yolov5-best-sim.onnx yolov5s.param yolov5s.bin

轉換的過程中會出現上圖所示的ncnn不支持層,下邊就是要修改param文件,把不支持層改成支持層。

2、修改.param 參數去除不支持的網絡層

去掉不支持的網絡層,打開轉換得到的yolov5s.param文件,前面幾行需要刪除的是標紅部分。(注意我們訓練yoloV5的版本是V3.1,這里不同的版本可能會不同。)

修改結果如下綠色框和紅色框中的。因為去掉了10層所以變成191 ?228。并用YoloV5Focus網絡層代替去掉的10層,而YoloV5Focus網絡層中的images代表該層的輸入,207代表的輸出名,這個是根據下邊一層的卷積層輸入層數寫的。?

修改網路的輸出shape:

當基于修改后的網路使用ncnn/examples/yolov5測試時會發現出現圖片中一堆亂框,這種情況需要修改網路的輸出部分。在保證輸出名一致的情況下,修改Reshape中的0=-1,使的最終的輸出shape不固定。具體的修改地方以及修改之前和之后見下圖。

3、ncnn的c++測試代碼實現

以下是用C++實現的完整代碼。建議一劃到底,先看最后的整體思路

#include <string>
#include <vector>
#include "iostream"  
//#include <fstream>  
//#include < ctime >
//#include <direct.h>
//#include <io.h>// ncnn
#include "ncnn/layer.h"
#include "ncnn/net.h"
#include "ncnn/benchmark.h"
//#include "gpu.h"#include "opencv2/core/core.hpp"
#include "opencv2/highgui/highgui.hpp"
#include <opencv2/imgproc.hpp>
#include "opencv2/opencv.hpp"  using namespace std;
using namespace cv;static ncnn::UnlockedPoolAllocator g_blob_pool_allocator;
static ncnn::PoolAllocator g_workspace_pool_allocator;static ncnn::Net yolov5;class YoloV5Focus : public ncnn::Layer
{
public:YoloV5Focus(){one_blob_only = true;}virtual int forward(const ncnn::Mat& bottom_blob, ncnn::Mat& top_blob, const ncnn::Option& opt) const{int w = bottom_blob.w;int h = bottom_blob.h;int channels = bottom_blob.c;int outw = w / 2;int outh = h / 2;int outc = channels * 4;top_blob.create(outw, outh, outc, 4u, 1, opt.blob_allocator);if (top_blob.empty())return -100;#pragma omp parallel for num_threads(opt.num_threads)for (int p = 0; p < outc; p++){const float* ptr = bottom_blob.channel(p % channels).row((p / channels) % 2) + ((p / channels) / 2);float* outptr = top_blob.channel(p);for (int i = 0; i < outh; i++){for (int j = 0; j < outw; j++){*outptr = *ptr;outptr += 1;ptr += 2;}ptr += w;}}return 0;}
};
DEFINE_LAYER_CREATOR(YoloV5Focus)struct Object
{float x;float y;float w;float h;int label;float prob;
};static inline float intersection_area(const Object& a, const Object& b)
{if (a.x > b.x + b.w || a.x + a.w < b.x || a.y > b.y + b.h || a.y + a.h < b.y){// no intersectionreturn 0.f;}float inter_width = std::min(a.x + a.w, b.x + b.w) - std::max(a.x, b.x);float inter_height = std::min(a.y + a.h, b.y + b.h) - std::max(a.y, b.y);return inter_width * inter_height;
}static void qsort_descent_inplace(std::vector<Object>& faceobjects, int left, int right)
{int i = left;int j = right;float p = faceobjects[(left + right) / 2].prob;while (i <= j){while (faceobjects[i].prob > p)i++;while (faceobjects[j].prob < p)j--;if (i <= j){// swapstd::swap(faceobjects[i], faceobjects[j]);i++;j--;}}#pragma omp parallel sections{
#pragma omp section{if (left < j) qsort_descent_inplace(faceobjects, left, j);}
#pragma omp section{if (i < right) qsort_descent_inplace(faceobjects, i, right);}}
}static void qsort_descent_inplace(std::vector<Object>& faceobjects)
{if (faceobjects.empty())return;qsort_descent_inplace(faceobjects, 0, faceobjects.size() - 1);
}static void nms_sorted_bboxes(const std::vector<Object>& faceobjects, std::vector<int>& picked, float nms_threshold)
{picked.clear();const int n = faceobjects.size();std::vector<float> areas(n);for (int i = 0; i < n; i++){areas[i] = faceobjects[i].w * faceobjects[i].h;}for (int i = 0; i < n; i++){const Object& a = faceobjects[i];int keep = 1;for (int j = 0; j < (int)picked.size(); j++){const Object& b = faceobjects[picked[j]];// intersection over unionfloat inter_area = intersection_area(a, b);float union_area = areas[i] + areas[picked[j]] - inter_area;// float IoU = inter_area / union_areaif (inter_area / union_area > nms_threshold)keep = 0;}if (keep)picked.push_back(i);}
}static inline float sigmoid(float x)
{return static_cast<float>(1.f / (1.f + exp(-x)));
}static void generate_proposals(const ncnn::Mat& anchors, int stride, const ncnn::Mat& in_pad, const ncnn::Mat& feat_blob, float prob_threshold, std::vector<Object>& objects)
{const int num_grid = feat_blob.h;int num_grid_x;int num_grid_y;if (in_pad.w > in_pad.h){num_grid_x = in_pad.w / stride;num_grid_y = num_grid / num_grid_x;}else{num_grid_y = in_pad.h / stride;num_grid_x = num_grid / num_grid_y;}const int num_class = feat_blob.w - 5;const int num_anchors = anchors.w / 2;for (int q = 0; q < num_anchors; q++){const float anchor_w = anchors[q * 2];const float anchor_h = anchors[q * 2 + 1];const ncnn::Mat feat = feat_blob.channel(q);for (int i = 0; i < num_grid_y; i++){for (int j = 0; j < num_grid_x; j++){const float* featptr = feat.row(i * num_grid_x + j);// find class index with max class scoreint class_index = 0;float class_score = -FLT_MAX;for (int k = 0; k < num_class; k++){float score = featptr[5 + k];if (score > class_score){class_index = k;class_score = score;}}float box_score = featptr[4];float confidence = sigmoid(box_score) * sigmoid(class_score);if (confidence >= prob_threshold){float dx = sigmoid(featptr[0]);float dy = sigmoid(featptr[1]);float dw = sigmoid(featptr[2]);float dh = sigmoid(featptr[3]);float pb_cx = (dx * 2.f - 0.5f + j) * stride;float pb_cy = (dy * 2.f - 0.5f + i) * stride;float pb_w = pow(dw * 2.f, 2) * anchor_w;float pb_h = pow(dh * 2.f, 2) * anchor_h;float x0 = pb_cx - pb_w * 0.5f;float y0 = pb_cy - pb_h * 0.5f;float x1 = pb_cx + pb_w * 0.5f;float y1 = pb_cy + pb_h * 0.5f;Object obj;obj.x = x0;obj.y = y0;obj.w = x1 - x0;obj.h = y1 - y0;obj.label = class_index;obj.prob = confidence;objects.push_back(obj);}}}}
}extern "C" {void release(){fprintf(stderr, "YoloV5Ncnn finished!");//ncnn::destroy_gpu_instance();}int init(){fprintf(stderr, "YoloV5Ncnn init!\n");ncnn::Option opt;opt.lightmode = true;opt.num_threads = 4;opt.blob_allocator = &g_blob_pool_allocator;opt.workspace_allocator = &g_workspace_pool_allocator;opt.use_packing_layout = true;yolov5.opt = opt;yolov5.register_custom_layer("YoloV5Focus", YoloV5Focus_layer_creator);// init param{int ret = yolov5.load_param("yolov5s.param");  if (ret != 0){std::cout << "ret= " << ret << std::endl;fprintf(stderr, "YoloV5Ncnn, load_param failed");return -301;}}// init bin{int ret = yolov5.load_model("yolov5s.bin");  if (ret != 0){fprintf(stderr, "YoloV5Ncnn, load_model failed");return -301;}}return 0;}int detect(cv::Mat img, std::vector<Object> &objects){double start_time = ncnn::get_current_time();const int target_size = 320;// letterbox pad to multiple of 32const int width = img.cols;//1280const int height = img.rows;//720int w = img.cols;//1280int h = img.rows;//720float scale = 1.f;if (w > h){scale = (float)target_size / w;//640/1280w = target_size;//640h = h * scale;//360}else{scale = (float)target_size / h;h = target_size;w = w * scale;}cv::resize(img, img, cv::Size(w, h));ncnn::Mat in = ncnn::Mat::from_pixels(img.data, ncnn::Mat::PIXEL_BGR2RGB, w, h);// pad to target_size rectangle// yolov5/utils/datasets.py letterboxint wpad = (w + 31) / 32 * 32 - w;int hpad = (h + 31) / 32 * 32 - h;ncnn::Mat in_pad;ncnn::copy_make_border(in, in_pad, hpad / 2, hpad - hpad / 2, wpad / 2, wpad - wpad / 2, ncnn::BORDER_CONSTANT, 114.f);// yolov5//std::vector<Object> objects;{const float prob_threshold = 0.4f;const float nms_threshold = 0.51f;const float norm_vals[3] = { 1 / 255.f, 1 / 255.f, 1 / 255.f };in_pad.substract_mean_normalize(0, norm_vals);ncnn::Extractor ex = yolov5.create_extractor();//ex.set_vulkan_compute(use_gpu);ex.input("images", in_pad);std::vector<Object> proposals;// anchor setting from yolov5/models/yolov5s.yaml// stride 8{ncnn::Mat out;ex.extract("output", out);ncnn::Mat anchors(6);anchors[0] = 10.f;anchors[1] = 13.f;anchors[2] = 16.f;anchors[3] = 30.f;anchors[4] = 33.f;anchors[5] = 23.f;std::vector<Object> objects8;generate_proposals(anchors, 8, in_pad, out, prob_threshold, objects8);proposals.insert(proposals.end(), objects8.begin(), objects8.end());}// stride 16{ncnn::Mat out;ex.extract("771", out);ncnn::Mat anchors(6);anchors[0] = 30.f;anchors[1] = 61.f;anchors[2] = 62.f;anchors[3] = 45.f;anchors[4] = 59.f;anchors[5] = 119.f;std::vector<Object> objects16;generate_proposals(anchors, 16, in_pad, out, prob_threshold, objects16);proposals.insert(proposals.end(), objects16.begin(), objects16.end());}// stride 32{ncnn::Mat out;ex.extract("791", out);ncnn::Mat anchors(6);anchors[0] = 116.f;anchors[1] = 90.f;anchors[2] = 156.f;anchors[3] = 198.f;anchors[4] = 373.f;anchors[5] = 326.f;std::vector<Object> objects32;generate_proposals(anchors, 32, in_pad, out, prob_threshold, objects32);proposals.insert(proposals.end(), objects32.begin(), objects32.end());}// sort all proposals by score from highest to lowestqsort_descent_inplace(proposals);// apply nms with nms_thresholdstd::vector<int> picked;nms_sorted_bboxes(proposals, picked, nms_threshold);int count = picked.size();objects.resize(count);for (int i = 0; i < count; i++){objects[i] = proposals[picked[i]];// adjust offset to original unpaddedfloat x0 = (objects[i].x - (wpad / 2)) / scale;float y0 = (objects[i].y - (hpad / 2)) / scale;float x1 = (objects[i].x + objects[i].w - (wpad / 2)) / scale;float y1 = (objects[i].y + objects[i].h - (hpad / 2)) / scale;// clipx0 = std::max(std::min(x0, (float)(width - 1)), 0.f);y0 = std::max(std::min(y0, (float)(height - 1)), 0.f);x1 = std::max(std::min(x1, (float)(width - 1)), 0.f);y1 = std::max(std::min(y1, (float)(height - 1)), 0.f);objects[i].x = x0;objects[i].y = y0;objects[i].w = x1;objects[i].h = y1;}}return 0;}
}static const char* class_names[] = {"four_fingers","hand_with_fingers_splayed","index_pointing_up","little_finger","ok_hand","raised_fist","raised_hand","sign_of_the_horns","three","thumbup","victory_hand"
};void draw_face_box(cv::Mat& bgr, std::vector<Object> object) //主要的emoji顯示函數
{for (int i = 0; i < object.size(); i++){const auto obj = object[i];cv::rectangle(bgr, cv::Point(obj.x, obj.y), cv::Point(obj.w, obj.h), cv::Scalar(0, 255, 0), 3, 8, 0);std::cout << "label:" << class_names[obj.label] << std::endl;string emoji_path = "emoji\\" + string(class_names[obj.label]) + ".png"; //這個是emoji圖片的路徑cv::Mat logo = cv::imread(emoji_path);if (logo.empty()) {std::cout << "imread logo failed!!!" << std::endl;return;}resize(logo, logo, cv::Size(80, 80));cv::Mat imageROI = bgr(cv::Range(obj.x, obj.x + logo.rows), cv::Range(obj.y, obj.y + logo.cols));  //emoji的圖片放在圖中的位置,也就是手勢框的旁邊logo.copyTo(imageROI); //把emoji放在原圖中}}int main()
{Mat frame;VideoCapture capture(0);init();while (true){capture >> frame;            if (!frame.empty()) {          std::vector<Object> objects;detect(frame, objects);draw_face_box(frame, objects);imshow("window", frame);  }if (waitKey(20) == 'q')    break;}capture.release();     return 0;
}

這里是首先用yolov5s識別出手勢,然后利用圖像ROI融合,把相應的Emoji縮放到80x80大小顯示在手勢框的旁邊,實現根據不同的手勢顯示相應的Emoji。

4、實現emoji和手勢的映射

到這里,我們終于大功告成!達成了開頭的效果。

圖就是最上面的

5.3、YOLO5~PCB板缺陷檢測

利用YOLOv5算法實現對PCB板上的缺陷進行檢測識別。

一、數據集介紹

使用的DeepPCB缺陷數據集中的所有圖像都是從線性掃描CCD獲得的,分辨率約為每1毫米48個像素,以上述方式從采樣圖像中手動檢查

測試圖像的原始大小約為16k x 16k像素, 然后將它們裁剪成許多大小為640 x 640的子圖像,共1500張圖片,DeepPCB數據集中的部分圖片如下圖所示。

PCB面板數據集自己去找

對于測試圖像中的每個缺陷,我們使用軸對齊的邊界框和一個類ID。如上所示,我們標注了六種常見的PCB缺陷類型:open、short、mousebite、spur、pin-hole、spur。

由于實際測試圖像中只有少數缺陷,我們根據 PCB 缺陷模式在每個測試圖像上手動論證一些人工缺陷,這導致每個640 x 640圖像中大約有3到12個缺陷。

PCB缺陷數如下圖所示。我們將1000 張圖像作為訓練集,剩下的作為測試集。

二、構建訓練數據集?1、先構建數據集文件夾

本人按照VOC格式創建數據集,具體格式如下:

├── data
│   ├── xml  進行 detection 任務時的標簽文件,xml 形式,文件名與圖片名一一對應
│   ├── image  存放.jpg 格式的圖片文件
│   ├── label  存放label標注信息的txt文件,與圖片一一對應
│   ├── txt  存放原始標注信息,x1,y1,x2,y2,type
├── dataSet(train,val,test建議按照8:1:1比例劃分)
│   ├── train.txt  寫著用于訓練的圖片名稱
│   ├── val.txt  寫著用于驗證的圖片名稱
│   ├── trainval.txt  train與val的合集
│   ├── test.txt  寫著用于測試的圖片名稱

2、數據集格式轉換

原始的標注信息是保存成txt文件,txt文件里面的每一行都包含一個標注信息,格式為x1,y1,x2,y2,type,這里 (x1,y1) 和 (x2,y2) 是缺陷邊界框的左上角和右下角

type是匹配后的整數 ID:0-background、1-open、2-short、3-mousebite、4-spur、5-copper、6-pin-hole。通過一下代碼進行轉換:

import os
import cv2
import time
from xml.dom import minidomname_dict = {'0': 'background', '1': 'open', '2': 'short','3': 'mousebite', '4': 'spur', '5': 'copper', '6': 'pin-hole'}def transfer_to_xml(pic, txt, file_name,xml_save_path):if not os.path.exists(xml_save_path):os.makedirs(xml_save_path,exist_ok=True)img = cv2.imread(pic)img_w = img.shape[1]img_h = img.shape[0]img_d = img.shape[2]doc = minidom.Document()annotation = doc.createElement("annotation")doc.appendChild(annotation)folder = doc.createElement('folder')folder.appendChild(doc.createTextNode('visdrone'))annotation.appendChild(folder)filename = doc.createElement('filename')filename.appendChild(doc.createTextNode(file_name))annotation.appendChild(filename)source = doc.createElement('source')database = doc.createElement('database')database.appendChild(doc.createTextNode("Unknown"))source.appendChild(database)annotation.appendChild(source)size = doc.createElement('size')width = doc.createElement('width')width.appendChild(doc.createTextNode(str(img_w)))size.appendChild(width)height = doc.createElement('height')height.appendChild(doc.createTextNode(str(img_h)))size.appendChild(height)depth = doc.createElement('depth')depth.appendChild(doc.createTextNode(str(img_d)))size.appendChild(depth)annotation.appendChild(size)segmented = doc.createElement('segmented')segmented.appendChild(doc.createTextNode("0"))annotation.appendChild(segmented)with open(txt, 'r') as f:lines = [f.readlines()]for line in lines:for boxes in line:box = boxes.strip('\n')box = box.split(" ")x_min = box[0]y_min = box[1]x_max = box[2]y_max = box[3]object_name = name_dict[box[4]]if object_name != "background":object = doc.createElement('object')nm = doc.createElement('name')nm.appendChild(doc.createTextNode(object_name))object.appendChild(nm)pose = doc.createElement('pose')pose.appendChild(doc.createTextNode("Unspecified"))object.appendChild(pose)truncated = doc.createElement('truncated')truncated.appendChild(doc.createTextNode("1"))object.appendChild(truncated)difficult = doc.createElement('difficult')difficult.appendChild(doc.createTextNode("0"))object.appendChild(difficult)bndbox = doc.createElement('bndbox')xmin = doc.createElement('xmin')xmin.appendChild(doc.createTextNode(x_min))bndbox.appendChild(xmin)ymin = doc.createElement('ymin')ymin.appendChild(doc.createTextNode(y_min))bndbox.appendChild(ymin)xmax = doc.createElement('xmax')xmax.appendChild(doc.createTextNode(str(x_max)))bndbox.appendChild(xmax)ymax = doc.createElement('ymax')ymax.appendChild(doc.createTextNode(str(y_max)))bndbox.appendChild(ymax)object.appendChild(bndbox)annotation.appendChild(object)with open(os.path.join(xml_save_path, file_name + '.xml'), 'w') as x:x.write(doc.toprettyxml())x.close()f.close()if __name__ == '__main__':t = time.time()print('Transfer .txt to .xml...ing....')txt_folder = 'data/PCBDatasets/txt'txt_file = os.listdir(txt_folder)img_folder = 'data/PCBDatasets/image'xml_save_path = 'data/PCBDatasets/xml/'for txt in txt_file:txt_full_path = os.path.join(txt_folder, txt)img_full_path = os.path.join(img_folder, txt.split('.')[0] + '.jpg')try:transfer_to_xml(img_full_path, txt_full_path, txt.split('.')[0],xml_save_path)except Exception as e:print(e)print("Transfer .txt to .XML sucessed. costed: {:.3f}s...".format(time.time() - t))

3、訓練集劃分代碼

主要是將數據集分類成訓練數據集和測試數據集,默認train,val,test按照比例進行隨機分類,運行后dataSet文件夾中會出現四個文件

主要是生成的訓練數據集和測試數據集的圖片名稱,如下圖。同時data目錄下也會出現這四個文件,內容是訓練數據集和測試數據集的圖片路徑。

import os
import randomtrainval_percent = 0.9
train_percent = 0.9
xmlfilepath = 'data/PCBDatasets/xml/'
txtsavepath = 'data/PCBDatasets/dataSet/'
total_xml = os.listdir(xmlfilepath)num = len(total_xml)
list = range(num)
tv = int(num * trainval_percent)
tr = int(tv * train_percent)
trainval = random.sample(list, tv)
train = random.sample(trainval, tr)ftrainval = open('data/PCBDatasets/dataSet/trainval.txt', 'w')
ftest = open('data/PCBDatasets/dataSet/test.txt', 'w')
ftrain = open('data/PCBDatasets/dataSet/train.txt', 'w')
fval = open('data/PCBDatasets/dataSet/val.txt', 'w')for i in list:name = total_xml[i][:-4] + '\n'if i in trainval:ftrainval.write(name)if i in train:ftrain.write(name)else:fval.write(name)else:ftest.write(name)ftrainval.close()
ftrain.close()
fval.close()
ftest.close()

4、生成yolo格式的標簽

主要是將圖片數據集標注后的xml文件中的標注信息讀取出來并寫入txt文件,運行后在label文件夾中出現所有圖片數據集的標注信息

# xml解析包import xml.etree.ElementTree as ET
import pickle
import os# os.listdir() 方法用于返回指定的文件夾包含的文件或文件夾的名字的列表from os import listdir, getcwd
from os.path import joinsets = ['train', 'test', 'val']
classes = ['open', 'short','mousebite','spur', 'copper', 'pin-hole']# 進行歸一化操作def convert(size, box):  # size:(原圖w,原圖h) , box:(xmin,xmax,ymin,ymax)dw = 1./size[0]     # 1/wdh = 1./size[1]     # 1/hx = (box[0] + box[1])/2.0   # 物體在圖中的中心點x坐標y = (box[2] + box[3])/2.0   # 物體在圖中的中心點y坐標w = box[1] - box[0]         # 物體實際像素寬度h = box[3] - box[2]         # 物體實際像素高度x = x*dw    # 物體中心點x的坐標比(相當于 x/原圖w)w = w*dw    # 物體寬度的寬度比(相當于 w/原圖w)y = y*dh    # 物體中心點y的坐標比(相當于 y/原圖h)h = h*dh    # 物體寬度的寬度比(相當于 h/原圖h)return (x, y, w, h)    # 返回 相對于原圖的物體中心點的x坐標比,y坐標比,寬度比,高度比,取值范圍[0-1]def convert_annotation(image_id):'''將對應文件名的xml文件轉化為label文件,xml文件包含了對應的bunding框以及圖片長款大小等信息,通過對其解析,然后進行歸一化最終讀到label文件中去,也就是說一張圖片文件對應一個xml文件,然后通過解析和歸一化,能夠將對應的信息保存到唯一一個label文件中去labal文件中的格式:calss x y w h  同時,一張圖片對應的類別有多個,所以對應的bounding的信息也有多個'''# 對應的通過year 找到相應的文件夾,并且打開相應image_id的xml文件,其對應bund文件in_file = open('data/PCBDatasets/xml/%s.xml' % (image_id), encoding='utf-8')# 準備在對應的image_id 中寫入對應的label,分別為# <object-class> <x> <y> <width> <height>out_file = open('data/PCBDatasets/label/%s.txt' % (image_id), 'w', encoding='utf-8')# 解析xml文件tree = ET.parse(in_file)# 獲得對應的鍵值對root = tree.getroot()# 獲得圖片的尺寸大小size = root.find('size')# 如果xml內的標記為空,增加判斷條件if size != None:# 獲得寬w = int(size.find('width').text)# 獲得高h = int(size.find('height').text)# 遍歷目標objfor obj in root.iter('object'):# 獲得difficult ??difficult = obj.find('difficult').text# 獲得類別 =string 類型cls = obj.find('name').text# 如果類別不是對應在我們預定好的class文件中,或difficult==1則跳過if cls not in classes or int(difficult) == 1:continue# 通過類別名稱找到idcls_id = classes.index(cls)# 找到bndbox 對象xmlbox = obj.find('bndbox')# 獲取對應的bndbox的數組 = ['xmin','xmax','ymin','ymax']b = (float(xmlbox.find('xmin').text), float(xmlbox.find('xmax').text), float(xmlbox.find('ymin').text),float(xmlbox.find('ymax').text))print(image_id, cls, b)# 帶入進行歸一化操作# w = 寬, h = 高, b= bndbox的數組 = ['xmin','xmax','ymin','ymax']bb = convert((w, h), b)# bb 對應的是歸一化后的(x,y,w,h)# 生成 calss x y w h 在label文件中out_file.write(str(cls_id) + " " + " ".join([str(a) for a in bb]) + '\n')# 返回當前工作目錄wd = getcwd()
print(wd)for image_set in sets:'''對所有的文件數據集進行遍歷做了兩個工作:1.將所有圖片文件都遍歷一遍,并且將其所有的全路徑都寫在對應的txt文件中去,方便定位2.同時對所有的圖片文件進行解析和轉化,將其對應的bundingbox 以及類別的信息全部解析寫到label 文件中去最后再通過直接讀取文件,就能找到對應的label 信息'''# 先找labels文件夾如果不存在則創建if not os.path.exists('data/PCBDatasets/labels/'):os.makedirs('data/PCBDatasets/labels/')# 讀取在ImageSets/Main 中的train、test..等文件的內容# 包含對應的文件名稱image_ids = open('data/PCBDatasets/dataSet/%s.txt' % (image_set)).read().strip().split()list_file = open('data/PCBDatasets/%s.txt' % (image_set), 'w')# 將對應的文件_id以及全路徑寫進去并換行for image_id in image_ids:list_file.write('data/PCBDatasets/image/%s.jpg\n' % (image_id))# 調用  year = 年份  image_id = 對應的文件名_idconvert_annotation(image_id)# 關閉文件list_file.close()

label文件夾中某文件內容如下:

三、修改配置文件1、數據配置文件

首先需要在/yolov5-master/data文件夾中,新建一個PCBDetect.yaml文件,內容設置如下:

train: data/PCBDatasets/dataSet/train.txt
val:  data/PCBDatasets/dataSet/val.txt
test: data/PCBDatasets/dataSet/test.txtnc: 6names: ['copper', 'mousebite', 'open', 'pin-hole', 'short', 'spur']

2、網絡參數修改

對yolov5-master/model文件夾中,對yolov5x.yaml(根據自己選擇的模型而定)文件內容修改。

3、trian.py修改

主要用到的幾個參數:–weights,–cfg,–data,–epochs,–batch-size,–img-size,–project,-workers

重點注意:–weights,–cfg,–data,其他的默認即可(batch_size,workers根據自己電腦屬性進行設置)。

四、訓練及測試1、訓練

在完成上述所有的操作之后,就可以進行訓練,在命令窗口輸入python train.py即可以進行訓練。

2、測試

在訓練完成后可以利用測試集對訓練后的模型進行測試,利用val.py文件進行測試,主要修改一下地方:

測試完成后會輸出map、precision、recall等指標,具體如下圖所示:?

P-R曲線如下圖所示:

同時也可以利用detect.py文件對測試集進行測試,將檢測后的框繪制在圖像上,部分測試結果如下圖所示:?

?大大的demo 完事了 不過靠不靠譜我也不敢保證~~

6、Yolo8

6.1、YOLOv8~2

又是一個講v8的 , 本人還沒有試 不過聽說不錯

YOLOv8 是 ultralytics 公司在 2023 年 1月 10 號開源的 YOLOv5 的下一個重大更新版本,目前支持圖像分類、物體檢測和實例分割任務,在還沒有開源時就收到了用戶的廣泛關注。開源地址:https://github.com/ultralytics/ultralytics

YOLOv8 是一個 SOTA 模型,它建立在以前 YOLO 版本的成功基礎上,并引入了新的功能和改進,以進一步提升性能和靈活性。具體創新包括一個新的骨干網絡、一個新的 Ancher-Free 檢測頭和一個新的損失函數,可以在從 CPU 到 GPU 的各種硬件平臺上運行。

下面是使用YOLOv8做目標檢測和實例分割的演示視頻:發不了....

YOLO: A Brief History

YOLO(You Only Look Once)是一種流行的對象檢測和圖像分割模型,由華盛頓大學的Joseph Redmon和Ali Farhadi開發。YOLO于2015年推出,以其高速度和高精度迅速走紅。

  • YOLOv2于2016年發布,通過合并批處理規范化、錨盒和維度集群來改進原始模型
  • 2018年推出的YOLOv3使用更高效的骨干網絡、多個錨點和空間金字塔池進一步增強了該模型的性能
  • YOLOv4于2020年發布,引入了Mosaic數據增強、新的無錨檢測頭和新的丟失功能等創新
  • YOLOv5進一步提高了模型的性能,并添加了超參數優化、集成實驗跟蹤和自動導出到流行導出格式等新功能
  • YOLOv6于2022年由美團開源,目前正在該公司的許多自動配送機器人中使用
  • YOLOv7在COCO關鍵點數據集上添加了額外的任務,如姿態估計
  • YOLOv8是Ultralytics公司推出的YOLO的最新版本。作為一款尖端、最先進的(SOTA)車型,YOLOv8在之前版本的成功基礎上,引入了新的功能和改進,以增強性能、靈活性和效率。YOLOv8支持全方位的視覺AI任務,包括檢測、分割、姿態估計、跟蹤和分類。這種多功能性允許用戶在不同的應用程序和域中利用YOLOv8的功能

YOLOv8的新特性與可用模型

Ultralytics 并沒有直接將開源庫命名為 YOLOv8,而是直接使用 ultralytics 這個詞,原因是 ultralytics 將這個庫定位為算法框架,而非某一個特定算法,一個主要特點是可擴展性。其希望這個庫不僅僅能夠用于 YOLO 系列模型,而是能夠支持非 YOLO 模型以及分類分割姿態估計等各類任務。總而言之,ultralytics 開源庫的兩個主要優點是:

  • 融合眾多當前 SOTA 技術于一體
  • 未來將支持其他 YOLO 系列以及 YOLO 之外的更多算法

Ultralytics為YOLO模型發布了一個全新的存儲庫。它被構建為 用于訓練對象檢測、實例分割和圖像分類模型的統一框架。

  1. 提供了一個全新的 SOTA 模型,包括 P5 640 和 P6 1280 分辨率的目標檢測網絡和基于?YOLACT?的實例分割模型。和 YOLOv5 一樣,基于縮放系數也提供了 N/S/M/L/X 尺度的不同大小模型,用于滿足不同場景需求
  2. 骨干網絡和 Neck 部分可能參考了 YOLOv7 ELAN 設計思想,將 YOLOv5 的 C3 結構換成了梯度流更豐富的 C2f 結構,并對不同尺度模型調整了不同的通道數,屬于對模型結構精心微調,不再是無腦一套參數應用所有模型,大幅提升了模型性能。不過這個 C2f 模塊中存在 Split 等操作對特定硬件部署沒有之前那么友好了
  3. Head 部分相比 YOLOv5 改動較大,換成了目前主流的解耦頭結構,將分類和檢測頭分離,同時也從 Anchor-Based 換成了 Anchor-Free
  4. Loss 計算方面采用了 TaskAlignedAssigner 正樣本分配策略,并引入了 Distribution Focal Loss
  5. 訓練的數據增強部分引入了 YOLOX 中的最后 10 epoch 關閉 Mosiac 增強的操作,可以有效地提升精度

YOLOv8 還高效靈活地支持多種導出格式,并且該模型可以在 CPU 和 GPU 上運行。YOLOv8 模型的每個類別中有五個模型用于檢測、分割和分類。YOLOv8 Nano 是最快和最小的,而 YOLOv8 Extra Large (YOLOv8x) 是其中最準確但最慢的。

如下是使用YOLOv8x做目標檢測和實例分割模型的輸出:

如何使用YOLOv8

Pip install the ultralytics package including all?requirements?in a?Python>=3.7?environment with?PyTorch>=1.7.

pip install ultralytics

YOLOv8可以通過yolo命令直接在命令行界面(CLI)中使用:

yolo predict model=yolov8n.pt source='https://ultralytics.com/images/bus.jpg'

yolo可以用于各種任務和模式,并接受額外的參數,即imgsz=640。有關示例,請參閱YOLOv8 CLI文檔。

YOLOv8 CLI文檔:https://docs.ultralytics.com/usage/cli/

YOLOv8也可以直接在Python環境中使用,并接受與上面CLI示例中相同的參數:

from ultralytics import YOLO
# Load a model
model = YOLO("yolov8n.yaml")  # build a new model from scratch
model = YOLO("yolov8n.pt")  # load a pretrained model (recommended for training)
# Use the model
model.train(data="coco128.yaml", epochs=3)  # train the model
metrics = model.val()  # evaluate model performance on the validation set
results = model("https://ultralytics.com/images/bus.jpg")  # predict on an image
success = model.export(format="onnx")  # export the model to ONNX format

模型自動從最新的Ultralytics版本下載。有關更多示例,請參閱YOLOv8 Python文檔。

??https://docs.ultralytics.com/usage/python/??

推理在筆記本電腦GTX1060 GPU上以接近105 FPS的速度運行。我們得到以下輸出:

YOLOv8 Nano 模型在幾幀中將貓混淆為狗。讓我們使用 YOLOv8 Extra Large 模型對同一視頻運行檢測并檢查輸出:

yolo task=detect mode=predict model=yolov8x.pt source='input/video_3.mp4' show=True

Extra Large模型在GTX1060 GPU上的平均運行速度為 17 FPS。

實例分割的推理結果

使用YOLOv8 實例分割模型運行推理同樣簡單。我們只需要更改上面命令中的task和model名稱。

yolo task=segment mode=predict model=yolov8x-seg.pt source='input/video_3.mp4' show=True

因為實例分割與對象檢測相結合,所以這次的平均 FPS 約為 13。

分割圖在輸出中看起來非常干凈。即使貓在最后幾幀中躲在方塊下,模型也能夠檢測并分割它。

圖像分類推理結果

最后,由于YOLOv8已經提供了預訓練的分類模型,讓我們使用該yolov8x-cls模型對同一視頻進行分類推理。這是存儲庫提供的最大分類模型。

yolo task=classify mode=predict model=yolov8x-cls.pt source='input/video_3.mp4' show=True

默認情況下,視頻使用模型預測的前5個類進行注釋。在沒有任何后處理的情況下,注釋直接匹配ImageNet類名。

?案例

快速檢測缺陷并提供重要的安全功能?

計算機視覺可以取代生產線上容易出錯的手動零件組裝和質量檢查。在車內,計算機視覺可以為重要的安全功能提供動力,如分心的駕駛員監控、檢測車道偏離、識別其他車輛和行人以及讀取交通信號。收集用于訓練的圖像和視頻數據。將從車輛和生產線攝像頭收集的視頻和圖像轉換為數據,以建立您的計算機視覺模型。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/64196.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/64196.shtml
英文地址,請注明出處:http://en.pswp.cn/web/64196.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Docker Container 可觀測性最佳實踐

Docker Container 介紹 Docker Container&#xff08; Docker 容器&#xff09;是一種輕量級、可移植的、自給自足的軟件運行環境&#xff0c;它在 Docker 引擎的宿主機上運行。容器在許多方面類似于虛擬機&#xff0c;但它們更輕量&#xff0c;因為它們不需要模擬整個操作系統…

氣相色譜-質譜聯用分析方法中的常用部件,分流平板更換

分流平板&#xff0c;是氣相色譜-質譜聯用分析方法中的一個常用部件&#xff0c;它可以實現氣相色譜柱流與MS檢測器流的分離和分流。常見的氣質聯用儀分流平板有很多種&#xff0c;如單層T型分流平板、雙層T型分流平板、螺旋分流平板等等。 操作視頻http://www.spcctech.com/v…

易基因: BS+ChIP-seq揭示DNA甲基化調控非編碼RNA(VIM-AS1)抑制腫瘤侵襲性|Exp Mol Med

大家好&#xff0c;這里是專注表觀組學十余年&#xff0c;領跑多組學科研服務的易基因。 肝細胞癌&#xff08;hepatocellular carcinoma&#xff0c;HCC&#xff09;早期復發仍然是一個具有挑戰性的領域&#xff0c;其中涉及的機制尚未完全被理解。盡管微血管侵犯&#xff08…

鴻蒙系統文件管理基礎服務的設計背景和設計目標

有一定經驗的開發者通常對文件管理相關的api應用或者底層邏輯都比較熟悉&#xff0c;但是關于文件管理服務的設計背景和設計目標可能了解得不那么清楚&#xff0c;本文旨在分享文件管理服務的設計背景及目標&#xff0c;方便廣大開發者更好地理解鴻蒙系統文件管理服務。 1 鴻蒙…

如何配置 Java 環境變量:設置 JAVA_HOME 和 PATH

目錄 一、什么是 Java 環境變量&#xff1f; 二、配置 Java 環境變量 1. 下載并安裝 JDK 2. 配置 JAVA_HOME Windows 系統 Linux / macOS 系統 3. 配置 PATH Windows 系統 Linux / macOS 系統 4. 驗證配置 三、常見問題與解決方案 1. 無法識別 java 或 javac 命令 …

Doris 數據庫外部表-JDBC 外表,Oracle to Doris

簡介 提供了 Doris 通過數據庫訪問的標準接口 (JDBC) 來訪問外部表&#xff0c;外部表省去了繁瑣的數據導入工作&#xff0c;讓 Doris 可以具有了訪問各式數據庫的能力&#xff0c;并借助 Doris 本身的 OLAP 的能力來解決外部表的數據分析問題&#xff1a; 支持各種數據源接入…

分布式 IO 模塊助力沖壓機械臂產線實現智能控制

在當今制造業蓬勃發展的浪潮中&#xff0c;沖壓機械臂產線的智能化控制已然成為提升生產效率、保障產品質量以及增強企業競爭力的關鍵所在。而分布式 IO 模塊的應用&#xff0c;正如同為這條產線注入了一股強大的智能動力&#xff0c;開啟了全新的高效生產篇章。 傳統挑戰 沖壓…

CSS系列(37)-- Overscroll Behavior詳解

前端技術探索系列&#xff1a;CSS Overscroll Behavior詳解 &#x1f4f1; 致讀者&#xff1a;探索滾動交互的藝術 &#x1f44b; 前端開發者們&#xff0c; 今天我們將深入探討 CSS Overscroll Behavior&#xff0c;這個強大的滾動行為控制特性。 基礎概念 &#x1f680; …

深度學習中的并行策略概述:4 Tensor Parallelism

深度學習中的并行策略概述&#xff1a;4 Tensor Parallelism 使用 PyTorch 實現 Tensor Parallelism 。首先定義了一個簡單的模型 SimpleModel&#xff0c;它包含兩個全連接層。然后&#xff0c;本文使用 torch.distributed.device_mesh 初始化了一個設備網格&#xff0c;這代…

企業銷售人員培訓系統|Java|SSM|VUE| 前后端分離

【技術棧】 1??&#xff1a;架構: B/S、MVC 2??&#xff1a;系統環境&#xff1a;Windowsh/Mac 3??&#xff1a;開發環境&#xff1a;IDEA、JDK1.8、Maven、Mysql5.7 4??&#xff1a;技術棧&#xff1a;Java、Mysql、SSM、Mybatis-Plus、VUE、jquery,html 5??數據庫…

vue 本地自測iframe通訊

使用 postMessage API 來實現跨窗口&#xff08;跨域&#xff09;的消息傳遞。postMessage 允許你安全地發送消息到其他窗口&#xff0c;包括嵌套的 iframe&#xff0c;而不需要擔心同源策略的問題。 發送消息&#xff08;父應用&#xff09; 1. 父應用&#xff1a;發送消息給…

Linux:code:network:devinet_sysctl_forward;IN_DEV_FORWARD

文章目錄 簡介sysctl 設置使用,arp_process間接使用IN_DEV_RX_REDIRECTSdev_disable_lro簡介 最近在看Linux里的forwarding的功能。順便在這里總結一下。有些詳細代碼邏輯,如果可以記錄一下,會好一點。 sysctl 設置 這個函數在查看的時候需要注意的問題:變量名起的有點簡…

自然語言處理與知識圖譜的融合與應用

目錄 前言1. 知識圖譜與自然語言處理的關系1.1 知識圖譜的定義與特點1.2 自然語言處理的核心任務1.3 二者的互補性 2. NLP在知識圖譜構建中的應用2.1 信息抽取2.1.1 實體識別2.1.2 關系抽取2.1.3 屬性抽取 2.2 知識融合2.3 知識推理 3. NLP與知識圖譜融合的實際應用3.1 智能問答…

PHP 數組

PHP 數組 PHP 是一種流行的服務器端編程語言&#xff0c;它提供了強大的數組處理能力。PHP 數組是一種數據結構&#xff0c;用于存儲相同類型或不同類型的多個值。在 PHP 中&#xff0c;數組可以分為一維數組、二維數組和多維數組。本文將詳細介紹 PHP 數組的各種操作&#xf…

CSS(三)盒子模型

目錄 Content Padding Border Margin 盒子模型計算方式 使用 box-sizing 屬性控制盒子模型的計算 所有的HTML元素都可以看作像下圖這樣一個矩形盒子&#xff1a; 這個模型包括了四個區域&#xff1a;content&#xff08;內容區域&#xff09;、padding&#xff08;內邊距…

基于NodeMCU的物聯網窗簾控制系統設計

最終效果 基于NodeMCU的物聯網窗簾控制系統設計 項目介紹 該項目是“物聯網實驗室監測控制系統設計&#xff08;仿智能家居&#xff09;”項目中的“家電控制設計”中的“窗簾控制”子項目&#xff0c;最前者還包括“物聯網設計”、“環境監測設計”、“門禁系統設計計”和“小…

有沒有免費提取音頻的軟件?音頻編輯軟件介紹!

出于工作和生活娛樂等原因&#xff0c;有時候我們需要把音頻單獨提取出來&#xff08;比如歌曲伴奏、人聲清唱等、樂器獨奏等&#xff09;。要提取音頻必須借助音頻處理軟件&#xff0c;那么有沒有免費提取音頻的軟件呢&#xff1f;下面我們將為大家介紹幾款免費軟件&#xff0…

WPF自定義窗口 輸入驗證不生效

WPF自定義窗口 輸入驗證不生效 WPF ValidationRule 不生效 WPF ValidationRule 不生效 解決方案&#xff1a;在WindowStyle的Template中添加AdornerDecorator標簽。 <Style x:Key"WindowStyle1" TargetType"{x:Type Window}"><Setter Property&…

【保姆式】python調用api通過機器人發送文件到飛書指定群聊

當前飛書webhook機器人還不支持發送文件類型的群消息&#xff0c;它目前僅支持文本&#xff0c;富文本&#xff0c;卡片等文字類型的數據。 我們可以申請創建一個機器人應用來實現群發送文件消息。 創建飛書應用 創建飛書應用、配置權限、添加機器人 來到飛書開發者后臺 創建…

MySQL-存儲過程(頭歌數據庫實驗題)

&#xff08;學校數據庫課程的頭歌平臺實驗題&#xff0c;根據自己理解編寫&#xff0c;希望對正在學的人有啟發作用和借鑒幫助&#xff0c;不喜勿噴&#xff0c;有錯請聯系改正&#xff09; 實驗 存儲過程&#xff1a;輸入1 任務描述&#xff1a; 本關任務&#xff1a;編寫…