延迟初始化——【torch学习笔记】

延迟初始化

引用翻译:《动手学深度学习》

Pytorch(或任何其他框架)没有办法预测网络的输入维度。以后,在处理卷积网络和图像时,这个问题会变得更加相关,因为输入维度(即图像的分辨率)会在很远的范围内影响后续层的维度。

因此,在编写代码时不需要知道维度是多少就能设置参数,可以大大简化统计建模。在下面的内容中,我们将以初始化为例来讨论这一点。毕竟,我们不能初始化那些我们不知道存在的变量。

一、实例化一个网络

import torch
import torch.nn as nn
def getnet(in_features,out_features):
    net=nn.Sequential(
    nn.Linear(in_features,256),
    nn.ReLU(),
    nn.Linear(256,out_features))
    return net
net=getnet(20,10)
print(net)
Sequential(
  (0): Linear(in_features=20, out_features=256, bias=True)
  (1): ReLU()
  (2): Linear(in_features=256, out_features=10, bias=True)
)

在pytorch中,定义一个层而不提及该层的in_features是不可能的

for name,param in net.named_parameters():
    print(name,'----',param.shape)
0.weight ---- torch.Size([256, 20])
0.bias ---- torch.Size([256])
2.weight ---- torch.Size([10, 256])
2.bias ---- torch.Size([10])

现在可以通过使用pytorch制作一个自定义的nn模块,使网络从输入的数据中学习大小。

二、延迟初始化的实践

现在我们知道了它在理论上是如何工作的,让我们看看初始化是什么时候被实际触发的。为了做到这一点,我们模拟了一个初始化器。

初始化器init_weights被调用时,它初始化了网络的权重。它还将神经网络的权重设置为非零值,这对神经网络来说是有帮助的,因为神经网络往往会陷入局部最小值,所以给它们许多不同的起始值是个好主意。如果它们都从零开始,你就无法做到这一点。

def init_weights(m):
    print("Init",m)
    
net.apply(init_weights)  # 每层都循环一下,最后对整个Sequential也进行操作
print('网络结构:\n',net)
print('第一层网络结构:\n',net[0].weight)
print('第二层网络结构:\n',net[2].weight)
Init Linear(in_features=20, out_features=256, bias=True)
Init ReLU()
Init Linear(in_features=256, out_features=10, bias=True)
Init Sequential(
  (0): Linear(in_features=20, out_features=256, bias=True)
  (1): ReLU()
  (2): Linear(in_features=256, out_features=10, bias=True)
)
网络结构:
 Sequential(
  (0): Linear(in_features=20, out_features=256, bias=True)
  (1): ReLU()
  (2): Linear(in_features=256, out_features=10, bias=True)
)
第一层网络结构:
 Parameter containing:
tensor([[-0.1491, -0.0097,  0.1623,  ..., -0.1184,  0.2214, -0.1529],
        [-0.0892, -0.1382, -0.0009,  ...,  0.0528, -0.0051, -0.1143],
        [-0.0705, -0.1571, -0.1572,  ..., -0.2094, -0.0218,  0.0845],
        ...,
        [-0.0584, -0.1813, -0.1787,  ..., -0.0242, -0.0433,  0.1609],
        [-0.1334,  0.0800,  0.1350,  ...,  0.2139,  0.1093,  0.0588],
        [ 0.1241, -0.0655, -0.2102,  ..., -0.1037, -0.0853,  0.0529]],
       requires_grad=True)
第二层网络结构:
 Parameter containing:
tensor([[-0.0312, -0.0561,  0.0472,  ...,  0.0527,  0.0263, -0.0429],
        [-0.0421,  0.0304, -0.0371,  ...,  0.0384, -0.0500, -0.0262],
        [ 0.0455, -0.0400,  0.0406,  ..., -0.0037,  0.0095, -0.0102],
        ...,
        [-0.0079,  0.0409, -0.0562,  ...,  0.0608, -0.0308, -0.0254],
        [ 0.0493, -0.0368,  0.0212,  ...,  0.0034, -0.0446,  0.0049],
        [ 0.0257,  0.0608, -0.0222,  ..., -0.0282, -0.0210, -0.0462]],
       requires_grad=True)
