动手学深度学习—深度学习计算(层和块、参数管理、自定义层和读写文件)

news2024/12/22 2:00:45

目录

  • 1. 层和块
    • 1.1 自定义块
    • 1.2 顺序块
    • 1.3 在前向传播函数中执行代码
  • 2. 参数管理
    • 2.1 参数访问
      • 2.1.1 目标参数
      • 2.1.2 一次性访问所有参数
      • 2.1.3 从嵌套块收集参数
    • 2.2 参数初始化
      • 2.2.1 内置初始化
      • 2.2.2 自定义初始化
    • 2.3 参数绑定
  • 3. 自定义层
    • 3.1 不带参数的层
    • 3.2 带参数的层
  • 4. 读写文件
    • 4.1 加载和保存张量
    • 4.2 加载和保存模型参数
  • 5. GPU

1. 层和块

块可以描述单个层、由多个层组成的组件或整个模型本身。

# 生成一个网络,其中包含一个具有256个单元和ReLU激活函数的全连接隐藏层
# 然后是一个具有10个隐藏单元且不带激活函数的全连接输出层
import torch
from torch import nn
from torch.nn import functional as F

net = nn.Sequential(nn.Linear(20,256), nn.ReLU(), nn.Linear(256,10))

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

在这里插入图片描述

1.1 自定义块

"""
    自定义块:
    1、将输入数据作为其前向传播函数的参数。
    2、通过前向传播函数来生成输出(输出的形状可能与输入的形状不同)。
    3、计算其输出关于输入的梯度,可通过其反向传播函数进行访问。
    4、存储和访问前向传播计算所需的参数。
    5、根据需要初始化模型参数。
"""
"""
    多层感知机:
    1、输入是一个20维的输入。
    2、具有256个隐藏单元的隐藏层和一个10维输出层。
"""
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)))

在这里插入图片描述

1.2 顺序块

"""
    顺序块(相当于Sequential类):
    1、一种将块逐个追加到列表中的函数;
    2、一种前向传播函数,用于将输入按追加块的顺序传递给块组成的“链条”。
"""
class MySequential(nn.Module):
    def __init__(self, *args):
        # __init__函数将每个模块逐个添加到有序字典_modules中
        super().__init__()
        for idx, module in enumerate(args):
            # 这里,module是Module子类的一个实例。我们把它保存在'Module'类的成员
            # _module的类型是OrderedDict,在模块的参数初始化过程中, 系统知道在_modules字典中查找需要初始化参数的子块。
            self._modules[str(idx)] = module
            
    def forward(self, X):
        # OrderedDict保证了按照成员添加的顺序遍历它们
        for block in self._modules.values():
            X = block(X)
        return X

在这里插入图片描述

1.3 在前向传播函数中执行代码

"""
   实现FixedHiddenMLP模型类:
   1、实现一个隐藏层, 其权重(self.rand_weight)在实例化时被随机初始化,之后为常量。
   2、这个权重不是一个模型参数,因此它永远不会被反向传播更新。
   3、神经网络将这个固定层的输出通过一个全连接层。
   4、返回输出时做一个循环操作,输出需小于1
"""
class FixedHiddenMLP(nn.Module):
    def __init__(self):
        super().__init__()
        # 不计算梯度的随机权重参数。因此其在训练期间保持不变
        self.rand_weight = torch.rand((20, 20), requires_grad=False)
        self.linear = nn.Linear(20 ,20)
        
    def forward(self, X):
        X = self.linear(X)
        # 使用创建的常量参数以及relu和mm函数
        X = F.relu(torch.mm(X, self.rand_weight) + 1)
        # 复用全连接层。这相当于两个全连接层共享参数
        X = self.linear(X)
        # 控制流
        while X.abs().sum() > 1:
            X /= 2
        return X.sum()

在这里插入图片描述

# 混合搭配各种组合块
class NestMLP(nn.Module):
    def __init__(self):
        super().__init__()
        self.net = nn.Sequential(nn.Linear(20, 64), nn.ReLU(),
                                 nn.Linear(64, 32), nn.ReLU())
        self.linear = nn.Linear(32, 16)
    
    def forward(self, X):
        return self.linear(self.net(X))

chimera = nn.Sequential(NestMLP(), nn.Linear(16, 20), FixedHiddenMLP())
chimera(X)

在这里插入图片描述

2. 参数管理

  1. 访问参数,用于调试、诊断和可视化;
  2. 参数初始化;
  3. 在不同模型组件间共享参数。
