yolov5特征圖可視化的使用步驟
前言
最近寫論文需要觀察中間特征層的特征圖,使用的是yolov5的代碼倉庫,但是苦于找不到很好的輪子,于是參考了很多,只找了這個(gè),但是我覺得作者寫的太復(fù)雜了(我之前就是這個(gè)作者的小粉絲),在參考了github的yolov5作者給出的issue建議后,自己寫了個(gè)輪子,沒有復(fù)雜的步驟,借助torchvision中的transforms將tensor轉(zhuǎn)化為PIL,再通過matplotlib保存特圖。希望能給大家?guī)硪恍椭?/p>
一、效果圖
先上一下效果圖,因?yàn)樯顚拥奶卣饔懈哌_(dá)1024個(gè),這里我只打印了8*8的特征圖,用plt.subplot將64張?zhí)卣鲌D展示在一張圖片上。原圖為我在百度上隨便搜的貓咪:
這是yolov5x.pt進(jìn)行detect過程中,經(jīng)過可視化后的第一個(gè)C3模塊的前64張?zhí)卣鲌D:
這里也可以設(shè)置為灰度圖,后續(xù)代碼中會(huì)給出。
可以看到不同特征圖所提取到的特征幾乎都不相同,有的側(cè)重邊緣,有的則是側(cè)重整體,當(dāng)然這只是第一個(gè)C3的特征圖,相對(duì)于更深層的特征來說,淺層的特征大多是完整的,而更深層的特征則會(huì)更小,而且是提取到的細(xì)小特征,當(dāng)然,這些特征圖也都是相互聯(lián)系的,網(wǎng)絡(luò)結(jié)構(gòu)是個(gè)整體。
借助yolov5作者在issue里說到的:
BTW, a single feature map may be in my opinion a shallow set of information, as you are looking at a 2d spatial slice but are not aptly observing relationships across the feature space (as the convolutions do).
I guess an analogy is that you would be viewing the R, G, B layers of a color image by themselves, when it helps to view them together to get the complete picture.
單個(gè)特征圖可能是一組淺層信息,因?yàn)槟阏诓榭?2d 空間切片,但并未恰當(dāng)?shù)赜^察特征空間中的關(guān)系(如卷積所做的那樣)。
這里是我自己的理解,通過特征圖的可視化,也進(jìn)一步的理解了卷積到底干了些什么事情,如果有想進(jìn)一步交流的小伙伴,私信一起討論,一起學(xué)習(xí)呀。
二、使用步驟
1.使用方法
使用方法很簡單,只需要在utils中的general.py或者plots.py添加如下函數(shù):
import matplotlib.pyplot as plt from torchvision import transforms def feature_visualization(features, model_type, model_id, feature_num=64): """ features: The feature map which you need to visualization model_type: The type of feature map model_id: The id of feature map feature_num: The amount of visualization you need save_dir = "features/" if not os.path.exists(save_dir): os.makedirs(save_dir) # print(features.shape) # block by channel dimension blocks = torch.chunk(features, features.shape[1], dim=1) # # size of feature # size = features.shape[2], features.shape[3] plt.figure() for i in range(feature_num): torch.squeeze(blocks[i]) feature = transforms.ToPILImage()(blocks[i].squeeze()) # print(feature) ax = plt.subplot(int(math.sqrt(feature_num)), int(math.sqrt(feature_num)), i+1) ax.set_xticks([]) ax.set_yticks([]) plt.imshow(feature) # gray feature # plt.imshow(feature, cmap='gray') # plt.show() plt.savefig(save_dir + '{}_{}_feature_map_{}.png' .format(model_type.split('.')[2], model_id, feature_num), dpi=300)
接著在models中的yolo.py中的這個(gè)地方:
def forward_once(self, x, profile=False): y, dt = [], [] # outputs for m in self.model: if m.f != -1: # if not from previous layer x = y[m.f] if isinstance(m.f, int) else [x if j == -1 else y[j] for j in m.f] # from earlier layers if profile: o = thop.profile(m, inputs=(x,), verbose=False)[0] / 1E9 * 2 if thop else 0 # FLOPS t = time_synchronized() for _ in range(10): _ = m(x) dt.append((time_synchronized() - t) * 100) print('%10.1f%10.0f%10.1fms %-40s' % (o, m.np, dt[-1], m.type)) x = m(x) # run y.append(x if m.i in self.save else None) # save output # add in here if profile: print('%.1fms total' % sum(dt)) return x
添加如下代碼:
feature_vis = True if m.type == 'models.common.C3' and feature_vis: print(m.type, m.i) feature_visualization(x, m.type, m.i)
添加在yolo.py后,無論是在detect.py還是在train.py中都會(huì)進(jìn)行可視化特征圖。
然而訓(xùn)練的過程中并不一定需要一直可視化特征圖,feature_vis參數(shù)是用來控制是否保存可視化特征圖的,保存的特征圖會(huì)存在features文件夾中。如果想看其它層的特征只需要修改m.type或是用m.i來進(jìn)行判斷是否可視化特征圖。m.type對(duì)應(yīng)的是yaml文件中的module,即yolov5的基礎(chǔ)模塊,例如c3,conv,spp等等,而m.i則更好理解,即是模塊的id,通常就是順序,如果你嘗試修改過配置文件,那么你肯定知道是什么。
如果不明白,多使用print函數(shù),用list.len()和tensor.size去查看列表長度和張量維度,打印出來你就知道了。
這里有一個(gè)點(diǎn)我很迷惑,不知道有沒有大佬可以告訴我原因,就是我并沒有找到y(tǒng)olo.py和detect.py之間的關(guān)聯(lián),detect.py中使用的是:
model = attempt_load(weights, map_location=device)
而并沒有使用yolo.py中的Model函數(shù),但是運(yùn)行detect.py同樣可以可視化特征圖,不是很懂pytorch代碼中的這個(gè)機(jī)制,希望有大佬可以指教一下,代碼還是有些菜。
2.注意事項(xiàng)
注意1:在yolo.py的開頭import feature_visualization:
from utils.general import feature_visualization
注意2:yolov5無論是在detect還是在train的過程中,都會(huì)先對(duì)模型進(jìn)行Summary,即驗(yàn)證你的模型的層數(shù),參數(shù)以及是否有梯度,這個(gè)過程也會(huì)保存特征圖,但是不要擔(dān)心,因?yàn)槟惚4娴奶卣鲌D名字是相同的,會(huì)被覆蓋,如果你打印的出來log就會(huì)看到整個(gè)模型跑了兩次:
Model Summary: 476 layers, 87730285 parameters, 0 gradients
注意3:建議訓(xùn)練完成的網(wǎng)絡(luò)使用detect.py來進(jìn)行驗(yàn)證特征圖。
當(dāng)然在yolo.py里面也可以將'__main__'中的 :
model = Model(opt.cfg).to(device)
替換為:
model = attempt_load(opt.weights, map_location=device)
同樣可以跑通(把detect.py中的opt.weights復(fù)制過來)。在yolo.py中打開Profile,將隨機(jī)生成的圖片換成自己的圖片,就可以正常的進(jìn)行驗(yàn)證。
總結(jié)
周末摸魚時(shí)間寫了這個(gè)(也不算摸魚,下周該寫論文初稿了orz),希望給大家?guī)韼椭?,如果有疑問或者錯(cuò)誤,在評(píng)論區(qū)或者私信聯(lián)系我,之后我會(huì)把這個(gè)提交一個(gè)pr到y(tǒng)olov5的官方倉庫里(之前提交了一個(gè)visdrone.yaml的配置文件,幸被采用了,參考的就是這個(gè)作者的代碼,感謝!),就到這里,最后上一個(gè)spp結(jié)構(gòu)的特征圖輸出,希望和大家一起討論。
以上。
參考
pytorch 提取卷積神經(jīng)網(wǎng)絡(luò)的特征圖可視化
深度學(xué)習(xí)筆記~卷積網(wǎng)絡(luò)中特征圖的可視化
Pytorch中Tensor與各種圖像格式的相互轉(zhuǎn)化
到此這篇關(guān)于yolov5特征圖可視化的文章就介紹到這了,更多相關(guān)yolov5可視化內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Python時(shí)間的精準(zhǔn)正則匹配方法分析
這篇文章主要介紹了Python時(shí)間的精準(zhǔn)正則匹配方法,結(jié)合實(shí)例形式對(duì)比分析了Python針對(duì)時(shí)間格式相關(guān)正則匹配技巧,需要的朋友可以參考下2017-08-08Python api構(gòu)建tensorrt加速模型的步驟詳解
小編個(gè)人認(rèn)為python比c++更容易讀并且已經(jīng)有很多包裝很好的科學(xué)運(yùn)算庫(numpy,scikit等),今天通過本文給大家分享Python api構(gòu)建tensorrt加速模型的步驟,感興趣的朋友一起看看吧2021-09-09Django處理文件上傳File Uploads的實(shí)例
今天小編就為大家分享一篇Django處理文件上傳File Uploads的實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2018-05-05基于Python實(shí)現(xiàn)B站視頻數(shù)據(jù)信息內(nèi)容采集
這篇文章主要介紹了如何基于Python實(shí)現(xiàn)B站視頻數(shù)據(jù)信息內(nèi)容采集,文中有非常詳細(xì)的代碼示例,對(duì)正在學(xué)習(xí)python的小伙伴們有非常好的幫助,需要的朋友可以參考下2024-02-02如何用VScode配置Python開發(fā)環(huán)境
這篇文章主要介紹了如何用VScode配置Python開發(fā)環(huán)境,vscode有很多優(yōu)點(diǎn),用VScode來編寫Python,也是相當(dāng)?shù)暮糜玫?需要的朋友可以參考下2023-03-03