修改YOLOv5的模型結構第三彈

  • 🍨 本文為🔗365天深度學習訓練營 中的學習記錄博客
  • 🍖 原作者:K同學啊 | 接輔導、項目定制
  • 🚀 文章來源:K同學的學習圈子

    文章目錄

    • 任務
      • 任務拆解
    • 開始修改
      • C2模塊
      • 修改yolo.py
      • 修改模型配置文件
    • 模型訓練

上次已經做了一個對YOLOv5的魔改任務,這次繼續魔改。使用的素材還是之前說到的C2模塊,但這次會對模型進行范圍更大的修改

任務

將原模型修改為新模型
原模型如圖:
原模型
新模型如圖:
新模型

任務拆解

首先分析兩個模型之間的改動有哪些

  • 第4層的C3*2修改為了C2*2
  • 第6層的C3*3修改為了C3*1
  • 移除了第7層的卷積
  • 移除了第8層的C3*1

其中C2模塊是由C3模塊修改而來,在之前的博客中也提到過,這里貼下圖
C2模塊

開始修改

C2模塊

首先還是要先編寫一個C2模塊。打開models/common.py在class C3附近新建一個我們的C2模塊

class C3(nn.Module):# CSP Bottleneck with 3 convolutionsdef __init__(self, c1, c2, n=1, shortcut=True, g=1, e=0.5):  # ch_in, ch_out, number, shortcut, groups, expansionsuper().__init__()c_ = int(c2 * e)  # hidden channelsself.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):return self.cv3(torch.cat((self.m(self.cv1(x)), self.cv2(x)), 1))class C2(nn.Module):def __init__(self, c1, c2, n=1, shortcut=True, g=1, e=0.5):super().__init__()c_1 = c2 // 2c_2 = c2 - c_1self.cv1 = Conv(c1, c_2, 1, 1)self.cv2 = Conv(c1, c_1, 1, 1)self.m = nn.Sequential(*(Bottleneck(c_2, c_2, shortcut, g, e=1.0) for _ in range(n)))def forward(self, x):return torch.cat((self.m(self.cv1(x)), self.cv2(x)), 1)

修改yolo.py

修改yolo.py中函數parse_model中的代碼,使模型支持我們剛寫的C2模塊

def parse_model(d, ch):  # model_dict, input_channels(3)# Parse a YOLOv5 model.yaml dictionaryLOGGER.info(f"\n{'':>3}{'from':>18}{'n':>3}{'params':>10}  {'module':<40}{'arguments':<30}")anchors, nc, gd, gw, act = d['anchors'], d['nc'], d['depth_multiple'], d['width_multiple'], d.get('activation')if act:Conv.default_act = eval(act)  # redefine default activation, i.e. Conv.default_act = nn.SiLU()LOGGER.info(f"{colorstr('activation:')} {act}")  # printna = (len(anchors[0]) // 2) if isinstance(anchors, list) else anchors  # number of anchorsno = na * (nc + 5)  # number of outputs = anchors * (classes + 5)layers, save, c2 = [], [], ch[-1]  # layers, savelist, ch outfor i, (f, n, m, args) in enumerate(d['backbone'] + d['head']):  # from, number, module, argsm = eval(m) if isinstance(m, str) else m  # eval stringsfor j, a in enumerate(args):with contextlib.suppress(NameError):args[j] = eval(a) if isinstance(a, str) else a  # eval stringsn = n_ = max(round(n * gd), 1) if n > 1 else n  # depth gain# 在這個集合中增加了C2模塊if m in {Conv, GhostConv, Bottleneck, GhostBottleneck, SPP, SPPF, DWConv, MixConv2d, Focus, CrossConv,BottleneckCSP, C3, C2, C3TR, C3SPP, C3Ghost, nn.ConvTranspose2d, DWConvTranspose2d, C3x}: c1, c2 = ch[f], args[0]if c2 != no:  # if not outputc2 = make_divisible(c2 * gw, 8)args = [c1, c2, *args[1:]]# 這這個集合中也增加了C2模塊if m in {BottleneckCSP, C3, C2, C3TR, C3Ghost, C3x}: args.insert(2, n)  # number of repeatsn = 1elif m is nn.BatchNorm2d:args = [ch[f]]elif m is Concat:c2 = sum(ch[x] for x in f)# TODO: channel, gw, gdelif m in {Detect, Segment}:args.append([ch[x] for x in f])if isinstance(args[1], int):  # number of anchorsargs[1] = [list(range(args[1] * 2))] * len(f)if m is Segment:args[3] = make_divisible(args[3] * gw, 8)elif m is Contract:c2 = ch[f] * args[0] ** 2elif m is Expand:c2 = ch[f] // args[0] ** 2else:c2 = ch[f]m_ = nn.Sequential(*(m(*args) for _ in range(n))) if n > 1 else m(*args)  # modulet = str(m)[8:-2].replace('__main__.', '')  # module typenp = sum(x.numel() for x in m_.parameters())  # number paramsm_.i, m_.f, m_.type, m_.np = i, f, t, np  # attach index, 'from' index, type, number paramsLOGGER.info(f'{i:>3}{str(f):>18}{n_:>3}{np:10.0f}  {t:<40}{str(args):<30}')  # printsave.extend(x % i for x in ([f] if isinstance(f, int) else f) if x != -1)  # append to savelistlayers.append(m_)if i == 0:ch = []ch.append(c2)return nn.Sequential(*layers), sorted(save)