import torch 
from torch import nn

net = nn.Sequential(nn.Linear(4, 8), nn.ReLU(), nn.Linear(8, 1))
X = torch.rand(size=(2, 4))
net(X)

在这里插入图片描述

2.1 参数访问

"""
    检查第二个全连接层的参数:
    1、这个全连接层包含两个参数,分别是该层的权重和偏置。
    2、两者都存储为单精度浮点数(float32)。
"""
print(net[2].state_dict())

在这里插入图片描述

2.1.1 目标参数

# 访问目标参数
print(type(net[2].bias))
print(net[2].bias)
print(net[2].bias.data)

在这里插入图片描述

2.1.2 一次性访问所有参数

# 一次性访问所有参数
print(*[(name, param.shape) for name, param in net[0].named_parameters()])
print(*[(name, param.shape) for name, param in net.named_parameters()])

在这里插入图片描述

2.1.3 从嵌套块收集参数

# 从嵌套块收集参数
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.S

在这里插入图片描述

2.2 参数初始化

"""
    参数初始化:
    1、内置初始化
    2、自定义初始化
"""
# 将所有权重参数初始化为标准差为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)

# model.apply(fn)会递归地将函数fn应用到父模块的每个子模块submodule,也包括model这个父模块自身
net.apply(init_normal)
net[0].weight.data[0], net[0].bias.data[0]

在这里插入图片描述

2.2.1 内置初始化

# 将所有参数初始化为给定的常数,比如初始化为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]

在这里插入图片描述

# 使用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)

在这里插入图片描述

2.2.2 自定义初始化

# 自定义初始化
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]
# net[0].weight[0:]

在这里插入图片描述

2.3 参数绑定

# 在多个层间共享参数: 我们可以定义一个稠密层,然后使用它的参数来设置另一个层的参数。
# 我们需要给共享层一个名称,以便可以引用它的参数
"""
    参数绑定:
    1、第三个和第五个神经网络层的参数是绑定的。 它们不仅值相等,而且由相同的张量表示。
    2、如果我们改变其中一个参数,另一个参数也会改变。
    3、由于模型参数包含梯度,因此在反向传播期间第二个隐藏层 (即第三个神经网络层)和第三个隐藏层(即第五个神经网络层)的梯度会加在一起。
"""
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])

在这里插入图片描述

3. 自定义层

我们可以用创造性的方式组合不同的层,从而设计出适用于各种任务的架构。

3.1 不带参数的层

"""
    自定义CenteredLayer类:
    1、要从其输入中减去均值;
    2、要构建它,我们只需继承基础层类并实现前向传播功能。
"""
import torch
import torch.nn.functional as F
from torch import nn

class CenteredLayer(nn.Module):
    def __init__(self):
        super().__init__()
        
    def forward(self, X):
        return X - X.mean()

在这里插入图片描述

3.2 带参数的层

"""
    自定义带参数的全连接层:
    1、该层需要两个参数,一个用于表示权重,另一个用于表示偏置项;
    2、使用修正线性单元作为激活函;
    3、in_units和units,分别表示输入数和输出数。
"""
class MyLinear(nn.Module):
    def __init__(self, in_units, units):
        super().__init__()
        self.weight = nn.Parameter(torch.randn(in_units, units))
        self.bias = nn.Parameter(torch.randn(units,))
    def forward(self, X):
        linear = torch.matmul(X, self.weight.data) + self.bias.data
        return F.relu(linear)

在这里插入图片描述

4. 读写文件

有时我们希望保存训练的模型, 以备将来在各种环境中使用(比如在部署中进行预测)。

4.1 加载和保存张量

import torch
from torch import nn
from torch.nn import functional as F

x = torch.arange(4)
torch.save(x, 'x-file')

在这里插入图片描述

# 存储一个张量列表,然后把它们读回内存。
y = torch.zeros(4)
torch.save([x, y], 'x-files')
x2, y2 = torch.load('x-files')
(x2, y2)

在这里插入图片描述

# 写入或读取从字符串映射到张量的字典
mydict = {'x': x, 'y': y}
torch.save(mydict, 'mydict')
mydict2 = torch.load('mydict')
mydict2

在这里插入图片描述

4.2 加载和保存模型参数

