python打卡day47

特征圖與注意力熱圖
知識點回顧:

  1. 不同CNN層的特征圖:不同通道的特征圖
  2. 通道注意力后的特征圖和熱力圖

特征圖本質就是不同的卷積核的輸出,淺層指的是離輸入圖近的卷積層,淺層卷積層的特征圖通常較大,而深層特征圖會經過多次下采樣,尺寸顯著縮小,尺寸差異過大時,小尺寸特征圖在視覺上會顯得模糊或丟失細節。步驟邏輯如下:

1. 初始化設置:

  • 將模型設為評估模式,準備類別名稱列表

2.數據加載與處理:

  • 從測試數據加載器中獲取圖像和標簽
  • 限制處理量以避免冗余,僅處理前 `num_images` 張圖像(如2張)

3. 注冊鉤子捕獲特征圖:

  • 為指定層(如 `conv1`, `conv2`, `conv3`)注冊前向鉤子
  • 鉤子函數將這些層的輸出(特征圖)保存到字典中(以層名為鍵,特征圖(Tensor)為值)

4. 前向傳播與特征提取:

  • 模型處理圖像,觸發鉤子函數,獲取并保存特征圖
  • 移除鉤子,避免后續干擾

5. 可視化特征圖:對每張圖像

  • 恢復原始像素值并顯示(反標準化)
  • 為每個目標層創建子圖,展示前 `num_channels` 個通道的特征圖(每個通道的特征圖是單通道灰度圖,需獨立顯示)
  • 每個通道的特征圖以網格形式排列,顯示通道編號
def visualize_feature_maps(model, test_loader, device, layer_names, num_images=3, num_channels=9):"""可視化指定層的特征圖(修復循環冗余問題)參數:model: 模型test_loader: 測試數據加載器layer_names: 要可視化的層名稱(如['conv1', 'conv2', 'conv3'])num_images: 可視化的圖像總數num_channels: 每個圖像顯示的通道數(取前num_channels個通道)"""model.eval()  # 設置為評估模式class_names = ['飛機', '汽車', '鳥', '貓', '鹿', '狗', '青蛙', '馬', '船', '卡車']# 從測試集加載器中提取指定數量的圖像(避免嵌套循環)images_list, labels_list = [], []for images, labels in test_loader:images_list.append(images)labels_list.append(labels)if len(images_list) * test_loader.batch_size >= num_images:break# 拼接并截取到目標數量images = torch.cat(images_list, dim=0)[:num_images].to(device) # torch.cat拼接多個batch的數據labels = torch.cat(labels_list, dim=0)[:num_images].to(device)with torch.no_grad():# 存儲各層特征圖feature_maps = {}# 保存鉤子句柄hooks = []# 定義鉤子函數,捕獲指定層的輸出def hook(module, input, output, name):feature_maps[name] = output.cpu()  # 保存特征圖到字典,保存到CPU,避免GPU內存占用# 為每個目標層注冊鉤子,并保存鉤子句柄for name in layer_names:module = getattr(model, name) # 根據層名獲取模塊hook_handle = module.register_forward_hook(lambda m, i, o, n=name: hook(m, i, o, n)) # 綁定層名到鉤子hooks.append(hook_handle)# 前向傳播觸發鉤子_ = model(images)# 正確移除鉤子for hook_handle in hooks:hook_handle.remove()# 可視化每個圖像的各層特征圖(僅一層循環)for img_idx in range(num_images):img = images[img_idx].cpu().permute(1, 2, 0).numpy() # [C,H,W]→[H,W,C]# 反標準化處理(恢復原始像素值)img = img * np.array([0.2023, 0.1994, 0.2010]).reshape(1, 1, 3) + np.array([0.4914, 0.4822, 0.4465]).reshape(1, 1, 3)img = np.clip(img, 0, 1)  # 確保像素值在[0,1]范圍內# 創建子圖num_layers = len(layer_names)fig, axes = plt.subplots(1, num_layers + 1, figsize=(4 * (num_layers + 1), 4))# 顯示原始圖像axes[0].imshow(img)axes[0].set_title(f'原始圖像\n類別: {class_names[labels[img_idx]]}')axes[0].axis('off')# 顯示各層特征圖for layer_idx, layer_name in enumerate(layer_names):fm = feature_maps[layer_name][img_idx]  # 取第img_idx張圖像的特征圖fm = fm[:num_channels]  # 僅取前num_channels個通道num_rows = int(np.sqrt(num_channels)) # 計算網格行數num_cols = num_channels // num_rows if num_rows != 0 else 1 # 計算網格列數# 創建子圖網格layer_ax = axes[layer_idx + 1]layer_ax.set_title(f'{layer_name}特征圖 \n')# 加個換行讓文字分離上去layer_ax.axis('off')  # 關閉大子圖的坐標軸# 在大子圖內創建小網格for ch_idx, channel in enumerate(fm):ax = layer_ax.inset_axes([ch_idx % num_cols / num_cols, (num_rows - 1 - ch_idx // num_cols) / num_rows, 1/num_cols, 1/num_rows])ax.imshow(channel.numpy(), cmap='viridis')ax.set_title(f'通道 {ch_idx + 1}')ax.axis('off')plt.tight_layout()plt.show()# 調用示例(按需修改參數)
layer_names = ['conv1', 'conv2', 'conv3']
visualize_feature_maps(model=model,test_loader=test_loader,device=device,layer_names=layer_names,num_images=5,  # 可視化5張測試圖像 → 輸出5張大圖num_channels=9   # 每張圖像顯示前9個通道的特征圖
)

