yolov5特征圖可視化的使用步驟
前言
最近寫論文需要觀察中間特征層的特征圖,使用的是yolov5的代碼倉庫,但是苦於找不到很好的輪子,於是參考瞭很多,隻找瞭這個,但是我覺得作者寫的太復雜瞭(我之前就是這個作者的小粉絲),在參考瞭github的yolov5作者給出的issue建議後,自己寫瞭個輪子,沒有復雜的步驟,借助torchvision中的transforms將tensor轉化為PIL,再通過matplotlib保存特圖。希望能給大傢帶來一些幫助。
一、效果圖
先上一下效果圖,因為深層的特征有高達1024個,這裡我隻打印瞭8*8的特征圖,用plt.subplot將64張特征圖展示在一張圖片上。原圖為我在百度上隨便搜的貓咪:
這是yolov5x.pt進行detect過程中,經過可視化後的第一個C3模塊的前64張特征圖:
這裡也可以設置為灰度圖,後續代碼中會給出。
可以看到不同特征圖所提取到的特征幾乎都不相同,有的側重邊緣,有的則是側重整體,當然這隻是第一個C3的特征圖,相對於更深層的特征來說,淺層的特征大多是完整的,而更深層的特征則會更小,而且是提取到的細小特征,當然,這些特征圖也都是相互聯系的,網絡結構是個整體。
借助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 空間切片,但並未恰當地觀察特征空間中的關系(如卷積所做的那樣)。
這裡是我自己的理解,通過特征圖的可視化,也進一步的理解瞭卷積到底幹瞭些什麼事情,如果有想進一步交流的小夥伴,私信一起討論,一起學習呀。
二、使用步驟
1.使用方法
使用方法很簡單,隻需要在utils中的general.py或者plots.py添加如下函數:
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中都會進行可視化特征圖。
然而訓練的過程中並不一定需要一直可視化特征圖,feature_vis參數是用來控制是否保存可視化特征圖的,保存的特征圖會存在features文件夾中。如果想看其它層的特征隻需要修改m.type或是用m.i來進行判斷是否可視化特征圖。m.type對應的是yaml文件中的module,即yolov5的基礎模塊,例如c3,conv,spp等等,而m.i則更好理解,即是模塊的id,通常就是順序,如果你嘗試修改過配置文件,那麼你肯定知道是什麼。
如果不明白,多使用print函數,用list.len()和tensor.size去查看列表長度和張量維度,打印出來你就知道瞭。
這裡有一個點我很迷惑,不知道有沒有大佬可以告訴我原因,就是我並沒有找到yolo.py和detect.py之間的關聯,detect.py中使用的是:
model = attempt_load(weights, map_location=device)
而並沒有使用yolo.py中的Model函數,但是運行detect.py同樣可以可視化特征圖,不是很懂pytorch代碼中的這個機制,希望有大佬可以指教一下,代碼還是有些菜。
2.註意事項
註意1:在yolo.py的開頭import feature_visualization:
from utils.general import feature_visualization
註意2:yolov5無論是在detect還是在train的過程中,都會先對模型進行Summary,即驗證你的模型的層數,參數以及是否有梯度,這個過程也會保存特征圖,但是不要擔心,因為你保存的特征圖名字是相同的,會被覆蓋,如果你打印的出來log就會看到整個模型跑瞭兩次:
Model Summary: 476 layers, 87730285 parameters, 0 gradients
註意3:建議訓練完成的網絡使用detect.py來進行驗證特征圖。
當然在yolo.py裡面也可以將'__main__'中的 :
model = Model(opt.cfg).to(device)
替換為:
model = attempt_load(opt.weights, map_location=device)
同樣可以跑通(把detect.py中的opt.weights復制過來)。在yolo.py中打開Profile,將隨機生成的圖片換成自己的圖片,就可以正常的進行驗證。
總結
周末摸魚時間寫瞭這個(也不算摸魚,下周該寫論文初稿瞭orz),希望給大傢帶來幫助,如果有疑問或者錯誤,在評論區或者私信聯系我,之後我會把這個提交一個pr到yolov5的官方倉庫裡(之前提交瞭一個visdrone.yaml的配置文件,幸被采用瞭,參考的就是這個作者的代碼,感謝!),就到這裡,最後上一個spp結構的特征圖輸出,希望和大傢一起討論。
以上。
參考
pytorch特征圖可視化
pytorch 提取卷積神經網絡的特征圖可視化
深度學習筆記~卷積網絡中特征圖的可視化
自用代碼 | YOLOv5 特征圖可視化代碼
將tensor張量轉換成圖片格式並保存
Pytorch中Tensor與各種圖像格式的相互轉化
到此這篇關於yolov5特征圖可視化的文章就介紹到這瞭,更多相關yolov5可視化內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!
推薦閱讀:
- YOLOv8訓練自己的數據集(詳細教程)
- python目標檢測實現黑花屏分類任務示例
- yolov5中head修改為decouple head詳解
- pytorch plt.savefig()的用法及保存路徑
- pytorch 搭建神經網路的實現