修改模型配置文件

參考models/yolov5s.yaml來修改模型的配置
對照著剛才識別到的改動來操作

  1. 第4層的C3*2修改為了C2*2
    將backbone下面的數組第4個元素中的C3修改為C2
# 舊[-1, 6, C3, [256]],
# 新[-1, 6, C2, [256]],
  1. 第6層的C3*3修改為了C3*1
    將backbone下面的數組第6個元素中的 number由9修改為3
# 舊[-1, 9, C3, [512]],
# 新[-1, 3, C3, [512]]
  1. 移除了第7層的卷積
  2. 移除了第8層的C3*1
    刪除backbone中第7個和第8個元素
   [-1, 1, Conv, [1024, 3, 2]],  # 7-P5/32[-1, 3, C3, [1024]],

修改到當前這一步,我以為就已經完成了,但是實際上只完成了一半。
通過對前面知識的回顧,Concat模塊會引用上層的模塊的輸出,體現在配置文件中,就是會引用數組中的下標,但是我們在數組中刪除了兩個元素,會使數組原本的索引失效。
通過上面的模型結構圖也可以發現,刪除兩層后,6層以后的下標都要減2。于是修改配置文件中的head下面的配置

# YOLOv5 v6.0 head
head:[[-1, 1, Conv, [512, 1, 1]],[-1, 1, nn.Upsample, [None, 2, 'nearest']],[[-1, 6], 1, Concat, [1]],  # 6 不用修改[-1, 3, C3, [512, False]],  # 13[-1, 1, Conv, [256, 1, 1]],[-1, 1, nn.Upsample, [None, 2, 'nearest']],[[-1, 4], 1, Concat, [1]],  # 4 不用修改[-1, 3, C3, [256, False]],  # 17 (P3/8-small)[-1, 1, Conv, [256, 3, 2]],[[-1, 14], 1, Concat, [1]],  # 原來的14現在是12了[-1, 3, C3, [512, False]],  # 20 (P4/16-medium)[-1, 1, Conv, [512, 3, 2]],[[-1, 10], 1, Concat, [1]],  # 原來的10現在是8了[-1, 3, C3, [1024, False]],  # 23 (P5/32-large)[[17, 20, 23], 1, Detect, [nc, anchors]],  # 原來的17,20,23對應現在的15,18,21]

如此改完后,我又一次認為已經完成了,但是跑了一下卻報錯了。如圖:
報錯圖
通過錯誤信息可以發現是特征圖的維度不一致導致的。于是回頭分析我們所有的改動,C2模塊天生就和C3模塊的輸入和輸出維度一樣,所有可以無縫替換、增加到模型中。另外之所以可以實現C3*n的效果,就是因為單個模塊的輸入和輸出也一樣。
所以問題不會出現在對C3->C2的改動。剩下的就是刪除了兩層中有一層是卷積。于是回頭看了一下刪除的卷積的,[-1, 1, Conv, [1024, 3, 2]],它的kernelsize是3,stride是2,這是一個會讓特征圖的尺寸縮小一半的卷積,由于我們刪除了它,后面的流程中特征圖的尺寸會和原來有所不同,最終導致錯誤。我們需要想辦法彌補這個差異。
在head的第一層中,使用了一個1x1的卷積,我們把它修改為kernelsize=3,stride=2的卷積。

# 前
head:[[-1, 1, Conv, [512, 1, 1]],
# 后
head:[[-1, 1, Conv, [512, 3, 2]],

最終模型配置文件被修改為

# YOLOv5 🚀 by Ultralytics, AGPL-3.0 license# Parameters
nc: 80  # number of classes
depth_multiple: 0.33  # model depth multiple
width_multiple: 0.50  # layer channel multiple
anchors:- [10,13, 16,30, 33,23]  # P3/8- [30,61, 62,45, 59,119]  # P4/16- [116,90, 156,198, 373,326]  # P5/32# YOLOv5 v6.0 backbone
backbone:# [from, number, module, args][[-1, 1, Conv, [64, 6, 2, 2]],  # 0-P1/2[-1, 1, Conv, [128, 3, 2]],  # 1-P2/4[-1, 3, C3, [128]],[-1, 1, Conv, [256, 3, 2]],  # 3-P3/8[-1, 6, C2, [256]],[-1, 1, Conv, [512, 3, 2]],  # 5-P4/16[-1, 3, C3, [512]],[-1, 1, SPPF, [1024, 5]],  # 7]# YOLOv5 v6.0 head
head:[[-1, 1, Conv, [512, 3, 2]],                        # 8 必須使用stride=2來彌補backbone中刪除的卷積,不然后面特征圖的尺寸對不上[-1, 1, nn.Upsample, [None, 2, 'nearest']],        # 9[[-1, 6], 1, Concat, [1]],  # cat backbone P4       10[-1, 3, C3, [512, False]],  #                       11[-1, 1, Conv, [256, 1, 1]], #                       12[-1, 1, nn.Upsample, [None, 2, 'nearest']], #       13[[-1, 4], 1, Concat, [1]],  # cat backbone P3       14[-1, 3, C3, [256, False]],  #  (P3/8-small)         15[-1, 1, Conv, [256, 3, 2]],                       # 16[[-1, 12], 1, Concat, [1]], # cat head P4           17[-1, 3, C3, [512, False]],  # (P4/16-medium)        18[-1, 1, Conv, [512, 3, 2]],                       # 19[[-1, 8], 1, Concat, [1]], # cat head P5            20[-1, 3, C3, [1024, False]], #  (P5/32-large)        21[[15, 18, 21], 1, Detect, [nc, anchors]],  # Detect(P3, P4, P5)]

模型訓練

所有的修改至此就完成了,使用train.py腳本訓練一下修改后的模型。結果如圖:

模型訓練結果圖

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

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

相關文章

【工具使用】Keil工具的使用——常用配置介紹

Keil調試具體教程學習 目錄 ???????Keil調試具體教程學習 常用功能總結 &#xff08;2&#xff09;目標設置&#xff08;Target&#xff09; ①設置晶振頻率 ②跨模塊優化選項 ③微庫選項 &#xff08;3&#xff09;輸出設置&#xff08;Output&#xff09; ①…

插入排序(形象類比)

最近在看riscv手冊的時候&#xff0c;里面有一段代碼是插入排序&#xff0c;但是單看代碼的時候有點迷&#xff0c;沒看懂咋操作的&#xff0c;后來又查資料復習了一下&#xff0c;最終才把代碼看明白&#xff0c;所以寫篇博客記錄一下。 插入排序像打撲克牌 這是我聽到過比較形…

list的總結

目錄 1.什么是list 1.1list 的優勢和劣勢 優勢&#xff1a; 劣勢&#xff1a; 2.構造函數 2.1 default (1) 2.2 fill (2) 2.3 range (3) 2.4 copy (4) 3.list iterator的使用 3.1. begin() 3.2. end() 3.3迭代器遍歷 4. list容量函數 4.1. empty() 4.2. siz…

語音合成綜述Speech Synthesis

一、語音合成概述 語音信號的產生分為兩個階段&#xff0c;信息編碼和生理控制。首先在大腦中出現某種想要表達的想法&#xff0c;然后由大腦將其編碼為具體的語言文字序列&#xff0c;及語音中可能存在的強調、重讀等韻律信息。經過語言的組織&#xff0c;大腦通過控制發音器…

正整數分解

題目編號&#xff1a;Exp08-Basic01&#xff0c;GJBook3-12-05 題目名稱&#xff1a;正整數分解 題目描述&#xff1a;正整數n&#xff0c;按第一項遞減的順序依次輸出其和等于n的所有不增的正整數和式。 輸入&#xff1a;一個正整數n&#xff08;0<n≤15&#xff09;。 …

qRT-PCR相對定量計算詳解qPCR相對定量計算方式——2^-(??Ct) deta t

做完轉錄組分析之后&#xff0c;一般都要求做qRT-PCR來驗證二代測序得到的轉錄本表達是否可靠。熒光定量PCR是一種相對表達定量的方法&#xff0c;他的計算方法有很多&#xff0c;常用的相對定量數據分析方法有雙標曲線法&#xff0c;ΔCt法&#xff0c;2^-ΔΔCt法(Livak法)&a…

順序表基本操作全面解析

文章目錄 1.線性表2.順序表分類2.1 靜態順序表2.2 動態順序表 3. 順序表各接口實現1. 定義結構體(Seqlist)2. 結構體初始化(SLInit)3.檢查容量 (SLCheckCapacity)4.打印數據 (SLPrintf)5.插入操作5.1 從數據頭部插入(SLPushFront)5.2 從數據尾部插入(SLPushBack)5.3 從任意下標…

100天精通Python(可視化篇)——第106天:Pyecharts繪制多種炫酷桑基圖參數說明+代碼實戰

文章目錄 專欄導讀一、桑基圖介紹1. 桑基圖是什么?2. 桑基圖應用場景?二、桑基圖配置選項1. 導包2. add函數3. 分層設置三、桑基圖基礎1. 普通桑基圖2. 修改標簽位置3. 修改節點布局方向4、月度開支桑基圖書籍推薦專欄導讀 ????本文已收錄于《100天精通Python從入門到就…

線性表之順序表

文章目錄 主要內容一.順序表1.插入操作&#xff1a;代碼如下&#xff08;示例&#xff09;: 2.刪除操作&#xff1a;代碼如下&#xff08;示例&#xff09;: 3.按值查找&#xff1a;代碼如下&#xff08;示例&#xff09;: 總結 主要內容 順序表 預備知識 定義&#xff1a; 線…

GEE:基于 Landst 遙感數據計算的 kNDVI 下載 APP

作者&#xff1a;CSDN _養樂多_ 本文記錄了在Google Earth Engine&#xff08;GEE&#xff09;平臺中&#xff0c;使用 Landsat 遙感數據計算并且下載 kNDVI 的應用 APP 鏈接&#xff0c;并介紹該 APP 的使用方法和步驟。該APP可以為用戶展示 NDVI 和 kNDVI 的遙感影像&#…

抽象類, 接口, Object類 ---java

目錄 一. 抽象類 1.1 抽象類概念 1.2 抽象類語法 1.3 抽象類特性 1.4 抽象類的作用 二. 接口 2.1 接口的概念 2.2 語法規則 2.3 接口的使用 2.4 接口間的繼承 2.5 抽象類和接口的區別 三. Object類 3.1 toString() 方法 3.2 對象比較equals()方法 3.3 hash…

免費獲取GPT-4的五種工具

不可否認&#xff0c;由OpenAI帶來的GPT-4已是全球最受歡迎的、功能最強大的大語言模型&#xff08;LLM&#xff09;之一。大多數人都需要使用ChatGPT Plus的訂閱服務去訪問GPT-4。為此&#xff0c;他們通常需要每月支付20美元。那么問題來了&#xff0c;如果您不想每月有這筆支…

基于JavaWeb+SpringBoot+Vue醫院管理系統小程序的設計和實現

基于JavaWebSpringBootVue醫院管理系統小程序的設計和實現 源碼獲取入口Lun文目錄前言主要技術系統設計功能截圖訂閱經典源碼專欄[Java 源碼獲取 源碼獲取入口 Lun文目錄 目錄 1系統概述 1 1.1 研究背景 1 1.2研究目的 1 1.3系統設計思想 1 2相關技術 2 2.1微信小程序 2 2.2 …

井蓋位移傳感器廠家批發,守護井蓋安全

窨井蓋廣泛分布于城市街道&#xff0c;其管理效果直接反映了城市治理的現代化程度。根據住房和城鄉建設部發布的《關于進一步加強城市窨井蓋安全管理的通知》&#xff0c;全國各地需加強窨井蓋的安全管理。作為市政基礎設施的一個重要的組成部分&#xff0c;井蓋的管理工作不僅…

去水印網站哪個好?試試這個去水印軟件!

在工作中&#xff0c;我們都曾遇到過圖片水印的困擾。在眾多的在線水印去除工具中&#xff0c;雖然選擇看似豐富&#xff0c;但往往很難找到完全滿足我們需求的那一個。有些工具操作過程繁復&#xff0c;有些工具在處理復雜水印時力不從心&#xff0c;還有些工具在去水印的過程…

【Spring日志】

一.日志作用 1.定位和發現問題 這是日志的主要用途,通過查看日志,我們可以定位問題發生的位置,從而快速的發現問題,分析問題. 2.系統監控 監控幾乎是一個成熟系統的標配,我們可以通過日志記錄這個系統的運行狀態,比如記錄方法的響應時間,響應狀態,通過設置不同的規則,超過閾值就…

【MyBatis <if> <where>標簽介紹】

文章目錄 <if>標簽<where>標簽<foreach>標簽 <if>標簽 <if>標簽允許我們在SQL語句中添加條件判斷。 <if test"condition"><!-- 當條件滿足時執行的SQL語句 --> </if>其中&#xff0c;test屬性是一個表達式&#x…

葡萄酒按酒體如何分類,都有什么特點?

葡萄酒的酒體是指酒液在口腔中的飽滿度和分量感&#xff0c;品酒者常用“輕盈”“厚重”“適中”等詞匯來形容。所以&#xff0c;云倉酒莊的品牌雷盛紅酒分享在葡萄酒分類中還有一個類型&#xff0c;就是按照酒體進行分類。一般分為輕盈型、中等型、飽滿型。 輕盈型&#xff1…

海外https代理ip如何保障信息安全?該怎么選擇?

海外https代理ip是指通信協議為https的海外真實網絡地址ip&#xff0c;通常應用在各種跨境業務中。 一、什么是HTTPS協議 HTTP協議是一個應用層協議&#xff0c;通常運行在TCP協議之上。它是一個明文協議&#xff0c;客戶端發起請求&#xff0c;服務端給出響應的響應。由于網…

表單郵箱密碼登錄 原生+Jquery實現

文章目錄 效果代碼郵箱驗證正則表達式HTMLCSS JS 效果 正確密碼為&#xff1a;123456 點擊登錄按鈕校驗。 代碼 表單校驗 - CodeSandbox 郵箱驗證正則表達式 /(?:[a-z0-9!#$%&*/?^_{|}~-](?:\.[a-z0-9!#$%&*/?^_{|}~-])*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1…