1. 基于PyTorch的模型参数统计与FLOPs计算
任务目标
为后续模型裁剪建立量化基准:编写一个可复用的PyTorch脚本,统计给定CNN模型的总参数量、可训练参数量以及理论FLOPs(浮点运算次数)。本案例以轻量级CNN(类似VGG风格的简化网络)为例,输出结构化的统计报告。
环境与依赖
- Python 3.8+
- PyTorch 1.12+(含
torchvision,用于加载预训练模型或自定义模型) - thop库(用于FLOPs计算):
pip install thop
关键完整代码
import torch
import torch.nn as nn
from thop import profile, clever_format
# ---------- 1. 定义示例CNN模型(可替换为任意nn.Module) ----------
class SimpleCNN(nn.Module):
def __init__(self, num_classes=10):
super(SimpleCNN, self).__init__()
self.features = nn.Sequential(
nn.Conv2d(3, 32, kernel_size=3, padding=1), # 输出: 32x32x32
nn.ReLU(inplace=True),
nn.MaxPool2d(2), # 输出: 32x16x16
nn.Conv2d(32, 64, kernel_size=3, padding=1), # 输出: 64x16x16
nn.ReLU(inplace=True),
nn.MaxPool2d(2), # 输出: 64x8x8
)
self.classifier = nn.Sequential(
nn.Flatten(),
nn.Linear(64 * 8 * 8, 128),
nn.ReLU(inplace=True),
nn.Linear(128, num_classes)
)
def forward(self, x):
x = self.features(x)
x = self.classifier(x)
return x
# ---------- 2. 参数统计函数 ----------
def count_parameters(model):
"""返回总参数量与可训练参数量(单位:百万)"""
total = sum(p.numel() for p in model.parameters())
trainable = sum(p.numel() for p in model.parameters() if p.requires_grad)
return total / 1e6, trainable / 1e6
# ---------- 3. FLOPs统计函数 ----------
def compute_flops(model, input_size=(1, 3, 32, 32)):
"""使用thop计算FLOPs与参数量(thop内部也统计参数)"""
device = next(model.parameters()).device
dummy_input = torch.randn(input_size).to(device)
flops, params = profile(model, inputs=(dummy_input,), verbose=False)
return flops, params
# ---------- 4. 主执行入口 ----------
if __name__ == "__main__":
# 初始化模型
model = SimpleCNN(num_classes=10)
model.eval()
# 参数统计
total_m, trainable_m = count_parameters(model)
print(f"总参数量: {total_m:.4f} M")
print(f"可训练参数量: {trainable_m:.4f} M")
# FLOPs统计(输入尺寸需与模型实际输入匹配)
flops, params = compute_flops(model, input_size=(1, 3, 32, 32))
flops_readable, params_readable = clever_format([flops, params], "%.3f")
print(f"FLOPs: {flops_readable}")
print(f"thop统计参数量: {params_readable}")
# 额外:打印每层参数量(便于定位裁剪目标)
print("\n各层参数量明细:")
for name, param in model.named_parameters():
if param.requires_grad:
print(f"{name}: {param.numel():,} 参数")
运行与验证
- 运行方式:将上述代码保存为
model_stats.py,在终端执行python model_stats.py。 - 预期输出(基于代码逻辑直接推算,非实测值):
- 总参数量与可训练参数量相等(本模型无冻结层),约为 0.21 M(具体数值由网络结构决定)。
- FLOPs约为 0.09 G(输入3×32×32时)。
- 每层参数明细会列出
features.0.weight、classifier.1.weight等各层参数数量。
- 通过条件:
- 脚本无报错运行完成;
- 输出的参数量与FLOPs为有限正数;
- 若替换为其他CNN(如
torchvision.models.resnet18),只需修改模型初始化部分并调整输入尺寸,脚本仍能正确输出统计结果。
关键说明
- FLOPs计算原理:thop通过向模型传入一个随机输入,跟踪各层实际执行的乘加运算次数。因此输入尺寸必须与模型期望尺寸一致,否则会报错或得到错误结果。
- 参数量与FLOPs的区别:参数量反映模型存储开销,FLOPs反映单次推理的计算量。裁剪时通常同时关注两者:参数量影响模型文件大小,FLOPs影响推理延迟。
- 扩展性:本脚本中的
SimpleCNN可替换为任何继承自nn.Module的网络(包括加载的预训练模型),统计函数无需修改。