目录
一、前言
二、完成情况
2.1 特征图保存方法
2.1.1 定义网络模型
2.1.2 定义保存特征图的钩子函数
2.1.3 为模型层注册钩子
2.1.4 运行模型并检查特征图
2.2 实验情况
三、下周计划
一、前言
本周的7月11日~7月14日参加了机器培训的学习讨论会,对很多概念有了更深的理解。同时,在空闲时间利用笔记本跑了小批量的数据。
二、完成情况
2.1 特征图保存方法
在深度学习领域,在网络训练过程中生成每一阶段的特征图是一个常见的需求。
2.1.1 定义网络模型
首先,需要确定我们当前使用的网络模型,不同的模型结果具有不同的层数和层类型,这将影响特征图的生成。
这里以InversionNet为例:
class InversionNet(nn.Module):def __init__(self, dim1=32, dim2=64, dim3=128, dim4=256, dim5=512, sample_spatial=1.0, **kwargs):super(InversionNet, self).__init__()self.convblock1 = ConvBlock(5, dim1, kernel_size=(7, 1), stride=(2, 1), padding=(3, 0))self.convblock2_1 = ConvBlock(dim1, dim2, kernel_size=(3, 1), stride=(2, 1), padding=(1, 0))self.convblock2_2 = ConvBlock(dim2, dim2, kernel_size=(3, 1), padding=(1, 0))self.convblock3_1 = ConvBlock(dim2, dim2, kernel_size=(3, 1), stride=(2, 1), padding=(1, 0))self.convblock3_2 = ConvBlock(dim2, dim2, kernel_size=(3, 1), padding=(1, 0))self.convblock4_1 = ConvBlock(dim2, dim3, kernel_size=(3, 1), stride=(2, 1), padding=(1, 0))self.convblock4_2 = ConvBlock(dim3, dim3, kernel_size=(3, 1), padding=(1, 0))self.convblock5_1 = ConvBlock(dim3, dim3, stride=2)self.convblock5_2 = ConvBlock(dim3, dim3)self.convblock6_1 = ConvBlock(dim3, dim4, stride=2)self.convblock6_2 = ConvBlock(dim4, dim4)self.convblock7_1 = ConvBlock(dim4, dim4, stride=2)self.convblock7_2 = ConvBlock(dim4, dim4)self.convblock8 = ConvBlock(dim4, dim5, kernel_size=(8, ceil(70 * sample_spatial / 8)), padding=0)self.deconv1_1 = DeconvBlock(dim5, dim5, kernel_size=5)self.deconv1_2 = ConvBlock(dim5, dim5)self.deconv2_1 = DeconvBlock(dim5, dim4, kernel_size=4, stride=2, padding=1)self.deconv2_2 = ConvBlock(dim4, dim4)self.deconv3_1 = DeconvBlock(dim4, dim3, kernel_size=4, stride=2, padding=1)self.deconv3_2 = ConvBlock(dim3, dim3)self.deconv4_1 = DeconvBlock(dim3, dim2, kernel_size=4, stride=2, padding=1)self.deconv4_2 = ConvBlock(dim2, dim2)self.deconv5_1 = DeconvBlock(dim2, dim1, kernel_size=4, stride=2, padding=1)self.deconv5_2 = ConvBlock(dim1, dim1)self.deconv6 = ConvBlock_Tanh(dim1, 1)def forward(self, x):# Encoder Partx = self.convblock1(x) # (None, 32, 500, 70)x = self.convblock2_1(x) # (None, 64, 250, 70)x = self.convblock2_2(x) # (None, 64, 250, 70)x = self.convblock3_1(x) # (None, 64, 125, 70)x = self.convblock3_2(x) # (None, 64, 125, 70)x = self.convblock4_1(x) # (None, 128, 63, 70)x = self.convblock4_2(x) # (None, 128, 63, 70)x = self.convblock5_1(x) # (None, 128, 32, 35)x = self.convblock5_2(x) # (None, 128, 32, 35)x = self.convblock6_1(x) # (None, 256, 16, 18)x = self.convblock6_2(x) # (None, 256, 16, 18)x = self.convblock7_1(x) # (None, 256, 8, 9)x = self.convblock7_2(x) # (None, 256, 8, 9)x = self.convblock8(x) # (None, 512, 1, 1)# Decoder Part Vmodelx = self.deconv1_1(x) # (None, 512, 5, 5)x = self.deconv1_2(x) # (None, 512, 5, 5)x = self.deconv2_1(x) # (None, 256, 10, 10)x = self.deconv2_2(x) # (None, 256, 10, 10)x = self.deconv3_1(x) # (None, 128, 20, 20)x = self.deconv3_2(x) # (None, 128, 20, 20)x = self.deconv4_1(x) # (None, 64, 40, 40)x = self.deconv4_2(x) # (None, 64, 40, 40)x = self.deconv5_1(x) # (None, 32, 80, 80)x = self.deconv5_2(x) # (None, 32, 80, 80)x = F.pad(x, [-5, -5, -5, -5], mode="constant", value=0) # (None, 32, 70, 70) 125, 100x = self.deconv6(x) # (None, 1, 70, 70)return x
2.1.2 定义保存特征图的钩子函数
接下来,定义特征图保存函数。PyTorch提供了register_forward_hook
方法,允许在模型的特定层上注册一个回调函数,该函数将在该层的前向传播之后被调用。因此,我们可以利用这个机制来自动保存每个阶段的特征图。钩子方法(hook method)是回调函数(callback function)的一种,它相当于一个监测器,在消息传递的过程中,捕获自己感兴趣的内容,然后去处理。
import torch # 全局的字典用于存储特征图
feature_maps = {} def save_feature_map(module, input, output): # 'module' 是注册了钩子的模块(在这里以一个convblock为例) # 'input' 是该模块的输入 # 'output' 是该模块的输出,即我们要保存的特征图 # 我们需要一种方式来唯一标识每个convblock,这里我们简单地使用模块的名称 key = module.__class__.__name__ if hasattr(module, '__class__') else type(module).__name__ if key.startswith('ConvBlock'): # 假设所有convblock类的名称都以'ConvBlock'开头 feature_maps[key] = output.detach().cpu() # 保存特征图到CPU # 注意:上面的key获取方式是基于假设的,需要根据实际的convblock类名来调整
2.1.3 为模型层注册钩子
然后,需要再模型初始化初始化或某个适当的地方,为这些convblock
注册钩子。这里为所有的convblock层注册钩子,也可以单独注册。
# 一个方法来注册所有ConvBlock的钩子
def register_ConvBlock_hooks(self):for name, module in self._modules.items():if isinstance(module, convblock):handle = module.register_forward_hook(self.save_feature_map)self.hook_handles.append((name, handle))
2.1.4 运行模型并检查特征图
在训练循环中,除了正常的梯度计算和参数更新外,还需要确保特征图保存机制被正确触发。在每个epoch或每个batch之后,根据需求保存特征图。
def save_feature_map(self, module, input, output):# 打印输出尺寸作为示例print(f"Feature map shape from {module._get_name()}: {output.shape}")# 假设我们想要保存第一个批次和第一个通道的特征图batch_idx, channel_idx = 0, 0# 提取特征图的一个批次和一个通道feature_map = output[batch_idx, channel_idx, :, :]# 将tensor从GPU(如果有)移动到CPU,并转换为numpy数组feature_map_np = feature_map.detach().cpu().numpy()# 归一化特征图到[0, 1]feature_map_np = (feature_map_np - feature_map_np.min()) / (feature_map_np.max() - feature_map_np.min())# 使用PIL或其他库保存图像# 由于PIL期望的是[0, 255]的整数,需要将归一化后的图像乘以255并转换为uint8image = Image.fromarray((feature_map_np * 255).astype(np.uint8))# 为模块创建一个唯一的名称(这里只是示例)module_name = module.__class__.__name__ + "_" + str(id(module))# 保存图像image_path = f"{module_name}_feature_map.png"image.save(image_path)print(f"Saved feature map to {image_path}")
目前只能生成灰度图像,在生成彩色图片时遇到问题,报错如下所示,下周解决该问题。
2.2 实验情况
在本周对设计的实验进行了验证,在验证过程中发现选择合适的学习率很重要,指标相差也很大。
目前的网络结构效果在5000的 CurveFaultA 数据集上优于InversionNet,但是不知道大数据集上表现如何。
损失函数的表现在小数据集上不太明显,部分指标较好,但是部分指标不好。
三、下周计划
-
利用工作站完成实验;
-
验证特征图保存方法是否适用;
-
了解高级优化算法;