在线观看www成人影院-在线观看www日本免费网站-在线观看www视频-在线观看操-欧美18在线-欧美1级

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

一文徹底搞懂YOLOv8(網(wǎng)絡(luò)結(jié)構(gòu)+代碼+實(shí)操)

jt_rfid5 ? 來(lái)源:新機(jī)器視覺 ? 2023-06-19 16:55 ? 次閱讀


	
								

本文概述了YOLOv8算法的核心特性及改進(jìn)點(diǎn),詳細(xì)介紹了網(wǎng)絡(luò)結(jié)構(gòu)、Loss計(jì)算、數(shù)據(jù)增強(qiáng)手段、訓(xùn)練策略、模型推理,對(duì)網(wǎng)絡(luò)結(jié)構(gòu)進(jìn)行了詳盡的分析,最后給出實(shí)操步驟。

0.引言

Section Name

Yolo系列對(duì)比:

e0bada28-0cf6-11ee-962d-dac502259ad0.png

1.概述

Section Name

YOLOv8 算法的核心特性和改動(dòng)可以歸結(jié)為如下:

提供了一個(gè)全新的 SOTA 模型,包括 P5 640 和 P6 1280 分辨率的目標(biāo)檢測(cè)網(wǎng)絡(luò)和基于 YOLACT 的實(shí)例分割模型。和 YOLOv5 一樣,基于縮放系數(shù)也提供了 N/S/M/L/X 尺度的不同大小模型,用于滿足不同場(chǎng)景需求

01

Backbone

骨干網(wǎng)絡(luò)和 Neck 部分可能參考了 YOLOv7 ELAN 設(shè)計(jì)思想,將 YOLOv5 的 C3 結(jié)構(gòu)換成了梯度流更豐富的 C2f 結(jié)構(gòu),并對(duì)不同尺度模型調(diào)整了不同的通道數(shù)。

屬于對(duì)模型結(jié)構(gòu)精心微調(diào),不再是無(wú)腦一套參數(shù)應(yīng)用所有模型,大幅提升了模型性能。不過這個(gè) C2f 模塊中存在 Split 等操作對(duì)特定硬件部署沒有之前那么友好了

02

Head

Head部分較yolov5而言有兩大改進(jìn):1)換成了目前主流的解耦頭結(jié)構(gòu)(Decoupled-Head),將分類和檢測(cè)頭分離 2)同時(shí)也從 Anchor-Based 換成了 Anchor-Free

03

Loss

1) YOLOv8拋棄了以往的IOU匹配或者單邊比例的分配方式,而是使用了Task-Aligned Assigner正負(fù)樣本匹配方式。2)并引入了 Distribution Focal Loss(DFL)

04

Train

訓(xùn)練的數(shù)據(jù)增強(qiáng)部分引入了 YOLOX 中的最后 10 epoch 關(guān)閉 Mosiac 增強(qiáng)的操作,可以有效地提升精度

從上面可以看出,YOLOv8 主要參考了最近提出的諸如 YOLOX、YOLOv6、YOLOv7 和 PPYOLOE 等算法的相關(guān)設(shè)計(jì),本身的創(chuàng)新點(diǎn)不多,偏向工程實(shí)踐,主推的還是 ultralytics 這個(gè)框架本身。

下面將按照模型結(jié)構(gòu)設(shè)計(jì)、Loss 計(jì)算、訓(xùn)練數(shù)據(jù)增強(qiáng)、訓(xùn)練策略和模型推理過程共 5 個(gè)部分詳細(xì)介紹 YOLOv8 目標(biāo)檢測(cè)的各種改進(jìn),實(shí)例分割部分暫時(shí)不進(jìn)行描述。

2.模型結(jié)構(gòu)

Section Name

如下圖, 左側(cè)為 YOLOv5-s,右側(cè)為 YOLOv8-s。
在暫時(shí)不考慮 Head 情況下,對(duì)比 YOLOv5 和 YOLOv8 的 yaml 配置文件可以發(fā)現(xiàn)改動(dòng)較小。

e0cfc8de-0cf6-11ee-962d-dac502259ad0.png

e0ddf7f6-0cf6-11ee-962d-dac502259ad0.jpg

01

Backbone和Neck的具體變化

a)第一個(gè)卷積層的 kernel 從 6x6 變成了 3x3
b)所有的 C3 模塊換成 C2f,結(jié)構(gòu)如下所示,可以發(fā)現(xiàn)多了更多的跳層連接和額外的 Split 操作

e0ed3fb8-0cf6-11ee-962d-dac502259ad0.png

c)去掉了 Neck 模塊中的 2 個(gè)卷積連接層

d) Backbone 中 C2f 的 block 數(shù)從 3-6-9-3 改成了 3-6-6-3

e) 查看 N/S/M/L/X 等不同大小模型,可以發(fā)現(xiàn) N/S 和 L/X 兩組模型只是改了縮放系數(shù),但是 S/M/L 等骨干網(wǎng)絡(luò)的通道數(shù)設(shè)置不一樣,沒有遵循同一套縮放系數(shù)。如此設(shè)計(jì)的原因應(yīng)該是同一套縮放系數(shù)下的通道設(shè)置不是最優(yōu)設(shè)計(jì),YOLOv7 網(wǎng)絡(luò)設(shè)計(jì)時(shí)也沒有遵循一套縮放系數(shù)作用于所有模型

02

Head的具體變化

從原先的耦合頭變成了解耦頭,并且從 YOLOv5 的 Anchor-Based 變成了 Anchor-Free。

e0ff914a-0cf6-11ee-962d-dac502259ad0.png

從上圖可以看出,不再有之前的 objectness 分支,只有解耦的分類和回歸分支,并且其回歸分支使用了 Distribution Focal Loss 中提出的積分形式表示法。

3.Loss 計(jì)算

Section Name

Loss 計(jì)算過程包括 2 個(gè)部分:正負(fù)樣本分配策略和 Loss 計(jì)算。

01

正負(fù)樣本分配策略

現(xiàn)代目標(biāo)檢測(cè)器大部分都會(huì)在正負(fù)樣本分配策略上面做文章,典型的如 YOLOX 的 simOTA、TOOD 的 TaskAlignedAssigner 和 RTMDet 的 DynamicSoftLabelAssigner,這類 Assigner 大都是動(dòng)態(tài)分配策略,而 YOLOv5 采用的依然是靜態(tài)分配策略。考慮到動(dòng)態(tài)分配策略的優(yōu)異性,YOLOv8 算法中則直接引用了 TOOD 的 TaskAlignedAssigner。

TaskAlignedAssigner 的匹配策略簡(jiǎn)單總結(jié)為:根據(jù)分類與回歸的分?jǐn)?shù)加權(quán)的分?jǐn)?shù)選擇正樣本。

02

Loss計(jì)算

Loss 計(jì)算包括 2 個(gè)分支:分類和回歸分支,沒有了之前的 objectness 分支。

分類分支依然采用 BCE Loss。回歸分支需要和 Distribution Focal Loss 中提出的積分形式表示法綁定,因此使用了 Distribution Focal Loss, 同時(shí)還使用了 CIoU Loss。3 個(gè) Loss 采用一定權(quán)重比例加權(quán)即可。

4.訓(xùn)練數(shù)據(jù)增強(qiáng)

Section Name

數(shù)據(jù)增強(qiáng)方面和 YOLOv5 差距不大,只不過引入了 YOLOX 中提出的最后 10 個(gè) epoch 關(guān)閉 Mosaic 的操作。假設(shè)訓(xùn)練 epoch 是 500,其示意圖如下所示:

e10ddebc-0cf6-11ee-962d-dac502259ad0.png

考慮到不同模型應(yīng)該采用的數(shù)據(jù)增強(qiáng)強(qiáng)度不一樣,因此對(duì)于不同大小模型,有部分超參會(huì)進(jìn)行修改,典型的如大模型會(huì)開啟 MixUp 和 CopyPaste。數(shù)據(jù)增強(qiáng)后典型效果如下所示:

e1173c0a-0cf6-11ee-962d-dac502259ad0.png

5.訓(xùn)練策略

Section Name

YOLOv8 的訓(xùn)練策略和 YOLOv5 沒有啥區(qū)別,最大區(qū)別就是模型的訓(xùn)練總 epoch 數(shù)從 300 提升到了 500,這也導(dǎo)致訓(xùn)練時(shí)間急劇增加。以 YOLOv8-S 為例,其訓(xùn)練策略匯總?cè)缦拢?/span>

