Python打卡训练营Day43

DAY 43 复习日

作业:

kaggle找到一个图像数据集,用cnn网络进行训练并且用grad-cam做可视化

数据集地址:Lung Nodule Malignancy 肺结核良恶性判断 

进阶:并拆分成多个文件

import os
import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split
from torch.utils.data import Dataset, DataLoader
from PIL import Image
import torch
from torchvision import transforms
import torch.nn as nn
import torch.optim as optim
import matplotlib.pyplot as plt# 1. 读标签并映射 0/1
df = pd.read_csv('archive/malignancy.csv')# 2. 按 patch_id 划 train/val
ids    = df['NoduleID'].values
labels = df['malignancy'].values
train_ids, val_ids = train_test_split(ids, test_size=0.2, random_state=42, stratify=labels
)
train_df = df[df['NoduleID'].isin(train_ids)].reset_index(drop=True)
val_df   = df[df['NoduleID'].isin(val_ids)].reset_index(drop=True)# 3. Dataset:多页 TIFF 按页读取
class LungTBDataset(Dataset):def __init__(self, tif_path, df, transform=None):self.tif_path = tif_pathself.df = dfself.transform = transformdef __len__(self):return len(self.df)def __getitem__(self, idx):row = self.df.iloc[idx]pid = int(row['NoduleID'])label = int(row['malignancy'])try:with Image.open(self.tif_path) as img:# 检查 pid 是否超出实际帧数total_pages = sum(1 for _ in ImageSequence.Iterator(img))if pid >= total_pages:pid = total_pages - 1  # 取最后一帧img.seek(pid)img = img.convert('RGB')except Exception as e:# 返回黑色占位图img = Image.new('RGB', (224, 224), (0, 0, 0))if self.transform:img = self.transform(img)return img, label# 4. 变换 & DataLoader
transform = transforms.Compose([transforms.Resize((224,224)),transforms.ToTensor(),transforms.Normalize(mean=[0.485,0.456,0.406],std =[0.229,0.224,0.225])
])
train_ds = LungTBDataset('archive/ct_tiles.tif', train_df, transform)
val_ds   = LungTBDataset('archive/ct_tiles.tif',   val_df, transform)
train_loader = DataLoader(train_ds, batch_size=16, shuffle=True,  num_workers=0, pin_memory=True)
val_loader   = DataLoader(val_ds,   batch_size=16, shuffle=False, num_workers=0, pin_memory=True)# 5. 定义简单 CNN(3层卷积 + 全连接)
class SimpleCNN(nn.Module):def __init__(self):super(SimpleCNN, self).__init__()# 卷积层self.conv1 = nn.Sequential(nn.Conv2d(3, 32, kernel_size=3, padding=1),nn.ReLU(inplace=True),nn.MaxPool2d(2)  # 224->112)self.conv2 = nn.Sequential(nn.Conv2d(32, 64, kernel_size=3, padding=1),nn.ReLU(inplace=True),nn.MaxPool2d(2)  # 112->56)# 最后一层卷积,用于 Grad-CAMself.conv3 = nn.Sequential(nn.Conv2d(64, 128, kernel_size=3, padding=1),nn.ReLU(inplace=True),nn.MaxPool2d(2)  # 56->28)# 全连接分类器self.fc = nn.Sequential(nn.Flatten(),nn.Linear(128 * 28 * 28, 256),nn.ReLU(inplace=True),nn.Linear(256, 2))def forward(self, x):x = self.conv1(x)x = self.conv2(x)x = self.conv3(x)      # 保留这一层的输出作 CAMx = self.fc(x)return xdevice = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
model = SimpleCNN().to(device)criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(model.parameters(), lr=1e-4)# 6. 训练 + 验证循环
num_epochs = 5
for epoch in range(num_epochs):# 训练model.train()running_loss = 0for imgs, labs in train_loader:imgs, labs = imgs.to(device), labs.to(device)optimizer.zero_grad()outputs = model(imgs)loss    = criterion(outputs, labs)loss.backward()optimizer.step()running_loss += loss.item() * imgs.size(0)epoch_loss = running_loss / len(train_ds)# 验证model.eval()correct = 0with torch.no_grad():for imgs, labs in val_loader:imgs, labs = imgs.to(device), labs.to(device)preds = model(imgs).argmax(dim=1)correct += (preds == labs).sum().item()val_acc = correct / len(val_ds)print(f'Epoch {epoch+1}/{num_epochs}  Loss={epoch_loss:.4f}  ValAcc={val_acc:.4f}')# 7. 简易 Grad-CAM
class GradCAM:def __init__(self, model, target_conv):self.model = modelself.target_conv = target_convself.grad    = Noneself.activation = None# 注册 hooktarget_conv.register_forward_hook(self._forward)target_conv.register_backward_hook(self._backward)def _forward(self, module, inp, outp):self.activation = outp.detach()def _backward(self, module, grad_in, grad_out):self.grad = grad_out[0].detach()def __call__(self, x, class_idx=None):self.model.zero_grad()out = self.model(x)if class_idx is None:class_idx = out.argmax(dim=1).item()loss = out[0, class_idx]loss.backward()# 计算权重weights = self.grad.mean(dim=(2,3))  # (1,C)cam = (weights.view(-1,1,1) * self.activation[0]).sum(dim=0)cam = torch.relu(cam)cam -= cam.min()cam /= cam.max()return cam.cpu().numpy()# 8. 随机选一张验证图做可视化
model.eval()
imgs, labs = next(iter(val_loader))
img, lab = imgs[0:1].to(device), labs[0].item()# 以 conv3 的最后 Conv2d 为 target
# conv3 是 Sequential,取其中的第0层 Conv2d
target_layer = model.conv3[0]
gradcam = GradCAM(model, target_layer)
heatmap = gradcam(img)  # (28,28)# 上采样到 224×224
heatmap = np.uint8(255 * heatmap)
heatmap = Image.fromarray(heatmap).resize((224,224), resample=Image.BILINEAR)
heatmap = np.array(heatmap) / 255.0# 反归一化 & 可视化叠加
inv_norm = transforms.Normalize(mean=[-0.485/0.229, -0.456/0.224, -0.406/0.225],std =[1/0.229,       1/0.224,       1/0.225]
)
img_show = inv_norm(img[0]).permute(1,2,0).cpu().numpy()
img_show = np.clip(img_show, 0, 1)plt.figure(figsize=(8,4))
plt.subplot(1,2,1)
plt.imshow(img_show)
plt.title(f'Label={lab}')
plt.axis('off')plt.subplot(1,2,2)
plt.imshow(img_show, alpha=0.6)
plt.imshow(heatmap, cmap='jet', alpha=0.4)
plt.title('Grad-CAM')
plt.axis('off')
plt.tight_layout()
plt.show()

