day 47

注意力可視化

訓練模型

包含通道注意力模塊和CNN模型的定義(通道注意力的插入)

import torch
import torch.nn as nn
import torch.optim as optim
from torchvision import datasets, transforms
from torch.utils.data import DataLoader
import matplotlib.pyplot as plt
import numpy as np# 設置中文字體支持
plt.rcParams["font.family"] = ["SimHei"]
plt.rcParams['axes.unicode_minus'] = False  # 解決負號顯示問題# 檢查GPU是否可用
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
print(f"使用設備: {device}")# 1. 數據預處理
# 訓練集:使用多種數據增強方法提高模型泛化能力
train_transform = transforms.Compose([# 隨機裁剪圖像,從原圖中隨機截取32x32大小的區域transforms.RandomCrop(32, padding=4),# 隨機水平翻轉圖像(概率0.5)transforms.RandomHorizontalFlip(),# 隨機顏色抖動:亮度、對比度、飽和度和色調隨機變化transforms.ColorJitter(brightness=0.2, contrast=0.2, saturation=0.2, hue=0.1),# 隨機旋轉圖像(最大角度15度)transforms.RandomRotation(15),# 將PIL圖像或numpy數組轉換為張量transforms.ToTensor(),# 標準化處理:每個通道的均值和標準差,使數據分布更合理transforms.Normalize((0.4914, 0.4822, 0.4465), (0.2023, 0.1994, 0.2010))
])# 測試集:僅進行必要的標準化,保持數據原始特性,標準化不損失數據信息,可還原
test_transform = transforms.Compose([transforms.ToTensor(),transforms.Normalize((0.4914, 0.4822, 0.4465), (0.2023, 0.1994, 0.2010))
])# 2. 加載CIFAR-10數據集
train_dataset = datasets.CIFAR10(root='./data',train=True,download=True,transform=train_transform  # 使用增強后的預處理
)test_dataset = datasets.CIFAR10(root='./data',train=False,transform=test_transform  # 測試集不使用增強
)# 3. 創建數據加載器
batch_size = 64
train_loader = DataLoader(train_dataset, batch_size=batch_size, shuffle=True)
test_loader = DataLoader(test_dataset, batch_size=batch_size, shuffle=False)# ===================== 新增:通道注意力模塊(SE模塊) =====================
class ChannelAttention(nn.Module):"""通道注意力模塊(Squeeze-and-Excitation)"""def __init__(self, in_channels, reduction_ratio=16):"""參數:in_channels: 輸入特征圖的通道數reduction_ratio: 降維比例,用于減少參數量"""super(ChannelAttention, self).__init__()# 全局平均池化 - 將空間維度壓縮為1x1,保留通道信息self.avg_pool = nn.AdaptiveAvgPool2d(1)# 全連接層 + 激活函數,用于學習通道間的依賴關系self.fc = nn.Sequential(# 降維:壓縮通道數,減少計算量nn.Linear(in_channels, in_channels // reduction_ratio, bias=False),nn.ReLU(inplace=True),# 升維:恢復原始通道數nn.Linear(in_channels // reduction_ratio, in_channels, bias=False),# Sigmoid將輸出值歸一化到[0,1],表示通道重要性權重nn.Sigmoid())def forward(self, x):"""參數:x: 輸入特征圖,形狀為 [batch_size, channels, height, width]返回:加權后的特征圖,形狀不變"""batch_size, channels, height, width = x.size()# 1. 全局平均池化:[batch_size, channels, height, width] → [batch_size, channels, 1, 1]avg_pool_output = self.avg_pool(x)# 2. 展平為一維向量:[batch_size, channels, 1, 1] → [batch_size, channels]avg_pool_output = avg_pool_output.view(batch_size, channels)# 3. 通過全連接層學習通道權重:[batch_size, channels] → [batch_size, channels]channel_weights = self.fc(avg_pool_output)# 4. 重塑為二維張量:[batch_size, channels] → [batch_size, channels, 1, 1]channel_weights = channel_weights.view(batch_size, channels, 1, 1)# 5. 將權重應用到原始特征圖上(逐通道相乘)return x * channel_weights  # 輸出形狀:[batch_size, channels, height, width]# 4. 定義CNN模型的定義(通道注意力的插入)
class CNN(nn.Module):def __init__(self):super(CNN, self).__init__()  # ---------------------- 第一個卷積塊 ----------------------self.conv1 = nn.Conv2d(3, 32, 3, padding=1)self.bn1 = nn.BatchNorm2d(32)self.relu1 = nn.ReLU()# 新增:插入通道注意力模塊(SE模塊)self.ca1 = ChannelAttention(in_channels=32, reduction_ratio=16)  self.pool1 = nn.MaxPool2d(2, 2)  # ---------------------- 第二個卷積塊 ----------------------self.conv2 = nn.Conv2d(32, 64, 3, padding=1)self.bn2 = nn.BatchNorm2d(64)self.relu2 = nn.ReLU()# 新增:插入通道注意力模塊(SE模塊)self.ca2 = ChannelAttention(in_channels=64, reduction_ratio=16)  self.pool2 = nn.MaxPool2d(2)  # ---------------------- 第三個卷積塊 ----------------------self.conv3 = nn.Conv2d(64, 128, 3, padding=1)self.bn3 = nn.BatchNorm2d(128)self.relu3 = nn.ReLU()# 新增:插入通道注意力模塊(SE模塊)self.ca3 = ChannelAttention(in_channels=128, reduction_ratio=16)  self.pool3 = nn.MaxPool2d(2)  # ---------------------- 全連接層(分類器) ----------------------self.fc1 = nn.Linear(128 * 4 * 4, 512)self.dropout = nn.Dropout(p=0.5)self.fc2 = nn.Linear(512, 10)def forward(self, x):# ---------- 卷積塊1處理 ----------x = self.conv1(x)       x = self.bn1(x)         x = self.relu1(x)       x = self.ca1(x)  # 應用通道注意力x = self.pool1(x)       # ---------- 卷積塊2處理 ----------x = self.conv2(x)       x = self.bn2(x)         x = self.relu2(x)       x = self.ca2(x)  # 應用通道注意力x = self.pool2(x)       # ---------- 卷積塊3處理 ----------x = self.conv3(x)       x = self.bn3(x)         x = self.relu3(x)       x = self.ca3(x)  # 應用通道注意力x = self.pool3(x)       # ---------- 展平與全連接層 ----------x = x.view(-1, 128 * 4 * 4)  x = self.fc1(x)           x = self.relu3(x)         x = self.dropout(x)       x = self.fc2(x)           return x  # 重新初始化模型,包含通道注意力模塊
model = CNN()
model = model.to(device)  # 將模型移至GPU(如果可用)criterion = nn.CrossEntropyLoss()  # 交叉熵損失函數
optimizer = optim.Adam(model.parameters(), lr=0.001)  # Adam優化器# 引入學習率調度器,在訓練過程中動態調整學習率--訓練初期使用較大的 LR 快速降低損失,訓練后期使用較小的 LR 更精細地逼近全局最優解。
# 在每個 epoch 結束后,需要手動調用調度器來更新學習率,可以在訓練過程中調用 scheduler.step()
scheduler = optim.lr_scheduler.ReduceLROnPlateau(optimizer,        # 指定要控制的優化器(這里是Adam)mode='min',       # 監測的指標是"最小化"(如損失函數)patience=3,       # 如果連續3個epoch指標沒有改善,才降低LRfactor=0.5        # 降低LR的比例(新LR = 舊LR × 0.5)
)# 5. 訓練模型(記錄每個 iteration 的損失)
def train(model, train_loader, test_loader, criterion, optimizer, scheduler, device, epochs):model.train()  # 設置為訓練模式# 記錄每個 iteration 的損失all_iter_losses = []  # 存儲所有 batch 的損失iter_indices = []     # 存儲 iteration 序號# 記錄每個 epoch 的準確率和損失train_acc_history = []test_acc_history = []train_loss_history = []test_loss_history = []for epoch in range(epochs):running_loss = 0.0correct = 0total = 0for batch_idx, (data, target) in enumerate(train_loader):data, target = data.to(device), target.to(device)  # 移至GPUoptimizer.zero_grad()  # 梯度清零output = model(data)  # 前向傳播loss = criterion(output, target)  # 計算損失loss.backward()  # 反向傳播optimizer.step()  # 更新參數# 記錄當前 iteration 的損失iter_loss = loss.item()all_iter_losses.append(iter_loss)iter_indices.append(epoch * len(train_loader) + batch_idx + 1)# 統計準確率和損失running_loss += iter_loss_, predicted = output.max(1)total += target.size(0)correct += predicted.eq(target).sum().item()# 每100個批次打印一次訓練信息if (batch_idx + 1) % 100 == 0:print(f'Epoch: {epoch+1}/{epochs} | Batch: {batch_idx+1}/{len(train_loader)} 'f'| 單Batch損失: {iter_loss:.4f} | 累計平均損失: {running_loss/(batch_idx+1):.4f}')# 計算當前epoch的平均訓練損失和準確率epoch_train_loss = running_loss / len(train_loader)epoch_train_acc = 100. * correct / totaltrain_acc_history.append(epoch_train_acc)train_loss_history.append(epoch_train_loss)# 測試階段model.eval()  # 設置為評估模式test_loss = 0correct_test = 0total_test = 0with torch.no_grad():for data, target in test_loader:data, target = data.to(device), target.to(device)output = model(data)test_loss += criterion(output, target).item()_, predicted = output.max(1)total_test += target.size(0)correct_test += predicted.eq(target).sum().item()epoch_test_loss = test_loss / len(test_loader)epoch_test_acc = 100. * correct_test / total_testtest_acc_history.append(epoch_test_acc)test_loss_history.append(epoch_test_loss)# 更新學習率調度器scheduler.step(epoch_test_loss)print(f'Epoch {epoch+1}/{epochs} 完成 | 訓練準確率: {epoch_train_acc:.2f}% | 測試準確率: {epoch_test_acc:.2f}%')# 繪制所有 iteration 的損失曲線plot_iter_losses(all_iter_losses, iter_indices)# 繪制每個 epoch 的準確率和損失曲線plot_epoch_metrics(train_acc_history, test_acc_history, train_loss_history, test_loss_history)return epoch_test_acc  # 返回最終測試準確率# 6. 繪制每個 iteration 的損失曲線
def plot_iter_losses(losses, indices):plt.figure(figsize=(10, 4))plt.plot(indices, losses, 'b-', alpha=0.7, label='Iteration Loss')plt.xlabel('Iteration(Batch序號)')plt.ylabel('損失值')plt.title('每個 Iteration 的訓練損失')plt.legend()plt.grid(True)plt.tight_layout()plt.show()# 7. 繪制每個 epoch 的準確率和損失曲線
def plot_epoch_metrics(train_acc, test_acc, train_loss, test_loss):epochs = range(1, len(train_acc) + 1)plt.figure(figsize=(12, 4))# 繪制準確率曲線plt.subplot(1, 2, 1)plt.plot(epochs, train_acc, 'b-', label='訓練準確率')plt.plot(epochs, test_acc, 'r-', label='測試準確率')plt.xlabel('Epoch')plt.ylabel('準確率 (%)')plt.title('訓練和測試準確率')plt.legend()plt.grid(True)# 繪制損失曲線plt.subplot(1, 2, 2)plt.plot(epochs, train_loss, 'b-', label='訓練損失')plt.plot(epochs, test_loss, 'r-', label='測試損失')plt.xlabel('Epoch')plt.ylabel('損失值')plt.title('訓練和測試損失')plt.legend()plt.grid(True)plt.tight_layout()plt.show()# 訓練模型(復用原有的train函數)
print("開始訓練帶通道注意力的CNN模型...")
final_accuracy = train(model, train_loader, test_loader, criterion, optimizer, scheduler, device, epochs=20)
print(f"訓練完成!最終測試準確率: {final_accuracy:.2f}%")