e12dd5aa-0cf6-11ee-962d-dac502259ad0.png

6.模型推理過程

Section Name

YOLOv8 的推理過程和 YOLOv5 幾乎一樣,唯一差別在于前面需要對(duì) Distribution Focal Loss 中的積分表示 bbox 形式進(jìn)行解碼,變成常規(guī)的 4 維度 bbox,后續(xù)計(jì)算過程就和 YOLOv5 一樣了。

e144a032-0cf6-11ee-962d-dac502259ad0.png

其推理和后處理過程為:

(1) bbox 積分形式轉(zhuǎn)換為 4d bbox 格式

對(duì) Head 輸出的 bbox 分支進(jìn)行轉(zhuǎn)換,利用 Softmax 和 Conv 計(jì)算將積分形式轉(zhuǎn)換為 4 維 bbox 格式

(2) 維度變換

YOLOv8 輸出特征圖尺度為 80x80、40x40 和 20x20 的三個(gè)特征圖。Head 部分輸出分類和回歸共 6 個(gè)尺度的特征圖。將 3 個(gè)不同尺度的類別預(yù)測(cè)分支、bbox 預(yù)測(cè)分支進(jìn)行拼接,并進(jìn)行維度變換。為了后續(xù)方便處理,會(huì)將原先的通道維度置換到最后,類別預(yù)測(cè)分支 和 bbox 預(yù)測(cè)分支 shape 分別為 (b, 80x80+40x40+20x20, 80)=(b,8400,80),(b,8400,4)。

(3) 解碼還原到原圖尺度

分類預(yù)測(cè)分支進(jìn)行 Sigmoid 計(jì)算,而 bbox 預(yù)測(cè)分支需要進(jìn)行解碼,還原為真實(shí)的原圖解碼后 xyxy 格式。

(4) 閾值過濾

遍歷 batch 中的每張圖,采用 score_thr 進(jìn)行閾值過濾。在這過程中還需要考慮 multi_label 和 nms_pre,確保過濾后的檢測(cè)框數(shù)目不會(huì)多于 nms_pre。

(5) 還原到原圖尺度和 nms

基于前處理過程,將剩下的檢測(cè)框還原到網(wǎng)絡(luò)輸出前的原圖尺度,然后進(jìn)行 nms 即可。最終輸出的檢測(cè)框不能多于 max_per_img。

有一個(gè)特別注意的點(diǎn):YOLOv5 中采用的 Batch shape 推理策略,在 YOLOv8 推理中暫時(shí)沒有開啟,不清楚后面是否會(huì)開啟,在 MMYOLO 中快速測(cè)試了下,如果開啟 Batch shape 會(huì)漲大概 0.1~0.2

7.網(wǎng)絡(luò)模型解析

Section Name

01

卷積神經(jīng)單元(model.py)

ultralytics/nn/modules.py文件中定義了yolov8網(wǎng)絡(luò)中的卷積神經(jīng)單元。

01

autopad

功能:返回pad的大小,使得padding后輸出張量的大小不變。

參數(shù):

k: 卷積核(kernel)的大小。類型可能是一個(gè)int也可能是一個(gè)序列。

p: 填充(padding)的大小。默認(rèn)為None。

d: 擴(kuò)張率(dilation rate)的大小, 默認(rèn)為1 。普通卷積的擴(kuò)張率為1,空洞卷積的擴(kuò)張率大于1。

假設(shè)k為原始卷積核大小,d為卷積擴(kuò)張率(dilation rate),加入空洞之后的實(shí)際卷積核尺寸與原始卷積核尺寸之間的關(guān)系:k =d(k-1)+1

e1518cd4-0cf6-11ee-962d-dac502259ad0.png

def autopad(k, p=None, d=1):  # kernel(卷積核), padding(填充), dilation(擴(kuò)張)
    # 返回pad的大小,使得padding后輸出張量的shape不變
    if d > 1: # 如果采用擴(kuò)張卷積,則計(jì)算擴(kuò)張后實(shí)際的kernel大小
        k = d * (k - 1) + 1 if isinstance(k, int) else [d * (x - 1) + 1 for x in k]  # 
    if p is None:
        p = k // 2 if isinstance(k, int) else [x // 2 for x in k]  # 自動(dòng)pad
returnp

02

Conv

  • 功能:標(biāo)準(zhǔn)的卷積

  • 參數(shù):輸入通道數(shù)(c1), 輸出通道數(shù)(c2), 卷積核大小(k,默認(rèn)是1), 步長(zhǎng)(s,默認(rèn)是1), 填充(p,默認(rèn)為None), 組(g, 默認(rèn)為1), 擴(kuò)張率(d,默認(rèn)為1), 是否采用激活函數(shù)(act,默認(rèn)為True, 且采用SiLU為激活函數(shù))

e1627288-0cf6-11ee-962d-dac502259ad0.png

激活函數(shù)采用的是SiLU。

e16ff6c4-0cf6-11ee-962d-dac502259ad0.png

class Conv(nn.Module):
    # 標(biāo)準(zhǔn)的卷積 參數(shù)(輸入通道數(shù), 輸出通道數(shù), 卷積核大小, 步長(zhǎng), 填充, 組, 擴(kuò)張, 激活函數(shù))
    default_act = nn.SiLU()  # 默認(rèn)的激活函數(shù)


    def __init__(self, c1, c2, k=1, s=1, p=None, g=1, d=1, act=True):
        super().__init__()
        self.conv = nn.Conv2d(c1, c2, k, s, autopad(k, p, d), groups=g, dilation=d, bias=False) # 2維卷積,其中采用了自動(dòng)填充函數(shù)。
        self.bn = nn.BatchNorm2d(c2) # 使得每一個(gè)batch的特征圖均滿足均值為0,方差為1的分布規(guī)律
        # 如果act=True 則采用默認(rèn)的激活函數(shù)SiLU;如果act的類型是nn.Module,則采用傳入的act; 否則不采取任何動(dòng)作 (nn.Identity函數(shù)相當(dāng)于f(x)=x,只用做占位,返回原始的輸入)。
        self.act = self.default_act if act is True else act if isinstance(act, nn.Module) else nn.Identity() 


    def forward(self, x):  # 前向傳播
        return self.act(self.bn(self.conv(x))) # 采用BatchNorm
    def forward_fuse(self, x): #  用于Model類的fuse函數(shù)融合 Conv + BN 加速推理,一般用于測(cè)試/驗(yàn)證階段
returnself.act(self.conv(x))#不采用BatchNorm

03

DWConv

深度可分離卷積,繼承自Conv。g=math.gcd(c1, c2)分組數(shù)是輸入通道(c1)和輸出通道(c2)的最大公約數(shù)。(因?yàn)榉纸M卷積時(shí),分組數(shù)需要能夠整除輸入通道和輸出通道)

class DWConv(Conv):
    # 深度可分離卷積
    def __init__(self, c1, c2, k=1, s=1, d=1, act=True):  # ch_in, ch_out, kernel, stride, dilation, activation
super().__init__(c1,c2,k,s,g=math.gcd(c1,c2),d=d,act=act)

04

DWConvTranspose2d

帶有深度分離的轉(zhuǎn)置卷積,繼承自nn.ConvTranspose2d
groups=math.gcd(c1, c2)分組數(shù)是輸入通道(c1)和輸出通道(c2)的最大公約數(shù)。(因?yàn)榉纸M卷積時(shí),分組數(shù)需要能夠整除輸入通道和輸出通道)

class DWConvTranspose2d(nn.ConvTranspose2d):
    # Depth-wise transpose convolution
    def __init__(self, c1, c2, k=1, s=1, p1=0, p2=0):  # 輸入通道, 輸出通道, 卷積核大小, 步長(zhǎng), padding, padding_out
super().__init__(c1,c2,k,s,p1,p2,groups=math.gcd(c1,c2))

05

ConvTranspose

和Conv類似,只是把Conv2d換成了ConvTranspose2d

class ConvTranspose(nn.Module):
    # Convolution transpose 2d layer
    default_act = nn.SiLU()  # default activation


    def __init__(self, c1, c2, k=2, s=2, p=0, bn=True, act=True):
        super().__init__()
        self.conv_transpose = nn.ConvTranspose2d(c1, c2, k, s, p, bias=not bn)
        self.bn = nn.BatchNorm2d(c2) if bn else nn.Identity()
        self.act = self.default_act if act is True else act if isinstance(act, nn.Module) else nn.Identity()


    def forward(self, x):
