nn.init.kaiming_normal_必须传入二维及以上tensor(如layer.weight),并显式指定mode和nonlinearity(如'fan_in', 'relu'),且需先判空、判类型、确保维度合规。

PyTorch自定义层里nn.init.kaiming_normal_该传什么参数?
直接调用nn.init.kaiming_normal_必须传入一个Tensor,不能传Parameter或nn.Linear这类模块对象。常见错误是写成nn.init.kaiming_normal_(layer.weight)却忘了layer.weight可能为None(比如nn.Linear(in_features, out_features, bias=False)时weight存在但bias为None),或没检查weight是否可训练。
正确做法是先判断属性是否存在且是torch.nn.Parameter类型,并确保其维度≥2(Kaiming初始化要求至少二维张量):
import torch.nn as nn
import torch.nn.init as init
<p>class MyLayer(nn.Module):
def <strong>init</strong>(self, in_dim, out_dim):
super().<strong>init</strong>()
self.weight = nn.Parameter(torch.empty(out_dim, in_dim))
self.bias = nn.Parameter(torch.empty(out_dim))</p><h1>初始化</h1><pre class="brush:python;toolbar:false;"> init.kaiming_normal_(self.weight, a=0, mode='fan_in', nonlinearity='relu')
init.constant_(self.bias, 0)
-
a是LeakyReLU的负斜率,用ReLU就填0;用LeakyReLU就填对应negative_slope -
mode='fan_in'(默认)适用于前向传播方差稳定,'fan_out'适合反向传播;多数情况用'fan_in' - 别漏掉
nonlinearity参数——即使你用的是ReLU,也得显式写nonlinearity='relu',否则默认按'leaky_relu'算,缩放系数会错
用apply()批量初始化时为什么有些权重没被设上?
apply()遍历模型所有子模块并调用传入函数,但它**不保证执行顺序**,也不自动跳过没有weight或bias的模块(比如nn.ReLU)。最常踩的坑是:在函数里无条件调用init.kaiming_normal_(m.weight),结果遇到m是nn.BatchNorm2d或nn.Dropout就报AttributeError: 'BatchNorm2d' object has no attribute 'weight'。
安全写法是逐个检查属性是否存在、是否为Parameter、是否满足初始化前提:
def init_weights(m):
if isinstance(m, nn.Linear) or isinstance(m, nn.Conv2d):
init.kaiming_normal_(m.weight, mode='fan_in', nonlinearity='relu')
if m.bias is not None:
init.constant_(m.bias, 0)
elif isinstance(m, nn.BatchNorm2d):
init.constant_(m.weight, 1)
init.constant_(m.bias, 0)
<p>model = MyNet()
model.apply(init_weights)</p>
- 不要用
isinstance(m, nn.Module)做泛化判断——几乎所有模块都继承它,会误伤 -
nn.Embedding要用init.normal_而非Kaiming(它不是线性变换) - 如果模型含
nn.LSTM等复合模块,apply会进到它的子模块(如weight_ih_l0),但那些参数名不叫weight,需单独处理
初始化后model.parameters()没变?是不是没生效?
初始化操作是原地修改(in-place),不会返回新Tensor,所以不需要赋值。但如果你在初始化后立刻打印model.state_dict()发现数值“还是老样子”,大概率是因为:你在__init__里初始化了,又在后续调用了model.apply(...),而后者又把刚设好的权重覆盖掉了——尤其是当apply函数里没加类型判断,对所有模块都强行重置时。
- 推荐只选一种初始化方式:要么在
__init__里手动初化关键层,要么统一用apply,别混用 - 验证是否生效,最直接的是在初始化后立即检查:
print(model.conv1.weight.data.mean(), model.conv1.weight.data.std())——Kaiming normal 初始化后std应接近sqrt(2 / fan_in) - 注意
model.train()/model.eval()不影响初始化结果,但会影响BatchNorm等模块内部状态,别误以为是初始化问题
自定义层带可学习参数但不是weight/bias名怎么办?
比如你写了self.gamma = nn.Parameter(...)用于缩放,或self.register_parameter('alpha', ...),这些名字不会被apply里的通用逻辑捕获,也不会被PyTorch默认初始化策略识别。
必须在__init__中显式初始化,或在apply函数里额外判断:
def init_weights(m):
if hasattr(m, 'gamma') and isinstance(m.gamma, nn.Parameter):
init.constant_(m.gamma, 1.0)
if hasattr(m, 'alpha') and isinstance(m.alpha, nn.Parameter):
init.normal_(m.alpha, 0, 0.02)
# 其他常规初始化...
- 别依赖
named_parameters()在apply里做反射——apply传入的是模块实例m,不是名称 - 如果参数名不固定(比如通过字符串动态注册),初始化逻辑就得移到
__init__末尾,或用register_load_state_dict_post_hook补救(极少需要)
真正容易被忽略的是:Kaiming初始化只对「权重张量」有意义,对偏置、缩放因子、门控系数等,该用constant_、normal_或xavier_uniform_就得换,不能硬套kaiming_normal_。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