可以看到特征逐層抽象,從“看得見的細節”(conv1)→ “局部結構”(conv2)→ “類別相關的抽象模式”(conv3),模型通過這種方式實現從“看圖像”到“理解語義”的跨越;并且每層各個通道也聚焦了不同特征(如通道1檢測邊緣輪廓,通道2檢測紋理細節...),共同協作完成分類任務

?分別針對不同層次的模型理解需求的三種主流的神經網絡可視化方法,就差注意力熱圖沒學了,一般用于檢查注意力模塊是否聚焦與任務相關的關鍵通道或者空間,具體來說:

  1. 通道注意力熱圖:展示不同通道的權重分布,例如,在圖像分類任務中,模型可能會對包含目標物體的通道賦予更高的注意力權重

  2. 空間注意力熱圖:展示輸入圖像中不同空間位置的權重分布,例如,在目標檢測或圖像分類任務中,模型可能會對目標物體所在的區域分配更高的注意力權重

注意力熱圖的步驟和特征圖差不多,就是注意一下鉤子注冊位置僅在最后一個卷積層,就用昨天加入了通道注意力模塊的cnn模型訓練的結果來可視化

# 可視化空間注意力熱力圖(顯示模型關注的圖像區域)
def visualize_attention_map(model, test_loader, device, class_names, num_samples=3):"""可視化模型的注意力熱力圖,展示模型關注的圖像區域"""model.eval()  # 設置為評估模式with torch.no_grad():for i, (images, labels) in enumerate(test_loader):if i >= num_samples:  # 只可視化前幾個樣本breakimages, labels = images.to(device), labels.to(device)# 創建一個鉤子,捕獲中間特征圖activation_maps = []def hook(module, input, output):activation_maps.append(output.cpu())# 為最后一個卷積層注冊鉤子(獲取特征圖)hook_handle = model.conv3.register_forward_hook(hook)# 前向傳播,觸發鉤子outputs = model(images)# 移除鉤子hook_handle.remove()# 獲取預測結果_, predicted = torch.max(outputs, 1)# 獲取原始圖像img = images[0].cpu().permute(1, 2, 0).numpy()# 反標準化處理img = img * np.array([0.2023, 0.1994, 0.2010]).reshape(1, 1, 3) + np.array([0.4914, 0.4822, 0.4465]).reshape(1, 1, 3)img = np.clip(img, 0, 1)# 獲取激活圖(最后一個卷積層的輸出)feature_map = activation_maps[0][0].cpu()  # 取第一個樣本# 計算通道注意力權重(使用SE模塊的全局平均池化)channel_weights = torch.mean(feature_map, dim=(1, 2))  # [C]# 按權重對通道排序sorted_indices = torch.argsort(channel_weights, descending=True)# 創建子圖fig, axes = plt.subplots(1, 4, figsize=(16, 4))# 顯示原始圖像axes[0].imshow(img)axes[0].set_title(f'原始圖像\n真實: {class_names[labels[0]]}\n預測: {class_names[predicted[0]]}')axes[0].axis('off')# 顯示前3個最活躍通道的熱力圖for j in range(3):channel_idx = sorted_indices[j]# 獲取對應通道的特征圖channel_map = feature_map[channel_idx].numpy()# 歸一化到[0,1]channel_map = (channel_map - channel_map.min()) / (channel_map.max() - channel_map.min() + 1e-8)# 調整熱力圖大小以匹配原始圖像from scipy.ndimage import zoomheatmap = zoom(channel_map, (32/feature_map.shape[1], 32/feature_map.shape[2]))# 顯示熱力圖axes[j+1].imshow(img)axes[j+1].imshow(heatmap, alpha=0.5, cmap='jet')axes[j+1].set_title(f'注意力熱力圖 - 通道 {channel_idx}')axes[j+1].axis('off')plt.tight_layout()plt.show()# 調用可視化函數
visualize_attention_map(model, test_loader, device, class_names, num_samples=3)