returnself.act(self.bn(self.conv_transpose(x)))

06

DFL(Distribution Focal Loss)

本篇文章(https://ieeexplore.ieee.org/document/9792391)提出了GFL(了Generalized Focal Loss)。GFL具體又包括Quality Focal Loss(QFL)和Distribution Focal Loss(DFL),其中QFL用于優(yōu)化分類和質(zhì)量估計(jì)聯(lián)合分支,DFL用于優(yōu)化邊框分支。

class DFL(nn.Module):
    # Integral module of Distribution Focal Loss (DFL) proposed in Generalized Focal Loss 
    def __init__(self, c1=16):
        super().__init__()
        self.conv = nn.Conv2d(c1, 1, 1, bias=False).requires_grad_(False)
        x = torch.arange(c1, dtype=torch.float)
        self.conv.weight.data[:] = nn.Parameter(x.view(1, c1, 1, 1))
        self.c1 = c1


    def forward(self, x):
        b, c, a = x.shape  # batch, channels, anchors
        return self.conv(x.view(b, 4, self.c1, a).transpose(2, 1).softmax(1)).view(b, 4, a)
        # return self.conv(x.view(b, self.c1, 4, a).softmax(1)).view(b, 4, a)

07

TransformerLayer

e17e7ce4-0cf6-11ee-962d-dac502259ad0.png

e1942c9c-0cf6-11ee-962d-dac502259ad0.png

我們可以發(fā)現(xiàn)它和yolo中的TransformerLayer部分只是少了層規(guī)范化(LayerNorm),以及在Feed-Forward Networks 中只采用了兩個(gè)不帶偏置線性層,且沒有采用激活函數(shù)。

e1a4da9c-0cf6-11ee-962d-dac502259ad0.png

TransformerLayer代碼實(shí)現(xiàn)如下:

class TransformerLayer(nn.Module):
    # Transformer layer  (LayerNorm layers removed for better performance)
    def __init__(self, c, num_heads): # c: 詞特征向量的大小  num_heads 檢測(cè)頭的個(gè)數(shù)。
        super().__init__()
        self.q = nn.Linear(c, c, bias=False)# 計(jì)算query, in_features=out_features=c
        self.k = nn.Linear(c, c, bias=False)# 計(jì)算key
        self.v = nn.Linear(c, c, bias=False)# 計(jì)算value
        self.ma = nn.MultiheadAttention(embed_dim=c, num_heads=num_heads) # 多頭注意力機(jī)制
        self.fc1 = nn.Linear(c, c, bias=False)
        self.fc2 = nn.Linear(c, c, bias=False)


    def forward(self, x):
        x = self.ma(self.q(x), self.k(x), self.v(x))[0] + x  # 多頭注意力機(jī)制+殘差連接
        x = self.fc2(self.fc1(x)) + x  # 兩個(gè)全連接層+ 殘差連接
returnx

如果輸入是x,x的大小是(s,n,c) 。其中n是batch size, s是源序列長(zhǎng)度,c是詞特征向量的大小(embed_dim)。

然后x分別通過3個(gè)Linear層 (線性層的結(jié)構(gòu)相同,但是可學(xué)習(xí)參數(shù)不同)計(jì)算得到鍵k、查詢q、值v。因?yàn)榫€性層的輸入特征數(shù)和輸出特征數(shù)均等于c, 所以k,q,v的大小也是(s,n,c)。

接著,把k、q、v作為參數(shù)輸入到多頭注意力ma中,返回兩個(gè)結(jié)果attn_output(注意力機(jī)制的輸出)和attn_output_weights(注意力機(jī)制的權(quán)重)。在這里,我們只需要注意力機(jī)制的輸出就可以,因此,我們?nèi)?a target="_blank">索引0 self.ma(self.q(x), self.k(x), self.v(x))[0],它的大小是(s,n,c)。+x 表示殘差連接,不改變x的形狀。

self.fc2(self.fc1(x)) 表示經(jīng)過兩個(gè)全連接層,輸出大小是(s,n,c)。+x 表示殘差連接,不改變x的形狀。因此最終輸出的形狀大小和輸入的形狀一樣。

08

Transformer Block

TransformerBlock是把若干個(gè)TransformerLayer串聯(lián)起來(lái)。

對(duì)于圖像數(shù)據(jù)而言,輸入數(shù)據(jù)形狀是 [batch, channel, height, width],變換成 [height × width, batch, channel]。height × width把圖像中各個(gè)像素點(diǎn)看作一個(gè)單詞,其對(duì)應(yīng)通道的信息連在一起就是詞向量。channel就是詞向量的長(zhǎng)度。

e1af09a4-0cf6-11ee-962d-dac502259ad0.png

TransformerBlock的實(shí)現(xiàn)代碼如下:

class TransformerBlock(nn.Module):
    def __init__(self, c1, c2, num_heads, num_layers):
        super().__init__()
        self.conv = None
        if c1 != c2:
            self.conv = Conv(c1, c2)
        self.linear = nn.Linear(c2, c2)  # learnable position embedding
        self.tr = nn.Sequential(*(TransformerLayer(c2, num_heads) for _ in range(num_layers)))
        self.c2 = c2


    def forward(self, x):  # x:(b,c1,w0,h0)
        if self.conv is not None:
            x = self.conv(x) # x:(b,c2,w,h)
        b, _, w, h = x.shape
        p = x.flatten(2).permute(2, 0, 1) # flatten后:(b,c2,w*h)  p: (w*h,b,c2)  
        # linear后: (w*h,b,c2)   tr后: (w*h,b,c2)   permute后: (b,c2,w*h)  reshape后:(b,c2,w,h)
returnself.tr(p+self.linear(p)).permute(1,2,0).reshape(b,self.c2,w,h)

1)輸入的x大小為(b,c1,w,h)。其中b為batch size, c1 是輸入通道數(shù)大小, w 和h 分別表示圖像的寬和高。

2)經(jīng)過Conv層:Conv層中的2d卷積,卷積核大小是1x1, 步長(zhǎng)為1,無(wú)填充,擴(kuò)張率為1。因此不改變w和h, 只改變輸出通道數(shù),形狀變?yōu)?b,c2,w,h)。Conv層中的BN和SiLU不改變形狀大小。輸出的x大小為(b,c2,w,h)

3)對(duì)x進(jìn)行變換得到p: x.flatten(2)后,大小變?yōu)?(b,c2,w*h) permute(2, 0, 1)后,p的大小為(w*h,b,c2)

4) 將p輸入到線性層后,因?yàn)榫€性層的輸入特征數(shù)和輸出特征數(shù)相等,因此輸出的大小為(w*h,b,c2)。

+p 進(jìn)行殘差連接后,大小不變,仍為(w*h,b,c2)

5) 然后將上一步的結(jié)果輸入到num_layers個(gè)TransformerLayer中。w*h 相當(dāng)于序列長(zhǎng)度,b是批量的大小,c2相當(dāng)于詞嵌入特征長(zhǎng)度。每個(gè)TransformerLayer的輸入和輸出的大小不變。經(jīng)過若干個(gè)TransformerLayer后,大小是(w*h,b,c2)。

6)permute(1, 2, 0)后: 形狀變?yōu)?b,c2,w*h) reshape(b, self.c2, w, h)后:(b,c2,w,h)

09

Bottleneck

先使用 3x3 卷積降維,剔除冗余信息;再使用 3×3 卷積升維。

e1bb8aa8-0cf6-11ee-962d-dac502259ad0.png

class Bottleneck(nn.Module):
    # Standard bottleneck
    def __init__(self, c1, c2, shortcut=True, g=1, k=(3, 3), e=0.5):  # ch_in, ch_out, shortcut, groups, kernels, expand
        super().__init__()
        c_ = int(c2 * e)  # hidden channels
        self.cv1 = Conv(c1, c_, k[0], 1)  # 輸入通道: c1, 輸出通道:c_ , 卷積核:3x3, 步長(zhǎng)1
        self.cv2 = Conv(c_, c2, k[1], 1, g=g) # 輸入通道:c_ , 輸出通道c2, 卷積核:3x3, 步長(zhǎng)1
        self.add = shortcut and c1 == c2  # 當(dāng)傳入的shortcut參數(shù)為true,且c1和c2相等時(shí),則使用殘差連接。


    def forward(self, x):