可視化空間注意力熱力圖

對比conv1,conv2,conv3這三個卷積層

# 可視化空間注意力熱力圖(顯示模型關注的圖像區域)
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 = {}conv_layers = ['conv1', 'conv2', 'conv3']def hook(module, input, output, layer_name):activation_maps[layer_name] = output.cpu()# 為每個卷積層注冊鉤子hook_handles = []for layer_name in conv_layers:layer = getattr(model, layer_name)handle = layer.register_forward_hook(lambda m, i, o, name=layer_name: hook(m, i, o, name))hook_handles.append(handle)# 前向傳播,觸發鉤子outputs = model(images)# 移除所有鉤子for handle in hook_handles: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)# 為每個卷積層創建子圖for layer_name in conv_layers:# 獲取激活圖(對應卷積層的輸出)feature_map = activation_maps[layer_name][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'{layer_name} 注意力熱力圖 - 通道 {channel_idx}')axes[j+1].axis('off')plt.tight_layout()plt.show()# 調用可視化函數
class_names = ['飛機', '汽車', '鳥', '貓', '鹿', '狗', '青蛙', '馬', '船', '卡車']
visualize_attention_map(model, test_loader, device, class_names, num_samples=3)

@浙大疏錦行

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

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

相關文章

《Vuejs設計與實現》第 8 章(掛載與更新)

