神经网络工具箱——nn.funtional、初始化策略

4.nn.functional

nn中还有一个很常用的模块:nn.functionalnn中大多数layer在functional中都有一个与之对应的函数。

nn.functional中的函数和nn.Module的主要区别在于,用nn.Module实现的layers是一个特殊的类,都是由class Layer(nn.Module)定义,会自动提取可学习的参数;
nn.functional中的函数更像是纯函数,由def function(input)定义。

input=V(t.randn(2,3))
model=nn.Linear(3,4)
output1=model(input)
output2=nn.functional.linear(input, model.weight, model.bias)
output1==output2

运行结果:

tensor([[ 1,  1,  1,  1],
        [ 1,  1,  1,  1]], dtype=torch.uint8)
b=nn.functional.relu(input)
b2=nn.ReLU()(input)
b==b2

结果:

tensor([[ 1,  1,  1],
        [ 1,  1,  1]], dtype=torch.uint8)

设么时候用nn.Module,什么时候用nn.functional呢??
1)如果模型有可学习的参数,最好用nn.Module,否则既可以用nn.functional也可以用nn.Module,二者在性能上没有太大的差异。
2)由于激活函数(ReLU,sigmoid、tanh),池化(MaxPool)等层没有可学习参数,可以使用对应的functional函数代替。
3)卷积、全连接等具有可学习参数的网络建议使用nn.Module.
4) 虽然dropout操作也没有可学习参数,但建议还是使用nn.Dropout而不是nn.functional.dropout, 因为dropout在训练和测试两个阶段的行为有所差别,使用nn.Module对象能够通过model.eval操作加以区分。

from torch.nn import functional as F
class Net(nn.Module):
    def __init__(self):
        super(Net, self).__init()
        self.conv1=nn.Conv2d(3,6,5)
        self.conv2=nn.Conv2d(6,16,5)
        self.fc1=nn.Linear(16*5*5, 120)
        self.fc2=nn.Linear(120,84)
        self.fc3=nn.Linear(84,10)

    def forward(self,x):
        x=F.pool(F.relu(self.conv1(x)),2)  #卷积1、激活、池化  三个操作
        x=F.pool(F.relu(self.conv2(x)),2)  #卷积2、激活、池化  三个操作
        x=x.view(-1,16*5*5)
        x=F.relu(self.fc1(x))         #全连接1、激活
        x=F.relu(self.fc2(x))         #全连接2、激活
        x=self.fc3(x)                 #全连接3
        return x

不具备可学习参数的层(激活、池化层等),将他们用函数代替,这样可以不用放置在构造函数__init__()中。
有可学习参数的模块,也可以用functional代替,只不过实现起来较麻烦,需要手动定义参数parameter,如前面实现自定义的全连接层,就可将weight和bias两个参数单独拿出来,在构造函数中初始化为parameter.

class MyLinear(nn.Module):
    def __init__(self):
        super(MyLinear,self).__init__()
        self.weight=nn.Parameter(t.randn(3,4))
        self.bias=nn.Parameter(t.zeros(3))

    def forward(self):
        return F.linear(input,weight,bias)

5. 初始化策略

Pytorch中的nn.Module的模块都采取了较合理的初始化策略,一般不用我们考虑。当然也可以用自定义的初始化策略替代系统的默认初始化。
当我们使用Parameter时,自定义初始化尤为重要,因为t.Tensor()返回的是内存中的随机数,很可能会有极大值,这在实际训练网络中会造成溢出或者梯度消失

Pytorch中的nn.init模块专门为初始化设计,实现了常用的 初始化策略。如果某种初始化策略n.init不提供,用户也可以自己直接初始化。

#利用nn.init 初始化
from torch.nn import init
linear=nn.Linear(3,4)

t.manual_seed(1)
#等价于linear.weight.data.normal_(0,std)
init.xavier_normal_(linear.weight)

结果:

扫描二维码关注公众号,回复: 2119315 查看本文章
Parameter containing:
tensor([[ 0.3535,  0.1427,  0.0330],
        [ 0.3321, -0.2416, -0.0888],
        [-0.8140,  0.2040, -0.5493],
        [-0.3010, -0.4769, -0.0311]])
#直接初始化
import math
t.manual_seed(1)

std=math.sqrt(2)/math.sqrt(7.)
linear.weight.data.normal_(0,std)

结果:

tensor([[ 0.3535,  0.1427,  0.0330],
        [ 0.3321, -0.2416, -0.0888],
        [-0.8140,  0.2040, -0.5493],
        [-0.3010, -0.4769, -0.0311]])
#对模型的所有参数进行初始化
for neme,params in net.named_parameters():
    if name.find('linear')!=-1:
        #init linear
        params[0] #weight
        params[1] #bias
    elif name.find('conv')!=-1:
        pass
    elif neme.find('norm')!=-1:
        pass

6. nn.Module 深入分析

猜你喜欢

转载自blog.csdn.net/zhenaoxi1077/article/details/80949698
今日推荐