核心内容摘要
动态修改内核 / 模块代码
浙大疏锦行知识点回顾
回调函数# 定义一个回调函数 def handle_result(result): 处理计算结果的回调函数 print(f计算结果是: {result}) # 定义一个接受回调函数的函数 def calculate(a, b, callback): # callback是一个约定俗成的参数名 这个函数接受两个数值和一个回调函数用于处理计算结果。
执行计算并调用回调函数 result a b callback(result) # 在计算完成后调用回调函数 # 使用回调函数 calculate(3, 5, handle_result) # 输出: 计算结果是:
lambda 函数# 定义匿名函数计算平方 square lambda x: x ** 2 # 调用 print(square(
) # 输出:
hook 函数的模块钩子和张量钩子import torch import torch.nn as nn import numpy as np import matplotlib.pyplot as plt # 设置随机种子保证结果可复现 torch.manual_seed(
np.random.seed(
import torch import torch.nn as nn # 定义一个简单的卷积神经网络模型 class SimpleModel(nn.Module): def __init__(self): super(SimpleModel, self).__init__() # 定义卷积层输入通道1输出通道2卷积核3x3填充1保持尺寸不变 self.conv nn.Conv2d(1, 2, kernel_size3, padding
# 定义ReLU激活函数 self.relu nn.ReLU() # 定义全连接层输入特征2*4*4输出10分类 self.fc nn.Linear(2 * 4 * 4,
def forward(self, x): # 卷积操作 x self.conv(x) # 激活函数 x self.relu(x) # 展平为一维向量准备输入全连接层 x x.view(-1, 2 * 4 *
# 全连接分类 x self.fc(x) return x # 创建模型实例 model SimpleModel() # 创建一个列表用于存储中间层的输出 conv_outputs [] # 定义前向钩子函数 - 用于在模型前向传播过程中获取中间层信息 def forward_hook(module, input, output): 前向钩子函数会在模块每次执行前向传播后被自动调用 参数: module: 当前应用钩子的模块实例 input: 传递给该模块的输入张量元组 output: 该模块产生的输出张量 print(f钩子被调用模块类型: {type(module)}) print(f输入形状: {input[0].shape}) # input是一个元组对应 (image, label) print(f输出形状: {output.shape}) # 保存卷积层的输出用于后续分析 # 使用detach()避免追踪梯度防止内存泄漏 conv_outputs.append(output.detach()) # 在卷积层注册前向钩子 # register_forward_hook返回一个句柄用于后续移除钩子 hook_handle model.conv.register_forward_hook(forward_hook) # 创建一个随机输入张量 (批次大小1, 通道1, 高度4, 宽度
x torch.randn(1, 1, 4,
# 执行前向传播 - 此时会自动触发钩子函数 output model(x) # 释放钩子 - 重要防止在后续模型使用中持续调用钩子造成意外行为或内存泄漏 hook_handle.remove() # # 打印中间层输出结果 # if conv_outputs: # print(f\n卷积层输出形状: {conv_outputs[0].shape}) # print(f卷积层输出值示例: {conv_outputs[0][0, 0, :, :]}) # 定义一个存储梯度的列表 conv_gradients [] # 定义反向钩子函数 def backward_hook(module, grad_input, grad_output): # 模块当前应用钩子的模块 # grad_input模块输入的梯度 # grad_output模块输出的梯度 print(f反向钩子被调用模块类型: {type(module)}) print(f输入梯度数量: {len(grad_input)}) print(f输出梯度数量: {len(grad_output)}) # 保存梯度供后续分析 conv_gradients.append((grad_input, grad_output)) # 在卷积层注册反向钩子 hook_handle model.conv.register_backward_hook(backward_hook) # 创建一个随机输入并进行前向传播 x torch.randn(1, 1, 4, 4, requires_gradTrue) output model(x) # 定义一个简单的损失函数并进行反向传播 loss output.sum() loss.backward() # 释放钩子 hook_handle.remove()
Grad-CAM 的示例import torch import torch.nn as nn import torch.nn.functional as F import torchvision import torchvision.transforms as transforms import numpy as np import matplotlib.pyplot as plt from PIL import Image # 设置随机种子确保结果可复现 # 在深度学习中随机种子可以让每次运行代码时模型初始化参数、数据打乱等随机操作保持一致方便调试和对比实验结果 torch.manual_seed(
np.random.seed(
# 加载CIFAR-10数据集 # 定义数据预处理步骤先将图像转换为张量再进行归一化操作 # 归一化的均值和标准差是(
5,
5,
0.
这里的均值和标准差是对CIFAR-10数据集的经验值使得数据分布更有利于模型训练 transform transforms.Compose([ transforms.ToTensor(), transforms.Normalize((
5,
5,
0.
, (
5,
5,
0.
) ]) # 加载测试集指定数据集根目录为./data设置为测试集trainFalse如果数据不存在则下载downloadTrue并应用上述定义的预处理 testset torchvision.datasets.CIFAR10( root./data, trainFalse, downloadTrue, transformtransform ) # 定义类别名称CIFAR-10数据集包含这10个类别 classes (飞机, 汽车, 鸟, 猫, 鹿, 狗, 青蛙, 马, 船, 卡车) # 定义一个简单的CNN模型 class SimpleCNN(nn.Module): def __init__(self): super(SimpleCNN, self).__init__() # 第一个卷积层输入通道为3彩色图像输出通道为32卷积核大小为3x3填充为1以保持图像尺寸不变 self.conv1 nn.Conv2d(3, 32, kernel_size3, padding
# 第二个卷积层输入通道为32输出通道为64卷积核大小为3x3填充为1 self.conv2 nn.Conv2d(32, 64, kernel_size3, padding
# 第三个卷积层输入通道为64输出通道为128卷积核大小为3x3填充为1 self.conv3 nn.Conv2d(64, 128, kernel_size3, padding
# 最大池化层池化核大小为2x2步长为2用于下采样减少数据量并提取主要特征 self.pool nn.MaxPool2d(2,
# 第一个全连接层输入特征数为128 * 4 * 4经过前面卷积和池化后的特征维度输出为512 self.fc1 nn.Linear(128 * 4 * 4,
# 第二个全连接层输入为512输出为10对应CIFAR-10的10个类别 self.fc2 nn.Linear(512,
def forward(self, x): # 第一个卷积层后接ReLU激活函数和最大池化操作经过池化后图像尺寸变为原来的一半这里输出尺寸变为16x16 x self.pool(F.relu(self.conv1(x))) # 第二个卷积层后接ReLU激活函数和最大池化操作输出尺寸变为8x8 x self.pool(F.relu(self.conv2(x))) # 第三个卷积层后接ReLU激活函数和最大池化操作输出尺寸变为4x4 x self.pool(F.relu(self.conv3(x))) # 将特征图展平为一维向量以便输入到全连接层 x x.view(-1, 128 * 4 *
# 第一个全连接层后接ReLU激活函数 x F.relu(self.fc1(x)) # 第二个全连接层输出分类结果 x self.fc2(x) return x # 初始化模型 model SimpleCNN() print(模型已创建) # 如果有GPU则使用GPU将模型转移到对应的设备上 device torch.device(cuda:0 if torch.cuda.is_available() else cpu) model model.to(device) # 训练模型简化版实际应用中应该进行完整训练 def train_model(model, epochs
: # 加载训练集指定数据集根目录为./data设置为训练集trainTrue如果数据不存在则下载downloadTrue并应用前面定义的预处理 trainset torchvision.datasets.CIFAR10( root./data, trainTrue, downloadTrue, transformtransform ) # 创建数据加载器设置批量大小为64打乱数据顺序shuffleTrue使用2个线程加载数据 trainloader torch.utils.data.DataLoader( trainset, batch_size64, shuffleTrue, num_workers2 ) # 定义损失函数为交叉熵损失用于分类任务 criterion nn.CrossEntropyLoss() # 定义优化器为Adam用于更新模型参数学习率设置为
001 optimizer torch.optim.Adam(model.parameters(), lr
0.