在创建model后直接调用torch.nn.init里的初始化函数。
conv = torch.nn.Conv2d(3, 64, kernel_size = 3, stride = 1, padding = 1)
torch.nn.init.xavier_uniform_(conv.weight)
torch.nn.init.xavier_uniform_(conv.bias, 0)
(1). 使用apply函数,在_init_函数中用self.modules()进行初始化
先定义初始化模型方法,运用apply()调用weight_init函数.
class Net(nn.Module):
def __init__(self, in_dim, n_hidden_1, n_hidden_2, out_dim):
super().__init__()
self.layer = nn.Sequential(
nn.Linear(in_dim, n_hidden_1),
nn.ReLU(True),
nn.Linear(n_hidden_1, n_hidden_2),
nn.ReLU(True),
nn.Linear(n_hidden_2, out_dim)
)
def forward(self, x):
x = self.layer1(x)
x = self.layer2(x)
x = self.layer3(x)
return x
# 1. 根据网络层的不同定义不同的初始化方式
def weight_init(m):
if isinstance(m, nn.Linear):
nn.init.xavier_normal_(m.weight)
nn.init.constant_(m.bias, 0)
# 也可以判断是否为conv2d,使用相应的初始化方式
elif isinstance(m, nn.Conv2d):
nn.init.kaiming_normal_(m.weight, mode='fan_out', nonlinearity='relu')
# 是否为批归一化层
elif isinstance(m, nn.BatchNorm2d):
nn.init.constant_(m.weight, 1)
nn.init.constant_(m.bias, 0)
# 2. 初始化网络结构
model = Net(in_dim, n_hidden_1, n_hidden_2, out_dim)
# 3. 将weight_init应用在子模块上
model.apply(weight_init)
#torch中的apply函数通过可以不断遍历model的各个模块,并将weight_init函数应用在这些Module上
(2)定义在模型中,利用self.modules()来进行循环(推荐)
class Net(nn.Module):
def __init__(self, in_dim, n_hidden_1, n_hidden_2, out_dim):
super().__init__()
self.layer = nn.Sequential(
nn.Linear(in_dim, n_hidden_1),
nn.ReLU(True),
nn.Linear(n_hidden_1, n_hidden_2),
nn.ReLU(True),
nn.Linear(n_hidden_2, out_dim)
)
for m in self.modules():
if isinstance(m, nn.Conv2d):
nn.init.kaiming_normal_(m.weight, mode='fan_out', nonlinearity='relu')
elif isinstance(m, (nn.BatchNorm2d, nn.GroupNorm)):
nn.init.constant_(m.weight, 1)
nn.init.constant_(m.bias, 0)
def forward(self, x):
x = self.layer1(x)
x = self.layer2(x)
x = self.layer3(x)
return x
init.uniform(tensor, a=0, b=1)
nn.init.uniform(w)
从均匀分布 U ( a , b )中生成值,填充输入的张量或变量
nn.init.normal(tensor, mean=0, std=1)
nn.init.normal(w)
从给定均值和标准差的正态分布N(mean,std)中生成值,填充输入的张量或变量
nn.init.constant(tensor, val)
nn.init.constant(w)
用val的值填充输入的张量或变量
nn.init.eye(tensor)
nn.init.eye(w)
用单位矩阵来填充2维输入张量或变量。在线性层尽可能多的保存输入特性
nn.init.dirac(tensor)
nn.init.dirac(w)
用Dirac δ 函数来填充{3, 4, 5}维输入张量或变量。在卷积层尽可能多的保存输入通道特性
基本思想是维持输入和输出的方差一致,避免了所有的输出值都为0, 使用于任何激活函数,但是Xavier初始化在tanh中表现的很好, 在relu中表现很差
nn.init.xavier_uniform(tensor, gain=1)
nn.init.xavier_uniform(w, gain=math.sqrt(2.0))
用一个均匀分布生成值,填充输入的张量或变量。结果张量中的值采样自U(-a, a)
针对Xavier在relu表现不佳被提出。基本思想仍然从“输入输出方差一致性”角度出发,在Relu网络中, 假设每一层有一半的神经元被激活,另一半为0。一般在使用Relu的网络中推荐使用这种初始化方式。
nn.init.xavier_normal(tensor, gain=1)
nn.init.xavier_normal(w)
用一个正态分布生成值,填充输入的张量或变量。结果张量中的值采样自均值为0的正态分布。
nn.init.kaiming_uniform(tensor, a=0, mode='fan_in',nonlinearity='leaky_relu')
nn.init.kaiming_uniform(w, mode='fan_in')
用一个均匀分布生成值,填充输入的张量或变量。结果张量中的值采样自U(-bound, bound)
nn.init.kaiming_normal(tensor, a=0, mode='fan_in')
nn.init.kaiming_normal(w, mode='fan_out')
用一个正态分布生成值,填充输入的张量或变量。结果张量中的值采样自均值为0的正态分布.
主要是解决神经网络中出现的梯度消失和梯度爆炸等问题,是RNN中常用的初始化方法
nn.init.orthogonal(tensor, gain=1)
nn.init.orthogonal(w)
用正交矩阵填充输入的张量或变量。输入张量必须至少是2维的,对于更高维度的张量,超出的维度会被展平,视作行等于第一个维度,列等于稀疏矩阵乘积的2维表示【其中非零元素生成自均值为0,标准差为std的正态分布】
nn.init.sparse(tensor, sparsity, std=0.01)
# 非零元素采用正态分布 N(0, 0.01) 初始化.
nn.init.sparse(w, sparsity=0.1)
将2维的输入张量或变量当做 稀疏矩阵填充,其中非零元素根据一个均值为0,标准差为std的正态分布生成。