x=torch.rand((2,20))
y=net(x) # Forward computation
for name,param in net.named_parameters():
    print(name,param.shape)
0.weight torch.Size([256, 20])
0.bias torch.Size([256])
2.weight torch.Size([10, 256])
2.bias torch.Size([10])

与之前的主要区别是,只要我们知道输入维度,x是R 20,就可以定义第一层的权重矩阵,即W1是R 256 * 20。解决了这个问题,我们就可以进入第二层,将其维度定义为10*256,并通过计算图以此类推,在所有维度可用时将其绑定。一旦知道这一点,我们就可以通过初始化参数来进行。

正如本节开始时提到的,延迟初始化也会引起混乱。

在第一次正向计算之前,我们无法直接操作模型参数,例如,我们无法使用data和set_data函数来获取和修改参数。因此,我们经常通过网络发送一个样本观测来强制初始化。

pytorch延迟初始化

使用 torch.nn.LazyLinear,但是平时所用PyTorch都是提前将网络输入输出指定的,与tensorflow等框架有一定区别。

样例如下:

import torch
from torch import nn
net = nn.Sequential(nn.LazyLinear(256), nn.ReLU(),nn.Linear(256,10))
print(net)
[net[i].state_dict() for i in range(len(net))]
low = torch.finfo(torch.float32).min/10
high = torch.finfo(torch.float32).max/10
X = torch.zeros([2,20],dtype=torch.float32).uniform_(low, high)
net(X)
print(net)

输出:

Sequential(
  (0): LazyLinear(in_features=0, out_features=256, bias=True)
  (1): ReLU()
  (2): Linear(in_features=256, out_features=10, bias=True)
)
Sequential(
  (0): Linear(in_features=20, out_features=256, bias=True)
  (1): ReLU()
  (2): Linear(in_features=256, out_features=10, bias=True)
)

三、强制初始化

如果系统在调用初始化函数时知道所有参数的形状,那么延迟初始化就不会发生。这可能发生在两种情况下:

1、我们已经看到了一些数据,我们只是想重置参数。

2、我们在定义网络时指定了网络的所有输入和输出尺寸。

第一种情况很好用,如下图所示。

一旦我们看到一些数据并定义了参数,之后我们再使用init_weights函数初始化这些参数

net1=nn.Sequential()
net1.add_module("Linear1",nn.Linear(20,256))
net1.add_module("Linear2",nn.Linear(256,10))
print(net1)
Sequential(
  (Linear1): Linear(in_features=20, out_features=256, bias=True)
  (Linear2): Linear(in_features=256, out_features=10, bias=True)
)

在第二种情况下,我们在初始化网络时指定剩余的一组参数

def init_weights_forced(m):
    if type(m) == nn.Linear:
        torch.nn.init.xavier_uniform_(m.weight)
net1.apply(init_weights_forced)
for name,param in net1.named_parameters():
    print(name,param.shape)
Linear1.weight torch.Size([256, 20])
Linear1.bias torch.Size([256])
Linear2.weight torch.Size([10, 256])
Linear2.bias torch.Size([10])

在上面的例子中,我们已经有了数据,现在我们使用这些数据允许模型本身以它想要的方式来设置in_features和参数。

第二种情况需要我们在创建图层时指定其余的参数集。例如,对于密集层,我们还需要指定in_features,以便一旦调用就能立即发生初始化。

四、摘要

1、Pytorch没有提供一个稳定的内置的延迟初始化功能。目前可使用torch.nn.LazyLinear进行试用,但是后期可能会有所变化。

2、延迟初始化是个好东西。它允许自动设置许多东西,并且在定义新的网络结构时消除了一个很大的错误来源。

3、我们可以通过指定所有隐式定义的变量来覆盖它。

4、延后初始化使框架能够自动推断参数形状,使修改模型架构变得容易,避免了一些常见的错误。

五、练习

1、如果你只指定输入维度的一部分,会发生什么?你还会得到立即初始化吗?

2、如果你指定不匹配的维度会发生什么?

3、如果你有不同维度的输入,你需要做什么?提示–看看参数捆绑。