"""
    加载和保存模型参数:
    1、深度学习框架提供了内置函数来保存和加载整个网络;
    2、保存模型的参数而不是保存整个模型。
"""
class MLP(nn.Module):
    def __init__(self):
        super().__init__()
        self.hidden = nn.Linear(20, 256)
        self.output = nn.Linear(256, 10)
        
    def forward(self, x):
        return self.output(F.relu(self.hidden(x)))
    
net = MLP()
X = torch.randn(size=(2, 20))
Y = net(X)

在这里插入图片描述

# 为了恢复模型,我们实例化了原始多层感知机模型的一个备份
clone = MLP()
clone.load_state_dict(torch.load('mlp.params'))
clone.eval()

在这里插入图片描述

5. GPU

GPU能够帮助我们更好地进行计算,使用nvidia-smi命令来查看显卡信息。

!nvidia-smi
# 定义了两个方便的函数, 这两个函数允许我们在不存在所需所有GPU的情况下运行代码
def try_gpu(i=0): #@save
    """如果存在,则返回gpu(i),否则返回cpu()"""
    if torch.cuda.device_count() >= i + 1:
        return torch.device(f'cuda:{i}')
    return torch.device('cpu')

def try_all_gpus(): #@save
    """返回所有可用的GPU,如果没有GPU,则返回[cpu(),]"""
    devices = [torch.device(f'cuda{i}')
              for i in range(torch.cuda.device_count())]
    return devices if devices else [torch.device('cpu')]

try_gpu(), try_gpu(10), try_all_gpus()

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/821497.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【PWN · 栈迁移】[BUUCTF][Black Watch 入群题]PWN

记一道栈迁移题目 前言 【PWN 栈迁移】[BUUCTF]ciscn_2019_es_2_Mr_Fmnwon的博客-CSDN博客 一、代码审计 总结信息如下: 1. 第12行存在栈溢出漏洞,刚好可以溢出覆盖到ebp和ret 2. 第9行可输入大量数据到bss段 二、思路过程 1.栈迁移 进能够覆盖e…

Nodejs 第八章(npm搭建私服)

构建npm私服 构建私服有什么收益吗? 可以离线使用,你可以将npm私服部署到内网集群,这样离线也可以访问私有的包。提高包的安全性,使用私有的npm仓库可以更好的管理你的包,避免在使用公共的npm包的时候出现漏洞。提高…

SAM(Segment Anything)大模型论文汇总

A Comprehensive Survey on Segment Anything Model for Vision and Beyond 论文:https://arxiv.org/abs/2305.08196 25页综述,198篇参考文献!52个开源项目!本文第一个全面回顾了分割一切模型(SAM)的研究和应用进展,…

AttributeError: module ‘PyQt5.QtGui‘ has no attribute ‘QMainWindow‘

场景描述: 这个问题是使用PyUIC将ui文件变成py文件后遇到的 解决办法: 改动1:把object改成QtWidgets.QMainWindow 改动2:增加__init__函数,函数结构如下: def __init__(self):super(Ui_MainWindow,self).…

vue03 es6中对数组的操作,vue对数据监控的原理(分别对对象和数组的监控)

在js中,对数组的操作一般都是固定的模式:常用的函数,具体的方法在这个文章中去看: http://t.csdn.cn/Fn1Ik 一般会用到的函数有: pop() 这个函数是表示把数组中的元素(数组&#xff…

Elasticsearch 全文检索 分词检索-Elasticsearch文章四

文章目录 官方文档地址refercence文档全文搜索体系match简单查询match 多词/分词单字段分词match多个词的逻辑控制match的匹配精度match_pharse_prefix分词前缀方式match_bool_prefixmulti_match多字段匹配 query string类型Interval类型DSL查询之Term详解聚合查询之Bucket聚合…

Java入门指南:Java语言优势及其特点

目录 1. Java语言简介及发展概述 2. Java语言的优势 2.1 可移植性 2.2 面向对象 2.3 安全性 2.4 大量类库 3. Java语言与C/C的区别 4. 初识Java程序入口之main方法 5. 注释、标识符、关键字 5.1 注释 5.2 标识符 5.3 关键字 1. Java语言简介及发展概述 Java是一种面…

天下风云出我辈,AI准独角兽实在智能获评“十大数字经济风云企业

