全局平均池化(Global Average Pooling)
1. 导入库和设备配置
import torch.nn as nn
import torch.nn.functional as F
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
- import torch.nn as nn :导入PyTorch的神经网络模块,用于构建神经网络层。
- import torch.nn.functional as F :导入PyTorch的函数式接口,包含激活函数等常用功能。
- device = torch.device(...) :检测是否有可用的CUDA(GPU)设备,如果有则使用 cuda:0 (第一个GPU),否则使用CPU。
2. 定义神经网络类
class Net(nn.Module):
def __init__(self):
super(Net, self).__init__()
self.conv1 = nn.Conv2d(3, 16, 5)
self.pool1 = nn.MaxPool2d(2, 2)
self.conv2 = nn.Conv2d(16, 36, 5)
self.pool2 = nn.MaxPool2d(2, 2)
#self.fc1 = nn.Linear(16 * 5 * 5, 120)
self.aap=nn.AdaptiveAvgPool2d(1)
self.fc3 = nn.Linear(36, 10)
- class Net(nn.Module) :定义一个名为 Net 的类,继承自 nn.Module ,这是所有PyTorch神经网络模块的基类。
- __init__ 方法是类的构造函数:
- super(Net, self).__init__() :调用父类的构造函数进行初始化。
- self.conv1 = nn.Conv2d(3, 16, 5) :定义第一个卷积层,输入通道数为3(通常对应RGB图像),输出通道数为16,卷积核大小为5x5。
- self.pool1 = nn.MaxPool2d(2, 2) :定义第一个最大池化层,池化核大小为2x2。
- self.conv2 = nn.Conv2d(16, 36, 5) :第二个卷积层,输入通道数为16,输出通道数为36,卷积核大小为5x5。
- self.pool2 = nn.MaxPool2d(2, 2) :第二个最大池化层。
- 注释掉的 self.fc1 = nn.Linear(16 * 5 * 5, 120) 原本是全连接层,但由于采用了全局平均池化,这里不再需要。
- self.aap=nn.AdaptiveAvgPool2d(1) :定义自适应平均池化层,将输出尺寸调整为1x1,实现全局平均池化效果。
- self.fc3 = nn.Linear(36, 10) :定义全连接层,输入维度为36(上一层输出通道数),输出维度为10(对应分类任务的类别数,比如CIFAR - 10数据集有10个类别)。
3. 定义前向传播函数
def forward(self, x):
x = self.pool1(F.relu(self.conv1(x)))
x = self.pool2(F.relu(self.conv2(x)))
x = self.aap(x)
x = x.view(x.shape[0], -1)
x = self.fc3(x)
return x
- forward 方法定义了数据在网络中的流动方向:
- x = self.pool1(F.relu(self.conv1(x))) :输入数据 x 先经过第一个卷积层 conv1 ,然后使用ReLU激活函数,最后通过第一个最大池化层 pool1 。
- x = self.pool2(F.relu(self.conv2(x))) :经过第二个卷积层、ReLU激活和第二个最大池化层。
- x = self.aap(x) :通过全局平均池化层。
- x = x.view(x.shape[0], -1) :将池化后的结果展平, x.shape[0] 表示批量大小, -1 表示自动计算其他维度。
- x = self.fc3(x) :通过全连接层。
- return x :返回最终的输出结果。
4. 实例化网络并转移到指定设备
net = Net()
net=net.to(device)
- net = Net() :创建一个 Net 类的实例 net ,即构建好的神经网络模型。
- net=net.to(device) :将神经网络模型转移到之前定义的设备(GPU或CPU)上。
像在Keras中那样,显示PyTorch模型各层的参数信息
1. 导入库
import collections
import torch
这里导入了 collections 和 torch 库。 collections 库用于处理容器数据类型,在代码中用来创建有序字典; torch 是PyTorch的核心库,用于构建和操作神经网络。
2. 定义主函数 paras_summary
def paras_summary(input_size, model):
paras_summary 函数接受两个参数:
- input_size :表示输入数据的形状,用于模拟数据传入模型,以便获取各层的输入输出形状。
- model :需要分析参数的PyTorch模型。
3. 定义内部函数 register_hook
def register_hook(module):
def hook(module, input, output):
class_name = str(module.__class__).split('.')[-1].split("'")[0]
module_idx = len(summary)
m_key = '%s-%i' % (class_name, module_idx+1)
summary[m_key] = collections.OrderedDict()
summary[m_key]['input_shape'] = list(input[0].size())
summary[m_key]['input_shape'][0] = -1
summary[m_key]['output_shape'] = list(output.size())
summary[m_key]['output_shape'][0] = -1
params = 0
if hasattr(module, 'weight'):
params += torch.prod(torch.LongTensor(list(module.weight.size())))
if module.weight.requires_grad:
summary[m_key]['trainable'] = True
else:
summary[m_key]['trainable'] = False
if hasattr(module, 'bias'):
params += torch.prod(torch.LongTensor(list(module.bias.size())))
summary[m_key]['nb_params'] = params
- register_hook 函数用于为模型的每一层注册一个钩子(hook)函数,这个钩子函数会在每次前向传播经过该层时被调用。
- 内部的 hook 函数是实际执行获取参数信息操作的函数:
- 首先获取当前层的类名 class_name ,以及该层在模型中的索引 module_idx ,并生成一个唯一的键 m_key 用于在字典中标识该层。
- 接着创建一个有序字典 summary[m_key] ,并记录该层的输入形状 input_shape 和输出形状 output_shape ,将batch维度设为 -1 表示可变。
- 然后计算该层的参数数量 params :
- 如果该层有 weight 属性,计算权重参数的数量,并根据 weight.requires_grad 判断参数是否可训练。
- 如果该层有 bias 属性,计算偏置参数的数量。
- 最后将参数总数记录在 summary[m_key]['nb_params']