首页 > 其他分享 >5. 深度学习计算

5. 深度学习计算

时间:2023-09-28 22:55:58浏览次数:37  
标签:nn weight 学习 bias 计算 深度 net True Linear

层与块

块是由若干个层组成, 在编程中我们一般用类表示块, 一般我们通过实例化nn.Sequential()来构建模型, 而有时我们需要自定义块;

class MLP(nn.Module): # 用模型参数声明层。这里,我们声明两个全连接的层 
	def __init__(self): 
		# 调用MLP的父类Module的构造函数来执行必要的初始化。
		# 这样,在类实例化时也可以指定其他函数参数,例如模型参数params(稍后将介绍)
		super().__init__() 
		self.hidden = nn.Linear(20, 256) # 隐藏层 
		self.out = nn.Linear(256, 10) # 输出层
	# 定义模型的前向传播,即如何根据输入X返回所需的模型输出 
	def forward(self, X): 
		# 注意,这里我们使用ReLU的函数版本,其在nn.functional模块中定义。 
		return self.out(F.relu(self.hidden(X)))

参数管理

参数访问

给出一个具有单隐藏层的MLP, 当通过Sequential类定义模型时, 我们可以通过索引来访问模型的任意层。 这就像模型是一个列表一样,每层的参数都在其属性中。我们可以用.state_dict()函数来访问这一层的参数, 如下所示,我们可以访问第二个全连接层的参数。

net = nn.Sequential(nn.Linear(4, 8), nn.ReLU(), nn.Linear(8, 1))
X = torch.rand(size=(2, 4))
print(net[2].state_dict())
OrderedDict([('weight', tensor([[-0.0427, -0.2939, -0.1894,  0.0220, -0.1709, -0.1522, -0.0334, -0.2263]])), ('bias', tensor([0.0887]))])

输出的结果告诉我们一些重要的事情: 首先,这个全连接层包含两个参数,分别是该层的权重和偏置。 两者都存储为单精度浮点数(float32)。 注意,参数名称允许唯一标识每个参数,即使在包含数百个层的网络中也是如此。

提取参数也很简单:

print(type(net[2].bias))
print(net[2].bias)
print(net[2].bias.data)
Parameter containing:
tensor([0.0887], requires_grad=True)
tensor([0.0887])

一次性访问所有参数可以用:

print(*[(name, param.shape) for name, param in net.named_parameters()])
('0.weight', torch.Size([8, 4])) ('0.bias', torch.Size([8])) ('2.weight', torch.Size([1, 8])) ('2.bias', torch.Size([1]))
# 0.weight中的0表示这是第一个层的参数, 对应的2.weight就是第三个层的参数;

这也引出了另一种访问参数的方式:

net.state_dict()['2.bias'].data
tensor([0.0887])

当多个块相互嵌套时就可以看作多维数组去进行访问

def block1():
    return nn.Sequential(nn.Linear(4, 8), nn.ReLU(),
                         nn.Linear(8, 4), nn.ReLU())

def block2():
    net = nn.Sequential()
    for i in range(4):
        # 在这里嵌套
        net.add_module(f'block {i}', block1())
    return net

rgnet = nn.Sequential(block2(), nn.Linear(4, 1))

print(rgnet)

rgnet[0][1][0].bias.data
Sequential(
  (0): Sequential(
    (block 0): Sequential(
      (0): Linear(in_features=4, out_features=8, bias=True)
      (1): ReLU()
      (2): Linear(in_features=8, out_features=4, bias=True)
      (3): ReLU()
    )
    (block 1): Sequential(
      (0): Linear(in_features=4, out_features=8, bias=True)
      (1): ReLU()
      (2): Linear(in_features=8, out_features=4, bias=True)
      (3): ReLU()
    )
    (block 2): Sequential(
      (0): Linear(in_features=4, out_features=8, bias=True)
      (1): ReLU()
      (2): Linear(in_features=8, out_features=4, bias=True)
      (3): ReLU()
    )
    (block 3): Sequential(
      (0): Linear(in_features=4, out_features=8, bias=True)
      (1): ReLU()
      (2): Linear(in_features=8, out_features=4, bias=True)
      (3): ReLU()
    )
  )
  (1): Linear(in_features=4, out_features=1, bias=True)
)

