首页 > 其他分享 >层、块以及参数管理

层、块以及参数管理

时间:2024-10-23 11:13:36浏览次数:1  
标签:初始化 nn 以及 self 管理 init 参数 net

此Blog仅作为日常学习工作中记录使用,Blog中有不足之处欢迎指出

​ 在研究过程中发现,比单层神经网络大,比整个深度神经网络模型小的组件往往更具价值。以计算机视觉为例,ResNet-152具有数百层,这些层是由层组(groups of layers)的重复模式组成。

​ 块(block)可以描述单个层、由多个层组成的组件或整个模型本身。使用块进行抽象的一个好处是可以将一些块组合成更大的组件,这一过程通常是递归的。通过定义代码来按需生成任意复杂度的块,我们可以通过简洁的代码实现复杂的神经网络。

​ 从编程的角度来看,块由类(class)表示。它的任何子类都必须定义一个将其输入转换为输出的前向传播函 数,并且必须存储任何必需的参数。注意,有些块不需要任何参数。最后,为了计算梯度,块必须具有反向 传播函数。在定义我们自己的块时,由于深度学习算法框架的自动微分提供了一些后端实现,我们只需要考虑前向传播函数和必需的参数。

层与块

自定义块

每个块必须提供的基本功能:

  1. 将输入数据作为其前向传播函数的参数。
  2. 通过前向传播函数来生成输出。
  3. 计算其输出关于输入的梯度,可通过其反向传播函数进行访问。(自动实现)
  4. 存储和访问前向传播计算所需的参数。
  5. 根据需要初始化模型参数。(有内置初始化,也可自定义)

因此,在构建自定义块的时候,主要注意力在构造函数和前向函数上。

例子:

# 创建my_block块
class my_block(nn.Module): # 继承自父类Module
    def __init__(self): # 若想自定义层数和每层结构,可在__init__函数中携带入参
        super().__init__() # 调用父类__init__构造函数,执行必要的初始化
        # 创建了两层网络(net),由两层全连接层和两层Relu激活函数
        # 并在前向函数中,使用一层全连接层输出
        self.net = nn.Sequential()
        self.net.add_module(nn.Linear(10, 20))
        self.net.add_module(nn.ReLU())
        self.net.add_module(nn.Linear(20, 30))
        self.net.add_module(nn.ReLU())
        self.linear = nn.Linear(30, 2)
        
    def forward(self, X): # 前向函数
        return self.linear(self.net(X))
    
net = my_block()
X = torch.rand(20,10)

print(net(X))

输出:

tensor([[ 0.0905, -0.0987],
        [ 0.1018, -0.1237],
        [ 0.0783, -0.1111],
        [ 0.0693, -0.1341],
        [ 0.0558, -0.1214],
        [ 0.0822, -0.0971],
        [ 0.1115, -0.1514],
        [ 0.1314, -0.1436],
        [ 0.0833, -0.1109],
        [ 0.0837, -0.1035],
        [ 0.0777, -0.1171],
        [ 0.1149, -0.1599],
        [ 0.0817, -0.1272],
        [ 0.0921, -0.1114],
        [ 0.0925, -0.1291],
        [ 0.0855, -0.0905],
        [ 0.0607, -0.1470],
        [ 0.1040, -0.1015],
        [ 0.0722, -0.1411],
        [ 0.1086, -0.1517]], grad_fn=<AddmmBackward0>)

顺序块

Sequential类的设计是为了把其他模块串起 来。为了构建我们自己的简化的MySequential,我们只需要定义两个关键函数:

  1. 一种将块逐个追加到列表中的函数;
  2. 一种前向传播函数,用于将输入按追加块的顺序传递给块组成的“链条”。
class my_sequential(nn.Module): # 同样需要继承自Module父类
    def __init__(self,*args):
        super().__init__()
        for idx,module in enumerate(args):
            self._modules[str(idx)] = module # _modules属性是一个有序字典(OrderedDict),定义在父类(Module)中的一个属性
            # OrderedDict保证了按照成员添加的顺序遍历它们

    def forward(self, X):
        for block in self._modules.values():
            X = block(X)
        return X
net = nn.Sequential(
    nn.Linear(10,20),
    nn.ReLU(),
    nn.Linear(20,3),
)
X = torch.rand(2,10)
net(X)
tensor([[-0.2760, -0.0287,  0.1601],
        [-0.2675, -0.0232,  0.1811]], grad_fn=<AddmmBackward0>)

init__函数将每个模块逐个添加到有序字典_modules中。不创建新的python列表,而是用父类中 _modules的好处:在模块的参数初始化过程中,系统知道在 _modules字典中查找需要初始化参数的子块。

前向函数执行自定义代码

如果需要对网络参数和激活值以外的参数(常数参数)进行操作,或者对网络运算过程进行修改,则需要在前向函数中进行定义。

例子:

class forwoard_net(nn.Module):
    def __init__(self):
        super().__init__()
        # 设置权重参数,该权重参数无需保留梯度,在训练期间权重值保持不变
        self.rand_weight = torch.rand((20,20), requires_grad=False) # requries_grad属性设置为False,表示该参数无需保留梯度
        self.linear = nn.Linear(20, 20) # 线性层

    def forward(self, X):
        X = self.linear(X) # 线性层
        X = F.relu(torch.mm(X, self.rand_weight) + 1) # relu激活函数
        X = self.linear(X) # 线性层
        # 控制流
        while X.abs().sum() > 1:
            X /= 2
        return X.sum()

net = forwoard_net()
X = torch.rand(2, 20)
net(X)

输出:

tensor(-0.0486, grad_fn=<SumBackward0>)

在上述代码中,实现了一个隐藏层X = F.relu(torch.mm(X, self.rand_weight) + 1),该隐藏层中,随机初始化了一组权重参数,并且该权重参数为常量参数,并不会被反向传播更新。

此外,在输出以后,前向函数还将对输出结果进行while循环,在输出结果的L1范数的结果大于1,将对输出结果除2,直到满足结果为止。

参数管理

参数访问

net = nn.Sequential(
    nn.Linear(20, 15),
    nn.ReLU(),
    nn.Linear(15, 2),
)
X = torch.rand(2, 20)
net(X)
tensor([[-0.0823, -0.0976],
        [-0.0775, -0.2395]], grad_fn=<AddmmBackward0>)

上述模型定义了两层全连接层以及一层relu激活层

print(net)
Sequential(
  (0): Linear(in_features=20, out_features=15, bias=True)
  (1): ReLU()
  (2): Linear(in_features=15, out_features=2, bias=True)
)

访问目标参数

访问目标层的weight、bias和grad由多种方法:

net[2].state_dict() # 获取第二个全连接层的weight和bias
net[2].bias # 获取第二个全连接层的bias
net[2].bias.data # 获取第二个全连接层的bias
net[2].weight.grad # 获取第二个全连接层的梯度

注:上述net中,net[0]代表第一个全连接层,net[1]为ReLU层,net[2]为第二个全连接层。

访问所有参数

net.state_dict()
print(*[(name,param,param.shape,param.data) for name,param in net.named_parameters()])

注:第二种方式较为通用

嵌套块访问参数

class Block_1(nn.Module):
    def __init__(self):
        super().__init__()
        self.bk_1_net = nn.Sequential(nn.Linear(20, 64), nn.ReLU(), nn.Linear(64,20),nn.ReLU())

    def forward(self,X):
        return self.bk_1_net(X)
class Block_2(nn.Module):
    def __init__(self):
        super().__init__()
        self.bk_2_net = nn.Sequential()
        for i in range(5):
            self.bk_2_net.add_module(f'block_{i}',Block_1())
        self.linear = nn.Linear(20, 2)

    def forward(self,X):
        return self.linear(self.bk_2_net(X))

nestNet = nn.Sequential(Block_2(),nn.Linear(2,1))
X = torch.rand((300, 20))
y = nestNet(X)

创建块Block_1和Block_2,Block_1由两个全连接层和两个ReLU激活层构成,Block_2由5个Block_1嵌套,并将嵌套结果通过一个全连接层输出。

可通过如下操作获取某层的网络结构以及参数:

print(nestNet[0]) # 获取Block_2中嵌套部分
print(nestNet[0].bk_2_net[0]) # 获取嵌套部分的第一个Block_1
print(nestNet[0].bk_2_net[0].bk_1_net[2]) # 获取嵌套部分第一个Block_1的第二个全连接层

可通过对获取到的网络进行.weight.state_dict()等操作,获取权重参数、偏置值以及梯度等

参数初始化

默认情况下,PyTorch会根据一个范围均匀地初始化权重和偏置矩阵,这个范围是根据输入和输出维度计算 出的。PyTorch的nn.init模块提供了多种预置初始化方法。

内置初始化

PyTorch有以下内置初始化器:

nn.init.normal_(m.weight,mean=0,std=0.01) # 将权重参数初始化为,标准差为0.01的高斯随机变量
nn.init.constant_(m.weight,1) # 将权重从参数初始化为1
nn.init.zeros_(m.weight) # 将权重参数初始化为0
nn.init.xavier_uniform(m.weight) # 使用xavier初始化方法初始化权重参数
nn.init.uniform_(m.weight) # 使用均匀分布初始化权重参数

使用例子:

# 创建初始化函数,将权重初始化为1,偏置初始化为0
# 初始化方法可以替换
# 可用于嵌套块的初始化
def init_weights(m):
    if type(m) == nn.Sequential:
        for block in m.children():
            init_weights(block)
    else:
        if type(m) == nn.Linear:
            nn.init.constant_(m.weight, 1)
            nn.init.constant_(m.bias, 0)
            
# 以嵌套块的nestNet模型为例
nestNet.apply(init_weight) # 使用初始化函数进行初始化
nestNet[0].apply(init_weight) # 嵌套层初始化

自定义初始化函数

例如采用以下分布初始化权重参数:

w = 0 (p = 1/2);w = U(5~10) (p = 1/4); w = U(-10~-5) (p = 1/4)