關于全局平均池化?torch.mean?vs nn.AdaptiveAvgPool2d 兩種方法其實功能上完全等價,只不過前者是直接操作張量的函數,更適合后處理;后者適合神經網絡。再明確一點,假設輸入特征圖[C, H, W]:

  • torch.mean(dim=(1, 2))?→ 輸出?[C](每個通道的標量均值)
  • nn.AdaptiveAvgPool2d(1)?→ 輸出?[C, 1, 1](可通過?squeeze()?轉為?[C],所以這里直接注冊鉤子捕獲這一層輸出得到通道權重也行

當前代碼的熱力圖是單通道特征圖的歸一化激活強度,再疊加到原圖上,并不是嚴格意義上的注意力熱圖,嚴謹一點的話應該用sigmoid后的通道權重來畫直方圖

@浙大疏錦行

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

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

相關文章

緩存一致性 與 執行流

上接多執行流系統中的可見性 在緩存一致性協議描述中,使用“處理器”或“CPU核心”比“執行流”更精確嗎? 核心結論:在緩存一致性協議描述中,使用“處理器”或“CPU核心”比“執行流”更精確! 你的直覺是正確的。 原因分析&am…

機器學習:load_predict_project

本文目錄: 一、project目錄二、utils里的兩個工具包(一)common.py(二)log.py 三、src文件夾代碼(一)模型訓練(train.py)(二)模型預測(…

Qt Test功能及架構

Qt Test 是 Qt 框架中的單元測試模塊,在 Qt 6.0 中提供了全面的測試功能。 一、主要功能 核心功能 1. 單元測試框架 提供完整的單元測試基礎設施 支持測試用例、測試套件的組織和執行 包含斷言宏和測試結果收集 2. 測試類型支持 單元測試:對單個函…

零基礎在實踐中學習網絡安全-皮卡丘靶場(第十一期-目錄遍歷模塊)

經過前面幾期的內容我們學習了很多網絡安全的知識,而這期內容就涉及到了前面的第六期-RCE模塊,第七期-File inclusion模塊,第八期-Unsafe Filedownload模塊。 什么是"遍歷"呢:對學過一些開發語言的朋友來說應該知道&…

LLM 筆記:Speculative Decoding 投機采樣

1 基本介紹 投機采樣(Speculative Sampling)是一種并行預測多個可能輸出,然后快速驗證并采納正確部分的加速策略 在不犧牲輸出質量的前提下,減少語言模型生成 token 所需的時間 傳統的語言模型生成是 串行 的 必須生成一個&…

Mysql批處理寫入數據庫

在學習mybatisPlus時,看到一個原本沒用過的參數: rewriteBatchedStatementstrue 將上述代碼裝入jdbc的url中即可使數據庫啟用批處理寫入。 需要注意的是,這個參數僅適用于MySQL JDBC 驅動的私有擴展參數。 作用原理是: 原本的…

數據類型--實型

C中的實型(也稱為浮點型,Floating Point Type)用于表示帶有小數部分的數值。 常見的實型有 float、double 和 long double,它們在精度和存儲空間上有所不同。 1. 常見實型及其特性 類型字節數(通常)精度&…

引領AI安全新時代 Accelerate 2025北亞巡展·北京站成功舉辦

6月5日,網絡安全行業年度盛會——"Accelerate 2025北亞巡展北京站"圓滿落幕!來自智庫、產業界、Fortinet管理層及技術團隊的權威專家,與來自各行業的企業客戶代表齊聚一堂,圍繞"AI智御全球引領安全新時代"主題…

coze平臺創建智能體,關于智能體后端接入的問題

一、智能體的插件在coze平臺能正常調用,在Apifox中測試,它卻直接回復直接回復“人設”或“知識庫”,你的提問等內容: 為什么會這樣?: Coze官方的插件(工具調用)機制是“分步交互式”…

Shell編程核心符號與格式化操作詳解

Shell編程作為Linux系統管理和自動化運維的核心技能,掌握其常用符號和格式化操作是提升腳本開發效率的關鍵。本文將深入解析Shell中重定向、管道符、EOF、輸入輸出格式化等核心概念,并通過豐富的實踐案例幫助讀者掌握這些重要技能。 一、信息傳遞與重定…

C++課設:簡易科學計算器(支持+-*/、sin、cos、tan、log等科學函數)

名人說:路漫漫其修遠兮,吾將上下而求索。—— 屈原《離騷》 創作者:Code_流蘇(CSDN)(一個喜歡古詩詞和編程的Coder😊) 專欄介紹:《編程項目實戰》 目錄 一、項目概覽與設計理念1. 功能特色2. 技…

WPF八大法則:告別模態窗口卡頓

?? 核心問題:阻塞式模態窗口的缺陷 原始代碼中ShowDialog()會阻塞UI線程,導致后續邏輯無法執行: var result modalWindow.ShowDialog(); // 線程阻塞 ProcessResult(result); // 必須等待窗口關閉根本問題&#xff1a…

UOS無法安裝deb軟件包

UOS無法安裝deb軟件包 問題描述解決辦法: 關閉安全中心的應用隔離結果驗證 問題描述 UOS安裝Linux微信的deb包時,無法正常安裝 解決辦法: 關閉安全中心的應用隔離 要關閉-安全中心的應用隔離后才可以正常軟件和運行。 應用安全----》 允許任意應用。 結果驗證 # …

鴻蒙jsonToArkTS_工具exe版本來了

前言導讀 相信大家在學習鴻蒙開發過程中最痛苦的就是編寫model 類 特別是那種復雜的json的時候對不對, 這時候有一個自動化的工具給你生成model是不是很開心。我們今天要分享的就是這個工具 JsonToArkTs 的用法 工具地址 https://gitee.com/qiuyu123/jsontomodel…

【Java算法】八大排序

八大排序算法 目錄 注意:以下排序均屬于內部排序 (1)插入排序 直接插入排序 改進版本 折半插入排序 希爾排序 (2)交換排序 冒泡排序 快速排序 (3)選擇排序 簡單選擇排序 堆排序&…

玩轉Docker | 使用Docker部署Qwerty Learner英語單詞學習網站

玩轉Docker | 使用Docker部署Qwerty Learner英語單詞學習網站 前言一、Qwerty Learner簡介Qwerty Learner 簡介主要特點二、系統要求環境要求環境檢查Docker版本檢查檢查操作系統版本三、部署Qwerty Learner服務下載Qwerty Learner鏡像編輯部署文件創建容器檢查容器狀態檢查服務…

Vue3中computed和watch的區別

文章目錄 前言🔍 一、computed vs watch? 示例對比1. computed 示例(適合模板綁定、衍生數據)2. watch 示例(副作用,如調用接口) 🧠 二、源碼實現原理(簡化理解)1. comp…

C++修煉:C++11(二)

Hello大家好&#xff01;很高興我們又見面啦&#xff01;給生活添點passion&#xff0c;開始今天的編程之路&#xff01; 我的博客&#xff1a;<但凡. 我的專欄&#xff1a;《編程之路》、《數據結構與算法之美》、《題海拾貝》、《C修煉之路》 歡迎點贊&#xff0c;關注&am…

單元測試與QTestLib框架使用

一.單元測試的意義 在軟件開發中&#xff0c;單元測試是指對軟件中最小可測試單元&#xff08;通常是函數、類的方法&#xff09;進行隔離的、可重復的驗證。進行單元測試具有以下重要意義&#xff1a; 1.提升代碼質量與可靠性&#xff1a; 早期錯誤檢測&#xff1a; 在開發…

(附實現代碼)Step-Back 回答回退策略擴大檢索范圍

1. LangChain 少量示例提示模板 在與 LLM 的對話中&#xff0c;提供少量的示例被稱為 少量示例&#xff0c;這是一種簡單但強大的指導生成的方式&#xff0c;在某些情況下可以顯著提高模型性能&#xff08;與之對應的是零樣本&#xff09;&#xff0c;少量示例可以降低 Prompt…