目錄 8.1 掛載子節點與屬性 8.2 HTML Attributes 與 DOM Properties 8.3 設置元素屬性的正確方式 8.4 處理 class 屬性 8.5 卸載操作 8.6 區分 vnode 類型 8.7 事件處理優化 8.8 事件冒泡與更新時機問題 8.9 子節點的更新 8.10 文本節點和注釋節點 8.11 片段&#xf…

自制操作系統(五、重寫引導部分和C語言的使用)

為了實現其他更多功能,我決定重新寫引導部分的內容 boot.asm ; boot.asm %include "config.inc"setuplen equ 4 bootseg equ 0x07c0 initseg equ def_initseg setupseg equ def_setupseg sysseg equ def_syssegsetupsector equ 2 syssector equ setupse…

口罩佩戴檢測算法AI智能分析網關V4工廠/工業等多場景守護公共衛生安全

一、引言? 在公共衛生安全日益受到重視的當下,口罩佩戴成為預防病毒傳播、保障人員健康的重要措施。為了高效、精準地實現對人員口罩佩戴情況的監測,AI智能分析網關V4口罩檢測方案應運而生。該方案依托先進的人工智能技術與強大的硬件性能,…

【評測】用Flux的圖片文本修改的PS效果

【評測】Flux的圖片文本修改的PS效果 1. 百度圖庫找一張有英文的圖片 2. 打開https://playground.bfl.ai/image/edit上傳圖片 3. 輸入提示詞 “change brarfant to goodbeer” 圖片的文字被修改了