returnx+self.cv2(self.cv1(x))ifself.addelseself.cv2(self.cv1(x))

第一層卷積,輸入通道: c1, 輸出通道:c_ , 卷積核:3x3, 步長(zhǎng)1

第一層卷積,輸入通道: c_, 輸出通道:c2 , 卷積核:3x3, 步長(zhǎng)1

其中c _ = c2/2。當(dāng)c1和c2相等時(shí),采用殘差連接。

10

BottleneckCSP

詳細(xì)請(qǐng)參考CSPNet的論文和源碼。論文《CSPNet: A New Backbone that can Enhance Learning Capability of CNN》

源碼https://github.com/WongKinYiu/CrossStagePartialNetworks

e1cbdbb0-0cf6-11ee-962d-dac502259ad0.png

class BottleneckCSP(nn.Module):
    # CSP Bottleneck https://github.com/WongKinYiu/CrossStagePartialNetworks
    def __init__(self, c1, c2, n=1, shortcut=True, g=1, e=0.5):  # ch_in, ch_out, number, shortcut, groups, expansion
        super().__init__()  
        c_ = int(c2 * e)  # hidden channels
        # 輸出x的大小是(b,c1,w,h)
        self.cv1 = Conv(c1, c_, 1, 1) # cv1的大小為(b,c_,w,h)
        self.cv2 = nn.Conv2d(c1, c_, 1, 1, bias=False) # cv2的大小為(b,c_,w,h)
        self.cv3 = nn.Conv2d(c_, c_, 1, 1, bias=False) # m通過Conv2d,變成cv3,大小是(b,c_,w,h)
        self.cv4 = Conv(2 * c_, c2, 1, 1)
        self.bn = nn.BatchNorm2d(2 * c_)  # applied to cat(cv2, cv3)
        self.act = nn.SiLU()
        self.m = nn.Sequential(*(Bottleneck(c_, c_, shortcut, g, e=1.0) for _ in range(n)))  
        # cv1通過n個(gè)串聯(lián)的bottleneck,變成m,大小為(b,c_,w,h)


    def forward(self, x):
        y1 = self.cv3(self.m(self.cv1(x))) # (b,c_,w,h)
        y2 = self.cv2(x) # (b,c_,w,h)
        return self.cv4(self.act(self.bn(torch.cat((y1, y2), 1))))
        # cat后:(b,2*c_,w,h) 返回cv4: (b,c2,w,h)

1)輸出x的大小是(b,c1,w,h), 然后有兩條計(jì)算路徑分別計(jì)算得到y(tǒng)1和y2。

y1的計(jì)算路徑:先x通過cv1,大小變成(b,c_,w,h) 。cv1通過n個(gè)串聯(lián)的bottleneck,變成m,大小為(b,c_,w,h)。m通過cv3, 得到y(tǒng)1, 大小是(b,c_,w,h)

y2的計(jì)算路徑:x通過cv2得到y(tǒng)2,大小是(b,c_,w,h)

2)y1和y2在dim=1處連接, 大小是(b,2*c_,w,h), 然后再通過BN和SiLU,大小不變。

3)最終,通過cv4, 返回結(jié)果的大小是(b,c2,w,h)

11

C3

與 BottleneckCSP 類似,但少了 1 個(gè) Conv、1 個(gè) BN、1 個(gè) Act,運(yùn)算量更少。總共只有3次卷積(cv1,cv2,cv3)。

e1d82cda-0cf6-11ee-962d-dac502259ad0.png

class C3(nn.Module):
    # CSP Bottleneck with 3 convolutions
    def __init__(self, c1, c2, n=1, shortcut=True, g=1, e=0.5):  # ch_in, ch_out, number, shortcut, groups, expansion
        super().__init__()
        c_ = int(c2 * e)  # hidden channels
        self.cv1 = Conv(c1, c_, 1, 1)
        self.cv2 = Conv(c1, c_, 1, 1)
        self.cv3 = Conv(2 * c_, c2, 1)  # optional act=FReLU(c2)
        self.m = nn.Sequential(*(Bottleneck(c_, c_, shortcut, g, e=1.0) for _ in range(n)))


    def forward(self, x):
returnself.cv3(torch.cat((self.m(self.cv1(x)),self.cv2(x)),1))

12

C2

C2只有兩個(gè)卷積(cv1,cv2)的CSP Bottleneck。

e1e45dca-0cf6-11ee-962d-dac502259ad0.png

class C2(nn.Module):
    # CSP Bottleneck with 2 convolutions
    def __init__(self, c1, c2, n=1, shortcut=True, g=1, e=0.5):  # ch_in, ch_out, number, shortcut, groups, expansion
        super().__init__()
     # 假設(shè)輸入的x大小是(b,c1,w,h)
        self.c = int(c2 * e)  # hidden channels e=0.5,對(duì)輸出通道進(jìn)行平分。
        self.cv1 = Conv(c1, 2 * self.c, 1, 1) # cv1的大小是(b,c2,w,h)
        self.cv2 = Conv(2 * self.c, c2, 1)  # optional act=FReLU(c2)
        # self.attention = ChannelAttention(2 * self.c)  # or SpatialAttention()   #此處可以使用空間注意力或者跨通道的注意力機(jī)制。
        self.m = nn.Sequential(*(Bottleneck(self.c, self.c, shortcut, g, k=((3, 3), (3, 3)), e=1.0) for _ in range(n)))  # a通過n個(gè)串聯(lián)的Bottleneck后的到m,m的大小是(b,c,w,h)


    def forward(self, x):
        a, b = self.cv1(x).split((self.c, self.c), 1)# 對(duì)cv進(jìn)行在維度1進(jìn)行平分,a和b的大小都是(b,c,w,h)
returnself.cv2(torch.cat((self.m(a),b),1))#把m和b在維度1進(jìn)行cat后,大小是(b,c2,w,h)。最終通過cv2,大小是(b,c2,w,h)

1)輸出x的大小是(b,c1,w,h), 通過Conv層,得到cv1, cv1的大小是(b,c2,w,h)

2) 然后再dim=1的維度上對(duì)cv1進(jìn)行分割,a和b的大小都是(b,c2/2,w,h)。

3) a通過n個(gè)串聯(lián)的Bottleneck后的到m,m的大小是(b,c,w,h)

4) 把m和b在維度1進(jìn)行cat后,大小是(b,c2,w,h)。最終m通過cv2,輸出的大小是(b,c2,w,h)

13

C2f

C2f與C2相比,每個(gè)Bottleneck的輸出都會(huì)被Concat到一起。

e1f13784-0cf6-11ee-962d-dac502259ad0.png

class C2f(nn.Module):
    # CSP Bottleneck with 2 convolutions
    def __init__(self, c1, c2, n=1, shortcut=False, g=1, e=0.5):  # ch_in, ch_out, number, shortcut, groups, expansion
        super().__init__()
        # 假設(shè)輸入的x大小是(b,c1,w,h)
        self.c = int(c2 * e)  # hidden channels
        self.cv1 = Conv(c1, 2 * self.c, 1, 1) # cv1的大小是(b,c2,w,h)
        self.cv2 = Conv((2 + n) * self.c, c2, 1)  # optional act=FReLU(c2)
        self.m = nn.ModuleList(Bottleneck(self.c, self.c, shortcut, g, k=((3, 3), (3, 3)), e=1.0) for _ in range(n)) # n個(gè)Bottleneck組成的ModuleList,可以把m看做是一個(gè)可迭代對(duì)象


    def forward(self, x):
        y = list(self.cv1(x).split((self.c, self.c), 1))
        # cv1的大小是(b,c2,w,h),對(duì)cv1在維度1等分成兩份(假設(shè)分別是a和b),a和b的大小均是(b,c2/2,w,h)。此時(shí)y=[a,b]。
        y.extend(m(y[-1]) for m in self.m)
        # 然后對(duì)列表y中的最后一個(gè)張量b輸入到ModuleList中的第1個(gè)bottleneck里,得到c,c的大小是(b,c2/2,w,h)。然后把c也加入y中。此時(shí)y=[a,b,c]
        # 重復(fù)上述操作n次(因?yàn)槭莕個(gè)bottleneck),最終得到的y列表中一共有n+2個(gè)元素。
        return self.cv2(torch.cat(y, 1)) 
        # 對(duì)列表y中的張量在維度1進(jìn)行連接,得到的張量大小是(b,(n+2)*c2/2,w,h)。