时值盛夏,各地全力拼经济的氛围同样热火朝天。在浙江省经济强区余杭区这片创业热土上,人工智能助力数字经济建设正焕发出蓬勃生机。 7月28日,经专家评审、公开投票,由中共杭州市余杭区委组织部(区委两新工委&#xff…

【Java】数据结构篇:经典链表OJ题 |超详细图解+代码

博主简介:努力学习的预备程序媛一枚~博主主页: @是瑶瑶子啦所属专栏: Java岛冒险记【从小白到大佬之路】文章目录 1、获取链表的中间节点⭐2、单链表的逆置⭐3、判定链表是否是回文⭐4、链表分割5、合并两个有序链表6、链表中倒数第k个结点⭐7、判定链表相交8、判断链表带环⭐…

15、两个Runner初始化器和 springboot创建非web应用

两个Runner初始化器 两个Runner初始化器——主要作用是对component组件来执行初始化 这里的Component组件我理解为是被Component注解修饰的类 Component //用这个注解修饰的类,意味着这个类是spring容器中的一个组件,springboot应用会自动加载该组件。 …

一文读懂浏览器本地存储:Web Storage

一、 简介 二、localStorage 和 sessionStorage 2.1、区别 2.2、浏览器兼容性 三、使用说明 3.1、API介绍 3.2、浏览器查看 3.3、监听 四、存储 4.1、存储容量 4.2、存储性能 五、应用 5.1、使用习惯记录 5.2、首次打开提示 5.3、减少重复访问接口 六、总结 一、 …

在 3ds Max 中使用相机映射将静止图像转换为实时素材

推荐: NSDT场景编辑器 助你快速搭建可二次开发的3D应用场景 1. 在 Photoshop 中准备图像 步骤 1 这是我将在教程中使用的静止图像。 这是我的静态相机纸箱的快照。 静止图像 步骤 2 打开 Photoshop。将图像导入 Photoshop。 打开 Photoshop 步骤 3 单击套索工…

计算机网络基础(静态路由,动态路由,公网IP,私网IP,NAT技术)

文章目录 一:静态路由和动态路由二:静态路由的配置路由信息的方式演示三:默认路由四:公网IP和私网IP和NAT技术的基本理解 一:静态路由和动态路由 在说静态路由和动态路由前,我们需要来了解一下&#xff0…

近2年入侵13家电信公司的幕后黑手浮出水面

10月20日,网络安全公司赛门铁克刚披露了一个针对南亚电信公司的神秘APT(高级持续威胁)组织,一个名为 LightBasin 的黑客组织被确定为针对电信行业发起一系列攻击的幕后黑手,其目标是从移动通信基础设施中收集“高度特定…

【iOS】GCD深入学习

关于GCD和队列的简单介绍请看:【iOS】GCD学习 本篇主要介绍GCD中的方法。 栅栏方法:dispatch_barrier_async 我们有时候需要异步执行两组操作,而且第一组操作执行完之后,才能开始执行第二组操作,当然操作组里也可以包含一个或者…

JVM之三大垃圾回收算法

文章目录 前言一、复制算法二、标记清除三、标记整理 前言 提示:这里可以添加本文要记录的大概内容: 例如:随着人工智能的不断发展,机器学习这门技术也越来越重要,很多人都开启了学习机器学习,本文就介绍…

Django实现音乐网站 ⑶

使用Python Django框架制作一个音乐网站,在系列文章2的基础上继续开发,本篇主要是后台单曲、专辑、首页轮播图表模块开发。 目录 后台单曲、专辑表模块开发 表结构设计 单曲表(singe)结构 专辑表(album&#xff09…

安达发|APS生产派单系统对数字化工厂有哪些影响和作用

数字化工厂是当今制造业的热门话题,而APS软件则是这一领域的颠覆者。它以其独特的影响和作用,给制造业带来了巨大的改变。让我们一起来看看APS软件对数字化工厂有哪些影响和作用吧! 提高生产效率的神器 1.APS软件作为数字化工厂的核心系统&a…

Jenkins工具系列 —— 启动 Jenkins 服务报错

错误显示 apt-get 安装 Jenkins 后,自动启动 Jenkins 服务报错。 排查原因 直接运行jenkins命令 发现具体报错log:Failed to start Jetty或Failed to bind to 0.0.0.0/0.0.0.0:8080或Address already in use 说明:这里提示的是8080端口号…

权威认可|云畅科技再次入选中国信通院「高质量数字化转型产品及服务全景图」

7月27日,由中国信通院主办的2023数字生态发展大会暨中国信通院“铸基计划”年中会议在北京成功召开。 会上,中国信通院重磅发布了「高质量数字化转型产品及服务全景图(2023)」,云畅科技凭借其自研产品「万应低代码」在…