【匯編逆向系列】三、函數調用包含單個參數之float類型-xmm0寄存器,sub,rep,stos,movss,mulss,addss指令

一、匯編代碼 single_float_param:0000000000000060: F3 0F 11 44 24 08 movss dword ptr [rsp8],xmm00000000000000066: 57 push rdi0000000000000067: 48 83 EC 10 sub rsp,10h000000000000006B: 48 8B FC mov …

深入了解UDP套接字:構建高效網絡通信

個人主頁:chian-ocean 文章專欄-NET 深入了解UDP套接字:構建高效網絡通信 個人主頁:chian-ocean文章專欄-NET 前言:UDPUDP 特點:UDP的應用 套接字地址IP地址(Internet Protocol Address)IP地址…

C++課設:實現簡易文件加密工具(凱撒密碼、異或加密、Base64編碼)

名人說:路漫漫其修遠兮,吾將上下而求索。—— 屈原《離騷》 創作者:Code_流蘇(CSDN)(一個喜歡古詩詞和編程的Coder😊) 專欄介紹:《編程項目實戰》 目錄 一、初識文件加密:為什么需要…

Qt/C++學習系列之Excel使用記錄

Qt/C學習系列之Excel使用記錄 前言The process was ended forcefully.解決方式斷點查語句問題 總結 前言 在項目中解析條目達50多條,并且都需要將對應的結果進行顯示。為了將結果顯示的更加清晰,考慮采用QTableWidget進行表格設置,而在使用過…

Mac軟件卸載指南,簡單易懂!

剛和Adobe分手,它卻總在Library里給你寫"回憶錄"?卸載的Final Cut Pro像電子幽靈般陰魂不散?總是會有殘留文件,別慌!這份Mac軟件卸載指南,將用最硬核的方式教你"數字分手術"&#xff0…