#最終通過cv2,輸出張量的大小是(b,c2,w,h)

1)cv1的大小是(b,c2,w,h),對(duì)cv1在維度1等分成兩份(假設(shè)分別是a和b),a和b的大小均是(b,c2/2,w,h)。此時(shí)y=[a,b]。

2)然后對(duì)列表y中的最后一個(gè)張量b輸入到ModuleList中的第1個(gè)bottleneck里,得到c,c的大小是(b,c2/2,w,h)。然后把c也加入y中。此時(shí)y=[a,b,c]。

3)上述步驟重復(fù)上述操作n次(因?yàn)槭莕個(gè)bottleneck),最終得到的y列表中一共有n+2個(gè)元素。

4)對(duì)列表y中的張量在維度1進(jìn)行連接,得到的張量大小是(b,(n+2)*c2/2,w,h)。

5)最終通過cv2,輸出張量的大小是(b,c2,w,h)

14

ChannelAttention

通道注意力模型: 通道維度不變,壓縮空間維度。該模塊關(guān)注輸入圖片中有意義的信息。

e1fc8080-0cf6-11ee-962d-dac502259ad0.png

class ChannelAttention(nn.Module):
    # Channel-attention module https://github.com/open-mmlab/mmdetection/tree/v3.0.0rc1/configs/rtmdet
    def __init__(self, channels: int) -> None:
        super().__init__()
        self.pool = nn.AdaptiveAvgPool2d(1) # 自適應(yīng)平均池化后,大小為(b,c,1,1)
        self.fc = nn.Conv2d(channels, channels, 1, 1, 0, bias=True)
        self.act = nn.Sigmoid()


    def forward(self, x: torch.Tensor) -> torch.Tensor:
returnx*self.act(self.fc(self.pool(x)))

1)假設(shè)輸入的數(shù)據(jù)大小是(b,c,w,h)
2)通過自適應(yīng)平均池化使得輸出的大小變?yōu)?/span>(b,c,1,1)
3)通過2d卷積和sigmod激活函數(shù)后,大小是(b,c,1,1)
4)將上一步輸出的結(jié)果和輸入的數(shù)據(jù)相乘,輸出數(shù)據(jù)大小是(b,c,w,h)

15

SpatialAttention

空間注意力模塊:空間維度不變,壓縮通道維度。該模塊關(guān)注的是目標(biāo)的位置信息。

e20ef274-0cf6-11ee-962d-dac502259ad0.png

class SpatialAttention(nn.Module):
    # Spatial-attention module
    def __init__(self, kernel_size=7):
        super().__init__()
        assert kernel_size in (3, 7), 'kernel size must be 3 or 7'  # kernel size 的大小必須是3或者7
        padding = 3 if kernel_size == 7 else 1  # 當(dāng)kernel_size是7時(shí),padding=3; 當(dāng)kernel_size是3時(shí),padding=1
        self.cv1 = nn.Conv2d(2, 1, kernel_size, padding=padding, bias=False)
        self.act = nn.Sigmoid()


    def forward(self, x):
returnx*self.act(self.cv1(torch.cat([torch.mean(x,1,keepdim=True),torch.max(x,1,keepdim=True)[0]],1)))

1) 假設(shè)輸入的數(shù)據(jù)x是(b,c,w,h),并進(jìn)行兩路處理。

2)其中一路在通道維度上進(jìn)行求平均值,得到的大小是(b,1,w,h);另外一路也在通道維度上進(jìn)行求最大值,得到的大小是(b,1,w,h)。

3) 然后對(duì)上述步驟的兩路輸出進(jìn)行連接,輸出的大小是(b,2,w,h)

4)經(jīng)過一個(gè)二維卷積網(wǎng)絡(luò),把輸出通道變?yōu)?,輸出大小是(b,1,w,h)

4)將上一步輸出的結(jié)果和輸入的數(shù)據(jù)x相乘,最終輸出數(shù)據(jù)大小是(b,c,w,h)。

16

CBAM

CBAM就是把ChannelAttention和SpatialAttention串聯(lián)在一起。

e21a05a6-0cf6-11ee-962d-dac502259ad0.png

class CBAM(nn.Module):
    # Convolutional Block Attention Module
    def __init__(self, c1, kernel_size=7):  # ch_in, kernels
        super().__init__()
        self.channel_attention = ChannelAttention(c1)
        self.spatial_attention = SpatialAttention(kernel_size)


    def forward(self, x):
        return self.spatial_attention(self.channel_attention(x))

17

C1

總共只有3次卷積(cv1,cv2,cv3)的Bottleneck。

e223a80e-0cf6-11ee-962d-dac502259ad0.png

class C1(nn.Module):
    # CSP Bottleneck with 1 convolution
    def __init__(self, c1, c2, n=1):  # ch_in, ch_out, number
        super().__init__()
        self.cv1 = Conv(c1, c2, 1, 1)
        self.m = nn.Sequential(*(Conv(c2, c2, 3) for _ in range(n)))


    def forward(self, x):
        y = self.cv1(x)
returnself.m(y)+y

1)假設(shè)輸入的數(shù)據(jù)是(b,c1,w,h)
2) 首先通過一個(gè)Conv塊,得到y, 大小為(b,c2,w,h)
3) 然后讓y通過n個(gè)3x3的Conv塊,得到m
4) 最后讓m和y相加。

18

C3x

C3x 繼承自C3, 變換是Bottleneck中的卷積核大小變?yōu)?1,3)和(3,3)

class C3x(C3):
    # C3 module with cross-convolutions
    def __init__(self, c1, c2, n=1, shortcut=True, g=1, e=0.5):
        super().__init__(c1, c2, n, shortcut, g, e)
        self.c_ = int(c2 * e)
self.m=nn.Sequential(*(Bottleneck(self.c_,self.c_,shortcut,g,k=((1,3),(3,1)),e=1)for_inrange(n)))

19

C3TR

C3TR繼承自C3, n 個(gè) Bottleneck 更換為 1 個(gè) TransformerBlock。

e2300464-0cf6-11ee-962d-dac502259ad0.png

class C3TR(C3):
    # C3 module with TransformerBlock()
    def __init__(self, c1, c2, n=1, shortcut=True, g=1, e=0.5):
        super().__init__(c1, c2, n, shortcut, g, e)
        c_ = int(c2 * e)
        self.m = TransformerBlock(c_, c_, 4, n)# num_heads=4, num_layers=n

20

SPP

《Spatial Pyramid Pooling in Deep Convolutional Networks for Visual Recognition》

e23d2d10-0cf6-11ee-962d-dac502259ad0.png