### 回答1: 在PyTorch中,torch.nn.Module类中的层初始化是一致的,即默认情况下所有的层组件都使用相同的初始化方法。默认情况下,PyTorch中的各种层使用均匀分布或正态分布的方法进行初始化。 例如,当创建一个全连接层(torch.nn.Linear)时,默认的初始化方法是从均匀分布中随机选择权重值。我们可以通过指定权重初始化方法的输入参数来改变初始化方法,比如使用正态分布来初始化。 对于某些特定类型的层组件,PyTorch提供了特殊的初始化方法。比如,对于卷积层(torch.nn.Conv2d),可以通过设置参数来自定义初始化。默认情况下,卷积层的权重参数是从均匀分布中随机选择的。但我们也可以通过设置参数来改变初始化方法,比如使用正态分布初始化。 除了权重参数初始化外,偏置参数(bias)也可以通过设置输入参数来进行初始化。偏置参数初始化默认也是从均匀分布中随机选择的。 在实际使用中,我们也可以自己定义初始化方法。我们可以通过继承torch.nn.Module类,然后重写层组件的初始化方法来实现自定义的初始化过程。这样我们就可以根据实际需要选择合适的初始化方法了。 总之,PyTorch中的层初始化是一致的,但我们可以通过设置参数来改变初始化方法,或者自定义初始化方法,以满足具体的需求。 ### 回答2: torch的层初始化一致,是指在神经网络的构建过程中,使用相同的初始化方法和参数对所有的层进行初始化神经网络模型的层初始化非常重要,它决定了模型的初始状态和性能。如果层初始化不一致,不同的层可能会有不同的初始权重和偏差,这可能导致训练过程中收敛速度慢,性能差,甚至无法收敛。 为了保证层初始化的一致性,Torch提供了一些内置的初始化方法,如常见的xavier初始化、正态分布初始化或均匀分布初始化。这些初始化方法可以保证每个层的初始权重和偏差在一定范围内随机初始化,使得初始值足够接近最优解。当然,用户也可以自定义初始化方法来满足特定需求。 在构建神经网络模型时,通常会使用循环或迭代的方式添加各个层,然后使用统一的初始化方法对它们进行初始化。这样可以确保所有的层使用相同的初始化参数,从而保证了层初始化的一致性。 除了层初始化的一致性外,Torch还提供了一些其他的初始化策略来提高模型的性能和效果,比如Batch Normalization(批归一化)等。这些策略可以有效地减少梯度消失和梯度爆炸等问题,加速网络的收敛速度,提高模型的泛化能力。 总之,torch的层初始化一致是为了确保每个层的初始权重和偏差在一定范围内随机初始化,并提供了一些内置的初始化方法和其他初始化策略来提高模型的性能和效果。 ### 回答3: torch的层初始化一致是指在神经网络模型中,使用torch库提供的初始化方法时,对于每个相同类型的层,初始化的方式是一样的。这种一致性可以帮助我们更好地控制模型的初始化过程,以提高模型的训练性能和泛化能力。 在torch中,我们可以使用nn.Module中提供的方法来初始化层,常见的初始化方法包括xavier初始化、正态分布初始化、均匀分布初始化等。这些方法都是基于torch.nn.init模块实现的。 当我们创建一个神经网络模型时,可以通过在模型的初始化方法中调用nn.Module中的初始化方法来对模型的各个层进行初始化。我们可以根据需要选择使用不同的初始化方法,并且对于相同类型的层,可以使用相同的初始化方法。 这种一致的初始化方法带来的好处是可以保持模型的一致性和可复现性。在实验中,我们通常会多次训练模型,并比较不同初始化方法对模型性能的影响。如果每次初始化的方式都是一样的,那么我们可以更准确地比较各种初始化方法的效果,找到最优的初始化方法。 另外,一致的初始化方法还可以帮助我们更方便地调试和验证模型。在模型的训练过程中,如果遇到性能下降或其他问题,我们可以通过检查模型的初始化方法是否一致,来确定是否是初始化方式导致的问题。 总而言之,torch的层初始化一致是指使用相同的初始化方法来初始化相同类型的层,这种一致性可以提高模型的训练性能和泛化能力,同时也方便了模型的调试和验证。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值