代码没问题但跑的很慢不知道啥原因。

浙大疏锦行-CSDN博客

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.pswp.cn/diannao/85493.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

悲观锁与乐观锁:并发编程中的两种核心控制策略详解

在并发编程中,悲观锁和乐观锁是两种不同的并发控制策略,用于解决多个线程或进程对共享资源的并发访问问题。下面将详细介绍它们的概念、实现方式以及优缺点。 悲观锁 概念 悲观锁认为在并发环境下,多个线程或进程对共享资源的访问大概率会发…

python 如何写4或5的表达式

python写4或5的表达式的方法: python中和是用“and”语句,或是用“or”语句。那么4或5的表达式为“4 or 5” 具体示例如下: 执行结果:

麻省理工新突破:家庭场景下机器人实现精准控制,real-to-sim-to-real学习助力

麻省理工学院电气工程与计算机科学系Pulkit Agrawal教授,介绍了一种新方法,可以让机器人在扫描的家庭环境模拟中接受训练,为任何人都可以实现定制的家庭自动化铺平了道路。 本文将探讨通过Franka机器人在虚拟环境中训练的特点,研…

Linux程序管理练习题

Linux程序管理100题 一、Linux程序与进程(1-15) 程序、进程、线程的本质区别是什么? 答案:程序是静态指令集,进程是运行中的程序实例,线程是进程内的执行单元 进程的并发性和交往性体现在哪些方面&#xf…

虚幻基础:模型

能帮到你的话,就给个赞吧 😘 文章目录 资源模型:骨架/骨骼模型动画:一系列姿势补帧:只需设定关键姿势,则系统在关键帧姿势之间自动生成动画。姿势的变换:即骨骼的变换 动画蓝图:执行…

《Discuz! X3.5开发从入门到生态共建》第1章 Discuz! 的前世今生-优雅草卓伊凡

《Discuz! X3.5开发从入门到生态共建》第1章 Discuz! 的前世今生-优雅草卓伊凡 第一节 从康盛创想到腾讯收购:PC时代的辉煌 1.1 Discuz! 的诞生:康盛创想的开源梦想 2001年,中国互联网正处于萌芽阶段,个人网站和论坛开始兴起。…

如何打包conda环境从一台电脑到另外一台电脑

在 Ubuntu 系统下,使用的是 VSCode 和 Conda 环境开发项目,想要将整个 Conda 环境从一台电脑迁移到另一台电脑,可以通过以下步骤来实现打包和导入: ✅ 一、在原电脑上导出 Conda 环境 1. 激活你要导出的环境 conda activate you…

2025GDCPC广东省赛游记(附赛时代码)

我觉得算是给swan的自证之旅画上一个句号吧...说实话HDU给我带来的不止是排位上的压力,更多的是对自己能力的怀疑,特别是pluto不明说但是我很清楚的看不起(没有责备本人的意思),evil和jxj之类的总感觉看到我就是看小丑…

MySQL 修改数据的全链路流程