class SPP(nn.Module):
    # Spatial Pyramid Pooling (SPP) layer https://arxiv.org/abs/1406.4729
    def __init__(self, c1, c2, k=(5, 9, 13)):
        super().__init__()
        c_ = c1 // 2  # hidden channels
        self.cv1 = Conv(c1, c_, 1, 1)
        self.cv2 = Conv(c_ * (len(k) + 1), c2, 1, 1)
        self.m = nn.ModuleList([nn.MaxPool2d(kernel_size=x, stride=1, padding=x // 2) for x in k])


    def forward(self, x):
        x = self.cv1(x)
        with warnings.catch_warnings():
            warnings.simplefilter('ignore')  # suppress torch 1.9.0 max_pool2d() warning
returnself.cv2(torch.cat([x]+[m(x)forminself.m],1))

21

SPPF

這個(gè)是YOLOv5作者Glenn Jocher基于SPP提出的,速度較SPP快很多,所以叫SPP-Fast。

三個(gè)MaxPool 串行連接,kerner size都是5*5。效果等價(jià)于SPP,但是運(yùn)算量從原來(lái)的5^2 + 9^2 + 13^2 = 275減少到3* 5^2 =75

e24af576-0cf6-11ee-962d-dac502259ad0.png

池化尺寸等價(jià)于SPP中kernel size分別為5 * 59 * 913 * 13的池化層并行連接。

class SPPF(nn.Module):
    # Spatial Pyramid Pooling - Fast (SPPF) layer for YOLOv5 by Glenn Jocher
    def __init__(self, c1, c2, k=5):  # equivalent to SPP(k=(5, 9, 13))
        super().__init__()
        c_ = c1 // 2  # hidden channels
        self.cv1 = Conv(c1, c_, 1, 1)
        self.cv2 = Conv(c_ * 4, c2, 1, 1)
        self.m = nn.MaxPool2d(kernel_size=k, stride=1, padding=k // 2)


    def forward(self, x):
        x = self.cv1(x)
        with warnings.catch_warnings():
            warnings.simplefilter('ignore')  # suppress torch 1.9.0 max_pool2d() warning
            y1 = self.m(x)
            y2 = self.m(y1)
returnself.cv2(torch.cat((x,y1,y2,self.m(y2)),1))

22

Focus

Focus模塊在v5中是圖片進(jìn)入backbone前,對(duì)圖片進(jìn)行切片操作,具體操作是在一張圖片中每隔一個(gè)像素拿到一個(gè)值,類似于鄰近下采樣,這樣就拿到了四張圖片,四張圖片互補(bǔ),長(zhǎng)的差不多,但是沒有信息丟失,這樣一來(lái),將W、H信息就集中到了通道空間,輸入通道擴(kuò)充了4倍,即拼接起來(lái)的圖片相對(duì)于原先的RGB三通道模式變成了12個(gè)通道,最后將得到的新圖片再經(jīng)過卷積操作,最終得到了沒有信息丟失情況下的二倍下采樣特征圖。

例如:原始的640 × 640 × 3的圖像輸入Focus結(jié)構(gòu),采用切片操作,先變成320 × 320 × 12的特征圖,再經(jīng)過一次卷積操作,最終變成320 × 320 × 32的特征圖。切片操作如下

e260c450-0cf6-11ee-962d-dac502259ad0.png

e26dce16-0cf6-11ee-962d-dac502259ad0.png

class Focus(nn.Module):
    # Focus wh information into c-space
    def __init__(self, c1, c2, k=1, s=1, p=None, g=1, act=True):  # ch_in, ch_out, kernel, stride, padding, groups
        super().__init__()
        self.conv = Conv(c1 * 4, c2, k, s, p, g, act=act)
        # self.contract = Contract(gain=2)


    def forward(self, x):  # x(b,c,w,h) -> y(b,4c,w/2,h/2)
        return self.conv(torch.cat((x[..., ::2, ::2], x[..., 1::2, ::2], x[..., ::2, 1::2], x[..., 1::2, 1::2]), 1))
#returnself.conv(self.contract(x))

23

GhostConv

Ghost卷積來(lái)自華為諾亞方舟實(shí)驗(yàn)室,《GhostNet: More Features from Cheap Operations》發(fā)表于2020年的CVPR上。提供了一個(gè)全新的Ghost模塊,旨在通過廉價(jià)操作生成更多的特征圖。

原理如下圖所示:

e277df6e-0cf6-11ee-962d-dac502259ad0.png

Ghost Module分為兩步操作來(lái)獲得與普通卷積一樣數(shù)量的特征圖:

Step1:少量卷積(比如正常用128個(gè)卷積核,這里就用64個(gè),從而減少一半的計(jì)算量);

Step2:cheap operations,用圖中的Φ表示,Φ是諸如33、55的卷積,并且是逐個(gè)特征圖的進(jìn)行卷積(Depth-wise convolutional,深度卷積)。

e294c7d2-0cf6-11ee-962d-dac502259ad0.png

class GhostConv(nn.Module):
    # Ghost Convolution https://github.com/huawei-noah/ghostnet
    def __init__(self, c1, c2, k=1, s=1, g=1, act=True):  # ch_in, ch_out, kernel, stride, groups
        super().__init__()
        c_ = c2 // 2  # hidden channels
        self.cv1 = Conv(c1, c_, k, s, None, g, act=act)
        self.cv2 = Conv(c_, c_, 5, 1, None, c_, act=act)  # 分組數(shù)=c_=通道數(shù),進(jìn)行point-wise的深度分離卷積


    def forward(self, x):
        y = self.cv1(x)
returntorch.cat((y,self.cv2(y)),1)

24

GhostBottleneck

e2a2c116-0cf6-11ee-962d-dac502259ad0.png

class GhostBottleneck(nn.Module):
    # Ghost Bottleneck https://github.com/huawei-noah/ghostnet
    def __init__(self, c1, c2, k=3, s=1):  # ch_in, ch_out, kernel, stride
        super().__init__()
        c_ = c2 // 2
        self.conv = nn.Sequential(
            GhostConv(c1, c_, 1, 1),  # 卷積核的大小是1*1,屬于point-wise的深度可分離卷積
            DWConv(c_, c_, k, s, act=False) if s == 2 else nn.Identity(),  # 輸入通道數(shù)和輸出通道數(shù)相等,屬于depth-wise的深度可分離卷積
            GhostConv(c_, c2, 1, 1, act=False))  #point-wise的深度可分離卷積,且不采用偏置項(xiàng)。
        self.shortcut = nn.Sequential(DWConv(c1, c1, k, s, act=False), Conv(c1, c2, 1, 1,
                                                                            act=False)) if s == 2 else nn.Identity()


    def forward(self, x):
returnself.conv(x)+self.shortcut(x)

25

C3Ghost

C3Ghost繼承自C3, Bottleneck更換為GhostBottleneck

e2af0886-0cf6-11ee-962d-dac502259ad0.png

class C3Ghost(C3):
    # C3 module with GhostBottleneck()
    def __init__(self, c1, c2, n=1, shortcut=True, g=1, e=0.5):
        super().__init__(c1, c2, n, shortcut, g, e)
        c_ = int(c2 * e)  # hidden channels
self.m=nn.Sequential(*(GhostBottleneck(c_,c_)for_inrange(n)))

26

Concat

當(dāng)dimension=1時(shí),將多張相同尺寸的圖像在通道維度維度上進(jìn)行拼接。

class Concat(nn.Module):
    # Concatenate a list of tensors along dimension
    def __init__(self, dimension=1):
        super().__init__()
        self.d = dimension


    def forward(self, x):
returntorch.cat(x,self.d)

8.Yolov8實(shí)操

Section Name

01

下載工程并安裝ultralytics

git clone https://github.com/ultralytics/ultralytics
cd ultralytics
pipinstall-e.

02

數(shù)據(jù)集準(zhǔn)備

數(shù)據(jù)集制作參考:YOLO格式數(shù)據(jù)集制作

# 訓(xùn)練/驗(yàn)證/測(cè)試 數(shù)據(jù)
train: /data/zyw/project/dataset/finalTrafficLightDataset/train/images
val: /data/zyw/project/dataset/finalTrafficLightDataset/val/images
test: /data/zyw/project/dataset/finalTrafficLightDataset/WPIDataset/images
# 類別個(gè)數(shù)
nc: 12


# 類別名稱
names:["greenCircle","yellowCircle","redCircle","greenLeft","yellowLeft","redLeft","greenRight","yellowRight","redRight","greenForward","yellowForward","redForward"]

03

模型的訓(xùn)練/驗(yàn)證/預(yù)測(cè)/驗(yàn)證

01

使用CLI

如果你想對(duì)模型進(jìn)行訓(xùn)練、驗(yàn)證或運(yùn)行推斷,并且不需要對(duì)代碼進(jìn)行任何修改,那么使用YOLO命令行接口是最簡(jiǎn)單的入門方法。

YOLO命令行界面(command line interface, CLI) 方便在各種任務(wù)和版本上訓(xùn)練、驗(yàn)證或推斷模型。CLI不需要定制或代碼,可以使用yolo命令從終端運(yùn)行所有任務(wù)。

(1)語(yǔ)法

yolo task=detect    mode=train    model=yolov8n.yaml      args...
          classify       predict        yolov8n-cls.yaml  args...
          segment        val            yolov8n-seg.yaml  args...
exportyolov8n.ptformat=onnxargs...

(2)訓(xùn)練示例

yolotask=detectmode=trainmodel=yolov8n.ptdata=coco128.yamldevice=0

(3)多GPU訓(xùn)練示例

yolotask=detectmode=trainmodel=yolov8n.ptdata=coco128.yamldevice='0,1,2,3'

(4)重寫默認(rèn)的配置參數(shù)

# 語(yǔ)法
yolo task= ... mode= ...  arg=val
# 例子:進(jìn)行10個(gè)epoch的檢測(cè)訓(xùn)練,learning_rate為0.01
yolotask=detectmode=trainepochs=10lr0=0.01

(5)重寫默認(rèn)配置文件

# 可以在當(dāng)前工作目錄下創(chuàng)建一個(gè)默認(rèn)配置文件的副本
yolo task=init
# 然后可以使用cfg=name.yaml命令來(lái)傳遞新的配置文件
yolocfg=default.yaml

02

使用python

允許用戶在Python項(xiàng)目中輕松使用YOLOv8。它提供了加載和運(yùn)行模型以及處理模型輸出的函數(shù)。該界面設(shè)計(jì)易于使用,以便用戶可以在他們的項(xiàng)目中快速實(shí)現(xiàn)目標(biāo)檢測(cè)。

(1)訓(xùn)練

方式1:從預(yù)訓(xùn)練模型開始訓(xùn)練

from ultralytics import YOLO


model = YOLO("yolov8n.pt") # pass any model type
model.train(epochs=5)

方式2:從頭開始訓(xùn)練

from ultralytics import YOLO


model = YOLO("yolov8n.yaml")
model.train(data="coco128.yaml",epochs=5)

(2)驗(yàn)證

訓(xùn)練后驗(yàn)證:

from ultralytics import YOLO


  model = YOLO("yolov8n.yaml")
  model.train(data="coco128.yaml", epochs=5)
model.val()#It'llautomaticallyevaluatethedatayoutrained.

單獨(dú)驗(yàn)證:

from ultralytics import YOLO


  model = YOLO("model.pt")
  # 如果不設(shè)置數(shù)據(jù)的話,就使用model.pt中的data yaml文件
  model.val()
  # 或者直接設(shè)置需要驗(yàn)證的數(shù)據(jù)。
model.val(data="coco128.yaml")

(3)預(yù)測(cè)

從源文件預(yù)測(cè):

from ultralytics import YOLO


model = YOLO("model.pt")
model.predict(source="0") # accepts all formats - img/folder/vid.*(mp4/format). 0 for webcam
model.predict(source="folder",show=True)#Displaypreds.Acceptsallyolopredictarguments

返回結(jié)果:

from ultralytics import YOLO


model = YOLO("model.pt")
outputs = model.predict(source="0", return_outputs=True) # treat predict as a Python generator
for output in outputs:
  # each output here is a dict.
  # for detection
  print(output["det"])  # np.ndarray, (N, 6), xyxy, score, cls
  # for segmentation
  print(output["det"])  # np.ndarray, (N, 6), xyxy, score, cls
  print(output["segment"])  # List[np.ndarray] * N, bounding coordinates of masks
  # for classify
print(output["prob"])#np.ndarray,(num_class,),clsprob

04

數(shù)據(jù)擴(kuò)充

YOLO模型的增強(qiáng)設(shè)置是指應(yīng)用于訓(xùn)練數(shù)據(jù)的各種變換和修改,以增加數(shù)據(jù)集的多樣性和大小。這些設(shè)置會(huì)影響模型的性能、速度和精度。一些常見的YOLO增強(qiáng)設(shè)置包括應(yīng)用的轉(zhuǎn)換類型和強(qiáng)度(例如隨機(jī)翻轉(zhuǎn)、旋轉(zhuǎn)、裁剪、顏色變化),應(yīng)用每個(gè)轉(zhuǎn)換的概率,以及是否存在其他功能,如掩碼或每個(gè)框多個(gè)標(biāo)簽。其他可能影響數(shù)據(jù)擴(kuò)充過程的因素包括原始數(shù)據(jù)集的大小和組成,以及模型正在用于的特定任務(wù)。重要的是要仔細(xì)調(diào)整和實(shí)驗(yàn)這些設(shè)置,以確保增強(qiáng)后的數(shù)據(jù)集具有足夠的多樣性和代表性,以訓(xùn)練高性能的模型。

e2bcf018-0cf6-11ee-962d-dac502259ad0.png

05

日志、檢查點(diǎn)、繪圖與文件管理

在訓(xùn)練YOLO模型時(shí),日志記錄、檢查點(diǎn)、繪圖和文件管理是重要的考慮因素。

日志記錄:在訓(xùn)練期間記錄各種指標(biāo)和統(tǒng)計(jì)數(shù)據(jù)通常有助于跟蹤模型的進(jìn)展和診斷任何可能出現(xiàn)的問題。這可以通過使用日志庫(kù)(如TensorBoard)或?qū)⑷罩鞠懭胛募?lái)實(shí)現(xiàn)。

檢查點(diǎn):在訓(xùn)練期間,定期保存模型的檢查點(diǎn)是一個(gè)很好的做法。如果訓(xùn)練過程被中斷,或者你想嘗試不同的訓(xùn)練配置,這允許你從之前的點(diǎn)恢復(fù)訓(xùn)練。繪圖:可視化模型的性能和訓(xùn)練過程,有助于理解模型的行為方式和識(shí)別潛在問題。這可以使用matplotlib等繪圖庫(kù)完成,也可以使用TensorBoard等日志庫(kù)來(lái)繪圖。

文件管理:管理訓(xùn)練過程中生成的各種文件,例如模型檢查點(diǎn)、日志文件和繪圖,可能具有挑戰(zhàn)性。有一個(gè)清晰和有組織的文件結(jié)構(gòu)是很重要的,以便跟蹤這些文件,并使其易于根據(jù)需要訪問和分析它們。

有效的日志記錄、檢查點(diǎn)、繪圖和文件管理可以幫助您跟蹤模型的進(jìn)度,并使其更容易調(diào)試和優(yōu)化訓(xùn)練過程。

e2c675ac-0cf6-11ee-962d-dac502259ad0.png


			

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • 模型
    +關(guān)注

    關(guān)注

    1

    文章

    3315

    瀏覽量

    49233
  • 代碼
    +關(guān)注

    關(guān)注

    30

    文章

    4828

    瀏覽量

    69064
  • 網(wǎng)絡(luò)結(jié)構(gòu)

    關(guān)注

    0

    文章

    48

    瀏覽量

    11205

原文標(biāo)題:【光電智造】一文徹底搞懂YOLOv8(網(wǎng)絡(luò)結(jié)構(gòu)+代碼+實(shí)操)

文章出處:【微信號(hào):今日光電,微信公眾號(hào):今日光電】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

收藏 人收藏

    評(píng)論

    相關(guān)推薦

    YOLOv5網(wǎng)絡(luò)結(jié)構(gòu)解析

    1、YOLOv5 網(wǎng)絡(luò)結(jié)構(gòu)解析  YOLOv5針對(duì)不同大小(n, s, m, l, x)的網(wǎng)絡(luò)整體架構(gòu)都是樣的,只不過會(huì)在每個(gè)子模塊中采用
    發(fā)表于 10-31 16:30

    使用YOLOv8做目標(biāo)檢測(cè)和實(shí)例分割的演示

    YOLOv8是來(lái)自Ultralytics的最新的基于YOLO的對(duì)象檢測(cè)模型系列,提供最先進(jìn)的性能。
    的頭像 發(fā)表于 02-06 10:11 ?7653次閱讀

    YOLOv8自定義數(shù)據(jù)集訓(xùn)練到模型部署推理簡(jiǎn)析

    如果你只是想使用而不是開發(fā),強(qiáng)烈推薦通過pip安裝方式獲取YOLOv8包!YOLOv8安裝命令行
    的頭像 發(fā)表于 03-24 09:27 ?4759次閱讀

    TensorRT 8.6 C++開發(fā)環(huán)境配置與YOLOv8實(shí)例分割推理演示

    對(duì)YOLOv8實(shí)例分割TensorRT 推理代碼已經(jīng)完成C++類封裝,三行代碼即可實(shí)現(xiàn)YOLOv8對(duì)象檢測(cè)與實(shí)例分割模型推理,不需要改任何代碼
    的頭像 發(fā)表于 04-25 10:49 ?6042次閱讀
    TensorRT 8.6 C++開發(fā)環(huán)境配置與<b class='flag-5'>YOLOv8</b>實(shí)例分割推理演示

    在AI愛克斯開發(fā)板上用OpenVINO?加速YOLOv8目標(biāo)檢測(cè)模型

    《在 AI 愛克斯開發(fā)板上用 OpenVINO 加速 YOLOv8 分類模型》介紹了在 AI 愛克斯開發(fā)板上使用 OpenVINO 開發(fā)套件部署并測(cè)評(píng) YOLOv8 的分類模型,本文將介紹在 AI 愛克斯開發(fā)板上使用 OpenVINO 加速
    的頭像 發(fā)表于 05-12 09:08 ?1384次閱讀
    在AI愛克斯開發(fā)板上用OpenVINO?加速<b class='flag-5'>YOLOv8</b>目標(biāo)檢測(cè)模型

    YOLOv8版本升級(jí)支持小目標(biāo)檢測(cè)與高分辨率圖像輸入

    YOLOv8版本最近版本又更新了,除了支持姿態(tài)評(píng)估以外,通過模型結(jié)構(gòu)的修改還支持了小目標(biāo)檢測(cè)與高分辨率圖像檢測(cè)。原始的YOLOv8模型結(jié)構(gòu)如下。
    的頭像 發(fā)表于 05-16 11:14 ?1.3w次閱讀
    <b class='flag-5'>YOLOv8</b>版本升級(jí)支持小目標(biāo)檢測(cè)與高分辨率圖像輸入

    AI愛克斯開發(fā)板上使用OpenVINO加速YOLOv8目標(biāo)檢測(cè)模型

    《在AI愛克斯開發(fā)板上用OpenVINO加速YOLOv8分類模型》介紹了在AI愛克斯開發(fā)板上使用OpenVINO 開發(fā)套件部署并測(cè)評(píng)YOLOv8的分類模型,本文將介紹在AI愛克斯開發(fā)板上使用OpenVINO加速YOLOv8目標(biāo)檢
    的頭像 發(fā)表于 05-26 11:03 ?1335次閱讀
    AI愛克斯開發(fā)板上使用OpenVINO加速<b class='flag-5'>YOLOv8</b>目標(biāo)檢測(cè)模型

    徹底搞懂YOLOv8網(wǎng)絡(luò)結(jié)構(gòu)+代碼+實(shí)

    從上面可以看出,YOLOv8 主要參考了最近提出的諸如 YOLOX、YOLOv6、YOLOv7 和 PPYOLOE 等算法的相關(guān)設(shè)計(jì),本身的創(chuàng)新點(diǎn)不多,偏向工程實(shí)踐,主推的還是 ultralytics 這個(gè)框架本身。
    的頭像 發(fā)表于 06-15 17:15 ?1.2w次閱讀
    <b class='flag-5'>一</b><b class='flag-5'>文</b><b class='flag-5'>徹底</b><b class='flag-5'>搞懂</b><b class='flag-5'>YOLOv8</b>【<b class='flag-5'>網(wǎng)絡(luò)結(jié)構(gòu)</b>+<b class='flag-5'>代碼</b>+<b class='flag-5'>實(shí)</b><b class='flag-5'>操</b>】

    教你如何用兩行代碼搞定YOLOv8各種模型推理

    大家好,YOLOv8 框架本身提供的API函數(shù)是可以兩行代碼實(shí)現(xiàn) YOLOv8 模型推理,這次我把這段代碼封裝成了個(gè)類,只有40行
    的頭像 發(fā)表于 06-18 11:50 ?3165次閱讀
    教你如何用兩行<b class='flag-5'>代碼</b>搞定<b class='flag-5'>YOLOv8</b>各種模型推理

    目標(biāo)檢測(cè)算法再升級(jí)!YOLOv8保姆級(jí)教程鍵體驗(yàn)

    YOLO作為種基于圖像全局信息進(jìn)行預(yù)測(cè)的目標(biāo)檢測(cè)系統(tǒng),始終保持著極高的迭代更新率,從YOLOv5到YOLOv8,本次升級(jí)主要包括結(jié)構(gòu)算法、命令行界面、PythonAPI等。具體到
    的頭像 發(fā)表于 02-28 11:16 ?2828次閱讀
    目標(biāo)檢測(cè)算法再升級(jí)!<b class='flag-5'>YOLOv8</b>保姆級(jí)教程<b class='flag-5'>一</b>鍵體驗(yàn)

    解鎖YOLOv8修改+注意力模塊訓(xùn)練與部署流程

    很多人也想跟修改YOLOv5源碼樣的方式去修改YOLOv8的源碼,但是在github上面卻發(fā)現(xiàn)找到的YOLOv8項(xiàng)目下面TAG分支是空的
    的頭像 發(fā)表于 08-11 14:14 ?4559次閱讀
    解鎖<b class='flag-5'>YOLOv8</b>修改+注意力模塊訓(xùn)練與部署流程

    如何修改YOLOv8的源碼

    很多人也想跟修改YOLOv5源碼樣的方式去修改YOLOv8的源碼,但是在github上面卻發(fā)現(xiàn)找到的YOLOv8項(xiàng)目下面TAG分支是空的,然后就直接從master/main下面把源碼
    的頭像 發(fā)表于 09-04 10:02 ?2132次閱讀
    如何修改<b class='flag-5'>YOLOv8</b>的源碼

    YOLOv8實(shí)現(xiàn)任意目錄下命令行訓(xùn)練

    當(dāng)你使用YOLOv8命令行訓(xùn)練模型的時(shí)候,如果當(dāng)前執(zhí)行的目錄下沒有相關(guān)的預(yù)訓(xùn)練模型文件,YOLOv8就會(huì)自動(dòng)下載模型權(quán)重文件。這個(gè)是個(gè)正常操作,但是你還會(huì)發(fā)現(xiàn),當(dāng)你在參數(shù)model中指定已有
    的頭像 發(fā)表于 09-04 10:50 ?1191次閱讀
    <b class='flag-5'>YOLOv8</b>實(shí)現(xiàn)任意目錄下命令行訓(xùn)練

    基于YOLOv8的自定義醫(yī)學(xué)圖像分割

    YOLOv8種令人驚嘆的分割模型;它易于訓(xùn)練、測(cè)試和部署。在本教程中,我們將學(xué)習(xí)如何在自定義數(shù)據(jù)集上使用YOLOv8。但在此之前,我想告訴你為什么在存在其他優(yōu)秀的分割模型時(shí)應(yīng)該使用YOLO
    的頭像 發(fā)表于 12-20 10:51 ?848次閱讀
    基于<b class='flag-5'>YOLOv8</b>的自定義醫(yī)學(xué)圖像分割

    基于OpenCV DNN實(shí)現(xiàn)YOLOv8的模型部署與推理演示

    基于OpenCV DNN實(shí)現(xiàn)YOLOv8推理的好處就是代碼就可以部署在Windows10系統(tǒng)、烏班圖系統(tǒng)、Jetson的Jetpack系統(tǒng)
    的頭像 發(fā)表于 03-01 15:52 ?1870次閱讀
    基于OpenCV DNN實(shí)現(xiàn)<b class='flag-5'>YOLOv8</b>的模型部署與推理演示
    主站蜘蛛池模板: 狠狠干福利视频 | 四虎在线观看一区二区 | 欧美一级视频在线观看 | 午夜国产在线观看 | 精品久久久久久久久久 | 国产免费亚洲 | 国产成都一二三四区 | ccc36色影 | 色婷婷丁香六月 | 女人的天堂网站 | 5151四虎永久在线精品免费 | 国产玖玖在线 | 久久九九色 | 好大好紧好爽好湿润视频 | 日本黄色免费在线 | 一级免费视频 | 人人看人人玩 | 欧美美女一区二区三区 | 深夜视频免费在线观看 | 91激情网| 天天干天天拍天天射天天添天天爱 | 日本a级三级三级三级久久 日本a级影院 | 操美女在线看 | 涩涩涩综合在线亚洲第一 | 天堂资源在线官网资源 | 国产成人综合日韩精品婷婷九月 | 亚洲欧美日韩在线精品2021 | 亚洲色五月 | 失禁h啪肉尿出来高h受 | bt天堂新版中文在线地址 | 免费看成年视频网页 | 福利视频免费观看 | 亚洲性色成人 | 午夜免费观看福利片一区二区三区 | 亚欧免费视频一区二区三区 | 手机在线观看视频你懂的 | 丁香婷婷九月 | 五月天在线播放 | 日韩欧美一卡二区 | 国产男女怕怕怕免费视频 | 亚洲高清美女一区二区三区 |