yolov5特征圖可視化的使用步驟
前言
最近寫論文需要觀察中間特征層的特征圖,使用的是yolov5的代碼倉庫,但是苦于找不到很好的輪子,于是參考了很多,只找了這個,但是我覺得作者寫的太復(fù)雜了(我之前就是這個作者的小粉絲),在參考了github的yolov5作者給出的issue建議后,自己寫了個輪子,沒有復(fù)雜的步驟,借助torchvision中的transforms將tensor轉(zhuǎn)化為PIL,再通過matplotlib保存特圖。希望能給大家?guī)硪恍椭?/p>
一、效果圖
先上一下效果圖,因為深層的特征有高達(dá)1024個,這里我只打印了8*8的特征圖,用plt.subplot將64張?zhí)卣鲌D展示在一張圖片上。原圖為我在百度上隨便搜的貓咪:
這是yolov5x.pt進行detect過程中,經(jīng)過可視化后的第一個C3模塊的前64張?zhí)卣鲌D:
這里也可以設(shè)置為灰度圖,后續(xù)代碼中會給出。
可以看到不同特征圖所提取到的特征幾乎都不相同,有的側(cè)重邊緣,有的則是側(cè)重整體,當(dāng)然這只是第一個C3的特征圖,相對于更深層的特征來說,淺層的特征大多是完整的,而更深層的特征則會更小,而且是提取到的細(xì)小特征,當(dāng)然,這些特征圖也都是相互聯(lián)系的,網(wǎng)絡(luò)結(jié)構(gòu)是個整體。
借助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.
單個特征圖可能是一組淺層信息,因為你正在查看 2d 空間切片,但并未恰當(dāng)?shù)赜^察特征空間中的關(guā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中的這個地方:
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中都會進行可視化特征圖。
然而訓(xùn)練的過程中并不一定需要一直可視化特征圖,feature_vis參數(shù)是用來控制是否保存可視化特征圖的,保存的特征圖會存在features文件夾中。如果想看其它層的特征只需要修改m.type或是用m.i來進行判斷是否可視化特征圖。m.type對應(yīng)的是yaml文件中的module,即yolov5的基礎(chǔ)模塊,例如c3,conv,spp等等,而m.i則更好理解,即是模塊的id,通常就是順序,如果你嘗試修改過配置文件,那么你肯定知道是什么。
如果不明白,多使用print函數(shù),用list.len()和tensor.size去查看列表長度和張量維度,打印出來你就知道了。
這里有一個點我很迷惑,不知道有沒有大佬可以告訴我原因,就是我并沒有找到y(tǒng)olo.py和detect.py之間的關(guān)聯(lián),detect.py中使用的是:
model = attempt_load(weights, map_location=device)
而并沒有使用yolo.py中的Model函數(shù),但是運行detect.py同樣可以可視化特征圖,不是很懂pytorch代碼中的這個機制,希望有大佬可以指教一下,代碼還是有些菜。
2.注意事項
注意1:在yolo.py的開頭import feature_visualization:
from utils.general import feature_visualization
注意2:yolov5無論是在detect還是在train的過程中,都會先對模型進行Summary,即驗證你的模型的層數(shù),參數(shù)以及是否有梯度,這個過程也會保存特征圖,但是不要擔(dān)心,因為你保存的特征圖名字是相同的,會被覆蓋,如果你打印的出來log就會看到整個模型跑了兩次:
Model Summary: 476 layers, 87730285 parameters, 0 gradients
注意3:建議訓(xùn)練完成的網(wǎng)絡(luò)使用detect.py來進行驗證特征圖。
當(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,將隨機生成的圖片換成自己的圖片,就可以正常的進行驗證。
總結(jié)
周末摸魚時間寫了這個(也不算摸魚,下周該寫論文初稿了orz),希望給大家?guī)韼椭?,如果有疑問或者錯誤,在評論區(qū)或者私信聯(lián)系我,之后我會把這個提交一個pr到y(tǒng)olov5的官方倉庫里(之前提交了一個visdrone.yaml的配置文件,幸被采用了,參考的就是這個作者的代碼,感謝?。?,就到這里,最后上一個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)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Python api構(gòu)建tensorrt加速模型的步驟詳解
小編個人認(rèn)為python比c++更容易讀并且已經(jīng)有很多包裝很好的科學(xué)運算庫(numpy,scikit等),今天通過本文給大家分享Python api構(gòu)建tensorrt加速模型的步驟,感興趣的朋友一起看看吧2021-09-09基于Python實現(xiàn)B站視頻數(shù)據(jù)信息內(nèi)容采集
這篇文章主要介紹了如何基于Python實現(xiàn)B站視頻數(shù)據(jù)信息內(nèi)容采集,文中有非常詳細(xì)的代碼示例,對正在學(xué)習(xí)python的小伙伴們有非常好的幫助,需要的朋友可以參考下2024-02-02如何用VScode配置Python開發(fā)環(huán)境
這篇文章主要介紹了如何用VScode配置Python開發(fā)環(huán)境,vscode有很多優(yōu)點,用VScode來編寫Python,也是相當(dāng)?shù)暮糜玫?需要的朋友可以參考下2023-03-03