def my_init(m):
	if type(m) == nn.Linear:
        nn.init.uniform_(m.weight, -10,10) # 使用均匀分布将权重参数初始化为-10~10的均匀分布
        # 均匀分布的情况下,权重参数小于5的概率为1/2,任意数乘False为0
        m.weight.data *= m.weight.data.abs() >= 5

参数共享

shared = nn.Linear(8,8)
net = nn.Sequential(nn.Linear(4,8),nn.ReLU(),
                   shared,nn.ReLU(),
                   shared,nn.ReLU(),
                   nn.Linear(8,1))

创建共享层shared,并在net中,第三层和第五层的参数进行绑定。

注:好处是,第三层和第五层的参数共享,在反向传播计算梯度的时候,这个两层的梯度会计算两次并叠加,从而加快梯度下降速度,加快训练速度。

标签:初始化,nn,以及,self,管理,init,参数,net
From: https://www.cnblogs.com/AfroNicky/p/18495956

相关文章

  • Altair官方文档——HyperMesh模型管理
    1.4模型管理在HyperMesh中创建一个有效的求解输入文件时,模型管理功能是非常必要的。本节将介绍基本的模型管理方法,如单元和载荷归类、集合组装、重命名、删除、排序以及重新编号等。本节将学习如何:创建几何和组件归类。单元归类。组件重命名。识别和删除空组件。删除所有......
  • 跨站脚本攻击XSS以及Cookie如何实现用户管理
            跨站脚本攻击(Cross-SiteScripting,简称XSS)是一种常见的网络安全漏洞,通常发生在Web应用中。攻击者通过在网页中注入恶意脚本,这些脚本会自动执行,从而达到攻击的目的。XSS攻击可以导致数据泄露、会话劫持、篡改页面内容等多种危害。XSS攻击的类型反射型XSS(Refl......
  • 原创计算机毕业设计—69271 django重大公告卫生事件物资管理系统 (源码免费领)定制程序
    摘要随着信息技术的快速发展,计算机应用已经进入成千上万的家庭。随着物资数量的增加,物资库存管理也存在许多问题。物资数据的处理量正在迅速增加,原来的手工管理模式不适合这种形式。使用计算机可以完成数据收集、处理和分析,减少人力和物力的浪费。需要建立重大公告卫生事件......
  • 原创计算机毕业设计—58671 基于SpringBoot的健康管理系统(源码免费领)小程序、APP、JAV
    摘 要随着我国经济迅速发展,人们对手机的需求越来越大,各种手机软件也都在被广泛应用,但是对于手机进行数据信息管理,对于手机的各种软件也是备受用户的喜爱,健康管理系统被用户普遍使用,为方便用户能够可以随时进行健康管理系统的数据信息管理,特开发了基于springboot的健康管理系......
  • 鸿蒙Next之数据同步艺术之一:方舟数据管理揭秘
    本文旨在深入探讨华为鸿蒙HarmonyOSNext系统(截止目前API12)的技术细节,基于实际开发实践进行总结。主要作为技术分享与交流载体,难免错漏,欢迎各位同仁提出宝贵意见和问题,以便共同进步。本文为原创内容,任何形式的转载必须注明出处及原作者。本文将介绍华为鸿蒙HarmonyOSNext中的......
  • 创新!高级!【日前、日内非滚动、日内滚动调度以及实时修正】考虑需求侧响应的智慧楼宇多
     ......
  • 【K8s】Kubernetes 证书管理工具 Cert-Manager
    本文内容均来自个人笔记并重新梳理,如有错误欢迎指正!如果对您有帮助,烦请点赞、关注、转发、订阅专栏!专栏订阅入口| 精选文章 | Kubernetes |Docker|Linux |羊毛资源 | 工具推荐 |往期精彩文章【Docker】(全网首发)KylinV10下MySQL容器内存占用异常的解决......
  • 通讯录管理:BusyContacts 支持云同步的跨平台联系人管理macOS电脑软件
    BusyContacts是一款专为Mac设计的通讯录管理软件,支持与AppleContacts/iCloud、Google、Exchange等云服务同步,实现跨平台联系人管理。它提供便捷的联系人创建、查找和管理功能,利用标签系统进行分类,整合社交网络信息,并支持智能过滤器和活动清单展示联系人全面信息。此外,BusyContac......
  • SpringBoot养老知识考试管理系统-计算机毕业设计源码86305
    摘要随着人口老龄化趋势的加剧,老年人的健康管理和养老知识学习变得尤为重要。然而,传统的养老知识教育方式存在信息不对称、资源有限等问题,无法满足老年人广泛的学习需求。因此,本系统旨在利用互联网技术,为老年人提供便捷的养老知识学习和考试平台,帮助他们掌握养老知识、提高健......
  • 【开题报告】基于Springboot+vue中医古方名方信息管理系统(程序+源码+论文) 计算机毕业
    本系统(程序+源码)带文档lw万字以上文末可获取一份本项目的java源码和数据库参考。系统程序文件列表开题报告内容研究背景中医作为中华民族的传统医学,承载着丰富的历史文化底蕴与独特的医疗智慧。在历史的长河中,无数中医先辈通过临床实践,总结出了大量疗效显著的古方名方,这......