《动手学深度学习》5.3~5.5

目录

一、延后初始化

1.1实例化网络

二、自定义层

2.1不带参数的层

2.2带参数的层

三、读写文件

3.1加载和保存张量

3.2加载保存模型参数


一、延后初始化

在学习前面章节的时候,不知道你们有没有这种感觉,这些张量的形状自己总是搞不明白。作者一开始是这样的,后来代码写多了才渐渐理解的。

可在遇到这些东西的时候,还是要稍微停下来时间思考一下。

那是因为,到目前为止,我们忽略了建立网络时需要做的以下这些事情:

  • 我们定义了网络架构,但没有指定输入维度。

  • 我们添加层时没有指定前一层的输出维度。

  • 我们在初始化参数时,甚至没有足够的信息来确定模型应该包含多少参数

既然提出来问题了,那肯定是有解决办法的。这个问题的解决办法就是:框架的延后初始化

有了该技术将更加方便。 现在我们在编写代码时无须知道维度是什么就可以设置参数, 这种能力可以大大简化定义和修改模型的任务。

1.1实例化网络

实例化一个感知机:

python 复制代码
import torch
import torch.nn as nn

net = nn.Sequential(nn.LazyLinear(256),
                    nn.ReLU(),
                    nn.LazyLinear(10))
print(net[0].weight)
print(net)

这里的LazyLinear()就是延后初始化,我们不知道输入,只知道输出。

运行结果:

<UninitializedParameter>

Sequential(

(0): LazyLinear(in_features=0 , out_features=256, bias=True)

(1): ReLU()

(2): LazyLinear(in_features=0 , out_features=10, bias=True)

)

我们给这个网络一个特征值。

python 复制代码
X = torch.rand(2,20)
net(X)
print(net[0].weight)
print(net)

运行结果:

Parameter containing:

tensor([[-0.1142, -0.1500, -0.2170, ..., -0.0608, -0.0959, 0.0969],

-0.1418, 0.1375, 0.2137, ..., 0.1531, -0.0622, 0.1335\], \[-0.1582, -0.0558, 0.1994, ..., -0.0048, -0.0288, -0.1821\], ..., \[ 0.1771, -0.0401, 0.1677, ..., 0.1472, 0.1971, -0.1043\], \[-0.0685, -0.1094, -0.0304, ..., 0.2133, -0.2186, -0.1285\], \[ 0.1542, 0.0978, 0.0081, ..., -0.1878, -0.1788, 0.1976\]\], requires_grad=True) Sequential( (0): Linear(**in_features=20** , out_features=256, bias=True) (1): ReLU() (2): Linear(**in_features=256** , out_features=10, bias=True) ) 可以看到,发生了变化,这就是pytorch的延后初始化。 ## 二、自定义层 我们可以用创造性的方式组合不同的层,从而设计出适用于各种任务的架构。 但还是那个问题,再厉害的框架,也不可能包揽所有种类的层。 这个时候,就需要我们手搓一个我们专用的层,也就是自定义层。 ### 2.1不带参数的层 这是一个把输入减去输入的均值的层,虽然可能在实际中没有任何意义,但是这里的重点在于,PyTorch框架里面没有。 ```python 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() ``` 让我们验证它是否能按预期工作。 ```python layer = CenteredLayer() print(layer(torch.FloatTensor([1, 2, 3, 4, 5]))) ``` 运行结果: tensor(\[-2., -1., 0., 1., 2.\]) 我们可以像5.1节那样,把它合并到更复杂的模型中,但在这里就不掩饰了。 ### 2.2带参数的层 回想一下我们之前学过的那些全连接层,需要两个参数,一个用于表示权重,另一个用于表示偏置项。该层需要输入参数:`in_units`和`units`,分别表示输入数和输出数。 ```python 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) linear = MyLinear(5, 3) print(linear.weight) print(linear(torch.rand(2, 5)))#向前传播 ``` matmul()是矩阵乘法。 我们使用修正线性单元(ReLU)作为激活函数。 除此之外,应该没有什么需要解释的地方了。 运行结果: tensor(\[\[-1.2881, -1.2804, 0.7337\], \[-0.5448, -1.2296, -0.8849\], \[-0.0550, -0.0579, 0.2759\], \[-0.2484, -1.8061, 0.4572\], \[ 0.2487, -0.8685, 0.1223\]\], requires_grad=True) tensor(\[\[0.5101, 2.0328, 2.0510\], \[0.8924, 0.0000, 0.0000\]\]) ## 三、读写文件 目前为止,我们讨论了如何处理数据, 以及如何构建、训练和测试深度学习模型。 但是,我们目前训练的模型,都存储在内存中。程序运行停止之后就没有了。 我们目前手搓的模型体量都很小,但是在训练FashionMINIST的时候,已经感觉有些吃力了。那些数以亿万计的模型消耗的时间成本更是不知多少。 所以,现在是时候学习如何加载和存储权重向量和整个模型了。 ### 3.1加载和保存张量 对于张量,我们使用load和save方法进行加载和保存。 单个张量的保存和加载: ```python import torch from torch import nn from torch.nn import functional as F x = torch.arange(4) torch.save(x, 'x-file')#保存 print(torch.load('x-file'))#加载 ``` 运行结果: tensor(\[0, 1, 2, 3\]) 张量列表也是用这个方法: ```python y = torch.zeros(4) torch.save([x,y],'x-files') print(torch.load('x-files')) ``` 运行结果: \[tensor(\[0, 1, 2, 3\]), tensor(\[0., 0., 0., 0.\])

