参数量应直接对可训练参数调用numel()求和,而非用parameters_to_vector;thop统计flops易因动态分支、自定义op或torch.compile失效,需在编译前用固定shape输入测试。

用 torch.nn.utils.parameters_to_vector 和 sum 快速算参数量
参数量(Params)本质就是所有可训练 nn.Parameter 的元素总数,最直接的方法是遍历模型所有参数并累加 .numel()。别用 parameters_to_vector 做这个——它会把参数拼成大向量再算长度,浪费内存且没必要。
正确做法是:
- 对
model.parameters()迭代,每个p.numel()求和 - 只统计
requires_grad == True的参数(默认行为,但显式过滤更安全) - 注意:
Buffer(如running_mean)不算参数量,除非你明确要总张量大小
示例:
total_params = sum(p.numel() for p in model.parameters() if p.requires_grad)
用 thop.profile 算 FLOPs 时为什么常报错或结果为 0
thop 是目前最常用的第三方工具,但它对模型写法很敏感。常见失败原因不是安装问题,而是输入或模型结构不满足其 hook 机制:
- 输入必须是
torch.Tensor,且 shape 固定(不能含None或动态维度) - 模型中用了
if x.shape[0] > 1:这类运行时分支,thop的静态分析会跳过部分路径,FLOPs 被低估甚至归零 - 自定义
torch.autograd.Function或非标准 OP(如某些 CUDA 扩展)无法被识别,对应模块 FLOPs 计为 0 - 使用了
torch.jit.trace包装的模型,thop不支持
建议先用一个干净的前向函数测试:
from thop import profile<br>input = torch.randn(1, 3, 224, 224)<br>macs, params = profile(model, inputs=(input,), verbose=False)
注意:macs 是乘加次数,通常说的 FLOPs ≈ macs * 2(一次乘加算 2 个浮点运算)
自己写 hook 统计 FLOPs 更可靠,但要注意 forward 的副作用
如果 thop 失效,可以手动注册 register_forward_hook,在每层输出时根据输入/输出尺寸推算该层 FLOPs。但这要求你清楚每种 layer 的计算逻辑:
-
nn.Conv2d:FLOPs ≈2 × C_in × C_out × K_h × K_w × H_out × W_out -
nn.Linear:FLOPs ≈2 × in_features × out_features(忽略 bias) - Attention 中的
q @ k.T是最大头杀,容易漏算,尤其causal=True时需按三角矩阵算 - hook 函数里不能修改输入/输出张量,否则影响实际前向;建议只读属性、存到全局 dict
关键陷阱:有些层(如 nn.Dropout、nn.ReLU)理论上 FLOPs 为 0,但若 hook 注册在它们之后,可能误把上一层输出尺寸当成本层输入,导致重复或错位统计。
PyTorch 2.0+ 的 torch.compile 会让 FLOPs 统计失效
启用 torch.compile(model) 后,模型变成 CompiledFunction,原始 module 结构被封装,thop 和自定义 hook 都无法穿透。此时 profile 必须在 compile 之前做。
另一个隐性影响:某些优化(如算子融合)会让实际硬件执行的 FLOPs 低于理论值,但所有统计工具都只算“未融合”版本。也就是说,你算出来的数字反映的是模型结构层面的理论计算量,不是 GPU 上真实跑出的 flops。
如果你真要测硬件级吞吐,得用 nsys 或 torch.cuda.memory_stats 配合计时,而不是靠模型分析工具。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