MySQL 修改数据的全链路流程(InnoDB) 全链路流程图关键步骤详解1. 建立连接阶段2.SQL解析与优化3. InnoDB内存操作4. 日志记录过程5. 二阶段提交(2PC) 磁盘同步机制1. Redo Log刷盘策略(innodb_flush_log_at_trx_commi…

兰亭妙微十六年高水准交互设计公司

北京兰亭妙微(蓝蓝设计)成立于 2008 年(前身为设计工作室,2011 年正式注册),由清华团队主创,专注软件和互联网 UI/UE 设计开发 16 年。我们提供从需求调研、界面设计到开发落地的全流程服务&…

【脚本 完全参数化的通用 APT 源配置方案-Debian/Ubuntu】

通过脚本在 Debian/Ubuntu 系统上一键切换 APT 源 如Dockerfile中 使用某个源(比如 aliyun) 假设你的目录结构是: . ├── Dockerfile └── switch-apt-source.shFROM ubuntu:22.04# 把脚本拷贝到镜像中 COPY switch-apt-source.sh /us…

学习日记-day20-6.1

完成目标&#xff1a; 知识点&#xff1a; 1.集合_Collections集合工具类 方法:static <T> boolean addAll(Collection<? super T> c, T... elements)->批量添加元素 static void shuffle(List<?> list) ->将集合中的元素顺序打乱static <T>…

个人总结八股文之-基础篇(持续更新)

一、集合的分类有哪些&#xff1f; Java集合框架主要分为两大类&#xff1a;Collection和Map Collection主要分为以下三类&#xff1a; List&#xff1a;有序集合&#xff0c;允许重复元素。常见的实现类有ArrayList、LinkedList和Vector。 Set&#xff1a;无序集合&#xf…

leetcode hot100刷题日记——35.子集

解答&#xff1a; 方法一&#xff1a;选or不选的dfs&#xff08;输入视角&#xff09; 思路&#xff1a;[1,2,3]的全部子集可以看成是对数组的每一位数字做选择。 eg.空集就是一个数字都不选&#xff0c;[1,2]就是1&#xff0c;2选&#xff0c;3不选。 class Solution { pub…

华为OD机试真题——生成哈夫曼树(2025A卷:100分)Java/python/JavaScript/C/C++/GO六种最佳实现

2025 A卷 100分 题型 本文涵盖详细的问题分析、解题思路、代码实现、代码详解、测试用例以及综合分析; 并提供Java、python、JavaScript、C++、C语言、GO六种语言的最佳实现方式! 本文收录于专栏:《2025华为OD真题目录+全流程解析/备考攻略/经验分享》 华为OD机试真题《生成…

房屋租赁系统 Java+Vue.js+SpringBoot,包括房屋类型、房屋信息、预约看房、合同信息、房屋报修、房屋评价、房主管理模块

房屋租赁系统 JavaVue.jsSpringBoot&#xff0c;包括房屋类型、房屋信息、预约看房、合同信息、房屋报修、房屋评价、房主管理模块 百度云盘链接&#xff1a;https://pan.baidu.com/s/1KmwOFzN9qogyaLQei3b6qw 密码&#xff1a;l2yn 摘 要 社会的发展和科学技术的进步&#xf…

Unity 中 Update、FixedUpdate 和 LateUpdate 的区别及使用场景

在Unity开发中,Update、FixedUpdate 和 LateUpdate 是生命周期函数中最常见也最容易混淆的一组。 一、调用时机 方法名调用频率调用时机说明Update()每帧调用一次跟随帧率(帧率高则调用频率高)FixedUpdate()固定时间间隔调用默认每 0.02 秒执行一次LateUpdate()每帧调用一次…

Docker镜像之windows系统

https://github.com/dockur/windows 在 Docker 容器中运行 Windows 功能 ISO 下载器KVM 加速基于网页的查看器 使用方法 启动容器并通过浏览器连接到端口 8006。整个安装过程将全自动完成&#xff0c;无需手动干预。当桌面界面出现时&#xff0c;表示 Windows 安装已完成&a…

C# 用户控件(User Control)详解:创建、使用与最佳实践

在C#应用程序开发中&#xff0c;用户控件&#xff08;User Control&#xff09;是一种强大的工具&#xff0c;它允许开发者将多个标准控件组合成一个可复用的自定义组件。无论是Windows Forms还是WPF&#xff0c;用户控件都能显著提高UI开发的效率&#xff0c;减少重复代码&…

pikachu靶场通关笔记09 XSS关卡05-DOM型XSS-X

目录 一、XSS 二、DOM型XSS 三、源码分析 1、打开DOM-X型XSS关卡 2、XSS探测 3、源码分析 四、渗透实战 1、Payload1 2、Payload2 3、Payload3 五、DOM型XSS与DOM-X型XSS区别 本系列为通过《pikachu靶场通关笔记》的XSS攻击关卡(共10关&#xff09;渗透集合&#xf…