我们还可以写入或读取从字符串映射到张量的字典 。 当我们要读取或写入模型中的所有权重时,这很方便。

python 复制代码
mydict = {'x': x, 'y': y}
torch.save(mydict, 'mydict')
mydict2 = torch.load('mydict')
print(mydict2)

运行结果:

{'x': tensor([0, 1, 2, 3]), 'y': tensor([0., 0., 0., 0.])}

3.2加载保存模型参数

如果我们想要保存整个模型,只靠上面学到的是不够的,因为模型可能有数百个参数散布在各处。

于是,深度学习框架提供了内置函数来保存和加载整个网络。

但要注意,这将保存模型的参数而不是保存整个模型。

因为模型本身可以包含任意代码,所以模型本身难以序列化。为了恢复模型,我们需要用代码生成架构, 然后从磁盘加载参数。

为了理解上面的话,我们来创建一个多层感知机演示一下。

python 复制代码
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)

torch.save(net.state_dict(), 'mlp.params')#保存参数

这个是我们常用的单个隐藏层,隐藏层经过relu函数激活的多层感知机。

我们调用save方法,通过**.state_dict()**获取参数字典,保存在mlp.params参数中。

python 复制代码
clone = MLP()
clone.load_state_dict(torch.load('mlp.params'))
clone.eval()
print(clone)

现在我们重新创建一个同类型的多层感知机clone,然后让他加载保存的参数。

运行结果:

MLP(

(hidden): Linear(in_features=20, out_features=256, bias=True)

(output): Linear(in_features=256, out_features=10, bias=True)

)

两个实例具有相同的模型参数,在输入相同的X时, 两个实例的计算结果应该相同。 让我们来验证一下。

python 复制代码
Y_clone = clone(X)
print(Y_clone == Y)

运行结果:

tensor([[True, True, True, True, True, True, True, True, True, True],

True, True, True, True, True, True, True, True, True, True\]\])

相关推荐
科研服务器mike_leeso4 小时前
41 年 7 次转型!戴尔从 PC 到 AI 工厂的技术跃迁与组织重构
大数据·人工智能·机器学习
lisw054 小时前
如何改善基于深度学习的场重构
深度学习·重构·软件工程
大千AI助手4 小时前
机器学习模型评估指标AUC详解:从理论到实践
人工智能·机器学习·模型评估·roc·precision·recall·auc
2501_913981784 小时前
2025年智能家居无线数传设备品牌方案精选
大数据·人工智能·智能家居
不老刘4 小时前
GitHub Spec-Kit:AI 时代的规范驱动开发工具
人工智能·github·spec-kit
mit6.8244 小时前
[tile-lang] 张量核心 | 传统MMA->WGMMA | 底层自动选择优化
人工智能·chatgpt
csuzhucong4 小时前
人类知识体系分类
人工智能·分类·数据挖掘
DisonTangor4 小时前
Lumina-DiMOO:用于多模态生成与理解的全扩散大语言模型
人工智能·语言模型·自然语言处理·ai作画·aigc
golang学习记5 小时前
阿里又出手了,发布全新终端CLI工具,还支持VSCode
人工智能