tensor([ 0.1999, -0.4073, -0.1200, -0.2033, -0.1573,  0.3546, -0.2141, -0.2483])

参数初始化

默认情况下,PyTorch会根据一个范围均匀地初始化权重和偏置矩阵, 这个范围是根据输入和输出维度计算出的。 PyTorch的nn.init模块提供了多种预置初始化方法。下面的代码将所有权重参数初始化为标准差为0.01的高斯随机变量, 且将偏置参数设置为0。

def init_normal(m):
    if type(m) == nn.Linear:
        nn.init.normal_(m.weight, mean=0, std=0.01)
        nn.init.zeros_(m.bias)
net.apply(init_normal)
net[0].weight.data[0], net[0].bias.data[0]
(tensor([-0.0214, -0.0015, -0.0100, -0.0058]), tensor(0.))

我们还可以将所有参数初始化为给定的常数,比如初始化为1。

def init_constant(m):
    if type(m) == nn.Linear:
        nn.init.constant_(m.weight, 1)
        nn.init.zeros_(m.bias)
net.apply(init_constant)
net[0].weight.data[0], net[0].bias.data[0]
(tensor([1., 1., 1., 1.]), tensor(0.))

我们还可以对某些块应用不同的初始化方法。 例如,下面我们使用Xavier初始化方法初始化第一个神经网络层, 然后将第三个神经网络层初始化为常量值42。

def init_xavier(m):
    if type(m) == nn.Linear:
        nn.init.xavier_uniform_(m.weight)
def init_42(m):
    if type(m) == nn.Linear:
        nn.init.constant_(m.weight, 42)

net[0].apply(init_xavier)
net[2].apply(init_42)
print(net[0].weight.data[0])
print(net[2].weight.data)
tensor([ 0.5236,  0.0516, -0.3236,  0.3794])
tensor([[42., 42., 42., 42., 42., 42., 42., 42.]])

当然我们还可以自定义初始化:

def my_init(m):
    if type(m) == nn.Linear:
        print("Init", *[(name, param.shape)
                        for name, param in m.named_parameters()][0])
        nn.init.uniform_(m.weight, -10, 10)
        m.weight.data *= m.weight.data.abs() >= 5

net.apply(my_init)
net[0].weight[:2]
Init weight torch.Size([8, 4])
Init weight torch.Size([1, 8])

tensor([[5.4079, 9.3334, 5.0616, 8.3095],
        [0.0000, 7.2788, -0.0000, -0.0000]], grad_fn=<SliceBackward0>)

注意, 我们始终可以直接设置参数

net[0].weight.data[:] += 1
net[0].weight.data[0, 0] = 42
net[0].weight.data[0]
tensor([42.0000, 10.3334,  6.0616,  9.3095])

参数绑定

有时我们希望在多个层间共享参数: 我们可以定义一个稠密层,然后使用它的参数来设置另一个层的参数。

# 我们需要给共享层一个名称,以便可以引用它的参数
shared = nn.Linear(8, 8)
net = nn.Sequential(nn.Linear(4, 8), nn.ReLU(),
                    shared, nn.ReLU(),
                    shared, nn.ReLU(),
                    nn.Linear(8, 1))
net(X)
# 检查参数是否相同
print(net[2].weight.data[0] == net[4].weight.data[0])
net[2].weight.data[0, 0] = 100
# 确保它们实际上是同一个对象,而不只是有相同的值
print(net[2].weight.data[0] == net[4].weight.data[0])
tensor([True, True, True, True, True, True, True, True])
tensor([True, True, True, True, True, True, True, True])

这个例子表明第三个和第五个神经网络层的参数是绑定的。 它们不仅值相等,而且由相同的张量表示。 因此,如果我们改变其中一个参数,另一个参数也会改变。 这里有一个问题:当参数绑定时,梯度会发生什么情况? 答案是由于模型参数包含梯度,因此在反向传播期间第二个隐藏层 (即第三个神经网络层)和第三个隐藏层(即第五个神经网络层)的梯度会加在一起。

标签:nn,weight,学习,bias,计算,深度,net,True,Linear
From: https://www.cnblogs.com/mostimali/p/17736629.html