并發編程實戰(生產者消費者模型)

在并發編程中使用生產者和消費者模式能夠解決絕大多數的并發問題。該模式通過平衡生產線程和消費線程的工作能力來提高程序整體處理數據的速度。 生產者和消費者模式: 在線程的世界中生產者就是產生數據的線程,而消費者則是消費數據的線程。在多線程開…

力扣hot100---152.乘積最大子數組

給你一個整數數組 nums ,請你找出數組中乘積最大的非空連續子數組(該子數組中至少包含一個數字),并返回該子數組所對應的乘積。 測試用例的答案是一個 32-位 整數。 示例 1: 輸入: nums [2,3,-2,4] 輸出:6解釋: 子數組 [2,3] 有最…

什么是DevOps智能平臺的核心功能?

在數字化轉型的浪潮中,DevOps智能平臺已成為企業提升研發效能、加速產品迭代的核心工具。然而,許多人對“DevOps智能平臺”的理解仍停留在“自動化工具鏈”的表層概念。今天,我們從一個真實場景切入:假設你是某互聯網公司的技術負…

柯尼卡美能達Konica Minolta bizhub 205i打印機信息

基本參數 產品類型:激光數碼復合機顏色類型:黑白涵蓋功能:復印、打印、掃描最大原稿尺寸:A3內存容量:256MB供紙容量:標配 350 頁,最大 1350 頁介質重量:標準紙盒 64-157g/㎡&#xf…

虛擬機與宿主機應用通信配置指南

1. 選擇虛擬機網絡模式 橋接模式 (Bridged) 客戶機獲得獨立局域網IP,與宿主機同網段。 客戶機可直接訪問宿主機IP(如 192.168.1.x)。 Host-Only 模式 僅宿主機與客戶機之間通信,宿主機通常有一個虛擬網卡(如 192.16…

網絡庫libhv介紹

libhv是一個類似于libevent、libev、libuv的跨平臺網絡庫,提供了更易用的接口和更豐富的協議,用來開發TCP/UDP/SSL/HTTP/WebSocket/MQTT 客戶端/服務端。源碼地址:https://github.com/ithewei/libhv,最新發布版本為v1.3.3&#xf…

施耐德特價型號伺服電機VIA0703D31A1022、常見故障

?? ?一、啟動類故障? ?電機無法啟動? ?可能原因?:電源未接通、制動器未釋放、接線錯誤或控制器故障。?解決措施?: 檢查電源線路及斷路器狀態;驗證制動器是否打開(帶制動器型號);核對電機與控制器…

【Redis從入門到精通實戰文章匯總】

📚博客主頁:代碼探秘者 ?專欄:文章正在持續更新ing… ?C語言/C:C(詳細版) 數據結構) 十大排序算法 ?Java基礎:JavaSE基礎 面向對象大合集 JavaSE進階 Java版數據結構JDK新特性…

MCP 技術完全指南:微軟開源項目助力 AI 開發標準化學習

引言 在人工智能快速發展的今天,如何讓 AI 模型與客戶端應用程序之間建立標準化的交互機制,已成為開發者們亟待解決的關鍵問題。微軟近期開源的 mcp-for-beginners 項目,為我們提供了一個系統性學習 Model Context Protocol (MCP) 的絕佳機會…

SQL進階之旅 Day 20:鎖與并發控制技巧

【JDK21深度解密 Day 20】鎖與并發控制技巧 文章簡述 在高并發的數據庫環境中,鎖與并發控制是保障數據一致性和系統穩定性的核心機制。本文作為“SQL進階之旅”系列的第20天,深入探討SQL中的鎖機制、事務隔離級別以及并發控制策略。文章從理論基礎入手…

Qt(part 2)1、Qwindow(菜單欄,工具欄,狀態欄),鉚接部件,核心部件 ,2、添加資源文件 3、對話框

1、Qwindow tips:1,首先為什么創建出的對象基本都是指針形式,個人覺得是對象樹的原因(自動釋放內存),指針來訪問成員函數->的形式。2,菜單欄只能一個的,放窗口基本Set&#xff0c…