相关文章

  • Linux第7、8章学习笔记
    第七、八章学习笔记第七章文件操作文件操作级别文件操作分为五个级别,按照从高到低的顺序如下:(1)硬件级别:硬件级别的文件操作包括:fdisk:将硬盘、U盘或SDC盘分区。mkfs:格式化磁盘分区、为系统做好准备。fsck:检查和维修系统。碎片整理:压缩文件系统中的文件。大多数是......
  • Linux第七、八章学习笔记
    第七、八章学习笔记第七章文件操作文件操作级别文件操作分为五个级别,按照从高到低的顺序如下:(1)硬件级别:硬件级别的文件操作包括:fdisk:将硬盘、U盘或SDC盘分区。mkfs:格式化磁盘分区、为系统做好准备。fsck:检查和维修系统。碎片整理:压缩文件系统中的文件。大多数是......
  • 学习笔记4 第七八章的自学归纳
    第7章文件操作文件操作五个级别1.硬件级别:普通用户不会接触,但它是创建和维护系统不可缺少的工具fdisk、mkfs、fsck2.操作系统内核中的文件系统函数每个操作系统内核均可为基本文件操作提供支持。在类unix函数中前缀k表示内核函数3.系统调用用户模式程序使用系统调用来访问......
  • 信息安全系统设计与实现——学习笔记4
    任务详情:自学教材第7,8章,提交学习笔记(10分)Part1知识点归纳&GPT提问知识点归纳chap7文件操作级别硬件级别fdiskmkfsfsck碎片整理操作系统内核中的文件系统函数系统调用I/O库函数用户命令sh脚本文件I/O操作低级别文件操作分区Command(mforhelp):m---......
  • 信息安全系统设计与实现 学习笔记4
    文件操作文件操作级别硬件级别:fdisk将硬盘、U盘或SDC盘分区。mkfs:格式化磁盘分区,为系统做好准备。fsck:检查和维修系统。碎片整理:压缩文件系统中的文件。操作系统内核中的文件系统函数kmount(),kumount()kmkdir(),krmdir()系统调用用户模式使用系统调用来访问内核函数......
  • openGauss学习笔记-83 openGauss 数据库管理-内存优化表MOT管理-内存表特性-MOT使用内
    openGauss学习笔记-83openGauss数据库管理-内存优化表MOT管理-内存表特性-MOT使用内存和存储规划本节描述了为满足特定应用程序需求,在评估、估计和规划内存和存储容量数量时,需要注意的事项和准则,以及影响所需内存数量的各种数据,例如计划表的数据和索引大小、维持事务管理的内存......
  • 《Unix/Linux系统编程》教材学习笔记第七章、第八章
    chapter7文件操作级别文件操作分五个级别,从低到高排序如下:1.硬件级别:硬件级别的文件操作包括fdisk:将硬盘、U盘或SDC盘分区。mkfs:格式化磁盘分区,为系统做好准备。fsck:检查和维修系统。碎片整理:压缩文件系统中的文件。其中大多说是针对系统的实用程序。2.操作系统内核中......
  • 学习笔记4
    第七、八章文件操作文件操作级别1.硬件操作  大多数是针对系统的实用程序2.操作系统内核中的文件系统函数  每个操作系统内核均可为基本文件操作提供支持3.系统调用  用户模式程序使用系统调用来访问内核函数  每个库函数都会发出一个系统调用,使进程进入内核模式......
  • Vue源码学习(八):生命周期调用
    好家伙, Vue源码学习(七):合并生命周期(混入Vue.Mixin)书接上回,在上一篇中,我们已经实现了合并生命周期现在,我们要在我们的初始化过程中,注册生命周期 1.项目目录 红框为本篇涉及到的.js文件 2.先来看/utils/index.jsexportconstHOOKS=["beforeCreated......
  • 2023-2024-1 20231302 《计算机基础与程序设计》第一周学习总结
    作业信息这个作业属于计算机基础与程序设计https://edu.cnblogs.com/campus/besti/2023-2024-1-CFAP/作业要求https://www.cnblogs.com/rocedu/p/9577842.html#WEEK01作业目标快速浏览一遍教材计算机科学概论,课本每章提出至少一个自己不懂的或最想解决的问题并在期......